From ac7d5ef06a6d6e8d84abbd1f0b82162725f98326 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 11 May 1995 17:39:37 +0000 Subject: Initial revision --- c/src/exec/rtems/src/tasks.c | 816 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 816 insertions(+) create mode 100644 c/src/exec/rtems/src/tasks.c (limited to 'c/src/exec/rtems/src/tasks.c') diff --git a/c/src/exec/rtems/src/tasks.c b/c/src/exec/rtems/src/tasks.c new file mode 100644 index 0000000000..edba524d94 --- /dev/null +++ b/c/src/exec/rtems/src/tasks.c @@ -0,0 +1,816 @@ +/* + * RTEMS Task Manager + * + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*PAGE + * + * rtems_task_create + * + * This directive creates a thread by allocating and initializing a + * thread control block and a stack. The newly created thread is + * placed in the dormant state. + * + * Input parameters: + * name - user defined thread name + * initial_priority - thread priority + * stack_size - stack size in bytes + * initial_modes - initial thread mode + * attribute_set - thread attributes + * id - pointer to thread id + * + * Output parameters: + * id - thread id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_create( + Objects_Name name, + rtems_task_priority initial_priority, + unsigned32 stack_size, + rtems_mode initial_modes, + rtems_attribute attribute_set, + Objects_Id *id +) +{ + register Thread_Control *the_thread; + unsigned32 actual_stack_size; + unsigned32 memory_needed; + void *memory; + rtems_attribute the_attribute_set; + + if ( !_Objects_Is_name_valid( name ) ) + return ( RTEMS_INVALID_NAME ); + +#if 0 + if ( !_Stack_Is_enough( stack_size ) ) + return( RTEMS_INVALID_SIZE ); +#endif + + if ( !_Stack_Is_enough( stack_size ) ) + actual_stack_size = RTEMS_MINIMUM_STACK_SIZE; + else + actual_stack_size = stack_size; + + if ( !_Priority_Is_valid( initial_priority ) ) + return( RTEMS_INVALID_PRIORITY ); + + /* + * Fix the attribute set to match the attributes which + * this processor (1) requires and (2) is able to support. + * First add in the required flags for attribute_set + * Typically this might include FP if the platform + * or application required all tasks to be fp aware. + * Then turn off the requested bits which are not supported. + */ + + the_attribute_set = _Attributes_Set( attribute_set, ATTRIBUTES_REQUIRED ); + the_attribute_set = + _Attributes_Clear( the_attribute_set, ATTRIBUTES_NOT_SUPPORTED ); + + if ( _Attributes_Is_global( the_attribute_set ) && + !_Configuration_Is_multiprocessing() ) + return( RTEMS_MP_NOT_CONFIGURED ); + + _Thread_Disable_dispatch(); /* to prevent deletion */ + + the_thread = _RTEMS_tasks_Allocate(); + + if ( !the_thread ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + actual_stack_size = _Stack_Adjust_size( actual_stack_size ); + memory_needed = actual_stack_size; + + if ( _Attributes_Is_floating_point( the_attribute_set ) ) + memory_needed += CONTEXT_FP_SIZE; + + memory = _Workspace_Allocate( memory_needed ); + + if ( !memory ) { + _RTEMS_tasks_Free( the_thread ); + _Thread_Enable_dispatch(); + return( RTEMS_UNSATISFIED ); + } + + /* + * Stack is put in the lower address regions of the allocated memory. + * The optional floating point context area goes into the higher part + * of the allocated memory. + */ + + _Stack_Initialize( + &the_thread->Start.Initial_stack, memory, actual_stack_size ); + + if ( _Attributes_Is_floating_point( the_attribute_set ) ) + the_thread->fp_context = _Context_Fp_start( memory, actual_stack_size ); + else + the_thread->fp_context = NULL; + + the_thread->Start.fp_context = the_thread->fp_context; + + if ( _Attributes_Is_global( the_attribute_set ) && + !( _Objects_MP_Open( &_Thread_Information, name, + the_thread->Object.id, FALSE ) ) ) { + _RTEMS_tasks_Free( the_thread ); + (void) _Workspace_Free( memory ); + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + the_thread->name = name; + the_thread->attribute_set = the_attribute_set; + the_thread->current_state = STATES_DORMANT; + the_thread->current_modes = initial_modes; + the_thread->pending_events = EVENT_SETS_NONE_PENDING; + the_thread->resource_count = 0; + the_thread->real_priority = initial_priority; + the_thread->Start.initial_priority = initial_priority; + the_thread->Start.initial_modes = initial_modes; + + _Thread_Set_priority( the_thread, initial_priority ); + + _ASR_Initialize( &the_thread->Signal ); + + _Objects_Open( &_Thread_Information, &the_thread->Object, name ); + + *id = the_thread->Object.id; + + _User_extensions_Task_create( the_thread ); + + if ( _Attributes_Is_global( the_attribute_set ) ) + _RTEMS_tasks_MP_Send_process_packet( + RTEMS_TASKS_MP_ANNOUNCE_CREATE, + the_thread->Object.id, + name + ); + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_task_ident + * + * This directive returns the system ID associated with + * the thread name. + * + * Input parameters: + * name - user defined thread name + * node - node(s) to be searched + * id - pointer to thread id + * + * Output parameters: + * *id - thread id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_ident( + Objects_Name name, + unsigned32 node, + Objects_Id *id +) +{ + if ( name != OBJECTS_ID_OF_SELF ) + return( _Objects_Name_to_id( &_Thread_Information, name, node, id ) ); + + *id = _Thread_Executing->Object.id; + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_task_start + * + * This directive readies the thread identified by the "id" + * based on its current priorty, to await execution. A thread + * can be started only from the dormant state. + * + * Input parameters: + * id - thread id + * entry_point - start execution address of thread + * argument - thread argument + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_start( + Objects_Id id, + rtems_task_entry entry_point, + unsigned32 argument +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + if ( entry_point == NULL ) + return( RTEMS_INVALID_ADDRESS ); + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return( RTEMS_ILLEGAL_ON_REMOTE_OBJECT ); + case OBJECTS_LOCAL: + if ( _States_Is_dormant( the_thread->current_state ) ) { + + the_thread->Start.entry_point = entry_point; + the_thread->Start.initial_argument = argument; + + _Thread_Load_environment( the_thread ); + + _Thread_Ready( the_thread ); + + _User_extensions_Task_start( the_thread ); + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_INCORRECT_STATE ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_restart + * + * This directive readies the specified thread. It restores + * the thread environment to the original values established + * at thread creation and start time. A thread can be restarted + * from any state except the dormant state. + * + * Input parameters: + * id - thread id + * argument - thread argument + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_restart( + Objects_Id id, + unsigned32 argument +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return( RTEMS_ILLEGAL_ON_REMOTE_OBJECT ); + case OBJECTS_LOCAL: + if ( !_States_Is_dormant( the_thread->current_state ) ) { + + _Thread_Set_transient( the_thread ); + _ASR_Initialize( &the_thread->Signal ); + the_thread->pending_events = EVENT_SETS_NONE_PENDING; + the_thread->resource_count = 0; + the_thread->current_modes = the_thread->Start.initial_modes; + the_thread->Start.initial_argument = argument; + + _RTEMS_tasks_Cancel_wait( the_thread ); + + if ( the_thread->current_priority != + the_thread->Start.initial_priority ) { + the_thread->real_priority = the_thread->Start.initial_priority; + _Thread_Set_priority( the_thread, + the_thread->Start.initial_priority ); + } + + _Thread_Load_environment( the_thread ); + + _Thread_Ready( the_thread ); + + _User_extensions_Task_restart( the_thread ); + + if ( _Thread_Is_executing ( the_thread ) ) + _Thread_Restart_self(); + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_INCORRECT_STATE ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_delete + * + * This directive allows a thread to delete itself or the thread + * identified in the id field. The executive halts execution + * of the thread and frees the thread control block. + * + * Input parameters: + * id - thread id + * + * Output parameters: + * nothing - if id is the requesting thread (always succeeds) + * RTEMS_SUCCESSFUL - if successful and id is + * not the requesting thread + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_delete( + Objects_Id id +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return( RTEMS_ILLEGAL_ON_REMOTE_OBJECT ); + case OBJECTS_LOCAL: + _Objects_Close( &_Thread_Information, &the_thread->Object ); + + _Thread_Set_state( the_thread, STATES_TRANSIENT ); + + _User_extensions_Task_delete( the_thread ); + +#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) + if ( _Thread_Is_allocated_fp( the_thread ) ) + _Thread_Deallocate_fp(); +#endif + the_thread->fp_context = NULL; + + _RTEMS_tasks_Cancel_wait( the_thread ); + + (void) _Workspace_Free( the_thread->Start.Initial_stack.area ); + + _RTEMS_tasks_Free( the_thread ); + + if ( _Attributes_Is_global( the_thread->attribute_set ) ) { + + _Objects_MP_Close( &_Thread_Information, the_thread->Object.id ); + + _RTEMS_tasks_MP_Send_process_packet( + RTEMS_TASKS_MP_ANNOUNCE_DELETE, + the_thread->Object.id, + 0 /* Not used */ + ); + } + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_suspend + * + * This directive will place the specified thread in the "suspended" + * state. Note that the suspended state can be in addition to + * other waiting states. + * + * Input parameters: + * id - thread id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_suspend( + Objects_Id id +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + return( + _RTEMS_tasks_MP_Send_request_packet( + RTEMS_TASKS_MP_SUSPEND_REQUEST, + id, + 0, /* Not used */ + 0, /* Not used */ + 0 /* Not used */ + ) + ); + case OBJECTS_LOCAL: + if ( !_States_Is_suspended( the_thread->current_state ) ) { + _Thread_Set_state( the_thread, STATES_SUSPENDED ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_ALREADY_SUSPENDED ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_resume + * + * This directive will remove the specified thread + * from the suspended state. + * + * Input parameters: + * id - thread id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_resume( + Objects_Id id +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + return( + _RTEMS_tasks_MP_Send_request_packet( + RTEMS_TASKS_MP_RESUME_REQUEST, + id, + 0, /* Not used */ + 0, /* Not used */ + 0 /* Not used */ + ) + ); + case OBJECTS_LOCAL: + if ( _States_Is_suspended( the_thread->current_state ) ) { + _Thread_Resume( the_thread ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_INCORRECT_STATE ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_set_priority + * + * This directive changes the priority of the specified thread. + * The specified thread can be any thread in the system including + * the requesting thread. + * + * Input parameters: + * id - thread id (0 indicates requesting thread) + * new_priority - thread priority (0 indicates current priority) + * old_priority - pointer to previous priority + * + * Output parameters: + * old_priority - previous priority + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_set_priority( + Objects_Id id, + rtems_task_priority new_priority, + rtems_task_priority *old_priority +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + if ( new_priority != RTEMS_CURRENT_PRIORITY && + !_Priority_Is_valid( new_priority ) ) + return( RTEMS_INVALID_PRIORITY ); + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Executing->Wait.return_argument = old_priority; + return( + _RTEMS_tasks_MP_Send_request_packet( + RTEMS_TASKS_MP_SET_PRIORITY_REQUEST, + id, + new_priority, + 0, /* Not used */ + 0 /* Not used */ + ) + ); + case OBJECTS_LOCAL: + *old_priority = the_thread->current_priority; + if ( new_priority != RTEMS_CURRENT_PRIORITY ) { + the_thread->real_priority = new_priority; + if ( the_thread->resource_count == 0 || + the_thread->current_priority > new_priority ) + _Thread_Change_priority( the_thread, new_priority ); + } + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_mode + * + * This directive enables and disables several modes of + * execution for the requesting thread. + * + * Input parameters: + * mode_set - new mode + * mask - mask + * previous_mode_set - address of previous mode set + * + * Output: + * *previous_mode_set - previous mode set + * always returns RTEMS_SUCCESSFUL + */ + +rtems_status_code rtems_task_mode( + rtems_mode mode_set, + rtems_mode mask, + rtems_mode *previous_mode_set +) +{ + if ( _Thread_Change_mode( mode_set, mask, previous_mode_set ) ) + _Thread_Dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_task_get_note + * + * This directive obtains the note from the specified notepad + * of the specified thread. + * + * Input parameters: + * id - thread id + * notepad - notepad number + * note - pointer to note + * + * Output parameters: + * note - filled in if successful + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_get_note( + Objects_Id id, + unsigned32 notepad, + unsigned32 *note +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + /* + * NOTE: There is no check for < RTEMS_NOTEPAD_FIRST because that would + * be checking an unsigned number for being negative. + */ + + if ( notepad > RTEMS_NOTEPAD_LAST ) + return( RTEMS_INVALID_NUMBER ); + + /* + * Optimize the most likely case to avoid the Thread_Dispatch. + */ + + if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) || + _Objects_Are_ids_equal( id, _Thread_Executing->Object.id ) ) { + *note = _Thread_Executing->Notepads[ notepad ]; + return( RTEMS_SUCCESSFUL ); + } + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Executing->Wait.return_argument = note; + + return _RTEMS_tasks_MP_Send_request_packet( + RTEMS_TASKS_MP_GET_NOTE_REQUEST, + id, + 0, /* Not used */ + notepad, + 0 /* Not used */ + ); + case OBJECTS_LOCAL: + *note= the_thread->Notepads[ notepad ]; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_set_note + * + * This directive sets the specified notepad contents to the given + * note. + * + * Input parameters: + * id - thread id + * notepad - notepad number + * note - note value + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_set_note( + Objects_Id id, + unsigned32 notepad, + unsigned32 note +) +{ + register Thread_Control *the_thread; + Objects_Locations location; + + /* + * NOTE: There is no check for < RTEMS_NOTEPAD_FIRST because that would + * be checking an unsigned number for being negative. + */ + + if ( notepad > RTEMS_NOTEPAD_LAST ) + return( RTEMS_INVALID_NUMBER ); + + /* + * Optimize the most likely case to avoid the Thread_Dispatch. + */ + + if ( _Objects_Are_ids_equal( id, OBJECTS_ID_OF_SELF ) || + _Objects_Are_ids_equal( id, _Thread_Executing->Object.id ) ) { + _Thread_Executing->Notepads[ notepad ] = note; + return( RTEMS_SUCCESSFUL ); + } + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + return _RTEMS_tasks_MP_Send_request_packet( + RTEMS_TASKS_MP_SET_NOTE_REQUEST, + id, + 0, /* Not used */ + notepad, + note + ); + + case OBJECTS_LOCAL: + the_thread->Notepads[ notepad ] = note; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_task_wake_after + * + * This directive suspends the requesting thread for the given amount + * of ticks. + * + * Input parameters: + * ticks - number of ticks to wait + * + * Output parameters: + * RTEMS_SUCCESSFUL - always successful + */ + +rtems_status_code rtems_task_wake_after( + rtems_interval ticks +) +{ + if ( ticks == 0 ) { + _Thread_Yield_processor(); + _Thread_Dispatch(); + } else { + _Thread_Disable_dispatch(); + _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, WATCHDOG_ACTIVATE_NOW ); + _Thread_Enable_dispatch(); + } + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_task_wake_when + * + * This directive blocks the requesting thread until the given date and + * time is reached. + * + * Input parameters: + * time_buffer - pointer to the time and date structure + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_task_wake_when( +rtems_time_of_day *time_buffer +) +{ + rtems_interval seconds; + rtems_status_code local_result; + + if ( !_TOD_Is_set() ) + return( RTEMS_NOT_DEFINED ); + + time_buffer->ticks = 0; + + local_result = _TOD_Validate( time_buffer ); + + if ( !rtems_is_status_successful( local_result ) ) + return( local_result ); + + 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, WATCHDOG_ACTIVATE_NOW ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} -- cgit v1.2.3