Changeset 1b1be254 in rtems


Ignore:
Timestamp:
Mar 25, 2014, 9:54:49 AM (6 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, master
Children:
fb7199d
Parents:
226c731
git-author:
Sebastian Huber <sebastian.huber@…> (03/25/14 09:54:49)
git-committer:
Sebastian Huber <sebastian.huber@…> (03/31/14 06:29:43)
Message:

score: Thread life cycle re-implementation

The thread deletion is now supported on SMP.

This change fixes the following PRs:

PR1814: SMP race condition between stack free and dispatch

PR2035: psxcancel reveals NULL pointer access in _Thread_queue_Extract()

The POSIX cleanup handler are now called in the right context (should be
called in the context of the terminating thread).

http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html

Add a user extension the reflects a thread termination event. This is
used to reclaim the Newlib reentrancy structure (may use file
operations), the POSIX cleanup handlers and the POSIX key destructors.

Files:
1 deleted
25 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libcsupport/include/rtems/libcsupport.h

    r226c731 r1b1be254  
    8989  rtems_tcb *current_task,
    9090  rtems_tcb *deleted_task
     91);
     92
     93void newlib_terminate_hook(
     94  rtems_tcb *current_task
    9195);
    9296
     
    100104  __RTEMS_NEWLIB_BEGIN,   /* task_begin   */ \
    101105  0,                      /* task_exitted */ \
    102   0                       /* fatal        */ \
     106  0,                      /* fatal        */ \
     107  newlib_terminate_hook   /* thread terminate */ \
    103108}
    104109
  • cpukit/libcsupport/src/newlibc_reent.c

    r226c731 r1b1be254  
    6767)
    6868{
    69   struct _reent *ptr;
     69  (void) current_task;
    7070
    71   ptr = deleted_task->libc_reent;
    72   deleted_task->libc_reent = NULL;
     71  _Workspace_Free(deleted_task->libc_reent);
     72}
    7373
    74   _reclaim_reent(ptr);
    75   _Workspace_Free(ptr);
     74void newlib_terminate_hook(
     75  rtems_tcb *current_task
     76)
     77{
     78  _reclaim_reent(current_task->libc_reent);
    7679}
    7780
  • cpukit/libcsupport/src/resource_snapshot.c

    r226c731 r1b1be254  
    2323#include <rtems/libio_.h>
    2424#include <rtems/malloc.h>
     25#include <rtems/score/protectedheap.h>
     26#include <rtems/score/threadimpl.h>
    2527#include <rtems/score/wkspace.h>
    26 #include <rtems/score/protectedheap.h>
    2728
    2829#include <rtems/extensionimpl.h>
     
    117118  free_all_delayed_blocks();
    118119
     120  _Thread_Kill_zombies();
     121
    119122  _Protected_heap_Get_information(RTEMS_Malloc_Heap, &snapshot->heap_info);
    120123
  • cpukit/libmisc/monitor/mon-prmisc.c

    r226c731 r1b1be254  
    136136    { "Wisig",  STATES_INTERRUPTIBLE_BY_SIGNAL, 0 },
    137137    { "Wwkup",  STATES_WAITING_FOR_BSD_WAKEUP, 0 },
     138    { "Wterm",  STATES_WAITING_FOR_TERMINATION, 0 },
     139    { "ZOMBI",  STATES_ZOMBIE, 0 },
    138140    { 0, 0, 0 },
    139141};
  • cpukit/posix/include/rtems/posix/pthreadimpl.h

    r226c731 r1b1be254  
    2424#include <rtems/posix/threadsup.h>
    2525#include <rtems/score/objectimpl.h>
    26 #include <rtems/score/thread.h>
     26#include <rtems/score/threadimpl.h>
    2727#include <rtems/score/assert.h>
    2828
     
    218218RTEMS_INLINE_ROUTINE Thread_Control *_POSIX_Threads_Allocate( void )
    219219{
     220  _Thread_Kill_zombies();
     221
    220222  return (Thread_Control *) _Objects_Allocate( &_POSIX_Threads_Information );
    221223}
  • cpukit/posix/src/keyrundestructors.c

    r226c731 r1b1be254  
    88/*
    99 * Copyright (c) 2012 Zhongwei Yao.
    10  * Copyright (c) 2010 embedded brains GmbH.
     10 * Copyright (c) 2010-2014 embedded brains GmbH.
    1111 *
    1212 * COPYRIGHT (c) 1989-2014.
     
    2323
    2424#include <rtems/posix/keyimpl.h>
     25#include <rtems/score/assert.h>
    2526#include <rtems/score/chainimpl.h>
    2627#include <rtems/score/thread.h>
     
    4546  Objects_Locations location;
    4647
    47   _Thread_Disable_dispatch();
    48 
    4948  chain = &thread->Key_Chain;
    5049  iter = (POSIX_Keys_Key_value_pair *) _Chain_First( chain );
     
    5251    next = (POSIX_Keys_Key_value_pair *)
    5352      _Chain_Next( &iter->Key_values_per_thread_node );
     53
     54    the_key = _POSIX_Keys_Get( iter->key, &location );
     55    _Assert( location == OBJECTS_LOCAL );
    5456
    5557    /**
     
    6567    _Chain_Extract_unprotected( &iter->Key_values_per_thread_node );
    6668
     69    destructor = the_key->destructor;
     70    value = iter->value;
     71
     72    _POSIX_Keys_Key_value_pair_free( iter );
     73
     74    _Objects_Put( &the_key->Object );
     75
    6776    /**
    6877     * run key value's destructor if destructor and value are both non-null.
    6978     */
    70     the_key = _POSIX_Keys_Get( iter->key, &location );
    71     destructor = the_key->destructor;
    72     value = iter->value;
    7379    if ( destructor != NULL && value != NULL )
    7480      (*destructor)( value );
    7581
    76     _Objects_Put( &the_key->Object );
    77 
    78     _POSIX_Keys_Key_value_pair_free( iter );
    79 
    8082    iter = next;
    8183  }
    82 
    83   _Thread_Enable_dispatch();
    8484}
  • cpukit/posix/src/pthread.c

    r226c731 r1b1be254  
    275275)
    276276{
     277  _Workspace_Free( deleted->API_Extensions[ THREAD_API_POSIX ] );
     278}
     279
     280static void _POSIX_Threads_Terminate_extension(
     281  Thread_Control *executing
     282)
     283{
    277284  Thread_Control     *the_thread;
    278285  POSIX_API_Control  *api;
    279286  void              **value_ptr;
    280287
    281   api = deleted->API_Extensions[ THREAD_API_POSIX ];
     288  api = executing->API_Extensions[ THREAD_API_POSIX ];
    282289
    283290  /*
    284291   *  Run the POSIX cancellation handlers
    285292   */
    286   _POSIX_Threads_cancel_run( deleted );
     293  _POSIX_Threads_cancel_run( executing );
     294
     295  _Thread_Disable_dispatch();
    287296
    288297  /*
    289298   *  Wakeup all the tasks which joined with this one
    290299   */
    291   value_ptr = (void **) deleted->Wait.return_argument;
     300  value_ptr = (void **) executing->Wait.return_argument;
    292301
    293302  while ( (the_thread = _Thread_queue_Dequeue( &api->Join_List )) )
     
    297306    (void) _Watchdog_Remove( &api->Sporadic_timer );
    298307
    299   deleted->API_Extensions[ THREAD_API_POSIX ] = NULL;
    300 
    301   _Workspace_Free( api );
     308  _Thread_Enable_dispatch();
    302309}
    303310
     
    351358    NULL,                                     /* begin */
    352359    _POSIX_Threads_Exitted_extension,         /* exitted */
    353     NULL                                      /* fatal */
     360    NULL,                                     /* fatal */
     361    _POSIX_Threads_Terminate_extension        /* terminate */
    354362  }
    355363};
  • cpukit/posix/src/pthreadexit.c

    r226c731 r1b1be254  
    2222
    2323#include <rtems/posix/pthreadimpl.h>
     24#include <rtems/score/assert.h>
    2425#include <rtems/score/apimutex.h>
    2526#include <rtems/score/threadimpl.h>
     
    3132)
    3233{
    33   Objects_Information  *the_information;
    34   Thread_Control       *unblocked;
    35   POSIX_API_Control    *api;
    36 
    37   the_information = _Objects_Get_information_id( the_thread->Object.id );
     34  Thread_Control    *unblocked;
     35  POSIX_API_Control *api;
     36  bool               previous_life_protection;
    3837
    3938  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
    4039
     40  _Assert( _Debug_Is_thread_dispatching_allowed() );
     41
     42  previous_life_protection = _Thread_Set_life_protection( true );
     43  _Thread_Disable_dispatch();
     44
     45  the_thread->Wait.return_argument = value_ptr;
    4146
    4247  /*
    43    * The_information has to be non-NULL.  Otherwise, we couldn't be
    44    * running in a thread of this API and class.
    45    *
    46    * NOTE: Lock and unlock in different order so we do not throw a
    47    *       fatal error when locking the allocator mutex.  And after
    48    *       we unlock, we want to defer the context switch until we
    49    *       are ready to be switched out.  Otherwise, an ISR could
    50    *       occur and preempt us out while we still hold the
    51    *       allocator mutex.
     48   * Process join
    5249   */
     50  if ( api->detachstate == PTHREAD_CREATE_JOINABLE ) {
     51    unblocked = _Thread_queue_Dequeue( &api->Join_List );
     52    if ( unblocked ) {
     53      do {
     54        *(void **)unblocked->Wait.return_argument = value_ptr;
     55      } while ( (unblocked = _Thread_queue_Dequeue( &api->Join_List )) );
     56    } else {
     57      _Thread_Set_state(
     58        the_thread,
     59        STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_TRANSIENT
     60      );
     61      _Thread_Enable_dispatch();
     62      /* now waiting for thread to arrive */
     63      _Thread_Disable_dispatch();
     64    }
     65  }
    5366
    54   _RTEMS_Lock_allocator();
    55     _Thread_Disable_dispatch();
     67  /*
     68   *  Now shut down the thread
     69   */
     70  _Thread_Close( the_thread, _Thread_Executing );
    5671
    57       the_thread->Wait.return_argument = value_ptr;
    58 
    59       /*
    60        * Process join
    61        */
    62       if ( api->detachstate == PTHREAD_CREATE_JOINABLE ) {
    63         unblocked = _Thread_queue_Dequeue( &api->Join_List );
    64         if ( unblocked ) {
    65           do {
    66             *(void **)unblocked->Wait.return_argument = value_ptr;
    67           } while ( (unblocked = _Thread_queue_Dequeue( &api->Join_List )) );
    68         } else {
    69           _Thread_Set_state(
    70             the_thread,
    71             STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_TRANSIENT
    72           );
    73            /* FIXME: Lock order reversal */
    74            _RTEMS_Unlock_allocator();
    75           _Thread_Enable_dispatch();
    76           /* now waiting for thread to arrive */
    77           _RTEMS_Lock_allocator();
    78           _Thread_Disable_dispatch();
    79         }
    80       }
    81 
    82       /*
    83        *  Now shut down the thread
    84        */
    85       _Thread_Close( the_information, the_thread );
    86 
    87       _POSIX_Threads_Free( the_thread );
    88 
    89      /* FIXME: Lock order reversal */
    90     _RTEMS_Unlock_allocator();
    9172  _Thread_Enable_dispatch();
     73  _Thread_Set_life_protection( previous_life_protection );
    9274}
    9375
  • cpukit/rtems/include/rtems/rtems/tasksimpl.h

    r226c731 r1b1be254  
    2020#include <rtems/rtems/tasks.h>
    2121#include <rtems/score/objectimpl.h>
     22#include <rtems/score/threadimpl.h>
    2223
    2324#ifdef __cplusplus
     
    8586RTEMS_INLINE_ROUTINE Thread_Control *_RTEMS_tasks_Allocate( void )
    8687{
     88  _Thread_Kill_zombies();
     89
    8790  return (Thread_Control *) _Objects_Allocate( &_RTEMS_tasks_Information );
    8891}
  • cpukit/rtems/src/taskdelete.c

    r226c731 r1b1be254  
    2828)
    2929{
    30   Thread_Control          *the_thread;
    31   Objects_Locations        location;
    32   Objects_Information     *the_information;
     30  Thread_Control    *the_thread;
     31  Objects_Locations  location;
     32  bool               previous_life_protection;
    3333
    34 #if defined( RTEMS_SMP )
    35   if ( rtems_configuration_is_smp_enabled() ) {
    36     return RTEMS_NOT_IMPLEMENTED;
    37   }
    38 #endif
    39 
    40   _RTEMS_Lock_allocator();
    41 
     34  previous_life_protection = _Thread_Set_life_protection( true );
    4235  the_thread = _Thread_Get( id, &location );
    4336  switch ( location ) {
    4437
    4538    case OBJECTS_LOCAL:
    46       the_information = _Objects_Get_information_id( the_thread->Object.id );
    47 
    48       #if defined(RTEMS_DEBUG)
    49         if ( !the_information ) {
    50           _Objects_Put( &the_thread->Object );
    51           return RTEMS_INVALID_ID;
    52           /* This should never happen if _Thread_Get() works right */
    53         }
    54       #endif
    55 
    5639      #if defined(RTEMS_MULTIPROCESSING)
    5740        if ( the_thread->is_global ) {
     
    6548      #endif
    6649
    67       _Thread_Close( the_information, the_thread );
     50      _Thread_Close( the_thread, _Thread_Executing );
    6851
    69       _RTEMS_tasks_Free( the_thread );
    70 
    71       /* FIXME: Lock order reversal */
    72       _RTEMS_Unlock_allocator();
    7352      _Objects_Put( &the_thread->Object );
     53      _Thread_Set_life_protection( previous_life_protection );
    7454      return RTEMS_SUCCESSFUL;
    7555
    7656#if defined(RTEMS_MULTIPROCESSING)
    7757    case OBJECTS_REMOTE:
    78       _RTEMS_Unlock_allocator();
    7958      _Thread_Dispatch();
     59      _Thread_Set_life_protection( previous_life_protection );
    8060      return RTEMS_ILLEGAL_ON_REMOTE_OBJECT;
    8161#endif
     
    8565  }
    8666
    87   _RTEMS_Unlock_allocator();
     67  _Thread_Set_life_protection( previous_life_protection );
     68
    8869  return RTEMS_INVALID_ID;
    8970}
  • cpukit/rtems/src/tasks.c

    r226c731 r1b1be254  
    114114)
    115115{
     116  /*
     117   *  Free API specific memory
     118   */
     119
     120  (void) _Workspace_Free( deleted->API_Extensions[ THREAD_API_RTEMS ] );
     121}
     122
     123static void _RTEMS_tasks_Terminate_extension(
     124  Thread_Control *executing
     125)
     126{
    116127  rtems_task_variable_t *tvp, *next;
    117128
     
    120131   */
    121132
    122   tvp = deleted->task_variables;
    123   deleted->task_variables = NULL;
     133  tvp = executing->task_variables;
     134  executing->task_variables = NULL;
    124135  while (tvp) {
    125136    next = (rtems_task_variable_t *)tvp->next;
    126     _RTEMS_Tasks_Invoke_task_variable_dtor( deleted, tvp );
     137    _RTEMS_Tasks_Invoke_task_variable_dtor( executing, tvp );
    127138    tvp = next;
    128139  }
     
    131142   *  Run all the key destructors
    132143   */
    133   _POSIX_Keys_Run_destructors( deleted );
    134 
    135   /*
    136    *  Free API specific memory
    137    */
    138 
    139   (void) _Workspace_Free( deleted->API_Extensions[ THREAD_API_RTEMS ] );
    140   deleted->API_Extensions[ THREAD_API_RTEMS ] = NULL;
     144  _POSIX_Keys_Run_destructors( executing );
    141145}
    142146
     
    190194    NULL,                                     /* begin */
    191195    NULL,                                     /* exitted */
    192     NULL                                      /* fatal */
     196    NULL,                                     /* fatal */
     197    _RTEMS_tasks_Terminate_extension          /* terminate */
    193198  }
    194199};
  • cpukit/rtems/src/taskvariable_invoke_dtor.c

    r226c731 r1b1be254  
    3232
    3333  dtor = tvp->dtor;
    34   if (_Thread_Is_executing(the_thread)) {
     34  if (_Thread_Get_executing() == the_thread) {
    3535    value = *tvp->ptr;
    3636    *tvp->ptr = tvp->gval;
  • cpukit/score/Makefile.am

    r226c731 r1b1be254  
    273273## THREAD_C_FILES
    274274libscore_a_SOURCES += src/thread.c src/threadchangepriority.c \
    275     src/threadclearstate.c src/threadclose.c src/threadcreateidle.c \
     275    src/threadclearstate.c src/threadcreateidle.c \
    276276    src/threaddelayended.c src/threaddispatch.c \
    277277    src/threadenabledispatch.c src/threaddisabledispatch.c \
  • cpukit/score/include/rtems/score/statesimpl.h

    r226c731 r1b1be254  
    7979/** This macro corresponds to a task waiting for BSD wakeup. */
    8080#define STATES_WAITING_FOR_BSD_WAKEUP          0x80000
     81/** This macro corresponds to a task waiting for a task termination. */
     82#define STATES_WAITING_FOR_TERMINATION         0x100000
     83/** This macro corresponds to a task being a zombie. */
     84#define STATES_ZOMBIE                          0x200000
    8185
    8286/** This macro corresponds to a task which is in an interruptible
  • cpukit/score/include/rtems/score/thread.h

    r226c731 r1b1be254  
    1111 *  COPYRIGHT (c) 1989-2014.
    1212 *  On-Line Applications Research Corporation (OAR).
     13 *
     14 *  Copyright (c) 2014 embedded brains GmbH.
    1315 *
    1416 *  The license and distribution terms for this file may be
     
    397399} Thread_Action_control;
    398400
     401/**
     402 * @brief Thread life states.
     403 *
     404 * The thread life states are orthogonal to the thread states used for
     405 * synchronization primitives and blocking operations.  They reflect the state
     406 * changes triggered with thread restart and delete requests.
     407 */
     408typedef enum {
     409  THREAD_LIFE_NORMAL = 0x0,
     410  THREAD_LIFE_PROTECTED = 0x1,
     411  THREAD_LIFE_RESTARTING = 0x2,
     412  THREAD_LIFE_PROTECTED_RESTARTING = 0x3,
     413  THREAD_LIFE_TERMINATING = 0x4,
     414  THREAD_LIFE_PROTECTED_TERMINATING = 0x5,
     415  THREAD_LIFE_RESTARTING_TERMINTING = 0x6,
     416  THREAD_LIFE_PROTECTED_RESTARTING_TERMINTING = 0x7
     417} Thread_Life_state;
     418
     419/**
     420 * @brief Thread life control.
     421 */
    399422typedef struct {
     423  /**
     424   * @brief Thread life action used to react upon thread restart and delete
     425   * requests.
     426   */
    400427  Thread_Action      Action;
     428
     429  /**
     430   * @brief The current thread life state.
     431   */
     432  Thread_Life_state  state;
     433
     434  /**
     435   * @brief The terminator thread of this thread.
     436   *
     437   * In case the thread is terminated and another thread (the terminator) waits
     438   * for the actual termination completion, then this field references the
     439   * terminator thread.
     440   */
     441  Thread_Control    *terminator;
    401442} Thread_Life_control;
    402443
     
    471512   * remote processor needs help from an inter-processor interrupt, thus it
    472513   * will take some time to complete the state change.  A lot of things can
    473    * happen in the meantime.
    474    */
    475   bool                                  is_executing;
     514   * happen in the meantime.  This field is volatile since it is polled in
     515   * _Thread_Kill_zombies().
     516   */
     517  volatile bool                         is_executing;
    476518
    477519#if __RTEMS_HAVE_SYS_CPUSET_H__
  • cpukit/score/include/rtems/score/threadimpl.h

    r226c731 r1b1be254  
    1111 *  COPYRIGHT (c) 1989-2008.
    1212 *  On-Line Applications Research Corporation (OAR).
     13 *
     14 *  Copyright (c) 2014 embedded brains GmbH.
    1315 *
    1416 *  The license and distribution terms for this file may be
     
    195197);
    196198
     199bool _Thread_Set_life_protection( bool protect );
     200
    197201void _Thread_Life_action_handler(
    198202  Thread_Control  *executing,
     
    203207
    204208/**
    205  *  @brief Frees all memory associated with the specified thread.
    206  *
    207  *  This routine frees all memory associated with the specified
    208  *  thread and removes it from the local object table so no further
    209  *  operations on this thread are allowed.
    210  */
    211 void _Thread_Close(
    212   Objects_Information  *information,
    213   Thread_Control       *the_thread
    214 );
     209 * @brief Kills all zombie threads in the system.
     210 *
     211 * Threads change into the zombie state as the last step in the thread
     212 * termination sequence right before a context switch to the heir thread is
     213 * initiated.  Since the thread stack is still in use during this phase we have
     214 * to postpone the thread stack reclamation until this point.  On SMP
     215 * configurations we may have to busy wait for context switch completion here.
     216 */
     217void _Thread_Kill_zombies( void );
     218
     219/**
     220 * @brief Closes the thread.
     221 *
     222 * Closes the thread object and starts the thread termination sequence.  In
     223 * case the executing thread is not terminated, then this function waits until
     224 * the terminating thread reached the zombie state.
     225 */
     226void _Thread_Close( Thread_Control *the_thread, Thread_Control *executing );
    215227
    216228/**
     
    711723}
    712724
     725RTEMS_INLINE_ROUTINE bool _Thread_Is_life_restarting(
     726  Thread_Life_state life_state
     727)
     728{
     729  return ( life_state & THREAD_LIFE_RESTARTING ) != 0;
     730}
     731
     732RTEMS_INLINE_ROUTINE bool _Thread_Is_life_terminating(
     733  Thread_Life_state life_state
     734)
     735{
     736  return ( life_state & THREAD_LIFE_TERMINATING ) != 0;
     737}
     738
     739RTEMS_INLINE_ROUTINE bool _Thread_Is_life_protected(
     740  Thread_Life_state life_state
     741)
     742{
     743  return ( life_state & THREAD_LIFE_PROTECTED ) != 0;
     744}
     745
     746RTEMS_INLINE_ROUTINE bool _Thread_Is_life_changing(
     747  Thread_Life_state life_state
     748)
     749{
     750  return ( life_state & THREAD_LIFE_RESTARTING_TERMINTING ) != 0;
     751}
     752
    713753#if !defined(__DYNAMIC_REENT__)
    714754/**
  • cpukit/score/include/rtems/score/userext.h

    r226c731 r1b1be254  
    4444 *
    4545 * It corresponds to _Thread_Initialize() (used by the rtems_task_create()
    46  * directive).  The first parameter points to the currently executing thread
    47  * which created the new thread.  The second parameter points to the created
    48  * thread.
     46 * directive and pthread_create()).
    4947 *
    5048 * It is invoked after the new thread has been completely initialized, but
     
    6058 * It can be assumed that the executing thread locked the allocator mutex.
    6159 * The only exception is the creation of the idle thread.  In this case the
    62  * allocator mutex is not locked.  Since the allocator mutex is non-recursive,
    63  * it is prohibited to call the normal memory allocation routines.  It is
    64  * possible to use internal rountines like _Workspace_Allocate() or
    65  * _Heap_Allocate() for heaps which are protected by the allocator mutex.
    66  *
    67  * @retval true The thread create extension was successful.
     60 * allocator mutex is not locked.  Since the allocator mutex allows nesting the
     61 * normal memory allocation routines can be used.
     62 *
     63 * @param[in] executing The executing thread.
     64 * @param[in] created The created thread.
     65 *
     66 * @retval true Successful operation.
    6867 * @retval false A thread create user extension will frequently attempt to
    6968 * allocate resources.  If this allocation fails, then the extension should
     
    7170 */
    7271typedef bool ( *User_extensions_thread_create_extension )(
    73   Thread_Control *,
    74   Thread_Control *
     72  Thread_Control *executing,
     73  Thread_Control *created
    7574);
    7675
     
    7978 *
    8079 * It corresponds to _Thread_Close() (used by the rtems_task_delete()
    81  * directive).  The first parameter points to the currently executing thread
    82  * which deleted the thread.  The second parameter points to the deleted
    83  * thread.
    84  *
    85  * It is invoked before all resources of the thread are deleted.
     80 * directive, pthread_exit() and pthread_cancel()).
     81 *
     82 * It is invoked before all resources of the thread are deleted.  The executing
     83 * and deleted arguments are never equal.
    8684 *
    8785 * Thread dispatching is enabled.  The executing thread locked the allocator
    8886 * mutex.
     87 *
     88 * @param[in] executing The executing thread.
     89 * @param[in] deleted The deleted thread.
    8990 */
    9091typedef void( *User_extensions_thread_delete_extension )(
    91   Thread_Control *,
    92   Thread_Control *
     92  Thread_Control *executing,
     93  Thread_Control *deleted
    9394);
    9495
     
    9798 *
    9899 * It corresponds to _Thread_Start() (used by the rtems_task_start()
    99  * directive).  The first parameter points to the currently executing thread
    100  * which started the thread.  The second parameter points to the started
    101  * thread.
     100 * directive).
    102101 *
    103102 * It is invoked after the environment of the thread has been loaded and the
     
    106105 * Thread dispatching is disabled.  The executing thread is not the holder of
    107106 * the allocator mutex.
     107 *
     108 * @param[in] executing The executing thread.
     109 * @param[in] started The started thread.
    108110 */
    109111typedef void( *User_extensions_thread_start_extension )(
    110   Thread_Control *,
    111   Thread_Control *
     112  Thread_Control *executing,
     113  Thread_Control *started
    112114);
    113115
     
    116118 *
    117119 * It corresponds to _Thread_Restart() (used by the rtems_task_restart()
    118  * directive).  The first parameter points to the currently executing thread
    119  * which restarted the thread.  The second parameter points to the restarted
    120  * thread.
     120 * directive).
    121121 *
    122122 * It is invoked in the context of the restarted thread right before the
    123  * execution context is restarted.  The executing and restarted arguments are
    124  * equal.  The thread stack reflects the previous execution context.
     123 * execution context is reloaded.  The executing and restarted arguments are
     124 * always equal.  The thread stack reflects the previous execution context.
    125125 *
    126126 * Thread dispatching is enabled.  The thread is not the holder of the
    127  * allocator mutex.
     127 * allocator mutex.  The thread life is protected.  Thread restart and delete
     128 * requests issued by restart extensions lead to recursion.
     129 *
     130 * @param[in] executing The executing thread.
     131 * @param[in] restarted The executing thread.  Yes, the executing thread.
    128132 */
    129133typedef void( *User_extensions_thread_restart_extension )(
    130   Thread_Control *,
    131   Thread_Control *
     134  Thread_Control *executing,
     135  Thread_Control *restarted
    132136);
    133137
     
    135139 * @brief Task switch extension.
    136140 *
    137  * It corresponds to _Thread_Dispatch().  The first parameter points to the
    138  * currently executing thread.  The second parameter points to the heir thread.
     141 * It corresponds to _Thread_Dispatch().
    139142 *
    140143 * It is invoked before the context switch from the executing to the heir
     
    142145 *
    143146 * Thread dispatching is disabled.  The state of the allocator mutex is
    144  * arbitrary.
    145  *
    146  * The context switches initiated through _Thread_Start_multitasking() and
    147  * _Thread_Stop_multitasking() are not covered by this extension.  The
    148  * executing thread may run with a minimal setup, for example with a freed task
    149  * stack.
     147 * arbitrary.  Interrupts are disabled and the per-CPU lock is acquired on SMP
     148 * configurations.
     149 *
     150 * The context switches initiated through _Thread_Start_multitasking() are not
     151 * covered by this extension.
     152 *
     153 * @param[in] executing The executing thread.
     154 * @param[in] heir The heir thread.
    150155 */
    151156typedef void( *User_extensions_thread_switch_extension )(
    152   Thread_Control *,
    153   Thread_Control *
     157  Thread_Control *executing,
     158  Thread_Control *heir
    154159);
    155160
     
    157162 * @brief Task begin extension.
    158163 *
    159  * It corresponds to _Thread_Handler().  The first parameter points to the
    160  * currently executing thread which begins now execution.
     164 * It corresponds to _Thread_Handler().
    161165 *
    162166 * Thread dispatching is disabled.  The executing thread is not the holder of
    163167 * the allocator mutex.
     168 *
     169 * @param[in] executing The executing thread.
    164170 */
    165171typedef void( *User_extensions_thread_begin_extension )(
    166   Thread_Control *
     172  Thread_Control *executing
    167173);
    168174
     
    170176 * @brief Task exitted extension.
    171177 *
    172  * It corresponds to _Thread_Handler().  The first parameter points to the
    173  * currently executing thread which exitted before.
     178 * It corresponds to _Thread_Handler() after a return of the entry function.
    174179 *
    175180 * Thread dispatching is disabled.  The state of the allocator mutex is
    176181 * arbitrary.
     182 *
     183 * @param[in] executing The executing thread.
    177184 */
    178185typedef void( *User_extensions_thread_exitted_extension )(
    179   Thread_Control *
     186  Thread_Control *executing
    180187);
    181188
     
    183190 * @brief Fatal error extension.
    184191 *
    185  * It corresponds to _Terminate() (used by the
    186  * rtems_fatal_error_occurred() directive).  The first parameter contains the
    187  * error source.  The second parameter indicates if it was an internal error.
    188  * The third parameter contains the error code.
     192 * It corresponds to _Terminate() (used by the rtems_fatal() directive).
    189193 *
    190194 * This extension should not call any RTEMS directives.
     195 *
     196 * @param[in] source The fatal source indicating the subsystem the fatal
     197 * condition originated in.
     198 * @param[in] is_internal Indicates if the fatal condition was generated
     199 * internally to the executive.
     200 * @param[in] code The fatal error code.  This value must be interpreted with
     201 * respect to the source.
    191202 */
    192203typedef void( *User_extensions_fatal_extension )(
    193   Internal_errors_Source,
    194   bool,
    195   Internal_errors_t
     204  Internal_errors_Source source,
     205  bool                   is_internal,
     206  Internal_errors_t      code
     207);
     208
     209/**
     210 * @brief Task termination extension.
     211 *
     212 * This extension is invoked by _Thread_Life_action_handler() in case a
     213 * termination request is recognized.
     214 *
     215 * It is invoked in the context of the terminated thread right before the
     216 * thread dispatch to the heir thread.  The POSIX cleanup and key destructors
     217 * execute in this context.
     218 *
     219 * Thread dispatching is enabled.  The thread is not the holder of the
     220 * allocator mutex.  The thread life is protected.  Thread restart and delete
     221 * requests issued by terminate extensions lead to recursion.
     222 *
     223 * @param[in] terminated The terminated thread.
     224 */
     225typedef void( *User_extensions_thread_terminate_extension )(
     226  Thread_Control *terminated
    196227);
    197228
     
    208239  User_extensions_thread_exitted_extension thread_exitted;
    209240  User_extensions_fatal_extension          fatal;
     241  User_extensions_thread_terminate_extension thread_terminate;
    210242}   User_extensions_Table;
    211243
  • cpukit/score/include/rtems/score/userextimpl.h

    r226c731 r1b1be254  
    143143);
    144144
     145void _User_extensions_Thread_terminate_visitor(
     146  Thread_Control              *executing,
     147  void                        *arg,
     148  const User_extensions_Table *callouts
     149);
     150
    145151/**
    146152 * @brief Iterates through all user extensions and calls the visitor for each.
     
    240246}
    241247
     248static inline void _User_extensions_Thread_terminate(
     249  Thread_Control *executing
     250)
     251{
     252  _User_extensions_Iterate(
     253    executing,
     254    _User_extensions_Thread_terminate_visitor
     255  );
     256}
     257
    242258/** @} */
    243259
  • cpukit/score/src/heapfree.c

    r226c731 r1b1be254  
    8484    Heap_Block *const next = block->Protection_begin.next_delayed_free_block;
    8585
    86     /*
    87      * Sometimes after a free the allocated area is still in use.  An example
    88      * is the task stack of a thread that deletes itself.  The thread dispatch
    89      * disable level is a way to detect this use case.
    90      */
    91     if ( _Thread_Dispatch_is_enabled() ) {
    92       if ( next == NULL ) {
    93         _Heap_Protection_delay_block_free( heap, block );
    94         do_free = false;
    95       } else if ( next == HEAP_PROTECTION_OBOLUS ) {
    96         _Heap_Protection_check_free_block( heap, block );
    97       } else {
    98         _Heap_Protection_block_error( heap, block );
    99       }
    100     } else if ( next == NULL ) {
    101       /*
    102        * This is a hack to prevent heavy workspace fragmentation which would
    103        * lead to test suite failures.
    104        */
    105       _Heap_Protection_free_all_delayed_blocks( heap );
     86    if ( next == NULL ) {
     87      _Heap_Protection_delay_block_free( heap, block );
     88      do_free = false;
     89    } else if ( next == HEAP_PROTECTION_OBOLUS ) {
     90      _Heap_Protection_check_free_block( heap, block );
     91    } else {
     92      _Heap_Protection_block_error( heap, block );
    10693    }
    10794
  • cpukit/score/src/threadinitialize.c

    r226c731 r1b1be254  
    245245    _Thread_Life_action_handler
    246246  );
     247  the_thread->Life.state = THREAD_LIFE_NORMAL;
     248  the_thread->Life.terminator = NULL;
    247249
    248250  /*
  • cpukit/score/src/threadrestart.c

    r226c731 r1b1be254  
    1010 *  On-Line Applications Research Corporation (OAR).
    1111 *
     12 *  Copyright (c) 2014 embedded brains GmbH.
     13 *
    1214 *  The license and distribution terms for this file may be
    1315 *  found in the file LICENSE in this distribution or at
     
    2022
    2123#include <rtems/score/threadimpl.h>
     24#include <rtems/score/apimutex.h>
     25#include <rtems/score/assert.h>
     26#include <rtems/score/chainimpl.h>
     27#include <rtems/score/isrlock.h>
     28#include <rtems/score/schedulerimpl.h>
     29#include <rtems/score/sysstate.h>
    2230#include <rtems/score/threadqimpl.h>
    2331#include <rtems/score/userextimpl.h>
    2432#include <rtems/score/watchdogimpl.h>
     33#include <rtems/score/wkspace.h>
     34
     35typedef struct {
     36  Chain_Control Chain;
     37  ISR_lock_Control Lock;
     38} Thread_Zombie_control;
     39
     40static Thread_Zombie_control _Thread_Zombies = {
     41  .Chain = CHAIN_INITIALIZER_EMPTY( _Thread_Zombies.Chain ),
     42  .Lock = ISR_LOCK_INITIALIZER( "thread zombies" )
     43};
     44
     45static void _Thread_Make_zombie( Thread_Control *the_thread )
     46{
     47  ISR_lock_Context lock_context;
     48  Thread_Zombie_control *zombies = &_Thread_Zombies;
     49
     50  _Thread_Set_state( the_thread, STATES_ZOMBIE );
     51  _Thread_queue_Extract_with_proxy( the_thread );
     52  _Watchdog_Remove( &the_thread->Timer );
     53
     54  _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
     55  _Chain_Append_unprotected( &zombies->Chain, &the_thread->Object.Node );
     56  _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
     57}
     58
     59static void _Thread_Free( Thread_Control *the_thread )
     60{
     61  _User_extensions_Thread_delete( the_thread );
     62
     63  /*
     64   * Free the per-thread scheduling information.
     65   */
     66  _Scheduler_Free( the_thread );
     67
     68  /*
     69   *  The thread might have been FP.  So deal with that.
     70   */
     71#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
     72#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
     73  if ( _Thread_Is_allocated_fp( the_thread ) )
     74    _Thread_Deallocate_fp();
     75#endif
     76
     77  _Workspace_Free( the_thread->Start.fp_context );
     78#endif
     79
     80  /*
     81   *  Free the rest of the memory associated with this task
     82   *  and set the associated pointers to NULL for safety.
     83   */
     84  _Thread_Stack_Free( the_thread );
     85
     86  _Workspace_Free( the_thread->extensions );
     87
     88  _Workspace_Free( the_thread->Start.tls_area );
     89
     90  _Objects_Free(
     91    _Objects_Get_information_id( the_thread->Object.id ),
     92    &the_thread->Object
     93  );
     94}
     95
     96static void _Thread_Wait_for_execution_stop( Thread_Control *the_thread )
     97{
     98#if defined(RTEMS_SMP)
     99  /*
     100   * It is very unlikely that we see an executing thread here.  It can happen
     101   * in case the thread termination sequence is interrupted by a slow interrupt
     102   * service on a remote processor.
     103   */
     104  while (the_thread->is_executing) {
     105    /* Wait */
     106  }
     107#else
     108  (void) the_thread;
     109#endif
     110}
     111
     112void _Thread_Kill_zombies( void )
     113{
     114  ISR_lock_Context lock_context;
     115  Thread_Zombie_control *zombies = &_Thread_Zombies;
     116  Thread_Control *the_thread;
     117
     118  _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
     119
     120  the_thread = (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain );
     121  while ( the_thread != NULL ) {
     122    _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
     123
     124    _Thread_Wait_for_execution_stop( the_thread );
     125    _Thread_Free( the_thread );
     126
     127    _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
     128
     129    the_thread = (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain );
     130  }
     131
     132  _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
     133}
     134
     135static void _Thread_Start_life_change_for_executing(
     136  Thread_Control *executing
     137)
     138{
     139  _Assert( executing->Timer.state == WATCHDOG_INACTIVE );
     140  _Assert(
     141    executing->current_state == STATES_READY
     142      || executing->current_state == STATES_SUSPENDED
     143  );
     144
     145  _Thread_Add_post_switch_action( executing, &executing->Life.Action );
     146}
    25147
    26148void _Thread_Life_action_handler(
     
    31153)
    32154{
     155  Thread_Life_state previous_life_state;
     156
    33157  (void) action;
     158
     159  previous_life_state = executing->Life.state;
     160  executing->Life.state = THREAD_LIFE_PROTECTED;
     161
    34162  _Thread_Action_release_and_ISR_enable( cpu, level );
    35163
    36   _User_extensions_Thread_restart( the_thread );
     164  if ( _Thread_Is_life_terminating( previous_life_state ) ) {
     165    _User_extensions_Thread_terminate( executing );
     166  } else {
     167    _Assert( _Thread_Is_life_restarting( previous_life_state ) );
     168
     169    _User_extensions_Thread_restart( executing );
     170  }
    37171
    38172  _Thread_Disable_dispatch();
    39173
    40   _Thread_Load_environment( executing );
    41   _Thread_Restart_self( executing );
     174  if ( _Thread_Is_life_terminating( previous_life_state ) ) {
     175    _Thread_Make_zombie( executing );
     176
     177    if ( executing->Life.terminator != NULL ) {
     178      _Thread_Clear_state(
     179        executing->Life.terminator,
     180        STATES_WAITING_FOR_TERMINATION
     181      );
     182    }
     183
     184    _Thread_Enable_dispatch();
     185
     186    _Assert_Not_reached();
     187  } else {
     188    _Assert( _Thread_Is_life_restarting( previous_life_state ) );
     189
     190    if ( _Thread_Is_life_terminating( executing->Life.state ) ) {
     191      /* Someone deleted us in the mean-time */
     192      _Thread_Start_life_change_for_executing( executing );
     193    } else {
     194      _Assert( executing->Timer.state == WATCHDOG_INACTIVE );
     195      _Assert(
     196        executing->current_state == STATES_READY
     197          || executing->current_state == STATES_SUSPENDED
     198      );
     199
     200      executing->Life.state = THREAD_LIFE_NORMAL;
     201
     202      _Thread_Load_environment( executing );
     203      _Thread_Restart_self( executing );
     204
     205      _Assert_Not_reached();
     206    }
     207  }
    42208}
    43209
     
    56222  _Thread_queue_Extract_with_proxy( the_thread );
    57223  _Watchdog_Remove( &the_thread->Timer );
    58   _Thread_Set_priority( the_thread, priority );
     224  _Scheduler_Set_priority_if_higher( the_thread, priority );
    59225  _Thread_Add_post_switch_action( the_thread, &the_thread->Life.Action );
    60226  _Thread_Ready( the_thread );
     
    65231  Thread_Control    *the_thread,
    66232  Thread_Control    *executing,
    67   Priority_Control   priority
    68 )
    69 {
    70   _Thread_Start_life_change( the_thread, priority );
     233  Priority_Control   priority,
     234  Thread_Life_state  additional_life_state
     235)
     236{
     237  Thread_Life_state previous_life_state;
     238  Per_CPU_Control *cpu;
     239  ISR_Level level;
     240
     241  cpu = _Thread_Action_ISR_disable_and_acquire( the_thread, &level );
     242  previous_life_state = the_thread->Life.state;
     243  the_thread->Life.state = previous_life_state | additional_life_state;
     244  _Thread_Action_release_and_ISR_enable( cpu, level );
     245
     246  if ( the_thread == executing ) {
     247    executing->real_priority = priority;
     248
     249    _Scheduler_Set_priority_if_higher( the_thread, priority );
     250    _Thread_Start_life_change_for_executing( executing );
     251  } else if ( previous_life_state == THREAD_LIFE_NORMAL ) {
     252    _Thread_Start_life_change( the_thread, priority );
     253  } else {
     254    _Thread_Clear_state( the_thread, STATES_SUSPENDED );
     255
     256    if ( _Thread_Is_life_terminating( additional_life_state ) ) {
     257      the_thread->real_priority = _Scheduler_Highest_priority_of_two(
     258        the_thread->real_priority,
     259        priority
     260      );
     261
     262      _Scheduler_Change_priority_if_higher( the_thread, priority, false );
     263    }
     264  }
     265}
     266
     267void _Thread_Close( Thread_Control *the_thread, Thread_Control *executing )
     268{
     269  _Assert( _Thread_Is_life_protected( executing->Life.state ) );
     270
     271  _Objects_Close(
     272    _Objects_Get_information_id( the_thread->Object.id ),
     273    &the_thread->Object
     274  );
     275
     276  if ( _States_Is_dormant( the_thread->current_state ) ) {
     277    _Thread_Make_zombie( the_thread );
     278  } else {
     279    if (
     280      the_thread != executing
     281        && !_Thread_Is_life_terminating( executing->Life.state )
     282    ) {
     283      /*
     284       * Wait for termination of victim thread.  If the executing thread is
     285       * also terminated, then do not wait.  This avoids potential cyclic
     286       * dependencies and thus dead lock.
     287       */
     288       the_thread->Life.terminator = executing;
     289       _Thread_Set_state( executing, STATES_WAITING_FOR_TERMINATION );
     290    }
     291
     292    _Thread_Request_life_change(
     293      the_thread,
     294      executing,
     295      executing->current_priority,
     296      THREAD_LIFE_TERMINATING
     297    );
     298  }
    71299}
    72300
     
    85313      the_thread,
    86314      executing,
    87       the_thread->Start.initial_priority
     315      the_thread->Start.initial_priority,
     316      THREAD_LIFE_RESTARTING
    88317    );
    89318
     
    93322  return false;
    94323}
     324
     325bool _Thread_Set_life_protection( bool protect )
     326{
     327  bool previous_life_protection;
     328  ISR_Level level;
     329  Per_CPU_Control *cpu;
     330  Thread_Control *executing;
     331  Thread_Life_state previous_life_state;
     332
     333  cpu = _Thread_Action_ISR_disable_and_acquire_for_executing( &level );
     334  executing = cpu->executing;
     335
     336  previous_life_state = executing->Life.state;
     337  previous_life_protection = _Thread_Is_life_protected( previous_life_state );
     338
     339  if ( protect ) {
     340    executing->Life.state = previous_life_state | THREAD_LIFE_PROTECTED;
     341  } else {
     342    executing->Life.state = previous_life_state & ~THREAD_LIFE_PROTECTED;
     343  }
     344
     345  _Thread_Action_release_and_ISR_enable( cpu, level );
     346
     347#if defined(RTEMS_SMP)
     348  /*
     349   * On SMP configurations it is possible that a life change of an executing
     350   * thread is requested, but this thread didn't notice it yet.  The life
     351   * change is first marked in the life state field and then all scheduling and
     352   * other thread state updates are performed.  The last step is to issues an
     353   * inter-processor interrupt if necessary.  Since this takes some time we
     354   * have to synchronize here.
     355   */
     356  if (
     357    !_Thread_Is_life_protected( previous_life_state )
     358      && _Thread_Is_life_changing( previous_life_state )
     359  ) {
     360    _Thread_Disable_dispatch();
     361    _Thread_Enable_dispatch();
     362
     363    _Assert_Not_reached();
     364  }
     365#endif
     366
     367  if (
     368    !protect
     369      && _Thread_Is_life_changing( previous_life_state )
     370  ) {
     371    _Thread_Disable_dispatch();
     372    _Thread_Start_life_change_for_executing( executing );
     373    _Thread_Enable_dispatch();
     374
     375    _Assert_Not_reached();
     376  }
     377
     378  return previous_life_protection;
     379}
  • cpukit/score/src/userextiterate.c

    r226c731 r1b1be254  
    125125}
    126126
     127void _User_extensions_Thread_terminate_visitor(
     128  Thread_Control              *executing,
     129  void                        *arg,
     130  const User_extensions_Table *callouts
     131)
     132{
     133  User_extensions_thread_terminate_extension callout =
     134    callouts->thread_terminate;
     135
     136  if ( callout != NULL ) {
     137    (*callout)( executing );
     138  }
     139}
     140
    127141void _User_extensions_Iterate(
    128142  void                    *arg,
  • testsuites/psxtests/psxcleanup01/init.c

    r226c731 r1b1be254  
    9797
    9898  rtems_test_assert(restart_cleanup_arg == 1);
     99
     100  wait_for_restart_task();
     101
     102  sc = rtems_task_delete(id);
     103  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     104
     105  wait_for_restart_task();
     106
     107  rtems_test_assert(restart_cleanup_arg == 2);
    99108}
    100109
  • testsuites/smptests/smpthreadlife01/init.c

    r226c731 r1b1be254  
    2020
    2121#include <rtems.h>
     22#include <rtems/libcsupport.h>
    2223#include <rtems/score/smpbarrier.h>
    2324
     
    2930  volatile rtems_task_argument main_arg;
    3031  volatile rtems_task_argument worker_arg;
     32  volatile bool terminated;
    3133  SMP_barrier_Control barrier;
    3234  SMP_barrier_State worker_barrier_state;
     
    3739  .worker_barrier_state = SMP_BARRIER_STATE_INITIALIZER
    3840};
     41
     42static void restart_extension(
     43  Thread_Control *executing,
     44  Thread_Control *restarted
     45)
     46{
     47  rtems_test_assert(executing == restarted);
     48}
     49
     50static void delete_extension(
     51  Thread_Control *executing,
     52  Thread_Control *deleted
     53)
     54{
     55  rtems_test_assert(executing != deleted);
     56}
     57
     58static void terminate_extension(Thread_Control *executing)
     59{
     60  test_context *ctx = &test_instance;
     61
     62  ctx->terminated = true;
     63}
    3964
    4065static void worker_task(rtems_task_argument arg)
     
    6085  rtems_id id;
    6186  rtems_task_argument arg;
     87  rtems_resource_snapshot snapshot;
     88
     89  rtems_resource_snapshot_take(&snapshot);
    6290
    6391  sc = rtems_task_create(
     
    91119    rtems_test_assert(ctx->worker_arg == arg);
    92120  }
     121
     122  sc = rtems_task_delete(id);
     123  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     124
     125  rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
     126
     127  for (arg = 31; arg < 57; ++arg) {
     128    ctx->main_arg = arg;
     129    ctx->worker_arg = 0;
     130    ctx->terminated = false;
     131
     132    sc = rtems_task_create(
     133      rtems_build_name('W', 'O', 'R', 'K'),
     134      1,
     135      RTEMS_MINIMUM_STACK_SIZE,
     136      RTEMS_DEFAULT_MODES,
     137      RTEMS_DEFAULT_ATTRIBUTES,
     138      &id
     139    );
     140    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     141
     142    sc = rtems_task_start(id, worker_task, arg);
     143    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     144
     145    _SMP_barrier_Wait(&ctx->barrier, &barrier_state, CPU_COUNT);
     146
     147    rtems_test_assert(ctx->worker_arg == arg);
     148    rtems_test_assert(!ctx->terminated);
     149
     150    sc = rtems_task_delete(id);
     151    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     152
     153    rtems_test_assert(ctx->terminated);
     154
     155    rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
     156  }
    93157}
    94158
     
    114178#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
    115179
    116 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
     180#define CONFIGURE_INITIAL_EXTENSIONS \
     181  { \
     182    .thread_restart = restart_extension, \
     183    .thread_delete = delete_extension, \
     184    .thread_terminate = terminate_extension \
     185  }, \
     186  RTEMS_TEST_INITIAL_EXTENSION
    117187
    118188#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
  • testsuites/smptests/smpunsupported01/init.c

    r226c731 r1b1be254  
    2828
    2929  rtems_test_assert(rtems_configuration_is_smp_enabled());
    30 
    31   sc = rtems_task_delete(RTEMS_SELF);
    32   rtems_test_assert(sc == RTEMS_NOT_IMPLEMENTED);
    3330
    3431  sc = rtems_task_variable_add(RTEMS_SELF, NULL, NULL);
Note: See TracChangeset for help on using the changeset viewer.