diff options
Diffstat (limited to 'cpukit/posix/src/pthreadjoin.c')
-rw-r--r-- | cpukit/posix/src/pthreadjoin.c | 131 |
1 files changed, 67 insertions, 64 deletions
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 <pthread.h> #include <errno.h> -#include <rtems/posix/pthreadimpl.h> +#include <rtems/posix/threadsup.h> #include <rtems/score/threadimpl.h> -#include <rtems/score/threadqimpl.h> #include <rtems/score/statesimpl.h> -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; } |