4 \f0\froman Times New Roman;
5 \f1\fdecor Courier New;}
11 \red255\green255\blue0;}
20 {\uldb Introduction}{\v intro}
22 {\uldb Initialization}{\v init}
24 {\uldb Mutexes}{\v mutexes}
26 {\uldb ReadWrite Locks}{\v rwlocks}
28 {\uldb Condition Variables}{\v conds}
30 {\uldb Locking Hierarchies}{\v hierarchies}
32 {\uldb Debugging}{\v debug}
38 ${\footnote Introduction}
41 The OSI package provides very efficient locking and synchronization
42 primitives for the Win32 environment.
45 These primitives include both {\uldb mutexes}{\v mutexes}, representing
46 resources that must always be allocated exclusively to one entity
47 (thread) at a time, as well as {\uldb read/write locks}{\v rwlocks},
48 representing resources that may have N readers or one writer at any
52 In addition to the basic primitives sketched above, the OSI package
53 provides a {\uldb condition variable}{\v conds} mechanism that allows a
54 thread holding a mutex or a read/write lock to wait for an interesting
55 event to occur. These condition variable operations allow a thread
56 holding a resource to atomically suspend itself (sleep) and
57 simultaneously release the lock or mutex it holds on the resource. The
58 atomicity of these operations is critical to avoiding race conditions.
59 A function is also provided to wakeup a thread waiting at a condition
63 Some support is also provided for aiding programs in initializing
64 themselves safely in a multi-threaded environment.
67 Finally, an optional remote debugging and statistics gathering interface
68 is provided. If desired, the locks and mutexes provided by the OSI
69 package can keep track of statistics on lock contention, and these
70 statistics are available to remote users to examine, using the osidebug
77 ${\footnote Initialization}
80 There are two sets of routines describe herein, one used for
82 OSI package itself, and one for initializing your application.
84 The function {\uldb osi_Init}{\vosiInit} must be called before any other
85 functions in the OSI library, except for the other initialization
86 functions described in this section (osi_Init, osi_InitDebug, osi_Once
90 The function {\uldb osi_InitDebug} must be called before remote
91 debugging information and statistic can be retrieved via RPC by the
92 osidebug program. This function need not be ever called, however, if
93 you do not need to be able to retrieve locking information from a
97 The function {\uldb osi_Once}{\v osiOnce} can be used by the application
98 programmer to ensure that the application program executes its
99 initialization code exactly once. This function takes one parameter,
100 intended to be allocated as a static variable, which will be initialized
101 by the system at load time to zero. The {\uldb osi_Once}{\v osiOnce}
102 function is called with a pointer to this variable, and returns TRUE if
103 the program should execute its initialization code now, or FALSE if
104 osi_Once has already been executed once in this application already.
107 The function {\uldb osi_EndOnce}{\v osiEndOnce} must be called before
108 other calls to {\uldb osi_Once}{\v osiOnce} will complete; the section
109 of code bounded by osi_Once and osi_EndOnce is executed atomically with
110 respect to other calls to osi_Once.
113 The function {\uldb osi_TestOnce}{\v osiTestOnce} may be used as a hint
114 to see if {\uldb osi_Once}{\v osiOnce} might need to be called. It
115 returns the same values as osi_Once, but doesn't change the state of the
116 state variable to indicate that {\uldb osi_Once}{\v osiOnce} has been
117 called. Of course, its result can only be used as a hint, but if {\uldb
118 osi_TestOnce}{\v osiTestOnce} returns false, the caller knows that the
119 initialization work for this code has already run. If it returns true,
120 the programmer may still need to call osi_Once, or it may be called by
121 some other thread first.
127 ${\footnote osi_Init}
128 K{\footnote osi_Init}
132 void \cf2 osi_Init\cf0 (void)
136 This function initializes the OSI library. It must be called before any
137 other functions in the OSI library except the other initialization
138 calls: osi_InitDebug, osi_Once, osi_EndOnce and osi_TestOnce.
141 Failure to call this function will result in traps in your application
147 #{\footnote osiInitDebug}
148 ${\footnote osi_InitDebug}
149 K{\footnote osi_InitDebug}
153 long \cf2 osi_InitDebug \cf0 (char *rpcName)
157 This function initializes the RDC debugging interface in your
158 application. The parameter rpcName is an RPC NSI name into which your
159 RPC binding information will be exported. It must start with the string
160 "/.:/" For example, a database server for your payroll database might
161 export its binding information into "/.:/payroll"
164 The function returns 0 if it succeeds, otherwise it returns an RPC error
171 ${\footnote osi_Once}
172 K{\footnote osi_Once}
176 int \cf2 osi_Once \cf0 (osi_once_t *parm)
180 This function can be used by application programs in a multi-threaded
181 environment to ensure that they execute their initialization code
182 exactly once, no matter how many threads try to execute the code.
185 int foo_Init(void) \line
187 static osi_once_t once; \line
188 if (osi_Once(&once)) \{ \line
189 YourInitializationHere = 1; \line
190 osi_EndOnce(&once); \line
192 return SUCCESS; \line
197 In the above function, the assignment into YourInitializationHere will
198 occur exactly once, no matter how many times foo_Init is called, in any
199 number of threads, all calling foo_Init concurrently.
203 #{\footnote osiEndOnce}
204 ${\footnote osi_EndOnce}
205 K{\footnote osi_EndOnce}
209 void \cf2 osi_EndOnce \cf0 (osi_once_t *parm)
213 This function ends the initialization block started by osi_Once. This
214 function must be called exactly once for each call to osi_Once that
217 An example of the use of this function can be found in the description
218 of {\uldb osi_Once}{\v osiOnce}.
222 #{\footnote osiTestOnce}
223 ${\footnote osi_TestOnce}
224 K{\footnote osi_TestOnce}
228 int \cf2 osi_TestOnce \cf0 (osi_once_t *parm)
232 This function returns true if osi_Once would have returned true, and
236 Unlike osi_Once, this function does not mark the initialization block
237 described by *parm as initialized; this is only an advisory function.
238 For this reason, the function {\uldb osi_EndOnce}{\v osiEndOnce} should
239 not be called if osi_TestOnce returns true.
244 ${\footnote Mutual Exclusion Objects}
245 +{\footnote mutexes:01}
247 Mutual exclusion objects are used to prevent two threads from accesing
248 the same object at the same time. Typically, some collection of data
249 is associated with an object of osi_mutex_t, and any thread, before
250 accessing the object, first obtains the mutex by calling {\uldb
251 lock_ObtainMutex}{\v lockObtainMutex}. When it is done processing the
252 object, the thread calls {\uldb lock_ReleaseMutex}{\v lockReleaseMutex}.
255 Typically, a thread will release a mutex once for each time that it
256 obtains the mutex, using {\uldb osi_SleepM}{\v osiSleepM} or
257 {\uldb lock_ReleaseMutex}{\v lockReleaseMutex}.
260 These mutex objects are not recursive mutexes: a thread may not
261 re-obtain the mutex while still holding it.
264 Before using a mutex, the mutex \cf1 must \cf0 be initialized by calling
265 {\uldb lock_InitializeMutex}{\v lockInitializeMutex}.
268 If the mutex is allocated from dynamically allocated memory (rather than
269 being statically allocated), then the mutex must be finalized before
270 the memory is freed. The function
271 {\uldb lock_FinalizeMutex}{\v lockFinalizeMutex} should be used for this
275 An object of type osi_mutex_t uses about 8 bytes of storage.
280 #{\footnote lockInitializeMutex}
281 ${\footnote lock_InitializeMutex}
282 K{\footnote lock_InitializeMutex}
283 +{\footnote mutexes:02}
286 void \cf2 lock_InitializeMutex \cf0 (osi_mutex_t *mutex)
290 This function is called with a pointer to a mutex, to initialize the storage
291 so that the mutex can be obtained and released by this or other threads.
292 This function should only be called at an initialization point where the
293 programmer knows that no other threads are accessing the mutex variable.
298 #{\footnote lockObtainMutex}
299 ${\footnote lock_ObtainMutex}
300 K{\footnote lock_ObtainMutex}
301 +{\footnote mutexes:03}
304 void \cf2 lock_ObtainMutex \cf0 (osi_mutex_t *mutex)
308 This function is called with a pointer to a mutex,
309 and waits until no other thread is using the mutex. It then
310 obtains the mutex for the calling thread and returns.
313 Mutexes are not recursively obtainable by a thread: if a thread tries
314 to obtain a mutex a second time, it will deadlock (wait forever).
317 The mutex can be released {\uldb lock_ReleaseMutex}{\v lockReleaseMutex}
318 or by {\uldb osi_SleepM}{\v osiSleepM}.
323 #{\footnote lockReleaseMutex}
324 ${\footnote lock_ReleaseMutex}
325 K{\footnote lock_ReleaseMutex}
326 +{\footnote mutexes:04}
329 void \cf2 lock_ReleaseMutex \cf0 (osi_mutex_t *mutex)
333 This function relinquishes the caller's use of the resource; if any other threads
334 are waiting for the mutex, they are woken at this point, and one of the other
335 threads is given the mutex.
338 It is an error to release a mutex twice. However, a mutex can be released by a different
339 thread than that which obtained it, as long as this is the programmer's intention.
344 #{\footnote lockFinalizeMutex}
345 ${\footnote lock_FinalizeMutex}
346 K{\footnote lock_FinalizeMutex}
347 +{\footnote mutexes:05}
350 void \cf2 lock_FinalizeMutex \cf0 (osi_mutex_t *mutex)
354 This function is used to free up any auxiliary storage and control structures
355 associated with a mutex. In the current implementation, this function does nothing
356 except when running with the statistics gathering implementation of mutexes, but
357 this is not guaranteed to stay true in later releases of the OSI library. Furthermore,
358 anyone can enable statistics gathering.
361 Locks and mutexes need not be finalized if the process is about to terminate, since any
362 resources allocated are allocated on behalf of the process, and will be freed when
367 #{\footnote lockTryMutex}
368 ${\footnote lock_TryMutex}
369 K{\footnote lock_TryMutex}
370 +{\footnote mutexes:06}
373 int \cf2 lock_TryMutex \cf0 (osi_mutex_t *mutexp)
377 This function is a non-blocking version of {\uldb lock_ObtainMutex}{\v lockObtainMutex}.
378 It tries to obtain the specified mutex, and if it succeeds, it returns 1. Otherwise,
379 instead of blocking and waiting until the mutex is available, it returns 0 and leaves
383 This function is typically used when the programmer needs to obtain locks in an order
384 incompatible with their locking hierarchy. See the section on {\uldb locking hierarchies}
385 {\v hierarchies} for an example of its use for this purpose.
388 The caller must be careful to release the mutex if and only if the function returns 1.
394 ${\footnote Read/Write Locks}
395 +{\footnote rwlocks:01}
397 Read/write locks are similar in use to mutexes. They are used to mediate access to
398 data structures that are accessed by multiple threads.
401 Unlike {\uldb mutexes}{\v mutexes}, however, read/write locks mediate two forms of access
402 to the structures: read accesses, of which several can be executing concurrently, and write
403 accesses, only one of which can be executing at any given time.
406 Like mutexes, read/write locks \cf1 must \cf0 be initialized before they can be used, and need
407 to be finalized when their storage is going to be freed. The procedures
408 {\uldb lock_InitializeRWLock}{\v lockInitializeRWLock} and
409 {\uldb lock_FinalizeRWLock}{\v lockFinalizeRWLock} perform these functions.
413 #{\footnote lockInitializeRWLock}
414 ${\footnote lock_InitializeRWLock}
415 K{\footnote lock_InitializeRWLock}
416 +{\footnote rwlocks:02}
419 void \cf2 lock_InitializeRWLock \cf0 (osi_rwlock_t *lockp)
423 This function initializes the storage used by a read/write lock. The structure
424 \cf1 must \cf0 be initialized before it is obtained or released by the functions
425 described in this section.
430 #{\footnote lockObtainRead}
431 ${\footnote lock_ObtainRead}
432 K{\footnote lock_ObtainRead}
433 +{\footnote rwlocks:03}
436 void \cf2 lock_ObtainRead \cf0 (osi_rwlock_t *lockp)
440 This function obtains a read/write lock for reading. The lock must have been
441 previously initialized with {\uldb lock_InitializeRWLock}{\v lockInitializeRWLock}.
444 When done with the lock, the programmer must ensure that the function
445 {\uldb lock_ReleaseRead}{\v lockReleaseRead} or
446 {\uldb osi_SleepR}{\v osiSleepR} is called to release the lock.
450 #{\footnote lockObtainWrite}
451 ${\footnote lock_ObtainWrite}
452 K{\footnote lock_ObtainWrite}
453 +{\footnote rwlocks:04}
456 void \cf2 lock_ObtainWrite \cf0 (osi_rwlock_t *lockp)
460 This function obtains a read/write lock for writing. The lock must have been
461 previously initialized with {\uldb lock_InitializeRWLock}{\v lockInitializeRWLock}.
464 At most one thread can have a read/write lock held for writing at any time, and
465 no thread can simultaneously have a read/write lock held for reading at that time.
468 When done with the lock, the programmer must ensure that the function
469 {\uldb lock_ReleaseWrite}{\v lockReleaseWrite} or
470 {\uldb osi_SleepW}{\v osiSleepW} is called to release the lock.
474 #{\footnote lockReleaseRead}
475 ${\footnote lock_ReleaseRead}
476 K{\footnote lock_ReleaseRead}
477 +{\footnote rwlocks:05}
480 void \cf2 lock_ReadRead\cf0 (osi_rwlock_t *lockp)
484 This function releases a lock held in read mode. If the number of readers
485 drops to zero, a writer may obtain the lock, otherwise only readers may
486 obtain the lock. If any writers are waiting for this lock, they are woken
487 up and may proceed at this time.
490 The application program must have obtained this lock in read mode before calling
491 this function; it is an error to release a read lock more often than it was
497 #{\footnote lockReleaseWrite}
498 ${\footnote lock_ReleaseWrite}
499 K{\footnote lock_ReleaseWrite}
500 +{\footnote rwlocks:06}
503 void \cf2 lock_ReleaseWrite\cf0 (osi_rwlock_t *lockp)
507 This function releases a lock held in write mode. After this call,
508 anyone waiting for a read lock or a write lock is woken up and may
512 The application program must have obtained this lock in read mode before calling
513 this function; it is an error to release a read lock more often than it was
519 #{\footnote lockFinalizeRWLock}
520 ${\footnote lock_FinalizeRWLock}
521 K{\footnote lock_FinalizeRWLock}
522 +{\footnote rwlocks:07}
525 void \cf2 lock_FinalizeRWLock \cf0 (osi_rwlock_t *lockp)
529 This function is called to free up any auxiliary data structures associated with
530 the read/write lock. This function \cf1 must \cf0 be called before freeing any
531 storage containing a read/write lock. This function must be called at a time when
532 there are no threads holding or waiting for the lock concerned.
535 Locks allocated from static storage need never be finalized.
540 #{\footnote lockTryRead}
541 ${\footnote lock_TryRead}
542 K{\footnote lock_TryRead}
543 +{\footnote rwlocks:08}
546 int \cf2 lock_TryRead\cf0 (osi_rwlock_t *rwlockp)
550 This function is a non-blocking version of {\uldb lock_ObtainRead}{\v
551 lockObtainRead}. It tries to obtain the specified read/write lock in
552 read mode, and if it succeeds, it returns 1. Otherwise, instead of
553 blocking and waiting until the lock is available, it returns 0 and
554 leaves the lock unchanged.
557 This function is typically used when the programmer needs to obtain locks in an order
558 incompatible with their locking hierarchy. See the section on {\uldb locking hierarchies}
559 {\v hierarchies} for an example of its use for this purpose.
562 The caller must be careful to release the read lock if and only if the function returns 1.
567 #{\footnote lockTryWrite}
568 ${\footnote lock_TryWrite}
569 K{\footnote lock_TryWrite}
570 +{\footnote rwlocks:09}
573 int \cf2 lock_TryWrite\cf0 (osi_rwlock_t *rwlockp)
577 This function is a non-blocking version of {\uldb lock_ObtainWrite}{\v
578 lockObtainWrite}. It tries to obtain the specified read/write lock in
579 write mode, and if it succeeds, it returns 1. Otherwise, instead of
580 blocking and waiting until the lock is available, it returns 0 and
581 leaves the lock unchanged.
584 This function is typically used when the programmer needs to obtain locks in an order
585 incompatible with their locking hierarchy. See the section on {\uldb locking hierarchies}
586 {\v hierarchies} for an example of its use for this purpose.
589 The caller must be careful to release the write lock if and only if the function returns 1.
595 ${\footnote Condition Variables}
596 +{\footnote conds:01}
598 Condition variables are used to allow a threaded program to wait for an interesting
602 Condition variables are represented as long integers. By convention, these long
603 integers are cast from addresses of mnemonic structures (so that, when waiting for a
604 particular structure, foo, to change state, you might sleep on "(long)&foo"), but
605 the sleep functions do not change any storage at the address named by the condition variable,
606 and indeed, condition variable integers can really be any numbers you desire.
609 The basic idea is that a thread that wants to wait for a particular event
610 waits for a condition variable by calling \f1 osi_Sleep \f0 with the condition variable
611 as a parameter, which blocks the calling thread. When the interesting event occurs,
612 the thread that notices the event calls \f1 osi_Wakeup \f0, waking up \cf1 all\cf0
613 threads sleeping on that condition variable.
616 Unfortunately, condition variables as described so far are unusable in most cases, due to
617 a race condition that occurs in their typical uses. Here's an example: assume that there
618 is a structure that represents a buffer of data. Some threads read from the buffer, waiting
619 until there is data available, and others add data to the buffer, waiting until there is
620 space available. The structure, read and write calls might be coded like this:
625 #define BSIZE 100 /* buffer size */\line
627 typedef struct buffer \{\line
628 char data[BSIZE]; /* buffer */\line
629 int nbytes; /* bytes used in the buffer */\line
630 osi_mutex_t mutex; /* mutex for synchronizing access */\line
631 BOOL readWaiting; /* true if someone is waiting for data */\line
632 BOOL writeWaiting; /* true if someone is waiting for space */\line
636 int Read(buffer_t *bp, char *data)\line
638 long bytesRead; \line
641 lock_ObtainMutex(&bp->mutex);\line
642 if (nbytes == 0) \{ /* no data available */\line
643 readWaiting = 1;\line
644 /* wait for something interesting */\line
645 lock_ReleaseMutex(&bp->mutex); /*BUG*/\line
646 osi_Sleep((long) &bp->readWaiting); /*BUG*/\line
650 memcpy(bp->data, data, bp->nbytes);\line
651 nbytes = bp->nbytes; /* remember for later */ \line
652 bp->nbytes = 0; \line
654 /* now wakeup anyone waiting for space */ \line
655 if (bp->writeWaiting) \{ \line
656 bp->writeWaiting = 0; \line
657 osi_Wakeup((long) &bp->writeWaiting); \line
660 /* and we're done, so return # of bytes read */ \line
661 lock_ReleaseMutex(&bp->mutex);\line
667 void Write(buffer_t *bp, char *data, int len) \line
670 lock_ObtainMutex(&bp->mutex); \line
671 if (len > BSIZE-bp->nbytes) \{ \line
672 /* no space available */\line
673 writeWaiting = 1;\line
674 /* wait for something interesting */\line
675 lock_ReleaseMutex(&bp->mutex); /*BUG*/ \line
676 osi_Sleep((long) &bp->writeWaiting); /*BUG*/ \line
680 memcpy(data, bp->data+bp->nbytes, len);\line
681 bp->nbytes += len; \line
683 /* now wakeup anyone waiting for data */ \line
684 if (bp->readWaiting) \{ \line
685 bp->readWaiting = 0; \line
686 osi_Wakeup((long) &bp->readWaiting); \line
689 /* and we're done, so return # of bytes read */ \line
690 lock_ReleaseMutex(&bp->mutex);\line
697 There are a number of things to note in the above example. First, note our use of
698 memory addresses as condition variables. The calls to {\uldb osi_Sleep}{\v osiSleep} and
699 {\uldb osi_Wakeup}{\v osiWakeup} do not change the data at bp->readWaiting or bp->writeWaiting,
700 but the call \f1 osi_Wakeup((long) &bp->readWaiting)\f0 only wakes up the thread sleeping
701 in the call \f1 osi_Sleep((long) &bp->readWaiting)\f0, not
702 \f1 osi_Sleep((long) &bp->writeWaiting) \f0.
705 Please also note that accesses by multiple threads to this buffer structure are mediated
706 by a mutex structure stored in the buffer itself. Whenever either \f1 Read\f0 or \f1 Write\f0
707 block waiting for the other to supply/remove data, they of course must release the mutex
708 so that the other thread can access the structure to supply/remove the data.
711 Unfortunately, there is also a bug in the above code: consider the case
712 where the \f1 Read\f0 call is interrupted due to a clock interrupt
713 between the time that a thread releases the mutex and the time that
714 the thread then calls \f1 osi_Sleep\f0. Assume that the OS does a context switch
715 to a new thread, that calls \f1 Write\f0, and runs through completely, doing the call
716 to \f1 osi_Wakeup\f0. The OS then switches back to the thread doing the read,
717 and the thread proceeds and calls \f1 osi_Sleep\f0, even though there is data now waiting.
718 Unfortunately, no one is going to wake us up to notice that there is data available now.
721 This problem would be solved if it were impossible for a wakeup call to execute between
722 the time that the mutex was released and the time that the thread blocked in \f1 osi_Sleep\f0.
723 This combination of releasing a lock or a mutex and sleeping on a condition variable is provided
724 by three functions, {\uldb osi_SleepM}{\v osiSleepM}, {\uldb osi_SleepR}{\v osiSleepR} and
725 {\uldb osi_SleepW}{\v osiSleepW}, which atomically sleep and release a mutex, read lock and
726 write lock, respectively.
729 Thus, the two pairs of lines in the example source above that are labelled with
730 \f1 /*BUG*/\f0 should
731 be replaced by \f1 osi_SleepM((long) &bp->readWaiting, &bp->mutex) \f0 and
732 \f1 osi_SleepM((long) &bp->writeWaiting, &bp->mutex)\f0 , respectively.
734 Indeed, almost every use of \f1 osi_Sleep\f0 instead of one of the combination routines described
735 above is incorrect, and has a race condition between the last release of a lock or mutex, and
736 the call to \f1 osi_Sleep\f0. So, please be careful when using \f1 osi_Sleep\f0 to be sure
737 to check for this condition.
742 #{\footnote osiSleepM}
743 ${\footnote osi_SleepM}
744 K{\footnote osi_SleepM}
745 +{\footnote conds:02}
749 void \cf2 osi_SleepM\cf0 (long sleepValue, osi_mutex_t *mutex)
754 This function atomically sleeps at \f1 sleepValue\f0 and releases the mutex at
755 \f1 mutex\f0. Atomically in this case means that no \f1 osi_Wakeup\f0 calls will
757 before the lock is released until after the thread is asleep.
760 The programmer must \cf1 always\cf0 be prepared for rare, spontaneous wakeups from
761 any of the \f1 osi_Sleep\f0 family of functions. Thus, any use of \f1 osi_SleepM\f0
762 should be contained within a \f1 while \f0 loop that rechecks the appropriate condition
763 that the thread is waiting for, and tries sleeping again if the wakeup was a spurious one.
768 #{\footnote osiSleepR}
769 ${\footnote osi_SleepR}
770 K{\footnote osi_SleepR}
771 +{\footnote conds:03}
775 void \cf2 osi_SleepR\cf0 (long sleepValue, osi_rwlock_t *lockp)
780 This function atomically sleeps at \f1 sleepValue\f0 and releases the read lock at
781 \f1 lockp\f0. Atomically in this case means that no \f1 osi_Wakeup\f0 calls will
783 before the lock is released until after the thread is asleep.
786 The programmer must \cf1 always\cf0 be prepared for rare, spontaneous wakeups from
787 any of the \f1 osi_Sleep\f0 family of functions. Thus, any use of \f1 osi_SleepR\f0
788 should be contained within a \f1 while \f0 loop that rechecks the appropriate condition
789 that the thread is waiting for, and tries sleeping again if the wakeup was a spurious one.
794 #{\footnote osiSleepW}
795 ${\footnote osi_SleepW}
796 K{\footnote osi_SleepW}
797 +{\footnote conds:04}
801 void \cf2 osi_SleepW\cf0 (long sleepValue, osi_rwlock_t *lockp)
806 This function atomically sleeps at \f1 sleepValue\f0 and releases the write lock at
807 \f1 lockp\f0. Atomically in this case means that no \f1 osi_Wakeup\f0 calls will
809 before the lock is released until after the thread is asleep.
812 The programmer must \cf1 always\cf0 be prepared for rare, spontaneous wakeups from
813 any of the \f1 osi_Sleep\f0 family of functions. Thus, any use of \f1 osi_SleepW\f0
814 should be contained within a \f1 while \f0 loop that rechecks the appropriate condition
815 that the thread is waiting for, and tries sleeping again if the wakeup was a spurious one.
820 #{\footnote osiSleep}
821 ${\footnote osi_Sleep}
822 K{\footnote osi_Sleep}
823 +{\footnote conds:05}
827 void \cf2 osi_Sleep\cf0 (long sleepValue)
832 This function sleeps at \f1 sleepValue\f0. The thread will not resume execution until
833 after another thread later executes a call to \f1 osi_Wakeup\f0 with the same value
834 for \f1 sleepValue\f0.
837 The programmer must \cf1 always\cf0 be prepared for rare, spontaneous wakeups from
838 any of the \f1 osi_Sleep\f0 family of functions. Thus, any use of \f1 osi_Sleep\f0
839 should be contained within a \f1 while \f0 loop that rechecks the appropriate condition
840 that the thread is waiting for, and tries sleeping again if the wakeup was a spurious one.
843 Also remember that almost every use of this function when waiting for a change in data protected
844 by a mutex or read/write lock is incorrect, and you probably should be using one of
845 {\uldb osi_SleepM}{\v osiSleepM},
846 {\uldb osi_SleepR}{\v osiSleepR},
847 or {\uldb osi_SleepW}{\v osiSleepW} to simultaneously release the data protection lock and
852 #{\footnote osiWakeup}
853 ${\footnote osi_Wakeup}
854 K{\footnote osi_Wakeup}
855 +{\footnote conds:06}
859 void \cf2 osi_Wakeup\cf0 (long sleepValue)
864 This function wakes up all threads already sleeping at \f1 sleepValue\f0. Threads sleep
865 by calling {\uldb osi_Sleep}{\v osiSleep},
866 {\uldb osi_SleepM}{\v osiSleepM},
867 {\uldb osi_SleepR}{\v osiSleepR},
868 or {\uldb osi_SleepW}{\v osiSleepW}.
871 This call will synchronize appropriately with
872 {\uldb osi_SleepM}{\v osiSleepM},
873 {\uldb osi_SleepR}{\v osiSleepR},
874 and {\uldb osi_SleepW}{\v osiSleepW}, so that if it is called while the corresponding lock
875 or mutex is held, the \f1 osi_Wakeup\f0 function won't execute until after the thread sleeping
876 on the condition variable is blocked. This avoid race conditions of the form described in
877 the section on {\uldb condition variables}{\v conds}.
882 #{\footnote hierarchies}
883 ${\footnote Locking Hierarchies}
886 Whenever a thread obtains more than one lock at a time, there is a
887 possibility of deadlock if the locks are obtained in the wrong order.
888 For example, imagine a situation where there are two threads, numbered
889 1 and 2, and two locks, named A and B. If thread 1 tries to obtain
890 lock A first and then lock B, while thread 2 tries to lock B and then
891 lock A, these two threads will, on occasion, deadlock.
894 Specifically, what can happen is that thread 1 can obtain lock A, and
895 then lose the processor to thread 2, which then goes on to obtain lock
896 B. Thread 2, after obtaining lock B, tries to obtain lock A, and
897 blocks, since thread 1 already holds this lock. Eventually, thread 1
898 runs again, and tries to obtain lock B, but this lock is held (by
899 thread 2), and so thread 1 blocks, still holding lock A. This is a
900 classical case of a deadlock, or deadly embrace.
903 The heart of the problem is that two locks are obtained at the same
904 time, but in different orders by different threads. And so, this
905 problem can be solved in several different ways, some of which will be
908 The easiest way to solve this problem is to have a global locking order,
909 and have all threads lock their locks in this ordering. It is of course
910 imperative to come up with a reasonable locking hierarchy (ordering) to
911 make this as easy as possible. This solution is particularly good to
912 use when dealing with several locks in the same module or package, since
913 all of the locks can be understood by one programmer. Among locks held
914 by separate modules, as long as there is a standard ordering in which modules
915 call one another, so that for example module foo always calls module bar, while
916 module bar never calls module foo, the locking hierarchy within the individual
917 modules will naturally extend to the set of all modules.
920 Sometimes getting a simple locking hierarchy is difficult to do,
921 however. When establishing a good locking hierarchy is difficult or
922 impossible, another possibility is releasing one lock when obtaining
923 another lock. In the example above, thread 1 might grab lock A, do some
924 work, drop lock A and obtain lock B, do more work, and then drop lock B
925 and grab lock A. Since it never holds two locks at once, it avoids the
926 deadlock. However, when it grabs lock A for a second time, it must be
927 prepared to see changes made to the structures protected by lock A,
928 since for a time lock A was not held. Furthermore, if lock A was a
929 write lock or a mutex, we also must examine all other threads that might
930 have seen the data structure protected by lock A in the state after we
931 released the lock A the first time. We must ensure that they view the
932 state they might see as a consistent state, and are prepared to deal
933 with the structures in that state.
936 Finally, another choice we have is to use the \f1 lock_TryRead\f0 and similar functions.
937 Since the trylock functions don't block, we can use them safely to
938 obtain the second through Nth locks in a series. For example, the sequence:
942 lock_ObtainWrite(&lockB); \line
943 lock_ObtainWrite(&lockA); \line
947 can be replaced by this:
952 lock_ObtainWrite(&lockB); \line
953 if (lock_TryWrite(&lockA)) break; \line
955 /* otherwise we failed to get lock A, so camp on it \line
958 lock_ReleaseWrite(&lockB); \line
959 lock_ObtainWrite(&lockA); \line
961 /* once we get here, we've gotten lock A. Hopefully \line
962 * lock B is now available, too. Let's quickly drop \line
963 * this guy and try again. \line
965 lock_ReleaseWrite(&lockA); \line
968 /* when we get here, we have locked B and then A without having \line
969 * released B while obtaining A (in the last iteration). \line
974 Clearly the second piece of code is considerably more complex, but it does give
975 the programmer the ability to lock locks out of order, and do computations based on
976 the information seen under those locks. All modifications, of course, must be delayed
977 until all of the locks have been obtained at the exit of the big while loop, but that is
978 usually not a significant restriction.
984 ${\footnote Debugging and Profiling}
985 +{\footnote debug:01}
987 The state of any instance of the OSI package can be examined remotely by the
988 osidebug program, if the programmer so chooses. In order to export the basic information,
989 which consists of information on the thread IDs and sleep values for threads blocked in
990 one of the \f1 osi_Sleep\f0 functions, or blocked waiting for a lock. The sleep value
991 of a thread waiting for a lock is the address of the lock.
994 Furthermore, if lock statistics gathering has been enabled by calling
995 {\uldb osi_LockTypeSetDefault}{\v osiLockTypeSetDefault} before initializing some locks,
996 then statistics are gathered on those locks, and the osidebug program will report those
1000 To access any information remotely, the function
1001 {\uldb osi_InitDebug}{\v osiInitDebug} must be called. If this is not done, then
1002 the osidebug program will simply fail to bind to the application program.
1005 If the system deadlocks, enough information may be available from osidebug's output to
1006 enable the programmer to figure out what is wrong with the application program without
1007 resorting to a debugger on the target machine; this is especially convenient when debugging
1008 problems from a remote machine.
1011 More detailed information on osidebug can be obtained from that program's help menu.
1016 #{\footnote osilocktypesetdefault}
1017 ${\footnote osi_LockTypeSetDefault}
1018 K{\footnote osi_LockTypeSetDefault}
1019 +{\footnote debug:02}
1023 int \cf2 osi_LockTypeSetDefault\cf0 (char *name)
1028 This function takes a name of a lock type and sets a global state variable controlling
1029 the type of lock initialized by \f1 lock_InitializeMutex\f0 and \f1 lock_InitializeRWLock\f0 .
1030 Normally, when a lock initialization function is called, it creates a lock of a specific
1031 type, currently, a regular lock or mutex, or a statistics-gathering lock or mutex. Which
1032 type is created is determined by this global variable.
1035 If the name is "stat", then statistics gathering locks and mutexes will be created. If the
1036 type name is passed in as a NULL pointer, regular, non-statistics gathering lock and mutexes
1040 Since this is a global variable, it controls the type of lock and mutex created by all threads
1041 henceforth in this process.
1044 Note that it does not matter what the state of default lock type is when you are gathering
1046 \cf1 All that matter is the type of default lock at the time the locks are initialized. \cf0
1049 The system initializes itself creating regular locks and mutexes; this function must be
1050 used to enable statistics gathering, and it must be called \cf1 before\cf0 the
1051 calls to \f1 lock_InitializeMutex\f0 and \f1 lock_InitializeRWLock\f0 are done that
1052 initialize the locks whose statistics are to be gathered. After the locks have been
1053 initialized, this variable may even be reset, and the initialized locks will continue
1054 to gather statistics.