Semaphores


Many tasks running on a 3DO system can share data structures, storing a structure in one task's memory and allowing one or more outside tasks to read and write to that structure. Because one task using the data structure can never be sure what another task may be doing to the same structure, dangers arise. For example, one task writes to a data structure at the same time that another task writes to it. One task overwrites the data of another, and neither is aware of what happened. To avoid conflicts like this, a task must be able to lock down a shared data structure while it is working on it, and then release the structure when it's done.

To provide a lock, the kernel offers an item called a semaphore, which is defined as an element of a data structure. You can think of the semaphore as an "occupied" sign for a data structure. A polite task checks the semaphore of a data structure before it uses the structure. If the semaphore says that the structure is currently unused, the task can go to work on the structure. If the semaphore says that the structure is in use, the task must either wait until the semaphore says the structure is free or return to execution without using the structure.

To use a data structure with a semaphore, a task makes the function call LockSemaphore() to lock the structure's semaphore. If the semaphore is unlocked, the kernel locks it and the task can proceed with its business, using the semaphored data structure as it sees fit without interference from other polite tasks. When the task is done, it makes another function call, UnlockSemaphore(), to unlock the semaphore, releasing the semaphored data structure for use by other tasks.

When a task calls LockSemaphore(), it specifies what it will do if the semaphore is already locked: wait for the semaphore to be unlocked (putting itself in the wait queue); or return to execution without using the semaphored structure. If the semaphore is locked, the task acts accordingly.

The semaphore is a completely voluntary mechanism; it is what its name implies, only a flag that tells whether a data structure is in use or not. It does not deny write permission to tasks that want to use the data structure without checking the semaphore. If you want to share a data structure with another task, be sure that the other task is written to check for the semaphore before it goes about its business.