From ac7d5ef06a6d6e8d84abbd1f0b82162725f98326 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 11 May 1995 17:39:37 +0000 Subject: Initial revision --- cpukit/rtems/src/dpmem.c | 268 ++++++++++++++ cpukit/rtems/src/event.c | 294 +++++++++++++++ cpukit/rtems/src/eventmp.c | 188 ++++++++++ cpukit/rtems/src/intr.c | 85 +++++ cpukit/rtems/src/mp.c | 128 +++++++ cpukit/rtems/src/msg.c | 708 ++++++++++++++++++++++++++++++++++++ cpukit/rtems/src/msgmp.c | 397 ++++++++++++++++++++ cpukit/rtems/src/part.c | 322 +++++++++++++++++ cpukit/rtems/src/partmp.c | 300 ++++++++++++++++ cpukit/rtems/src/ratemon.c | 401 +++++++++++++++++++++ cpukit/rtems/src/region.c | 456 +++++++++++++++++++++++ cpukit/rtems/src/regionmp.c | 308 ++++++++++++++++ cpukit/rtems/src/rtclock.c | 153 ++++++++ cpukit/rtems/src/rtemstimer.c | 343 ++++++++++++++++++ cpukit/rtems/src/sem.c | 483 +++++++++++++++++++++++++ cpukit/rtems/src/semmp.c | 306 ++++++++++++++++ cpukit/rtems/src/signal.c | 110 ++++++ cpukit/rtems/src/signalmp.c | 187 ++++++++++ cpukit/rtems/src/taskmp.c | 338 +++++++++++++++++ cpukit/rtems/src/tasks.c | 816 ++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 6591 insertions(+) create mode 100644 cpukit/rtems/src/dpmem.c create mode 100644 cpukit/rtems/src/event.c create mode 100644 cpukit/rtems/src/eventmp.c create mode 100644 cpukit/rtems/src/intr.c create mode 100644 cpukit/rtems/src/mp.c create mode 100644 cpukit/rtems/src/msg.c create mode 100644 cpukit/rtems/src/msgmp.c create mode 100644 cpukit/rtems/src/part.c create mode 100644 cpukit/rtems/src/partmp.c create mode 100644 cpukit/rtems/src/ratemon.c create mode 100644 cpukit/rtems/src/region.c create mode 100644 cpukit/rtems/src/regionmp.c create mode 100644 cpukit/rtems/src/rtclock.c create mode 100644 cpukit/rtems/src/rtemstimer.c create mode 100644 cpukit/rtems/src/sem.c create mode 100644 cpukit/rtems/src/semmp.c create mode 100644 cpukit/rtems/src/signal.c create mode 100644 cpukit/rtems/src/signalmp.c create mode 100644 cpukit/rtems/src/taskmp.c create mode 100644 cpukit/rtems/src/tasks.c (limited to 'cpukit/rtems/src') diff --git a/cpukit/rtems/src/dpmem.c b/cpukit/rtems/src/dpmem.c new file mode 100644 index 0000000000..0aacecec5b --- /dev/null +++ b/cpukit/rtems/src/dpmem.c @@ -0,0 +1,268 @@ +/* + * Dual Port Memory 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 + +/*PAGE + * + * _Dual_ported_memory_Manager_initialization + * + * This routine initializes all dual-ported memory manager related + * data structures. + * + * Input parameters: + * maximum_ports - number of ports to initialize + * + * Output parameters: NONE + */ + +void _Dual_ported_memory_Manager_initialization( + unsigned32 maximum_ports +) +{ + _Objects_Initialize_information( + &_Dual_ported_memory_Information, + FALSE, + maximum_ports, + sizeof( Dual_ported_memory_Control ) + ); +} + +/*PAGE + * + * rtems_port_create + * + * This directive creates a port into a dual-ported memory area. + * + * Input parameters: + * name - user defined port name + * internal_start - internal start address of port + * external_start - external start address of port + * length - physical length in bytes + * id - address of port id to set + * + * Output parameters: + * id - port id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_port_create( + Objects_Name name, + void *internal_start, + void *external_start, + unsigned32 length, + Objects_Id *id +) +{ + register Dual_ported_memory_Control *the_port; + + if ( !_Objects_Is_name_valid( name) ) + return ( RTEMS_INVALID_NAME ); + + if ( !_Addresses_Is_aligned( internal_start ) || + !_Addresses_Is_aligned( external_start ) ) + return( RTEMS_INVALID_ADDRESS ); + + _Thread_Disable_dispatch(); /* to prevent deletion */ + + the_port = _Dual_ported_memory_Allocate(); + + if ( !the_port ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + the_port->internal_base = internal_start; + the_port->external_base = external_start; + the_port->length = length - 1; + + _Objects_Open( &_Dual_ported_memory_Information, + &the_port->Object, name ); + *id = the_port->Object.id; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_port_ident + * + * This directive returns the system ID associated with + * the port name. + * + * Input parameters: + * name - user defined port name + * id - pointer to port id + * + * Output parameters: + * *id - port id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_port_ident( + Objects_Name name, + Objects_Id *id +) +{ + return( + _Objects_Name_to_id( + &_Dual_ported_memory_Information, + name, + RTEMS_SEARCH_ALL_NODES, + id + ) + ); +} + +/*PAGE + * + * rtems_port_delete + * + * This directive allows a thread to delete a dual-ported memory area + * specified by the dual-ported memory identifier. + * + * Input parameters: + * id - dual-ported memory area id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_port_delete( + Objects_Id id +) +{ + register Dual_ported_memory_Control *the_port; + Objects_Locations location; + + the_port = _Dual_ported_memory_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + _Objects_Close( &_Dual_ported_memory_Information, &the_port->Object ); + _Dual_ported_memory_Free( the_port ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_port_internal_to_external + * + * This directive converts an internal dual-ported memory address to an + * external dual-ported memory address. If the given internal address + * is an invalid dual-ported address, then the external address is set + * to the given internal address. + * + * Input parameters: + * id - id of dual-ported memory object + * internal - internal address to set + * external - pointer to external address + * + * Output parameters: + * external - external address + * RTEMS_SUCCESSFUL - always succeeds + */ + +rtems_status_code rtems_port_internal_to_external( + Objects_Id id, + void *internal, + void **external +) +{ + register Dual_ported_memory_Control *the_port; + Objects_Locations location; + unsigned32 ending; + + the_port = _Dual_ported_memory_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + ending = _Addresses_Subtract( internal, the_port->internal_base ); + if ( ending > the_port->length ) + *external = internal; + else + *external = _Addresses_Add_offset( the_port->external_base, + ending ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_port_external_to_internal + * + * This directive converts an external dual-ported memory address to an + * internal dual-ported memory address. If the given external address + * is an invalid dual-ported address, then the internal address is set + * to the given external address. + * + * Input parameters: + * id - id of dp memory object + * external - external address + * internal - pointer of internal address to set + * + * Output parameters: + * internal - internal address + * RTEMS_SUCCESSFUL - always succeeds + */ + +rtems_status_code rtems_port_external_to_internal( + Objects_Id id, + void *external, + void **internal +) +{ + register Dual_ported_memory_Control *the_port; + Objects_Locations location; + unsigned32 ending; + + the_port = _Dual_ported_memory_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + ending = _Addresses_Subtract( external, the_port->external_base ); + if ( ending > the_port->length ) + *internal = external; + else + *internal = _Addresses_Add_offset( the_port->internal_base, + ending ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} diff --git a/cpukit/rtems/src/event.c b/cpukit/rtems/src/event.c new file mode 100644 index 0000000000..6a25ae81c3 --- /dev/null +++ b/cpukit/rtems/src/event.c @@ -0,0 +1,294 @@ +/* + * Event 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 + +/*PAGE + * + * rtems_event_send + * + * This directive allows a thread send an event set to another thread. + * + * Input parameters: + * id - thread id + * event - event set + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_event_send( + Objects_Id id, + rtems_event_set event_in +) +{ + 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( + _Event_MP_Send_request_packet( + EVENT_MP_SEND_REQUEST, + id, + event_in + ) + ); + case OBJECTS_LOCAL: + _Event_sets_Post( event_in, &the_thread->pending_events ); + _Event_Surrender( the_thread ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_event_receive + * + * This directive allows a thread to receive a set of events. + * + * Input parameters: + * event_in - input event condition + * option_set - options + * ticks - number of ticks to wait (0 means wait forever) + * event_out - pointer to output event set + * + * Output parameters: + * event out - event set + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_event_receive( + rtems_event_set event_in, + rtems_option option_set, + rtems_interval ticks, + rtems_event_set *event_out +) +{ + if ( _Event_sets_Is_empty( event_in ) ) { + *event_out = _Thread_Executing->pending_events; + return( RTEMS_SUCCESSFUL ); + } + + _Thread_Disable_dispatch(); + _Event_Seize( event_in, option_set, ticks ); + _Thread_Enable_dispatch(); + *event_out = _Thread_Executing->events_out; + return( _Thread_Executing->Wait.return_code ); +} + +/*PAGE + * + * _Event_Seize + * + * This routine attempts to satisfy the requested event condition + * for the running thread. + * + * Input parameters: + * event_in - the event condition to satisfy + * option_set - acquire event options + * ticks - interval to wait + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * available + * wait + * check sync + */ + +void _Event_Seize( + rtems_event_set event_in, + rtems_option option_set, + rtems_interval ticks +) +{ + Thread_Control *executing; + rtems_event_set seized_events; + rtems_event_set pending_events; + ISR_Level level; + + executing = _Thread_Executing; + executing->Wait.return_code = RTEMS_SUCCESSFUL; + + _ISR_Disable( level ); + pending_events = executing->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 )) ) { + executing->pending_events = + _Event_sets_Clear( pending_events, seized_events ); + _ISR_Enable( level ); + executing->events_out = seized_events; + return; + } + + if ( _Options_Is_no_wait( option_set ) ) { + _ISR_Enable( level ); + executing->Wait.return_code = RTEMS_UNSATISFIED; + executing->events_out = seized_events; + return; + } + + _Event_Sync = TRUE; + executing->Wait.option_set = option_set; + executing->Wait.Extra.event_condition = event_in; + + _ISR_Enable( level ); + _Thread_Set_state( executing, STATES_WAITING_FOR_EVENT ); + + if ( ticks ) { + _Watchdog_Initialize( + &executing->Timer, + _Event_Timeout, + executing->Object.id, + NULL + ); + _Watchdog_Insert_ticks( + &executing->Timer, + ticks, + WATCHDOG_NO_ACTIVATE + ); + } + + _ISR_Disable( level ); + if ( _Event_Sync == TRUE ) { + _Event_Sync = FALSE; + if ( ticks ) + _Watchdog_Activate( &executing->Timer ); + _ISR_Enable( level ); + return; + } + _ISR_Enable( level ); + (void) _Watchdog_Remove( &executing->Timer ); + _Thread_Unblock( executing ); + return; +} + +/*PAGE + * + * _Event_Surrender + * + * This routines remove a thread from the specified threadq. + * + * Input parameters: + * the_thread - pointer to thread to be dequeued + * + * Output parameters: NONE + * + * INTERRUPT LATENCY: + * before flash + * after flash + * check sync + */ + +void _Event_Surrender( + Thread_Control *the_thread +) +{ + ISR_Level level; + rtems_event_set pending_events; + rtems_event_set event_condition; + rtems_event_set seized_events; + + _ISR_Disable( level ); + pending_events = the_thread->pending_events; + event_condition = the_thread->Wait.Extra.event_condition; + + seized_events = _Event_sets_Get( pending_events, event_condition ); + + if ( !_Event_sets_Is_empty( seized_events ) ) { + if ( _States_Is_waiting_for_event( the_thread->current_state ) ) { + if ( seized_events == event_condition || + _Options_Is_any( the_thread->Wait.option_set ) ) { + the_thread->pending_events = + _Event_sets_Clear( pending_events, seized_events ); + (rtems_event_set *)the_thread->events_out = seized_events; + + _ISR_Flash( level ); + + if ( !_Watchdog_Is_active( &the_thread->Timer ) ) { + _ISR_Enable( level ); + _Thread_Unblock( the_thread ); + } + else { + _Watchdog_Deactivate( &the_thread->Timer ); + _ISR_Enable( level ); + (void) _Watchdog_Remove( &the_thread->Timer ); + _Thread_Unblock( the_thread ); + } + return; + } + } + else if ( _Thread_Is_executing( the_thread ) && _Event_Sync == TRUE ) { + if ( seized_events == event_condition || + _Options_Is_any( the_thread->Wait.option_set ) ) { + the_thread->pending_events = + _Event_sets_Clear( pending_events,seized_events ); + (rtems_event_set *)the_thread->events_out = seized_events; + _Event_Sync = FALSE; + } + } + } + _ISR_Enable( level ); +} + +/*PAGE + * + * _Event_Timeout + * + * This routine processes a thread which timeouts while waiting to + * receive an event_set. It is called by the watchdog handler. + * + * Input parameters: + * id - thread id + * + * Output parameters: NONE + */ + +void _Event_Timeout( + Objects_Id id, + void *ignored +) +{ + Thread_Control *the_thread; + Objects_Locations location; + + the_thread = _Thread_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: /* impossible */ + break; + case OBJECTS_LOCAL: + the_thread->Wait.return_code = RTEMS_TIMEOUT; + _Thread_Unblock( the_thread ); + _Thread_Unnest_dispatch(); + break; + } +} diff --git a/cpukit/rtems/src/eventmp.c b/cpukit/rtems/src/eventmp.c new file mode 100644 index 0000000000..4bc5925c2a --- /dev/null +++ b/cpukit/rtems/src/eventmp.c @@ -0,0 +1,188 @@ +/* + * Multiprocessing Support for the Event 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 + +/*PAGE + * + * _Event_MP_Send_process_packet + * + * This subprogram is not needed since there are no process + * packets to be sent by this manager. + * + */ + +/*PAGE + * + * _Event_MP_Send_request_packet + * + */ + +rtems_status_code _Event_MP_Send_request_packet ( + Event_MP_Remote_operations operation, + Objects_Id event_id, + rtems_event_set event_in +) +{ + Event_MP_Packet *the_packet; + + switch ( operation ) { + + case EVENT_MP_SEND_REQUEST: + + the_packet = _Event_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_EVENT; + the_packet->Prefix.length = sizeof ( Event_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Event_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = event_id; + the_packet->event_in = event_in; + + return + _MPCI_Send_request_packet( + rtems_get_node( event_id ), + &the_packet->Prefix, + STATES_READY + ); + + break; + + case EVENT_MP_SEND_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_SUCCESSFUL; +} + +/*PAGE + * + * _Event_MP_Send_response_packet + * + */ + +void _Event_MP_Send_response_packet ( + Event_MP_Remote_operations operation, + Thread_Control *the_thread +) +{ + Event_MP_Packet *the_packet; + + switch ( operation ) { + + case EVENT_MP_SEND_RESPONSE: + + the_packet = ( Event_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case EVENT_MP_SEND_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _Event_MP_Process_packet + * + */ + +void _Event_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + Event_MP_Packet *the_packet; + Thread_Control *the_thread; + + the_packet = (Event_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case EVENT_MP_SEND_REQUEST: + + the_packet->Prefix.return_code = rtems_event_send( + the_packet->Prefix.id, + the_packet->event_in + ); + + _Event_MP_Send_response_packet( + EVENT_MP_SEND_RESPONSE, + _Thread_Executing + ); + break; + + case EVENT_MP_SEND_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + + break; + + } +} + +/*PAGE + * + * _Event_MP_Send_object_was_deleted + * + * This subprogram is not needed since there are no objects + * deleted by this manager. + * + */ + +/*PAGE + * + * _Event_MP_Send_extract_proxy + * + * This subprogram is not needed since there are no objects + * deleted by this manager. + * + */ + +/*PAGE + * + * _Event_MP_Get_packet + * + */ + +Event_MP_Packet *_Event_MP_Get_packet ( void ) +{ + return ( (Event_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/intr.c b/cpukit/rtems/src/intr.c new file mode 100644 index 0000000000..25f5176967 --- /dev/null +++ b/cpukit/rtems/src/intr.c @@ -0,0 +1,85 @@ +/* + * Interrupt 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 + +/* _Interrupt_Manager_initialization + * + * This routine initializes the interrupt manager. + * + * Input parameters: NONE + * + * Output parameters: NONE + */ + +void _Interrupt_Manager_initialization( void ) +{ +#if ( CPU_ALLOCATE_INTERRUPT_STACK == TRUE ) + + if ( _CPU_Table.interrupt_stack_size < RTEMS_MINIMUM_STACK_SIZE ) + rtems_fatal_error_occurred( RTEMS_INVALID_SIZE ); + + _CPU_Interrupt_stack_low = + _Workspace_Allocate_or_fatal_error( _CPU_Table.interrupt_stack_size ); + + _CPU_Interrupt_stack_high = _Addresses_Add_offset( + _CPU_Interrupt_stack_low, + _CPU_Table.interrupt_stack_size + ); + +#endif + +#if ( CPU_HAS_HARDWARE_INTERRUPT_STACK == TRUE ) + _CPU_Install_interrupt_stack(); +#endif + +} + +/* rtems_interrupt_catch + * + * This directive allows a thread to specify what action to take when + * catching signals. + * + * Input parameters: + * new_isr_handler - address of interrupt service routine (isr) + * vector - interrupt vector number + * old_isr_handler - address at which to store previous ISR address + * + * Output parameters: + * RTEMS_SUCCESSFUL - always succeeds + * *old_isr_handler - previous ISR address + */ + +rtems_status_code rtems_interrupt_catch( + rtems_isr_entry new_isr_handler, + rtems_vector_number vector, + rtems_isr_entry *old_isr_handler +) +{ + if ( !_ISR_Is_vector_number_valid( vector ) ) + return( RTEMS_INVALID_NUMBER ); + + if ( !_ISR_Is_valid_user_handler( new_isr_handler ) ) + return( RTEMS_INVALID_ADDRESS ); + + _ISR_Install_vector( + vector, (proc_ptr)new_isr_handler, (proc_ptr *)old_isr_handler ); + + return( RTEMS_SUCCESSFUL ); +} diff --git a/cpukit/rtems/src/mp.c b/cpukit/rtems/src/mp.c new file mode 100644 index 0000000000..f9522b2296 --- /dev/null +++ b/cpukit/rtems/src/mp.c @@ -0,0 +1,128 @@ +/* + * Multiprocessing 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 +#include +#include +#include +#include +#include +#include +#include + +/*PAGE + * + * _Multiprocessing_Manager_initialization + * + */ + +void _Multiprocessing_Manager_initialization ( void ) +{ + if ( _Configuration_MP_table->node < 1 || + _Configuration_MP_table->node > _Configuration_MP_table->maximum_nodes ) + rtems_fatal_error_occurred( RTEMS_INVALID_NODE ); + + _Internal_threads_Set_MP_receive_server( _Multiprocessing_Receive_server ); +} + +/*PAGE + * + * rtems_multiprocessing_announce + * + */ + +void rtems_multiprocessing_announce ( void ) +{ + _Thread_MP_Ready(); +} + +/*PAGE + * + * _Multiprocessing_Receive_server + * + */ + +Thread _Multiprocessing_Receive_server ( + Thread_Argument ignored +) +{ + + rtems_packet_prefix *the_packet; + + _Thread_Dispatch_disable_level = 1; + + for ( ; ; ) { + + _Internal_threads_System_initialization_thread->Notepads[ 0 ] = 1; + + the_packet = _MPCI_Receive_packet(); + + if ( ! the_packet ) { + _Thread_MP_Block(); + _Thread_Dispatch_disable_level = 1; + } + else { + + _Thread_Executing->receive_packet = the_packet; + + switch ( the_packet->the_class ) { + + case RTEMS_MP_PACKET_INTERNAL_THREADS: + _Internal_threads_MP_Process_packet( the_packet ); + break; + + case RTEMS_MP_PACKET_TASKS: + _RTEMS_tasks_MP_Process_packet( the_packet ); + break; + + case RTEMS_MP_PACKET_MESSAGE_QUEUE: + _Message_queue_MP_Process_packet( the_packet ); + break; + + case RTEMS_MP_PACKET_SEMAPHORE: + _Semaphore_MP_Process_packet( the_packet ); + break; + + case RTEMS_MP_PACKET_PARTITION: + _Partition_MP_Process_packet( the_packet ); + break; + + case RTEMS_MP_PACKET_REGION: + /* Global regions are unsupported at this time */ + break; + + case RTEMS_MP_PACKET_EVENT: + _Event_MP_Process_packet( the_packet ); + break; + + case RTEMS_MP_PACKET_SIGNAL: + _Signal_MP_Process_packet( the_packet ); + break; + } + } + } +} + +/* end of file */ diff --git a/cpukit/rtems/src/msg.c b/cpukit/rtems/src/msg.c new file mode 100644 index 0000000000..7cfe683ce5 --- /dev/null +++ b/cpukit/rtems/src/msg.c @@ -0,0 +1,708 @@ +/* + * Message Queue 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 +#include + +/*PAGE + * + * _Message_queue_Manager_initialization + * + * This routine initializes all message queue manager related + * data structures. + * + * Input parameters: + * maximum_message_queues - number of message queues to initialize + * maximum_message - number of messages per queue + * + * Output parameters: NONE + */ + +void _Message_queue_Manager_initialization( + unsigned32 maximum_message_queues, + unsigned32 maximum_messages +) +{ + + _Objects_Initialize_information( + &_Message_queue_Information, + TRUE, + maximum_message_queues, + sizeof( Message_queue_Control ) + ); + + if ( maximum_messages == 0 ) { + + _Chain_Initialize_empty( &_Message_queue_Inactive_messages ); + + } else { + + + _Chain_Initialize( + &_Message_queue_Inactive_messages, + _Workspace_Allocate_or_fatal_error( + maximum_messages * sizeof( Message_queue_Buffer_control ) + ), + maximum_messages, + sizeof( Message_queue_Buffer_control ) + ); + + } +} + +/*PAGE + * + * rtems_message_queue_create + * + * This directive creates a message queue by allocating and initializing + * a message queue data structure. + * + * Input parameters: + * name - user defined queue name + * count - maximum message and reserved buffer count + * attribute_set - process method + * id - pointer to queue + * + * Output parameters: + * id - queue id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_create( + Objects_Name name, + unsigned32 count, + rtems_attribute attribute_set, + Objects_Id *id +) +{ + register Message_queue_Control *the_message_queue; + + if ( !_Objects_Is_name_valid( name ) ) + return ( RTEMS_INVALID_NAME ); + + if ( _Attributes_Is_global( attribute_set ) && + !_Configuration_Is_multiprocessing() ) + return( RTEMS_MP_NOT_CONFIGURED ); + + _Thread_Disable_dispatch(); /* protects object pointer */ + + the_message_queue = _Message_queue_Allocate(); + + if ( !the_message_queue ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + if ( _Attributes_Is_global( attribute_set ) && + !( _Objects_MP_Open( &_Message_queue_Information, name, + the_message_queue->Object.id, FALSE ) ) ) { + _Message_queue_Free( the_message_queue ); + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + if ( _Attributes_Is_limit( attribute_set ) ) + the_message_queue->maximum_pending_messages = count; + else + the_message_queue->maximum_pending_messages = 0xffffffff; + + the_message_queue->attribute_set = attribute_set; + the_message_queue->number_of_pending_messages = 0; + + _Chain_Initialize_empty( &the_message_queue->Pending_messages ); + + _Thread_queue_Initialize( &the_message_queue->Wait_queue, attribute_set, + STATES_WAITING_FOR_MESSAGE ); + + _Objects_Open( &_Message_queue_Information, + &the_message_queue->Object, name ); + + *id = the_message_queue->Object.id; + + if ( _Attributes_Is_global( attribute_set ) ) + _Message_queue_MP_Send_process_packet( + MESSAGE_QUEUE_MP_ANNOUNCE_CREATE, + the_message_queue->Object.id, + name, + 0 + ); + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_message_queue_ident + * + * This directive returns the system ID associated with + * the message queue name. + * + * Input parameters: + * name - user defined message queue name + * node - node(s) to be searched + * id - pointer to message queue id + * + * Output parameters: + * *id - message queue id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_ident( + Objects_Name name, + unsigned32 node, + Objects_Id *id +) +{ + return( _Objects_Name_to_id( &_Message_queue_Information, name, + node, id ) ); +} + +/*PAGE + * + * rtems_message_queue_delete + * + * This directive allows a thread to delete the message queue specified + * by the given queue identifier. + * + * Input parameters: + * id - queue id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_delete( + Objects_Id id +) +{ + register Message_queue_Control *the_message_queue; + Objects_Locations location; + + the_message_queue = _Message_queue_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( &_Message_queue_Information, + &the_message_queue->Object ); + + if ( the_message_queue->number_of_pending_messages != 0 ) + (void) _Message_queue_Flush_support( the_message_queue ); + else + _Thread_queue_Flush( + &the_message_queue->Wait_queue, + _Message_queue_MP_Send_object_was_deleted + ); + + _Message_queue_Free( the_message_queue ); + + if ( _Attributes_Is_global( the_message_queue->attribute_set ) ) { + _Objects_MP_Close( + &_Message_queue_Information, + the_message_queue->Object.id + ); + + _Message_queue_MP_Send_process_packet( + MESSAGE_QUEUE_MP_ANNOUNCE_DELETE, + the_message_queue->Object.id, + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ); + } + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_message_queue_send + * + * This routine implements the directives q_send. It sends a + * message to the specified message queue. + * + * Input parameters: + * id - pointer to message queue + * buffer - pointer to message buffer + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_send( + Objects_Id id, + void *buffer +) +{ + return( _Message_queue_Submit( + id, + (Message_queue_Buffer *) buffer, + MESSAGE_QUEUE_SEND_REQUEST + ) + ); +} + +/*PAGE + * + * rtems_message_queue_urgent + * + * This routine implements the directives q_urgent. It urgents a + * message to the specified message queue. + * + * Input parameters: + * id - pointer to message queue + * buffer - pointer to message buffer + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_urgent( + Objects_Id id, + void *buffer +) +{ + return( _Message_queue_Submit( + id, + (Message_queue_Buffer *) buffer, + MESSAGE_QUEUE_URGENT_REQUEST + ) + ); +} + +/*PAGE + * + * rtems_message_queue_broadcast + * + * This directive sends a message for every thread waiting on the queue + * designated by id. + * + * Input parameters: + * id - pointer to message queue + * buffer - pointer to message buffer + * count - pointer to area to store number of threads made ready + * + * Output parameters: + * count - number of threads made ready + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_broadcast( + Objects_Id id, + void *buffer, + unsigned32 *count +) +{ + register Message_queue_Control *the_message_queue; + Objects_Locations location; + Thread_Control *the_thread; + unsigned32 number_broadcasted; + + the_message_queue = _Message_queue_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Executing->Wait.return_argument = count; + + return + _Message_queue_MP_Send_request_packet( + MESSAGE_QUEUE_MP_BROADCAST_REQUEST, + id, + (Message_queue_Buffer *) buffer, + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ); + + case OBJECTS_LOCAL: + number_broadcasted = 0; + while ( (the_thread = + _Thread_queue_Dequeue(&the_message_queue->Wait_queue)) ) { + number_broadcasted += 1; + _Message_queue_Copy_buffer( + (Message_queue_Buffer *) buffer, + the_thread->Wait.return_argument + ); + + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + the_thread->receive_packet->return_code = RTEMS_SUCCESSFUL; + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_RECEIVE_RESPONSE, + id, + the_thread + ); + } + } + _Thread_Enable_dispatch(); + *count = number_broadcasted; + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_message_queue_receive + * + * This directive dequeues a message from the designated message queue + * and copies it into the requesting thread's buffer. + * + * Input parameters: + * id - queue id + * buffer - pointer to message buffer + * option_set - options on receive + * timeout - number of ticks to wait + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_receive( + Objects_Id id, + void *buffer, + unsigned32 option_set, + rtems_interval timeout +) +{ + register Message_queue_Control *the_message_queue; + Objects_Locations location; + + the_message_queue = _Message_queue_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Executing->Wait.return_argument = buffer; + return + _Message_queue_MP_Send_request_packet( + MESSAGE_QUEUE_MP_RECEIVE_REQUEST, + id, + buffer, + option_set, + timeout + ); + + case OBJECTS_LOCAL: + if ( !_Message_queue_Seize( the_message_queue, option_set, buffer ) ) + _Thread_queue_Enqueue( &the_message_queue->Wait_queue, timeout ); + _Thread_Enable_dispatch(); + return( _Thread_Executing->Wait.return_code ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_message_queue_flush + * + * This directive removes all pending messages from a queue and returns + * the number of messages removed. If no messages were present then + * a count of zero is returned. + * + * Input parameters: + * id - queue id + * count - return area for count + * + * Output parameters: + * count - number of messages removed ( 0 = empty queue ) + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_message_queue_flush( + Objects_Id id, + unsigned32 *count +) +{ + register Message_queue_Control *the_message_queue; + Objects_Locations location; + + the_message_queue = _Message_queue_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Executing->Wait.return_argument = count; + + return + _Message_queue_MP_Send_request_packet( + MESSAGE_QUEUE_MP_FLUSH_REQUEST, + id, + 0, /* Not used */ + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ); + + case OBJECTS_LOCAL: + if ( the_message_queue->number_of_pending_messages != 0 ) + *count = _Message_queue_Flush_support( the_message_queue ); + else + *count = 0; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * _Message_queue_Seize + * + * This kernel routine dequeues a message, copies the message buffer to + * a given destination buffer, and frees the message buffer to the + * inactive message pool. + * + * Input parameters: + * the_message_queue - pointer to message queue + * option_set - options on receive + * the_buffer - pointer to message buffer to be filled + * + * Output parameters: + * TRUE - if message received or RTEMS_NO_WAIT and no message + * FALSE - if thread is to block + * + * NOTE: Dependent on BUFFER_LENGTH + * + * INTERRUPT LATENCY: + * available + * wait + */ + +boolean _Message_queue_Seize( + Message_queue_Control *the_message_queue, + rtems_option option_set, + Message_queue_Buffer *buffer +) +{ + ISR_Level level; + Message_queue_Buffer_control *the_message; + Thread_Control *executing; + + executing = _Thread_Executing; + executing->Wait.return_code = RTEMS_SUCCESSFUL; + _ISR_Disable( level ); + if ( the_message_queue->number_of_pending_messages != 0 ) { + the_message_queue->number_of_pending_messages -= 1; + + the_message = _Message_queue_Get_pending_message( the_message_queue ); + _ISR_Enable( level ); + _Message_queue_Copy_buffer( &the_message->Contents, buffer ); + _Message_queue_Free_message_buffer( the_message ); + return( TRUE ); + } + + if ( _Options_Is_no_wait( option_set ) ) { + _ISR_Enable( level ); + executing->Wait.return_code = RTEMS_UNSATISFIED; + return( TRUE ); + } + + the_message_queue->Wait_queue.sync = TRUE; + executing->Wait.queue = &the_message_queue->Wait_queue; + executing->Wait.id = the_message_queue->Object.id; + executing->Wait.option_set = option_set; + executing->Wait.return_argument = (unsigned32 *)buffer; + _ISR_Enable( level ); + return( FALSE ); +} + +/*PAGE + * + * _Message_queue_Flush_support + * + * This message manager routine removes all messages from a message queue + * and returns them to the inactive message pool. + * + * Input parameters: + * the_message_queue - pointer to message queue + * + * Output parameters: + * returns - number of messages placed on inactive chain + * + * INTERRUPT LATENCY: + * only case + */ + +unsigned32 _Message_queue_Flush_support( + Message_queue_Control *the_message_queue +) +{ + ISR_Level level; + Chain_Node *inactive_first; + Chain_Node *message_queue_first; + Chain_Node *message_queue_last; + unsigned32 count; + + _ISR_Disable( level ); + inactive_first = _Message_queue_Inactive_messages.first; + message_queue_first = the_message_queue->Pending_messages.first; + message_queue_last = the_message_queue->Pending_messages.last; + + _Message_queue_Inactive_messages.first = message_queue_first; + message_queue_last->next = inactive_first; + inactive_first->previous = message_queue_last; + message_queue_first->previous = + _Chain_Head( &_Message_queue_Inactive_messages ); + + _Chain_Initialize_empty( &the_message_queue->Pending_messages ); + + count = the_message_queue->number_of_pending_messages; + the_message_queue->number_of_pending_messages = 0; + _ISR_Enable( level ); + return( count ); +} + +/*PAGE + * + * _Message_queue_Submit + * + * This routine implements the directives q_send and q_urgent. It + * processes a message that is to be submitted to the designated + * message queue. The message will either be processed as a send + * send message which it will be inserted at the rear of the queue + * or it will be processed as an urgent message which will be inserted + * at the front of the queue. + * + * Input parameters: + * id - pointer to message queue + * the_buffer - pointer to message buffer + * submit_type - send or urgent message + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code _Message_queue_Submit( + Objects_Id id, + Message_queue_Buffer *buffer, + Message_queue_Submit_types submit_type +) +{ + register Message_queue_Control *the_message_queue; + Objects_Locations location; + Thread_Control *the_thread; + Message_queue_Buffer_control *the_message; + + the_message_queue = _Message_queue_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + switch ( submit_type ) { + case MESSAGE_QUEUE_SEND_REQUEST: + return + _Message_queue_MP_Send_request_packet( + MESSAGE_QUEUE_MP_SEND_REQUEST, + id, + buffer, + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ); + + case MESSAGE_QUEUE_URGENT_REQUEST: + return + _Message_queue_MP_Send_request_packet( + MESSAGE_QUEUE_MP_URGENT_REQUEST, + id, + buffer, + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ); + } + case OBJECTS_LOCAL: + the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue ); + + if ( the_thread ) { + + _Message_queue_Copy_buffer( + buffer, + the_thread->Wait.return_argument + ); + + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + the_thread->receive_packet->return_code = RTEMS_SUCCESSFUL; + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_RECEIVE_RESPONSE, + id, + the_thread + ); + + } + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + if ( the_message_queue->number_of_pending_messages == + the_message_queue->maximum_pending_messages ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + the_message = _Message_queue_Allocate_message_buffer(); + + if ( !the_message ) { + _Thread_Enable_dispatch(); + return( RTEMS_UNSATISFIED ); + } + + _Message_queue_Copy_buffer( buffer, &the_message->Contents ); + + the_message_queue->number_of_pending_messages += 1; + + switch ( submit_type ) { + case MESSAGE_QUEUE_SEND_REQUEST: + _Message_queue_Append( the_message_queue, the_message ); + break; + case MESSAGE_QUEUE_URGENT_REQUEST: + _Message_queue_Prepend( the_message_queue, the_message ); + break; + } + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} diff --git a/cpukit/rtems/src/msgmp.c b/cpukit/rtems/src/msgmp.c new file mode 100644 index 0000000000..d3a1a02f33 --- /dev/null +++ b/cpukit/rtems/src/msgmp.c @@ -0,0 +1,397 @@ +/* + * Multiprocessing Support for the Message Queue 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 + +/*PAGE + * + * _Message_queue_MP_Send_process_packet + * + */ + +void _Message_queue_MP_Send_process_packet ( + Message_queue_MP_Remote_operations operation, + Objects_Id message_queue_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + Message_queue_MP_Packet *the_packet; + unsigned32 node; + + switch ( operation ) { + + case MESSAGE_QUEUE_MP_ANNOUNCE_CREATE: + case MESSAGE_QUEUE_MP_ANNOUNCE_DELETE: + case MESSAGE_QUEUE_MP_EXTRACT_PROXY: + + the_packet = _Message_queue_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_MESSAGE_QUEUE; + the_packet->Prefix.length = sizeof ( Message_queue_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Message_queue_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = message_queue_id; + the_packet->name = name; + the_packet->proxy_id = proxy_id; + + if ( operation == MESSAGE_QUEUE_MP_EXTRACT_PROXY ) + node = rtems_get_node( message_queue_id ); + else + node = MPCI_ALL_NODES; + + _MPCI_Send_process_packet( node, &the_packet->Prefix ); + break; + + case MESSAGE_QUEUE_MP_RECEIVE_REQUEST: + case MESSAGE_QUEUE_MP_RECEIVE_RESPONSE: + case MESSAGE_QUEUE_MP_SEND_REQUEST: + case MESSAGE_QUEUE_MP_SEND_RESPONSE: + case MESSAGE_QUEUE_MP_URGENT_REQUEST: + case MESSAGE_QUEUE_MP_URGENT_RESPONSE: + case MESSAGE_QUEUE_MP_BROADCAST_REQUEST: + case MESSAGE_QUEUE_MP_BROADCAST_RESPONSE: + case MESSAGE_QUEUE_MP_FLUSH_REQUEST: + case MESSAGE_QUEUE_MP_FLUSH_RESPONSE: + break; + + } +} + +/*PAGE + * + * _Message_queue_MP_Send_request_packet + * + */ + +rtems_status_code _Message_queue_MP_Send_request_packet ( + Message_queue_MP_Remote_operations operation, + Objects_Id message_queue_id, + Message_queue_Buffer *buffer, + rtems_option option_set, + rtems_interval timeout +) +{ + Message_queue_MP_Packet *the_packet; + + switch ( operation ) { + + case MESSAGE_QUEUE_MP_RECEIVE_REQUEST: + case MESSAGE_QUEUE_MP_SEND_REQUEST: + case MESSAGE_QUEUE_MP_URGENT_REQUEST: + case MESSAGE_QUEUE_MP_BROADCAST_REQUEST: + case MESSAGE_QUEUE_MP_FLUSH_REQUEST: + + the_packet = _Message_queue_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_MESSAGE_QUEUE; + the_packet->Prefix.length = sizeof ( Message_queue_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Message_queue_MP_Packet ) - + sizeof ( Message_queue_Buffer ); + if ( ! _Options_Is_no_wait(option_set)) + the_packet->Prefix.timeout = timeout; + + the_packet->operation = operation; + the_packet->Prefix.id = message_queue_id; + the_packet->option_set = option_set; + + if ( buffer ) + _Message_queue_Copy_buffer( buffer, &the_packet->Buffer ); + + return + _MPCI_Send_request_packet( + rtems_get_node( message_queue_id ), + &the_packet->Prefix, + STATES_WAITING_FOR_MESSAGE + ); + break; + + case MESSAGE_QUEUE_MP_ANNOUNCE_CREATE: + case MESSAGE_QUEUE_MP_ANNOUNCE_DELETE: + case MESSAGE_QUEUE_MP_EXTRACT_PROXY: + case MESSAGE_QUEUE_MP_RECEIVE_RESPONSE: + case MESSAGE_QUEUE_MP_SEND_RESPONSE: + case MESSAGE_QUEUE_MP_URGENT_RESPONSE: + case MESSAGE_QUEUE_MP_BROADCAST_RESPONSE: + case MESSAGE_QUEUE_MP_FLUSH_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_SUCCESSFUL; +} + +/*PAGE + * + * _Message_queue_MP_Send_response_packet + * + */ + +void _Message_queue_MP_Send_response_packet ( + Message_queue_MP_Remote_operations operation, + Objects_Id message_queue_id, + Thread_Control *the_thread +) +{ + Message_queue_MP_Packet *the_packet; + + switch ( operation ) { + + case MESSAGE_QUEUE_MP_RECEIVE_RESPONSE: + case MESSAGE_QUEUE_MP_SEND_RESPONSE: + case MESSAGE_QUEUE_MP_URGENT_RESPONSE: + case MESSAGE_QUEUE_MP_BROADCAST_RESPONSE: + case MESSAGE_QUEUE_MP_FLUSH_RESPONSE: + + the_packet = ( Message_queue_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case MESSAGE_QUEUE_MP_ANNOUNCE_CREATE: + case MESSAGE_QUEUE_MP_ANNOUNCE_DELETE: + case MESSAGE_QUEUE_MP_EXTRACT_PROXY: + case MESSAGE_QUEUE_MP_RECEIVE_REQUEST: + case MESSAGE_QUEUE_MP_SEND_REQUEST: + case MESSAGE_QUEUE_MP_URGENT_REQUEST: + case MESSAGE_QUEUE_MP_BROADCAST_REQUEST: + case MESSAGE_QUEUE_MP_FLUSH_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _Message_queue_MP_Process_packet + * + */ + +void _Message_queue_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + Message_queue_MP_Packet *the_packet; + Thread_Control *the_thread; + boolean ignored; + + the_packet = (Message_queue_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case MESSAGE_QUEUE_MP_ANNOUNCE_CREATE: + + ignored = _Objects_MP_Open( + &_Message_queue_Information, + the_packet->name, + the_packet->Prefix.id, + TRUE + ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case MESSAGE_QUEUE_MP_ANNOUNCE_DELETE: + + _Objects_MP_Close( &_Message_queue_Information, the_packet->Prefix.id ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case MESSAGE_QUEUE_MP_EXTRACT_PROXY: + + the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); + + if ( ! _Thread_Is_null( the_thread ) ) + _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case MESSAGE_QUEUE_MP_RECEIVE_REQUEST: + + the_packet->Prefix.return_code = rtems_message_queue_receive( + the_packet->Prefix.id, + &the_packet->Buffer, + the_packet->option_set, + the_packet->Prefix.timeout + ); + + if ( ! _Status_Is_proxy_blocking( the_packet->Prefix.return_code ) ) + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_RECEIVE_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case MESSAGE_QUEUE_MP_RECEIVE_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _Message_queue_Copy_buffer( + &the_packet->Buffer, + (Message_queue_Buffer *) the_thread->Wait.return_argument + ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case MESSAGE_QUEUE_MP_SEND_REQUEST: + + the_packet->Prefix.return_code = rtems_message_queue_send( + the_packet->Prefix.id, + &the_packet->Buffer + ); + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_SEND_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case MESSAGE_QUEUE_MP_SEND_RESPONSE: + case MESSAGE_QUEUE_MP_URGENT_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case MESSAGE_QUEUE_MP_URGENT_REQUEST: + + the_packet->Prefix.return_code = rtems_message_queue_urgent( + the_packet->Prefix.id, + &the_packet->Buffer + ); + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_URGENT_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case MESSAGE_QUEUE_MP_BROADCAST_REQUEST: + + the_packet->Prefix.return_code = rtems_message_queue_broadcast( + the_packet->Prefix.id, + &the_packet->Buffer, + &the_packet->count + ); + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_BROADCAST_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case MESSAGE_QUEUE_MP_BROADCAST_RESPONSE: + case MESSAGE_QUEUE_MP_FLUSH_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + *(unsigned32 *)the_thread->Wait.return_argument = the_packet->count; + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case MESSAGE_QUEUE_MP_FLUSH_REQUEST: + + the_packet->Prefix.return_code = rtems_message_queue_flush( + the_packet->Prefix.id, + &the_packet->count + ); + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_FLUSH_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + } +} + +/*PAGE + * + * _Message_queue_MP_Send_object_was_deleted + * + */ + +void _Message_queue_MP_Send_object_was_deleted ( + Thread_Control *the_proxy +) +{ + the_proxy->receive_packet->return_code = RTEMS_OBJECT_WAS_DELETED; + + _Message_queue_MP_Send_response_packet( + MESSAGE_QUEUE_MP_RECEIVE_RESPONSE, + the_proxy->Wait.id, + the_proxy + ); +} + +/*PAGE + * + * _Message_queue_MP_Send_extract_proxy + * + */ + +void _Message_queue_MP_Send_extract_proxy ( + Thread_Control *the_thread +) +{ + _Message_queue_MP_Send_process_packet( + MESSAGE_QUEUE_MP_EXTRACT_PROXY, + the_thread->Wait.id, + (Objects_Name) 0, + the_thread->Object.id + ); +} + +/*PAGE + * + * _Message_queue_MP_Get_packet + * + */ + +Message_queue_MP_Packet *_Message_queue_MP_Get_packet ( void ) +{ + return ( (Message_queue_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/part.c b/cpukit/rtems/src/part.c new file mode 100644 index 0000000000..1fa2e0e716 --- /dev/null +++ b/cpukit/rtems/src/part.c @@ -0,0 +1,322 @@ +/* + * Partition 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 + +/*PAGE + * + * _Partition_Manager_initialization + * + * This routine initializes all partition manager related + * data structures. + * + * Input parameters: + * maximum_partitions - number of partitions to initialize + * + * Output parameters: NONE + */ + +void _Partition_Manager_initialization( + unsigned32 maximum_partitions +) +{ + _Objects_Initialize_information( + &_Partition_Information, + TRUE, + maximum_partitions, + sizeof( Partition_Control ) + ); + +} + +/*PAGE + * + * rtems_partition_create + * + * This directive creates a partiton of fixed sized buffers from the + * given contiguous memory area. + * + * Input parameters: + * name - user defined partition name + * starting_address - physical start address of partition + * length - physical length in bytes + * buffer_size - size of buffers in bytes + * attribute_set - partition attributes + * id - pointer to partition id + * + * Output parameters: + * id - partition id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_partition_create( + Objects_Name name, + void *starting_address, + unsigned32 length, + unsigned32 buffer_size, + rtems_attribute attribute_set, + Objects_Id *id +) +{ + register Partition_Control *the_partition; + + if ( !_Objects_Is_name_valid( name ) ) + return ( RTEMS_INVALID_NAME ); + + if ( length == 0 || buffer_size == 0 || length < buffer_size || + !_Partition_Is_buffer_size_aligned( buffer_size ) ) + return ( RTEMS_INVALID_SIZE ); + + if ( !_Addresses_Is_aligned( starting_address ) ) + return( RTEMS_INVALID_ADDRESS ); + + if ( _Attributes_Is_global( attribute_set ) && + !_Configuration_Is_multiprocessing() ) + return( RTEMS_MP_NOT_CONFIGURED ); + + _Thread_Disable_dispatch(); /* prevents deletion */ + + the_partition = _Partition_Allocate(); + + if ( !the_partition ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + if ( _Attributes_Is_global( attribute_set ) && + !( _Objects_MP_Open( &_Partition_Information, name, + the_partition->Object.id, FALSE ) ) ) { + _Partition_Free( the_partition ); + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + the_partition->starting_address = starting_address; + the_partition->length = length; + the_partition->buffer_size = buffer_size; + the_partition->attribute_set = attribute_set; + the_partition->number_of_used_blocks = 0; + + _Chain_Initialize( &the_partition->Memory, starting_address, + length / buffer_size, buffer_size ); + + _Objects_Open( &_Partition_Information, &the_partition->Object, name ); + + *id = the_partition->Object.id; + if ( _Attributes_Is_global( attribute_set ) ) + _Partition_MP_Send_process_packet( + PARTITION_MP_ANNOUNCE_CREATE, + the_partition->Object.id, + name, + 0 /* Not used */ + ); + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_partition_ident + * + * This directive returns the system ID associated with + * the partition name. + * + * Input parameters: + * name - user defined partition name + * node - node(s) to be searched + * id - pointer to partition id + * + * Output parameters: + * *id - partition id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_partition_ident( + Objects_Name name, + unsigned32 node, + Objects_Id *id +) +{ + return( _Objects_Name_to_id( &_Partition_Information, name, node, id ) ); +} + +/*PAGE + * + * rtems_partition_delete + * + * This directive allows a thread to delete a partition specified by + * the partition identifier, provided that none of its buffers are + * still allocated. + * + * Input parameters: + * id - partition id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_partition_delete( + Objects_Id id +) +{ + register Partition_Control *the_partition; + Objects_Locations location; + + the_partition = _Partition_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 ( the_partition->number_of_used_blocks == 0 ) { + _Objects_Close( &_Partition_Information, &the_partition->Object ); + _Partition_Free( the_partition ); + if ( _Attributes_Is_global( the_partition->attribute_set ) ) { + + _Objects_MP_Close( + &_Partition_Information, + the_partition->Object.id + ); + + _Partition_MP_Send_process_packet( + PARTITION_MP_ANNOUNCE_DELETE, + the_partition->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_RESOURCE_IN_USE ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_partition_get_buffer + * + * This directive will obtain a buffer from a buffer partition. + * + * Input parameters: + * id - partition id + * buffer - pointer to buffer address + * + * Output parameters: + * buffer - pointer to buffer address filled in + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_partition_get_buffer( + Objects_Id id, + void **buffer +) +{ + register Partition_Control *the_partition; + Objects_Locations location; + void *the_buffer; + + the_partition = _Partition_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + _Thread_Executing->Wait.return_argument = buffer; + return( + _Partition_MP_Send_request_packet( + PARTITION_MP_GET_BUFFER_REQUEST, + id, + 0 /* Not used */ + ) + ); + case OBJECTS_LOCAL: + the_buffer = _Partition_Allocate_buffer( the_partition ); + if ( the_buffer ) { + the_partition->number_of_used_blocks += 1; + _Thread_Enable_dispatch(); + *buffer = the_buffer; + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_UNSATISFIED ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_partition_return_buffer + * + * This directive will return the given buffer to the specified + * buffer partition. + * + * Input parameters: + * id - partition id + * buffer - pointer to buffer address + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_partition_return_buffer( + Objects_Id id, + void *buffer +) +{ + register Partition_Control *the_partition; + Objects_Locations location; + + the_partition = _Partition_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + return( + _Partition_MP_Send_request_packet( + PARTITION_MP_RETURN_BUFFER_REQUEST, + id, + buffer + ) + ); + case OBJECTS_LOCAL: + if ( _Partition_Is_buffer_valid( buffer, the_partition ) ) { + _Partition_Free_buffer( the_partition, buffer ); + the_partition->number_of_used_blocks -= 1; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_INVALID_ADDRESS ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} diff --git a/cpukit/rtems/src/partmp.c b/cpukit/rtems/src/partmp.c new file mode 100644 index 0000000000..9cc1723106 --- /dev/null +++ b/cpukit/rtems/src/partmp.c @@ -0,0 +1,300 @@ +/* + * Multiprocessing Support for the Partition 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 + +/*PAGE + * + * _Partition_MP_Send_process_packet + * + */ + +void _Partition_MP_Send_process_packet ( + Partition_MP_Remote_operations operation, + Objects_Id partition_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + Partition_MP_Packet *the_packet; + unsigned32 node; + + switch ( operation ) { + + case PARTITION_MP_ANNOUNCE_CREATE: + case PARTITION_MP_ANNOUNCE_DELETE: + case PARTITION_MP_EXTRACT_PROXY: + + the_packet = _Partition_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_PARTITION; + the_packet->Prefix.length = sizeof ( Partition_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Partition_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = partition_id; + the_packet->name = name; + the_packet->proxy_id = proxy_id; + + if ( operation == PARTITION_MP_EXTRACT_PROXY ) + node = rtems_get_node( partition_id ); + else + node = MPCI_ALL_NODES; + + _MPCI_Send_process_packet( node, &the_packet->Prefix ); + break; + + case PARTITION_MP_GET_BUFFER_REQUEST: + case PARTITION_MP_GET_BUFFER_RESPONSE: + case PARTITION_MP_RETURN_BUFFER_REQUEST: + case PARTITION_MP_RETURN_BUFFER_RESPONSE: + break; + } +} + +/*PAGE + * + * _Partition_MP_Send_request_packet + * + */ + +rtems_status_code _Partition_MP_Send_request_packet ( + Partition_MP_Remote_operations operation, + Objects_Id partition_id, + void *buffer +) +{ + Partition_MP_Packet *the_packet; + + switch ( operation ) { + + case PARTITION_MP_GET_BUFFER_REQUEST: + case PARTITION_MP_RETURN_BUFFER_REQUEST: + + the_packet = _Partition_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_PARTITION; + the_packet->Prefix.length = sizeof ( Partition_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Partition_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = partition_id; + the_packet->buffer = buffer; + + return + _MPCI_Send_request_packet( + rtems_get_node( partition_id ), + &the_packet->Prefix, + STATES_READY /* Not used */ + ); + + break; + + case PARTITION_MP_ANNOUNCE_CREATE: + case PARTITION_MP_ANNOUNCE_DELETE: + case PARTITION_MP_EXTRACT_PROXY: + case PARTITION_MP_GET_BUFFER_RESPONSE: + case PARTITION_MP_RETURN_BUFFER_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_SUCCESSFUL; +} + +/*PAGE + * + * _Partition_MP_Send_response_packet + * + */ + +void _Partition_MP_Send_response_packet ( + Partition_MP_Remote_operations operation, + Objects_Id partition_id, + Thread_Control *the_thread +) +{ + Partition_MP_Packet *the_packet; + + switch ( operation ) { + + case PARTITION_MP_GET_BUFFER_RESPONSE: + case PARTITION_MP_RETURN_BUFFER_RESPONSE: + + the_packet = ( Partition_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case PARTITION_MP_ANNOUNCE_CREATE: + case PARTITION_MP_ANNOUNCE_DELETE: + case PARTITION_MP_EXTRACT_PROXY: + case PARTITION_MP_GET_BUFFER_REQUEST: + case PARTITION_MP_RETURN_BUFFER_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _Partition_MP_Process_packet + * + */ + +void _Partition_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + Partition_MP_Packet *the_packet; + Thread_Control *the_thread; + boolean ignored; + + the_packet = (Partition_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case PARTITION_MP_ANNOUNCE_CREATE: + + ignored = _Objects_MP_Open( + &_Partition_Information, + the_packet->name, + the_packet->Prefix.id, + TRUE + ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case PARTITION_MP_ANNOUNCE_DELETE: + + _Objects_MP_Close( &_Partition_Information, the_packet->Prefix.id ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case PARTITION_MP_EXTRACT_PROXY: + + the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); + + if ( ! _Thread_Is_null( the_thread ) ) + _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case PARTITION_MP_GET_BUFFER_REQUEST: + + the_packet->Prefix.return_code = rtems_partition_get_buffer( + the_packet->Prefix.id, + &the_packet->buffer + ); + + _Partition_MP_Send_response_packet( + PARTITION_MP_GET_BUFFER_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case PARTITION_MP_GET_BUFFER_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + *(void **)the_thread->Wait.return_argument = the_packet->buffer; + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case PARTITION_MP_RETURN_BUFFER_REQUEST: + + the_packet->Prefix.return_code = rtems_partition_return_buffer( + the_packet->Prefix.id, + the_packet->buffer + ); + + _Partition_MP_Send_response_packet( + PARTITION_MP_RETURN_BUFFER_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case PARTITION_MP_RETURN_BUFFER_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + } +} + +/*PAGE + * + * _Partition_MP_Send_object_was_deleted + * + * This routine is not needed by the Partition since a partition + * cannot be deleted when buffers are in use. + * + */ + +/*PAGE + * + * _Partition_MP_Send_extract_proxy + * + */ + +void _Partition_MP_Send_extract_proxy ( + Thread_Control *the_thread +) +{ + _Partition_MP_Send_process_packet( + PARTITION_MP_EXTRACT_PROXY, + the_thread->Wait.id, + (Objects_Name) 0, + the_thread->Object.id + ); + +} + +/*PAGE + * + * _Partition_MP_Get_packet + * + */ + +Partition_MP_Packet *_Partition_MP_Get_packet ( void ) +{ + return ( (Partition_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/ratemon.c b/cpukit/rtems/src/ratemon.c new file mode 100644 index 0000000000..3c0733a3ab --- /dev/null +++ b/cpukit/rtems/src/ratemon.c @@ -0,0 +1,401 @@ +/* + * Rate Monotonic 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 + +/*PAGE + * + * _Rate_monotonic_Manager_initialization + * + * This routine initializes all Rate Monotonic Manager related + * data structures. + * + * Input parameters: + * maximum_periods - number of periods timers to initialize + * + * Output parameters: NONE + * + * NOTE: The Rate Monotonic Manager is built on top of the Watchdog + * Handler. + */ + +void _Rate_monotonic_Manager_initialization( + unsigned32 maximum_periods +) +{ + _Objects_Initialize_information( + &_Rate_monotonic_Information, + FALSE, + maximum_periods, + sizeof( Rate_monotonic_Control ) + ); +} + +/*PAGE + * + * rtems_rate_monotonic_create + * + * This directive creates a rate monotonic timer and performs + * some initialization. + * + * Input parameters: + * name - name of period + * id - pointer to rate monotonic id + * + * Output parameters: + * id - rate monotonic id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_rate_monotonic_create( + Objects_Name name, + Objects_Id *id +) +{ + Rate_monotonic_Control *the_period; + + if ( !_Objects_Is_name_valid( name ) ) + return( RTEMS_INVALID_NAME ); + + _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; + + _Objects_Open( &_Rate_monotonic_Information, &the_period->Object, name ); + + *id = the_period->Object.id; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_rate_monotonic_ident + * + * This directive returns the system ID associated with + * the rate monotonic period name. + * + * Input parameters: + * name - user defined period name + * id - pointer to period id + * + * Output parameters: + * *id - region id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_rate_monotonic_ident( + Objects_Name name, + Objects_Id *id +) +{ + return _Objects_Name_to_id( + &_Rate_monotonic_Information, + name, + RTEMS_SEARCH_LOCAL_NODE, + id + ); +} + +/*PAGE + * + * rtems_rate_monotonic_cancel + * + * This directive allows a thread to cancel a rate monotonic timer. + * + * Input parameters: + * id - rate monotonic id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful and caller is not the owning thread + * error code - if unsuccessful + */ + +rtems_status_code rtems_rate_monotonic_cancel( + Objects_Id id +) +{ + Rate_monotonic_Control *the_period; + Objects_Locations location; + + the_period = _Rate_monotonic_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + if ( !_Thread_Is_executing( the_period->owner ) ) { + _Thread_Enable_dispatch(); + return( RTEMS_NOT_OWNER_OF_RESOURCE ); + } + (void) _Watchdog_Remove( &the_period->Timer ); + the_period->state = RATE_MONOTONIC_INACTIVE; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_rate_monotonic_delete + * + * This directive allows a thread to delete a rate monotonic timer. + * + * Input parameters: + * id - rate monotonic id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_rate_monotonic_delete( + Objects_Id id +) +{ + Rate_monotonic_Control *the_period; + Objects_Locations location; + + the_period = _Rate_monotonic_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + _Objects_Close( &_Rate_monotonic_Information, &the_period->Object ); + (void) _Watchdog_Remove( &the_period->Timer ); + the_period->state = RATE_MONOTONIC_INACTIVE; + _Rate_monotonic_Free( the_period ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_rate_monotonic_period + * + * This directive allows a thread to manipulate a rate monotonic timer. + * + * Input parameters: + * id - rate monotonic id + * length - length of period (in ticks) + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_rate_monotonic_period( + Objects_Id id, + rtems_interval length +) +{ + Rate_monotonic_Control *the_period; + Objects_Locations location; + rtems_status_code return_value; + + the_period = _Rate_monotonic_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + 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_ACTIVE: + return_value = RTEMS_SUCCESSFUL; + break; + case RATE_MONOTONIC_EXPIRED: + return_value = RTEMS_TIMEOUT; + break; + default: /* unreached -- only to remove warnings */ + return_value = RTEMS_INTERNAL_ERROR; + break; + } + _Thread_Enable_dispatch(); + return( return_value ); + } + + switch ( the_period->state ) { + case RATE_MONOTONIC_INACTIVE: + the_period->state = RATE_MONOTONIC_ACTIVE; + _Watchdog_Initialize( + &the_period->Timer, + _Rate_monotonic_Timeout, + id, + NULL + ); + _Watchdog_Insert_ticks( + &the_period->Timer, length, WATCHDOG_ACTIVATE_NOW ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + + case RATE_MONOTONIC_ACTIVE: +/* following is and could be a critical section problem */ + _Thread_Executing->Wait.id = the_period->Object.id; + if ( _Rate_monotonic_Set_state( the_period ) ) { + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + /* has expired -- fall into next case */ + case RATE_MONOTONIC_EXPIRED: + the_period->state = RATE_MONOTONIC_ACTIVE; + _Watchdog_Insert_ticks( + &the_period->Timer, length, WATCHDOG_ACTIVATE_NOW ); + _Thread_Enable_dispatch(); + return( RTEMS_TIMEOUT ); + } + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * _Rate_monotonic_Set_state + * + * This kernel routine sets the STATES_WAITING_FOR_PERIOD state in + * the running thread's tcb if the specified period has not expired. + * The ready chain is adjusted if necessary. + * + * Input parameters: + * the_period - pointer to period control block + * + * Output parameters: + * TRUE - if blocked successfully for period + * FALSE - if period has expired + * + * INTERRUPT LATENCY: + * delete node + * priority map + * select heir + */ + +boolean _Rate_monotonic_Set_state( +Rate_monotonic_Control *the_period +) +{ + Thread_Control *executing; + Chain_Control *ready; + ISR_Level level; + States_Control old_state; + + executing = _Thread_Executing; + ready = executing->ready; + _ISR_Disable( level ); + + old_state = executing->current_state; + + if ( _Rate_monotonic_Is_expired( the_period ) ) { + _ISR_Enable( level ); + return( FALSE ); + } + + executing->current_state = + _States_Set( STATES_WAITING_FOR_PERIOD, old_state ); + + if ( _States_Is_ready( old_state ) ) { + if ( _Chain_Has_only_one_node( ready ) ) { + _Chain_Initialize_empty( ready ); + _Priority_Remove_from_bit_map( &executing->Priority_map ); + _ISR_Flash( level ); + } else { + _Chain_Extract_unprotected( &executing->Object.Node ); + _ISR_Flash( level ); + } + + if ( _Thread_Is_heir( executing ) ) + _Thread_Calculate_heir(); + + _Context_Switch_necessary = TRUE; + } + + _ISR_Enable( level ); + return( TRUE ); +} + +/*PAGE + * + * _Rate_monotonic_Timeout + * + * This routine processes a period ending. If the owning thread + * is waiting for the period, that thread is unblocked and the + * period reinitiated. Otherwise, the period is expired. + * This routine is called by the watchdog handler. + * + * Input parameters: + * id - period id + * + * Output parameters: NONE + */ + +void _Rate_monotonic_Timeout( + Objects_Id id, + void *ignored +) +{ + Rate_monotonic_Control *the_period; + Objects_Locations location; + Thread_Control *the_thread; + + the_period = _Rate_monotonic_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + case OBJECTS_REMOTE: /* impossible */ + break; + case OBJECTS_LOCAL: + the_thread = the_period->owner; + if ( _States_Is_waiting_for_period( the_thread->current_state ) && + the_thread->Wait.id == the_period->Object.id ) { + _Thread_Unblock( the_thread ); + _Watchdog_Reset( &the_period->Timer ); + } + else + the_period->state = RATE_MONOTONIC_EXPIRED; + _Thread_Unnest_dispatch(); + break; + } +} + diff --git a/cpukit/rtems/src/region.c b/cpukit/rtems/src/region.c new file mode 100644 index 0000000000..c62214eaf6 --- /dev/null +++ b/cpukit/rtems/src/region.c @@ -0,0 +1,456 @@ +/* + * Region 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 + +/*PAGE + * + * _Region_Manager_initialization + * + * This routine initializes all region manager related data structures. + * + * Input parameters: + * maximum_regions - number of regions to initialize + * + * Output parameters: NONE + */ + +void _Region_Manager_initialization( + unsigned32 maximum_regions +) +{ + _Objects_Initialize_information( + &_Region_Information, + FALSE, + maximum_regions, + sizeof( Region_Control ) + ); +} + +/*PAGE + * + * rtems_region_create + * + * This directive creates a region of physical contiguous memory area + * from which variable sized segments can be allocated. + * + * Input parameters: + * name - user defined region name + * starting_address - physical start address of region + * length - physical length in bytes + * page_size - page size in bytes + * attribute_set - region attributes + * id - address of region id to set + * + * Output parameters: + * id - region id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_create( + Objects_Name name, + void *starting_address, + unsigned32 length, + unsigned32 page_size, + rtems_attribute attribute_set, + Objects_Id *id +) +{ + Region_Control *the_region; + + if ( !_Objects_Is_name_valid( name ) ) + return ( RTEMS_INVALID_NAME ); + + if ( !_Addresses_Is_aligned( starting_address ) ) + return( RTEMS_INVALID_ADDRESS ); + + _Thread_Disable_dispatch(); /* to prevent deletion */ + + the_region = _Region_Allocate(); + + if ( !the_region ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + the_region->maximum_segment_size = + _Heap_Initialize(&the_region->Memory, starting_address, length, page_size); + + if ( !the_region->maximum_segment_size ) { + _Region_Free( the_region ); + _Thread_Enable_dispatch(); + return( RTEMS_INVALID_SIZE ); + } + + the_region->starting_address = starting_address; + the_region->length = length; + the_region->page_size = page_size; + the_region->attribute_set = attribute_set; + the_region->number_of_used_blocks = 0; + + _Thread_queue_Initialize( + &the_region->Wait_queue, attribute_set, STATES_WAITING_FOR_SEGMENT ); + + _Objects_Open( &_Region_Information, &the_region->Object, name ); + + *id = the_region->Object.id; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_region_ident + * + * This directive returns the system ID associated with + * the region name. + * + * Input parameters: + * name - user defined region name + * id - pointer to region id + * + * Output parameters: + * *id - region id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_ident( + Objects_Name name, + Objects_Id *id +) +{ + return _Objects_Name_to_id( + &_Region_Information, + name, + RTEMS_SEARCH_LOCAL_NODE, + id + ); +} + +/*PAGE + * + * rtems_region_delete + * + * This directive allows a thread to delete a region specified by + * the region identifier, provided that none of its segments are + * still allocated. + * + * Input parameters: + * id - region id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_delete( + Objects_Id id +) +{ + register Region_Control *the_region; + Objects_Locations location; + + the_region = _Region_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + _Region_Debug_Walk( the_region, 5 ); + if ( the_region->number_of_used_blocks == 0 ) { + _Objects_Close( &_Region_Information, &the_region->Object ); + _Region_Free( the_region ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_RESOURCE_IN_USE ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_region_extend + * + * This directive attempts to grow a region of physical contiguous memory area + * from which variable sized segments can be allocated. + * + * Input parameters: + * id - id of region to grow + * start - starting address of memory area for extension + * length - physical length in bytes to grow the region + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_extend( + Objects_Id id, + void *starting_address, + unsigned32 length +) +{ + Region_Control *the_region; + Objects_Locations location; + unsigned32 amount_extended; + Heap_Extend_status heap_status; + rtems_status_code status; + + status = RTEMS_SUCCESSFUL; + + the_region = _Region_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + + heap_status = _Heap_Extend( + &the_region->Memory, + starting_address, + length, + &amount_extended + ); + + switch ( heap_status ) { + case HEAP_EXTEND_SUCCESSFUL: + the_region->length += amount_extended; + the_region->maximum_segment_size += amount_extended; + break; + case HEAP_EXTEND_ERROR: + status = RTEMS_INVALID_ADDRESS; + break; + case HEAP_EXTEND_NOT_IMPLEMENTED: + status = RTEMS_NOT_IMPLEMENTED; + break; + } + _Thread_Enable_dispatch(); + return( status ); + } + + return( RTEMS_INTERNAL_ERROR ); +} + +/*PAGE + * + * rtems_region_get_segment + * + * This directive will obtain a segment from the given region. + * + * Input parameters: + * id - region id + * size - segment size in bytes + * option_set - wait option + * timeout - number of ticks to wait (0 means wait forever) + * segment - pointer to segment address + * + * Output parameters: + * segment - pointer to segment address filled in + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_get_segment( + Objects_Id id, + unsigned32 size, + rtems_option option_set, + rtems_interval timeout, + void **segment +) +{ + register Region_Control *the_region; + Objects_Locations location; + Thread_Control *executing; + void *the_segment; + + if ( size == 0 ) + return( RTEMS_INVALID_SIZE ); + + executing = _Thread_Executing; + the_region = _Region_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + if ( size > the_region->maximum_segment_size ) { + _Thread_Enable_dispatch(); + return( RTEMS_INVALID_SIZE ); + } + + _Region_Debug_Walk( the_region, 1 ); + + the_segment = _Region_Allocate_segment( the_region, size ); + + _Region_Debug_Walk( the_region, 2 ); + + if ( the_segment ) { + the_region->number_of_used_blocks += 1; + _Thread_Enable_dispatch(); + *segment = the_segment; + return( RTEMS_SUCCESSFUL ); + } + + if ( _Options_Is_no_wait( option_set ) ) { + _Thread_Enable_dispatch(); + return( RTEMS_UNSATISFIED ); + } + + executing->Wait.queue = &the_region->Wait_queue; + executing->Wait.id = id; + executing->Wait.Extra.segment_size = size; + executing->Wait.return_argument = (unsigned32 *) segment; + + the_region->Wait_queue.sync = TRUE; + + _Thread_queue_Enqueue( &the_region->Wait_queue, timeout ); + + _Thread_Enable_dispatch(); + return( executing->Wait.return_code ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} +/*PAGE + * + * rtems_region_get_segment_size + * + * This directive will return the size of the segment indicated + * + * Input parameters: + * id - region id + * segment - segment address + * size - pointer to segment size in bytes + * + * Output parameters: + * size - segment size in bytes filled in + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_get_segment_size( + Objects_Id id, + void *segment, + unsigned32 *size +) +{ + register Region_Control *the_region; + Objects_Locations location; + Thread_Control *executing; + + executing = _Thread_Executing; + the_region = _Region_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + + if ( _Heap_Size_of_user_area( &the_region->Memory, segment, size ) ) { + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_INVALID_ADDRESS ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_region_return_segment + * + * This directive will return a segment to its region. + * + * Input parameters: + * id - region id + * segment - pointer to segment address + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_region_return_segment( + Objects_Id id, + void *segment +) +{ + register Region_Control *the_region; + Thread_Control *the_thread; + Objects_Locations location; + void **the_segment; + int status; + + the_region = _Region_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* this error cannot be returned */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + + _Region_Debug_Walk( the_region, 3 ); + + status = _Region_Free_segment( the_region, segment ); + + _Region_Debug_Walk( the_region, 4 ); + + if ( !status ) { + _Thread_Enable_dispatch(); + return( RTEMS_INVALID_ADDRESS ); + } + + the_region->number_of_used_blocks -= 1; + for ( ; ; ) { + the_thread = _Thread_queue_First( &the_region->Wait_queue ); + + if ( the_thread == NULL ) + break; + + the_segment = _Region_Allocate_segment( + the_region, the_thread->Wait.Extra.segment_size ); + + if ( the_segment == NULL ) + break; + + *(void **)the_thread->Wait.return_argument = the_segment; + the_region->number_of_used_blocks += 1; + _Thread_queue_Extract( &the_region->Wait_queue, the_thread ); + the_thread->Wait.return_code = RTEMS_SUCCESSFUL; + } + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} diff --git a/cpukit/rtems/src/regionmp.c b/cpukit/rtems/src/regionmp.c new file mode 100644 index 0000000000..558ae1639a --- /dev/null +++ b/cpukit/rtems/src/regionmp.c @@ -0,0 +1,308 @@ +/* + * Multiprocessing Support for the Region 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 + +/*PAGE + * + * _Region_MP_Send_process_packet + * + */ + +void _Region_MP_Send_process_packet ( + Region_MP_Remote_operations operation, + Objects_Id region_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + Region_MP_Packet *the_packet; + unsigned32 node; + + switch ( operation ) { + + case REGION_MP_ANNOUNCE_CREATE: + case REGION_MP_ANNOUNCE_DELETE: + case REGION_MP_EXTRACT_PROXY: + + the_packet = _Region_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_REGION; + the_packet->Prefix.length = sizeof ( Region_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Region_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = region_id; + the_packet->name = name; + the_packet->proxy_id = proxy_id; + + if ( operation == REGION_MP_EXTRACT_PROXY ) + node = rtems_get_node( region_id ); + else + node = MPCI_ALL_NODES; + + _MPCI_Send_process_packet( node, &the_packet->Prefix ); + break; + + case REGION_MP_GET_SEGMENT_REQUEST: + case REGION_MP_GET_SEGMENT_RESPONSE: + case REGION_MP_RETURN_SEGMENT_REQUEST: + case REGION_MP_RETURN_SEGMENT_RESPONSE: + break; + } +} + +/*PAGE + * + * _Region_MP_Send_request_packet + * + */ + +rtems_status_code _Region_MP_Send_request_packet ( + Region_MP_Remote_operations operation, + Objects_Id region_id, + void *segment, + unsigned32 size, + rtems_option option_set, + rtems_interval timeout +) +{ + Region_MP_Packet *the_packet; + + switch ( operation ) { + + case REGION_MP_GET_SEGMENT_REQUEST: + case REGION_MP_RETURN_SEGMENT_REQUEST: + + the_packet = _Region_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_REGION; + the_packet->Prefix.length = sizeof ( Region_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Region_MP_Packet ); + if ( ! _Options_Is_no_wait(option_set)) + the_packet->Prefix.timeout = timeout; + + the_packet->operation = operation; + the_packet->Prefix.id = region_id; + the_packet->segment = segment; + the_packet->size = size; + the_packet->option_set = option_set; + + return _MPCI_Send_request_packet( + rtems_get_node( region_id ), + &the_packet->Prefix, + STATES_READY /* Not used */ + ); + break; + + case REGION_MP_ANNOUNCE_CREATE: + case REGION_MP_ANNOUNCE_DELETE: + case REGION_MP_EXTRACT_PROXY: + case REGION_MP_GET_SEGMENT_RESPONSE: + case REGION_MP_RETURN_SEGMENT_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_INTERNAL_ERROR; +} + +/*PAGE + * + * _Region_MP_Send_response_packet + * + */ + +void _Region_MP_Send_response_packet ( + Region_MP_Remote_operations operation, + Objects_Id region_id, + Thread_Control *the_thread +) +{ + Region_MP_Packet *the_packet; + + switch ( operation ) { + + case REGION_MP_GET_SEGMENT_RESPONSE: + case REGION_MP_RETURN_SEGMENT_RESPONSE: + + the_packet = ( Region_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case REGION_MP_ANNOUNCE_CREATE: + case REGION_MP_ANNOUNCE_DELETE: + case REGION_MP_EXTRACT_PROXY: + case REGION_MP_GET_SEGMENT_REQUEST: + case REGION_MP_RETURN_SEGMENT_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _Region_MP_Process_packet + * + */ + +void _Region_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + Region_MP_Packet *the_packet; + Thread_Control *the_thread; + boolean ignored; + + the_packet = (Region_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case REGION_MP_ANNOUNCE_CREATE: + + ignored = _Objects_MP_Open( + &_Region_Information, + the_packet->name, + the_packet->Prefix.id, + TRUE + ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case REGION_MP_ANNOUNCE_DELETE: + + _Objects_MP_Close( &_Region_Information, the_packet->Prefix.id ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case REGION_MP_EXTRACT_PROXY: + + the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); + + if ( ! _Thread_Is_null( the_thread ) ) + _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case REGION_MP_GET_SEGMENT_REQUEST: + + the_packet->Prefix.return_code = rtems_region_get_segment( + the_packet->Prefix.id, + the_packet->size, + the_packet->option_set, + the_packet->Prefix.timeout, + &the_packet->segment + ); + + _Region_MP_Send_response_packet( + REGION_MP_GET_SEGMENT_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case REGION_MP_GET_SEGMENT_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + *(void **)the_thread->Wait.return_argument = the_packet->segment; + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case REGION_MP_RETURN_SEGMENT_REQUEST: + + the_packet->Prefix.return_code = rtems_region_return_segment( + the_packet->Prefix.id, + the_packet->segment + ); + + _Region_MP_Send_response_packet( + REGION_MP_RETURN_SEGMENT_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case REGION_MP_RETURN_SEGMENT_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + } +} + +/*PAGE + * + * _Region_MP_Send_object_was_deleted + * + * This routine is not needed by the Region since a region + * cannot be deleted when segments are in use. + * + */ + +/*PAGE + * + * _Region_MP_Send_extract_proxy + * + */ + +void _Region_MP_Send_extract_proxy ( + Thread_Control *the_thread +) +{ + _Region_MP_Send_process_packet( + REGION_MP_EXTRACT_PROXY, + the_thread->Wait.id, + (Objects_Name) 0, + the_thread->Object.id + ); +} + +/*PAGE + * + * _Region_MP_Get_packet + * + */ + +Region_MP_Packet *_Region_MP_Get_packet ( void ) +{ + return ( (Region_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/rtclock.c b/cpukit/rtems/src/rtclock.c new file mode 100644 index 0000000000..f82baa6337 --- /dev/null +++ b/cpukit/rtems/src/rtclock.c @@ -0,0 +1,153 @@ +/* + * Clock 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 + +/*PAGE + * + * rtems_clock_get + * + * This directive returns the current date and time. If the time has + * not been set by a tm_set then an error is returned. + * + * Input parameters: + * option - which value to return + * time_buffer - pointer to output buffer (a time and date structure + * or an interval) + * + * Output parameters: + * time_buffer - output filled in + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_clock_get( + rtems_clock_get_options option, + void *time_buffer +) +{ + ISR_Level level; + rtems_interval tmp; + + switch ( option ) { + case RTEMS_CLOCK_GET_TOD: + if ( !_TOD_Is_set() ) + return( RTEMS_NOT_DEFINED ); + + *(rtems_time_of_day *)time_buffer = _TOD_Current; + return( RTEMS_SUCCESSFUL ); + + case RTEMS_CLOCK_GET_SECONDS_SINCE_EPOCH: + if ( !_TOD_Is_set() ) + return( RTEMS_NOT_DEFINED ); + + *(rtems_interval *)time_buffer = _TOD_Seconds_since_epoch; + return( RTEMS_SUCCESSFUL ); + + case RTEMS_CLOCK_GET_TICKS_SINCE_BOOT: + *(rtems_interval *)time_buffer = _TOD_Ticks_since_boot; + return( RTEMS_SUCCESSFUL ); + + case RTEMS_CLOCK_GET_TICKS_PER_SECOND: + *(rtems_interval *)time_buffer = _TOD_Ticks_per_second; + return( RTEMS_SUCCESSFUL ); + + case RTEMS_CLOCK_GET_TIME_VALUE: + if ( !_TOD_Is_set() ) + return( RTEMS_NOT_DEFINED ); + + _ISR_Disable( level ); + ((rtems_clock_time_value *)time_buffer)->seconds = + _TOD_Seconds_since_epoch; + tmp = _TOD_Current.ticks; + _ISR_Enable( level ); + + tmp *= _Configuration_Table->microseconds_per_tick; + ((rtems_clock_time_value *)time_buffer)->microseconds = tmp; + + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_SUCCESSFUL ); /* should never get here */ + +} + +/*PAGE + * + * rtems_clock_set + * + * This directive sets the date and time for this node. + * + * 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_clock_set( + rtems_time_of_day *time_buffer +) +{ + rtems_status_code local_result; + rtems_interval seconds; + + local_result = _TOD_Validate( time_buffer ); + if ( rtems_is_status_successful( local_result ) ) { + seconds = _TOD_To_seconds( time_buffer ); + _Thread_Disable_dispatch(); + _TOD_Set( time_buffer, seconds ); + _Thread_Enable_dispatch(); + + } + return( local_result ); +} + +/*PAGE + * + * rtems_clock_tick + * + * This directive notifies the executve that a tick has occurred. + * When the tick occurs the time manager updates and maintains + * the calendar time, timeslicing, and any timeout delays. + * + * Input parameters: NONE + * + * Output parameters: + * RTEMS_SUCCESSFUL - always succeeds + * + * NOTE: This routine only works for leap-years through 2099. + */ + +rtems_status_code rtems_clock_tick( void ) +{ + _TOD_Tickle_ticks(); + + _Watchdog_Tickle_ticks(); + + _Thread_Tickle_timeslice(); + + if ( _Thread_Is_context_switch_necessary() && + _Thread_Is_dispatching_enabled() ) + _Thread_Dispatch(); + + return( RTEMS_SUCCESSFUL ); +} diff --git a/cpukit/rtems/src/rtemstimer.c b/cpukit/rtems/src/rtemstimer.c new file mode 100644 index 0000000000..076091bee4 --- /dev/null +++ b/cpukit/rtems/src/rtemstimer.c @@ -0,0 +1,343 @@ +/* + * Timer 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 + +/*PAGE + * + * _Timer_Manager_initialization + * + * This routine initializes all timer manager related data structures. + * + * Input parameters: + * maximum_timers - number of timers to initialize + * + * Output parameters: NONE + */ + +void _Timer_Manager_initialization( + unsigned32 maximum_timers +) +{ + _Objects_Initialize_information( + &_Timer_Information, + FALSE, + maximum_timers, + sizeof( Timer_Control ) + ); +} + +/*PAGE + * + * rtems_timer_create + * + * This directive creates a timer and performs some initialization. + * + * Input parameters: + * name - timer name + * id - pointer to timer id + * + * Output parameters: + * id - timer id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_create( + Objects_Name name, + Objects_Id *id +) +{ + Timer_Control *the_timer; + + if ( !_Objects_Is_name_valid( name ) ) + return ( RTEMS_INVALID_NAME ); + + _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; + + _Objects_Open( &_Timer_Information, &the_timer->Object, name ); + + *id = the_timer->Object.id; + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_timer_ident + * + * This directive returns the system ID associated with + * the timer name. + * + * Input parameters: + * name - user defined message queue name + * id - pointer to timer id + * + * Output parameters: + * *id - message queue id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_ident( + Objects_Name name, + Objects_Id *id +) +{ + return _Objects_Name_to_id( + &_Timer_Information, + name, + RTEMS_SEARCH_LOCAL_NODE, + id + ); +} + +/*PAGE + * + * rtems_timer_cancel + * + * This directive allows a thread to cancel a timer. + * + * Input parameters: + * id - timer id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_cancel( + Objects_Id id +) +{ + Timer_Control *the_timer; + Objects_Locations location; + + the_timer = _Timer_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + if ( !_Timer_Is_dormant_class( the_timer->the_class ) ) { + (void) _Watchdog_Remove( &the_timer->Ticker ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_INCORRECT_STATE ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_timer_delete + * + * This directive allows a thread to delete a timer. + * + * Input parameters: + * id - timer id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_delete( + Objects_Id id +) +{ + Timer_Control *the_timer; + Objects_Locations location; + + the_timer = _Timer_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + _Objects_Close( &_Timer_Information, &the_timer->Object ); + (void) _Watchdog_Remove( &the_timer->Ticker ); + _Timer_Free( the_timer ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_timer_fire_after + * + * This directive allows a thread to start a timer. + * + * Input parameters: + * id - timer id + * ticks - interval until routine is fired + * routine - routine to schedule + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_fire_after( + Objects_Id id, + rtems_interval ticks, + Timer_Service routine, + void *user_data +) +{ + Timer_Control *the_timer; + Objects_Locations location; + + if ( ticks == 0 ) + return( RTEMS_INVALID_NUMBER ); + + the_timer = _Timer_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + (void) _Watchdog_Remove( &the_timer->Ticker ); + the_timer->the_class = TIMER_INTERVAL; + _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); + _Watchdog_Insert_ticks( &the_timer->Ticker, + ticks, WATCHDOG_ACTIVATE_NOW ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_timer_fire_when + * + * This directive allows a thread to start a timer. + * + * Input parameters: + * id - timer id + * wall_time - time of day to fire timer + * routine - routine to schedule + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_fire_when( + Objects_Id id, + rtems_time_of_day *wall_time, + Timer_Service routine, + void *user_data +) +{ + Timer_Control *the_timer; + Objects_Locations location; + rtems_status_code validate_status; + rtems_interval seconds; + + if ( !_TOD_Is_set() ) + return( RTEMS_NOT_DEFINED ); + + validate_status = _TOD_Validate( wall_time ); + if ( !rtems_is_status_successful( validate_status ) ) + return( validate_status ); + + 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_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + (void) _Watchdog_Remove( &the_timer->Ticker ); + the_timer->the_class = TIMER_TIME_OF_DAY; + _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); + _Watchdog_Insert_seconds( &the_timer->Ticker, + seconds - _TOD_Seconds_since_epoch, WATCHDOG_ACTIVATE_NOW ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_timer_reset + * + * This directive allows a thread to reset a timer. + * + * Input parameters: + * id - timer id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_timer_reset( + Objects_Id id +) +{ + Timer_Control *the_timer; + Objects_Locations location; + + the_timer = _Timer_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: /* should never return this */ + return( RTEMS_INTERNAL_ERROR ); + case OBJECTS_LOCAL: + if ( _Timer_Is_interval_class( the_timer->the_class ) ) { + _Watchdog_Reset( &the_timer->Ticker ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_NOT_DEFINED ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} diff --git a/cpukit/rtems/src/sem.c b/cpukit/rtems/src/sem.c new file mode 100644 index 0000000000..19410c62f1 --- /dev/null +++ b/cpukit/rtems/src/sem.c @@ -0,0 +1,483 @@ +/* + * Semaphore Manager + * + * DESCRIPTION: + * + * This package is the implementation of the Semaphore Manager. + * This manager utilizes standard Dijkstra counting semaphores to provide + * synchronization and mutual exclusion capabilities. + * + * Directives provided are: + * + * + create a semaphore + * + get an ID of a semaphore + * + delete a semaphore + * + acquire a semaphore + * + release a semaphore + * + * 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 + * + * _Semaphore_Manager_initialization + * + * This routine initializes all semaphore manager related data structures. + * + * Input parameters: + * maximum_semaphores - maximum configured semaphores + * + * Output parameters: NONE + */ + +void _Semaphore_Manager_initialization( + unsigned32 maximum_semaphores +) +{ + _Objects_Initialize_information( + &_Semaphore_Information, + TRUE, + maximum_semaphores, + sizeof( Semaphore_Control ) + ); +} + +/*PAGE + * + * rtems_semaphore_create + * + * This directive creates a semaphore and sets the initial value based + * on the given count. A semaphore id is returned. + * + * Input parameters: + * name - user defined semaphore name + * count - initial count of semaphore + * attribute_set - semaphore attributes + * id - pointer to semaphore id + * + * Output parameters: + * id - semaphore id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_semaphore_create( + Objects_Name name, + unsigned32 count, + rtems_attribute attribute_set, + Objects_Id *id +) +{ + register Semaphore_Control *the_semaphore; + + if ( !_Objects_Is_name_valid( name ) ) + return ( RTEMS_INVALID_NAME ); + + if ( _Attributes_Is_global( attribute_set ) ) { + + if ( !_Configuration_Is_multiprocessing() ) + return( RTEMS_MP_NOT_CONFIGURED ); + + if ( _Attributes_Is_inherit_priority( attribute_set ) ) + return( RTEMS_NOT_DEFINED ); + + } else if ( _Attributes_Is_inherit_priority( attribute_set ) ) { + + if ( ! ( _Attributes_Is_binary_semaphore( attribute_set ) && + _Attributes_Is_priority( attribute_set ) ) ) + return( RTEMS_NOT_DEFINED ); + + } + + if ( _Attributes_Is_binary_semaphore( attribute_set ) && ( count > 1 ) ) + return( RTEMS_INVALID_NUMBER ); + + _Thread_Disable_dispatch(); /* prevents deletion */ + + the_semaphore = _Semaphore_Allocate(); + + if ( !the_semaphore ) { + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + if ( _Attributes_Is_global( attribute_set ) && + !( _Objects_MP_Open( &_Semaphore_Information, name, + the_semaphore->Object.id, FALSE ) ) ) { + _Semaphore_Free( the_semaphore ); + _Thread_Enable_dispatch(); + return( RTEMS_TOO_MANY ); + } + + the_semaphore->attribute_set = attribute_set; + the_semaphore->count = count; + + if ( _Attributes_Is_binary_semaphore( attribute_set ) && count == 0 ) { + the_semaphore->nest_count = 1; + the_semaphore->holder = _Thread_Executing; + the_semaphore->holder_id = _Thread_Executing->Object.id; + _Thread_Executing->resource_count++; + } else { + the_semaphore->nest_count = 0; + the_semaphore->holder = NULL; + the_semaphore->holder_id = 0; + } + + _Thread_queue_Initialize( &the_semaphore->Wait_queue, + attribute_set, STATES_WAITING_FOR_SEMAPHORE ); + + _Objects_Open( &_Semaphore_Information, &the_semaphore->Object, name ); + + *id = the_semaphore->Object.id; + + if ( _Attributes_Is_global( attribute_set ) ) + _Semaphore_MP_Send_process_packet( + SEMAPHORE_MP_ANNOUNCE_CREATE, + the_semaphore->Object.id, + name, + 0 /* Not used */ + ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_semaphore_ident + * + * This directive returns the system ID associated with + * the semaphore name. + * + * Input parameters: + * name - user defined semaphore name + * node - node(s) to be searched + * id - pointer to semaphore id + * + * Output parameters: + * *id - semaphore id + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_semaphore_ident( + Objects_Name name, + unsigned32 node, + Objects_Id *id +) +{ + return( _Objects_Name_to_id( &_Semaphore_Information, name, node, id ) ); +} + +/*PAGE + * + * rtems_semaphore_delete + * + * This directive allows a thread to delete a semaphore specified by + * the semaphore id. The semaphore is freed back to the inactive + * semaphore chain. + * + * Input parameters: + * id - semaphore id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_semaphore_delete( + Objects_Id id +) +{ + register Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _Semaphore_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 ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set) && + ( the_semaphore->count == 0 ) ) { + _Thread_Enable_dispatch(); + return( RTEMS_RESOURCE_IN_USE ); + } + + _Objects_Close( &_Semaphore_Information, &the_semaphore->Object ); + + _Thread_queue_Flush( + &the_semaphore->Wait_queue, + _Semaphore_MP_Send_object_was_deleted + ); + + _Semaphore_Free( the_semaphore ); + + if ( _Attributes_Is_global( the_semaphore->attribute_set ) ) { + + _Objects_MP_Close( &_Semaphore_Information, the_semaphore->Object.id ); + + _Semaphore_MP_Send_process_packet( + SEMAPHORE_MP_ANNOUNCE_DELETE, + the_semaphore->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_semaphore_obtain + * + * This directive allows a thread to acquire a semaphore. + * + * Input parameters: + * id - semaphore id + * option_set - wait option + * timeout - number of ticks to wait (0 means wait forever) + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_semaphore_obtain( + Objects_Id id, + unsigned32 option_set, + rtems_interval timeout +) +{ + register Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _Semaphore_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + return _Semaphore_MP_Send_request_packet( + SEMAPHORE_MP_OBTAIN_REQUEST, + id, + option_set, + timeout + ); + case OBJECTS_LOCAL: + if ( !_Semaphore_Seize( the_semaphore, option_set ) ) { + if ( _Attributes_Is_inherit_priority( the_semaphore->attribute_set ) && + the_semaphore->holder->current_priority > + _Thread_Executing->current_priority ) { + _Thread_Change_priority( + the_semaphore->holder, _Thread_Executing->current_priority ); + } + _Thread_queue_Enqueue( &the_semaphore->Wait_queue, timeout ); + } + _Thread_Enable_dispatch(); + return( _Thread_Executing->Wait.return_code ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * rtems_semaphore_release + * + * This directive allows a thread to release a semaphore. + * + * Input parameters: + * id - semaphore id + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_semaphore_release( + Objects_Id id +) +{ + register Semaphore_Control *the_semaphore; + Objects_Locations location; + Thread_Control *the_thread; + + the_semaphore = _Semaphore_Get( id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + return( RTEMS_INVALID_ID ); + case OBJECTS_REMOTE: + return( + _Semaphore_MP_Send_request_packet( + SEMAPHORE_MP_RELEASE_REQUEST, + id, + 0, /* Not used */ + MPCI_DEFAULT_TIMEOUT + ) + ); + case OBJECTS_LOCAL: + if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set)) { + + if ( !_Objects_Are_ids_equal( + _Thread_Executing->Object.id, the_semaphore->holder_id ) ) { + _Thread_Enable_dispatch(); + return( RTEMS_NOT_OWNER_OF_RESOURCE ); + } + + the_semaphore->nest_count--; + + if ( the_semaphore->nest_count != 0 ) { + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + _Thread_Executing->resource_count--; + the_semaphore->holder = NULL; + the_semaphore->holder_id = 0; + + /* + * Whether or not someone is waiting for the semaphore, an + * inherited priority must be lowered if this is the last + * semaphore (i.e. resource) this task has. + */ + + if ( _Attributes_Is_inherit_priority(the_semaphore->attribute_set) && + _Thread_Executing->resource_count == 0 && + _Thread_Executing->real_priority != + _Thread_Executing->current_priority ) { + _Thread_Change_priority( + _Thread_Executing, _Thread_Executing->real_priority ); + } + + } + + if ( (the_thread = _Thread_queue_Dequeue(&the_semaphore->Wait_queue)) ) { + + if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { + the_thread->receive_packet->return_code = RTEMS_SUCCESSFUL; + + if ( _Attributes_Is_binary_semaphore(the_semaphore->attribute_set) ) { + the_semaphore->holder = NULL; + the_semaphore->holder_id = the_thread->Object.id; + the_semaphore->nest_count = 1; + } + + _Semaphore_MP_Send_response_packet( + SEMAPHORE_MP_OBTAIN_RESPONSE, + id, + the_thread + ); + } else { + + if ( _Attributes_Is_binary_semaphore(the_semaphore->attribute_set) ) { + the_semaphore->holder = the_thread; + the_semaphore->holder_id = the_thread->Object.id; + the_thread->resource_count++; + the_semaphore->nest_count = 1; + } + + /* + * No special action for priority inheritance because the_thread + * is guaranteed to be the highest priority thread waiting for + * the semaphore. + */ + } + } else + the_semaphore->count += 1; + + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} + +/*PAGE + * + * _Semaphore_Seize + * + * This routine attempts to allocate a semaphore to the calling thread. + * + * Input parameters: + * the_semaphore - pointer to semaphore control block + * option_set - acquire semaphore options + * + * Output parameters: + * TRUE - if semaphore allocated + * FALSE - if semaphore NOT allocated + * + * INTERRUPT LATENCY: + * available + * wait + */ + +boolean _Semaphore_Seize( + Semaphore_Control *the_semaphore, + rtems_option option_set +) +{ + Thread_Control *executing; + ISR_Level level; + + executing = _Thread_Executing; + executing->Wait.return_code = RTEMS_SUCCESSFUL; + _ISR_Disable( level ); + if ( the_semaphore->count != 0 ) { + the_semaphore->count -= 1; + if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set ) ) { + the_semaphore->holder = executing; + the_semaphore->holder_id = executing->Object.id; + the_semaphore->nest_count = 1; + executing->resource_count++; + } + _ISR_Enable( level ); + return( TRUE ); + } + + if ( _Options_Is_no_wait( option_set ) ) { + _ISR_Enable( level ); + executing->Wait.return_code = RTEMS_UNSATISFIED; + return( TRUE ); + } + + if ( _Attributes_Is_binary_semaphore( the_semaphore->attribute_set ) ) { + if ( _Objects_Are_ids_equal( + _Thread_Executing->Object.id, the_semaphore->holder_id ) ) { + the_semaphore->nest_count++; + _ISR_Enable( level ); + return( TRUE ); + } + } + + the_semaphore->Wait_queue.sync = TRUE; + executing->Wait.queue = &the_semaphore->Wait_queue; + executing->Wait.id = the_semaphore->Object.id; + executing->Wait.option_set = option_set; + _ISR_Enable( level ); + return( FALSE ); +} diff --git a/cpukit/rtems/src/semmp.c b/cpukit/rtems/src/semmp.c new file mode 100644 index 0000000000..d131d48150 --- /dev/null +++ b/cpukit/rtems/src/semmp.c @@ -0,0 +1,306 @@ +/* + * Multiprocessing Support for the Semaphore 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 + +/*PAGE + * + * _Semaphore_MP_Send_process_packet + * + */ + +void _Semaphore_MP_Send_process_packet ( + Semaphore_MP_Remote_operations operation, + Objects_Id semaphore_id, + Objects_Name name, + Objects_Id proxy_id +) +{ + Semaphore_MP_Packet *the_packet; + unsigned32 node; + + switch ( operation ) { + + case SEMAPHORE_MP_ANNOUNCE_CREATE: + case SEMAPHORE_MP_ANNOUNCE_DELETE: + case SEMAPHORE_MP_EXTRACT_PROXY: + + the_packet = _Semaphore_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_SEMAPHORE; + the_packet->Prefix.length = sizeof ( Semaphore_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Semaphore_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = semaphore_id; + the_packet->name = name; + the_packet->proxy_id = proxy_id; + + if ( operation == SEMAPHORE_MP_EXTRACT_PROXY ) + node = rtems_get_node( semaphore_id ); + else + node = MPCI_ALL_NODES; + + _MPCI_Send_process_packet( node, &the_packet->Prefix ); + break; + + case SEMAPHORE_MP_OBTAIN_REQUEST: + case SEMAPHORE_MP_OBTAIN_RESPONSE: + case SEMAPHORE_MP_RELEASE_REQUEST: + case SEMAPHORE_MP_RELEASE_RESPONSE: + break; + } +} + +/*PAGE + * + * _Semaphore_MP_Send_request_packet + * + */ + +rtems_status_code _Semaphore_MP_Send_request_packet ( + Semaphore_MP_Remote_operations operation, + Objects_Id semaphore_id, + rtems_option option_set, + rtems_interval timeout +) +{ + Semaphore_MP_Packet *the_packet; + + switch ( operation ) { + + case SEMAPHORE_MP_OBTAIN_REQUEST: + case SEMAPHORE_MP_RELEASE_REQUEST: + + the_packet = _Semaphore_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_SEMAPHORE; + the_packet->Prefix.length = sizeof ( Semaphore_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Semaphore_MP_Packet ); + if ( ! _Options_Is_no_wait(option_set)) + the_packet->Prefix.timeout = timeout; + + the_packet->operation = operation; + the_packet->Prefix.id = semaphore_id; + the_packet->option_set = option_set; + + return _MPCI_Send_request_packet( + rtems_get_node( semaphore_id ), + &the_packet->Prefix, + STATES_WAITING_FOR_SEMAPHORE + ); + break; + + case SEMAPHORE_MP_ANNOUNCE_CREATE: + case SEMAPHORE_MP_ANNOUNCE_DELETE: + case SEMAPHORE_MP_EXTRACT_PROXY: + case SEMAPHORE_MP_OBTAIN_RESPONSE: + case SEMAPHORE_MP_RELEASE_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_SUCCESSFUL; +} + +/*PAGE + * + * _Semaphore_MP_Send_response_packet + * + */ + +void _Semaphore_MP_Send_response_packet ( + Semaphore_MP_Remote_operations operation, + Objects_Id semaphore_id, + Thread_Control *the_thread +) +{ + Semaphore_MP_Packet *the_packet; + + switch ( operation ) { + + case SEMAPHORE_MP_OBTAIN_RESPONSE: + case SEMAPHORE_MP_RELEASE_RESPONSE: + + the_packet = ( Semaphore_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case SEMAPHORE_MP_ANNOUNCE_CREATE: + case SEMAPHORE_MP_ANNOUNCE_DELETE: + case SEMAPHORE_MP_EXTRACT_PROXY: + case SEMAPHORE_MP_OBTAIN_REQUEST: + case SEMAPHORE_MP_RELEASE_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _Semaphore_MP_Process_packet + * + */ + +void _Semaphore_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + Semaphore_MP_Packet *the_packet; + Thread_Control *the_thread; + boolean ignored; + + the_packet = (Semaphore_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case SEMAPHORE_MP_ANNOUNCE_CREATE: + + ignored = _Objects_MP_Open( + &_Semaphore_Information, + the_packet->name, + the_packet->Prefix.id, + TRUE + ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case SEMAPHORE_MP_ANNOUNCE_DELETE: + + _Objects_MP_Close( &_Semaphore_Information, the_packet->Prefix.id ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case SEMAPHORE_MP_EXTRACT_PROXY: + + the_thread = _Thread_MP_Find_proxy( the_packet->proxy_id ); + + if ( ! _Thread_Is_null( the_thread ) ) + _Thread_queue_Extract( the_thread->Wait.queue, the_thread ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case SEMAPHORE_MP_OBTAIN_REQUEST: + + the_packet->Prefix.return_code = rtems_semaphore_obtain( + the_packet->Prefix.id, + the_packet->option_set, + the_packet->Prefix.timeout + ); + + if ( ! _Status_Is_proxy_blocking( the_packet->Prefix.return_code ) ) + _Semaphore_MP_Send_response_packet( + SEMAPHORE_MP_OBTAIN_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + + case SEMAPHORE_MP_OBTAIN_RESPONSE: + case SEMAPHORE_MP_RELEASE_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case SEMAPHORE_MP_RELEASE_REQUEST: + + the_packet->Prefix.return_code = rtems_semaphore_release( + the_packet->Prefix.id + ); + + _Semaphore_MP_Send_response_packet( + SEMAPHORE_MP_RELEASE_RESPONSE, + the_packet->Prefix.id, + _Thread_Executing + ); + break; + } +} + +/*PAGE + * + * _Semaphore_MP_Send_object_was_deleted + * + */ + +void _Semaphore_MP_Send_object_was_deleted ( + Thread_Control *the_proxy +) +{ + the_proxy->receive_packet->return_code = RTEMS_OBJECT_WAS_DELETED; + + _Semaphore_MP_Send_response_packet( + SEMAPHORE_MP_OBTAIN_RESPONSE, + the_proxy->Wait.id, + the_proxy + ); + +} + +/*PAGE + * + * _Semaphore_MP_Send_extract_proxy + * + */ + +void _Semaphore_MP_Send_extract_proxy ( + Thread_Control *the_thread +) +{ + _Semaphore_MP_Send_process_packet( + SEMAPHORE_MP_EXTRACT_PROXY, + the_thread->Wait.id, + (Objects_Name) 0, + the_thread->Object.id + ); + +} + +/*PAGE + * + * _Semaphore_MP_Get_packet + * + */ + +Semaphore_MP_Packet *_Semaphore_MP_Get_packet ( void ) +{ + return ( (Semaphore_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/signal.c b/cpukit/rtems/src/signal.c new file mode 100644 index 0000000000..411df5d86c --- /dev/null +++ b/cpukit/rtems/src/signal.c @@ -0,0 +1,110 @@ +/* + * Signal 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 + +/*PAGE + * + * rtems_signal_catch + * + * This directive allows a thread to specify what action to take when + * catching signals. + * + * Input parameters: + * handler - address of asynchronous signal routine (asr) + * ( NULL indicates asr is invalid ) + * mode_set - mode value for asr + * + * Output parameters: + * RTEMS_SUCCESSFUL - always succeeds + */ + +rtems_status_code rtems_signal_catch( + rtems_asr_entry handler, + rtems_mode mode_set +) +{ + Thread_Control *executing; + + executing = _Thread_Executing; + _Thread_Disable_dispatch(); /* cannot reschedule while */ + /* the thread is inconsistent */ + + if ( ! _ASR_Is_null_handler( handler ) ) { + executing->Signal.mode_set = mode_set; + executing->Signal.handler = handler; + } + else + _ASR_Initialize( &executing->Signal ); + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); +} + +/*PAGE + * + * rtems_signal_send + * + * This directive allows a thread to send signals to a thread. + * + * Input parameters: + * id - thread id + * signal_set - signal set + * + * Output parameters: + * RTEMS_SUCCESSFUL - if successful + * error code - if unsuccessful + */ + +rtems_status_code rtems_signal_send( + Objects_Id id, + rtems_signal_set signal_set +) +{ + 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 _Signal_MP_Send_request_packet( + SIGNAL_MP_SEND_REQUEST, + id, + signal_set + ); + case OBJECTS_LOCAL: + if ( ! _ASR_Is_null_handler( the_thread->Signal.handler ) ) { + if ( _Modes_Is_asr_disabled( the_thread->current_modes ) ) + _ASR_Post_signals( signal_set, &the_thread->Signal.signals_pending ); + else { + _ASR_Post_signals( signal_set, &the_thread->Signal.signals_posted ); + if ( _ISR_Is_in_progress() && _Thread_Is_executing( the_thread ) ) + _ISR_Signals_to_thread_executing = TRUE; + } + _Thread_Enable_dispatch(); + return( RTEMS_SUCCESSFUL ); + } + _Thread_Enable_dispatch(); + return( RTEMS_NOT_DEFINED ); + } + + return( RTEMS_INTERNAL_ERROR ); /* unreached - only to remove warnings */ +} diff --git a/cpukit/rtems/src/signalmp.c b/cpukit/rtems/src/signalmp.c new file mode 100644 index 0000000000..4ac8123766 --- /dev/null +++ b/cpukit/rtems/src/signalmp.c @@ -0,0 +1,187 @@ +/* + * Multiprocessing Support for the Signal 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 + +/*PAGE + * + * _Signal_MP_Send_process_packet + * + * This subprogram is not needed since there are no process + * packets to be sent by this manager. + * + */ + +/*PAGE + * + * _Signal_MP_Send_request_packet + * + */ + +rtems_status_code _Signal_MP_Send_request_packet ( + Signal_MP_Remote_operations operation, + Objects_Id task_id, + rtems_signal_set signal_in +) +{ + Signal_MP_Packet *the_packet; + + switch ( operation ) { + + case SIGNAL_MP_SEND_REQUEST: + + the_packet = _Signal_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_SIGNAL; + the_packet->Prefix.length = sizeof ( Signal_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( Signal_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = task_id; + the_packet->signal_in = signal_in; + + return _MPCI_Send_request_packet( + rtems_get_node( task_id ), + &the_packet->Prefix, + STATES_READY /* Not used */ + ); + break; + + case SIGNAL_MP_SEND_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_INTERNAL_ERROR; +} + +/*PAGE + * + * _Signal_MP_Send_response_packet + * + */ + +void _Signal_MP_Send_response_packet ( + Signal_MP_Remote_operations operation, + Thread_Control *the_thread +) +{ + Signal_MP_Packet *the_packet; + + switch ( operation ) { + + case SIGNAL_MP_SEND_RESPONSE: + + the_packet = ( Signal_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case SIGNAL_MP_SEND_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _Signal_MP_Process_packet + * + */ + +void _Signal_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + Signal_MP_Packet *the_packet; + Thread_Control *the_thread; + + the_packet = (Signal_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case SIGNAL_MP_SEND_REQUEST: + + the_packet->Prefix.return_code = rtems_signal_send( + the_packet->Prefix.id, + the_packet->signal_in + ); + + _Signal_MP_Send_response_packet( + SIGNAL_MP_SEND_RESPONSE, + _Thread_Executing + ); + break; + + case SIGNAL_MP_SEND_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + } +} + +/*PAGE + * + * _Signal_MP_Send_object_was_deleted + * + * This subprogram is not needed since there are no objects + * deleted by this manager. + * + */ + +/*PAGE + * + * _Signal_MP_Send_extract_proxy + * + * This subprogram is not needed since there are no objects + * deleted by this manager. + * + */ + +/*PAGE + * + * _Signal_MP_Get_packet + * + */ + +Signal_MP_Packet *_Signal_MP_Get_packet ( void ) +{ + return ( (Signal_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/taskmp.c b/cpukit/rtems/src/taskmp.c new file mode 100644 index 0000000000..b938c60c53 --- /dev/null +++ b/cpukit/rtems/src/taskmp.c @@ -0,0 +1,338 @@ +/* + * Multiprocessing Support for the 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 + +/*PAGE + * + * _RTEMS_tasks_MP_Send_process_packet + * + */ + +void _RTEMS_tasks_MP_Send_process_packet ( + RTEMS_tasks_MP_Remote_operations operation, + Objects_Id task_id, + Objects_Name name +) +{ + RTEMS_tasks_MP_Packet *the_packet; + + switch ( operation ) { + + case RTEMS_TASKS_MP_ANNOUNCE_CREATE: + case RTEMS_TASKS_MP_ANNOUNCE_DELETE: + + the_packet = _RTEMS_tasks_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_TASKS; + the_packet->Prefix.length = sizeof ( RTEMS_tasks_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( RTEMS_tasks_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = task_id; + the_packet->name = name; + + _MPCI_Send_process_packet( MPCI_ALL_NODES, &the_packet->Prefix ); + break; + + case RTEMS_TASKS_MP_SUSPEND_REQUEST: + case RTEMS_TASKS_MP_SUSPEND_RESPONSE: + case RTEMS_TASKS_MP_RESUME_REQUEST: + case RTEMS_TASKS_MP_RESUME_RESPONSE: + case RTEMS_TASKS_MP_SET_PRIORITY_REQUEST: + case RTEMS_TASKS_MP_SET_PRIORITY_RESPONSE: + case RTEMS_TASKS_MP_GET_NOTE_REQUEST: + case RTEMS_TASKS_MP_GET_NOTE_RESPONSE: + case RTEMS_TASKS_MP_SET_NOTE_REQUEST: + case RTEMS_TASKS_MP_SET_NOTE_RESPONSE: + break; + } +} + +/*PAGE + * + * _RTEMS_tasks_MP_Send_request_packet + * + */ + +rtems_status_code _RTEMS_tasks_MP_Send_request_packet ( + RTEMS_tasks_MP_Remote_operations operation, + Objects_Id task_id, + rtems_task_priority new_priority, + unsigned32 notepad, + unsigned32 note +) +{ + RTEMS_tasks_MP_Packet *the_packet; + + switch ( operation ) { + + case RTEMS_TASKS_MP_SUSPEND_REQUEST: + case RTEMS_TASKS_MP_RESUME_REQUEST: + case RTEMS_TASKS_MP_SET_PRIORITY_REQUEST: + case RTEMS_TASKS_MP_GET_NOTE_REQUEST: + case RTEMS_TASKS_MP_SET_NOTE_REQUEST: + + the_packet = _RTEMS_tasks_MP_Get_packet(); + the_packet->Prefix.the_class = RTEMS_MP_PACKET_TASKS; + the_packet->Prefix.length = sizeof ( RTEMS_tasks_MP_Packet ); + the_packet->Prefix.to_convert = sizeof ( RTEMS_tasks_MP_Packet ); + the_packet->operation = operation; + the_packet->Prefix.id = task_id; + the_packet->the_priority = new_priority; + the_packet->notepad = notepad; + the_packet->note = note; + + return _MPCI_Send_request_packet( + rtems_get_node( task_id ), + &the_packet->Prefix, + STATES_READY /* Not used */ + ); + break; + + case RTEMS_TASKS_MP_ANNOUNCE_CREATE: + case RTEMS_TASKS_MP_ANNOUNCE_DELETE: + case RTEMS_TASKS_MP_SUSPEND_RESPONSE: + case RTEMS_TASKS_MP_RESUME_RESPONSE: + case RTEMS_TASKS_MP_SET_PRIORITY_RESPONSE: + case RTEMS_TASKS_MP_GET_NOTE_RESPONSE: + case RTEMS_TASKS_MP_SET_NOTE_RESPONSE: + break; + + } + /* + * The following line is included to satisfy compilers which + * produce warnings when a function does not end with a return. + */ + return RTEMS_SUCCESSFUL; +} + +/*PAGE + * + * _RTEMS_tasks_MP_Send_response_packet + * + */ + +void _RTEMS_tasks_MP_Send_response_packet ( + RTEMS_tasks_MP_Remote_operations operation, + Thread_Control *the_thread +) +{ + RTEMS_tasks_MP_Packet *the_packet; + + switch ( operation ) { + + case RTEMS_TASKS_MP_SUSPEND_RESPONSE: + case RTEMS_TASKS_MP_RESUME_RESPONSE: + case RTEMS_TASKS_MP_SET_PRIORITY_RESPONSE: + case RTEMS_TASKS_MP_GET_NOTE_RESPONSE: + case RTEMS_TASKS_MP_SET_NOTE_RESPONSE: + + the_packet = (RTEMS_tasks_MP_Packet *) the_thread->receive_packet; + +/* + * The packet being returned already contains the class, length, and + * to_convert fields, therefore they are not set in this routine. + */ + the_packet->operation = operation; + the_packet->Prefix.id = the_packet->Prefix.source_tid; + + _MPCI_Send_response_packet( + rtems_get_node( the_packet->Prefix.source_tid ), + &the_packet->Prefix + ); + break; + + case RTEMS_TASKS_MP_ANNOUNCE_CREATE: + case RTEMS_TASKS_MP_ANNOUNCE_DELETE: + case RTEMS_TASKS_MP_SUSPEND_REQUEST: + case RTEMS_TASKS_MP_RESUME_REQUEST: + case RTEMS_TASKS_MP_SET_PRIORITY_REQUEST: + case RTEMS_TASKS_MP_GET_NOTE_REQUEST: + case RTEMS_TASKS_MP_SET_NOTE_REQUEST: + break; + + } +} + +/*PAGE + * + * + * _RTEMS_tasks_MP_Process_packet + * + */ + +void _RTEMS_tasks_MP_Process_packet ( + rtems_packet_prefix *the_packet_prefix +) +{ + RTEMS_tasks_MP_Packet *the_packet; + Thread_Control *the_thread; + boolean ignored; + + the_packet = (RTEMS_tasks_MP_Packet *) the_packet_prefix; + + switch ( the_packet->operation ) { + + case RTEMS_TASKS_MP_ANNOUNCE_CREATE: + + ignored = _Objects_MP_Open( + &_Thread_Information, + the_packet->name, + the_packet->Prefix.id, + TRUE + ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case RTEMS_TASKS_MP_ANNOUNCE_DELETE: + + _Objects_MP_Close( &_Thread_Information, the_packet->Prefix.id ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case RTEMS_TASKS_MP_SUSPEND_REQUEST: + + the_packet->Prefix.return_code = rtems_task_suspend( + the_packet->Prefix.id + ); + + _RTEMS_tasks_MP_Send_response_packet( + RTEMS_TASKS_MP_SUSPEND_RESPONSE, + _Thread_Executing + ); + break; + + case RTEMS_TASKS_MP_SUSPEND_RESPONSE: + case RTEMS_TASKS_MP_RESUME_RESPONSE: + case RTEMS_TASKS_MP_SET_NOTE_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case RTEMS_TASKS_MP_RESUME_REQUEST: + + the_packet->Prefix.return_code = rtems_task_resume( + the_packet->Prefix.id + ); + + _RTEMS_tasks_MP_Send_response_packet( + RTEMS_TASKS_MP_RESUME_RESPONSE, + _Thread_Executing + ); + break; + + case RTEMS_TASKS_MP_SET_PRIORITY_REQUEST: + + the_packet->Prefix.return_code = rtems_task_set_priority( + the_packet->Prefix.id, + the_packet->the_priority, + &the_packet->the_priority + ); + + _RTEMS_tasks_MP_Send_response_packet( + RTEMS_TASKS_MP_SET_PRIORITY_RESPONSE, + _Thread_Executing + ); + break; + + case RTEMS_TASKS_MP_SET_PRIORITY_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + *(rtems_task_priority *)the_thread->Wait.return_argument = + the_packet->the_priority; + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case RTEMS_TASKS_MP_GET_NOTE_REQUEST: + + the_packet->Prefix.return_code = rtems_task_get_note( + the_packet->Prefix.id, + the_packet->notepad, + &the_packet->note + ); + + _RTEMS_tasks_MP_Send_response_packet( + RTEMS_TASKS_MP_GET_NOTE_RESPONSE, + _Thread_Executing + ); + break; + + case RTEMS_TASKS_MP_GET_NOTE_RESPONSE: + + the_thread = _MPCI_Process_response( the_packet_prefix ); + + *(unsigned32 *)the_thread->Wait.return_argument = the_packet->note; + + _MPCI_Return_packet( the_packet_prefix ); + break; + + case RTEMS_TASKS_MP_SET_NOTE_REQUEST: + + the_packet->Prefix.return_code = rtems_task_set_note( + the_packet->Prefix.id, + the_packet->notepad, + the_packet->note + ); + + _RTEMS_tasks_MP_Send_response_packet( + RTEMS_TASKS_MP_SET_NOTE_RESPONSE, + _Thread_Executing + ); + break; + } +} + +/*PAGE + * + * _RTEMS_tasks_MP_Send_object_was_deleted + * + * This routine is not neededby the Tasks since a task + * cannot be globally deleted. + * + */ + +/*PAGE + * + * _RTEMS_tasks_MP_Send_extract_proxy + * + * This routine is not neededby the Tasks since a task + * cannot be globally deleted. + * + */ + +/*PAGE + * + * _RTEMS_tasks_MP_Get_packet + * + */ + +RTEMS_tasks_MP_Packet *_RTEMS_tasks_MP_Get_packet ( void ) +{ + return ( (RTEMS_tasks_MP_Packet *) _MPCI_Get_packet() ); +} + +/* end of file */ diff --git a/cpukit/rtems/src/tasks.c b/cpukit/rtems/src/tasks.c new file mode 100644 index 0000000000..edba524d94 --- /dev/null +++ b/cpukit/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