void *pthread_getspecific( pthread_key_t key ) { register POSIX_Keys_Control *the_key; uint32_t api; uint32_t index; Objects_Locations location; void *key_data; the_key = _POSIX_Keys_Get( key, &location ); switch ( location ) { case OBJECTS_LOCAL: api = _Objects_Get_API( _Thread_Executing->Object.id ); index = _Objects_Get_index( _Thread_Executing->Object.id ); key_data = (void *) the_key->Values[ api ][ index ]; _Thread_Enable_dispatch(); return key_data; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* should never happen */ #endif case OBJECTS_ERROR: break; } return NULL; }
static bool _Thread_Handler_is_constructor_execution_required( Thread_Control *executing ) { static bool doneConstructors; bool doCons = false; #if defined(RTEMS_SMP) static SMP_lock_Control constructor_lock = SMP_LOCK_INITIALIZER; if ( !doneConstructors ) { _SMP_lock_Acquire( &constructor_lock ); #endif #if defined(RTEMS_MULTIPROCESSING) doCons = !doneConstructors && _Objects_Get_API( executing->Object.id ) != OBJECTS_INTERNAL_API; if (doCons) doneConstructors = true; #else (void) executing; doCons = !doneConstructors; doneConstructors = true; #endif #if defined(RTEMS_SMP) _SMP_lock_Release( &constructor_lock ); } #endif return doCons; }
Objects_Information *_Objects_Get_information_id( Objects_Id id ) { return _Objects_Get_information( _Objects_Get_API( id ), _Objects_Get_class( id ) ); }
/** * This function maps thread IDs to thread control * blocks. If ID corresponds to a local thread, then it * returns the_thread control pointer which maps to ID * and location is set to OBJECTS_LOCAL. If the thread ID is * global and resides on a remote node, then location is set * to OBJECTS_REMOTE, and the_thread is undefined. * Otherwise, location is set to OBJECTS_ERROR and * the_thread is undefined. * * @note The performance of many RTEMS services depends upon * the quick execution of the "good object" path in this * routine. If there is a possibility of saving a few * cycles off the execution time, this routine is worth * further optimization attention. */ Thread_Control *_Thread_Get ( Objects_Id id, Objects_Locations *location ) { uint32_t the_api; uint32_t the_class; Objects_Information **api_information; Objects_Information *information; Thread_Control *tp = (Thread_Control *) 0; if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) { _Thread_Disable_dispatch(); *location = OBJECTS_LOCAL; tp = _Thread_Executing; goto done; } the_api = _Objects_Get_API( id ); if ( !_Objects_Is_api_valid( the_api ) ) { *location = OBJECTS_ERROR; goto done; } the_class = _Objects_Get_class( id ); if ( the_class != 1 ) { /* threads are always first class :) */ *location = OBJECTS_ERROR; goto done; } api_information = _Objects_Information_table[ the_api ]; /* * There is no way for this to happen if POSIX is enabled. But there * is actually a test case in sp43 for this which trips it whether or * not POSIX is enabled. So in the interest of safety, this is left * on in all configurations. */ if ( !api_information ) { *location = OBJECTS_ERROR; goto done; } information = api_information[ the_class ]; if ( !information ) { *location = OBJECTS_ERROR; goto done; } tp = (Thread_Control *) _Objects_Get( information, id, location ); done: return tp; }
Objects_Name_or_id_lookup_errors _Objects_Id_to_name ( Objects_Id id, Objects_Name *name ) { uint32_t the_api; uint32_t the_class; Objects_Id tmpId; Objects_Information *information; Objects_Control *the_object = (Objects_Control *) 0; Objects_Locations ignored_location; ISR_lock_Context lock_context; /* * Caller is trusted for name != NULL. */ tmpId = (id == OBJECTS_ID_OF_SELF) ? _Thread_Get_executing()->Object.id : id; the_api = _Objects_Get_API( tmpId ); if ( !_Objects_Is_api_valid( the_api ) ) return OBJECTS_INVALID_ID; if ( !_Objects_Information_table[ the_api ] ) return OBJECTS_INVALID_ID; the_class = _Objects_Get_class( tmpId ); information = _Objects_Information_table[ the_api ][ the_class ]; if ( !information ) return OBJECTS_INVALID_ID; #if defined(RTEMS_SCORE_OBJECT_ENABLE_STRING_NAMES) if ( information->is_string ) return OBJECTS_INVALID_ID; #endif the_object = _Objects_Get_isr_disable( information, tmpId, &ignored_location, &lock_context ); if ( !the_object ) return OBJECTS_INVALID_ID; *name = the_object->name; _ISR_lock_ISR_enable( &lock_context ); return OBJECTS_NAME_OR_ID_LOOKUP_SUCCESSFUL; }
Thread_Control *_Thread_Get ( Objects_Id id, Objects_Locations *location ) { uint32_t the_api; uint32_t the_class; Objects_Information **api_information; Objects_Information *information; Thread_Control *tp = (Thread_Control *) 0; if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) ) { _Thread_Disable_dispatch(); *location = OBJECTS_LOCAL; tp = _Thread_Executing; goto done; } the_api = _Objects_Get_API( id ); if ( !_Objects_Is_api_valid( the_api ) ) { *location = OBJECTS_ERROR; goto done; } the_class = _Objects_Get_class( id ); if ( the_class != 1 ) { /* threads are always first class :) */ *location = OBJECTS_ERROR; goto done; } api_information = _Objects_Information_table[ the_api ]; if ( !api_information ) { *location = OBJECTS_ERROR; goto done; } information = api_information[ the_class ]; if ( !information ) { *location = OBJECTS_ERROR; goto done; } tp = (Thread_Control *) _Objects_Get( information, id, location ); done: return tp; }
void _POSIX_Keys_Run_destructors( Thread_Control *thread ) { Objects_Maximum thread_index = _Objects_Get_index( thread->Object.id ); Objects_APIs thread_api = _Objects_Get_API( thread->Object.id ); bool done = false; /* * The standard allows one to avoid a potential infinite loop and limit the * number of iterations. An infinite loop may happen if destructors set * thread specific data. This can be considered dubious. * * Reference: 17.1.1.2 P1003.1c/Draft 10, p. 163, line 99. */ while ( !done ) { Objects_Maximum index = 0; Objects_Maximum max = _POSIX_Keys_Information.maximum; done = true; for ( index = 1 ; index <= max ; ++index ) { POSIX_Keys_Control *key = (POSIX_Keys_Control *) _POSIX_Keys_Information.local_table [ index ]; if ( key != NULL && key->destructor != NULL ) { void *value = key->Values [ thread_api ][ thread_index ]; if ( value != NULL ) { key->Values [ thread_api ][ thread_index ] = NULL; (*key->destructor)( value ); done = false; } } } } }
int rtems_object_id_get_api( rtems_id id ) { return _Objects_Get_API( id ); }
void _Thread_Handler( void ) { ISR_Level level; Thread_Control *executing; #if defined(EXECUTE_GLOBAL_CONSTRUCTORS) static bool doneConstructors; bool doCons; #endif executing = _Thread_Executing; /* * Some CPUs need to tinker with the call frame or registers when the * thread actually begins to execute for the first time. This is a * hook point where the port gets a shot at doing whatever it requires. */ _Context_Initialization_at_thread_begin(); /* * have to put level into a register for those cpu's that use * inline asm here */ level = executing->Start.isr_level; _ISR_Set_level(level); #if defined(EXECUTE_GLOBAL_CONSTRUCTORS) #if defined(RTEMS_MULTIPROCESSING) doCons = !doneConstructors && _Objects_Get_API( executing->Object.id ) != OBJECTS_INTERNAL_API; if (doCons) doneConstructors = true; #else doCons = !doneConstructors; doneConstructors = true; #endif #endif /* * Initialize the floating point context because we do not come * through _Thread_Dispatch on our first invocation. So the normal * code path for performing the FP context switch is not hit. */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) if ( (executing->fp_context != NULL) && !_Thread_Is_allocated_fp( executing ) ) { if ( _Thread_Allocated_fp != NULL ) _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); _Thread_Allocated_fp = executing; } #endif #endif /* * Take care that 'begin' extensions get to complete before * 'switch' extensions can run. This means must keep dispatch * disabled until all 'begin' extensions complete. */ _User_extensions_Thread_begin( executing ); /* * At this point, the dispatch disable level BETTER be 1. */ _Thread_Enable_dispatch(); #if defined(EXECUTE_GLOBAL_CONSTRUCTORS) /* * _init could be a weak symbol and we SHOULD test it but it isn't * in any configuration I know of and it generates a warning on every * RTEMS target configuration. --joel (12 May 2007) */ if (doCons) /* && (volatile void *)_init) */ { INIT_NAME (); } #endif /* * RTEMS supports multiple APIs and each API can define a different * thread/task prototype. The following code supports invoking the * user thread entry point using the prototype expected. */ if ( executing->Start.prototype == THREAD_START_NUMERIC ) { executing->Wait.return_argument = (*(Thread_Entry_numeric) executing->Start.entry_point)( executing->Start.numeric_argument ); } #if defined(RTEMS_POSIX_API) else if ( executing->Start.prototype == THREAD_START_POINTER ) { executing->Wait.return_argument = (*(Thread_Entry_pointer) executing->Start.entry_point)( executing->Start.pointer_argument ); } #endif #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) else if ( executing->Start.prototype == THREAD_START_BOTH_POINTER_FIRST ) { executing->Wait.return_argument = (*(Thread_Entry_both_pointer_first) executing->Start.entry_point)( executing->Start.pointer_argument, executing->Start.numeric_argument ); } else if ( executing->Start.prototype == THREAD_START_BOTH_NUMERIC_FIRST ) { executing->Wait.return_argument = (*(Thread_Entry_both_numeric_first) executing->Start.entry_point)( executing->Start.numeric_argument, executing->Start.pointer_argument ); } #endif /* * In the switch above, the return code from the user thread body * was placed in return_argument. This assumed that if it returned * anything (which is not supporting in all APIs), then it would be * able to fit in a (void *). */ _User_extensions_Thread_exitted( executing ); _Internal_error_Occurred( INTERNAL_ERROR_CORE, true, INTERNAL_ERROR_THREAD_EXITTED ); }