/** * @file * * @ingroup RTEMSImplClassicSemaphore * * @brief This source file contains the implementation of * rtems_semaphore_create() and the Semaphore Manager system initialization. */ /* * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #define SEMAPHORE_KIND_MASK ( RTEMS_SEMAPHORE_CLASS | RTEMS_INHERIT_PRIORITY \ | RTEMS_PRIORITY_CEILING | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING ) rtems_status_code rtems_semaphore_create( rtems_name name, uint32_t count, rtems_attribute attribute_set, rtems_task_priority priority_ceiling, rtems_id *id ) { Semaphore_Control *the_semaphore; Thread_Control *executing; Status_Control status; rtems_attribute maybe_global; rtems_attribute mutex_with_protocol; Semaphore_Variant variant; const Scheduler_Control *scheduler; bool valid; Priority_Control priority; uintptr_t flags; if ( !rtems_is_name_valid( name ) ) return RTEMS_INVALID_NAME; if ( !id ) return RTEMS_INVALID_ADDRESS; #if defined(RTEMS_MULTIPROCESSING) if ( !_System_state_Is_multiprocessing ) { attribute_set = _Attributes_Clear( attribute_set, RTEMS_GLOBAL ); } #endif /* Attribute subset defining a potentially global semaphore variant */ maybe_global = attribute_set & SEMAPHORE_KIND_MASK; /* Attribute subset defining a mutex variant with a locking protocol */ mutex_with_protocol = attribute_set & ( SEMAPHORE_KIND_MASK | RTEMS_GLOBAL | RTEMS_PRIORITY ); if ( maybe_global == RTEMS_COUNTING_SEMAPHORE ) { variant = SEMAPHORE_VARIANT_COUNTING; } else if ( maybe_global == RTEMS_SIMPLE_BINARY_SEMAPHORE ) { variant = SEMAPHORE_VARIANT_SIMPLE_BINARY; } else if ( maybe_global == RTEMS_BINARY_SEMAPHORE ) { variant = SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL; } else if ( mutex_with_protocol == ( RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY ) ) { variant = SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY; } else if ( mutex_with_protocol == ( RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING ) ) { variant = SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING; } else if ( mutex_with_protocol == ( RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING ) ) { #if defined(RTEMS_SMP) variant = SEMAPHORE_VARIANT_MRSP; #else /* * On uni-processor configurations the Multiprocessor Resource Sharing * Protocol is equivalent to the Priority Ceiling Protocol. */ variant = SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING; #endif } else { return RTEMS_NOT_DEFINED; } if ( count > 1 && variant != SEMAPHORE_VARIANT_COUNTING ) { return RTEMS_INVALID_NUMBER; } the_semaphore = _Semaphore_Allocate(); if ( !the_semaphore ) { _Objects_Allocator_unlock(); return RTEMS_TOO_MANY; } flags = _Semaphore_Set_variant( 0, variant ); #if defined(RTEMS_MULTIPROCESSING) if ( _Attributes_Is_global( attribute_set ) ) { bool ok; ok = _Objects_MP_Allocate_and_open( &_Semaphore_Information, name, the_semaphore->Object.id, false ); if ( !ok ) { _Semaphore_Free( the_semaphore ); _Objects_Allocator_unlock(); return RTEMS_TOO_MANY; } flags = _Semaphore_Make_global( flags ); } #endif if ( _Attributes_Is_priority( attribute_set ) ) { flags = _Semaphore_Set_discipline( flags, SEMAPHORE_DISCIPLINE_PRIORITY ); } else { flags = _Semaphore_Set_discipline( flags, SEMAPHORE_DISCIPLINE_FIFO ); } _Semaphore_Set_flags( the_semaphore, flags ); executing = _Thread_Get_executing(); switch ( variant ) { case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: _CORE_recursive_mutex_Initialize( &the_semaphore->Core_control.Mutex.Recursive ); if ( count == 0 ) { _CORE_mutex_Set_owner( &the_semaphore->Core_control.Mutex.Recursive.Mutex, executing ); _Thread_Resource_count_increment( executing ); } status = STATUS_SUCCESSFUL; break; case SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING: scheduler = _Thread_Scheduler_get_home( executing ); priority = _RTEMS_Priority_To_core( scheduler, priority_ceiling, &valid ); if ( valid ) { _CORE_ceiling_mutex_Initialize( &the_semaphore->Core_control.Mutex, scheduler, priority ); if ( count == 0 ) { Thread_queue_Context queue_context; _Thread_queue_Context_initialize( &queue_context ); _Thread_queue_Context_clear_priority_updates( &queue_context ); _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context ); _CORE_mutex_Acquire_critical( &the_semaphore->Core_control.Mutex.Recursive.Mutex, &queue_context ); status = _CORE_ceiling_mutex_Set_owner( &the_semaphore->Core_control.Mutex, executing, &queue_context ); if ( status != STATUS_SUCCESSFUL ) { _Thread_queue_Destroy( &the_semaphore->Core_control.Wait_queue ); } } else { status = STATUS_SUCCESSFUL; } } else { status = STATUS_INVALID_PRIORITY; } break; #if defined(RTEMS_SMP) case SEMAPHORE_VARIANT_MRSP: scheduler = _Thread_Scheduler_get_home( executing ); priority = _RTEMS_Priority_To_core( scheduler, priority_ceiling, &valid ); if ( valid ) { status = _MRSP_Initialize( &the_semaphore->Core_control.MRSP, scheduler, priority, executing, count == 0 ); } else { status = STATUS_INVALID_PRIORITY; } break; #endif default: _Assert( variant == SEMAPHORE_VARIANT_SIMPLE_BINARY || variant == SEMAPHORE_VARIANT_COUNTING ); _CORE_semaphore_Initialize( &the_semaphore->Core_control.Semaphore, count ); status = STATUS_SUCCESSFUL; break; } if ( status != STATUS_SUCCESSFUL ) { _Semaphore_Free( the_semaphore ); _Objects_Allocator_unlock(); return _Status_Get( status ); } /* * Whether we initialized it as a mutex or counting semaphore, it is * now ready to be "offered" for use as a Classic API Semaphore. */ *id = _Objects_Open_u32( &_Semaphore_Information, &the_semaphore->Object, name ); #if defined(RTEMS_MULTIPROCESSING) if ( _Attributes_Is_global( attribute_set ) ) _Semaphore_MP_Send_process_packet( SEMAPHORE_MP_ANNOUNCE_CREATE, the_semaphore->Object.id, name, 0 /* Not used */ ); #endif _Objects_Allocator_unlock(); return RTEMS_SUCCESSFUL; } static void _Semaphore_Manager_initialization( void ) { _Objects_Initialize_information( &_Semaphore_Information ); } RTEMS_SYSINIT_ITEM( _Semaphore_Manager_initialization, RTEMS_SYSINIT_CLASSIC_SEMAPHORE, RTEMS_SYSINIT_ORDER_MIDDLE );