/* * $Id$ */ #include #include #include #include #include #include #include #include #include /* * TEMPORARY */ void _POSIX_Mutex_MP_Send_process_packet ( POSIX_Mutex_MP_Remote_operations operation, Objects_Id mutex_id, Objects_Name name, Objects_Id proxy_id ) { (void) POSIX_MP_NOT_IMPLEMENTED(); } void _POSIX_Mutex_MP_Send_object_was_deleted ( Thread_Control *the_proxy ) { (void) POSIX_MP_NOT_IMPLEMENTED(); } int _POSIX_Mutex_MP_Send_request_packet ( POSIX_Mutex_MP_Remote_operations operation, Objects_Id mutex_id, boolean wait, /* XXX options */ Watchdog_Interval timeout ) { return POSIX_MP_NOT_IMPLEMENTED(); } /* * END OF TEMPORARY */ /*PAGE * * The default mutex attributes structure. */ const pthread_mutexattr_t _POSIX_Mutex_Default_attributes = { TRUE, /* is_initialized */ PTHREAD_PROCESS_PRIVATE, /* process_shared */ POSIX_SCHEDULER_MINIMUM_PRIORITY, /* prio_ceiling */ PTHREAD_PRIO_NONE, /* protocol */ FALSE /* recursive */ }; /*PAGE * * _POSIX_Mutex_Manager_initialization * * This routine initializes all mutex manager related data structures. * * Input parameters: * maximum_mutexes - maximum configured mutexes * * Output parameters: NONE */ void _POSIX_Mutex_Manager_initialization( unsigned32 maximum_mutexes ) { _Objects_Initialize_information( &_POSIX_Mutex_Information, OBJECTS_POSIX_MUTEXES, TRUE, maximum_mutexes, sizeof( POSIX_Mutex_Control ), FALSE, 0, FALSE ); } /*PAGE * * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 */ int pthread_mutexattr_init( pthread_mutexattr_t *attr ) { if ( !attr ) return EINVAL; *attr = _POSIX_Mutex_Default_attributes; return 0; } /*PAGE * * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 */ int pthread_mutexattr_destroy( pthread_mutexattr_t *attr ) { if ( !attr || attr->is_initialized == FALSE ) return EINVAL; attr->is_initialized = FALSE; return 0; } /*PAGE * * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 */ int pthread_mutexattr_getpshared( const pthread_mutexattr_t *attr, int *pshared ) { if ( !attr ) return EINVAL; *pshared = attr->process_shared; return 0; } /*PAGE * * 11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81 */ int pthread_mutexattr_setpshared( pthread_mutexattr_t *attr, int pshared ) { if ( !attr ) return EINVAL; switch ( pshared ) { case PTHREAD_PROCESS_SHARED: case PTHREAD_PROCESS_PRIVATE: attr->process_shared = pshared; return 0; default: return EINVAL; } } /*PAGE * * 11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87 * * NOTE: XXX Could be optimized so all the attribute error checking * is not performed when attr is NULL. */ int pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr ) { POSIX_Mutex_Control *the_mutex; CORE_mutex_Attributes *the_mutex_attr; const pthread_mutexattr_t *the_attr; CORE_mutex_Disciplines the_discipline; if ( attr ) the_attr = attr; else the_attr = &_POSIX_Mutex_Default_attributes; /* * XXX: Be careful about attributes when global!!! */ if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) return POSIX_MP_NOT_IMPLEMENTED(); if ( !the_attr->is_initialized ) return EINVAL; /* * Determine the discipline of the mutex */ switch ( the_attr->protocol ) { case PTHREAD_PRIO_NONE: the_discipline = CORE_MUTEX_DISCIPLINES_FIFO; break; case PTHREAD_PRIO_INHERIT: the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; break; case PTHREAD_PRIO_PROTECT: the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; break; default: return EINVAL; } if ( !_POSIX_Priority_Is_valid( the_attr->prio_ceiling ) ) return EINVAL; _Thread_Disable_dispatch(); the_mutex = _POSIX_Mutex_Allocate(); if ( !the_mutex ) { _Thread_Enable_dispatch(); return ENOMEM; } if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED && !( _Objects_MP_Allocate_and_open( &_POSIX_Mutex_Information, 0, the_mutex->Object.id, FALSE ) ) ) { _POSIX_Mutex_Free( the_mutex ); _Thread_Enable_dispatch(); return EAGAIN; } the_mutex->process_shared = the_attr->process_shared; the_mutex_attr = &the_mutex->Mutex.Attributes; the_mutex_attr->allow_nesting = the_attr->recursive; the_mutex_attr->priority_ceiling = _POSIX_Priority_To_core( the_attr->prio_ceiling ); the_mutex_attr->discipline = the_discipline; /* * Must be initialized to unlocked. */ _CORE_mutex_Initialize( &the_mutex->Mutex, OBJECTS_POSIX_MUTEXES, the_mutex_attr, CORE_MUTEX_UNLOCKED, 0 /* XXX proxy_extract_callout */ ); _Objects_Open( &_POSIX_Mutex_Information, &the_mutex->Object, 0 ); *mutex = the_mutex->Object.id; if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED ) _POSIX_Mutex_MP_Send_process_packet( POSIX_MUTEX_MP_ANNOUNCE_CREATE, the_mutex->Object.id, 0, /* Name not used */ 0 /* Not used */ ); _Thread_Enable_dispatch(); return 0; } /*PAGE * * 11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87 */ int pthread_mutex_destroy( pthread_mutex_t *mutex ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_ERROR: return EINVAL; case OBJECTS_REMOTE: _Thread_Dispatch(); return POSIX_MP_NOT_IMPLEMENTED(); return EINVAL; case OBJECTS_LOCAL: /* * XXX: There is an error for the mutex being locked * or being in use by a condition variable. */ if ( _CORE_mutex_Is_locked( &the_mutex->Mutex ) ) { _Thread_Enable_dispatch(); return EBUSY; } _Objects_Close( &_POSIX_Mutex_Information, &the_mutex->Object ); _CORE_mutex_Flush( &the_mutex->Mutex, _POSIX_Mutex_MP_Send_object_was_deleted, EINVAL ); _POSIX_Mutex_Free( the_mutex ); if ( the_mutex->process_shared == PTHREAD_PROCESS_SHARED ) { _Objects_MP_Close( &_POSIX_Mutex_Information, the_mutex->Object.id ); _POSIX_Mutex_MP_Send_process_packet( POSIX_MUTEX_MP_ANNOUNCE_DELETE, the_mutex->Object.id, 0, /* Not used */ 0 /* Not used */ ); } _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); } /* * _POSIX_Mutex_Lock_support * * A support routine which implements guts of the blocking, non-blocking, and * timed wait version of mutex lock. */ int _POSIX_Mutex_Lock_support( pthread_mutex_t *mutex, boolean blocking, Watchdog_Interval timeout ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_ERROR: return EINVAL; case OBJECTS_REMOTE: return _POSIX_Mutex_MP_Send_request_packet( POSIX_MUTEX_MP_OBTAIN_REQUEST, *mutex, 0, /* must define the option set */ WATCHDOG_NO_TIMEOUT ); case OBJECTS_LOCAL: _CORE_mutex_Seize( &the_mutex->Mutex, the_mutex->Object.id, blocking, timeout ); _Thread_Enable_dispatch(); return _Thread_Executing->Wait.return_code; break; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 * * NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29 */ int pthread_mutex_lock( pthread_mutex_t *mutex ) { return _POSIX_Mutex_Lock_support( mutex, TRUE, THREAD_QUEUE_WAIT_FOREVER ); } /*PAGE * * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 * * NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29 */ int pthread_mutex_trylock( pthread_mutex_t *mutex ) { return _POSIX_Mutex_Lock_support( mutex, FALSE, THREAD_QUEUE_WAIT_FOREVER ); } /*PAGE * * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 * * NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29 */ void POSIX_Threads_mutex_MP_support( Thread_Control *the_thread, Objects_Id id ) { (void) POSIX_MP_NOT_IMPLEMENTED(); /* XXX: should never get here */ } int pthread_mutex_unlock( pthread_mutex_t *mutex ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_ERROR: return EINVAL; case OBJECTS_REMOTE: return _POSIX_Mutex_MP_Send_request_packet( POSIX_MUTEX_MP_RELEASE_REQUEST, *mutex, 0, /* Not used */ MPCI_DEFAULT_TIMEOUT ); case OBJECTS_LOCAL: _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, POSIX_Threads_mutex_MP_support ); _Thread_Enable_dispatch(); return _Thread_Executing->Wait.return_code; /* XXX return status */ break; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 * * NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29 */ int pthread_mutex_timedlock( pthread_mutex_t *mutex, const struct timespec *timeout ) { return _POSIX_Mutex_Lock_support( mutex, TRUE, _POSIX_Time_Spec_to_interval( timeout ) ); } /*PAGE * * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 */ int pthread_mutexattr_setprotocol( pthread_mutexattr_t *attr, int protocol ) { if ( !attr ) return EINVAL; switch ( protocol ) { case PTHREAD_PRIO_NONE: case PTHREAD_PRIO_INHERIT: case PTHREAD_PRIO_PROTECT: attr->protocol = protocol; return 0; default: return EINVAL; } } /*PAGE * * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 */ int pthread_mutexattr_getprotocol( const pthread_mutexattr_t *attr, int *protocol ) { if ( !attr ) return EINVAL; *protocol = attr->protocol; return 0; } /*PAGE * * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 */ int pthread_mutexattr_setprioceiling( pthread_mutexattr_t *attr, int prioceiling ) { if ( !attr ) return EINVAL; if ( !_POSIX_Priority_Is_valid( attr->prio_ceiling ) ) return EINVAL; attr->prio_ceiling = prioceiling; return 0; } /*PAGE * * 13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 */ int pthread_mutexattr_getprioceiling( const pthread_mutexattr_t *attr, int *prioceiling ) { if ( !attr ) return EINVAL; *prioceiling = attr->prio_ceiling; return 0; } /*PAGE * * 13.6.2 Change the Priority Ceiling of a Mutex, P1003.1c/Draft 10, p. 131 */ int pthread_mutex_setprioceiling( pthread_mutex_t *mutex, int prioceiling, int *old_ceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; Priority_Control the_priority; int status; if ( !_POSIX_Priority_Is_valid( prioceiling ) ) return EINVAL; the_priority = _POSIX_Priority_To_core( prioceiling ); /* * Must acquire the mutex before we can change it's ceiling */ status = pthread_mutex_lock( mutex ); if ( status ) return status; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_ERROR: return EINVAL; case OBJECTS_REMOTE: return POSIX_MP_NOT_IMPLEMENTED(); /* XXX feels questionable */ return EINVAL; case OBJECTS_LOCAL: the_mutex->Mutex.Attributes.priority_ceiling = the_priority; _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, POSIX_Threads_mutex_MP_support ); _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); } /*PAGE * * 13.6.2 Change the Priority Ceiling of a Mutex, P1003.1c/Draft 10, p. 131 */ int pthread_mutex_getprioceiling( pthread_mutex_t *mutex, int *prioceiling ) { register POSIX_Mutex_Control *the_mutex; Objects_Locations location; the_mutex = _POSIX_Mutex_Get( mutex, &location ); switch ( location ) { case OBJECTS_ERROR: return EINVAL; case OBJECTS_REMOTE: return POSIX_MP_NOT_IMPLEMENTED(); /* XXX feels questionable */ case OBJECTS_LOCAL: *prioceiling = _POSIX_Priority_From_core( the_mutex->Mutex.Attributes.priority_ceiling ); _Thread_Enable_dispatch(); return 0; } return POSIX_BOTTOM_REACHED(); }