SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause copyrights: - Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) enabled-by: true functional-type: action links: - role: interface-function uid: ../if/delete post-conditions: - name: Status states: - name: Ok test-code: | T_rsc_success( ctx->status ); text: | The return status of ${../if/delete:/name} shall be ${../../status/if/successful:/name}. - name: InvId test-code: | T_rsc( ctx->status, RTEMS_INVALID_ID ); text: | The return status of ${../if/delete:/name} shall be ${../../status/if/invalid-id:/name}. - name: CalledFromISR test-code: | T_rsc( ctx->status, RTEMS_CALLED_FROM_ISR ); text: | The return status of ${../if/delete:/name} shall be ${../../status/if/called-from-isr:/name}. - name: NoReturn test-code: | T_rsc( ctx->status, RTEMS_NOT_IMPLEMENTED ); text: | The ${../if/delete:/name} call shall not return. test-epilogue: null test-prologue: null - name: FatalError states: - name: 'Yes' test-code: | T_eq_u32( ctx->calls.fatal, 1 ); text: | The fatal error with a fatal source of ${/score/interr/if/internal-error-core:/name} and a fatal code of ${/score/interr/if/bad-thread-dispatch-disable-level:/name} shall occur through the ${../if/delete:/name} call. - name: Nop test-code: | T_eq_u32( ctx->calls.fatal, 0 ); text: | No fatal error shall occur through the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: Zombie states: - name: 'Yes' test-code: | T_eq_u32( ctx->worker_state & STATES_ZOMBIE, STATES_ZOMBIE ) text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be in the zombie state after the ${../if/delete:/name} call. - name: 'No' test-code: | T_eq_u32( ctx->worker_state & STATES_ZOMBIE, 0 ) text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall not be in the zombie state after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: TaskPriority states: - name: Raise test-code: | T_eq_u32( ctx->worker_priority, PRIO_ULTRA_HIGH ); text: | Each priority of the calling task which is higher than the highest priority of the task specified by the ${../if/delete:/params[0]/name} parameter shall be made the highest priority of the task. - name: Nop test-code: | T_eq_u32( ctx->worker_priority, PRIO_NORMAL ); text: | The priorities of the task specified by the ${../if/delete:/params[0]/name} parameter shall not be changed by the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: RestartExtensions states: - name: Nop test-code: | T_eq_u32( ctx->calls_after_restart.thread_restart, 0 ); text: | The thread delete user extensions shall not be invoked by the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: TerminateExtensions states: - name: 'Yes' test-code: | T_eq_u32( ctx->calls_after_restart.thread_terminate, 1 ); text: | The thread terminate user extensions shall be invoked by the ${../if/delete:/name} call. - name: Nop test-code: | T_eq_u32( ctx->calls_after_restart.thread_terminate, 0 ); text: | The thread terminate user extensions shall not be invoked by the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: Dormant states: - name: 'Yes' test-code: | T_eq_u32( ctx->worker_state & STATES_DORMANT, STATES_DORMANT ) text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be dormant after the ${../if/delete:/name} call. - name: 'No' test-code: | T_eq_u32( ctx->worker_state & STATES_DORMANT, 0 ) text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall not be dormant after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: Suspended states: - name: 'Yes' test-code: | T_eq_u32( ctx->worker_state & STATES_SUSPENDED, STATES_SUSPENDED ) text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be suspended after the ${../if/delete:/name} call. - name: 'No' test-code: | T_eq_u32( ctx->worker_state & STATES_SUSPENDED, 0 ) text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall not be suspended after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: Restarting states: - name: 'Yes' test-code: | T_ne_int( ctx->worker_life_state & THREAD_LIFE_RESTARTING, 0 ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be restarting after the ${../if/delete:/name} call. - name: 'No' test-code: | T_eq_int( ctx->worker_life_state & THREAD_LIFE_RESTARTING, 0 ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall not be restarting after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: Terminating states: - name: 'Yes' test-code: | T_ne_int( ctx->worker_life_state & THREAD_LIFE_TERMINATING, 0 ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be terminating after the ${../if/delete:/name} call. - name: 'No' test-code: | T_eq_int( ctx->worker_life_state & THREAD_LIFE_TERMINATING, 0 ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall not be terminating after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: Protected states: - name: 'Yes' test-code: | T_ne_int( ctx->worker_life_state & THREAD_LIFE_PROTECTED, 0 ); text: | The thread life of the task specified by the ${../if/delete:/params[0]/name} parameter be protected after the ${../if/delete:/name} call. - name: 'No' test-code: | T_eq_int( ctx->worker_life_state & THREAD_LIFE_PROTECTED, 0 ); text: | The thread life of the task specified by the ${../if/delete:/params[0]/name} parameter shall not be protected after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null - name: State states: - name: Enqueued test-code: | T_ne_u32( ctx->worker_state & STATES_BLOCKED, 0 ) T_not_null( ctx->worker_wait_queue ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be enqueued on a ${/glossary/waitqueue:/term} and blocked. - name: Ready test-code: | T_eq_u32( ctx->worker_state & STATES_BLOCKED, 0 ) T_null( ctx->worker_wait_queue ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall not be enqueued on a ${/glossary/waitqueue:/term} and not blocked. - name: Blocked test-code: | T_ne_u32( ctx->worker_state & STATES_BLOCKED, 0 ) T_null( ctx->worker_wait_queue ); text: | The task specified by the ${../if/delete:/params[0]/name} parameter shall be not enqueued on a ${/glossary/waitqueue:/term} and blocked. test-epilogue: null test-prologue: null - name: Timer states: - name: Active test-code: | T_eq_int( ctx->worker_timer_info.state, TASK_TIMER_TICKS ); text: | The timer of the task specified by the ${../if/delete:/params[0]/name} parameter shall be active after the ${../if/delete:/name} call. - name: Inactive test-code: | T_eq_int( ctx->worker_timer_info.state, TASK_TIMER_INACTIVE ); text: | The timer of the task specified by the ${../if/delete:/params[0]/name} parameter shall be inactive after the ${../if/delete:/name} call. test-epilogue: null test-prologue: null pre-conditions: - name: Id states: - name: Executing test-code: | ctx->id = RTEMS_SELF; text: | While the ${../if/delete:/params[0]/name} parameter is associated with the calling task. - name: Other test-code: | ctx->id = ctx->worker_id; text: | While the ${../if/delete:/params[0]/name} parameter is associated with a task other than the calling task. - name: Invalid test-code: | ctx->id = INVALID_ID; text: | While the ${../if/delete:/params[0]/name} parameter is not associated with a task. test-epilogue: null test-prologue: null - name: Context states: - name: Task test-code: | ctx->interrupt = false; text: | While the ${../if/delete:/name} directive is called from within task context. - name: Interrupt test-code: | ctx->interrupt = true; text: | While the ${../if/delete:/name} directive is called from within interrupt context. test-epilogue: null test-prologue: null - name: ThreadDispatch states: - name: Disabled test-code: | ctx->dispatch_disabled = true; text: | While thread dispatching is disabled for the calling task. - name: Enabled test-code: | ctx->dispatch_disabled = false; text: | While thread dispatching is enabled for the calling task. test-epilogue: null test-prologue: null - name: CallerPriority states: - name: Vital test-code: | ctx->vital_deleter_priority = true; text: | While at least one priority of the calling task is higher than the highest priority of the task specified by the ${../if/delete:/params[0]/name} parameter. - name: Dispensable test-code: | ctx->vital_deleter_priority = false; text: | While all priorities of the calling task are lower than or equal to the highest priority of the task specified by the ${../if/delete:/params[0]/name} parameter. test-epilogue: null test-prologue: null - name: Dormant states: - name: 'No' test-code: | ctx->dormant = false; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is not dormant. - name: 'Yes' test-code: | ctx->dormant = true; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is dormant. test-epilogue: null test-prologue: null - name: Suspended states: - name: 'Yes' test-code: | ctx->suspended = true; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is suspended. - name: 'No' test-code: | ctx->suspended = false; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is not suspended. test-epilogue: null test-prologue: null - name: Restarting states: - name: 'No' test-code: | ctx->restarting = false; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is not restarting. - name: 'Yes' test-code: | ctx->restarting = true; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is restarting. test-epilogue: null test-prologue: null - name: Terminating states: - name: 'No' test-code: | ctx->terminating = false; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is not terminating. - name: 'Yes' test-code: | ctx->terminating = true; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is terminating. test-epilogue: null test-prologue: null - name: Protected states: - name: 'Yes' test-code: | ctx->protected = true; text: | While thread life of the task specified by the ${../if/delete:/params[0]/name} parameter is protected. - name: 'No' test-code: | ctx->protected = false; text: | While thread life of the task specified by the ${../if/delete:/params[0]/name} parameter is not protected. test-epilogue: null test-prologue: null - name: State states: - name: Enqueued test-code: | ctx->blocked = true; ctx->enqueued = true; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is enqueued on a ${/glossary/waitqueue:/term}. - name: Ready test-code: | ctx->blocked = false; ctx->enqueued = false; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is a ${/glossary/readytask:/term} or a ${/glossary/scheduledtask:/term}. - name: Blocked test-code: | ctx->blocked = true; ctx->enqueued = false; text: | While the task specified by the ${../if/delete:/params[0]/name} parameter is blocked. test-epilogue: null test-prologue: null - name: Timer states: - name: Inactive test-code: | ctx->timer_active = false; text: | While timer of the task specified by the ${../if/delete:/params[0]/name} parameter is inactive. - name: Active test-code: | ctx->timer_active = true; text: | While timer of the task specified by the ${../if/delete:/params[0]/name} parameter is active. test-epilogue: null test-prologue: null rationale: null references: [] requirement-type: functional skip-reasons: ExecutingIsNotDormant: | An executing thread was started and thus is never dormant. ExecutingIsNotBlocked: | An executing thread is not blocked. NotBlockedHasInactiveTimer: | The timer of a not blocked thread is inactive. ThreadDispatchDisabled: | While ISRs or nested requests are processed, the thread dispatching is disabled. test-action: | rtems_status_code sc; if ( ctx->id != INVALID_ID && !ctx->dormant ) { ctx->worker_is_mutex_owner = false; StartTask( ctx->worker_id, Worker, ctx ); /* Let the worker catch signals and set the thread life protection state */ Yield(); sc = rtems_signal_send( ctx->worker_id, RTEMS_SIGNAL_0 ); T_rsc_success( sc ); if ( ctx->restarting ) { sc = rtems_task_restart( ctx->worker_id, 0 ); T_rsc_success( sc ); } if ( ctx->terminating ) { sc = rtems_task_restart( ctx->deleter_id, (rtems_task_argument) ctx ); T_rsc_success( sc ); } else { Yield(); } } if ( ctx->id != RTEMS_SELF ) { if ( ctx->interrupt ) { CallWithinISR( Delete, ctx ); } else { sc = rtems_task_restart( ctx->deleter_2_id, (rtems_task_argument) ctx ); T_rsc_success( sc ); } } Cleanup( ctx ); test-brief: null test-cleanup: null test-context: - brief: | This member provides the scheduler operation records. description: null member: | T_scheduler_log_10 scheduler_log - brief: | This member provides a jump context to resume a thread dispatch. description: null member: | jmp_buf thread_dispatch_context; - brief: | This member contains the identifier of the runner scheduler. description: null member: | rtems_id scheduler_id - brief: | This member contains the identifier of the runner task. description: null member: | rtems_id runner_id - brief: | This member references the TCB of the runner task. description: null member: | rtems_tcb *runner_tcb - brief: | This member contains the identifier of the mutex. description: null member: | rtems_id mutex_id - brief: | This member provides an event set used to set up the blocking conditions of the task to delete. description: null member: | rtems_event_set events - brief: | This member contains the identifier of the worker task. description: null member: | rtems_id worker_id - brief: | This member references the TCB of the worker task. description: null member: | rtems_tcb *worker_tcb - brief: | This member contains the worker state at the end of the ${../if/delete:/name} call. description: null member: | States_Control worker_state - brief: | This member contains the worker timer info at the end of the ${../if/delete:/name} call. description: null member: | TaskTimerInfo worker_timer_info; - brief: | This member contains the worker thread queue at the end of the ${../if/delete:/name} call. description: null member: | const Thread_queue_Queue *worker_wait_queue; - brief: | This member contains the worker thread life state at the end of the ${../if/delete:/name} call. description: null member: | Thread_Life_state worker_life_state - brief: | This member contains the worker priority at the end of the ${../if/delete:/name} call. description: null member: | rtems_task_priority worker_priority - brief: | This member contains the identifier of the deleter task. description: null member: | rtems_id deleter_id - brief: | This member references the TCB of the deleter task. description: null member: | rtems_tcb *deleter_tcb - brief: | This member contains the identifier of the second deleter task. description: null member: | rtems_id deleter_2_id - brief: | This member references the TCB of the second deleter task. description: null member: | rtems_tcb *deleter_2_tcb - brief: | This member contains the identifier of the test user extensions. description: null member: | rtems_id extension_id - brief: | This member contains extension calls. description: null member: | ExtensionCalls calls; - brief: | This member contains extension calls after the ${../if/delete:/name} call. description: null member: | ExtensionCalls calls_after_restart; - brief: | This member contains the delete counter. description: null member: | uint32_t restart_counter - brief: | If this member is true, then the worker shall be dormant before the ${../if/delete:/name} call. description: null member: | bool dormant - brief: | If this member is true, then the worker shall be suspended before the ${../if/delete:/name} call. description: null member: | bool suspended - brief: | If this member is true, then the thread life of the worker shall be protected before the ${../if/delete:/name} call. description: null member: | bool protected - brief: | If this member is true, then the worker shall be restarting before the ${../if/delete:/name} call. description: null member: | bool restarting - brief: | If this member is true, then the worker shall be terminating before the ${../if/delete:/name} call. description: null member: | bool terminating - brief: | If this member is true, then the ${../if/delete:/name} shall be called from within interrupt context. description: null member: | bool interrupt - brief: | If this member is true, then the worker shall be blocked before the ${../if/delete:/name} call. description: null member: | bool blocked - brief: | If this member is true, then the worker shall be enqueued on a ${/glossary/waitqueue:/term} before the ${../if/delete:/name} call. description: null member: | bool enqueued - brief: | If this member is true, then the worker obtained a mutex. description: null member: | bool worker_is_mutex_owner - brief: | If this member is true, then the timer of the worker shall be active before the ${../if/delete:/name} call. description: null member: | bool timer_active - brief: | If this member is true, then the deleter shall have a vital priority for the worker. description: null member: | bool vital_deleter_priority - brief: | If this member is true, then thread dispatching is disabled by the worker task before the ${../if/delete:/name} call. description: null member: | bool dispatch_disabled - brief: | If this member is true, then it is expected to delete the worker. description: null member: | bool delete_worker_expected - brief: | This member contains the return value of the ${../if/delete:/name} call. description: null member: | rtems_status_code status - brief: | This member specifies if the ${../if/delete:/params[0]/name} parameter value. description: null member: | rtems_id id test-context-support: null test-description: null test-header: null test-includes: - rtems.h - rtems/test-scheduler.h - rtems/bspIo.h - rtems/score/io.h - rtems/score/statesimpl.h - rtems/score/threaddispatch.h - rtems/score/threadimpl.h - limits.h - setjmp.h test-local-includes: - tx-support.h test-prepare: | ctx->status = RTEMS_NOT_IMPLEMENTED; ctx->restart_counter = 0; ctx->delete_worker_expected = false; ctx->worker_id = CreateTask( "WORK", PRIO_NORMAL ); ctx->delete_worker_expected = true; ctx->worker_tcb = GetThread( ctx->worker_id ); ctx->worker_state = UINT32_MAX; ctx->worker_life_state = INT_MAX; ctx->worker_priority = UINT32_MAX; test-setup: brief: null code: | rtems_status_code sc; ctx->runner_id = rtems_task_self(); ctx->runner_tcb = GetThread( ctx->runner_id ); ctx->scheduler_id = GetSelfScheduler(); ctx->mutex_id = CreateMutexNoProtocol(); ObtainMutex( ctx->mutex_id ); sc = rtems_extension_create( rtems_build_name( 'T', 'E', 'S', 'T' ), &extensions, &ctx->extension_id ); T_rsc_success( sc ); SetFatalHandler( Fatal, ctx ); SetTaskSwitchExtension( TaskSwitch ); SetSelfPriority( PRIO_NORMAL ); ctx->deleter_id = CreateTask( "DELE", PRIO_HIGH ); ctx->deleter_tcb = GetThread( ctx->deleter_id ); StartTask( ctx->deleter_id, Deleter, NULL ); ctx->deleter_2_id = CreateTask( "DEL2", PRIO_ULTRA_HIGH ); ctx->deleter_2_tcb = GetThread( ctx->deleter_2_id ); StartTask( ctx->deleter_2_id, SecondDeleter, NULL ); description: null test-stop: null test-support: | typedef ${.:/test-context-type} Context; static void CaptureWorkerState( Context *ctx ) { T_scheduler_log *log; log = T_scheduler_record( NULL ); if ( log != NULL ) { T_eq_ptr( &log->header, &ctx->scheduler_log.header ); ctx->worker_wait_queue = ctx->worker_tcb->Wait.queue; ctx->worker_state = ctx->worker_tcb->current_state; ctx->worker_life_state = ctx->worker_tcb->Life.state; ctx->worker_priority = SCHEDULER_PRIORITY_UNMAP( _Thread_Get_priority( ctx->worker_tcb ) ); CopyExtensionCalls( &ctx->calls, &ctx->calls_after_restart ); GetTaskTimerInfoByThread( ctx->worker_tcb, &ctx->worker_timer_info ); } } static void TaskSwitch( rtems_tcb *executing, rtems_tcb *heir ) { (void) executing; (void) heir; CaptureWorkerState( T_fixture_context() ); } static void VerifyTaskPreparation( const Context *ctx ) { if ( ctx->id != INVALID_ID ) { States_Control state; Thread_Life_state life_state; state = STATES_READY; life_state = ctx->worker_tcb->Life.state; if ( ctx->suspended ) { state |= STATES_SUSPENDED; } if ( ctx->dormant ) { T_eq_int( life_state, 0 ); state |= STATES_DORMANT; } else { T_eq( ctx->protected, ( life_state & THREAD_LIFE_PROTECTED ) != 0 ); T_eq( ctx->restarting, ( life_state & THREAD_LIFE_RESTARTING ) != 0 ); T_eq( ctx->terminating, ( life_state & THREAD_LIFE_TERMINATING ) != 0 ); if ( ctx->blocked ) { if ( ctx->enqueued ) { state |= STATES_WAITING_FOR_MUTEX; } else { state |= STATES_WAITING_FOR_EVENT; } } } T_eq_u32( ctx->worker_tcb->current_state, state ); } } static void Fatal( rtems_fatal_source source, rtems_fatal_code code, void *arg ) { Context *ctx; T_eq_int( source, INTERNAL_ERROR_CORE ); T_eq_ulong( code, INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL ); ctx = arg; ++ctx->calls.fatal; T_assert_eq_int( ctx->calls.fatal, 1 ); longjmp( ctx->thread_dispatch_context, 1 ); } static void ResumeThreadDispatch( rtems_fatal_source source, rtems_fatal_code code, void *arg ) { Context *ctx; T_eq_int( source, INTERNAL_ERROR_CORE ); T_eq_ulong( code, INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL ); ctx = arg; SetFatalHandler( Fatal, ctx ); longjmp( ctx->thread_dispatch_context, 1 ); } static void Delete( void *arg ) { Context *ctx; T_scheduler_log *log; ctx = arg; if ( ctx->suspended && ctx->id != INVALID_ID ) { if ( ctx->id != RTEMS_SELF || ctx->interrupt ) { SuspendTask( ctx->worker_id ); } else { Per_CPU_Control *cpu_self; /* * Where the system was built with SMP support enabled, a suspended * executing thread during the ${../if/delete:/name} call can happen * if the thread was suspended by another processor and the * inter-processor interrupt did not yet arrive. Where the system was * built with SMP support disabled, this state cannot happen with the * current implementation. However, we still specify and validate this * behaviour unconditionally since there exist alternative * implementations which would lead to such a state if the executing * thread is suspended by an ISR. */ cpu_self = _Thread_Dispatch_disable(); SuspendSelf(); cpu_self->dispatch_necessary = false; _Thread_Dispatch_enable( cpu_self ); } } if ( ctx->dispatch_disabled ) { _Thread_Dispatch_disable(); } VerifyTaskPreparation( ctx ); ClearExtensionCalls( &ctx->calls ); log = T_scheduler_record_10( &ctx->scheduler_log ); T_null( log ); if ( setjmp( ctx->thread_dispatch_context ) == 0 ) { ctx->status = rtems_task_delete( ctx->id ); } else { _Thread_Dispatch_unnest( _Per_CPU_Get() ); } CaptureWorkerState( ctx ); if ( ctx->dispatch_disabled ) { _Thread_Dispatch_enable( _Per_CPU_Get() ); } } static void Block( Context *ctx ) { rtems_interval ticks; if ( ctx->timer_active ) { ticks = UINT32_MAX; } else { ticks = RTEMS_NO_TIMEOUT; } if ( ctx->enqueued ) { ObtainMutexTimed( ctx->mutex_id, ticks ); ctx->worker_is_mutex_owner = true; } else { /* * Do not use a stack variable for the event set, since we may jump out * of the directive call. */ (void) rtems_event_receive( RTEMS_ALL_EVENTS, RTEMS_EVENT_ANY | RTEMS_WAIT, ticks, &ctx->events ); } } static void BlockDone( Context *ctx ) { if ( ctx->enqueued ) { ReleaseMutex( ctx->mutex_id ); } } static void Signal( rtems_signal_set signals ) { Context *ctx; (void) signals; ctx = T_fixture_context(); if ( ctx->id == RTEMS_SELF ) { SetPriority( ctx->runner_id, PRIO_LOW ); if ( ctx->interrupt ) { if ( ctx->blocked ) { Per_CPU_Control *cpu_self; SetFatalHandler( ResumeThreadDispatch, ctx ); cpu_self = _Thread_Dispatch_disable(); if ( setjmp( ctx->thread_dispatch_context ) == 0 ) { Block( ctx ); } else { _Thread_Dispatch_unnest( cpu_self ); } CallWithinISR( Delete, ctx ); _Thread_Dispatch_direct( cpu_self ); BlockDone( ctx ); } else { CallWithinISR( Delete, ctx ); } } else { Delete( ctx ); } } else { if ( ctx->blocked ) { Block( ctx ); BlockDone( ctx ); } else { SetPriority( ctx->runner_id, PRIO_HIGH ); } } if ( ctx->protected ) { _Thread_Set_life_protection( 0 ); } } static void Deleter( rtems_task_argument arg ) { Context *ctx; ctx = (Context *) arg; if ( ctx != NULL ) { /* We have to prevent the priority boost in the task delete below */ SetPriority( ctx->runner_id, PRIO_LOW ); SetSelfPriorityNoYield( PRIO_NORMAL ); DeleteTask( ctx->worker_id ); } SuspendSelf(); } static void SecondDeleter( rtems_task_argument arg ) { Context *ctx; ctx = (Context *) arg; if ( ctx != NULL ) { if ( !ctx->vital_deleter_priority ) { SetPriority( ctx->runner_id, PRIO_LOW ); SetSelfPriorityNoYield( PRIO_NORMAL ); } Delete( ctx ); } SuspendSelf(); } static void Worker( rtems_task_argument arg ) { Context *ctx; ctx = T_fixture_context(); if ( arg != 0 ) { rtems_status_code sc; sc = rtems_signal_catch( Signal, RTEMS_NO_ASR ); T_rsc_success( sc ); if ( ctx->protected ) { _Thread_Set_life_protection( THREAD_LIFE_PROTECTED ); } Yield(); } if ( IsMutexOwner( ctx->mutex_id ) ) { ReleaseMutex( ctx->mutex_id ); } rtems_task_exit(); } static void ThreadDelete( rtems_tcb *executing, rtems_tcb *deleted ) { Context *ctx; ctx = T_fixture_context(); ++ctx->calls.thread_delete; T_eq_u32( executing->Object.id, ctx->runner_id ); if ( ctx->delete_worker_expected ) { T_eq_u32( deleted->Object.id, ctx->worker_id ); } } static void ThreadRestart( rtems_tcb *executing, rtems_tcb *restarted ) { Context *ctx; ctx = T_fixture_context(); ++ctx->calls.thread_restart; } static void ThreadTerminate( rtems_tcb *executing ) { Context *ctx; ctx = T_fixture_context(); ++ctx->calls.thread_terminate; T_eq_u32( executing->Object.id, ctx->worker_id ); if ( IsMutexOwner( ctx->mutex_id ) ) { ReleaseMutex( ctx->mutex_id ); } } static void Cleanup( Context *ctx ) { SetSelfPriority( PRIO_VERY_LOW ); if ( ( ctx->id == RTEMS_SELF || ctx->interrupt ) && ctx->suspended ) { ResumeTask( ctx->worker_id ); } if ( ctx->protected && ctx->blocked ) { if ( ctx->enqueued ) { ReleaseMutex( ctx->mutex_id ); ObtainMutex( ctx->mutex_id ); } else { SendEvents( ctx->worker_id, RTEMS_EVENT_0 ); } } if ( ctx->id == INVALID_ID || ( ctx->calls.thread_terminate == 0 && !( ctx->dormant && ctx->status != RTEMS_CALLED_FROM_ISR ) ) ) { DeleteTask( ctx->worker_id ); } SetSelfPriority( PRIO_NORMAL ); } static const rtems_extensions_table extensions = { .thread_delete = ThreadDelete, .thread_restart = ThreadRestart, .thread_terminate = ThreadTerminate }; test-target: testsuites/validation/tc-task-delete.c test-teardown: brief: null code: | rtems_status_code sc; sc = rtems_extension_delete( ctx->extension_id ); T_rsc_success( sc ); SetFatalHandler( NULL, NULL ); SetTaskSwitchExtension( NULL ); DeleteTask( ctx->deleter_id ); DeleteTask( ctx->deleter_2_id ); ReleaseMutex( ctx->mutex_id ); DeleteMutex( ctx->mutex_id ); RestoreRunnerASR(); RestoreRunnerPriority(); description: null text: ${.:text-template} transition-map: - enabled-by: true post-conditions: Status: - if: pre-conditions: Context: Interrupt then: CalledFromISR - else: NoReturn FatalError: - if: pre-conditions: Context: Task ThreadDispatch: Disabled then: 'Yes' - else: Nop Dormant: 'No' Suspended: - specified-by: Suspended Zombie: - if: pre-conditions: Context: Interrupt then: 'No' - if: pre-conditions: ThreadDispatch: Disabled then: 'No' - if: pre-conditions: Suspended: 'Yes' then: 'No' - else: 'Yes' TaskPriority: Nop State: - specified-by: State Timer: - if: pre-conditions: Context: Interrupt then-specified-by: Timer - else: Inactive Restarting: - specified-by: Restarting Terminating: - if: pre-conditions: Context: Interrupt then-specified-by: Terminating - else: 'Yes' Protected: - if: pre-conditions: Suspended: 'No' Context: Task ThreadDispatch: Enabled then: 'Yes' - specified-by: Protected RestartExtensions: Nop TerminateExtensions: - if: pre-conditions: Suspended: 'No' Context: Task ThreadDispatch: Enabled then: 'Yes' - else: Nop pre-conditions: Id: - Executing Dormant: - 'No' Suspended: all Restarting: all Terminating: all Protected: all Context: all State: all Timer: all CallerPriority: N/A ThreadDispatch: all - enabled-by: true post-conditions: Status: - if: pre-conditions: Context: Interrupt then: CalledFromISR - if: pre-conditions: ThreadDispatch: Disabled then: NoReturn - else: Ok FatalError: - if: pre-conditions: Context: Task ThreadDispatch: Disabled then: 'Yes' - else: Nop Dormant: 'No' Suspended: - if: pre-conditions: Context: Interrupt then-specified-by: Suspended - else: 'No' Zombie: 'No' TaskPriority: - if: pre-conditions: Context: Task CallerPriority: Vital then: Raise - else: Nop State: - if: pre-conditions: Context: Interrupt then-specified-by: State - if: pre-conditions: Protected: 'Yes' then-specified-by: State - else: Ready Timer: - if: pre-conditions: Context: Interrupt then-specified-by: Timer - if: pre-conditions: Protected: 'Yes' then-specified-by: Timer - else: Inactive Restarting: - specified-by: Restarting Terminating: - if: pre-conditions: Context: Task then: 'Yes' - specified-by: Terminating Protected: - specified-by: Protected RestartExtensions: Nop TerminateExtensions: - else: Nop pre-conditions: Id: - Other Dormant: - 'No' Suspended: all Restarting: all Terminating: all Protected: all Context: all State: all Timer: all CallerPriority: all ThreadDispatch: all - enabled-by: true post-conditions: Status: InvId FatalError: Nop Dormant: N/A Suspended: N/A Zombie: N/A TaskPriority: N/A State: N/A Timer: N/A Restarting: N/A Terminating: N/A Protected: N/A RestartExtensions: Nop TerminateExtensions: Nop pre-conditions: Id: - Invalid Dormant: N/A Suspended: N/A Restarting: N/A Terminating: N/A Protected: N/A Context: all State: N/A Timer: N/A CallerPriority: N/A ThreadDispatch: all - enabled-by: true post-conditions: Status: - if: pre-conditions: Context: Interrupt then: CalledFromISR - else: Ok FatalError: Nop Dormant: 'Yes' Suspended: - specified-by: Suspended Zombie: - if: pre-conditions: Context: Interrupt then: 'No' - else: 'Yes' TaskPriority: Nop State: Ready Timer: Inactive Restarting: 'No' Terminating: - if: pre-conditions: Context: Interrupt then: 'No' - else: 'Yes' Protected: 'No' RestartExtensions: Nop TerminateExtensions: Nop pre-conditions: Id: - Other Dormant: - 'Yes' Suspended: all Restarting: N/A Terminating: N/A Protected: N/A Context: all State: N/A Timer: N/A CallerPriority: all ThreadDispatch: all - enabled-by: true post-conditions: ExecutingIsNotDormant pre-conditions: Id: - Executing Dormant: - 'Yes' Suspended: all Restarting: all Terminating: all Protected: all Context: all State: all Timer: all CallerPriority: all ThreadDispatch: all - enabled-by: true post-conditions: ExecutingIsNotBlocked pre-conditions: Id: - Executing Dormant: - 'No' Suspended: all Restarting: all Terminating: all Protected: all Context: - Task State: - Blocked - Enqueued Timer: all CallerPriority: all ThreadDispatch: all - enabled-by: true post-conditions: NotBlockedHasInactiveTimer pre-conditions: Id: - Executing - Other Dormant: - 'No' Suspended: all Restarting: all Terminating: all Protected: all Context: all State: - Ready Timer: - Active CallerPriority: all ThreadDispatch: all - enabled-by: true post-conditions: ThreadDispatchDisabled pre-conditions: Id: all Dormant: all Suspended: all Restarting: all Terminating: all Protected: all Context: - Interrupt State: all Enqueued: all Timer: all CallerPriority: all ThreadDispatch: - Enabled type: requirement