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/sem.c | 483 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 cpukit/rtems/src/sem.c (limited to 'cpukit/rtems/src/sem.c') 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 ); +} -- cgit v1.2.3