![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Ada Kernel Layer The Ada Kernel Layer is a runtime nucleus with concurrency and synchronization services. It satisfies all the runtime requirements of Ada tasking and the Rational Exec extensions. For more information, refer to these topics:
The Ada Kernel Layer defines and provides operations for the following concurrency and synchronization objects. For more information, refer to these topics:
- Ada Program
- Ada Task
- Ada Task Master
- Kernel Scheduling
- Callout
- Task Storage
- Interrupts
- Time
- Alarm
- Mutex
- Condition Variable
- Binary Semaphore
- Counting Semaphore
- Mailbox
- Name
- Protected Records
For each object there are type definitions and a collection of services. Most objects have a set of user-definable attributes that are used to initialize them. Type and attribute definitions for each object are in package Ada_Krn_Defs. Package Ada_Krn_I contains the interface to all the object services. Both packages are located in the rational.ss subsystem.
Mutex and Condition Variable Object Types DefinitionThe mutex and condition variable object types are used to implement mutual exclusion between tasks and task suspension. The definition of these objects is extracted from the POSIX 1003.1c standard, (IEEE Threads Extension for Portable Operating Systems). Refer to this standard for more details about POSIX.
Mutex
A mutex is a synchronization object used to allow multiple threads to serialize their access to shared data. The name derives from the capability it provides: mutual exclusion.
The thread that has locked a mutex becomes its owner and remains the owner until the same thread unlocks the mutex. Other threads that attempt to lock the mutex during this period suspend execution until the original thread unlocks it. The act of suspending the execution of a thread awaiting a mutex does not prevent other threads from making progress in their computations.
In the Ada tasking layer, an Abort_Safe option has been added to mutexes. A task that has locked an Abort_Safe mutex is inhibited from being completed by an Ada abort until it unlocks the mutex.
Condition Variable
A condition variable is a synchronization object that allows a thread to suspend execution until some condition is true. Typically, a thread holding a mutex determines that it cannot proceed by examining the shared data guarded by the mutex. The thread then waits on a condition variable associated with some state of the shared data. Waiting on the condition variable atomically releases the mutex. If another thread modifies the shared data to make the condition true, that thread signals threads waiting on the condition variable. This wakes up one or more waiting threads, which then contend for the mutex and check the condition on which they have been waiting. This is typically done using a loop structure:
while not Condition loop cond_wait (CV, M); end loop;
Ideally, if multiple threads are waiting on CV, a call to cond_signal(CV) will wake up only one of them. This is the case with the current implementation of Rational Exec Microkernel, but it is not required by the POSIX standard, and may not be the case with other threads implementations over which the Apex Kernel Layer is implemented.
In the Ada tasking layer, an Abort_Safe option has been added to condition variables. A task locking an Abort_Safe mutex is inhibited from being completed by an Ada abort until it unlocks the mutex. However, if a task is aborted while waiting at a condition variable (after an implicit mutex unlock), it is allowed to complete.
Ada Kernel Layer ImplementationThe Ada Kernel Layer can be layered on numerous target kernels. So far it has been ported to Rational Software Corporation's Rational Exec Microkernel, Windows NT Threads, and the POSIX threads implementations of Sun Solaris, Compaq OSF-1, SGI Irix, IBM AIX, HP-UX, and LynxOS. Each Ada Kernel Layer implementation maps the objects, attributes, and services defined in Ada_Krn_Defs and Ada_Krn_I onto the underlying microkernel objects and services. By layering Ada tasks on microkernels, Ada tasks can coexist with and call thread based services written in other languages, such as threaded windows written in C.
In addition, a SUN, Compaq, Alpha and SGI workstations can have multiple CPUs. Their microkernel services have been designed to allow concurrent thread execution from a single program across multiple CPUs. By layering Ada tasks upon threads, we also obtain the multi-CPU capability.
The same Ada_Krn_Defs and Ada_Krn_I interface is provided across all the Ada Kernel Layer implementations. However, each implementation has a different representation for the object and attribute type definitions. Target kernel specific capabilities are made available to the application program through the object attributes.
Object attributes can be used in the following places in an application program:
- A counting semaphore attributes access value is passed to the Rational Exec service, V_Semaphores.Create_Semaphore, which returns a counting semaphore ID.
- A mailbox attributes access value is passed to the VADS Exec service, V_Mailboxes.Create_Mailbox.
- A mutex attributes access value is passed to the Rational Exec service, V_Mutexes.Create_Mutex, which returns a mutex ID.
Ada_Krn_Defs provides a set of subprograms for initializing the object attributes. For example, the following subprograms are provided to initialize mutex attributes:
fifo_mutex_attr_init prio_mutex_attr_init prio_inherit_mutex_attr_init prio_ceiling_mutex_attr_init intr_attr_init
These subprograms are applicable to all implementations of the Ada Kernel Layer. If an implementation does not support a particular attribute capability, it raises the Program_Error exception. Since these subprograms insulate the application software from the underlying attribute type representation, they should be used instead of explicitly initializing each field of an attribute record.
Even though the Ada Kernel Layer exists primarily to satisfy the requirements of Ada tasking and the Rational Exec extensions, some of its services are of interest to the application programmer. Rational Exec has services for binary semaphores, counting semaphores, mutexes, condition variables, mailboxes, and names. These services are layered on the corresponding services in the Ada Kernel Layer. The application may elect to bypass the additional overhead incurred by the Rational Exec layer and call the Ada Kernel Layer services directly.
Warning: Since the program, master, and task services have complex semantics and implicit dependencies, avoid calling these services directly.
The following sections discuss each of the objects in the Ada Kernel Layer. For each object, the following topics are addressed:
- Types
- Constants
- Attributes
- Services
- Support Subprograms
The interface to the services provided in ada_krn_i.1.ada and ada_krn_defs.1.ada contain the rest. Both files are in the rational.ss subsystem.
Ada Program
There is a single Ada program object per executable entity. The Ada program object is automatically created and initialized during program startup.
Types
- Program_Id
Type of the Ada program's object. The type definition for Program_Id is in the package System.
- Krn_Program_Id
Type of the underlying program/process. There are services for mapping between the Ada Program_Id and Krn_Program_Id.
Attributes
Services
Since the Ada program services should not be called directly, they are only listed here. Consult ada_krn_i.1.ada in rational.ss for more details.
- Program services
- Program_Init
- Program_Exit
- Program_Diagnostic
- Panic_Exit
- Program_Is_Active
- Program_Self
- Program_Inter_Call
- Program services (Rational Exec augmentation)
- Program_Get
- Program_Start
- Program_Set_Is_Server
- Program_Is_Server
- Program_Terminate
- Program_Get_Key
- Program_Get_Ada_Id
- Program_Get_Krn_Id
- Inter_Program_Call
Ada Task
An Ada task object exists for each thread of execution. Most operations on Ada task objects are done implicitly using the tasking semantics of the Ada language.
Types
- Task_Id
Type of the Ada task's object. The type definition for Task_Id is in the package System.
- Krn_Task_Id
Type of the underlying thread. There are services for mapping between the Ada Task_Id and Krn_Task_Id.
Attributes
- Default_Task_Attributes
Is used if no Task_Attribtes pragma is specified.
- Task_Attr_T
The address of a Task_Attr_T record is the first or second argument of the Task_Attributes pragma and is passed to the ada tasking layer task creation. The definition of the Task_Attr_T record is Rational Exec Microkernel specific. However, all variations of the Task_Attr_T record contain at least the Prio, Mutex_Attr_Address, and Cond_Attr_Address fields. The prio field specifies the priority of the task. If the task also had a pragma Priority(prio).
The Mutex_Attr_Address field contains the address of the attributes to be used to initialize the mutex object implicitly created for the task. This mutex is used to protect the task's data structure. For example, the task's mutex is locked when another task attempts to rendezvous with it. If Mutex_Attr_Address is set to No_Addr, the Mutex_Attr_Address value specified by the V_Usr_Conf.Configuration_Table parameter, Default_Task_Attributes is used. Otherwise, Mutex_Attr_Address must be set to the address of an Ada_Krn_Defs.Mutex_Attr_T record. The Mutex_Attr_T record should be initialized using one of the mutex attribute init subprograms.
The Cond_Attr_Address field contains the address of the attributes to be used to initialize the condition variable object implicitly created for the task. When the task blocks, it waits on this condition variable. If Cond_Attr_Address is set to No_Addr, the cond_attr_address value specified by the V_Usr_Conf.Configuration_Table parameter, Default_Task_Attributes is used. Otherwise, Cond_Attr_Address must be set to the address of a Ada_Krn_Defs.Cond_Attr_T record. The Cond_Attr_T record should be initialized using one of the condition variable attribute init routines.
The Task_Attr_T record can be initialized using one of the overloaded Task_Attr_Init subprograms. Refer to Ada Task Support Subprograms, for more information.
Additional Topics
For additional information, refer to these topics:
Services
There are two services for mapping between the Ada Task_Id and the Krn_Task_Id:
function Task_Get_Ada_Id(Krn_Tsk: Krn_Task_Id) return Task_Id; -- Returns NO_Task_ID if the kernel task is not also an Ada task function Task_Get_Krn_Id(tsk: Task_Id) return Krn_Task_Id;Since the remaining Ada task services should not be called directly, they are listed here. Consult ada_krn_i.1.ada in rational.ss for more details.
- Task management services
- Task_Self
- Task_Set_Priority
- Task_Get_Priority
- Task_Create
- Task_Get_Sequence_Number
- Task_Activate
- Task_Stop
- Task_Destroy
- Task_Stop_Self
- Task_Destroy_Self
- Task_Abort
- Task management services (Rational Exec augmentation)
- Task_Disable_Preemption
- Task_Enable_Preemption
- Task_Suspend
- Task_Resume
- Task_Get_Time_Slice
- Task_Set_Time_Slice
- Task_Get_Supervisor_State
- Task_Enter_Supervisor_State
- Task_Leave_Supervisor_State
- Task synchronization services
- Task_Lock
- Task_Unlock
- Task_Wait
- Task_Wait_Locked_Masters
- Task_Timed_Wait
- Task_Signal
- Task_Wait_Unlock
- Task_Signal_Unlock
- Task_Signal_Wait_Unlock
- Task_Timed_Wait_Until
Ada Task Support Subprograms
The Task_Attr_T record can be initialized using one of the overloaded Task_Attr_Init subprograms. The task_attr parameter identifies the address of the storage allocated for the task attribute record.
procedure task_attr_init( task_attr : a_task_attr_t; prio : priority := priority'first; -- ... OS Threads specific fields; mutex_attr : a_mutex_attr_t := null; cond_attr : a_cond_attr_t := null ); function task_attr_init( task_attr : a_task_attr_t; prio : priority := priority'first; -- ... OS Threads specific fields mutex_attr : a_mutex_attr_t := null; cond_attr : a_cond_attr_t := null ) return address; function task_attr_init( -- does an implicit "task_attr: a_task_attr_t := -- new task_attr_t;" prio : priority := priority'first; -- ... OS Threads specific fields; mutex_attr : a_mutex_attr_t := null; cond_attr : a_cond_attr_t := null ) return address;
Note: It may be desirable to specify priority ceiling for implicit task mutexes. In extremely rare cases, failure to do this might result in an unbounded priority inversion.
Examples
The following is an example of initializing the Task_Attr_T record.
with system; with ada_krn_defs; package one is -- Does an implicit allocation of the task_attr_t record task a is pragma task_attributes(ada_krn_defs.task_attr_init( prio => 20, ... OS_threads_specific_fields )); end; task type tt; b: tt; pragma task_attributes(b, ada_krn_defs.task_attr_init( prio => 30, ... OS_threads_specific_fields )); end one; with system; with ada_krn_defs; package two is -- No implicit allocation is done a_attr_rec: ada_krn_defs.task_attr_t; a_attr: system.address := ada_krn_defs.task_attr_init( task_attr => ada_krn_defs.to_a_task_attr_t( a_attr_rec'address), prio => 20, ... OS_threads_specific_fields ); b_attr_rec: ada_krn_defs.task_attr_t; b_attr: system.address := ada_krn_defs.task_attr_init( task_attr => ada_krn_defs.to_a_task_attr_t( b_attr_rec'address), prio => 30, ... OS_threads_specific_fields ); task a is pragma task_attributes(a_attr); -- or -- pragma task_attributes(a_attr_rec'address); end; task type tt; b: tt; pragma task_attributes(b, b_attr); -- or -- pragma task_attributes(b, b_attr_rec'address); end two;Ada Task Master
A single task master lock exists to provide mutual exclusion for operations performed across multiple task objects (for example, aborting Ada tasks).
Types
None. There is one master lock and it is implied in the services.
Attributes
Services
Since the Ada task master services should not be called directly, they are only listed here. Consult ada_krn_i.1.ada in rational.ss for more details
- Task masters synchronization services:
- Masters_Lock
- Masters_Trylock
- Masters_Unlock
Kernel Scheduling
Services are provided to control the kernel scheduling policies.
Types
None. There is one kernel scheduling object and it is implied in the services.
Attributes
Services
The Ada Kernel Layer has the following scheduling services:
function kernel_get_time_slicing_enabled return boolean; procedure kernel_set_time_slicing_enabled(new_value: boolean);
Warning: The above scheduling services are not supported for all implementations of the Ada Kernel Layer.
Callout
Services are provided that allow a subprogram to be called at a program, task, or idle event.
Types
- Callout_Event_T
All versions of the Ada Kernel Layer are expected to support at least the program events: Exit_Event and Unexpected_Exit_Event.
Attributes
Services
The following service installs a callout for the specified program, task or idle event. It returns False if the service is not supported or it is unable to do the installation.
function callout_install(event: callout_event_t; proc: address) return boolean;V_Xtasking.Install_Callout in Rational Exec is layered directly on the Callout_Install service. Consult the Rational Exec documentation for more details.
Task Storage
Some versions of the Ada Kernel Layer support user-defined storage on a per-task basis (currently supported only over the Rational Exec Microkernel).
Types
Attributes
Services
The following task storage allocation services are currently supported only over Rational Exec Microkernel:
function task_storage_alloc(size: natural) return task_storage_id; -- If service isn't supported or unable to allocate memory, it -- returns NO_Task_STORAGE_ID. function task_storage_get(tsk: task_id; storage: task_storage_id) return address; function task_storage_get2(krn_tsk: krn_task_id; storage: task_storage_id) return address;The Rational Exec V_X tasking services (Allocate_Task_Storage, Get_Task_Storage, and Get_Task_Storage2) are layered directly on the above Ada Kernel Layer services.
Interrupts
Services are provided to enable/disable interrupts, get interrupt enabled/disabled status, attach/detach interrupt service routine (ISR), get an attached ISR, and check if it is in an ISR. (On native, interrupts are UNIX signals.)
Types
- Intr_Vector_Id_T
- Intr_Status_T
- Intr_Entry_T
The address of an Intr_Entry_T object is specified in an interrupt entry address clause. The Intr_Entry_T record contains two fields: interrupt vector and the task priority for executing the interrupt entry's accept body.
The Intr_Entry_T record can be initialized using one of the overloaded Intr_Entry_Init subprograms. Refer to Interrupt Support Subprograms, for more information.
Constants
- Disable_Intr_Status
Constant for disabling all asynchronous signals
- Enable_Intr_Status
Constant for enabling all asynchronous signals
- Bad_Intr_Vector
Value returned for a bad interrupt vector passed to one of these services..
Attributes
Services
The Ada Kernel Layer has the following interrupt services:
procedure interrupts_get_status(status: out intr_status_t); procedure interrupts_set_status(old_status: out intr_status_t; new_status: intr_status_t); function isr_attach(iv: intr_vector_id_t; isr: address) return address; -- Returns address of previously attached isr. -- Ada_Krn_Defs.BAD_Intr_Vector is returned for a bad intr_vector -- parameter. function isr_detach(iv: intr_vector_id_t) return address; -- Returns address of previously attached isr. -- Ada_Krn_Defs.BAD_Intr_Vector is returned for a bad intr_vector -- parameter. function isr_get(iv: intr_vector_id_t) return address; -- Returns the address of the currently attached isr. -- ada_krn_defs.BAD_Intr_Vector is returned for a bad intr_vector -- parameter. function isr_get_ivt return address; -- Returns address of the Interrupt Vector Table (IVT). Normally, -- the IVT is an array of ISR addresses. However, the IVT -- representation is CPU dependent (for 386 cross, its the IDT). function isr_in_check return boolean; -- If in an ISR, returns True.The Rational Exec V_Interrupts services (Attach_Isr, Detach_Isr, Get.Isr, Get.Ivt, Current_Interrupt_Status, and Set_Interrupt_Status) are layered directly on the Ada Kernel Layer services.
Warning: No Rational Exec service is layered on the Isr_In_Check Ada Kernel Layer service.
Interrupt Support Subprograms
The Intr_Entry_T record can be initialized using one of the overloaded Intr_Entry_Init subprograms:
procedure intr_entry_init( intr_entry : a_intr_entry_t; intr_vector : intr_vector_id_t; prio : priority := priority'last); function intr_entry_init( intr_entry : a_intr_entry_t; intr_vector : intr_vector_id_t; prio : priority := priority'last) return address; function intr_entry_init( -- does an implicit "intr_entry: a_intr_entry_t := -- new intr_entry_t;" intr_vector : intr_vector_id_t; prio : priority := priority'last) return address;
Examples
Intr_Entry_Init can be used as follows to define an interrupt entry:
with system; with ada_krn_defs; package one is -- Does an implicit allocation of the intr_entry_t record task a is entry ctrl_c; for ctrl_c use at ada_krn_defs.intr_entry_init( intr_vector => 2, prio => priority'last); end; end one; with system; with ada_krn_defs; package two is -- No implicit allocation is done ctrl_c_intr_entry_rec: ada_krn_defs.intr_entry_t; ctrl_c_intr_entry: system.address := ada_krn_defs.intr_entry_init( intr_entry => ada_krn_defs.to_a_intr_entry_t( ctrl_c_intr_entry_rec'address), intr_vector => 2, prio => priority'last); task a is entry ctrl_c; for ctrl_c use at ctrl_c_intr_entry; -- OR -- for ctrl_c use at ctrl_c_intr_entry_rec'address; end; end two;
To see more about V_Interrupts see the Ada Extended Runtime Services Reference.
Time
The Ada Kernel Layer provides time services for supporting Ada's delay statement: the predefined Calendar package. the predefined Ada.Real_Time package (from the Ada 95 Real-time Annex), and Rational Software Corporation's calendar extensions in the XCalendar package.
The Ada delay statement and the procedure Time_Delay produce a delta delay, whereas the Ada delay until statement and the procedure Time_Delay_Until produce an absolute delay.
If a task used the Ada delay statement or has called Time_Delay, calling Set_Time does not affect how long the task actually delays.
If a task calls Time_Delay_Until, calling Set_Time changes how long the task actually delays by the amount of the adjustment. For example, if a task has called Delay_Until (T + To_Time_Span (100.0)), calling Set_Time (T + To_Time_Span (50.0)) shortens the length of time that the task delays by 50 seconds. Additionally, if the current time is moved past the Delay_Until time for a task, that task is placed on the run queue immediately.
In the current release, all delays initiated by an asynchronous select statement are effected by Set_Time, whether relative or absolute. A future release will make asynchronous delays consistent with synchronous delays.
Types
- Duration
An interval of time. Duration is a predefined Ada type
- Time_T
- Time_Span_T
Another representation of an interval of time. Usually, though not always, more accurate than duration. Time_T and Time_Span_T are underlying representations of Ada.Real_Time.Time and Time_Span. Their representation varies with configuration. See Configuring the User Library for more information.
Attributes
Services
The Ada Kernel Layer has the following time services:
procedure time_set(time : v_i_types.time_t; timer_support_arg: address := NO_ADDR); -- -- timer_support_arg - on native, if not NO_ADDR, then, -- the address of the OS's time record. This allows, -- time_set to be atomically set with the OS's current time. procedure time_get(time: out v_i_types.time_t); procedure time_delay(sec: duration); procedure time_span_delay(sec: v_i_types.time_span_t); procedure time_delay_until(time : v_i_types.time_t);Alarm
An alarm is used to provide asynchronous notification that a specified time has arrived. It is used to implement Ada asynchronous delays.
Notification is provided by calling a procedure with an address argument, both of which are specified when the alarm is set. The profile of this procedure is
procedure Alarm_Handler (Arg : System.Address);
Types
- Time_Event_T, A_Time_Event_T
Time_Event_T objects are used to control and identify alarm requests. A_Time_Event_T is the access type of a time event object. The function A_Krn_Defs.To_A_Time_Event_T can be used to convert the address of the Time_Event_T record to its access type.
Services
Since the Ada alarm services should not be called directly, they are only listed here. Consult ada_krn_i.1.ada in rational.ss for more details.
- Alarm_Set
- Alarm_Cancel
Mutex
Mutexes can be used explicitly by the user to serialize access to shared data.
The semantics of locking/unlocking a mutex adheres to the POSIX 1003.1c standard. Refer to the latest draft of that standard for more details about POSIX mutexes.
An Abort_Safe version of the mutex services is provided in the V_I_Mutex package found in rational.ss. A task locking an Abort_Safe mutex is inhibited from being completed by an Ada abort until it unlocks the mutex.
Types
- Mutex_T, A_Mutex_T
Mutex_T is the type of a mutex object. A_Mutex_T is the access type of a mutex object. The address of a mutex object can be converted to its access type with the function Ada_Krn_Defs.To_A_Mutex_T.
Attributes
- Mutex_Attr_T, A_Mutex_Attr_T
Mutex_Attr_T is the type definition of the mutex attributes. A_Mutex_Attr_T is its access type. The function Ada_Krn_Defs.To_A_Mutex_Attr_T can be used to convert the address of the mutex attribute record to its access type.
The Mutex_Attr_T record can be initialized using one of the mutex attribute init subprograms. Refer to Mutex Support Subprograms, for more information.
The mutex attributes are target kernel dependent. Refer to ada_krn_defs.1.ada in rational.ss for the options supported. Rational Exec Microkernel locks the mutex by executing a test-and-set instruction or by disabling interrupts. It supports FIFO, priority, or priority inheritance waiting when the mutex is locked by another task.
Rational Exec Microkernel has the following variant mutex attribute record type:
- Intr_Attr_T
Disables interrupts (signals) to provide mutual exclusion.
The function Default_Mutex_Attr is provided to select the default mutex attributes.
To provide mutual exclusion by disabling all interrupts, use Default_Intr_Attr. If the underlying microkernel does not support interrupt attributes, the Program_Error exception is raised.
Services
The Ada Kernel Layer has the following mutex services:
function mutex_init(mutex: a_mutex_t; attr: a_mutex_attr_t) return boolean; -- Returns True if mutex was successfully initialized. procedure mutex_destroy(mutex: a_mutex_t); procedure mutex_lock(mutex: a_mutex_t); function mutex_trylock(mutex: a_mutex_t) return boolean; -- Returns True if the mutex can be locked without -- waiting. Otherwise, returns False without locking the mutex. procedure mutex_unlock(mutex: a_mutex_t);The Ada Kernel Layer has the following services for mutexes that can be locked from an ISR:
function isr_mutex_lockable(mutex: a_mutex_t) return boolean; -- Returns True if mutex can be locked from an ISR. This -- service is called for a passive task with an interrupt -- entry. Since the passive task's critical region will be -- entered from an ISR, we must be able to lock its mutex -- from an ISR. procedure isr_mutex_lock(mutex: a_mutex_t); procedure isr_mutex_unlock(mutex: a_mutex_t); -- The isr_mutex_lock/isr_mutex_unlock services must only -- be called from an ISR using a mutex that is lockable -- from an ISR.Mutex Support Subprograms
The following subprograms are provided to initialize the Mutex_Attr_T record:
fifo_mutex_attr_init prio_mutex_attr_init prio_inherit_mutex_attr_init prio_ceiling_mutex_attr_init intr_attr_init
If the underlying Target kernel does not support the type of mutex being initialized, the Program_Error exception is raised.
Here are the overloaded subprograms for initializing the Mutex_Attr_T record:
procedure fifo_mutex_attr_init( attr : a_mutex_attr_t); function fifo_mutex_attr_init( attr : a_mutex_attr_t) return a_mutex_attr_t; function fifo_mutex_attr_init( attr : a_mutex_attr_t) return address; function fifo_mutex_attr_init return a_mutex_attr_t; -- does an implicit -- "attr: a_mutex_attr_t := new mutex_attr_t;" function fifo_mutex_attr_init return address; -- does an implicit -- "attr: a_mutex_attr_t := new mutex_attr_t;" procedure prio_mutex_attr_init( attr : a_mutex_attr_t); function prio_mutex_attr_init( attr : a_mutex_attr_t) return a_mutex_attr_t; function prio_mutex_attr_init( attr : a_mutex_attr_t) return address; function prio_mutex_attr_init return a_mutex_attr_t; -- does an implicit -- "attr: a_mutex_attr_t := new mutex_attr_t;" function prio_mutex_attr_init return address; -- does an implicit -- "attr: a_mutex_attr_t := new mutex_attr_t;" procedure prio_inherit_mutex_attr_init( attr : a_mutex_attr_t); function prio_inherit_mutex_attr_init( attr : a_mutex_attr_t) return a_mutex_attr_t; function prio_inherit_mutex_attr_init( attr : a_mutex_attr_t) return address; function prio_inherit_mutex_attr_init return a_mutex_attr_t; -- does an implicit -- "attr: a_mutex_attr_t := new mutex_attr_t;" function prio_inherit_mutex_attr_init return address; -- does an implicit -- "attr: a_mutex_attr_t := new mutex_attr_t;" procedure prio_ceiling_mutex_attr_init( attr : a_mutex_attr_t; ceiling_prio : priority := priority'last); function prio_ceiling_mutex_attr_init( attr : a_mutex_attr_t; ceiling_prio : priority := priority'last) return a_mutex_attr_t; function prio_ceiling_mutex_attr_init( attr : a_mutex_attr_t; ceiling_prio : priority := priority'last) return address; function prio_ceiling_mutex_attr_init( -- does an implicit "attr: a_mutex_attr_t := new mutex_attr_t;" ceiling_prio : priority := priority'last) return a_mutex_attr_t; function prio_ceiling_mutex_attr_init( -- does an implicit "attr: a_mutex_attr_t := new mutex_attr_t;" ceiling_prio : priority := priority'last) return address; procedure intr_attr_init( attr : a_mutex_attr_t; disable_status : intr_status_t := Disable_Intr_Status); function intr_attr_init( attr : a_mutex_attr_t; disable_status : intr_status_t := Disable_Intr_Status) return a_mutex_attr_t; function intr_attr_init( attr : a_mutex_attr_t; disable_status : intr_status_t := Disable_Intr_Status) return address; function intr_attr_init( -- does an implicit "attr: a_mutex_attr_t := new mutex_attr_t;" disable_status : intr_status_t := Disable_Intr_Status) return a_mutex_attr_t; function intr_attr_init( -- does an implicit "attr: a_mutex_attr_t := new mutex_attr_t;" disable_status : intr_status_t := Disable_Intr_Status) return address;Condition Variable
Condition variables are used to wait until a particular condition is True. A condition variable must be used in conjunction with a mutex.
The semantics of waiting on or signaling a condition variable and its interaction with a mutex adheres to the POSIX 1003.4a standard, IEEE Threads Extension for Portable Operating Systems. Refer to the latest draft of that standard for more details about POSIX condition variables.
An Abort_Safe version of the mutex and condition variable services is provided in package V_I_Mutex found in rational.ss. A task locking an Abort_Safe mutex is inhibited from being completed by an Ada abort until it unlocks the mutex. However, if a task is aborted while waiting at a condition variable (after an implicit mutex unlock), it is allowed to complete. The V_I_Mutex services also address the case where multiple Abort_Safe mutexes are locked. A task is inhibited from being completed until all the mutexes are unlocked or it does a condition variable wait with only one mutex locked.
Types
- Cond_T, A_Cond_T
Cond_T is the type of a condition variable object. A_Cond_T is the access type of a condition variable object. The address of a condition variable object can be converted to its access type using the function Ada_Krn_Defs.To_A_Cond_T.
Attributes
- Cond_Attr_T, A_Cond_Attr_T
Cond_Attr_T is the type definition of the condition variable attributes. A_Cond_Attr_T is its access type. The function Ada_Krn_Defs.To_A_Cond_Attr_T can be used to convert the address of the condition variable attributes to its access type.
The Cond_Attr_T record can be initialized using one of the condition variable init subprograms. Refer to Condition Variable Support Subprograms, for more information.
The condition variable attributes are target-dependent. Refer to ada_krn_defs.1.ada in rational.ss for the options supported. Rational Exec Microkernel supports FIFO or priority waiting.
The function Default_Cond_Attr is provided to select the default condition variable attributes.
Services
The Ada Kernel Layer has the following condition variable services:
function cond_init(cond: a_cond_t; attr: a_cond_attr_t) return boolean; -- Returns True if condition variable was successfully initialized. procedure cond_destroy(cond: a_cond_t); procedure cond_wait(cond: a_cond_t; mutex: a_mutex_t); -- COND_WAIT must be called with the mutex already locked by the -- calling task. COND_WAIT atomically releases the mutex and causes -- the calling task to block on the condition variable. The -- blocked task may be awakened by COND_SIGNAL, -- COND_SIGNAL_UNLOCK, COND_BROADCAST, or by some OS -- Threads specific stimulus. Any change in value of a condition associated -- with the condition variable cannot be inferred by the return -- of COND_WAIT and any such condition must be reevaluated. -- COND_WAIT always returns with the mutex locked by the calling -- task. function cond_timed_wait(cond: a_cond_t; mutex: a_mutex_t; sec: duration) return boolean; -- COND_TIMED_WAIT is similar to COND_WAIT, except that -- the calling task will only block for the amount of time -- specified by the sec parameter. If the condition variable -- wasn't signalled, COND_TIMED_WAIT returns False. For -- all cases, COND_TIMED_WAIT returns with the mutex -- locked by the calling task. procedure cond_signal(cond: a_cond_t); procedure cond_broadcast(cond: a_cond_t); -- COND_SIGNAL unblocks one task that is blocked on -- the condition variable. COND_BROADCAST unblocks all -- tasks that are blocked on the condition variable. If -- no tasks are blocked on the condition variable then -- COND_SIGNAL and COND_BROADCAST have no effect. Both -- procedures should be called under the protection of the -- same mutex that is used with the condition variable being -- signalled. Otherwise the condition variable may be -- signalled between the test of the associated condition -- and blocking in COND_WAIT. This can cause an infinite wait. procedure cond_signal_unlock(cond: a_cond_t; mutex: a_mutex_t); -- COND_SIGNAL_UNLOCK has the same semantics as making the -- following two calls: -- COND_SIGNAL(cond); -- MUTEX_UNLOCK(mutex); -- -- To improve performance, the Ada Kernel Layer implementation may -- treat the above condition variable signalling and the mutex -- unlocking sequence as an atomic operation.The Ada Kernel Layer has the following service for a condition variable that can be called only from an ISR:
procedure isr_cond_signal(cond: a_cond_t); -- Isr_COND_SIGNAL. It -- has the same semantics as COND_SIGNAL. The condition -- variable being signalled must be protected by an ISR -- lockable mutex.Condition Variable Support Subprograms
The following subprograms are provided to initialize the Cond_Attr_T record:
fifo_cond_attr_init prio_cond_attr_init
If the underlying Target kernel does not support the type of condition variable being initialized, the Program_Error exception is raised.
Here are the overloaded subprograms for initializing the Cond_Attr_T record:
procedure fifo_cond_attr_init( attr : a_cond_attr_t); function fifo_cond_attr_init( attr : a_cond_attr_t) return a_cond_attr_t; function fifo_cond_attr_init return a_cond_attr_t; -- does an implicit -- "attr: a_cond_attr_t := new cond_attr_t;" procedure prio_cond_attr_init( attr : a_cond_attr_t); function prio_cond_attr_init( attr : a_cond_attr_t) return a_cond_attr_t; function prio_cond_attr_init return a_cond_attr_t; -- does an implicit -- "attr: a_cond_attr_t := new cond_attr_t;"
Binary Semaphore
A binary semaphore is an object that can be in one of two states, full or empty. If a task waits on a full semaphore, then it makes the semaphore empty and continues executing. If a task waits on an empty semaphore, then it blocks until it is signalled. When a semaphore is signalled, the next available task is unblocked. If no task was blocked on the semaphore, the semaphore becomes full.
Binary semaphores are used by the Rational Exec V_Semaphores services. The overhead added by the Rational Exec layer can be eliminated by directly using the Ada Kernel Layer binary semaphores.
Types
- Semaphore_T, A_Semaphore_T
Semaphore_T is the type of a binary semaphore object. A_Semaphore_T is the access type of a binary semaphore object. The address of a binary semaphore object can be converted to its access type with the function Ada_Krn_Defs.To_A_Semaphore_T.
- Semaphore_State_T
Binary semaphore's state: Semaphore_Full or Semaphore_Empty.
Constants
- Semaphore_Full
- Semaphore_Empty
Attributes
- Semaphore_Attr_T, A_Semaphore_Attr_T
Semaphore_Attr_T is the type definition of the binary semaphore attributes. A_Semaphore_Attr_T is its access type. The function Ada_Krn_Defs.To_A_Semaphore_Attr_T can be used to convert the address of the binary semaphore attributes to its access type.
The A_Semaphore_Attr_T access value is passed to the Rational Exec service, V_Semaphores.Create_Semaphore, which returns a Binary_Semaphore_Id.
The semaphore attributes are target kernel dependent. Refer to ada_krn_defs.1.ada in rational.ss for the different options supported. (Rational Exec Microkernel supports FIFO queuing only when the task waits on a semaphore.)
The function Default_Semaphore_Attr is provided to select the default semaphore attributes.
Services
The Ada Kernel Layer has the following binary semaphore services:
function semaphore_init(s: a_semaphore_t; init_state: semaphore_state_t; attr: a_semaphore_attr_t) return boolean; -- Returns True if semaphore was successfully initialized. procedure semaphore_destroy(s: a_semaphore_t); procedure semaphore_wait(s: a_semaphore_t); function semaphore_trywait(s: a_semaphore_t) return boolean; -- Returns True if the semaphore was FULL. function semaphore_timed_wait(s: a_semaphore_t; sec: duration) return boolean; -- Returns True if we didn't timeout waiting for the -- semaphore to be FULL or signalled. procedure semaphore_signal(s: a_semaphore_t); function semaphore_get_in_use(s: a_semaphore_t) return boolean; -- Returns True if any task is waiting on the semaphore. If the -- Ada Kernel Layer is unable to detect this condition, it returns -- True. -- -- SEMAPHORE_GET_IN_USE is called by Rational Exec -- V_SEMAPHORES.DELETE_SEMAPHORE service for a binary -- semaphore.Counting Semaphore
A counting semaphore is an object with a non-negative count. If a task waits on a semaphore with a non-zero count, it decrements the count and continues executing. If a task waits on a semaphore with a zero count, then it blocks until it is signalled. When a semaphore is signalled, the next available task is unblocked. If no task was blocked on the semaphore, the semaphore's count is incremented.
Counting semaphores are used by the Rational Exec V_Semaphores services. The overhead added by the Rational Exec layer can be eliminated by directly using the Ada Kernel Layer's counting semaphores.
Types
- Count_Semaphore_T, A_Count_Semaphore_T
Count_Semaphore_T is the type of a counting semaphore object. A_Count_Semaphore_T is the access type of a counting semaphore object. The address of a counting semaphore object can be converted to its access type with the function Ada_Krn_Defs.To_A_Count_Semaphore_T.
Attributes
- Count_Semaphore_Attr_T, A_Count_Semaphore_Attr_T
Count_Semaphore_Attr_T is the type definition of the counting semaphore attributes. A_Count_Semaphore_Attr_T is its access type. The function Ada_Krn_Defs.To_A_Count_Semaphore_Attr_T can be used to convert the address of the counting semaphore attributes to its access type.
The A_Count_Semaphore_Attr_T access value is passed to the Rational Exec service, V_Semaphores.Create_Semaphore, which returns a Count_Semaphore_Id.
The counting semaphore attributes are target kernel dependent. Refer to ada_krn_defs.1.ada in rational.ss for the different options supported. (Rational Exec Microkernel uses a mutex to protect the count. It waits on a condition variable. The Count_Semaphore_Attr_T is a subtype of Mutex_Attr_T. The Cond_Attr_T is derived from the Mutex_Attr_T. A FIFO condition variable is used for a FIFO mutex. A priority condition variable is used for either a priority, priority inheritance, or priority ceiling mutex.)
Rational Exec Microkernel has the following variant counting semaphore attribute record type:
- Count_Intr_Attr_T
Interrupts are disabled when accessing the semaphore count.
The function, Default_Count_Semaphore_Attr, is provided to select the default counting semaphore attributes.
To protect counting semaphore operations by disabling all interrupts, use Default_Count_Intr_Attr. If the underlying microkernel does not support interrupt attributes, the Program_Error exception is raised. However, if the Default_Count_Semaphore_Attr is interrupt safe, then Default_Count_Intr_Attr returns Default_Count_Semaphore_Attr and does not raise Program_Error.
Alternatively, the counting semaphore attributes can be initialized to select the disable interrupts options by using one of the overloaded Count_Intr_Attr_Init subprograms. Refer to Counting Semaphore Support Subprograms, for more information.
Services
The Ada Kernel Layer has the following counting semaphore services:
function count_semaphore_init( s : a_count_semaphore_t; init_count : integer; attr : a_count_semaphore_attr_t) return boolean; -- Returns True if semaphore was successfully initialized. procedure count_semaphore_destroy(s: a_count_semaphore_t); function count_semaphore_wait(s: a_count_semaphore_t; wait_time: duration) return boolean; -- Waits on a counting semaphore. -- -- If semaphore's count > 0, decrements the count and returns True. -- Otherwise, returns according to the wait_time parameter: -- < 0.0 - the calling task blocks until the semaphore -- is signalled. It always returns True. -- = 0.0 - immediately returns False. -- > 0.0 - returns True if we didn't timeout waiting for -- the semaphore to be signalled. For a -- timeout, returns False. procedure count_semaphore_signal(s: a_count_semaphore_t); function count_semaphore_get_in_use(s: a_count_semaphore_t) return boolean; -- Returns True if any task is waiting on the semaphore. If the -- Ada Kernel Layer is unable to detect this condition, it returns -- True. -- -- SEMAPHORE_GET_IN_USE is called by the Rational Exec -- V_SEMAPHORES.DELETE_SEMAPHORE service for a counting -- semaphore.Counting Semaphore Support Subprograms
The counting semaphore attributes can be initialized to select the disable interrupts options by using one of the overloaded Count_Intr_Attr_Init subprograms.
procedure count_intr_attr_init( attr : a_count_semaphore_attr_t; disable_status : intr_status_t := Disable_Intr_Status); function count_intr_attr_init( attr : a_count_semaphore_attr_t; disable_status : intr_status_t := Disable_Intr_Status) return a_count_semaphore_attr_t; function count_intr_attr_init( -- does an implicit -- "attr: a_count_semaphore_attr_t := -- new count_semaphore_attr_t;" disable_status : intr_status_t := Disable_Intr_Status) return a_count_semaphore_attr_t;Mailbox
A mailbox object is used to queue fixed length messages between tasks or between ISRs and tasks. Any task or ISR can write messages to a mailbox object. Any task can read messages from a mailbox. If no message is in the mailbox, the reader can optionally wait until a message is written, return immediately with no message or wait up to a specified amount of time for a message.
Mailboxes are used by the Rational Exec V_Mailboxes services. The overhead added by the Rational Exec layer can be eliminated by directly using the Ada Kernel Layer mailboxes.
Types
- Mailbox_T, A_Mailbox_T
Mailbox_T is the type of a mailbox object. A_Mailbox_T is the access type of a mailbox object. The address of a mailbox object can be converted to its access type via the function, Ada_Krn_Defs.To_A_Mailbox_T.
Attributes
- Mailbox_Attr_T, A_Mailbox_Attr_T
Mailbox_Attr_T is the type definition of the mailbox attributes. A_Mailbox_Attr_T is its access type. The function, Ada_Krn_Defs.To_A_Mailbox_Attr_T can be used to convert the address of the mailbox attributes to its access type.
The A_Mailbox_Attr_T access value is passed to the Rational Exec service, V_Mailboxes.Create_Mailbox.
The mailbox attributes are target kernel dependent. Refer to ada_krn_defs.1.ada in rational.ss for the different options supported. (Rational Exec Microkernel uses a mutex to protect the mailbox. It waits on a condition variable. The Mailbox_Attr_T is a subtype of Mutex_Attr_T. The Cond_Attr_T is derived from the Mutex_Attr_T. A FIFO condition variable is used for a FIFO mutex. A priority condition variable is used for either a priority, priority inheritance or priority ceiling mutex.)
The Rational Exec Microkernel has the following variant mailbox attribute record type:
- Mailbox_Intr_Attr_T
Interrupts are disabled when accessing the mailbox.
The function Default_Mailbox_Attr is provided to select the default mailbox attributes.
To protect mailbox operations by disabling all interrupts, use Default_Mailbox_Intr_Attr. If the underlying microkernel does not support interrupt attributes, the Program_Error exception is raised. However, if the Default_Mailbox_Attr is interrupt safe, Default_Mailbox_Intr_Attr returns Default_Mailbox_Attr and does not raise Program_Error.
Alternatively, the mailbox attributes can be initialized to select the disable interrupts options by using one of the overloaded Mailbox_Intr_Attr_Init subprograms. Refer to Mailbox Support Subprograms, for more information.
The Ada Kernel Layer has the following mailbox services:
function mailbox_init( m : a_mailbox_t; slots_cnt : positive; slot_len : natural; attr : a_mailbox_attr_t) return boolean; -- MAILBOX_Init allocates memory for slots_cnt messages -- where each message has a fixed length of slot_len bytes. -- -- Returns True if mailbox was successfully initialized. procedure mailbox_destroy(m: a_mailbox_t); function mailbox_read(m: a_mailbox_t; msg_addr: address; wait_time: duration) return boolean; -- Reads a message from a mailbox. Returns True if message was -- successfully read. -- -- If no message is available for reading, then returns -- according to the wait_time parameter: -- < 0.0 - returns when message was successfully read. -- This may necessitate suspension of current -- task until another task does mailbox write. -- = 0.0 - returns False immediately. -- > 0.0 - if the mailbox read cannot be completed -- within "wait_time" amount of time, -- returns False. function mailbox_write(m: a_mailbox_t; msg_addr: address) return boolean; -- Writes a message to a mailbox. Returns False if no slot is -- available for writing. function mailbox_get_count(m: a_mailbox_t) return natural; -- Returns number of unread messages in mailbox. function mailbox_get_in_use(m: a_mailbox_t) return boolean; -- Returns True if any task is waiting to read from the mailbox. -- If the Ada Kernel Layer is unable to detect this condition, it -- returns True. -- -- MAILBOX_GET_IN_USE is called by the Rational Exec -- V_MAILBOXES.DELETE_MAILBOX service.Mailbox Support Subprograms
The mailbox attributes can be initialized to select the disable interrupts options by using one of the overloaded Mailbox_Intr_Attr_Init subprograms.
procedure mailbox_intr_attr_init( attr : a_mailbox_attr_t; disable_status : intr_status_t := Disable_Intr_Status); function mailbox_intr_attr_init( attr : a_mailbox_attr_t; disable_status : intr_status_t := Disable_Intr_Status) return a_mailbox_attr_t; function mailbox_intr_attr_init( -- does an implicit -- "attr: a_mailbox_attr_t := -- new mailbox_attr_t;" disable_status : intr_status_t := Disable_Intr_Status) return a_mailbox_attr_t;
Name
Objects or procedures can be named to allow them to be shared across multiple programs.
Supports the Rational Exec V_Names services and the Bind/Resolve services in the Rational Exec V_Mailboxes, V_Mutexes and V_Semaphores packages.
Types
- String
A name can be any arbitrary Ada string.
- Program_Id
Program containing object or subprogram.
- Address
Location of the object or subprogram.
- Name_Bind_Status_T
Status returned by the Name_Bind service.
- Name_Resolve_Status_T
Services
The Ada Kernel Layer has the following name services:
function name_bind( name : string; prg : program_id; addr : address) return name_bind_status_t; -- Bind a name to the program_id and address of a procedure or
-- object. -- -- The name parameter can be any sequence of characters. An exact -- match is done for all name searches. ("MY_NAME" diffs from -- "my_name".) -- -- The prg parameter should be set to NO_PROGRAM_ID if the name -- isn't bound to a particular program or if the current program and -- stack limit switch logic are to be eliminated for an -- ada_krn_i.program_inter_call. All procedures and objects in the -- kernel program are bound with prg implicitly set to -- NO_PROGRAM_ID. -- If successful, name_bind returns ada_krn_defs.1.ada.NAME_BIND_OK. -- Otherwise, it returns one of the following error codes also -- found in ada_krn_defs.1.ada: -- NAME_BIND_NOT_Supported -- NAME_BIND_BAD_ARG -- NAME_BIND_OUT_OF_Memory -- NAME_BIND_ALREADY_BOUND
procedure name_resolve( name : string; wait_time : duration; prg : out program_id; addr : out address; status : out name_resolve_status_t); -- Resolve the name of a procedure or object into its program_id and -- address. -- -- name_resolve first attempts to find an already bound name that -- exactly matches the name parameter. For a match, it returns -- immediately with the prg and addr out parameters updated and -- status set to ada_krn_defs.1.ada.NAME_RESOLVE_OK. Otherwise, it -- returns according to the wait_time parameter: -- < 0.0 - waits indefinitely until the name is bound. -- = 0.0 - returns immediately with status set to -- NAME_RESOLVE_FAILED. -- > 0.0 - if the name isn't bound within "wait_time", -- returns with status set to NAME_RESOLVE_TIMED_OUT. -- -- If name services aren't supported or name_resolve was called with -- a bad argument, then status is set to NAME_RESOLVE_NOT_Supported -- or NAME_RESOLVE_BAD_ARG.Protected Records
An Ada protected object provides synchronization without a separate thread of control. All operations on protected objects are done using the tasking semantics of the Ada language.
Types
- Prot_T, A_Prot_T
An object of type Prot_T exists for each Ada protected object. The Prot_T object represents the runtime state of the corresponding protected object. A_Prot_T is the access type for Prot_T.
Attributes
- Prot_Attr_T, A_Prot_Attr_T
Prot_Attr_T is the type definition of the protected object attributes. A_Prot_Attr_T is its access type. The function A_Krn_Defs.To_A_Prot_Attr_T can be used to convert the address of the protected object attribute record to its access type.
The Prot_Attr_T record can be initialized using the Ada_Krn_Defs.Default_Prot_Attr function. The current release does not provide any means to specify attributes other than the defaults.
Services
Since the Ada protected object services should not be called directly, they are only listed here. Consult ada_krn_i.1.ada in rational.ss for more details.
Protected_Init Protected_Destroy Protected_Mutex_Lock Protected_Mutex_Unlock Protected_Mutex_Reader_Lock Protected_Mutex_Reader_Unlock Protected_Signal Protected_Timed_Wait Protected_Timed_Wait_Until
Rational Software Corporation http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2002, Rational Software Corporation. All rights reserved. |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |