summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-08-05 09:02:27 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-08-06 14:05:53 +0200
commit0e6a9822e98e5e52abfad686b25ffcf8c539f960 (patch)
tree38f0bc3be153d9a570e11fa09d92e761d8d0840f
parentspec: Use SetSelfPriorityNoYield() (diff)
downloadrtems-central-0e6a9822e98e5e52abfad686b25ffcf8c539f960.tar.bz2
spec: Specify rtems_task_delete()
-rw-r--r--spec/rtems/task/req/delete.yml1433
1 files changed, 1433 insertions, 0 deletions
diff --git a/spec/rtems/task/req/delete.yml b/spec/rtems/task/req/delete.yml
new file mode 100644
index 00000000..e717dd18
--- /dev/null
+++ b/spec/rtems/task/req/delete.yml
@@ -0,0 +1,1433 @@
+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: RealPriority
+ states:
+ - name: Raised
+ test-code: |
+ T_eq_u32( ctx->worker_priority, PRIO_ULTRA_HIGH );
+ text: |
+ The ${/glossary/priority-real:/term} of the task specified by the
+ ${../if/delete:/params[0]/name} parameter shall be raised to the
+ ${/glossary/priority-current:/term} of the caller of
+ ${../if/delete:/name}.
+ - name: Nop
+ test-code: |
+ T_eq_u32( ctx->worker_priority, PRIO_NORMAL );
+ text: |
+ The ${/glossary/priority-real:/term} 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: Higher
+ test-code: |
+ ctx->deleter_has_higher_priority = true;
+ text: |
+ While the ${/glossary/priority-current:/term} of the task calling
+ ${../if/delete:/name} is higher than the ${/glossary/priority-real:/term}
+ of the task specified by the ${../if/delete:/params[0]/name} parameter.
+ - name: LowerEqual
+ test-code: |
+ ctx->deleter_has_higher_priority = false;
+ text: |
+ While the ${/glossary/priority-current:/term} of the task calling
+ ${../if/delete:/name} is lower than or equal to the
+ ${/glossary/priority-real:/term} 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 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 higher current
+ priority than the real priority of the worker.
+ description: null
+ member: |
+ bool deleter_has_higher_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 );
+
+ SetFatalExtension( Fatal );
+ 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 RtemsTaskReqDelete_Context 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( ctx->worker_tcb->Real_priority.priority );
+ 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,
+ bool always_set_to_false,
+ rtems_fatal_code code
+ )
+ {
+ Context *ctx;
+
+ T_eq_int( source, INTERNAL_ERROR_CORE );
+ T_false( always_set_to_false );
+ T_eq_ulong( code, INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL );
+
+ ctx = T_fixture_context();
+ ++ctx->calls.fatal;
+ T_assert_eq_int( ctx->calls.fatal, 1 );
+
+ ctx = T_fixture_context();
+ longjmp( ctx->thread_dispatch_context, 1 );
+ }
+
+ static void ResumeThreadDispatch(
+ rtems_fatal_source source,
+ bool always_set_to_false,
+ rtems_fatal_code code
+ )
+ {
+ Context *ctx;
+
+ T_eq_int( source, INTERNAL_ERROR_CORE );
+ T_false( always_set_to_false );
+ T_eq_ulong( code, INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL );
+
+ SetFatalExtension( Fatal );
+
+ ctx = T_fixture_context();
+ 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 {
+ (void) ReceiveAnyEventsTimed( ticks );
+ }
+ }
+
+ 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;
+
+ SetFatalExtension( ResumeThreadDispatch );
+ 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->deleter_has_higher_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 );
+
+ SetFatalExtension( 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'
+ RealPriority: 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'
+ RealPriority:
+ - if:
+ pre-conditions:
+ Context: Task
+ CallerPriority: Higher
+ then: Raised
+ - 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
+ RealPriority: 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
+ - if:
+ pre-conditions:
+ Context: Task
+ ThreadDispatch: Disabled
+ then: NoReturn
+ - else: Ok
+ FatalError:
+ - if:
+ pre-conditions:
+ Context: Task
+ ThreadDispatch: Disabled
+ then: 'Yes'
+ - else: Nop
+ Dormant: 'Yes'
+ Suspended:
+ - specified-by: Suspended
+ Zombie:
+ - if:
+ pre-conditions:
+ Context: Interrupt
+ then: 'No'
+ - else: 'Yes'
+ RealPriority: 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