File indexing completed on 2025-05-11 08:24:22
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 #ifdef HAVE_CONFIG_H
0042 #include "config.h"
0043 #endif
0044
0045 #include <pthread.h>
0046 #include <errno.h>
0047
0048 #include <rtems/posix/posixapi.h>
0049 #include <rtems/posix/priorityimpl.h>
0050 #if defined(RTEMS_POSIX_API)
0051 #include <rtems/posix/psignalimpl.h>
0052 #endif
0053 #include <rtems/posix/pthreadimpl.h>
0054 #include <rtems/posix/pthreadattrimpl.h>
0055 #include <rtems/score/assert.h>
0056 #include <rtems/score/threadcpubudget.h>
0057 #include <rtems/score/threadimpl.h>
0058 #include <rtems/score/apimutex.h>
0059 #include <rtems/score/stackimpl.h>
0060 #include <rtems/score/statesimpl.h>
0061 #include <rtems/score/schedulerimpl.h>
0062 #include <rtems/score/userextimpl.h>
0063 #include <rtems/sysinit.h>
0064
0065 #include <string.h>
0066
0067 static inline size_t _POSIX_Threads_Ensure_minimum_stack (
0068 size_t size
0069 )
0070 {
0071 if ( size >= PTHREAD_MINIMUM_STACK_SIZE )
0072 return size;
0073 return PTHREAD_MINIMUM_STACK_SIZE;
0074 }
0075
0076
0077 int pthread_create(
0078 pthread_t *thread,
0079 const pthread_attr_t *attr,
0080 void *(*start_routine)( void * ),
0081 void *arg
0082 )
0083 {
0084 Thread_Entry_information entry = {
0085 .adaptor = _Thread_Entry_adaptor_pointer,
0086 .Kinds = {
0087 .Pointer = {
0088 .entry = start_routine,
0089 .argument = arg
0090 }
0091 }
0092 };
0093 const pthread_attr_t *the_attr;
0094 int normal_prio;
0095 bool valid;
0096 Thread_Configuration config;
0097 Status_Control status;
0098 Thread_Control *the_thread;
0099 Thread_Control *executing;
0100 int schedpolicy = SCHED_RR;
0101 struct sched_param schedparam;
0102 int error;
0103 ISR_lock_Context lock_context;
0104 #if defined(RTEMS_POSIX_API)
0105 int low_prio;
0106 Priority_Control core_low_prio;
0107 POSIX_API_Control *api;
0108 #endif
0109
0110 if ( !start_routine )
0111 return EFAULT;
0112
0113 the_attr = (attr) ? attr : &_POSIX_Threads_Default_attributes;
0114
0115 if ( !the_attr->is_initialized )
0116 return EINVAL;
0117
0118 memset( &config, 0, sizeof( config ) );
0119
0120
0121
0122
0123
0124 config.is_fp = true;
0125
0126 config.is_preemptible = true;
0127
0128
0129
0130
0131
0132
0133
0134
0135 if ( the_attr->stackaddr != NULL ) {
0136 if ( !_Stack_Is_enough( the_attr->stacksize, config.is_fp ) ) {
0137 return EINVAL;
0138 }
0139
0140 config.stack_area = the_attr->stackaddr;
0141 config.stack_size = the_attr->stacksize;
0142 } else {
0143 config.stack_size = _POSIX_Threads_Ensure_minimum_stack(
0144 the_attr->stacksize
0145 );
0146 config.stack_size = _Stack_Extend_size( config.stack_size, config.is_fp );
0147 }
0148
0149 #if 0
0150 int cputime_clock_allowed;
0151 rtems_set_errno_and_return_minus_one( ENOSYS );
0152 #endif
0153
0154 executing = _Thread_Get_executing();
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164 switch ( the_attr->inheritsched ) {
0165 case PTHREAD_INHERIT_SCHED:
0166 error = pthread_getschedparam(
0167 pthread_self(),
0168 &schedpolicy,
0169 &schedparam
0170 );
0171 _Assert( error == 0 );
0172 (void) error;
0173 break;
0174
0175 case PTHREAD_EXPLICIT_SCHED:
0176 schedpolicy = the_attr->schedpolicy;
0177 schedparam = the_attr->schedparam;
0178 break;
0179
0180 default:
0181 return EINVAL;
0182 }
0183
0184
0185
0186
0187
0188 if ( the_attr->contentionscope != PTHREAD_SCOPE_PROCESS )
0189 return ENOTSUP;
0190
0191 error = _POSIX_Thread_Translate_sched_param(
0192 schedpolicy,
0193 &schedparam,
0194 &config
0195 );
0196 if ( error != 0 ) {
0197 return error;
0198 }
0199
0200 normal_prio = schedparam.sched_priority;
0201
0202 config.scheduler = _Thread_Scheduler_get_home( executing );
0203
0204 config.priority = _POSIX_Priority_To_core(
0205 config.scheduler,
0206 normal_prio,
0207 &valid
0208 );
0209 if ( !valid ) {
0210 return EINVAL;
0211 }
0212
0213 #if defined(RTEMS_POSIX_API)
0214 if ( schedpolicy == SCHED_SPORADIC ) {
0215 low_prio = schedparam.sched_ss_low_priority;
0216 } else {
0217 low_prio = normal_prio;
0218 }
0219
0220 core_low_prio = _POSIX_Priority_To_core( config.scheduler, low_prio, &valid );
0221 if ( !valid ) {
0222 return EINVAL;
0223 }
0224 #endif
0225
0226 if ( the_attr->affinityset == NULL ) {
0227 return EINVAL;
0228 }
0229
0230
0231
0232
0233
0234
0235 the_thread = _POSIX_Threads_Allocate();
0236 if ( !the_thread ) {
0237 _Objects_Allocator_unlock();
0238 return EAGAIN;
0239 }
0240
0241 if ( config.stack_area == NULL ) {
0242 config.stack_free = _Stack_Free;
0243 config.stack_area = _Stack_Allocate( config.stack_size );
0244 } else {
0245 config.stack_free = _Objects_Free_nothing;
0246 }
0247
0248 if ( config.stack_area == NULL ) {
0249 _Objects_Free( &_POSIX_Threads_Information.Objects, &the_thread->Object );
0250 _Objects_Allocator_unlock();
0251 return EAGAIN;
0252 }
0253
0254
0255
0256
0257 status = _Thread_Initialize(
0258 &_POSIX_Threads_Information,
0259 the_thread,
0260 &config
0261 );
0262 if ( status != STATUS_SUCCESSFUL ) {
0263 _Objects_Allocator_unlock();
0264 return _POSIX_Get_error( status );
0265 }
0266
0267 if ( the_attr->detachstate == PTHREAD_CREATE_DETACHED ) {
0268 the_thread->Life.state |= THREAD_LIFE_DETACHED;
0269 }
0270
0271 the_thread->Life.state |= THREAD_LIFE_CHANGE_DEFERRED;
0272
0273 _ISR_lock_ISR_disable( &lock_context );
0274 status = _Scheduler_Set_affinity(
0275 the_thread,
0276 the_attr->affinitysetsize,
0277 the_attr->affinityset
0278 );
0279 _ISR_lock_ISR_enable( &lock_context );
0280 if ( status != STATUS_SUCCESSFUL ) {
0281 _Thread_Free( &_POSIX_Threads_Information, the_thread );
0282 _RTEMS_Unlock_allocator();
0283 return EINVAL;
0284 }
0285
0286 the_thread->was_created_with_inherited_scheduler =
0287 ( the_attr->inheritsched == PTHREAD_INHERIT_SCHED );
0288
0289 #if defined(RTEMS_POSIX_API)
0290
0291
0292
0293 api = the_thread->API_Extensions[ THREAD_API_POSIX ];
0294
0295 _Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio );
0296 api->Sporadic.sched_ss_repl_period =
0297 the_attr->schedparam.sched_ss_repl_period;
0298 api->Sporadic.sched_ss_init_budget =
0299 the_attr->schedparam.sched_ss_init_budget;
0300 api->Sporadic.sched_ss_max_repl =
0301 the_attr->schedparam.sched_ss_max_repl;
0302
0303 if ( schedpolicy == SCHED_SPORADIC ) {
0304 #if defined(RTEMS_SCORE_THREAD_HAS_SCHEDULER_CHANGE_INHIBITORS)
0305 the_thread->is_scheduler_change_inhibited = true;
0306 #endif
0307 _POSIX_Threads_Sporadic_timer( &api->Sporadic.Timer );
0308 }
0309 #endif
0310
0311
0312
0313
0314 _ISR_lock_ISR_disable( &lock_context );
0315 status = _Thread_Start( the_thread, &entry, &lock_context );
0316
0317 #if defined(RTEMS_DEBUG)
0318
0319
0320
0321
0322
0323
0324 if ( status != STATUS_SUCCESSFUL ) {
0325 _Thread_Free( &_POSIX_Threads_Information, the_thread );
0326 _Objects_Allocator_unlock();
0327 return EINVAL;
0328 }
0329 #endif
0330
0331
0332
0333
0334 *thread = the_thread->Object.id;
0335
0336 _Objects_Allocator_unlock();
0337 return 0;
0338 }
0339
0340 #if defined(RTEMS_POSIX_API)
0341 void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
0342 {
0343 POSIX_API_Control *api;
0344 Thread_Control *the_thread;
0345 Thread_queue_Context queue_context;
0346
0347 api = RTEMS_CONTAINER_OF( watchdog, POSIX_API_Control, Sporadic.Timer );
0348 the_thread = api->Sporadic.thread;
0349
0350 _Thread_queue_Context_initialize( &queue_context );
0351 _Thread_queue_Context_clear_priority_updates( &queue_context );
0352 _Thread_Wait_acquire( the_thread, &queue_context );
0353
0354 if ( !_Priority_Node_is_active( &the_thread->Real_priority ) ) {
0355 _Thread_Priority_add(
0356 the_thread,
0357 &the_thread->Real_priority,
0358 &queue_context
0359 );
0360 _Thread_Priority_remove(
0361 the_thread,
0362 &api->Sporadic.Low_priority,
0363 &queue_context
0364 );
0365 }
0366
0367 _Watchdog_Per_CPU_remove_ticks( &api->Sporadic.Timer );
0368 _POSIX_Threads_Sporadic_timer_insert( the_thread, api );
0369
0370 _Thread_Wait_release( the_thread, &queue_context );
0371 _Thread_Priority_update( &queue_context );
0372 }
0373
0374 static void _POSIX_Threads_Sporadic_budget_callout(
0375 Thread_Control *the_thread
0376 )
0377 {
0378 POSIX_API_Control *api;
0379 Thread_queue_Context queue_context;
0380
0381 api = the_thread->API_Extensions[ THREAD_API_POSIX ];
0382
0383 _Thread_queue_Context_initialize( &queue_context );
0384 _Thread_queue_Context_clear_priority_updates( &queue_context );
0385 _Thread_Wait_acquire( the_thread, &queue_context );
0386
0387
0388
0389
0390
0391 the_thread->CPU_budget.available = UINT32_MAX;
0392
0393 if ( _Priority_Node_is_active( &the_thread->Real_priority ) ) {
0394 _Thread_Priority_add(
0395 the_thread,
0396 &api->Sporadic.Low_priority,
0397 &queue_context
0398 );
0399 _Thread_Priority_remove(
0400 the_thread,
0401 &the_thread->Real_priority,
0402 &queue_context
0403 );
0404 _Priority_Node_set_inactive( &the_thread->Real_priority );
0405 }
0406
0407 _Thread_Wait_release( the_thread, &queue_context );
0408 _Thread_Priority_update( &queue_context );
0409 }
0410
0411 static void _POSIX_Threads_Sporadic_budget_at_tick( Thread_Control *the_thread )
0412 {
0413 uint32_t budget_available;
0414
0415 if ( !the_thread->is_preemptible ) {
0416 return;
0417 }
0418
0419 if ( !_States_Is_ready( the_thread->current_state ) ) {
0420 return;
0421 }
0422
0423 budget_available = the_thread->CPU_budget.available;
0424
0425 if ( budget_available == 1 ) {
0426 the_thread->CPU_budget.available = 0;
0427 _POSIX_Threads_Sporadic_budget_callout ( the_thread );
0428 } else {
0429 the_thread->CPU_budget.available = budget_available - 1;
0430 }
0431 }
0432
0433 const Thread_CPU_budget_operations _POSIX_Threads_Sporadic_budget = {
0434 .at_tick = _POSIX_Threads_Sporadic_budget_at_tick,
0435 .at_context_switch = _Thread_CPU_budget_do_nothing,
0436 .initialize = _Thread_CPU_budget_do_nothing
0437 };
0438
0439 static bool _POSIX_Threads_Create_extension(
0440 Thread_Control *executing,
0441 Thread_Control *created
0442 )
0443 {
0444 POSIX_API_Control *api;
0445
0446 api = created->API_Extensions[ THREAD_API_POSIX ];
0447
0448 api->Sporadic.thread = created;
0449 _Watchdog_Preinitialize( &api->Sporadic.Timer, _Per_CPU_Get_by_index( 0 ) );
0450 _Watchdog_Initialize( &api->Sporadic.Timer, _POSIX_Threads_Sporadic_timer );
0451 _Priority_Node_set_inactive( &api->Sporadic.Low_priority );
0452
0453 #if defined(RTEMS_POSIX_API)
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474 if ( _Objects_Get_API(created->Object.id) == OBJECTS_INTERNAL_API ) {
0475
0476
0477
0478
0479
0480 api->signals_unblocked = 0;
0481 } else if ( _Objects_Get_API(executing->Object.id) == OBJECTS_INTERNAL_API ) {
0482
0483
0484
0485
0486
0487
0488
0489
0490 api->signals_unblocked = SIGNAL_ALL_MASK;
0491 } else {
0492 const POSIX_API_Control *executing_api;
0493
0494
0495
0496 executing_api = executing->API_Extensions[ THREAD_API_POSIX ];
0497 api->signals_unblocked = executing_api->signals_unblocked;
0498 }
0499 #endif
0500 return true;
0501 }
0502
0503 static void _POSIX_Threads_Terminate_extension( Thread_Control *executing )
0504 {
0505 POSIX_API_Control *api;
0506 ISR_lock_Context lock_context;
0507
0508 api = executing->API_Extensions[ THREAD_API_POSIX ];
0509
0510 _Thread_State_acquire( executing, &lock_context );
0511 _Watchdog_Per_CPU_remove_ticks( &api->Sporadic.Timer );
0512 _Thread_State_release( executing, &lock_context );
0513 }
0514 #endif
0515
0516 static void _POSIX_Threads_Exitted_extension(
0517 Thread_Control *executing
0518 )
0519 {
0520
0521
0522
0523
0524 if ( _Objects_Get_API( executing->Object.id ) == OBJECTS_POSIX_API )
0525 pthread_exit( executing->Wait.return_argument );
0526 }
0527
0528 static User_extensions_Control _POSIX_Threads_User_extensions = {
0529 .Callouts = {
0530 #if defined(RTEMS_POSIX_API)
0531 .thread_create = _POSIX_Threads_Create_extension,
0532 .thread_terminate = _POSIX_Threads_Terminate_extension,
0533 #endif
0534 .thread_exitted = _POSIX_Threads_Exitted_extension
0535 }
0536 };
0537
0538 static void _POSIX_Threads_Manager_initialization( void )
0539 {
0540 _Thread_Initialize_information( &_POSIX_Threads_Information );
0541 _User_extensions_Add_API_set( &_POSIX_Threads_User_extensions );
0542 }
0543
0544 RTEMS_SYSINIT_ITEM(
0545 _POSIX_Threads_Manager_initialization,
0546 RTEMS_SYSINIT_POSIX_THREADS,
0547 RTEMS_SYSINIT_ORDER_MIDDLE
0548 );