/* * 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 #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, OBJECTS_RTEMS_SEMAPHORES, TRUE, maximum_semaphores, sizeof( Semaphore_Control ), FALSE, RTEMS_MAXIMUM_NAME_LENGTH, FALSE ); } /*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( rtems_name name, unsigned32 count, rtems_attribute attribute_set, Objects_Id *id ) { register Semaphore_Control *the_semaphore; if ( !rtems_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( rtems_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 ); }