A region is a single-unit semaphore with special suspension, deletion, and priority adjustment features. Regions provide mutual exclusion for resources or data; only one thread may control a region at a time; only the thread in control of the region can access the resource or data protected by a region. Once a thread gains control of a region, the thread cannot be suspended or deleted until it gives up control of the region. When the running thread no longer needs access, it exits the region, which enables a waiting thread to obtain control of the region and thus access the resource or data protected by that region.
Regions have a thread queue where threads wait for access to the region. The queue may be FIFO- or priority-based.
Threads that have control of a region, or are queued at a region, cannot be deleted or suspended by other threads until they give up control of the region.
Threads that control a region cannot be preempted by other threads that want to control the region. A thread can, however, be preempted by a higher-priority thread that does not want to control the region.
If you use a priority-based queue, the priority of the thread that controls the region is dynamically raised whenever the thread at the head of the region's thread queue has a priority higher than that of the controlling thread. The priority of the controlling thread raises to match that of the queued thread. This priority adjustment prevents the priority inversion that can occur when threads use semaphores to get mutual exclusion.
Note: In the default configuration, once a thread's priority is raised in this way, the priority does not lower until the thread gives up control of all regions. It is not sufficient to give up control of the region that raised the priority if the thread still controls another region.
From INtime 7. a new configuration is available which allows a thread's priority to be restored as it exits each region in a chain. To enable this, change the value of "Nested region max depth" in a node's Kernel settings to a value representing the maximum number of regions a thread may acquire. A value of at least 64 is recommended, the maximum permitted value is 127. A value of 0 means that the legacy behavior will be maintained.
Regions also have a priority-inversion avoidance mechanism when the region's thread queue is priority based.
Then, if a higher-priority thread tries to enter a busy region, the priority of the thread in the region is raised temporarily so that it equals the waiting thread's priority. This helps prevent priority-inversion, as shown in this example:
Without the priority inversion avoidance mechanism, thread B would have preempted A while A had control of the region; C would have preempted B, but would have been unable to use the data because A had control of the region.
Regions require careful programming to avoid deadlock, where threads need simultaneous access to resources protected by nested regions, and one thread has control of one region while the other thread has control of another. To avoid deadlock, all threads must access nested regions in the same, arbitrary order, and release them in the same reverse order.
The only parameter you specify when creating a region using CreateRtRegion is whether the thread queue is FIFO or priority based.
Regions maintain a thread queue for threads waiting to receive control. Only priority-based thread queues prevent priority inversion; in general you should use priority-based queues.
Threads of equal priority in a priority-based queue are queued in a FIFO manner.
A thread in the region's thread queue sleeps until the region becomes available. It can wait indefinitely.
When you delete a region using DeleteRtRegion, the INtime kernel awakens any threads waiting for control of a region with an E_EXIST condition code.
A thread cannot delete a region it controls. It first must give up control of the region. Otherwise, an E_CONTEXT condition code returns.
Misuse of regions can corrupt the interaction between threads in an application system. Before writing a program that uses regions, ensure that you have a complete understanding of regions, the OS, and the entire application system. Avoid these region issues:
Problem | Explanation and consequences |
Deadlock | This occurs if two threads need control of two regions for access to the same two resources at the same time and each thread controls one region.
Since no time limit exists for waiting for control, threads can remain deadlocked indefinitely. Other threads that enter the region's thread queue also become deadlocked. For detailed information, see Nesting Regions. |
Deletion immunity | If a thread obtains control of a region, the thread cannot be deleted until it gives up control of the region. If the thread does not give up control, it cannot be deleted. |
No time limit | If control is not immediately available, there are two options:
If these are not acceptable, use a semaphore instead. |
A thread can take control of more than one region at a time. Regions are released in a last-obtained, first-released order. When a thread controls multiple regions, and releases control of one region, the most recently obtained region is released first.
Deadlock occurs with multiple nested regions as shown in the next figure. The example uses WaitForRtControl to gain control of the regions.
Neither thread can run. Neither thread can be deleted. Other threads that try to obtain control of either region also become deadlocked.
There are two ways to prevent deadlock in nested regions:
Thread A runs and then releases region Y, followed by region X. Then, its priority adjusts to its static level, 140. Thread C then wakes up, preempts A, and obtains control of both regions.
If a thread has control of several regions, and multiple threads with different priorities are waiting for the regions, the priority of the controlling thread can be raised more than once. But the controlling thread must surrender control of all the regions it controls before its priority reverts to its original static value.
This lists common operations related to regions and the INtime kernel system calls that do the operations:
To . . . | Use this system call . . . |
---|---|
Create a region object | CreateRtRegion |
Delete a region object | DeleteRtRegion |
Receive ownership of a region object | AcceptRtControl |
Gain ownership of a region | WaitForRtControl |
Release a region object for use by another thread | ReleaseRtControl |
Follow these region rules:
This shows the order to make region system calls and lists calls that regions frequently use: