static void test_watchdog_static_init( void ) { #if defined(RTEMS_USE_16_BIT_OBJECT) #define JUNK_ID 0x1234 #else #define JUNK_ID 0x12345678 #endif static Watchdog_Control a = WATCHDOG_INITIALIZER( test_watchdog_routine, JUNK_ID, (void *) 0xdeadbeef ); Watchdog_Control b; memset( &b, 0, sizeof( b ) ); _Watchdog_Initialize( &b, test_watchdog_routine, JUNK_ID, (void *) 0xdeadbeef ); rtems_test_assert( memcmp( &a, &b, sizeof( a ) ) == 0 ); }
rtems_status_code rtems_task_wake_after( rtems_interval ticks ) { /* * It is critical to obtain the executing thread after thread dispatching is * disabled on SMP configurations. */ Thread_Control *executing; Per_CPU_Control *cpu_self; cpu_self = _Thread_Dispatch_disable(); executing = _Thread_Executing; if ( ticks == 0 ) { _Thread_Yield( executing ); } else { _Thread_Set_state( executing, STATES_DELAYING ); _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); _Watchdog_Initialize( &executing->Timer, _Thread_Timeout, 0, executing ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; }
static void test_watchdog_init( test_watchdog *watchdog, int counter ) { _Watchdog_Preinitialize( &watchdog->Base, _Per_CPU_Get_snapshot() ); _Watchdog_Initialize( &watchdog->Base, test_watchdog_routine ); rtems_test_assert( test_watchdog_is_inactive( watchdog ) ) ; watchdog->counter = counter; }
boolean _Watchdog_Insert_ticks_helper( Watchdog_Control *timer, Watchdog_Interval ticks, Objects_Id id, Watchdog_Service_routine_entry TSR, void *arg ) { ISR_Level level; (void) _Watchdog_Remove( timer ); _ISR_Disable( level ); /* * Check to see if the watchdog has just been inserted by a * higher priority interrupt. If so, abandon this insert. */ if ( timer->state != WATCHDOG_INACTIVE ) { _ISR_Enable( level ); return FALSE; } /* * OK. Now we now the timer was not rescheduled by an interrupt * so we can atomically initialize it as in use. */ _Watchdog_Initialize( timer, TSR, id, arg ); _Watchdog_Insert_ticks( timer, ticks ); _ISR_Enable( level ); return TRUE; }
rtems_status_code rtems_timer_create( rtems_name name, rtems_id *id ) { Timer_Control *the_timer; if ( !rtems_is_name_valid( name ) ) return RTEMS_INVALID_NAME; if ( !id ) return RTEMS_INVALID_ADDRESS; _Thread_Disable_dispatch(); /* to prevent deletion */ the_timer = _Timer_Allocate(); if ( !the_timer ) { _Thread_Enable_dispatch(); return RTEMS_TOO_MANY; } the_timer->the_class = TIMER_DORMANT; _Watchdog_Initialize( &the_timer->Ticker, NULL, 0, NULL ); _Objects_Open( &_Timer_Information, &the_timer->Object, (Objects_Name) name ); *id = the_timer->Object.id; _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_timer_fire_after( rtems_id id, rtems_interval ticks, rtems_timer_service_routine_entry routine, void *user_data ) { Timer_Control *the_timer; Objects_Locations location; ISR_Level level; if ( ticks == 0 ) return RTEMS_INVALID_NUMBER; if ( !routine ) return RTEMS_INVALID_ADDRESS; the_timer = _Timer_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: _Timer_Cancel( the_timer ); _ISR_Disable( level ); /* * Check to see if the watchdog has just been inserted by a * higher priority interrupt. If so, abandon this insert. */ if ( the_timer->Ticker.state != WATCHDOG_INACTIVE ) { _ISR_Enable( level ); _Objects_Put( &the_timer->Object ); return RTEMS_SUCCESSFUL; } /* * OK. Now we now the timer was not rescheduled by an interrupt * so we can atomically initialize it as in use. */ the_timer->the_class = TIMER_INTERVAL; _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); _ISR_Enable( level ); _Watchdog_Insert_ticks( &the_timer->Ticker, ticks ); _Objects_Put( &the_timer->Object ); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* should never return this */ #endif case OBJECTS_ERROR: break; } return RTEMS_INVALID_ID; }
void _Thread_queue_Enqueue_with_handler( Thread_queue_Control *the_thread_queue, Watchdog_Interval timeout, Thread_queue_Timeout_callout handler ) { Thread_Control *the_thread; ISR_Level level; Thread_blocking_operation_States sync_state; Thread_blocking_operation_States (*enqueue_p)( Thread_queue_Control *, Thread_Control *, ISR_Level * ); the_thread = _Thread_Executing; #if defined(RTEMS_MULTIPROCESSING) if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) the_thread = _Thread_MP_Allocate_proxy( the_thread_queue->state ); else #endif /* * Set the blocking state for this thread queue in the thread. */ _Thread_Set_state( the_thread, the_thread_queue->state ); /* * If the thread wants to timeout, then schedule its timer. */ if ( timeout ) { _Watchdog_Initialize( &the_thread->Timer, handler, the_thread->Object.id, NULL ); _Watchdog_Insert_ticks( &the_thread->Timer, timeout ); } /* * Now enqueue the thread per the discipline for this thread queue. */ if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) enqueue_p = _Thread_queue_Enqueue_priority; else /* must be THREAD_QUEUE_DISCIPLINE_FIFO */ enqueue_p = _Thread_queue_Enqueue_fifo; sync_state = (*enqueue_p)( the_thread_queue, the_thread, &level ); if ( sync_state != THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) _Thread_blocking_operation_Cancel( sync_state, the_thread, level ); }
rtems_status_code rtems_timer_server_fire_when( rtems_id id, rtems_time_of_day *wall_time, rtems_timer_service_routine_entry routine, void *user_data ) { Timer_Control *the_timer; Objects_Locations location; rtems_interval seconds; Timer_server_Control *timer_server = _Timer_server; if ( !timer_server ) return RTEMS_INCORRECT_STATE; if ( !_TOD.is_set ) return RTEMS_NOT_DEFINED; if ( !routine ) return RTEMS_INVALID_ADDRESS; if ( !_TOD_Validate( wall_time ) ) return RTEMS_INVALID_CLOCK; seconds = _TOD_To_seconds( wall_time ); if ( seconds <= _TOD_Seconds_since_epoch() ) return RTEMS_INVALID_CLOCK; the_timer = _Timer_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: (void) _Watchdog_Remove( &the_timer->Ticker ); the_timer->the_class = TIMER_TIME_OF_DAY_ON_TASK; _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); the_timer->Ticker.initial = seconds - _TOD_Seconds_since_epoch(); (*timer_server->schedule_operation)( timer_server, the_timer ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* should never return this */ #endif case OBJECTS_ERROR: break; } return RTEMS_INVALID_ID; }
static void test_watchdog_static_init( void ) { static Watchdog_Control a = WATCHDOG_INITIALIZER( test_watchdog_routine ); Watchdog_Control b; memset( &b, 0, sizeof( b ) ); _Watchdog_Preinitialize( &b, _Per_CPU_Get_by_index( 0 ) ); _Watchdog_Initialize( &b, test_watchdog_routine ); rtems_test_assert( memcmp( &a, &b, sizeof( a ) ) == 0 ); }
rtems_status_code _Timer_Fire( rtems_id id, rtems_interval interval, rtems_timer_service_routine_entry routine, void *user_data, Timer_Classes the_class, Watchdog_Service_routine_entry adaptor ) { Timer_Control *the_timer; ISR_lock_Context lock_context; the_timer = _Timer_Get( id, &lock_context ); if ( the_timer != NULL ) { Per_CPU_Control *cpu; cpu = _Timer_Acquire_critical( the_timer, &lock_context ); _Timer_Cancel( cpu, the_timer ); _Watchdog_Initialize( &the_timer->Ticker, adaptor ); the_timer->the_class = the_class; the_timer->routine = routine; the_timer->user_data = user_data; the_timer->initial = interval; the_timer->start_time = _Timer_Get_CPU_ticks( cpu ); if ( _Timer_Is_interval_class( the_class ) ) { _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ], &the_timer->Ticker, cpu->Watchdog.ticks + interval ); } else { _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ], &the_timer->Ticker, _Watchdog_Realtime_from_seconds( interval ) ); } _Timer_Release( cpu, &lock_context ); return RTEMS_SUCCESSFUL; } return RTEMS_INVALID_ID; }
static void test_watchdog_static_init( void ) { static Watchdog_Control a = WATCHDOG_INITIALIZER( test_watchdog_routine, 0x12345678, (void *) 0xdeadbeef ); Watchdog_Control b; memset( &b, 0, sizeof( b ) ); _Watchdog_Initialize( &b, test_watchdog_routine, 0x12345678, (void *) 0xdeadbeef ); rtems_test_assert( memcmp( &a, &b, sizeof( a ) ) == 0 ); }
rtems_status_code rtems_rate_monotonic_create( rtems_name name, rtems_id *id ) { Rate_monotonic_Control *the_period; if ( !rtems_is_name_valid( name ) ) return RTEMS_INVALID_NAME; if ( !id ) return RTEMS_INVALID_ADDRESS; the_period = _Rate_monotonic_Allocate(); if ( !the_period ) { _Objects_Allocator_unlock(); return RTEMS_TOO_MANY; } _ISR_lock_Initialize( &the_period->Lock, "Rate Monotonic Period" ); _Priority_Node_initialize( &the_period->Priority, 0 ); _Priority_Node_set_inactive( &the_period->Priority ); the_period->owner = _Thread_Get_executing(); the_period->state = RATE_MONOTONIC_INACTIVE; _Watchdog_Preinitialize( &the_period->Timer, _Per_CPU_Get_by_index( 0 ) ); _Watchdog_Initialize( &the_period->Timer, _Rate_monotonic_Timeout ); _Rate_monotonic_Reset_statistics( the_period ); _Objects_Open( &_Rate_monotonic_Information, &the_period->Object, (Objects_Name) name ); *id = the_period->Object.id; _Objects_Allocator_unlock(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_task_wake_after( rtems_interval ticks ) { _Thread_Disable_dispatch(); if ( ticks == 0 ) { _Thread_Yield_processor(); } else { _Thread_Set_state( _Thread_Executing, STATES_DELAYING ); _Watchdog_Initialize( &_Thread_Executing->Timer, _Thread_Delay_ended, _Thread_Executing->Object.id, NULL ); _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks ); } _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_rate_monotonic_create( rtems_name name, rtems_id *id ) { Rate_monotonic_Control *the_period; if ( !rtems_is_name_valid( name ) ) return RTEMS_INVALID_NAME; if ( !id ) return RTEMS_INVALID_ADDRESS; _Thread_Disable_dispatch(); /* to prevent deletion */ the_period = _Rate_monotonic_Allocate(); if ( !the_period ) { _Thread_Enable_dispatch(); return RTEMS_TOO_MANY; } the_period->owner = _Thread_Executing; the_period->state = RATE_MONOTONIC_INACTIVE; _Watchdog_Initialize( &the_period->Timer, NULL, 0, NULL ); _Rate_monotonic_Reset_statistics( the_period ); _Objects_Open( &_Rate_monotonic_Information, &the_period->Object, (Objects_Name) name ); *id = the_period->Object.id; _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; }
rtems_status_code rtems_task_wake_when( rtems_time_of_day *time_buffer ) { Watchdog_Interval seconds; if ( !_TOD_Is_set() ) return RTEMS_NOT_DEFINED; if ( !time_buffer ) return RTEMS_INVALID_ADDRESS; time_buffer->ticks = 0; if ( !_TOD_Validate( time_buffer ) ) return RTEMS_INVALID_CLOCK; seconds = _TOD_To_seconds( time_buffer ); if ( seconds <= _TOD_Seconds_since_epoch() ) return RTEMS_INVALID_CLOCK; _Thread_Disable_dispatch(); _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_TIME ); _Watchdog_Initialize( &_Thread_Executing->Timer, _Thread_Delay_ended, _Thread_Executing->Object.id, NULL ); _Watchdog_Insert_seconds( &_Thread_Executing->Timer, seconds - _TOD_Seconds_since_epoch() ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; }
ER dly_tsk( DLYTIME dlytim ) { Watchdog_Interval ticks; ticks = TOD_MILLISECONDS_TO_TICKS(dlytim); _Thread_Disable_dispatch(); if ( ticks == 0 ) { _Thread_Yield_processor(); } else { _Thread_Set_state( _Thread_Executing, STATES_DELAYING ); _Watchdog_Initialize( &_Thread_Executing->Timer, _Thread_Delay_ended, _Thread_Executing->Object.id, NULL ); _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks ); } _Thread_Enable_dispatch(); return E_OK; }
rtems_status_code rtems_rate_monotonic_period( rtems_id id, rtems_interval length ) { Rate_monotonic_Control *the_period; Objects_Locations location; rtems_status_code return_value; rtems_rate_monotonic_period_states local_state; ISR_Level level; the_period = _Rate_monotonic_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( !_Thread_Is_executing( the_period->owner ) ) { _Thread_Enable_dispatch(); return RTEMS_NOT_OWNER_OF_RESOURCE; } if ( length == RTEMS_PERIOD_STATUS ) { switch ( the_period->state ) { case RATE_MONOTONIC_INACTIVE: return_value = RTEMS_NOT_DEFINED; break; case RATE_MONOTONIC_EXPIRED: case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING: return_value = RTEMS_TIMEOUT; break; case RATE_MONOTONIC_ACTIVE: default: /* unreached -- only to remove warnings */ return_value = RTEMS_SUCCESSFUL; break; } _Thread_Enable_dispatch(); return( return_value ); } _ISR_Disable( level ); if ( the_period->state == RATE_MONOTONIC_INACTIVE ) { _ISR_Enable( level ); the_period->next_length = length; /* * Baseline statistics information for the beginning of a period. */ _Rate_monotonic_Initiate_statistics( the_period ); the_period->state = RATE_MONOTONIC_ACTIVE; _Watchdog_Initialize( &the_period->Timer, _Rate_monotonic_Timeout, id, NULL ); _Watchdog_Insert_ticks( &the_period->Timer, length ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; } if ( the_period->state == RATE_MONOTONIC_ACTIVE ) { /* * Update statistics from the concluding period. */ _Rate_monotonic_Update_statistics( the_period ); /* * This tells the _Rate_monotonic_Timeout that this task is * in the process of blocking on the period and that we * may be changing the length of the next period. */ the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING; the_period->next_length = length; _ISR_Enable( level ); _Thread_Executing->Wait.id = the_period->Object.id; _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD ); /* * Did the watchdog timer expire while we were actually blocking * on it? */ _ISR_Disable( level ); local_state = the_period->state; the_period->state = RATE_MONOTONIC_ACTIVE; _ISR_Enable( level ); /* * If it did, then we want to unblock ourself and continue as * if nothing happen. The period was reset in the timeout routine. */ if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; } if ( the_period->state == RATE_MONOTONIC_EXPIRED ) { /* * Update statistics from the concluding period */ _Rate_monotonic_Update_statistics( the_period ); _ISR_Enable( level ); the_period->state = RATE_MONOTONIC_ACTIVE; the_period->next_length = length; _Watchdog_Insert_ticks( &the_period->Timer, length ); _Scheduler_Release_job(the_period->owner, the_period->next_length); _Thread_Enable_dispatch(); return RTEMS_TIMEOUT; } /* * These should never happen so just return invalid Id. * - RATE_MONOTONIC_OWNER_IS_BLOCKING: * - RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING: */ #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* should never return this */ #endif case OBJECTS_ERROR: break; } return RTEMS_INVALID_ID; }
/** * @brief rtems_timer_initiate_server * * This directive creates and starts the server for task-based timers. * It must be invoked before any task-based timers can be initiated. * * @param[in] priority is the timer server priority * @param[in] stack_size is the stack size in bytes * @param[in] attribute_set is the timer server attributes * * @return This method returns RTEMS_SUCCESSFUL if successful and an * error code otherwise. */ rtems_status_code rtems_timer_initiate_server( uint32_t priority, uint32_t stack_size, rtems_attribute attribute_set ) { rtems_id id; rtems_status_code status; rtems_task_priority _priority; static bool initialized = false; bool tmpInitialized; Timer_server_Control *ts = &_Timer_server_Default; /* * Make sure the requested priority is valid. The if is * structured so we check it is invalid before looking for * a specific invalid value as the default. */ _priority = priority; if ( !_RTEMS_tasks_Priority_is_valid( priority ) ) { if ( priority != RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) return RTEMS_INVALID_PRIORITY; _priority = 0; } /* * Just to make sure this is only called once. */ _Thread_Disable_dispatch(); tmpInitialized = initialized; initialized = true; _Thread_Enable_dispatch(); if ( tmpInitialized ) return RTEMS_INCORRECT_STATE; /* * Create the Timer Server with the name the name of "TIME". The attribute * RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it * higher than any other task in the system. It can be viewed as a low * priority interrupt. It is also always NO_PREEMPT so it looks like * an interrupt to other tasks. * * We allow the user to override the default priority because the Timer * Server can invoke TSRs which must adhere to language run-time or * other library rules. For example, if using a TSR written in Ada the * Server should run at the same priority as the priority Ada task. * Otherwise, the priority ceiling for the mutex used to protect the * GNAT run-time is violated. */ status = rtems_task_create( _Objects_Build_name('T','I','M','E'), /* "TIME" */ _priority, /* create with priority 1 since 0 is illegal */ stack_size, /* let user specify stack size */ RTEMS_NO_PREEMPT, /* no preempt is like an interrupt */ /* user may want floating point but we need */ /* system task specified for 0 priority */ attribute_set | RTEMS_SYSTEM_TASK, &id /* get the id back */ ); if (status) { initialized = false; return status; } /* * Do all the data structure initialization before starting the * Timer Server so we do not have to have a critical section. */ /* * We work with the TCB pointer, not the ID, so we need to convert * to a TCB pointer from here out. */ ts->thread = (Thread_Control *)_Objects_Get_local_object( &_RTEMS_tasks_Information, _Objects_Get_index(id) ); /* * Initialize the timer lists that the server will manage. */ _Chain_Initialize_empty( &ts->Interval_watchdogs.Chain ); _Chain_Initialize_empty( &ts->TOD_watchdogs.Chain ); /* * Initialize the timers that will be used to control when the * Timer Server wakes up and services the task-based timers. */ _Watchdog_Initialize( &ts->Interval_watchdogs.System_watchdog, _Thread_Delay_ended, id, NULL ); _Watchdog_Initialize( &ts->TOD_watchdogs.System_watchdog, _Thread_Delay_ended, id, NULL ); /* * Initialize the pointer to the timer schedule method so applications that * do not use the Timer Server do not have to pull it in. */ ts->schedule_operation = _Timer_server_Schedule_operation_method; ts->Interval_watchdogs.last_snapshot = _Watchdog_Ticks_since_boot; ts->TOD_watchdogs.last_snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); ts->insert_chain = NULL; ts->active = false; /* * The default timer server is now available. */ _Timer_server = ts; /* * Start the timer server */ status = rtems_task_start( id, _Timer_server_Body, (rtems_task_argument) ts ); #if defined(RTEMS_DEBUG) /* * One would expect a call to rtems_task_delete() here to clean up * but there is actually no way (in normal circumstances) that the * start can fail. The id and starting address are known to be * be good. If this service fails, something is weirdly wrong on the * target such as a stray write in an ISR or incorrect memory layout. */ if (status) { initialized = false; } #endif return status; }
void _Thread_queue_Enqueue( Thread_queue_Control *the_thread_queue, Thread_Control *the_thread, States_Control state, Watchdog_Interval timeout ) { ISR_lock_Context lock_context; Thread_blocking_operation_States sync_state; #if defined(RTEMS_MULTIPROCESSING) if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) the_thread = _Thread_MP_Allocate_proxy( state ); else #endif /* * Set the blocking state for this thread queue in the thread. */ _Thread_Set_state( the_thread, state ); /* * If the thread wants to timeout, then schedule its timer. */ if ( timeout ) { _Watchdog_Initialize( &the_thread->Timer, _Thread_queue_Timeout, the_thread->Object.id, NULL ); _Watchdog_Insert_ticks( &the_thread->Timer, timeout ); } /* * Now initiate the enqueuing and checking if the blocking operation * should be completed or the thread has had its blocking condition * satisfied before we got here. */ _Thread_queue_Acquire( &lock_context ); sync_state = the_thread_queue->sync_state; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { /* * Invoke the discipline specific enqueue method. */ if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) { _Chain_Append_unprotected( &the_thread_queue->Queues.Fifo, &the_thread->Object.Node ); } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */ _Thread_Lock_set( the_thread, &_Thread_queue_Lock ); _Thread_Priority_set_change_handler( the_thread, _Thread_queue_Requeue_priority, the_thread_queue ); _RBTree_Insert( &the_thread_queue->Queues.Priority, &the_thread->RBNode, _Thread_queue_Compare_priority, false ); } the_thread->Wait.queue = the_thread_queue; the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; _Thread_queue_Release( &lock_context ); } else { /* Cancel a blocking operation due to ISR */ _Assert( sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT || sync_state == THREAD_BLOCKING_OPERATION_SATISFIED ); _Thread_blocking_operation_Finalize( the_thread, &lock_context ); } }
int nanosleep( const struct timespec *rqtp, struct timespec *rmtp ) { Watchdog_Interval ticks; /* * Return EINVAL if the delay interval is negative. * * NOTE: This behavior is beyond the POSIX specification. * FSU and GNU/Linux pthreads shares this behavior. */ if ( !_Timespec_Is_valid( rqtp ) ) rtems_set_errno_and_return_minus_one( EINVAL ); ticks = _Timespec_To_ticks( rqtp ); /* * A nanosleep for zero time is implemented as a yield. * This behavior is also beyond the POSIX specification but is * consistent with the RTEMS API and yields desirable behavior. */ if ( !ticks ) { _Thread_Disable_dispatch(); _Scheduler_Yield(); _Thread_Enable_dispatch(); if ( rmtp ) { rmtp->tv_sec = 0; rmtp->tv_nsec = 0; } return 0; } /* * Block for the desired amount of time */ _Thread_Disable_dispatch(); _Thread_Set_state( _Thread_Executing, STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL ); _Watchdog_Initialize( &_Thread_Executing->Timer, _Thread_Delay_ended, _Thread_Executing->Object.id, NULL ); _Watchdog_Insert_ticks( &_Thread_Executing->Timer, ticks ); _Thread_Enable_dispatch(); /* calculate time remaining */ if ( rmtp ) { ticks -= _Thread_Executing->Timer.stop_time - _Thread_Executing->Timer.start_time; _Timespec_From_ticks( ticks, rmtp ); /* * Only when POSIX is enabled, can a sleep be interrupted. */ #if defined(RTEMS_POSIX_API) /* * If there is time remaining, then we were interrupted by a signal. */ if ( ticks ) rtems_set_errno_and_return_minus_one( EINTR ); #endif } return 0; }
void _Event_Seize( rtems_event_set event_in, rtems_option option_set, rtems_interval ticks, rtems_event_set *event_out ) { Thread_Control *executing; rtems_event_set seized_events; rtems_event_set pending_events; ISR_Level level; RTEMS_API_Control *api; Event_Sync_states sync_state; executing = _Thread_Executing; executing->Wait.return_code = RTEMS_SUCCESSFUL; api = executing->API_Extensions[ THREAD_API_RTEMS ]; _ISR_Disable( level ); pending_events = api->pending_events; seized_events = _Event_sets_Get( pending_events, event_in ); if ( !_Event_sets_Is_empty( seized_events ) && (seized_events == event_in || _Options_Is_any( option_set )) ) { api->pending_events = _Event_sets_Clear( pending_events, seized_events ); _ISR_Enable( level ); *event_out = seized_events; return; } if ( _Options_Is_no_wait( option_set ) ) { _ISR_Enable( level ); executing->Wait.return_code = RTEMS_UNSATISFIED; *event_out = seized_events; return; } _Event_Sync_state = EVENT_SYNC_NOTHING_HAPPENED; executing->Wait.option = (uint32_t ) option_set; executing->Wait.count = (uint32_t ) event_in; executing->Wait.return_argument = event_out; _ISR_Enable( level ); if ( ticks ) { _Watchdog_Initialize( &executing->Timer, _Event_Timeout, executing->Object.id, NULL ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Set_state( executing, STATES_WAITING_FOR_EVENT ); _ISR_Disable( level ); sync_state = _Event_Sync_state; _Event_Sync_state = EVENT_SYNC_SYNCHRONIZED; switch ( sync_state ) { case EVENT_SYNC_SYNCHRONIZED: /* * This cannot happen. It indicates that this routine did not * enter the synchronization states above. */ return; case EVENT_SYNC_NOTHING_HAPPENED: _ISR_Enable( level ); return; case EVENT_SYNC_TIMEOUT: executing->Wait.return_code = RTEMS_TIMEOUT; _ISR_Enable( level ); _Thread_Unblock( executing ); return; case EVENT_SYNC_SATISFIED: if ( _Watchdog_Is_active( &executing->Timer ) ) { _Watchdog_Deactivate( &executing->Timer ); _ISR_Enable( level ); (void) _Watchdog_Remove( &executing->Timer ); } else _ISR_Enable( level ); _Thread_Unblock( executing ); return; } }
/* * 14.2.5 High Resolution Sleep, P1003.1b-1993, p. 269 */ int nanosleep( const struct timespec *rqtp, struct timespec *rmtp ) { /* * It is critical to obtain the executing thread after thread dispatching is * disabled on SMP configurations. */ Thread_Control *executing; Watchdog_Interval ticks; Watchdog_Interval elapsed; /* * Return EINVAL if the delay interval is negative. * * NOTE: This behavior is beyond the POSIX specification. * FSU and GNU/Linux pthreads shares this behavior. */ if ( !_Timespec_Is_valid( rqtp ) ) rtems_set_errno_and_return_minus_one( EINVAL ); /* * Convert the timespec delay into the appropriate number of clock ticks. */ ticks = _Timespec_To_ticks( rqtp ); /* * A nanosleep for zero time is implemented as a yield. * This behavior is also beyond the POSIX specification but is * consistent with the RTEMS API and yields desirable behavior. */ if ( !ticks ) { _Thread_Disable_dispatch(); executing = _Thread_Executing; _Thread_Yield( executing ); _Thread_Enable_dispatch(); if ( rmtp ) { rmtp->tv_sec = 0; rmtp->tv_nsec = 0; } return 0; } /* * Block for the desired amount of time */ _Thread_Disable_dispatch(); executing = _Thread_Executing; _Thread_Set_state( executing, STATES_DELAYING | STATES_INTERRUPTIBLE_BY_SIGNAL ); _Watchdog_Initialize( &executing->Timer, _Thread_Delay_ended, 0, executing ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); _Thread_Enable_dispatch(); /* * Calculate the time that passed while we were sleeping and how * much remains from what we requested. */ elapsed = executing->Timer.stop_time - executing->Timer.start_time; if ( elapsed >= ticks ) ticks = 0; else ticks -= elapsed; /* * If the user wants the time remaining, do the conversion. */ if ( rmtp ) { _Timespec_From_ticks( ticks, rmtp ); } /* * Only when POSIX is enabled, can a sleep be interrupted. */ #if defined(RTEMS_POSIX_API) /* * If there is time remaining, then we were interrupted by a signal. */ if ( ticks ) rtems_set_errno_and_return_minus_one( EINTR ); #endif return 0; }
void _Event_Seize( rtems_event_set event_in, rtems_option option_set, rtems_interval ticks, rtems_event_set *event_out ) { Thread_Control *executing; rtems_event_set seized_events; rtems_event_set pending_events; ISR_Level level; RTEMS_API_Control *api; Thread_blocking_operation_States sync_state; executing = _Thread_Executing; executing->Wait.return_code = RTEMS_SUCCESSFUL; api = executing->API_Extensions[ THREAD_API_RTEMS ]; _ISR_Disable( level ); pending_events = api->pending_events; seized_events = _Event_sets_Get( pending_events, event_in ); if ( !_Event_sets_Is_empty( seized_events ) && (seized_events == event_in || _Options_Is_any( option_set )) ) { api->pending_events = _Event_sets_Clear( pending_events, seized_events ); _ISR_Enable( level ); *event_out = seized_events; return; } if ( _Options_Is_no_wait( option_set ) ) { _ISR_Enable( level ); executing->Wait.return_code = RTEMS_UNSATISFIED; *event_out = seized_events; return; } /* * Note what we are waiting for BEFORE we enter the critical section. * The interrupt critical section management code needs this to be * set properly when we are marked as in the event critical section. * * NOTE: Since interrupts are disabled, this isn't that much of an * issue but better safe than sorry. */ executing->Wait.option = (uint32_t) option_set; executing->Wait.count = (uint32_t) event_in; executing->Wait.return_argument = event_out; _Event_Sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED; _ISR_Enable( level ); if ( ticks ) { _Watchdog_Initialize( &executing->Timer, _Event_Timeout, executing->Object.id, NULL ); _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Set_state( executing, STATES_WAITING_FOR_EVENT ); _ISR_Disable( level ); sync_state = _Event_Sync_state; _Event_Sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED; if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) { _ISR_Enable( level ); return; } /* * An interrupt completed the thread's blocking request. * The blocking thread was satisfied by an ISR or timed out. * * WARNING! Returning with interrupts disabled! */ _Thread_blocking_operation_Cancel( sync_state, executing, level ); }
void _POSIX_signals_Manager_Initialization(void) { uint32_t signo; uint32_t maximum_queued_signals; maximum_queued_signals = Configuration_POSIX_API.maximum_queued_signals; /* * Ensure we have the same number of vectors and default vector entries */ #if defined(RTEMS_DEBUG) assert( sizeof(_POSIX_signals_Vectors) == sizeof(_POSIX_signals_Default_vectors) ); #endif memcpy( _POSIX_signals_Vectors, _POSIX_signals_Default_vectors, sizeof( _POSIX_signals_Vectors ) ); /* * Initialize the set of pending signals for the entire process */ sigemptyset( &_POSIX_signals_Pending ); /* * Initialize the queue we use to block for signals */ _Thread_queue_Initialize( &_POSIX_signals_Wait_queue, THREAD_QUEUE_DISCIPLINE_FIFO, STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL, EAGAIN ); /* XXX status codes */ /* * Allocate the siginfo pools. */ for ( signo=1 ; signo<= SIGRTMAX ; signo++ ) _Chain_Initialize_empty( &_POSIX_signals_Siginfo[ signo ] ); if ( maximum_queued_signals ) { _Chain_Initialize( &_POSIX_signals_Inactive_siginfo, _Workspace_Allocate_or_fatal_error( maximum_queued_signals * sizeof( POSIX_signals_Siginfo_node ) ), maximum_queued_signals, sizeof( POSIX_signals_Siginfo_node ) ); } else { _Chain_Initialize_empty( &_POSIX_signals_Inactive_siginfo ); } /* * Initialize the Alarm Timer */ _Watchdog_Initialize( &_POSIX_signals_Alarm_timer, NULL, 0, NULL ); _Watchdog_Initialize( &_POSIX_signals_Ualarm_timer, NULL, 0, NULL ); }
bool _Thread_Initialize( Objects_Information *information, Thread_Control *the_thread, void *stack_area, size_t stack_size, bool is_fp, Priority_Control priority, bool is_preemptible, Thread_CPU_budget_algorithms budget_algorithm, Thread_CPU_budget_algorithm_callout budget_callout, uint32_t isr_level, Objects_Name name ) { size_t actual_stack_size = 0; void *stack = NULL; #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) void *fp_area; #endif void *sched = NULL; void *extensions_area; bool extension_status; int i; #if defined( RTEMS_SMP ) if ( rtems_configuration_is_smp_enabled() && !is_preemptible ) { return false; } #endif /* * Initialize the Ada self pointer */ #if __RTEMS_ADA__ the_thread->rtems_ada_self = NULL; #endif /* * Zero out all the allocated memory fields */ for ( i=0 ; i <= THREAD_API_LAST ; i++ ) the_thread->API_Extensions[i] = NULL; extensions_area = NULL; the_thread->libc_reent = NULL; #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) fp_area = NULL; #endif /* * Allocate and Initialize the stack for this thread. */ #if !defined(RTEMS_SCORE_THREAD_ENABLE_USER_PROVIDED_STACK_VIA_API) actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size ); if ( !actual_stack_size || actual_stack_size < stack_size ) return false; /* stack allocation failed */ stack = the_thread->Start.stack; #else if ( !stack_area ) { actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size ); if ( !actual_stack_size || actual_stack_size < stack_size ) return false; /* stack allocation failed */ stack = the_thread->Start.stack; the_thread->Start.core_allocated_stack = true; } else { stack = stack_area; actual_stack_size = stack_size; the_thread->Start.core_allocated_stack = false; } #endif _Stack_Initialize( &the_thread->Start.Initial_stack, stack, actual_stack_size ); /* * Allocate the floating point area for this thread */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) if ( is_fp ) { fp_area = _Workspace_Allocate( CONTEXT_FP_SIZE ); if ( !fp_area ) goto failed; fp_area = _Context_Fp_start( fp_area, 0 ); } the_thread->fp_context = fp_area; the_thread->Start.fp_context = fp_area; #endif /* * Initialize the thread timer */ _Watchdog_Initialize( &the_thread->Timer, NULL, 0, NULL ); #ifdef __RTEMS_STRICT_ORDER_MUTEX__ /* Initialize the head of chain of held mutexes */ _Chain_Initialize_empty(&the_thread->lock_mutex); #endif /* * Allocate the extensions area for this thread */ if ( _Thread_Maximum_extensions ) { extensions_area = _Workspace_Allocate( (_Thread_Maximum_extensions + 1) * sizeof( void * ) ); if ( !extensions_area ) goto failed; } the_thread->extensions = (void **) extensions_area; /* * Clear the extensions area so extension users can determine * if they are linked to the thread. An extension user may * create the extension long after tasks have been created * so they cannot rely on the thread create user extension * call. */ if ( the_thread->extensions ) { for ( i = 0; i <= _Thread_Maximum_extensions ; i++ ) the_thread->extensions[i] = NULL; } /* * General initialization */ the_thread->Start.is_preemptible = is_preemptible; the_thread->Start.budget_algorithm = budget_algorithm; the_thread->Start.budget_callout = budget_callout; switch ( budget_algorithm ) { case THREAD_CPU_BUDGET_ALGORITHM_NONE: case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE: break; #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE) case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE: the_thread->cpu_time_budget = _Thread_Ticks_per_timeslice; break; #endif #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT) case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT: break; #endif } the_thread->Start.isr_level = isr_level; #if defined(RTEMS_SMP) the_thread->is_scheduled = false; the_thread->is_executing = false; /* Initialize the cpu field for the non-SMP schedulers */ the_thread->cpu = _Per_CPU_Get_by_index( 0 ); #endif the_thread->current_state = STATES_DORMANT; the_thread->Wait.queue = NULL; the_thread->resource_count = 0; the_thread->real_priority = priority; the_thread->Start.initial_priority = priority; sched =_Scheduler_Allocate( the_thread ); if ( !sched ) goto failed; _Thread_Set_priority( the_thread, priority ); /* * Initialize the CPU usage statistics */ #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ _Timestamp_Set_to_zero( &the_thread->cpu_time_used ); #else the_thread->cpu_time_used = 0; #endif /* * Open the object */ _Objects_Open( information, &the_thread->Object, name ); /* * We assume the Allocator Mutex is locked and dispatching is * enabled when we get here. We want to be able to run the * user extensions with dispatching enabled. The Allocator * Mutex provides sufficient protection to let the user extensions * run safely. */ extension_status = _User_extensions_Thread_create( the_thread ); if ( extension_status ) return true; failed: _Workspace_Free( the_thread->libc_reent ); for ( i=0 ; i <= THREAD_API_LAST ; i++ ) _Workspace_Free( the_thread->API_Extensions[i] ); _Workspace_Free( extensions_area ); #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) _Workspace_Free( fp_area ); #endif _Workspace_Free( sched ); _Thread_Stack_Free( the_thread ); return false; }
bool _Thread_Initialize( Objects_Information *information, Thread_Control *the_thread, const Scheduler_Control *scheduler, void *stack_area, size_t stack_size, bool is_fp, Priority_Control priority, bool is_preemptible, Thread_CPU_budget_algorithms budget_algorithm, Thread_CPU_budget_algorithm_callout budget_callout, uint32_t isr_level, Objects_Name name ) { uintptr_t tls_size = _TLS_Get_size(); size_t actual_stack_size = 0; void *stack = NULL; #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) void *fp_area = NULL; #endif bool extension_status; size_t i; bool scheduler_node_initialized = false; Per_CPU_Control *cpu = _Per_CPU_Get_by_index( 0 ); #if defined( RTEMS_SMP ) if ( rtems_configuration_is_smp_enabled() && !is_preemptible ) { return false; } #endif for ( i = 0 ; i < _Thread_Control_add_on_count ; ++i ) { const Thread_Control_add_on *add_on = &_Thread_Control_add_ons[ i ]; *(void **) ( (char *) the_thread + add_on->destination_offset ) = (char *) the_thread + add_on->source_offset; } /* * Initialize the Ada self pointer */ #if __RTEMS_ADA__ the_thread->rtems_ada_self = NULL; #endif the_thread->Start.tls_area = NULL; /* * Allocate and Initialize the stack for this thread. */ #if !defined(RTEMS_SCORE_THREAD_ENABLE_USER_PROVIDED_STACK_VIA_API) actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size ); if ( !actual_stack_size || actual_stack_size < stack_size ) return false; /* stack allocation failed */ stack = the_thread->Start.stack; #else if ( !stack_area ) { actual_stack_size = _Thread_Stack_Allocate( the_thread, stack_size ); if ( !actual_stack_size || actual_stack_size < stack_size ) return false; /* stack allocation failed */ stack = the_thread->Start.stack; the_thread->Start.core_allocated_stack = true; } else { stack = stack_area; actual_stack_size = stack_size; the_thread->Start.core_allocated_stack = false; } #endif _Stack_Initialize( &the_thread->Start.Initial_stack, stack, actual_stack_size ); /* Thread-local storage (TLS) area allocation */ if ( tls_size > 0 ) { uintptr_t tls_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment ); uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align ); the_thread->Start.tls_area = _Workspace_Allocate_aligned( tls_alloc, tls_align ); if ( the_thread->Start.tls_area == NULL ) { goto failed; } } /* * Allocate the floating point area for this thread */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) if ( is_fp ) { fp_area = _Workspace_Allocate( CONTEXT_FP_SIZE ); if ( !fp_area ) goto failed; fp_area = _Context_Fp_start( fp_area, 0 ); } the_thread->fp_context = fp_area; the_thread->Start.fp_context = fp_area; #endif /* * Initialize the thread timer */ _Watchdog_Initialize( &the_thread->Timer, NULL, 0, NULL ); #ifdef __RTEMS_STRICT_ORDER_MUTEX__ /* Initialize the head of chain of held mutexes */ _Chain_Initialize_empty(&the_thread->lock_mutex); #endif /* * Clear the extensions area so extension users can determine * if they are linked to the thread. An extension user may * create the extension long after tasks have been created * so they cannot rely on the thread create user extension * call. The object index starts with one, so the first extension context is * unused. */ for ( i = 1 ; i <= rtems_configuration_get_maximum_extensions() ; ++i ) the_thread->extensions[ i ] = NULL; /* * General initialization */ the_thread->Start.isr_level = isr_level; the_thread->Start.is_preemptible = is_preemptible; the_thread->Start.budget_algorithm = budget_algorithm; the_thread->Start.budget_callout = budget_callout; switch ( budget_algorithm ) { case THREAD_CPU_BUDGET_ALGORITHM_NONE: case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE: break; #if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE) case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE: the_thread->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice(); break; #endif #if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT) case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT: break; #endif } #if defined(RTEMS_SMP) the_thread->Scheduler.state = THREAD_SCHEDULER_BLOCKED; the_thread->Scheduler.own_control = scheduler; the_thread->Scheduler.control = scheduler; the_thread->Scheduler.own_node = the_thread->Scheduler.node; _Resource_Node_initialize( &the_thread->Resource_node ); _CPU_Context_Set_is_executing( &the_thread->Registers, false ); #endif _Thread_Debug_set_real_processor( the_thread, cpu ); /* Initialize the CPU for the non-SMP schedulers */ _Thread_Set_CPU( the_thread, cpu ); the_thread->current_state = STATES_DORMANT; the_thread->Wait.queue = NULL; the_thread->resource_count = 0; the_thread->real_priority = priority; the_thread->Start.initial_priority = priority; _Scheduler_Node_initialize( scheduler, the_thread ); scheduler_node_initialized = true; _Thread_Set_priority( the_thread, priority ); /* * Initialize the CPU usage statistics */ #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ _Timestamp_Set_to_zero( &the_thread->cpu_time_used ); #else the_thread->cpu_time_used = 0; #endif /* * initialize thread's key vaule node chain */ _Chain_Initialize_empty( &the_thread->Key_Chain ); _Thread_Action_control_initialize( &the_thread->Post_switch_actions ); _Thread_Action_initialize( &the_thread->Life.Action, _Thread_Life_action_handler ); the_thread->Life.state = THREAD_LIFE_NORMAL; the_thread->Life.terminator = NULL; /* * Open the object */ _Objects_Open( information, &the_thread->Object, name ); /* * We assume the Allocator Mutex is locked and dispatching is * enabled when we get here. We want to be able to run the * user extensions with dispatching enabled. The Allocator * Mutex provides sufficient protection to let the user extensions * run safely. */ extension_status = _User_extensions_Thread_create( the_thread ); if ( extension_status ) return true; failed: if ( scheduler_node_initialized ) { _Scheduler_Node_destroy( scheduler, the_thread ); } _Workspace_Free( the_thread->Start.tls_area ); #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) _Workspace_Free( fp_area ); #endif _Thread_Stack_Free( the_thread ); return false; }
int timer_settime( timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue ) { POSIX_Timer_Control *ptimer; Objects_Locations location; boolean activated; if ( value == NULL ) { rtems_set_errno_and_return_minus_one( EINVAL ); } /* First, it verifies if the structure "value" is correct */ if ( ( value->it_value.tv_nsec > TOD_NANOSECONDS_PER_SECOND ) || ( value->it_value.tv_nsec < 0 ) ) { /* The number of nanoseconds is not correct */ rtems_set_errno_and_return_minus_one( EINVAL ); } /* XXX check for seconds in the past */ if ( flags != TIMER_ABSTIME && flags != POSIX_TIMER_RELATIVE ) { rtems_set_errno_and_return_minus_one( EINVAL ); } /* If the function reaches this point, then it will be necessary to do * something with the structure of times of the timer: to stop, start * or start it again */ ptimer = _POSIX_Timer_Get( timerid, &location ); switch ( location ) { case OBJECTS_REMOTE: #if defined(RTEMS_MULTIPROCESSING) _Thread_Dispatch(); return -1; rtems_set_errno_and_return_minus_one( EINVAL ); #endif case OBJECTS_ERROR: return -1; case OBJECTS_LOCAL: /* First, it verifies if the timer must be stopped */ if ( value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0 ) { /* Stop the timer */ (void) _Watchdog_Remove( &ptimer->Timer ); /* The old data of the timer are returned */ if ( ovalue ) *ovalue = ptimer->timer_data; /* The new data are set */ ptimer->timer_data = *value; /* Indicates that the timer is created and stopped */ ptimer->state = POSIX_TIMER_STATE_CREATE_STOP; /* Returns with success */ _Thread_Enable_dispatch(); return 0; } /* absolute or relative? */ switch (flags) { case TIMER_ABSTIME: /* The fire time is absolute: use "rtems_time_fire_when" */ /* First, it converts from struct itimerspec to rtems_time_of_day */ _Watchdog_Initialize( &ptimer->Timer, _POSIX_Timer_TSR, ptimer->Object.id, ptimer ); _Watchdog_Insert_seconds( &ptimer->Timer, value->it_value.tv_sec - _TOD_Seconds_since_epoch ); /* Returns the old ones in "ovalue" */ if ( ovalue ) *ovalue = ptimer->timer_data; ptimer->timer_data = *value; /* Indicate that the time is running */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; /* Stores the time in which the timer was started again */ _TOD_Get( &ptimer->time ); _Thread_Enable_dispatch(); return 0; break; /* The fire time is relative: use "rtems_time_fire_after" */ case POSIX_TIMER_RELATIVE: /* First, convert from seconds and nanoseconds to ticks */ ptimer->ticks = _Timespec_To_ticks( &value->it_value ); activated = _Watchdog_Insert_ticks_helper( &ptimer->Timer, ptimer->ticks, ptimer->Object.id, _POSIX_Timer_TSR, ptimer ); if ( !activated ) { _Thread_Enable_dispatch(); return 0; } /* The timer has been started and is running */ /* return the old ones in "ovalue" */ if ( ovalue ) *ovalue = ptimer->timer_data; ptimer->timer_data = *value; /* Indicate that the time is running */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; _TOD_Get( &ptimer->time ); _Thread_Enable_dispatch(); return 0; } _Thread_Enable_dispatch(); rtems_set_errno_and_return_minus_one( EINVAL ); } return -1; /* unreached - only to remove warnings */ }
int timer_create( clockid_t clock_id, struct sigevent *evp, timer_t *timerid ) { POSIX_Timer_Control *ptimer; if ( clock_id != CLOCK_REALTIME ) rtems_set_errno_and_return_minus_one( EINVAL ); /* * The data of the structure evp are checked in order to verify if they * are coherent. */ if (evp != NULL) { /* The structure has data */ if ( ( evp->sigev_notify != SIGEV_NONE ) && ( evp->sigev_notify != SIGEV_SIGNAL ) ) { /* The value of the field sigev_notify is not valid */ rtems_set_errno_and_return_minus_one( EINVAL ); } if ( !evp->sigev_signo ) rtems_set_errno_and_return_minus_one( EINVAL ); if ( !is_valid_signo(evp->sigev_signo) ) rtems_set_errno_and_return_minus_one( EINVAL ); } _Thread_Disable_dispatch(); /* to prevent deletion */ /* * Allocate a timer */ ptimer = _POSIX_Timer_Allocate(); if ( !ptimer ) { _Thread_Enable_dispatch(); rtems_set_errno_and_return_minus_one( EAGAIN ); } /* The data of the created timer are stored to use them later */ ptimer->state = POSIX_TIMER_STATE_CREATE_NEW; ptimer->thread_id = _Thread_Executing->Object.id; if ( evp != NULL ) { ptimer->inf.sigev_notify = evp->sigev_notify; ptimer->inf.sigev_signo = evp->sigev_signo; ptimer->inf.sigev_value = evp->sigev_value; } ptimer->overrun = 0; ptimer->timer_data.it_value.tv_sec = 0; ptimer->timer_data.it_value.tv_nsec = 0; ptimer->timer_data.it_interval.tv_sec = 0; ptimer->timer_data.it_interval.tv_nsec = 0; _Watchdog_Initialize( &ptimer->Timer, NULL, 0, NULL ); _Objects_Open(&_POSIX_Timer_Information, &ptimer->Object, (Objects_Name) 0); *timerid = ptimer->Object.id; _Thread_Enable_dispatch(); return 0; }
rtems_status_code rtems_timer_server_fire_after( Objects_Id id, rtems_interval ticks, rtems_timer_service_routine_entry routine, void *user_data ) { Timer_Control *the_timer; Objects_Locations location; ISR_Level level; if ( !_Timer_Server ) return RTEMS_INCORRECT_STATE; if ( !routine ) return RTEMS_INVALID_ADDRESS; if ( ticks == 0 ) return RTEMS_INVALID_NUMBER; the_timer = _Timer_Get( id, &location ); switch ( location ) { case OBJECTS_REMOTE: /* should never return this */ return RTEMS_INTERNAL_ERROR; case OBJECTS_ERROR: return RTEMS_INVALID_ID; case OBJECTS_LOCAL: (void) _Watchdog_Remove( &the_timer->Ticker ); _ISR_Disable( level ); /* * Check to see if the watchdog has just been inserted by a * higher priority interrupt. If so, abandon this insert. */ if ( the_timer->Ticker.state != WATCHDOG_INACTIVE ) { _ISR_Enable( level ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; } /* * OK. Now we now the timer was not rescheduled by an interrupt * so we can atomically initialize it as in use. */ the_timer->the_class = TIMER_INTERVAL_ON_TASK; _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); the_timer->Ticker.initial = ticks; _ISR_Enable( level ); _Timer_Server_stop_ticks_timer(); _Timer_Server_process_ticks_chain(); _Watchdog_Insert( &_Timer_Ticks_chain, &the_timer->Ticker ); _Timer_Server_reset_ticks_timer(); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; } return RTEMS_INTERNAL_ERROR; /* unreached - only to remove warnings */ }