From 54550e048d3a49435912797d2024f80671e93267 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 13 May 2016 08:16:30 +0200 Subject: posix: Rework pthread_join() Rework pthread_join() to use _Thread_Join(). Close #2402. Update #2555. Update #2626. Close #2714. --- cpukit/posix/include/rtems/posix/pthreadimpl.h | 14 --- cpukit/posix/include/rtems/posix/threadsup.h | 4 - cpukit/posix/src/pthread.c | 51 ++-------- cpukit/posix/src/pthreadcreate.c | 5 +- cpukit/posix/src/pthreaddetach.c | 39 ++++---- cpukit/posix/src/pthreadexit.c | 37 ++----- cpukit/posix/src/pthreadgetattrnp.c | 6 ++ cpukit/posix/src/pthreadjoin.c | 131 +++++++++++++------------ cpukit/rtems/src/taskdelete.c | 10 +- cpukit/score/include/rtems/score/statesimpl.h | 7 ++ cpukit/score/include/rtems/score/thread.h | 15 ++- cpukit/score/include/rtems/score/threadimpl.h | 20 +++- cpukit/score/src/threadrestart.c | 92 ++++++++++++++++- 13 files changed, 243 insertions(+), 188 deletions(-) diff --git a/cpukit/posix/include/rtems/posix/pthreadimpl.h b/cpukit/posix/include/rtems/posix/pthreadimpl.h index 42f10b08bc..16b0163384 100644 --- a/cpukit/posix/include/rtems/posix/pthreadimpl.h +++ b/cpukit/posix/include/rtems/posix/pthreadimpl.h @@ -35,8 +35,6 @@ extern "C" { */ /**@{**/ -#define POSIX_THREAD_JOIN_TQ_OPERATIONS &_Thread_queue_Operations_FIFO - /** * The following sets the minimum stack size for POSIX threads. */ @@ -211,18 +209,6 @@ RTEMS_INLINE_ROUTINE bool _POSIX_Threads_Is_null ( return !the_pthread; } -RTEMS_INLINE_ROUTINE Thread_Control *_POSIX_Threads_Join_dequeue( - POSIX_API_Control *api -) -{ - return _Thread_queue_Dequeue( - &api->Join_List, - POSIX_THREAD_JOIN_TQ_OPERATIONS, - NULL, - 0 - ); -} - /** @} */ #ifdef __cplusplus diff --git a/cpukit/posix/include/rtems/posix/threadsup.h b/cpukit/posix/include/rtems/posix/threadsup.h index 8109921270..3a7cfbc6dc 100644 --- a/cpukit/posix/include/rtems/posix/threadsup.h +++ b/cpukit/posix/include/rtems/posix/threadsup.h @@ -47,10 +47,6 @@ typedef struct { Thread_Control *thread; /** This is the POSIX threads attribute set. */ pthread_attr_t Attributes; - /** This indicates whether the thread is attached or detached. */ - int detachstate; - /** This is the set of threads waiting for the thread to exit. */ - Thread_queue_Control Join_List; /** This is the thread's current scheduling policy. */ int schedpolicy; /** This is the thread's current set of scheduling parameters. */ diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index 5c5cff71d2..12c5ace537 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -203,7 +203,6 @@ static bool _POSIX_Threads_Create_extension( /* XXX check all fields are touched */ api->thread = created; _POSIX_Threads_Initialize_attributes( &api->Attributes ); - api->detachstate = _POSIX_Threads_Default_attributes.detachstate; api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy; api->schedparam = _POSIX_Threads_Default_attributes.schedparam; api->schedparam.sched_priority = @@ -231,8 +230,6 @@ static bool _POSIX_Threads_Create_extension( api->signals_unblocked = executing_api->signals_unblocked; } - _Thread_queue_Initialize( &api->Join_List ); - _Watchdog_Preinitialize( &api->Sporadic_timer, _Per_CPU_Get_by_index( 0 ) ); _Watchdog_Initialize( &api->Sporadic_timer, @@ -242,42 +239,13 @@ static bool _POSIX_Threads_Create_extension( return true; } -static void _POSIX_Threads_Delete_extension( - Thread_Control *executing, - Thread_Control *deleted -) +static void _POSIX_Threads_Terminate_extension( Thread_Control *executing ) { POSIX_API_Control *api; - - api = deleted->API_Extensions[ THREAD_API_POSIX ]; - - _Thread_queue_Destroy( &api->Join_List ); -} - -static void _POSIX_Threads_Terminate_extension( - Thread_Control *executing -) -{ - Thread_Control *the_thread; - POSIX_API_Control *api; - ISR_lock_Context lock_context; - void **value_ptr; + ISR_lock_Context lock_context; api = executing->API_Extensions[ THREAD_API_POSIX ]; - _Thread_Disable_dispatch(); - - /* - * Wakeup all the tasks which joined with this one - */ - value_ptr = (void **) executing->Wait.return_argument; - - while ( ( the_thread = _POSIX_Threads_Join_dequeue( api ) ) ) { - *(void **)the_thread->Wait.return_argument = value_ptr; - } - - _Thread_Enable_dispatch(); - _Thread_State_acquire( executing, &lock_context ); if ( api->schedpolicy == SCHED_SPORADIC ) { @@ -305,17 +273,10 @@ static void _POSIX_Threads_Exitted_extension( } User_extensions_Control _POSIX_Threads_User_extensions = { - { NULL, NULL }, - { { NULL, NULL }, NULL }, - { _POSIX_Threads_Create_extension, /* create */ - NULL, /* start */ - NULL, /* restart */ - _POSIX_Threads_Delete_extension, /* delete */ - NULL, /* switch */ - NULL, /* begin */ - _POSIX_Threads_Exitted_extension, /* exitted */ - NULL, /* fatal */ - _POSIX_Threads_Terminate_extension /* terminate */ + .Callouts = { + .thread_create = _POSIX_Threads_Create_extension, + .thread_exitted = _POSIX_Threads_Exitted_extension, + .thread_terminate = _POSIX_Threads_Terminate_extension } }; diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c index eedb80e203..1fe3fe4465 100644 --- a/cpukit/posix/src/pthreadcreate.c +++ b/cpukit/posix/src/pthreadcreate.c @@ -201,6 +201,10 @@ int pthread_create( return EAGAIN; } + if ( the_attr->detachstate == PTHREAD_CREATE_DETACHED ) { + the_thread->Life.state |= THREAD_LIFE_DETACHED; + } + #if defined(RTEMS_SMP) && __RTEMS_HAVE_SYS_CPUSET_H__ _ISR_lock_ISR_disable( &lock_context ); status = _Scheduler_Set_affinity( @@ -222,7 +226,6 @@ int pthread_create( api = the_thread->API_Extensions[ THREAD_API_POSIX ]; _POSIX_Threads_Copy_attributes( &api->Attributes, the_attr ); - api->detachstate = the_attr->detachstate; api->schedpolicy = schedpolicy; api->schedparam = schedparam; diff --git a/cpukit/posix/src/pthreaddetach.c b/cpukit/posix/src/pthreaddetach.c index d8c6afb06e..fe2a590252 100644 --- a/cpukit/posix/src/pthreaddetach.c +++ b/cpukit/posix/src/pthreaddetach.c @@ -9,6 +9,8 @@ * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * + * Copyright (c) 2016 embedded brains GmbH. + * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. @@ -21,37 +23,30 @@ #include #include -#include #include /** * 16.1.4 Detaching a Thread, P1003.1c/Draft 10, p. 149 */ -int pthread_detach( - pthread_t thread -) +int pthread_detach( pthread_t thread ) { - Thread_Control *the_thread; - POSIX_API_Control *api; - Objects_Locations location; + Thread_Control *the_thread; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu_self; - the_thread = _Thread_Get( thread, &location ); - switch ( location ) { + the_thread = _Thread_Get_interrupt_disable( thread, &lock_context ); - case OBJECTS_LOCAL: + if ( the_thread == NULL ) { + return ESRCH; + } - api = the_thread->API_Extensions[ THREAD_API_POSIX ]; - api->detachstate = PTHREAD_CREATE_DETACHED; - api->Attributes.detachstate = PTHREAD_CREATE_DETACHED; - _Objects_Put( &the_thread->Object ); - return 0; + _Thread_State_acquire( the_thread, &lock_context ); -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; - } + the_thread->Life.state |= THREAD_LIFE_DETACHED; + _Thread_Clear_state_locked( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); - return ESRCH; + cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); + _Thread_State_release( the_thread, &lock_context ); + _Thread_Dispatch_enable( cpu_self ); + return 0; } diff --git a/cpukit/posix/src/pthreadexit.c b/cpukit/posix/src/pthreadexit.c index 559e37cc41..3c4d3ebaaf 100644 --- a/cpukit/posix/src/pthreadexit.c +++ b/cpukit/posix/src/pthreadexit.c @@ -31,47 +31,24 @@ void _POSIX_Thread_Exit( void *value_ptr ) { - Thread_Control *executing; - Thread_Control *unblocked; - POSIX_API_Control *api; - - api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + Thread_Control *executing; + Per_CPU_Control *cpu_self; _Assert( _Debug_Is_thread_dispatching_allowed() ); - _Thread_Disable_dispatch(); - - the_thread->Wait.return_argument = value_ptr; - - /* - * Process join - */ - if ( api->detachstate == PTHREAD_CREATE_JOINABLE ) { - unblocked = _POSIX_Threads_Join_dequeue( api ); - if ( unblocked ) { - do { - *(void **)unblocked->Wait.return_argument = value_ptr; - } while ( ( unblocked = _POSIX_Threads_Join_dequeue( api ) ) ); - } else { - _Thread_Set_state( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); - _Thread_Enable_dispatch(); - /* now waiting for thread to arrive */ - _Thread_Disable_dispatch(); - } - } - - executing = _Thread_Executing; + cpu_self = _Thread_Dispatch_disable(); + executing = _Per_CPU_Get_executing( cpu_self ); /* * Now shut down the thread */ if ( the_thread == executing ) { - _Thread_Exit( executing ); + _Thread_Exit( executing, THREAD_LIFE_TERMINATING, value_ptr ); } else { - _Thread_Close( the_thread, executing ); + _Thread_Cancel( the_thread, executing, value_ptr ); } - _Thread_Enable_dispatch(); + _Thread_Dispatch_enable( cpu_self ); } void pthread_exit( diff --git a/cpukit/posix/src/pthreadgetattrnp.c b/cpukit/posix/src/pthreadgetattrnp.c index 57c53183ed..30cee97f06 100644 --- a/cpukit/posix/src/pthreadgetattrnp.c +++ b/cpukit/posix/src/pthreadgetattrnp.c @@ -49,6 +49,12 @@ int pthread_getattr_np( api = the_thread->API_Extensions[ THREAD_API_POSIX ]; _POSIX_Threads_Copy_attributes( attr, &api->Attributes); + if ( _Thread_Is_joinable( the_thread ) ) { + attr->detachstate = PTHREAD_CREATE_JOINABLE; + } else { + attr->detachstate = PTHREAD_CREATE_DETACHED; + } + _Thread_State_release( the_thread, &lock_context ); return 0; } diff --git a/cpukit/posix/src/pthreadjoin.c b/cpukit/posix/src/pthreadjoin.c index 877c4bda6a..8950be263e 100644 --- a/cpukit/posix/src/pthreadjoin.c +++ b/cpukit/posix/src/pthreadjoin.c @@ -11,6 +11,8 @@ * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * + * Copyright (c) 2016 embedded brains GmbH. + * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. @@ -23,74 +25,75 @@ #include #include -#include +#include #include -#include #include -int pthread_join( - pthread_t thread, - void **value_ptr -) +static int _POSIX_Threads_Join( pthread_t thread, void **value_ptr ) { - Thread_Control *the_thread; - POSIX_API_Control *api; - Objects_Locations location; - void *return_pointer; - Thread_Control *executing; - -on_EINTR: - the_thread = _Thread_Get( thread, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - api = the_thread->API_Extensions[ THREAD_API_POSIX ]; - - if ( api->detachstate == PTHREAD_CREATE_DETACHED ) { - _Objects_Put( &the_thread->Object ); - return EINVAL; - } - - executing = _Thread_Executing; - - if ( executing == the_thread ) { - _Objects_Put( &the_thread->Object ); - return EDEADLK; - } - - /* - * Put ourself on the threads join list - */ - - if ( the_thread->current_state == STATES_WAITING_FOR_JOIN_AT_EXIT ) { - return_pointer = the_thread->Wait.return_argument; - _Thread_Clear_state( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); - } else { - executing->Wait.return_argument = &return_pointer; - _Thread_queue_Enqueue( - &api->Join_List, - POSIX_THREAD_JOIN_TQ_OPERATIONS, - executing, - STATES_WAITING_FOR_JOIN | STATES_INTERRUPTIBLE_BY_SIGNAL, - WATCHDOG_NO_TIMEOUT, - 0 - ); - } - _Objects_Put( &the_thread->Object ); - - if ( executing->Wait.return_code == EINTR ) - goto on_EINTR; - - if ( value_ptr ) - *value_ptr = return_pointer; - return 0; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + Thread_Control *the_thread; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu_self; + Thread_Control *executing; + void *value; + + the_thread = _Thread_Get_interrupt_disable( thread, &lock_context ); + + if ( the_thread == NULL ) { + return ESRCH; + } + + cpu_self = _Per_CPU_Get(); + executing = _Per_CPU_Get_executing( cpu_self ); + + if ( executing == the_thread ) { + _ISR_lock_ISR_enable( &lock_context ); + return EDEADLK; + } + + _Thread_State_acquire_critical( the_thread, &lock_context ); + + if ( !_Thread_Is_joinable( the_thread ) ) { + _Thread_State_release( the_thread, &lock_context ); + return EINVAL; } - return ESRCH; + if ( _States_Is_waiting_for_join_at_exit( the_thread->current_state ) ) { + value = the_thread->Life.exit_value; + _Thread_Clear_state_locked( the_thread, STATES_WAITING_FOR_JOIN_AT_EXIT ); + _Thread_Dispatch_disable_with_CPU( cpu_self, &lock_context ); + _Thread_State_release( the_thread, &lock_context ); + _Thread_Dispatch_enable( cpu_self ); + } else { + _Thread_Join( + the_thread, + STATES_INTERRUPTIBLE_BY_SIGNAL | STATES_WAITING_FOR_JOIN, + executing, + &lock_context + ); + + if ( executing->Wait.return_code != 0 ) { + _Assert( executing->Wait.return_code == EINTR ); + return EINTR; + } + + value = executing->Wait.return_argument; + } + + if ( value_ptr != NULL ) { + *value_ptr = value; + } + + return 0; +} + +int pthread_join( pthread_t thread, void **value_ptr ) +{ + int error; + + do { + error = _POSIX_Threads_Join( thread, value_ptr ); + } while ( error == EINTR ); + + return error; } diff --git a/cpukit/rtems/src/taskdelete.c b/cpukit/rtems/src/taskdelete.c index 5830793688..2e8381cb81 100644 --- a/cpukit/rtems/src/taskdelete.c +++ b/cpukit/rtems/src/taskdelete.c @@ -52,7 +52,15 @@ rtems_status_code rtems_task_delete( executing = _Thread_Executing; if ( the_thread == executing ) { - _Thread_Exit( executing ); + /* + * The Classic tasks are neither detached nor joinable. In case of + * self deletion, they are detached, otherwise joinable by default. + */ + _Thread_Exit( + executing, + THREAD_LIFE_TERMINATING | THREAD_LIFE_DETACHED, + NULL + ); } else { _Thread_Close( the_thread, executing ); } diff --git a/cpukit/score/include/rtems/score/statesimpl.h b/cpukit/score/include/rtems/score/statesimpl.h index a560329a17..54052e2b74 100644 --- a/cpukit/score/include/rtems/score/statesimpl.h +++ b/cpukit/score/include/rtems/score/statesimpl.h @@ -385,6 +385,13 @@ RTEMS_INLINE_ROUTINE bool _States_Is_waiting_for_period ( return (the_states & STATES_WAITING_FOR_PERIOD); } +RTEMS_INLINE_ROUTINE bool _States_Is_waiting_for_join_at_exit( + States_Control the_states +) +{ + return ( the_states & STATES_WAITING_FOR_JOIN_AT_EXIT ) != 0; +} + /** * This function returns true if the task's state is set in * way that allows it to be interrupted by a signal. diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index dce3d3bd38..352fb2e434 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -525,7 +525,8 @@ typedef struct { typedef enum { THREAD_LIFE_PROTECTED = 0x1, THREAD_LIFE_RESTARTING = 0x2, - THREAD_LIFE_TERMINATING = 0x4 + THREAD_LIFE_TERMINATING = 0x4, + THREAD_LIFE_DETACHED = 0x10 } Thread_Life_state; /** @@ -547,6 +548,18 @@ typedef struct { * @brief The count of pending life change requests. */ uint32_t pending_life_change_requests; + +#if defined(RTEMS_POSIX_API) + /** + * @brief The thread exit value. + * + * It is, + * - the value passed to pthread_exit(), or + * - PTHREAD_CANCELED in case it is cancelled via pthread_cancel(), or + * - NULL. + */ + void *exit_value; +#endif } Thread_Life_control; #if defined(RTEMS_SMP) diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index e77352389c..cdd7f9b300 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -217,7 +217,11 @@ Thread_Life_state _Thread_Set_life_protection( Thread_Life_state state ); */ void _Thread_Kill_zombies( void ); -void _Thread_Exit( Thread_Control *executing ); +void _Thread_Exit( + Thread_Control *executing, + Thread_Life_state set, + void *exit_value +); void _Thread_Join( Thread_Control *the_thread, @@ -226,7 +230,11 @@ void _Thread_Join( ISR_lock_Context *lock_context ); -void _Thread_Cancel( Thread_Control *the_thread, Thread_Control *executing ); +void _Thread_Cancel( + Thread_Control *the_thread, + Thread_Control *executing, + void *exit_value +); /** * @brief Closes the thread. @@ -950,6 +958,14 @@ RTEMS_INLINE_ROUTINE bool _Thread_Is_life_changing( & ( THREAD_LIFE_RESTARTING | THREAD_LIFE_TERMINATING ) ) != 0; } +RTEMS_INLINE_ROUTINE bool _Thread_Is_joinable( + const Thread_Control *the_thread +) +{ + _Assert( _Thread_State_is_owner( the_thread ) ); + return ( the_thread->Life.state & THREAD_LIFE_DETACHED ) == 0; +} + /** * @brief Returns true if the thread owns resources, and false otherwise. * diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 4c105af12a..fbda7adbb8 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -88,17 +88,45 @@ static void _Thread_Raise_real_priority( typedef struct { ISR_lock_Context Base; +#if defined(RTEMS_POSIX_API) + void *exit_value; +#endif } Thread_Join_lock_context; +#if defined(RTEMS_POSIX_API) +static Thread_Control *_Thread_Join_flush_filter( + Thread_Control *the_thread, + Thread_queue_Queue *queue, + ISR_lock_Context *lock_context +) +{ + Thread_Join_lock_context *join_lock_context; + + join_lock_context = (Thread_Join_lock_context *) lock_context; + + the_thread->Wait.return_argument = join_lock_context->exit_value; + + return the_thread; +} +#endif + static void _Thread_Wake_up_joining_threads( Thread_Control *the_thread ) { Thread_Join_lock_context join_lock_context; +#if defined(RTEMS_POSIX_API) + join_lock_context.exit_value = the_thread->Life.exit_value; +#endif + _Thread_State_acquire( the_thread, &join_lock_context.Base ); _Thread_queue_Flush_critical( &the_thread->Join_queue.Queue, THREAD_JOIN_TQ_OPERATIONS, +#if defined(RTEMS_POSIX_API) + _Thread_Join_flush_filter, +#else _Thread_queue_Flush_default_filter, +#endif NULL, 0, &join_lock_context.Base @@ -256,6 +284,35 @@ static Thread_Life_state _Thread_Change_life_locked( return previous; } +static Per_CPU_Control *_Thread_Wait_for_join( + Thread_Control *executing, + Per_CPU_Control *cpu_self +) +{ +#if defined(RTEMS_POSIX_API) + ISR_lock_Context lock_context; + + _Thread_State_acquire( executing, &lock_context ); + + if ( + _Thread_Is_joinable( executing ) + && _Thread_queue_Is_empty( &executing->Join_queue.Queue ) + ) { + _Thread_Set_state_locked( executing, STATES_WAITING_FOR_JOIN_AT_EXIT ); + _Thread_State_release( executing, &lock_context ); + _Thread_Dispatch_enable( cpu_self ); + + /* Let other threads run */ + + cpu_self = _Thread_Dispatch_disable(); + } else { + _Thread_State_release( executing, &lock_context ); + } +#endif + + return cpu_self; +} + void _Thread_Life_action_handler( Thread_Control *executing, Thread_Action *action, @@ -283,6 +340,8 @@ void _Thread_Life_action_handler( cpu_self = _Thread_Dispatch_disable(); if ( _Thread_Is_life_terminating( previous_life_state ) ) { + cpu_self = _Thread_Wait_for_join( executing, cpu_self ); + _Thread_Make_zombie( executing ); _Thread_Dispatch_enable( cpu_self ); @@ -391,6 +450,11 @@ void _Thread_Join( _Assert( the_thread != executing ); _Assert( _Thread_State_is_owner( the_thread ) ); +#if defined(RTEMS_POSIX_API) + executing->Wait.return_code = 0; + executing->Wait.return_argument = NULL; +#endif + _Thread_queue_Enqueue_critical( &the_thread->Join_queue.Queue, THREAD_JOIN_TQ_OPERATIONS, @@ -402,7 +466,21 @@ void _Thread_Join( ); } -void _Thread_Cancel( Thread_Control *the_thread, Thread_Control *executing ) +static void _Thread_Set_exit_value( + Thread_Control *the_thread, + void *exit_value +) +{ +#if defined(RTEMS_POSIX_API) + the_thread->Life.exit_value = exit_value; +#endif +} + +void _Thread_Cancel( + Thread_Control *the_thread, + Thread_Control *executing, + void *exit_value +) { ISR_lock_Context lock_context; Thread_Life_state previous; @@ -413,6 +491,7 @@ void _Thread_Cancel( Thread_Control *the_thread, Thread_Control *executing ) _Thread_State_acquire( the_thread, &lock_context ); + _Thread_Set_exit_value( the_thread, exit_value ); previous = _Thread_Change_life_locked( the_thread, 0, @@ -454,10 +533,14 @@ void _Thread_Close( Thread_Control *the_thread, Thread_Control *executing ) executing, &lock_context ); - _Thread_Cancel( the_thread, executing ); + _Thread_Cancel( the_thread, executing, NULL ); } -void _Thread_Exit( Thread_Control *executing ) +void _Thread_Exit( + Thread_Control *executing, + Thread_Life_state set, + void *exit_value +) { ISR_lock_Context lock_context; @@ -470,10 +553,11 @@ void _Thread_Exit( Thread_Control *executing ) ); _Thread_State_acquire( executing, &lock_context ); + _Thread_Set_exit_value( executing, exit_value ); _Thread_Change_life_locked( executing, 0, - THREAD_LIFE_TERMINATING, + set, THREAD_LIFE_PROTECTED ); _Thread_State_release( executing, &lock_context ); -- cgit v1.2.3