summaryrefslogtreecommitdiffstats
path: root/c/src/exec/rtems/src/sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/exec/rtems/src/sem.c')
-rw-r--r--c/src/exec/rtems/src/sem.c483
1 files changed, 483 insertions, 0 deletions
diff --git a/c/src/exec/rtems/src/sem.c b/c/src/exec/rtems/src/sem.c
new file mode 100644
index 0000000000..19410c62f1
--- /dev/null
+++ b/c/src/exec/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 <rtems/system.h>
+#include <rtems/attr.h>
+#include <rtems/config.h>
+#include <rtems/isr.h>
+#include <rtems/object.h>
+#include <rtems/options.h>
+#include <rtems/sem.h>
+#include <rtems/states.h>
+#include <rtems/thread.h>
+#include <rtems/threadq.h>
+#include <rtems/mpci.h>
+
+/*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 );
+}