summaryrefslogblamecommitdiffstats
path: root/spec/rtems/task/req/delete.yml
blob: 105005216ed43e2e3a777eb27b3e6af0e8ca1a3b (plain) (tree)




































































                                                                               
                    
         
               


                                                        


                                                                           



                                                    
                                                 















































































































































































































                                                                                
               
                
                                         
           



                                                                        
                
                                          
           

                                                                             















































































































































































































                                                                               





                                                                               










































































































































                                                                               

                                                                            

                   
                               



































































                                                                             
                                  












                                                              
                                          













                                                           
                                                                            















































                                                                                

                            




                                            

                                                                         
              

                                           




                                               

                            




                                            

                                                                         

                                  






































































                                                                               









                                                                             























                                                
                                                       























































                                                                          
                                           

















































































































                                                                          
                                  









































                                    
                     









































































                                    
                 


                       

                               






















































                               
                     


























                            
              
                   








                             
                     

































































































                                             
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