/** * @file * * @brief rtems_semaphore_create * @ingroup ClassicSem Semaphores */ /* * 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. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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 * priority_ceiling - semaphore's ceiling priority * 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, 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; if ( !rtems_is_name_valid( name ) ) return RTEMS_INVALID_NAME; if ( !id ) return RTEMS_INVALID_ADDRESS; #if defined(RTEMS_MULTIPROCESSING) if ( _Attributes_Is_global( attribute_set ) ) { if ( !_System_state_Is_multiprocessing ) return RTEMS_MP_NOT_CONFIGURED; if ( _Attributes_Is_inherit_priority( attribute_set ) || _Attributes_Is_priority_ceiling( attribute_set ) || _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) return RTEMS_NOT_DEFINED; } else #endif if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) && !( _Attributes_Is_binary_semaphore( attribute_set ) && !_Attributes_Is_priority( attribute_set ) ) ) { return RTEMS_NOT_DEFINED; } if ( _Attributes_Is_inherit_priority( attribute_set ) || _Attributes_Is_priority_ceiling( attribute_set ) ) { if ( ! (_Attributes_Is_binary_semaphore( attribute_set ) && _Attributes_Is_priority( attribute_set ) ) ) return RTEMS_NOT_DEFINED; } if ( !_Attributes_Has_at_most_one_protocol( attribute_set ) ) return RTEMS_NOT_DEFINED; if ( !_Attributes_Is_counting_semaphore( attribute_set ) && ( count > 1 ) ) return RTEMS_INVALID_NUMBER; #if !defined(RTEMS_SMP) /* * On uni-processor configurations the Multiprocessor Resource Sharing * Protocol is equivalent to the Priority Ceiling Protocol. */ if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { attribute_set |= RTEMS_PRIORITY_CEILING | RTEMS_PRIORITY; } #endif the_semaphore = _Semaphore_Allocate(); if ( !the_semaphore ) { _Objects_Allocator_unlock(); return RTEMS_TOO_MANY; } #if defined(RTEMS_MULTIPROCESSING) the_semaphore->is_global = _Attributes_Is_global( attribute_set ); if ( _Attributes_Is_global( attribute_set ) && ! ( _Objects_MP_Allocate_and_open( &_Semaphore_Information, name, the_semaphore->Object.id, false ) ) ) { _Semaphore_Free( the_semaphore ); _Objects_Allocator_unlock(); return RTEMS_TOO_MANY; } #endif priority_ceiling = _RTEMS_tasks_Priority_to_Core( priority_ceiling ); executing = _Thread_Get_executing(); if ( _Attributes_Is_priority( attribute_set ) ) { the_semaphore->discipline = SEMAPHORE_DISCIPLINE_PRIORITY; } else { the_semaphore->discipline = SEMAPHORE_DISCIPLINE_FIFO; } if ( _Attributes_Is_counting_semaphore( attribute_set ) ) { the_semaphore->variant = SEMAPHORE_VARIANT_COUNTING; _CORE_semaphore_Initialize( &the_semaphore->Core_control.semaphore, count ); status = STATUS_SUCCESSFUL; } else if ( _Attributes_Is_simple_binary_semaphore( attribute_set ) ) { the_semaphore->variant = SEMAPHORE_VARIANT_SIMPLE_BINARY; _CORE_semaphore_Initialize( &the_semaphore->Core_control.semaphore, count != 0 ); status = STATUS_SUCCESSFUL; #if defined(RTEMS_SMP) } else if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { the_semaphore->variant = SEMAPHORE_VARIANT_MRSP; status = _MRSP_Initialize( &the_semaphore->Core_control.MRSP, priority_ceiling, executing, count != 1 ); #endif } else if ( _Attributes_Is_priority_ceiling( attribute_set ) ) { _Assert( _Attributes_Is_binary_semaphore( attribute_set ) ); the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING; _CORE_ceiling_mutex_Initialize( &the_semaphore->Core_control.Mutex, priority_ceiling ); if ( count == 0 ) { Thread_queue_Context queue_context; _Thread_queue_Context_initialize( &queue_context ); _ISR_lock_ISR_disable( &queue_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 ); } else { status = STATUS_SUCCESSFUL; } } else { _Assert( _Attributes_Is_binary_semaphore( attribute_set ) ); if ( _Attributes_Is_inherit_priority( attribute_set ) ) { the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY; } else { the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL; } _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 ); if ( _Attributes_Is_inherit_priority( attribute_set ) ) { ++executing->resource_count; } } status = STATUS_SUCCESSFUL; } 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. */ _Objects_Open( &_Semaphore_Information, &the_semaphore->Object, (Objects_Name) name ); *id = the_semaphore->Object.id; #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; }