diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/posix/src/semaphore.c | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/cpukit/posix/src/semaphore.c b/cpukit/posix/src/semaphore.c new file mode 100644 index 0000000000..16d44d1894 --- /dev/null +++ b/cpukit/posix/src/semaphore.c @@ -0,0 +1,575 @@ +/* semaphore.c + * + */ + +#include <stdarg.h> + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <limits.h> + +#include <rtems/system.h> +#include <rtems/score/object.h> +#include <rtems/posix/semaphore.h> +#include <rtems/posix/time.h> + +/*PAGE + * + * _POSIX_Semaphore_Manager_initialization + * + * This routine initializes all semaphore manager related data structures. + * + * Input parameters: + * maximum_semaphores - maximum configured semaphores + * + * Output parameters: NONE + */ + +void _POSIX_Semaphore_Manager_initialization( + unsigned32 maximum_semaphores +) +{ + _Objects_Initialize_information( + &_POSIX_Semaphore_Information, + OBJECTS_POSIX_SEMAPHORES, + TRUE, + maximum_semaphores, + sizeof( POSIX_Semaphore_Control ), + TRUE, + _POSIX_PATH_MAX, + FALSE + ); +} + +/*PAGE + * + * _POSIX_Semaphore_Create_support + */ + +int _POSIX_Semaphore_Create_support( + const char *name, + int pshared, + unsigned int value, + POSIX_Semaphore_Control **the_sem +) +{ + POSIX_Semaphore_Control *the_semaphore; + CORE_semaphore_Attributes *the_sem_attr; + + _Thread_Disable_dispatch(); + + the_semaphore = _POSIX_Semaphore_Allocate(); + + if ( !the_semaphore ) { + _Thread_Enable_dispatch(); + seterrno( ENOMEM ); + return -1; + } + + if ( pshared == PTHREAD_PROCESS_SHARED && + !( _Objects_MP_Allocate_and_open( &_POSIX_Semaphore_Information, 0, + the_semaphore->Object.id, FALSE ) ) ) { + _POSIX_Semaphore_Free( the_semaphore ); + _Thread_Enable_dispatch(); + seterrno( EAGAIN ); + return -1; + } + + the_semaphore->process_shared = pshared; + + if ( name ) { + the_semaphore->named = TRUE; + the_semaphore->open_count = 1; + the_semaphore->linked = TRUE; + } + else + the_semaphore->named = FALSE; + + the_sem_attr = &the_semaphore->Semaphore.Attributes; + + /* XXX + * + * Note should this be based on the current scheduling policy? + */ + + the_sem_attr->discipline = CORE_SEMAPHORE_DISCIPLINES_FIFO; + + _CORE_semaphore_Initialize( + &the_semaphore->Semaphore, + OBJECTS_POSIX_SEMAPHORES, + the_sem_attr, + value, + 0 /* XXX - proxy_extract_callout is unused */ + ); + + /* XXX - need Names to be a string!!! */ + _Objects_Open( + &_POSIX_Semaphore_Information, + &the_semaphore->Object, + (char *) name + ); + + *the_sem = the_semaphore; + + if ( pshared == PTHREAD_PROCESS_SHARED ) + _POSIX_Semaphore_MP_Send_process_packet( + POSIX_SEMAPHORE_MP_ANNOUNCE_CREATE, + the_semaphore->Object.id, + (char *) name, + 0 /* proxy id - Not used */ + ); + + _Thread_Enable_dispatch(); + return 0; +} + + +/*PAGE + * + * 11.2.1 Initialize an Unnamed Semaphore, P1003.1b-1993, p.219 + */ + +int sem_init( + sem_t *sem, + int pshared, + unsigned int value +) +{ + int status; + POSIX_Semaphore_Control *the_semaphore; + + status = _POSIX_Semaphore_Create_support( + NULL, + pshared, + value, + &the_semaphore + ); + + if ( status != -1 ) + *sem = the_semaphore->Object.id; + + return status; +} + +/*PAGE + * + * 11.2.2 Destroy an Unnamed Semaphore, P1003.1b-1993, p.220 + */ + +int sem_destroy( + sem_t *sem +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_LOCAL: + /* + * Undefined operation on a named semaphore. + */ + + if ( the_semaphore->named == TRUE ) { + seterrno( EINVAL ); + return( -1 ); + } + + _Objects_Close( &_POSIX_Semaphore_Information, &the_semaphore->Object ); + + _CORE_semaphore_Flush( + &the_semaphore->Semaphore, + _POSIX_Semaphore_MP_Send_object_was_deleted, + -1 /* XXX should also seterrno -> EINVAL */ + ); + + _POSIX_Semaphore_Free( the_semaphore ); + + if ( the_semaphore->process_shared == PTHREAD_PROCESS_SHARED ) { + + _Objects_MP_Close( + &_POSIX_Semaphore_Information, + the_semaphore->Object.id + ); + + _POSIX_Semaphore_MP_Send_process_packet( + POSIX_SEMAPHORE_MP_ANNOUNCE_DELETE, + the_semaphore->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} + +/*PAGE + * + * 11.2.3 Initialize/Open a Named Semaphore, P1003.1b-1993, p.221 + * + * NOTE: When oflag is O_CREAT, then optional third and fourth + * parameters must be present. + */ + +sem_t *sem_open( + const char *name, + int oflag, + ... + /* mode_t mode, */ + /* unsigned int value */ +) +{ + va_list arg; + mode_t mode; + unsigned int value; + int status; + Objects_Id the_semaphore_id; + POSIX_Semaphore_Control *the_semaphore; + + + if ( oflag & O_CREAT ) { + va_start(arg, oflag); + mode = (mode_t) va_arg( arg, mode_t * ); + value = (unsigned int) va_arg( arg, unsigned int * ); + va_end(arg); + } + + status = _POSIX_Semaphore_Name_to_id( name, &the_semaphore_id ); + + /* + * If the name to id translation worked, then the semaphore exists + * and we can just return a pointer to the id. Otherwise we may + * need to check to see if this is a "semaphore does not exist" + * or some other miscellaneous error on the name. + */ + + if ( status ) { + + if ( status == EINVAL ) { /* name -> ID translation failed */ + if ( !(oflag & O_CREAT) ) { /* willing to create it? */ + seterrno( ENOENT ); + return (sem_t *) -1; + } + /* we are willing to create it */ + } + seterrno( status ); /* some type of error */ + return (sem_t *) -1; + + } else { /* name -> ID translation succeeded */ + + if ( (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL) ) { + seterrno( EEXIST ); + return (sem_t *) -1; + } + + /* + * XXX In this case we need to do an ID->pointer conversion to + * check the mode. This is probably a good place for a subroutine. + */ + + the_semaphore->open_count += 1; + + return (sem_t *)&the_semaphore->Object.id; + + } + + /* XXX verify this comment... + * + * At this point, the semaphore does not exist and everything has been + * checked. We should go ahead and create a semaphore. + */ + + status = _POSIX_Semaphore_Create_support( + name, + TRUE, /* shared across processes */ + value, + &the_semaphore + ); + + if ( status == -1 ) + return (sem_t *) -1; + + return (sem_t *) &the_semaphore->Object.id; + +} + +/*PAGE + * + * _POSIX_Semaphore_Delete + */ + +void _POSIX_Semaphore_Delete( + POSIX_Semaphore_Control *the_semaphore +) +{ + if ( !the_semaphore->linked && !the_semaphore->open_count ) { + _POSIX_Semaphore_Free( the_semaphore ); + + if ( the_semaphore->process_shared == PTHREAD_PROCESS_SHARED ) { + + _Objects_MP_Close( + &_POSIX_Semaphore_Information, + the_semaphore->Object.id + ); + + _POSIX_Semaphore_MP_Send_process_packet( + POSIX_SEMAPHORE_MP_ANNOUNCE_DELETE, + the_semaphore->Object.id, + 0, /* Not used */ + 0 /* Not used */ + ); + } + + } +} + +/*PAGE + * + * 11.2.4 Close a Named Semaphore, P1003.1b-1993, p.224 + */ + +int sem_close( + sem_t *sem +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_LOCAL: + the_semaphore->open_count -= 1; + _POSIX_Semaphore_Delete( the_semaphore ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} + +/*PAGE + * + * 11.2.5 Remove a Named Semaphore, P1003.1b-1993, p.225 + */ + +int sem_unlink( + const char *name +) +{ + int status; + register POSIX_Semaphore_Control *the_semaphore; + Objects_Id the_semaphore_id; + Objects_Locations location; + + status = _POSIX_Semaphore_Name_to_id( name, &the_semaphore_id ); + + if ( !status ) { + seterrno( status ); + return -1; + } + + the_semaphore = _POSIX_Semaphore_Get( &the_semaphore_id, &location ); + switch ( location ) { + case OBJECTS_ERROR: + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_LOCAL: + + if ( the_semaphore->process_shared == PTHREAD_PROCESS_SHARED ) { + _Objects_MP_Close( + &_POSIX_Semaphore_Information, + the_semaphore->Object.id + ); + } + + the_semaphore->linked = FALSE; + + _POSIX_Semaphore_Delete( the_semaphore ); + + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} + +/*PAGE + * + * _POSIX_Semaphore_Wait_support + */ + +int _POSIX_Semaphore_Wait_support( + sem_t *sem, + boolean blocking, + Watchdog_Interval timeout +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_LOCAL: + _CORE_semaphore_Seize( + &the_semaphore->Semaphore, + the_semaphore->Object.id, + blocking, + timeout + ); + _Thread_Enable_dispatch(); + return _Thread_Executing->Wait.return_code; + } + return POSIX_BOTTOM_REACHED(); +} + +/*PAGE + * + * 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226 + * + * NOTE: P1003.4b/D8 adds sem_timedwait(), p. 27 + */ + +int sem_wait( + sem_t *sem +) +{ + return _POSIX_Semaphore_Wait_support( sem, TRUE, THREAD_QUEUE_WAIT_FOREVER ); +} + +/*PAGE + * + * 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226 + * + * NOTE: P1003.4b/D8 adds sem_timedwait(), p. 27 + */ + +int sem_trywait( + sem_t *sem +) +{ + return _POSIX_Semaphore_Wait_support( sem, FALSE, THREAD_QUEUE_WAIT_FOREVER ); +} + +/*PAGE + * + * 11.2.6 Lock a Semaphore, P1003.1b-1993, p.226 + * + * NOTE: P1003.4b/D8 adds sem_timedwait(), p. 27 + */ + +int sem_timedwait( + sem_t *sem, + const struct timespec *timeout +) +{ + return _POSIX_Semaphore_Wait_support( + sem, + TRUE, + _POSIX_Time_Spec_to_interval( timeout ) + ); +} + +/*PAGE + * + * 11.2.7 Unlock a Semaphore, P1003.1b-1993, p.227 + */ + +void POSIX_Semaphore_MP_support( + Thread_Control *the_thread, + Objects_Id id +) +{ + (void) POSIX_MP_NOT_IMPLEMENTED(); +} + + +int sem_post( + sem_t *sem +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_LOCAL: + _CORE_semaphore_Surrender( + &the_semaphore->Semaphore, + the_semaphore->Object.id, + POSIX_Semaphore_MP_support + ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} + +/*PAGE + * + * 11.2.8 Get the Value of a Semaphore, P1003.1b-1993, p.229 + */ + +int sem_getvalue( + sem_t *sem, + int *sval +) +{ + register POSIX_Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _POSIX_Semaphore_Get( sem, &location ); + switch ( location ) { + case OBJECTS_ERROR: + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return POSIX_MP_NOT_IMPLEMENTED(); + seterrno( EINVAL ); + return( -1 ); + case OBJECTS_LOCAL: + *sval = _CORE_semaphore_Get_count( &the_semaphore->Semaphore ); + _Thread_Enable_dispatch(); + return 0; + } + return POSIX_BOTTOM_REACHED(); +} |