INtime SDK Help
Regions
INtime SDK v6 > About INtime > INtime Kernel > Regions

Overview

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.

Deletion and suspension protection

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.

Priority adjustment

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.

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.

Priority inversions

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:

  1. Thread A is the running thread. It is a low-priority thread with control of a region, accessing some data. The region has a priority queue. The only other thread that uses the data is thread C, a high-priority thread that is not ready to run.
  2. Thread B, a medium-priority thread, becomes ready to run and preempts A.
  3. Thread C becomes ready to run and preempts B. It runs until it tries to gain control of the region. Thread A's priority is raised to equal thread C's priority until thread A releases the region; then its priority returns to its initial level.
  4. When thread A releases the region, thread C receives control of the region and uses the data. When thread C completes, thread B runs.

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.

Deadlocks

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.

Creating a region

The only parameter you specify when creating a region using CreateRtRegion is whether the thread queue is FIFO or priority based.

Thread queue

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.

Deleting a region

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.

Misusing regions

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 the thread cannot wait, it receives a condition code.
  • If the thread waits, it can never run again.

If these are not acceptable, use a semaphore instead.

Nesting regions

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.

  1. Thread A requests and obtains control of region X. It also needs control of region Y.
  2. Thread B preempts thread A. It requests and obtains control of region Y. It also needs control of region X.

Neither thread can run. Neither thread can be deleted. Other threads that try to obtain control of either region also become deadlocked.

Deadlock prevention

There are two ways to prevent deadlock in nested regions:

Region deadlock

  1. Thread A, priority 140, requests and obtains control of region X. It also needs control of region Y.
  2. Thread B, priority 135, preempts thread A. It requests control of region X. Thread A's priority raises to equal B's. Thread B can't obtain control so it enters the thread queue.
  3. Thread A requests and obtains control of region Y.
  4. Thread C, priority 130, preempts thread A. It requests control of region X. Thread A's priority raises to equal C's. Thread C can't obtain control so it enters the thread queue.

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.

System calls

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:

  1. Make these calls from the thread that has the resource that needs to be shared.
  2. Make these calls from the threads that need to obtain control of the region to access the resource.
  3. Make this call to give up control of the region.
  4. Make these calls from the thread that created the region.
See Also