|
|
1.1 root 1: #define _DDI_DKI 1
2: #define _SYSV4 1
3:
4:
5: /*
6: * System V DDI/DKI compatible synchronisation functions
7: *
8: * This implements the synchronisation functions introduced in the System V
9: * DDI/DKI multiprocessor edition for a simple uniprocessor. The locking
10: * implementations given here are totally unsuitable for multiprocessor use.
11: *
12: * Some good multiprocessor lock algorithms can be found in:
13: * "Synchronisation Without Contention"
14: * John M. Mellor-Crummey & Michael L. Scott,
15: * Proceedings 4th International Conference on Architectural Support for
16: * Programming Languages and Operating Systems (ASPLOS 4)
17: * 1991, ACM
18: */
19:
20: /*
21: *-IMPORTS:
22: * <common/ccompat.h>
23: * __CONST__
24: * __USE_PROTO__
25: * __ARGS ()
26: * <common/xdebug.h>
27: * __LOCAL__
28: * <kernel/x86lock.h>
29: * atomic_uchar_t
30: * atomic_ushort_t
31: * __atomic_uchar_t
32: * ATOMIC_TEST_AND_SET_UCHAR ()
33: * ATOMIC_FETCH_AND_STORE_USHORT ();
34: * ATOMIC_FETCH_UCHAR ();
35: * ATOMIC_FETCH_USHORT ();
36: * ATOMIC_CLEAR_UCHAR ();
37: * ATOMIC_CLEAR_USHORT ();
38: * <kernel/ddi_cpu.h>
39: * ASSERT_BASE_LEVEL ();
40: * ddi_cpu_data ()
41: * <kernel/v_proc.h>
42: * plist_t
43: * PROCESS_WOKEN
44: * PROCESS_SIGNALLED
45: * MAKE_SLEEPING ()
46: * WAKE_ONE ()
47: * WAKE_ALL ()
48: * PROC_HANDLE ()
49: * <sys/debug.h>
50: * ASSERT ()
51: * <sys/types.h>
52: * pl_t
53: * uchar_t
54: * uint_t
55: * <sys/inline.h>
56: * splhi ()
57: * splx ()
58: * splcmp ()
59: * <sys/cmn_err.h>
60: * cmn_err ()
61: * <sys/kmem.h>
62: * KM_SLEEP
63: * KM_NOSLEEP
64: */
65:
66: #include <common/ccompat.h>
67: #include <kernel/ddi_cpu.h>
68: #include <kernel/ddi_lock.h>
69: #include <kernel/v_proc.h>
70: #include <sys/debug.h>
71: #include <sys/types.h>
72: #include <sys/inline.h>
73: #include <sys/cmn_err.h>
74: #include <sys/kmem.h>
75:
76: #include <sys/ksynch.h>
77:
78:
79: /*
80: * The actual content definitions of the following data structures has been
81: * kept totally private to this file in order to reduce the temptation of
82: * allocating or accessing the definitions in other subsystems.
83: *
84: * Note that for efficiency considerations it might eventually become
85: * necessary to export these definitions elsewhere to allow locks to be
86: * statically defined (to break dependencies) or incorporated directly as
87: * members of other data structures (to reduce allocation overheads).
88: * (Of course, that means we have to define ...._INIT () routines).
89: *
90: * For now, we'll try very very hard to resist the temptation to optimize
91: * too early and violate our encapsulation.
92: */
93:
94: /*
95: * Configuration issue: DDI/DKI sleep locks don't really map well onto any
96: * old-style Unix kernel functionality, nor does the "wake one" feature of
97: * DDI/DKI synchronization variables. Sleep locks and synchronization
98: * variables need to interface intimately with the kernel scheduling services
99: * (in ways that were usually not anticipated by the original authors of those
100: * services). This requires us to confront some key aspects of the difference
101: * between the old and new styles to discover why we really *need* to
102: * introduce a different way of doing things.
103: *
104: * Some features of the old sleep ()/wakeup () model:
105: * a) These functions correspond exactly to the SV_WAIT[_SIG] () and
106: * SV_BROADCAST () functions in the DDI/DKI, except that they do not
107: * incorporate the basic-lock functionality of SV_WAIT[_SIG] ().
108: *
109: * b) Whether sleep was interruptible or not was related to the
110: * "priority" indication passed to SV_WAIT[_SIG] () rather than being
111: * orthogonal issue. This need not be vital, except that the
112: * "priority" for sleep ()/wakeup () calls was expressed in magic,
113: * highly implementation-dependent numbers. [*]
114: *
115: * c) On many systems, if sleep () was interrupted by a signal the result
116: * was that the sleep was aborted by a non-local return. This is not
117: * necessarily a problem *if* the caller was allowed to form a chain
118: * of handlers to provide unwind-protection facilities. Sadly, this
119: * is usually not the case.
120: *
121: * d) The ability to awaken only *one* process at a time was not
122: * considered an issue; firstly, because contention was normally only
123: * associated with actions involving long delay, such as I/O, and
124: * because processes could only be run sequentially anyway. In other
125: * words, even if contention happened, the fact that after a wakeup ()
126: * processes were run one at a time meant that often by the time a
127: * process was run after a wakeup () the lock had been acquired *and*
128: * released by any process with higher priority.
129: *
130: * [*] For instance, I have no idea what the three (!) different numbers that
131: * have to be passed to a sleep () call in Coherent really do. There is no
132: * internal documentation in the kernel source that clearly explicates the
133: * roles that each number plays, nor what effect it has on the overall picture
134: * of process scheduling.
135: *
136: * Each of features requires modification to the sleep ()/wakeup () model, as
137: * outlined below:
138: * a) In a uniprocessor kernel, sleep ()/wakeup () could function without
139: * basic locks since the caller could gain equivalent protection by
140: * simply manipulating the interrupt priority level, which would be
141: * reset during the course of the dispatch process after the caller
142: * had been safely put to sleep. In a multiprocessor, an unlock call
143: * occuring *during* a call to sleep () might occur before the
144: * process status had been changed, thus causing the caller to never
145: * see the unlock...
146: *
147: * This suggests the following basic model for sleep locks:
148: *
149: * for (;;) {
150: * acquire_basic_lock ();
151: * if (resource_available ())
152: * break;
153: * if (MAKE_SLEEPING () == PROCESS_SLEPT) {
154: * release_basic_lock ();
155: * RUN_NEXT (); // does not return
156: * }
157: * }
158: *
159: * where MAKE_SLEEPING () and RUN_NEXT () together form the same kind
160: * of actions as sleep (), but broken into a pair that makes the
161: * setjmp ()-style behaviour of rescheduling apparent and useful. In
162: * particular, this keeps the desirable property that the low-level
163: * scheduling system leaves the locking system in the hands of the
164: * client code.
165: *
166: * Of course, there are various ways that this can be achieved. The
167: * preferred style would be for MAKE_SLEEPING () to (optionally) test
168: * for signals and to return some discriminating value. The values
169: * returned from MAKE_SLEEPING () could be
170: *
171: * PROCESS_SLEPT slept
172: * PROCESS_WOKEN woken normally
173: * PROCESS_SIGNALLED woken by signal
174: *
175: * but for practical reasons this is difficult. While it is desirable
176: * to expose at least part of the context-saving behaviour of the
177: * inner scheduling layer, most of these facilities have the same
178: * limitations as the setjmp () facility in that if the context which
179: * directly called the context-save routine exits, all bets are off.
180: * See (c) below for further discussion, and the final form will be
181: * introduced at the end.
182: *
183: * b) This can be generally dealt with as-is by introducing appropriate
184: * magic to map the abstract priorities into numbers for passing to
185: * MAKE_SLEEPING ().
186: *
187: * c) The old style of signal handling is forbidden in the DDI/DKI
188: * envinronment due to the locking style in use. In fact, the only
189: * way that a driver can detect that a signal has been sent to a
190: * process is by performing SV_WAIT_SIG () or SLEEP_LOCK_SIG () and
191: * testing the return value.
192: *
193: * Moreover, signalling introduces one deficiency in the model
194: * presented in a) above, namely that if a process is signalled, the
195: * wakeup done in the signalling process knows nothing about the
196: * locking system being used above (and in fact, if we layer on top of
197: * old sleep ()/wakeup () code, our entire queueing system is ignored,
198: * which would be easily fixable but for that locking problem).
199: *
200: * The simple solution would be to introduce an extra lock on part of
201: * the process table than can ameliorate some of the problems, but
202: * too many basic locks leads to hierarchy/ordering problems, and is
203: * especially wasteful given that approriate row-level locking on
204: * list headers should be completely sufficient without having to
205: * introduce node-level locks.
206: *
207: * Essentially, we define the basic lock as being part of the list
208: * head that sleeping processes are queued on and put a back-pointer
209: * to the list head in the process table so that signal wakeup. This
210: * complicates the generic sleep-lock and synchronization variable
211: * functions a little, but we should be able to impose the semantics
212: * we want (namely being able to guarantee deterministic ordering
213: * on locks, which requires that the generic functions be accurately
214: * able to determine the status of processes threaded on the sleep
215: * queues).
216: *
217: * This definition of responsibilty for the queue head w.r.t. locking
218: * behaviour allows us to fold the release_basic_lock () and
219: * RUN_NEXT () behaviour into MAKE_SLEEPING (), which also helps to
220: * solve the problem of dealing with the scope of context-save
221: * introduced in (a). Note that we have to be careful about using the
222: * process-table pointer to the list head since in order to find the
223: * list head to lock it we have to read this information which is
224: * potentially being modified as we access it.
225: *
226: * [ Note that it is possible to write a macro for MAKE_SLEEPING ()
227: * that does the context save in the caller's scope, but since it is
228: * possible for a routine to *not* sleep at all (due to a pending
229: * signal), that would mean it had to take the form:
230: * FINALIZE_SLEEP (SAVE_CONTEXT (BEGIN_SLEEP (...)), ...)
231: * in order to avoid introducing auxiliaries. ]
232: *
233: * d) The assumptions on which the old-style behaviour is based are no
234: * longer valid on multiprocessing systems. Firstly, the more con-
235: * current nature of multiprocessor systems increases the likelihood
236: * of contention for locks. Secondly, broadcast wakeup is likely to
237: * cause several of the woken processes to be run simultaneously on
238: * different processors, resulting in timelines like this (measured
239: * from a broadcast wakeup of processes waiting for a resource):
240: *
241: * CPU A : |-<acquire----------release>...............
242: * CPU n : .|--*|--*|--*|--*...........|--<acquire ---
243: *
244: * where '|' indicates selection of a process, '-' indicates CPU time
245: * consumed, and '*' indicates a process sleeping due to resource
246: * unavailability, and '.' represents CPU time spent on unrelated
247: * activity. Clearly, broadcast wakeup is not an optimal way of
248: * implementing one-at-a-time lock functionality on a multiprocessor.
249: *
250: * Of course, implementing one-at-a-time wakeup facilities is not a
251: * trivial matter. While awakening a single waiting process is fairly
252: * simple, the matter of selecting *which* process to awaken is a
253: * complex one that can have considerable impact on other kernel
254: * systems such as the virtual memory system. In addition, there is
255: * extra information available in the DDI/DKI system whose relation
256: * to scheduling has not been studied (such as the number of locks
257: * held by a context). Clearly, the internal layering of the DDI/DKI
258: * implementation should be designed to make it easy to export this
259: * information to the low-level kernel scheduling system.
260: *
261: * Of course, the worst case is that normal kernel scheduling policy
262: * is completely supplanted in the DDI/DKI case. There looks to be
263: * little alternative for the multiprocessor case, but it seems to
264: * be a good idea to design the DDI/DKI implementation to support the
265: * old-style broadcast functionality as a fallback.
266: */
267:
268:
269: /*
270: * Common inital part of a lock that is used to queue locks and hold the
271: * statistics information. We use this definition to simplify the process of
272: * keeping lists of all the allocated locks and to permit simple generic
273: * operations on such lists.
274: *
275: * Downcast operators should be provided for the lock structures so that the
276: * mapping from the node to the lock can be done in a fully portable fashion.
277: */
278:
279: typedef struct lock_node lnode_t;
280:
281: struct lock_node {
282: lnode_t * ln_next; /* pointer to successor */
283: lnode_t * ln_prev; /* pointer to predecessor */
284: lkinfo_t * ln_lkinfo; /* statistics information */
285: };
286:
287:
288: /*
289: * Internal structure of a basic lock
290: */
291:
292: struct __basic_lock {
293: lnode_t bl_node; /* generic information */
294:
295: #ifdef __TICKET_LOCK__
296: atomic_ushort_t bl_next_ticket; /* next ticket number to be granted */
297: atomic_ushort_t bl_lock_holder; /* ticket number of lock holder */
298: #endif
299:
300: atomic_uchar_t bl_locked; /* is the basic lock acquired? */
301:
302: pl_t bl_min_pl; /* minimum pl to be used in LOCK () */
303:
304: uchar_t bl_hierarchy; /* acquisition order constraint */
305: };
306:
307:
308: /*
309: * Internal structure of a read/write lock.
310: *
311: * Due to the shared nature of read locks, they are naturally expressed by
312: * a count of outstanding readers maintained by atomic increment and
313: * decrement operations. The exclusive (write) mode of such locks are best
314: * expressed via the "ticket" mechanism if FIFO ordering is desired and/or
315: * contention is to be minimized.
316: *
317: * The following implementation consists of a basic (exclusive) lock simply
318: * augmented by a count; the use of a "ticket gate" test-and-set lock to
319: * control access to the lock internal data reduces dependency on atomic
320: * facilities such as fetch_and_increment and compare_and_swap that are not
321: * widely available. If such facilities are available, consider using the
322: * lock algorithm outlined in the paper referenced in the file header comment
323: * above.
324: */
325:
326: struct readwrite_lock {
327: lnode_t rw_node; /* generic information */
328:
329: atomic_ushort_t rw_next_ticket; /* next ticket number to be granted */
330: atomic_ushort_t rw_lock_holder; /* ticket number of lock holder */
331:
332: atomic_ushort_t rw_readers;
333:
334: atomic_uchar_t rw_locked;
335:
336: pl_t rw_min_pl; /* min pl to acquire the lock with */
337:
338: uchar_t rw_hierarchy; /* acquisition order constraint */
339: };
340:
341:
342: /*
343: * Internal structure of a synchronisation variable
344: */
345:
346: struct synch_var {
347: lnode_t sv_node; /* generic information */
348:
349: plist_t sv_plist [1]; /* list of blocked processes */
350: };
351:
352:
353: /*
354: * Internal structure of a sleep lock.
355: *
356: * Note that the "sl_holder" member exists purely to support the debugging
357: * SLEEP_LOCKOWNED () function, nothing else. What the System V documentation
358: * fails to discuss is that sleep locks don't have to be owned by *any*
359: * process. Sleep locks can be acquired at interrupt level via
360: * SLEEP_TRYLOCK (), and released by interrupts as well. There doesn't appear
361: * to be any mechanism to prevent locks being passed between processes by
362: * various methods, and so on and so forth.
363: *
364: * Therefore, the flag members are the only members actually used by the
365: * implementations of the sleep-lock functions, and the "sl_holder" member
366: * may not be correct if the lock was acquired by an interrupt context.
367: *
368: * As discussed elsewhere, the main focus of activity for sleep locks is the
369: * list of waiting processes, which contains a test-and-set lock that should
370: * be used to control most aspects of lock state.
371: */
372:
373: struct sleep_lock {
374: lnode_t sl_node; /* generic information */
375:
376: atomic_uchar_t sl_locked; /* is sleep lock held? */
377:
378: plist_t sl_plist [1]; /* process list */
379:
380: _VOID * sl_holder; /* ID of process holding lock */
381: };
382:
383:
384: /*
385: * Downcasting operators. Hopefully we won't need these.
386: */
387:
388: #define lnode_to_basic(n) ((lock_t *) ((char *) (n) - \
389: offsetof (lock_t, bl_node)))
390:
391: #define lnode_to_rw(n) ((rwlock_t *) ((char *) (n) - \
392: offsetof (rwlock_t, rw_node)))
393:
394: #define lnode_to_sv(n) ((sv_t *) ((char *) (n) - \
395: offsetof (sv_t, sv_node)))
396:
397: #define lnode_to_sleep(n) ((sleep_t *) ((char *) (n) - \
398: offsetof (sleep_t, sl_node)))
399:
400:
401: /*
402: * For debugging purposes, we want to keep lists of all the allocated locks.
403: *
404: * In the absence of atomic compare-and-swap operations, it's hard to define
405: * good list-manipulation code, so we'll protect our list operations with
406: * simple test-and-set locks. As usual on a uniprocessor these are still
407: * useful for detecting potential inconsistency.
408: *
409: * There are no init or destroy methods/macros for this structure since there
410: * are only the following static instances defined.
411: */
412:
413: __LOCAL__ struct lock_list {
414: __CONST__ char * ll_name; /* name of list */
415:
416: atomic_uchar_t ll_locked; /* single-thread list operations */
417: lnode_t * ll_head; /* head of list */
418: } basic_locks = { "basic lock" },
419: rw_locks = { "read/write lock" },
420: synch_vars = { "synchronisation variable" },
421: sleep_locks = { "sleep lock" };
422:
423: #define LOCKLIST_LOCK(l,n) (TEST_AND_SET_LOCK ((l)->ll_locked, plhi, n))
424: #define LOCKLIST_UNLOCK(l,p) (ATOMIC_CLEAR_UCHAR ((l)->ll_locked),\
425: (void) splx (p))
426:
427: /*
428: * We must abstract the linkage between locks and memory allocation; the lock
429: * system requires memory allocation services which require lock services...
430: * certain definitions below (and presumably similar definitions in the memory
431: * management system) can be used to resolve this dependency. In addition,
432: * the abstraction provided can be used to decouple the provided systems (and
433: * this aids portability) or to increase their coupling (to increase
434: * performance).
435: *
436: * The definitions (which may be macros):
437: * _lock_malloc ()
438: * _lock_free ()
439: * define an internal interface to the memory management system. If the memory
440: * allocation system uses LOCK_ALLOC () to allocate the locks used to
441: * coordinate access to the memory pool(s), the functions above will work as
442: * expected even during the memory system's call to LOCK_ALLOC (), and will
443: * coordinate access as necessary with other memory allocation interfaces
444: * thereafter.
445: */
446:
447: __EXTERN_C_BEGIN__
448:
449: _VOID * _lock_malloc __PROTO ((size_t size, int flag));
450: void _lock_free __PROTO ((_VOID * mem, size_t size));
451:
452: __EXTERN_C_END__
453:
454:
455: /*
456: * For now, we just map these functions onto the kmem_ interface and deal
457: * with startup issues there.
458: */
459:
460: #define _lock_malloc(s,f) kmem_alloc (s, f)
461: #define _lock_free(s,f) kmem_free (s, f)
462:
463:
464: /*
465: * This file-local function encapsulates the hierarchy-recording function that
466: * deals with the bookkeeping necessary to ensure that locks are acquired
467: * strictly in the order defined (to avoid deadlock).
468: *
469: * Due to the way in which the DDI/DKI locking functions are defined, it might
470: * be possible on some architectures for a basic or read/write lock acquired
471: * on one CPU to eventually be released on another.
472: *
473: * In a multi-processor system where this might be possible, it might be more
474: * sensible to record the hierarchy information in some per-priority-level
475: * fashion (as the DDI/DKI alludes to). Since this is currently not
476: * necessary, we'll elect to design that ability later.
477: */
478:
479: #if __USE_PROTO__
480: __LOCAL__ void (LOCK_COUNT_HIERARCHY) (__lkhier_t hierarchy)
481: #else
482: __LOCAL__ void
483: LOCK_COUNT_HIERARCHY __ARGS ((hierarchy))
484: __lkhier_t hierarchy;
485: #endif
486: {
487: dcdata_t * dcdata = ddi_cpu_data ();
488: pl_t prev_pl = splhi ();
489:
490: /*
491: * We'll skip the usual paranoid ASSERT () tests since this is purely
492: * a local function.
493: */
494:
495: dcdata->dc_hierarchy_cnt [hierarchy - __MIN_HIERARCHY__] ++;
496:
497: if (dcdata->dc_max_hierarchy < hierarchy)
498: dcdata->dc_max_hierarchy = hierarchy;
499:
500: (void) splx (prev_pl);
501: }
502:
503:
504: /*
505: * This file-local function is the dual to the above, for adjusting the
506: * hierarchy information for a lock release.
507: */
508:
509: #define ARRAY_MAX(array) (sizeof (array) / sizeof ((array) [0])
510:
511: #if __USE_PROTO__
512: __LOCAL__ void (LOCK_FREE_HIERARCHY) (__lkhier_t hierarchy)
513: #else
514: __LOCAL__ void
515: LOCK_FREE_HIERARCHY __ARGS ((hierarchy))
516: __lkhier_t hierarchy;
517: #endif
518: {
519: dcdata_t * dcdata = ddi_cpu_data ();
520: pl_t prev_pl = splhi ();
521:
522: /*
523: * We'll skip the usual paranoid ASSERT () tests since this is purely
524: * a local function.
525: */
526:
527: dcdata->dc_hierarchy_cnt [hierarchy - __MIN_HIERARCHY__] --;
528:
529: /*
530: * Work out the lowest occupied priority level.
531: */
532:
533: do {
534: if (dcdata->dc_hierarchy_cnt [dcdata->dc_max_hierarchy -
535: __MIN_HIERARCHY__] > 0)
536: break;
537: } while (-- dcdata->dc_max_hierarchy >= __MIN_HIERARCHY__);
538:
539: (void) splx (prev_pl);
540: }
541:
542:
543: #if 0
544: /*
545: * This file-local function takes care of recording debugging information and
546: * statistics relating to lock acquisition.
547: */
548:
549: #if __USE_PROTO__
550: __LOCAL__ void (TRACE_BASIC_LOCK) (lock_t * lockp)
551: #else
552: __LOCAL__ void
553: TRACE_BASIC_LOCK __ARGS ((lockp))
554: lock_t * lockp;
555: #endif
556: {
557: /*
558: * We'll skip the usual paranoid ASSERT () tests since this is purely
559: * a local function.
560: */
561: }
562:
563:
564:
565: /*
566: * This file-local function takes care of undoing any data-structure changes
567: * made by the above and recording additional statistics when a lock is
568: * released
569: */
570:
571: #if __USE_PROTO__
572: __LOCAL__ void (UNTRACE_BASIC_LOCK) (lock_t * lockp)
573: #else
574: __LOCAL__ void
575: UNTRACE_BASIC_LOCK __ARGS ((lockp))
576: lock_t * lockp;
577: #endif
578: {
579: /*
580: * We'll skip the usual paranoid ASSERT () tests since this is purely
581: * a local function.
582: */
583: }
584:
585:
586: /*
587: * This file-local function takes care of recording debugging information and
588: * statistics relating to lock acquisition.
589: */
590:
591: #if __USE_PROTO__
592: __LOCAL__ void (TRACE_RW_LOCK) (rwlock_t * lockp)
593: #else
594: __LOCAL__ void
595: TRACE_RW_LOCK __ARGS ((lockp))
596: rwlock_t * lockp;
597: #endif
598: {
599: /*
600: * We'll skip the usual paranoid ASSERT () tests since this is purely
601: * a local function.
602: */
603: }
604:
605:
606:
607: /*
608: * This file-local function takes care of undoing any data-structure changes
609: * made by the above and recording additional statistics when a lock is
610: * released.
611: */
612:
613: #if __USE_PROTO__
614: __LOCAL__ void (UNTRACE_RW_LOCK) (rwlock_t * lockp)
615: #else
616: __LOCAL__ void
617: UNTRACE_RW_LOCK __ARGS ((lockp))
618: rwlock_t * lockp;
619: #endif
620: {
621: /*
622: * We'll skip the usual paranoid ASSERT () tests since this is purely
623: * a local function.
624: */
625: }
626:
627: #else
628:
629: /*
630: * Since all the above functions have empty bodies, we'll define empty macros
631: * to get around the warnings.
632: */
633:
634: #define TRACE_BASIC_LOCK(l)
635: #define UNTRACE_BASIC_LOCK(l)
636:
637: #define TRACE_RW_LOCK(l)
638: #define UNTRACE_RW_LOCK(l)
639:
640: #endif
641:
642:
643:
644: /*
645: * Simple common function to acquire a simple test-and-set lock.
646: *
647: * TEST_AND_SET_LOCK () uses the splraise () private function defined in
648: * <sys/inline.h> to raise the processor priority level to "pl". This ensures
649: * maximum safety in the use of this function, and certain DDI/DKI facilities
650: * such as freezestr () require this behaviour.
651: */
652:
653: #if __USE_PROTO__
654: pl_t (TEST_AND_SET_LOCK) (__atomic_uchar_t locked, pl_t pl,
655: __CONST__ char * name)
656: #else
657: pl_t
658: TEST_AND_SET_LOCK __ARGS ((locked, pl, name))
659: __atomic_uchar_t locked;
660: pl_t pl;
661: __CONST__ char * name;
662: #endif
663: {
664: for (;;) {
665: pl_t prev_pl = splraise (pl);
666:
667: if (ATOMIC_TEST_AND_SET_UCHAR (locked) == 0)
668: return prev_pl; /* all OK */
669:
670:
671: /*
672: * While we spin for the lock, we can allow interrupts that
673: * were permissible at entry to this routine.
674: */
675:
676: (void) splx (prev_pl);
677:
678: #ifdef __UNIPROCESSOR__
679: cmn_err (CE_PANIC, "%s : test-and-set deadlock", name);
680: #elif defined (__TEST_AND_TEST__)
681: /*
682: * To reduce contention, we wait until the test-and-set lock
683: * is free before attempting to re-acquire it. Of course, more
684: * sophisticated backoff schemes might also help, even for
685: * this approach.
686: */
687:
688: while (ATOMIC_FETCH_UCHAR (locked) != 0)
689: /* DO NOTHING */;
690: #endif
691: }
692: }
693:
694:
695:
696: /*
697: * File-local function to initialise the generic part of a lock; this normally
698: * enqueues the lock on a list. This function also has the responsibility of
699: * allocating any needed statistics buffers, which requires that it be passed
700: * the flag which indicates whether it is allowed to block or not.
701: */
702:
703: #if __USE_PROTO__
704: __LOCAL__ void (INIT_LNODE) (lnode_t * lnode, lkinfo_t * lkinfop,
705: struct lock_list * list, int __NOTUSED (flag))
706: #else
707: __LOCAL__ void
708: INIT_LNODE __ARGS ((lnode, lkinfop, list, flag))
709: lnode_t * lnode;
710: lkinfo_t * lkinfop;
711: struct lock_list
712: * list;
713: int flag;
714: #endif
715: {
716: pl_t prev_pl;
717:
718: ASSERT (lnode != NULL && list != NULL);
719:
720: /*
721: * Here we allocate and initialise any needed statistics information,
722: * currently nothing.
723: */
724:
725: lnode->ln_lkinfo = lkinfop;
726: lnode->ln_prev = NULL;
727:
728:
729: /*
730: * Lock the list, enqueue the node, and unlock the list.
731: */
732:
733: prev_pl = LOCKLIST_LOCK (list, list->ll_name);
734:
735: if ((lnode->ln_next = list->ll_head) != NULL)
736: lnode->ln_next->ln_prev = lnode;
737: list->ll_head = lnode;
738:
739: LOCKLIST_UNLOCK (list, prev_pl);
740: }
741:
742:
743:
744: /*
745: * The dual to the above, this file-local function dequeues the node from the
746: * given list of locks and frees any statistics buffer memory.
747: */
748:
749: #if __USE_PROTO__
750: __LOCAL__ void (FREE_LNODE) (lnode_t * lnode, struct lock_list * list)
751: #else
752: __LOCAL__ void
753: FREE_LNODE __ARGS ((lnode, list))
754: lnode_t * lnode;
755: struct lock_list
756: * list;
757: #endif
758: {
759: pl_t prev_pl;
760:
761: /*
762: * We'll skip the paranoid assertions on this one, since the function
763: * is file-local.
764: *
765: * Lock the list, dequeue the node, unlock the list. After that we
766: * can free any statistics buffers.
767: */
768:
769: prev_pl = LOCKLIST_LOCK (list, list->ll_name);
770:
771: if (lnode->ln_prev == NULL)
772: list->ll_head = lnode->ln_next;
773: else
774: lnode->ln_prev->ln_next = lnode->ln_next;
775:
776: if (lnode->ln_next != NULL)
777: lnode->ln_next->ln_prev = lnode->ln_prev;
778:
779: LOCKLIST_UNLOCK (list, prev_pl);
780: }
781:
782:
783: /*
784: *-STATUS:
785: * DDI/DKI
786: *
787: *-NAME:
788: * LOCK_ALLOC () Allocate a basic lock
789: *
790: *-SYNOPSIS:
791: * #include <sys/types.h>
792: * #include <sys/kmem.h>
793: * #include <sys/ksynch.h>
794: *
795: * lock_t * LOCK_ALLOC (uchar_t hierarchy, pl_t min_pl,
796: * lkinfo_t * lkinfop, int flag);
797: *
798: *-ARGUMENTS:
799: * hierarchy Hierarchy value which asserts the order in which this
800: * lock will be acquired relative to other basic and
801: * read/write locks. "hierarchy" must be within the range
802: * of 1 through 32 inclusive and must be chosen such that
803: * locks are normally acquired in order of increasing
804: * "hierarchy" number. In other words, when acquiring a
805: * basic lock using any function other than TRYLOCK (),
806: * the lock being acquired must have a "hierarchy" value
807: * that is strictly greater than the "hierarchy" values
808: * associated with all locks currently held by the
809: * calling context.
810: *
811: * Implementations of lock testing may differ in whether
812: * they assume a separate range of "hierarchy" values for
813: * each interrupt priority level or a single range that
814: * spans all interrupt priority levels. In order to be
815: * portable across different implementations, drivers
816: * which may acquire locks at more than one interrupt
817: * priority level should define the "hierarchy" among
818: * those locks such that the "hierarchy" is strictly
819: * increasing with increasing priority level (eg. if M
820: * is the maximum "hierarchy" value defined for any lock
821: * that may be acquired at priority level N, then M + 1
822: * should be the minimum hierarchy value for any lock
823: * that may be acquired at any priority level greater
824: * than N).
825: *
826: * min_pl Minimum priority level argument which asserts the
827: * minimum priority leel that will be passed in with any
828: * attempt to acquire this lock [see LOCK ()].
829: * Implementations which do not require that the
830: * interrupt priority level be raised during lock
831: * acquisition may choose not to enforce the "min_pl"
832: * assertion. The valid values for this argument are as
833: * follows:
834: *
835: * plbase Block no interrupts
836: * pltimeout Block functions scheduled by itimeout
837: * and dtimeout
838: * pldisk Block disk device interrupts
839: * plstr Block STREAMS interrupts
840: * plhi Block all interrupts
841: *
842: * The notion of a "min_pl" assumes a defined order of
843: * priority levels. The following partial order is
844: * defined:
845: * plbase < pltimeout <= pldisk, plstr <= plhi
846: *
847: * The ordering of pldisk and plstr relative to each
848: * other is not defined.
849: *
850: * Setting a given priority level will block interrupts
851: * associated with that level as well as all levels that
852: * are defined to be less than or equal to the specified
853: * level. In order to be portable a driver should not
854: * acquire locks at different priority levels where the
855: * relative order of those priority levels is not defined
856: * above.
857: *
858: * The "min_pl" argument should specify a priority level
859: * that would be sufficient to block out any interrupt
860: * handler that might attempt to acquire this lock. In
861: * addition, potential deadlock problems involving
862: * multiple locks should be considered when defining the
863: * "min_pl" value. For example, if the normal order of
864: * acquisition of locks A and B (as defined by the lock
865: * hierarchy) is to acquire A first and then B, lock B
866: * should never be acquired at a priority level less
867: * than the "min_pl" for lock A. Therefore, the "min_pl"
868: * for lock B should be greater than or equal to the
869: * "min_pl" for lock A.
870: *
871: * Note that the specification of a "min_pl" with a
872: * LOCK_ALLOC () call does not actually cause any
873: * interrupts to be blocked upon lock acquisition, it
874: * simply asserts that subsequent LOCK () calls to
875: * acquire this lock will pass in a priority level at
876: * least as great as "min_pl".
877: *
878: * lkinfop Pointer to a lkinfo structure. The "lk_name" member of
879: * the "lkinfo" structure points to a character string
880: * defining a name that will be associated with the lock
881: * for the purposes of statistics gathering. The name
882: * should begin with the driver prefix and should be
883: * unique to the lock or group of locks for which the
884: * driver wishes to collect a uniquely identifiable set
885: * of statistics (ie, if a given name is shared by a
886: * group of locks, the statistics of the individual locks
887: * within the group will not be uniquely identifiable).
888: * There are no flags within the lk_flags member of the
889: * lkinfo structure defined for use with LOCK_ALLOC ().
890: *
891: * A given lkinfo structure may be shared among multiple
892: * basic locks and read/write locks but a lkinfo
893: * structure may not be shared between a basic lock and
894: * a sleep lock. The called must ensure that the lk_flags
895: * and lk_pad members of the lkinfo structure are zeroed
896: * out before passing it to LOCK_ALLOC ().
897: *
898: * flag Specifies whether the caller is willing to sleep
899: * waiting for memory. If "flag" is set to KM_SLEEP, the
900: * caller will sleep if necessary until sufficient memory
901: * is available. If "flag" is set to KM_NOSLEEP, the
902: * caller will not sleep, but LOCK_ALLOC () will return
903: * NULL if sufficient memory is not immediately
904: * available.
905: *
906: *-DESCRIPTION:
907: * LOCK_ALLOC () dynamically allocates and initialises an instance of a
908: * basic lock. The lock is initialised to the unlocked state.
909: *
910: *-RETURN VALUE:
911: * Upon successful completion, LOCK_ALLOC () returns a pointer to the
912: * newly allocated lock. If KM_NOSLEEP is specified and sufficient
913: * memory is not immediately available, LOCK_ALLOC () returns a NULL
914: * pointer.
915: *
916: *-LEVEL:
917: * Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
918: * set to KM_NOSLEEP.
919: *
920: *-NOTES:
921: * May sleep if "flag" is set to KM_NOSLEEP.
922: *
923: * Driver-defined basic locks and read/write locks may be held across
924: * calls to this function if "flag" is set to KM_NOSLEEP but may not be
925: * held if "flag" is KM_SLEEP.
926: *
927: * Driver-defined sleep locks may be held across calls to this function
928: * regardless of the value of "flag".
929: *
930: *-SEE ALSO:
931: * LOCK (), LOCK_DEALLOC (), TRYLOCK (), UNLOCK (), lkinfo
932: */
933:
934: #define ASSERT_HIERARCHY_OK(h,lk) \
935: ASSERT ((lk) != NULL), \
936: ASSERT ((h) >= __MIN_HIERARCHY__ && \
937: (h) <= (((lk)->lk_flags & INTERNAL_LOCK) != 0 ? \
938: __MAX_HIERARCHY__ : __MAX_DDI_HIERARCHY__))
939:
940: #if __USE_PROTO__
941: lock_t * (LOCK_ALLOC) (__lkhier_t hierarchy, pl_t min_pl, lkinfo_t * lkinfop,
942: int flag)
943: #else
944: lock_t *
945: LOCK_ALLOC __ARGS ((hierarchy, min_pl, lkinfop, flag))
946: __lkhier_t hierarchy;
947: pl_t min_pl;
948: lkinfo_t * lkinfop;
949: int flag;
950: #endif
951: {
952: lock_t * lockp;
953:
954: ASSERT_HIERARCHY_OK (hierarchy, lkinfop);
955: ASSERT (splcmp (plbase, min_pl) <= 0 && splcmp (min_pl, plhi) <= 0);
956: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
957:
958: /*
959: * Allocate and initialise the data, possibly waiting for enough
960: * memory to become available.
961: */
962:
963: if ((lockp = (lock_t *) _lock_malloc (sizeof (* lockp),
964: flag)) != NULL) {
965: INIT_LNODE (& lockp->bl_node, lkinfop, & basic_locks, flag);
966:
967: lockp->bl_min_pl = min_pl;
968: lockp->bl_hierarchy = hierarchy;
969:
970: ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
971:
972: #ifdef __TICKET_LOCK__
973: ATOMIC_CLEAR_USHORT (lockp->bl_next_ticket);
974: ATOMIC_CLEAR_USHORT (lockp->bl_lock_holder);
975: #endif
976: }
977:
978: return lockp;
979: }
980:
981:
982: /*
983: *-STATUS:
984: * DDI/DKI
985: *
986: *-NAME:
987: * LOCK_DEALLOC () Deallocate an instance of a basic lock.
988: *
989: *-SYNOPSIS:
990: * #include <sys/ksynch.h>
991: *
992: * void LOCK_DEALLOC (lock_t * lockp);
993: *
994: *-ARGUMENTS:
995: * lockp Pointer to the basic lock to be deallocated.
996: *
997: *-DESCRIPTION:
998: * LOCK_DEALLOC () deallocates the basic lock specified by "lockp".
999: *
1000: *-RETURN VALUE:
1001: * None.
1002: *
1003: *-LEVEL:
1004: * Base or Interrupt.
1005: *
1006: *-NOTES:
1007: * Does not sleep.
1008: *
1009: * Attempting to deallocate a lock that is currently locked or is being
1010: * waited for is an error and will result in undefined behavior.
1011: *
1012: * Driver-defined basic locks (other than the one being deallocated),
1013: * read/write locks and sleep locks may be held across calls to this
1014: * function.
1015: *
1016: *-SEE ALSO:
1017: * LOCK (), LOCK_ALLOC (), TRYLOCK (), UNLOCK ()
1018: */
1019:
1020: #if __USE_PROTO__
1021: void (LOCK_DEALLOC) (lock_t * lockp)
1022: #else
1023: void
1024: LOCK_DEALLOC __ARGS ((lockp))
1025: lock_t * lockp;
1026: #endif
1027: {
1028: ASSERT (lockp != NULL);
1029: ASSERT (ATOMIC_FETCH_UCHAR (lockp->bl_locked) == 0);
1030:
1031: #ifdef __TICKET_LOCK__
1032: ASSERT (ATOMIC_FETCH_USHORT (lockp->bl_next_ticket) ==
1033: ATOMIC_FETCH_USHORT (lockp->bl_lock_holder));
1034: #endif
1035:
1036: /*
1037: * Remove from the list of all basic locks and free any statistics
1038: * buffer space before freeing the lock itself.
1039: */
1040:
1041: FREE_LNODE (& lockp->bl_node, & basic_locks);
1042:
1043: _lock_free (lockp, sizeof (* lockp));
1044: }
1045:
1046:
1047: /*
1048: *-STATUS:
1049: * DDI/DKI
1050: *
1051: *-NAME:
1052: * LOCK () Acquire a basic lock
1053: *
1054: *-SYNOPSIS:
1055: * #include <sys/types.h>
1056: * #include <sys/ksynch.h>
1057: *
1058: * pl_t LOCK (lock_t * lockp, pl_t pl);
1059: *
1060: *-ARGUMENTS:
1061: * lockp Pointer to the basic lock to be acquired.
1062: *
1063: * pl The interrupt priority level to be set while the lock
1064: * is held by the caller. Because some implementations
1065: * require that interrupts that might attempt to acquire
1066: * the lock be blocked on which the lock is held,
1067: * portable drivers must specify a "pl" value that is
1068: * sufficient to block out any interrupt handler that
1069: * might attempt to acquire this lock. See the
1070: * description of the "min_pl" argument to LOCK_ALLOC ()
1071: * for additional discussion. Implementations that do
1072: * not require that the interrupt priority level be
1073: * raised during lock acquisition may choose to ignore
1074: * this argument.
1075: *
1076: *-DESCRIPTION:
1077: * LOCK () sets the interrupt priority level in accordance with the
1078: * value specified by "pl" (if required by the implementation) and
1079: * acquires the lock specified by "lockp". If the lock is not currently
1080: * available, the caller will wait until the lock is available. It is
1081: * implementation-defined whether the caller will block during the wait.
1082: * Some implementations may cause the caller to spin for the duration of
1083: * the wait, while on others the caller may block at some point.
1084: *
1085: *-RETURN VALUE:
1086: * Upon acquiring the lock, LOCK () returns the previous interrupt
1087: * priority level.
1088: *
1089: *-LEVEL:
1090: * Base or Interrupt.
1091: *
1092: *-NOTES:
1093: * Basic locks are not recursive. A call to LOCK () attempting to
1094: * acquire a lock that is already held by the calling context will
1095: * result in deadlock.
1096: *
1097: * Calls to LOCK () should honor the ordering defined by the lock
1098: * hierarchy [see LOCK_ALLOC ()] in order to avoid deadlock.
1099: *
1100: * Driver-defined sleep locks may be held across calls to this function.
1101: *
1102: * Driver-defined basic locks and read/write locks may be held across
1103: * calls to this function subject to the hierarchy and recursion
1104: * restrictions described above.
1105: *
1106: * When called from interrupt level, the "pl" argument must not specify
1107: * a priority below the level at which the interrupt handler is running.
1108: *
1109: *-SEE ALSO:
1110: * LOCK_ALLOC (), LOCK_DEALLOC (), TRYLOCK (), UNLOCK ()
1111: */
1112:
1113: #if __USE_PROTO__
1114: pl_t (LOCK) (lock_t * lockp, pl_t pl)
1115: #else
1116: pl_t
1117: LOCK __ARGS ((lockp, pl))
1118: lock_t * lockp;
1119: pl_t pl;
1120: #endif
1121: {
1122: pl_t prev_pl;
1123: #ifdef __TICKET_LOCK__
1124: ushort_t ticket_no;
1125: #endif
1126:
1127: ASSERT (lockp != NULL);
1128: ASSERT (splcmp (pl, plhi) <= 0);
1129:
1130:
1131: /*
1132: * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
1133: * that splcmp () abstracts subtraction-for-comparison of priority
1134: * levels, which explains the form of the assertion.
1135: */
1136:
1137: ASSERT (splcmp (pl, lockp->bl_min_pl) >= 0);
1138:
1139:
1140: /*
1141: * On a uniprocessor, encountering a basic lock that is already
1142: * locked is *always* an error, even on machines with many different
1143: * interrupt priority levels. The hierarchy-assertion mechanism
1144: * cannot always deal with this, since TRYLOCK () can acquire locks
1145: * in a different order.
1146: *
1147: * On a multiprocessor, we can just spin here. Note that since LOCK ()
1148: * is defined as requiring values of "pl" greater than the current
1149: * interrupt priority level, the use of splraise () by
1150: * TEST_AND_SET_LOCK () is legitimate.
1151: */
1152:
1153: prev_pl = TEST_AND_SET_LOCK (lockp->bl_locked, pl, "LOCK");
1154:
1155: #ifdef __TICKET_LOCK__
1156: /*
1157: * If we are working with a ticket-lock scheme, we now take a ticket
1158: * and release the test-and-set lock. After that, we can just wait for
1159: * our number to come up...
1160: */
1161:
1162: ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_next_ticket);
1163:
1164: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->bl_next_ticket,
1165: ticket_no + 1) != ticket_no) {
1166: /*
1167: * If we didn't read the same number twice, then the basic
1168: * lock protection isn't doing its job.
1169: */
1170:
1171: cmn_err (CE_PANIC, "LOCK : Ticket-lock gate failure");
1172: }
1173:
1174: ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
1175:
1176: while (ATOMIC_FETCH_USHORT (lockp->bl_lock_holder) != ticket_no) {
1177: /*
1178: * At this point we might want to implement some form of
1179: * proportional backoff to reduce memory traffic. Later.
1180: *
1181: * Another hot contender for this spot is detecting failures
1182: * on other CPUs...
1183: */
1184:
1185: #ifdef __UNIPROCESSOR__
1186: cmn_err (CE_PANIC, "LOCK : deadlock on ticket");
1187: #endif
1188: }
1189:
1190: #endif /* defined (__TICKET_LOCK__) */
1191:
1192:
1193: /*
1194: * Now would be an appropriate time to check that the requested level
1195: * is >= the current level on entry. The architectures that we are
1196: * likely to target require this to be true, although some novel
1197: * schemes which reduce interrupt latency do not.
1198: *
1199: * Since the TEST_AND_SET_LOCK () function which set our priority
1200: * level uses splraise (), we are safe making this test at this late
1201: * stage.
1202: */
1203:
1204: ASSERT (splcmp (pl, prev_pl) >= 0);
1205:
1206:
1207: /*
1208: * Test the lock-acquisition-hierarchy assertions.
1209: */
1210:
1211: ASSERT (ddi_cpu_data ()->dc_max_hierarchy < lockp->bl_hierarchy);
1212:
1213: LOCK_COUNT_HIERARCHY (lockp->bl_hierarchy);
1214:
1215:
1216: /*
1217: * Since it may be useful for post-mortem debugging to record some
1218: * information about the context which acquired the lock, we defer
1219: * to some generic recorder function or macro.
1220: *
1221: * Note that in general it does not appear to be possible to make
1222: * detailed assertions about the relation between the contexts in
1223: * which a lock is acquired and/or released. In particular, it
1224: * might be possible for a basic lock to be tied to some device
1225: * hardware-related operation where a lock might be acquired on one
1226: * CPU and released on another.
1227: *
1228: * In addition, any lock statistics are kept by this operation.
1229: */
1230:
1231: TRACE_BASIC_LOCK (lockp);
1232:
1233: return prev_pl;
1234: }
1235:
1236:
1237: /*
1238: *-STATUS:
1239: * DDI/DKI
1240: *
1241: *-NAME:
1242: * TRYLOCK () Try to acquire a basic lock
1243: *
1244: *-SYNOPSIS:
1245: * #include <sys/types.h>
1246: * #include <sys/ksynch.h>
1247: *
1248: * pl_t TRYLOCK (lock_t * lockp, pl_t pl);
1249: *
1250: *-ARGUMENTS:
1251: * lockp Pointer to the basic lock to be acquired.
1252: *
1253: * pl The interrupt priority level to be set while the lock
1254: * is held by the caller. Because some implementations
1255: * require that interrupts that might attempt to acquire
1256: * the lock be blocked on the processor on which the
1257: * lock is held, portable drivers must specify a "pl"
1258: * value that is sufficient to block out and interrupt
1259: * handler that might attempt to acquire this lock. See
1260: * the description of LOCK_ALLOC () for additional
1261: * discussion and a list of the valid values for "pl".
1262: * Implementations that do not require that the interrupt
1263: * priority level be raised during lock acquisition may
1264: * choose to ignore this argument.
1265: *
1266: *-DESCRIPTION:
1267: * If the lock specified by "lockp" is immediately available (can be
1268: * acquired without waiting) TRYLOCK () sets the interrupt priority level
1269: * in accordance with the value specified by "pl" (if required by the
1270: * implementation) and acquires the lock. If the lock is not immediately
1271: * available, the function returns without acquiring the lock.
1272: *
1273: *-RETURN VALUE:
1274: * If the lock is acquired, TRYLOCK () returns the previous interrupt
1275: * priority level ("plbase" - "plhi"). If the lock is not acquired the
1276: * value "invpl" is returned.
1277: *
1278: *-LEVEL:
1279: * Base or Interrupt.
1280: *
1281: *-NOTES:
1282: * Does not sleep.
1283: *
1284: * TRYLOCK () may be used to acquire a lock in a different order from
1285: * the order defined by the lock hierarchy.
1286: *
1287: * Driver-defined basic locks, read/write locks, and sleep locks may be
1288: * held across calls to this function.
1289: *
1290: * When called from interrupt level, the "pl" argument must not specify
1291: * a priority level below the level at which the interrupt handler is
1292: * running.
1293: *
1294: *-SEE ALSO:
1295: * LOCK (), LOCK_ALLOC (), LOCK_DEALLOC (), UNLOCK ()
1296: */
1297:
1298: #if __USE_PROTO__
1299: pl_t (TRYLOCK) (lock_t * lockp, pl_t pl)
1300: #else
1301: pl_t
1302: TRYLOCK __ARGS ((lockp, pl))
1303: lock_t * lockp;
1304: pl_t pl;
1305: #endif
1306: {
1307: pl_t prev_pl;
1308: #ifdef __TICKET_LOCK__
1309: ushort_t ticket_no;
1310: #endif
1311:
1312: ASSERT (lockp != NULL);
1313: ASSERT (splcmp (pl, plhi) <= 0);
1314:
1315:
1316: /*
1317: * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
1318: * that splcmp () abstracts subtraction-for-comparison of priority
1319: * levels, which explains the form of the assertion.
1320: */
1321:
1322: ASSERT (splcmp (pl, lockp->bl_min_pl) >= 0);
1323:
1324:
1325: #ifdef __TICKET_LOCK__
1326: /*
1327: * If this is a ticket-lock, we test the ticket numbers to see
1328: * whether there is any reason to even try acquiring the test-and-set
1329: * lock that forms the ticket gate.
1330: *
1331: * We read the "lock holder" and "next ticket" entries in that
1332: * sequence to be pessimistic, since we can assume that other CPUs
1333: * might be looking at this...
1334: */
1335:
1336: ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_lock_holder);
1337:
1338: if (ticket_no != ATOMIC_FETCH_USHORT (lockp->bl_next_ticket))
1339: return invpl;
1340: #endif
1341:
1342:
1343: /*
1344: * We block out interrupts at this point to allow the following
1345: * operations room to do their stuff in, since interrupts at an
1346: * inappropriate moment can cause deadlock... of course, if the
1347: * definition of the lock is such that interrupts can proceed, then
1348: * that's OK, since the lock acquisition is atomic.
1349: */
1350:
1351: prev_pl = splx (pl);
1352:
1353:
1354: /*
1355: * Now would be an appropriate time to check that the
1356: * requested level is >= the current level on entry. Strictly
1357: * speaking, this does not have to be true if the processor is
1358: * currently at base level, but for now we'll discourage that
1359: * behaviour.
1360: */
1361:
1362: ASSERT (splcmp (pl, prev_pl) >= 0);
1363:
1364:
1365: /*
1366: * Test to see whether the lock in question is already taken, and if
1367: * not, we take it. We don't spin if this is a ticket lock, since if
1368: * the basic lock is taken there is *no way* that the lock will be
1369: * free for us immediately.
1370: */
1371:
1372: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->bl_locked) == 0) {
1373: #ifdef __TICKET_LOCK__
1374: /*
1375: * If this is a ticket lock, now would be a good time to
1376: * check the ticket numbers to ensure that the lock *really*
1377: * is free.
1378: */
1379:
1380: ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_next_ticket);
1381:
1382: if (ticket_no != ATOMIC_FETCH_USHORT (lockp->bl_lock_holder)) {
1383:
1384: ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
1385: goto try_failed;
1386: }
1387:
1388: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->bl_next_ticket,
1389: ticket_no + 1) != ticket_no) {
1390: /*
1391: * If we didn't read the same number twice, then the
1392: * test-and-set lock protection isn't doing its job.
1393: */
1394:
1395: cmn_err (CE_PANIC, "TRYLOCK : Ticket-lock gate failure");
1396: }
1397:
1398:
1399: /*
1400: * Now we have the lock, we can release the ticket-gate lock.
1401: */
1402:
1403: ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
1404:
1405: #endif /* defined (__TICKET_LOCK__) */
1406:
1407:
1408: /*
1409: * TRYLOCK () bypasses the hierarchy-assertion mechanism,
1410: * although we record the maximum acquired hierarchy level for
1411: * maximum strictness checking in inner LOCK () attempts.
1412: *
1413: * We also record debugging and statistics information here
1414: * with TRACE_BASIC_LOCK ().
1415: */
1416:
1417: LOCK_COUNT_HIERARCHY (lockp->bl_hierarchy);
1418:
1419: TRACE_BASIC_LOCK (lockp);
1420:
1421: return prev_pl;
1422: }
1423:
1424: try_failed:
1425: /*
1426: * We cannot acquire the lock, so reset the priority and exit with
1427: * the flag value.
1428: */
1429:
1430: (void) splx (prev_pl);
1431:
1432: return invpl;
1433: }
1434:
1435:
1436: /*
1437: *-STATUS:
1438: * DDI/DKI
1439: *
1440: *-NAME:
1441: * UNLOCK () Release a basic lock.
1442: *
1443: *-SYNOPSIS:
1444: * #include <sys/types.h>
1445: * #include <sys/ksynch.h>
1446: *
1447: * void UNLOCK (lock_t * lockp, pl_t pl);
1448: *
1449: *-ARGUMENTS:
1450: * lockp Pointer to the basic lock to be released.
1451: *
1452: * pl The interrupt priority level to be set after releasing
1453: * the lock. See the description of the "min_pl" argument
1454: * to LOCK_ALLOC () for a list of the valid values for
1455: * "pl". If lock calls are not being nested or if the
1456: * caller is unlocking in the reverse order that locks
1457: * were acquired, the "pl" argument will typically be the
1458: * value that was returned from the corresponding call to
1459: * acquire the lock. The caller may need to specify a
1460: * different value for "pl" if nested locks are being
1461: * released in some order other that the reverse order of
1462: * acquisition, so as to ensure that the interrupt
1463: * priority level is kept sufficiently high to block
1464: * interrupt code that might attempt to acquire locks
1465: * which are still held. Although portable drivers must
1466: * always specify an appropriate "pl" argument,
1467: * implementations which do not require that the
1468: * interrupt priority level be raised during lock
1469: * acquisition may choose to ignore this argument.
1470: *
1471: *-DESCRIPTION:
1472: * UNLOCK () releases the basic lock specified by "lockp" and then sets
1473: * the interrupt priority level in accordance with the value specified by
1474: * "pl" (if required by the implementation).
1475: *
1476: *-RETURN VALUE:
1477: * None.
1478: *
1479: *-LEVEL:
1480: * Base or Interrupt.
1481: *
1482: *-NOTES:
1483: * Does not sleep.
1484: *
1485: * Driver-defined basic locks, read/write locks, and sleep locks may be
1486: * held across calls to this function.
1487: *
1488: *-SEE ALSO:
1489: * LOCK (), LOCK_ALLOC (), LOCK_DEALLOC (), TRYLOCK ()
1490: */
1491:
1492: #if __USE_PROTO__
1493: void (UNLOCK) (lock_t * lockp, pl_t pl)
1494: #else
1495: void
1496: UNLOCK __ARGS ((lockp, pl))
1497: lock_t * lockp;
1498: pl_t pl;
1499: #endif
1500: {
1501: #ifdef __TICKET_LOCK__
1502: ushort_t ticket_no;
1503: #endif
1504:
1505: ASSERT (lockp != NULL);
1506: ASSERT (splcmp (plbase, pl) <= 0 && splcmp (pl, plhi) <= 0);
1507:
1508:
1509: /*
1510: * We assert that the lock is actually held by someone... in the case
1511: * of the ticket lock, we fetch the ticket number now since we don't
1512: * have an increment instruction and we'll need it later anyway.
1513: */
1514:
1515: #ifdef __TICKET_LOCK__
1516: ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_lock_holder);
1517:
1518: ASSERT (ticket_no != ATOMIC_FETCH_USHORT (lockp->bl_next_ticket));
1519: #else
1520: ASSERT (ATOMIC_FETCH_UCHAR (lockp->bl_locked) != 0);
1521: #endif
1522:
1523: /*
1524: * Do whatever we need to do to undo the hierarchy-assertion and
1525: * debugging/statistics data structures.
1526: */
1527:
1528: LOCK_FREE_HIERARCHY (lockp->bl_hierarchy);
1529:
1530: UNTRACE_BASIC_LOCK (lockp);
1531:
1532:
1533: /*
1534: * Now release the lock, either to the next ticket-holder or to
1535: * whoever gets in first, depending on the locking system.
1536: */
1537:
1538: #ifdef __TICKET_LOCK__
1539: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->bl_lock_holder,
1540: ticket_no + 1) != ticket_no) {
1541: /*
1542: * If we didn't read the same number twice, then someone has
1543: * released the lock that we own!
1544: */
1545:
1546: cmn_err (CE_PANIC, "UNLOCK : Ticket-lock sequence problem");
1547: }
1548: #else
1549: ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
1550: #endif
1551:
1552: /*
1553: * And lower out priority level to finish up.
1554: */
1555:
1556: (void) splx (pl);
1557: }
1558:
1559:
1560: /*
1561: *-STATUS:
1562: * DDI/DKI
1563: *
1564: *-NAME:
1565: * RW_ALLOC () Allocate and initialize a read/write lock
1566: *
1567: *-SYNOPSIS:
1568: * #include <sys/types.h>
1569: * #include <sys/kmem.h>
1570: * #include <sys/ksynch.h>
1571: *
1572: * rwlock_t * RW_ALLOC (uchar_t hierarchy, pl_t min_pl,
1573: * lkinfo_t * lkinfop, int flag);
1574: *
1575: *-ARGUMENTS:
1576: * hierarchy Hierarchy value which asserts the order in which this
1577: * lock will be acquired relative to other basic and
1578: * read/write locks. "hierarchy" must be within the range
1579: * of 1 through 32 inclusive and must be chosen such that
1580: * locks are normally acquired in order of increasing
1581: * "hierarchy" number. In other words, when acquiring a
1582: * basic lock using any function other than
1583: * RW_TRYRDLOCK () or RW_TRYWRLOCK () the lock being
1584: * acquired must have a "hierarchy" value that is
1585: * strictly greater than the "hierarchy" values
1586: * associated with all locks currently held by the
1587: * calling context.
1588: *
1589: * Implementations of lock testing may differ in whether
1590: * they assume a separate range of "hierarchy" values for
1591: * each interrupt priority level or a single range that
1592: * spans all interrupt priority levels. In order to be
1593: * portable across different implementations, drivers
1594: * which may acquire locks at more than one interrupt
1595: * priority level should define the "hierarchy" among
1596: * those locks such that the "hierarchy" is strictly
1597: * increasing with increasing priority level (eg. if M
1598: * is the maximum "hierarchy" value defined for any lock
1599: * that may be acquired at priority level N, then M + 1
1600: * should be the minimum hierarchy value for any lock
1601: * that may be acquired at any priority level greater
1602: * than N).
1603: *
1604: * min_pl Minimum priority level argument which asserts the
1605: * minimum priority leel that will be passed in with any
1606: * attempt to acquire this lock [see RW_RDLOCK () and
1607: * RW_WRLOCK ()]. Implementations which do not require
1608: * that the interrupt priority level be raised during
1609: * lock acquisition may choose not to enforce the
1610: * "min_pl" assertion. The valid values for this
1611: * argument are as follows:
1612: *
1613: * plbase Block no interrupts
1614: * pltimeout Block functions scheduled by itimeout
1615: * and dtimeout
1616: * pldisk Block disk device interrupts
1617: * plstr Block STREAMS interrupts
1618: * plhi Block all interrupts
1619: *
1620: * The notion of a "min_pl" assumes a defined order of
1621: * priority levels. The following partial order is
1622: * defined:
1623: * plbase < pltimeout <= pldisk, plstr <= plhi
1624: *
1625: * The ordering of pldisk and plstr relative to each
1626: * other is not defined.
1627: *
1628: * Setting a given priority level will block interrupts
1629: * associated with that level as well as all levels that
1630: * are defined to be less than or equal to the specified
1631: * level. In order to be portable a driver should not
1632: * acquire locks at different priority levels where the
1633: * relative order of those priority levels is not defined
1634: * above.
1635: *
1636: * The "min_pl" argument should specify a priority level
1637: * that would be sufficient to block out any interrupt
1638: * handler that might attempt to acquire this lock. In
1639: * addition, potential deadlock problems involving
1640: * multiple locks should be considered when defining the
1641: * "min_pl" value. For example, if the normal order of
1642: * acquisition of locks A and B (as defined by the lock
1643: * hierarchy) is to acquire A first and then B, lock B
1644: * should never be acquired at a priority level less
1645: * than the "min_pl" for lock A. Therefore, the "min_pl"
1646: * for lock B should be greater than or equal to the
1647: * "min_pl" for lock A.
1648: *
1649: * Note that the specification of a "min_pl" with a
1650: * RW_ALLOC () call does not actually cause any
1651: * interrupts to be blocked upon lock acquisition, it
1652: * simply asserts that subsequent RW_RDLOCK () or
1653: * RW_WRLOCK () calls to acquire this lock will pass in a
1654: * priority level at least as great as "min_pl".
1655: *
1656: * lkinfop Pointer to a lkinfo structure. The lk_name member of
1657: * the lkinfo structure points to a character string
1658: * defining a name that will be associated with the lock
1659: * for the purposes of statistics gathering. The name
1660: * should begin with the driver prefix and should be
1661: * unique to the lock or group of locks for which the
1662: * driver wishes to collect a uniquely identifiable set
1663: * of statistics (ie, if a given name is shared by a
1664: * group of locks, the statistics of the individual locks
1665: * within the group will not be uniquely identifiable).
1666: * There are no flags within the lk_flags member of the
1667: * lkinfo structure defined for use with RW_ALLOC ().
1668: *
1669: * A given lkinfo structure may be shared among multiple
1670: * basic locks and read/write locks but a lkinfo
1671: * structure may not be shared between a basic lock and
1672: * a sleep lock. The called must ensure that the lk_flags
1673: * and lk_pad members of the lkinfo structure are zeroed
1674: * out before passing it to RW_ALLOC ().
1675: *
1676: * flag Specifies whether the caller is willing to sleep
1677: * waiting for memory. If "flag" is set to KM_SLEEP, the
1678: * caller will sleep if necessary until sufficient memory
1679: * is available. If "flag" is set to KM_NOSLEEP, the
1680: * caller will not sleep, but RW_ALLOC () will return
1681: * NULL if sufficient memory is not immediately
1682: * available.
1683: *
1684: *-DESCRIPTION:
1685: * RW_ALLOC () dynamically allocates and initialises an instance of a
1686: * read/write lock. The lock is initialised to the unlocked state.
1687: *
1688: *-RETURN VALUE:
1689: * Upon successful completion, RW_ALLOC () returns a pointer to the
1690: * newly allocated lock. If KM_NOSLEEP is specified and sufficient
1691: * memory is not immediately available, RW_ALLOC () returns a NULL
1692: * pointer.
1693: *
1694: *-LEVEL:
1695: * Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
1696: * set to KM_NOSLEEP.
1697: *
1698: *-NOTES:
1699: * May sleep if "flag" is set to KM_NOSLEEP.
1700: *
1701: * Driver-defined basic locks and read/write locks may be held across
1702: * calls to this function if "flag" is set to KM_NOSLEEP but may not be
1703: * held if "flag" is KM_SLEEP.
1704: *
1705: * Driver-defined sleep locks may be held across calls to this function
1706: * regardless of the value of "flag".
1707: *
1708: *-SEE_ALSO:
1709: * RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (), RW_TRYWRLOCK (),
1710: * RW_UNLOCK (), RW_WRLOCK (), lkinfo
1711: */
1712:
1713: #if __USE_PROTO__
1714: rwlock_t * (RW_ALLOC) (__lkhier_t hierarchy, pl_t min_pl, lkinfo_t * lkinfop,
1715: int flag)
1716: #else
1717: rwlock_t *
1718: RW_ALLOC __ARGS ((hierarchy, min_pl, lkinfop, flag))
1719: __lkhier_t hierarchy;
1720: pl_t min_pl;
1721: lkinfo_t * lkinfop;
1722: int flag;
1723: #endif
1724: {
1725: rwlock_t * lockp;
1726:
1727: ASSERT_HIERARCHY_OK (hierarchy, lkinfop);
1728: ASSERT (splcmp (plbase, min_pl) <= 0 && splcmp (min_pl, plhi) <= 0);
1729: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
1730:
1731:
1732: /*
1733: * Allocate and initialise the data, possibly waiting for enough
1734: * memory to become available.
1735: */
1736:
1737: if ((lockp = (rwlock_t *) _lock_malloc (sizeof (* lockp),
1738: flag)) != NULL) {
1739: INIT_LNODE (& lockp->rw_node, lkinfop, & rw_locks, flag);
1740:
1741: lockp->rw_min_pl = min_pl;
1742: lockp->rw_hierarchy = hierarchy;
1743:
1744: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
1745:
1746: ATOMIC_CLEAR_USHORT (lockp->rw_readers);
1747:
1748: ATOMIC_CLEAR_USHORT (lockp->rw_next_ticket);
1749: ATOMIC_CLEAR_USHORT (lockp->rw_lock_holder);
1750: }
1751:
1752: return lockp;
1753: }
1754:
1755:
1756: /*
1757: *-STATUS:
1758: * DDI/DKI
1759: *
1760: *-NAME:
1761: * RW_DEALLOC () Deallocate an instance of a read/write lock.
1762: *
1763: *-SYNOPSIS:
1764: * #include <sys/ksynch.h>
1765: *
1766: * void RW_DEALLOC (rwlock_t * lockp);
1767: *
1768: *-ARGUMENTS:
1769: * lockp Pointer to the read/write lock to be deallocated.
1770: *
1771: *-DESCRIPTION:
1772: * RW_DEALLOC () deallocates the read/write lock specified by "lockp".
1773: *
1774: *-RETURN VALUE:
1775: * None.
1776: *
1777: *-LEVEL:
1778: * Base or Interrupt.
1779: *
1780: *-NOTES:
1781: * Does not sleep.
1782: *
1783: * Attempting to deallocate a lock that is currently locked or is being
1784: * waited for is an error and will result in undefined behavior.
1785: *
1786: * Driver-defined basic locks, read/write locks (other than the one being
1787: * deallocated), and sleep locks may be held across calls to this
1788: * function.
1789: *
1790: *-SEE_ALSO:
1791: * RW_ALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (), RW_TRYWRLOCK (),
1792: * RW_UNLOCK (), RW_WRLOCK ()
1793: */
1794:
1795: #if __USE_PROTO__
1796: void (RW_DEALLOC) (rwlock_t * lockp)
1797: #else
1798: void
1799: RW_DEALLOC __ARGS ((lockp))
1800: rwlock_t * lockp;
1801: #endif
1802: {
1803: ASSERT (lockp != NULL);
1804: ASSERT (ATOMIC_FETCH_UCHAR (lockp->rw_locked) == 0);
1805: ASSERT (ATOMIC_FETCH_USHORT (lockp->rw_readers) == 0);
1806:
1807: ASSERT (ATOMIC_FETCH_USHORT (lockp->rw_next_ticket) ==
1808: ATOMIC_FETCH_USHORT (lockp->rw_lock_holder));
1809:
1810:
1811: /*
1812: * Remove from the list of all read/write locks and free any
1813: * statistics buffer space before freeing the lock itself.
1814: */
1815:
1816: FREE_LNODE (& lockp->rw_node, & rw_locks);
1817:
1818: _lock_free (lockp, sizeof (* lockp));
1819: }
1820:
1821:
1822: /*
1823: *-STATUS:
1824: * DDI/DKI
1825: *
1826: *-NAME:
1827: * RW_RDLOCK () Acquire a read/write lock in read mode.
1828: *
1829: *-SYNOPSIS:
1830: * #include <sys/types.h>
1831: * #include <sys/ksynch.h>
1832: *
1833: * pl_t RW_RDLOCK (rwlock_t * lockp, pl_t pl);
1834: *
1835: *-ARGUMENTS:
1836: * lockp Pointer to the read/write lock to be acquired.
1837: *
1838: * pl The interrupt priority level to be set while the lock
1839: * is held by the caller. Because some implementations
1840: * require that interrupts that might attempt to acquire
1841: * the lock be blocked on which the lock is held,
1842: * portable drivers must specify a "pl" value that is
1843: * sufficient to block out any interrupt handler that
1844: * might attempt to acquire this lock. See the
1845: * description of the "min_pl" argument to RW_ALLOC ()
1846: * for additional discussion. Implementations that do
1847: * not require that the interrupt priority level be
1848: * raised during lock acquisition may choose to ignore
1849: * this argument.
1850: *
1851: *-DESCRIPTION:
1852: * RW_RDLOCK () sets the interrupt priority level in accordance with the
1853: * value specified by "pl" (if required by the implementation) and
1854: * acquires the lock specified by "lockp". If the lock is not currently
1855: * available, the caller will wait until the lock is available in read
1856: * mode. A read/write lock is available in read mode when the lock is
1857: * not held by any context or when the lock is held by one or more
1858: * readers and there are no waiting writers. It is implementation-defined
1859: * whether the caller will block during the wait. Some implementations
1860: * may cause the caller to spin for the duration of the wait, while on
1861: * others the caller may block at some point.
1862: *
1863: *-RETURN VALUE:
1864: * Upon acquiring the lock, RW_RDLOCK () returns the previous interrupt
1865: * priority level.
1866: *
1867: *-LEVEL:
1868: * Base or Interrupt.
1869: *
1870: *-NOTES:
1871: * Read/write locks are not recursive. A call to RW_RDLOCK () attempting
1872: * to acquire a lock that is already held by the calling context may
1873: * result in deadlock.
1874: *
1875: * Calls to RD_RDLOCK () should honor the ordering defined by the lock
1876: * hierarchy [see RW_ALLOC ()] in order to avoid deadlock.
1877: *
1878: * Driver-defined sleep locks may be held across calls to this function.
1879: *
1880: * Driver-defined basic locks and read/write locks may be held across
1881: * calls to this function subject to the hierarchy and recursion
1882: * restrictions described above.
1883: *
1884: * When called from interrupt level, the "pl" argument must not specify
1885: * a priority below the level at which the interrupt handler is running.
1886: *
1887: *-SEE_ALSO:
1888: * RW_ALLOC (), RW_DEALLOC (), RW_TRYRDLOCK (), RW_TRYWRLOCK (),
1889: * RW_UNLOCK (), RW_WRLOCK ()
1890: */
1891:
1892: #if __USE_PROTO__
1893: pl_t (RW_RDLOCK) (rwlock_t * lockp, pl_t pl)
1894: #else
1895: pl_t
1896: RW_RDLOCK __ARGS ((lockp, pl))
1897: rwlock_t * lockp;
1898: pl_t pl;
1899: #endif
1900: {
1901: pl_t prev_pl;
1902: ushort_t ticket_no;
1903:
1904: ASSERT (lockp != NULL);
1905: ASSERT (splcmp (pl, plhi) <= 0);
1906:
1907:
1908: /*
1909: * Enforce minimum-priority assertion, pl >= lockp->rw_min_pl. Note
1910: * that splcmp () abstracts subtraction-for-comparison of priority
1911: * levels, which explains the form of the assertion.
1912: */
1913:
1914: ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
1915:
1916:
1917: /*
1918: * On a uniprocessor, encountering a read/write lock that is already
1919: * locked is *always* an error, even on machines with many different
1920: * interrupt priority levels. The hierarchy-assertion mechanism
1921: * cannot always deal with this, since RW_TRYRDLOCK () can acquire
1922: * locks in a different order.
1923: *
1924: * On a multiprocessor, we can just spin here.
1925: */
1926:
1927: for (;;) {
1928:
1929:
1930: /*
1931: * We block out merely the necessary interrupts at this point;
1932: * we don't need a blanket interrupt blockage since the lock
1933: * system works as atomically as possible.
1934: */
1935:
1936: prev_pl = splx (pl);
1937:
1938: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) == 0) {
1939: /*
1940: * Now we have acquired the test-and-set part, see
1941: * if there are any waiting writers preventing us
1942: * from acquiring a shared read lock.
1943: *
1944: * We read the "lock holder" and "next ticket" entries
1945: * in that sequence to be pessimistic, since we can
1946: * assume that other CPUs might be writing to this...
1947: */
1948:
1949: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
1950:
1951: if (ticket_no == ATOMIC_FETCH_USHORT (lockp->rw_next_ticket))
1952: break;
1953:
1954: /*
1955: * The read/write lock is held exclusively, release
1956: * the test-and-set sub-lock.
1957: */
1958:
1959: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
1960: }
1961:
1962: /*
1963: * We can return the interrupt priority to whatever it was
1964: * upon entry to this routine since we can't acquire the
1965: * initial test-and-set lock.
1966: */
1967:
1968: (void) splx (prev_pl);
1969:
1970: #ifdef __UNIPROCESSOR__
1971: cmn_err (CE_PANIC, "RW_RDLOCK : deadlock!");
1972: #elif defined (__TEST_AND_TEST__)
1973: /*
1974: * In order to reduce contention on the test-and-set part of
1975: * the read/write lock, we defer attempting to acquire that
1976: * lock until there appear to be no waiting writers, and until
1977: * the test-and-set lock is free before attempting to re-
1978: * acquire it. Of course, more sophisticated backoff schemes
1979: * might also help this approach.
1980: */
1981:
1982: do {
1983: /*
1984: * We use this idiom to ensure that the lock holder
1985: * item is read before the next ticket item for
1986: * maximum pessimism.
1987: */
1988:
1989: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
1990:
1991: } while (ticket_no !=
1992: ATOMIC_FETCH_USHORT (lockp->rw_next_ticket) ||
1993: ATOMIC_FETCH_UCHAR (lockp->rw_locked) != 0);
1994: #endif
1995: }
1996:
1997:
1998: /*
1999: * There are no waiting writers yet, so acquire the lock in read mode
2000: * by incrementing the count of readers.
2001: */
2002:
2003: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_readers);
2004:
2005: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_readers, ticket_no + 1)
2006: != ticket_no) {
2007: /*
2008: * If we didn't read the same number twice, then the
2009: * test-and-set lock protection isn't doing its job.
2010: */
2011:
2012: cmn_err (CE_PANIC, "RW_RDLOCK : lock increment failure");
2013: }
2014:
2015:
2016: #if 0
2017: #ifdef __UNIPROCESSOR__
2018: if (ticket_no != 0)
2019: cmn_err (CE_WARN, "RW_RDLOCK : Recursive read-lock attempt");
2020: #endif
2021: #endif
2022:
2023: /*
2024: * And allow other CPUs to try and acquire tickets or increment the
2025: * reader count by releasing the test-and-set lock.
2026: */
2027:
2028: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2029:
2030:
2031: /*
2032: * Here we check and maintain the hierarchy assertions, and record
2033: * any required debugging/statistics information about the lock.
2034: */
2035:
2036: LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
2037:
2038: TRACE_RW_LOCK (lockp);
2039:
2040:
2041: /*
2042: * Now would be an appropriate time to check that the requested level
2043: * is >= the current level on entry. Strictly speaking, this does not
2044: * have to be true if the processor is currently at base level, but
2045: * for now we'll discourage that behaviour.
2046: */
2047:
2048: ASSERT (splcmp (pl, prev_pl) >= 0);
2049:
2050: return prev_pl;
2051: }
2052:
2053:
2054: /*
2055: *-STATUS:
2056: * DDI/DKI
2057: *
2058: *-NAME:
2059: * RW_TRYRDLOCK () Try to acquire a read/write lock in read mode.
2060: *
2061: *-SYNOPSIS:
2062: * #include <sys/types.h>
2063: * #include <sys/ksynch.h>
2064: *
2065: * pl_t RW_TRYRDLOCK (rwlock_t * lockp, pl_t pl);
2066: *
2067: *-ARGUMENTS:
2068: * lockp Pointer to the read/write lock to be acquired.
2069: *
2070: * pl The interrupt priority level to be set while the lock
2071: * is held by the caller. Because some implementations
2072: * require that interrupts that might attempt to acquire
2073: * the lock be blocked on the processor on which the
2074: * lock is held, portable drivers must specify a "pl"
2075: * value that is sufficient to block out and interrupt
2076: * handler that might attempt to acquire this lock. See
2077: * the description of RW_ALLOC () for additional
2078: * discussion and a list of the valid values for "pl".
2079: * Implementations that do not require that the interrupt
2080: * priority level be raised during lock acquisition may
2081: * choose to ignore this argument.
2082: *
2083: *-DESCRIPTION:
2084: * If the lock specified by "lockp" is immediately available in read mode
2085: * (there is not a writer holding the lock and there are no waiting
2086: * writers) RW_TRYRDLOCK () sets the interrupt priority level in
2087: * accordance with the value specified by "pl" (if required by the
2088: * implementation) and acquires the lock in read mode. If the lock is not
2089: * immediately available in read mode, the function returns without
2090: * acquiring the lock.
2091: *
2092: *-RETURN VALUE:
2093: * If the lock is acquired, RW_TRYRDLOCK () returns the previous
2094: * interrupt priority level ("plbase" - "plhi"). If the lock is not
2095: * acquired the value "invpl" is returned.
2096: *
2097: *-LEVEL:
2098: * Base or Interrupt.
2099: *
2100: *-NOTES:
2101: * Does not sleep.
2102: *
2103: * RW_TRYRDLOCK () may be used to acquire a lock in a different order
2104: * from the order defined by the lock hierarchy.
2105: *
2106: * Driver-defined basic locks, read/write locks, and sleep locks may be
2107: * held across calls to this function.
2108: *
2109: * When called from interrupt level, the "pl" argument must not specify
2110: * a priority level below the level at which the interrupt handler is
2111: * running.
2112: *
2113: *-SEE_ALSO:
2114: * RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYWRLOCK (),
2115: * RW_UNLOCK (), RW_WRLOCK ()
2116: */
2117:
2118: #if __USE_PROTO__
2119: pl_t (RW_TRYRDLOCK) (rwlock_t * lockp, pl_t pl)
2120: #else
2121: pl_t
2122: RW_TRYRDLOCK __ARGS ((lockp, pl))
2123: rwlock_t * lockp;
2124: pl_t pl;
2125: #endif
2126: {
2127: pl_t prev_pl;
2128: ushort_t ticket_no;
2129:
2130: ASSERT (lockp != NULL);
2131: ASSERT (splcmp (pl, plhi) <= 0);
2132:
2133:
2134: /*
2135: * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
2136: * that splcmp () abstracts subtraction-for-comparison of priority
2137: * levels, which explains the form of the assertion.
2138: */
2139:
2140: ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
2141:
2142:
2143: #ifdef __TEST_AND_TEST__
2144: /*
2145: * We test the ticket numbers to see whether there is any reason to
2146: * even try acquiring the test-and-set lock that forms the ticket
2147: * gate.
2148: *
2149: * We read the "lock holder" and "next ticket" entries in that
2150: * sequence to be pessimistic, since we can assume that other CPUs
2151: * might be looking at this...
2152: */
2153:
2154: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
2155:
2156: if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_next_ticket))
2157: return invpl;
2158: #endif
2159:
2160:
2161: /*
2162: * We block out interrupts at this point to allow the following
2163: * operations room to do their stuff in, since interrupts at an
2164: * inappropriate moment can cause deadlock... of course, if the
2165: * definition of the lock is such that interrupts can proceed, then
2166: * that's OK, since the lock acquisition is atomic.
2167: */
2168:
2169: prev_pl = splx (pl);
2170:
2171:
2172: /*
2173: * Now would be an appropriate time to check that the requested level
2174: * is >= the current level on entry.
2175: */
2176:
2177: ASSERT (splcmp (pl, prev_pl) >= 0);
2178:
2179:
2180: /*
2181: * Test to see whether the lock in question is already taken, and if
2182: * not, we take it. We don't spin if this is a ticket lock, since if
2183: * the basic lock is taken there is *no way* that the lock will be
2184: * free for us immediately.
2185: */
2186:
2187: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) == 0) {
2188: /*
2189: * Check the ticket numbers to ensure that the lock *really*
2190: * is free.
2191: */
2192:
2193: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_next_ticket);
2194:
2195: if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_lock_holder)) {
2196:
2197: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2198: goto try_failed;
2199: }
2200:
2201: /*
2202: * Now acquire the lock in read mode by incrementing the
2203: * count of readers.
2204: */
2205:
2206: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_readers);
2207:
2208: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_readers,
2209: ticket_no + 1) != ticket_no) {
2210: /*
2211: * If we didn't read the same number twice, then the
2212: * test-and-set lock protection isn't doing its job.
2213: */
2214:
2215: cmn_err (CE_PANIC, "RW_TRYRDLOCK : Increment failure");
2216: }
2217:
2218:
2219: /*
2220: * Now we have the lock, we can release the test-and-set lock.
2221: */
2222:
2223: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2224:
2225:
2226: /*
2227: * RW_TRYRDLOCK () bypasses the hierarchy-assertion tests,
2228: * but we record the maximum acquired hierarchy level for
2229: * maximum strictness checking in inner lock attempts.
2230: *
2231: * We also record debugging and statistics information here
2232: * with TRACE_RW_LOCK ().
2233: */
2234:
2235: LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
2236:
2237: TRACE_RW_LOCK (lockp);
2238:
2239:
2240: /*
2241: * All done! Return successfully.
2242: */
2243:
2244: return prev_pl;
2245: }
2246:
2247: try_failed:
2248: /*
2249: * We cannot acquire the lock, so reset the priority and exit with
2250: * the flag value.
2251: */
2252:
2253: (void) splx (prev_pl);
2254:
2255: return invpl;
2256: }
2257:
2258:
2259: /*
2260: *-STATUS:
2261: * DDI/DKI
2262: *
2263: *-NAME:
2264: * RW_TRYWRLOCK () Try to acquire a read/write lock in write mode.
2265: *
2266: *-SYNOPSIS:
2267: * #include <sys/types.h>
2268: * #include <sys/ksynch.h>
2269: *
2270: * pl_t RW_TRYWRLOCK (rwlock_t * lockp, pl_t pl);
2271: *
2272: *-ARGUMENTS:
2273: * lockp Pointer to the read/write lock to be acquired.
2274: *
2275: * pl The interrupt priority level to be set while the lock
2276: * is held by the caller. Because some implementations
2277: * require that interrupts that might attempt to acquire
2278: * the lock be blocked on the processor on which the
2279: * lock is held, portable drivers must specify a "pl"
2280: * value that is sufficient to block out and interrupt
2281: * handler that might attempt to acquire this lock. See
2282: * the description of RW_ALLOC () for additional
2283: * discussion and a list of the valid values for "pl".
2284: * Implementations that do not require that the interrupt
2285: * priority level be raised during lock acquisition may
2286: * choose to ignore this argument.
2287: *
2288: *-DESCRIPTION:
2289: * If the lock specified by "lockp" is immediately available in write
2290: * mode (no context is holding the lock in read mode or write mode),
2291: * RW_TRYWRLOCK () sets the interrupt priority level in accordance with
2292: * the value specified by "pl" (if required by the implementation) and
2293: * acquires the lock in write mode. If the lock is not immediately
2294: * available in write mode, the function returns without acquiring the
2295: * lock.
2296: *
2297: *-RETURN VALUE:
2298: * If the lock is acquired, RW_TRYWRLOCK () returns the previous
2299: * interrupt priority level ("plbase" - "plhi"). If the lock is not
2300: * acquired the value "invpl" is returned.
2301: *
2302: *-LEVEL:
2303: * Base or Interrupt.
2304: *
2305: *-NOTES:
2306: * Does not sleep.
2307: *
2308: * RW_TRYWRLOCK () may be used to acquire a lock in a different order
2309: * from the order defined by the lock hierarchy.
2310: *
2311: * Driver-defined basic locks, read/write locks, and sleep locks may be
2312: * held across calls to this function.
2313: *
2314: * When called from interrupt level, the "pl" argument must not specify
2315: * a priority level below the level at which the interrupt handler is
2316: * running.
2317: *
2318: *-SEE_ALSO:
2319: * RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (),
2320: * RW_UNLOCK (), RW_WRLOCK ()
2321: */
2322:
2323: #if __USE_PROTO__
2324: pl_t (RW_TRYWRLOCK) (rwlock_t * lockp, pl_t pl)
2325: #else
2326: pl_t
2327: RW_TRYWRLOCK __ARGS ((lockp, pl))
2328: rwlock_t * lockp;
2329: pl_t pl;
2330: #endif
2331: {
2332: pl_t prev_pl;
2333: ushort_t ticket_no;
2334:
2335: ASSERT (lockp != NULL);
2336: ASSERT (splcmp (pl, plhi) <= 0);
2337:
2338:
2339: /*
2340: * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
2341: * that splcmp () abstracts subtraction-for-comparison of priority
2342: * levels, which explains the form of the assertion.
2343: */
2344:
2345: ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
2346:
2347:
2348: #ifdef __TEST_AND_TEST__
2349: /*
2350: * We test the ticket numbers and reader count to see whether there
2351: * is any reason to even try acquiring the test-and-set lock that
2352: * forms the ticket gate.
2353: *
2354: * We read the "lock holder" and "next ticket" entries in that
2355: * sequence to be pessimistic, since we can assume that other CPUs
2356: * might be looking at this...
2357: */
2358:
2359: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
2360:
2361: if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_next_ticket) ||
2362: ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0)
2363: return invpl;
2364: #endif
2365:
2366:
2367: /*
2368: * We block out interrupts at this point to allow the following
2369: * operations room to do their stuff in, since interrupts at an
2370: * inappropriate moment can cause deadlock... of course, if the
2371: * definition of the lock is such that interrupts can proceed, then
2372: * that's OK, since the lock acquisition is atomic.
2373: */
2374:
2375: prev_pl = splx (pl);
2376:
2377:
2378: /*
2379: * Now would be an appropriate time to check that the requested level
2380: * is >= the current level on entry.
2381: */
2382:
2383: ASSERT (splcmp (pl, prev_pl) >= 0);
2384:
2385:
2386: /*
2387: * Test to see whether the lock in question is already taken, and if
2388: * not, we take it. We don't spin if this is a ticket lock, since if
2389: * the basic lock is taken there is *no way* that the lock will be
2390: * free for us immediately.
2391: */
2392:
2393: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) == 0) {
2394: /*
2395: * Check the ticket numbers and the reader count to ensure
2396: * that the lock *really* is free.
2397: */
2398:
2399: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_next_ticket);
2400:
2401: if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_lock_holder) ||
2402: ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0) {
2403:
2404: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2405: goto try_failed;
2406: }
2407:
2408: /*
2409: * Now acquire the lock in write mode by incrementing the
2410: * ticket counter.
2411: */
2412:
2413: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_next_ticket,
2414: ticket_no + 1) != ticket_no) {
2415: /*
2416: * If we didn't read the same number twice, then the
2417: * test-and-set lock protection isn't doing its job.
2418: */
2419:
2420: cmn_err (CE_PANIC, "RW_TRYWRLOCK : Increment failure");
2421: }
2422:
2423:
2424: /*
2425: * Now we have the lock, we can release the test-and-set lock.
2426: */
2427:
2428: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2429:
2430:
2431: /*
2432: * RW_TRYWRLOCK () bypasses the hierarchy-assertion tests,
2433: * but we record the maximum acquired hierarchy level for
2434: * maximum strictness checking in inner lock attempts.
2435: *
2436: * We also record and debugging and statistics information
2437: * here with TRACE_RW_LOCK ().
2438: */
2439:
2440: LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
2441:
2442: TRACE_RW_LOCK (lockp);
2443:
2444:
2445: /*
2446: * All done! Return success...
2447: */
2448:
2449: return prev_pl;
2450: }
2451:
2452: try_failed:
2453: /*
2454: * We cannot acquire the lock, so reset the priority and exit with
2455: * the flag value.
2456: */
2457:
2458: (void) splx (prev_pl);
2459:
2460: return invpl;
2461: }
2462:
2463:
2464: /*
2465: *-STATUS:
2466: * DDI/DKI
2467: *
2468: *-NAME:
2469: * RW_UNLOCK () Release a read/write lock.
2470: *
2471: *-SYNOPSIS:
2472: * #include <sys/types.h>
2473: * #include <sys/ksynch.h>
2474: *
2475: * pl_t RW_UNLOCK (rwlock_t * lockp, pl_t pl);
2476: *
2477: *-ARGUMENTS:
2478: * lockp Pointer to the read/write lock to be released.
2479: *
2480: * pl The interrupt priority level to be set after releasing
2481: * the lock. See the description of the "min_pl" argument
2482: * to RW_ALLOC () for a list of the valid values for
2483: * "pl". If lock calls are not being nested or if the
2484: * caller is unlocking in the reverse order that locks
2485: * were acquired, the "pl" argument will typically be the
2486: * value that was returned from the corresponding call to
2487: * acquire the lock. The caller may need to specify a
2488: * different value for "pl" if nested locks are being
2489: * released in some order other that the reverse order of
2490: * acquisition, so as to ensure that the interrupt
2491: * priority level is kept sufficiently high to block
2492: * interrupt code that might attempt to acquire locks
2493: * which are still held. Although portable drivers must
2494: * always specify an appropriate "pl" argument,
2495: * implementations which do not require that the
2496: * interrupt priority level be raised during lock
2497: * acquisition may choose to ignore this argument.
2498: *
2499: *-DESCRIPTION:
2500: * RW_UNLOCK () releases the basic lock specified by "lockp" and then
2501: * sets the interrupt priority level in accordance with the value
2502: * specified by "pl" (if required by the implementation).
2503: *
2504: *-RETURN VALUE:
2505: * None.
2506: *
2507: *-LEVEL:
2508: * Base or Interrupt.
2509: *
2510: *-NOTES:
2511: * Does not sleep.
2512: *
2513: * Driver-defined basic locks, read/write locks, and sleep locks may be
2514: * held across calls to this function.
2515: *
2516: *-SEE_ALSO:
2517: * RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (),
2518: * RW_TRYWRLOCK (), RW_WRLOCK ()
2519: */
2520:
2521: #if __USE_PROTO__
2522: void (RW_UNLOCK) (rwlock_t * lockp, pl_t pl)
2523: #else
2524: void
2525: RW_UNLOCK __ARGS ((lockp, pl))
2526: rwlock_t * lockp;
2527: pl_t pl;
2528: #endif
2529: {
2530: ushort_t ticket_no;
2531:
2532: ASSERT (lockp != NULL);
2533: ASSERT (splcmp (plbase, pl) <= 0 && splcmp (pl, plhi) <= 0);
2534:
2535:
2536: /*
2537: * Undo whatever the hierarchy-assertion and debugging/statistics
2538: * mechanisms do.
2539: */
2540:
2541: LOCK_FREE_HIERARCHY (lockp->rw_hierarchy);
2542:
2543: UNTRACE_RW_LOCK (lockp);
2544:
2545:
2546: /*
2547: * Now release the lock... since writers have to wait for all readers
2548: * to release the lock, if there any readers then we are releasing
2549: * in read mode.
2550: */
2551:
2552: if (ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0) {
2553: /*
2554: * In order to safely decrement the reader count, we have to
2555: * acquire the test-and-set lock in the absence of an
2556: * atomic decrement facility.
2557: */
2558:
2559: while (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) != 0) {
2560:
2561: #ifdef __UNIPROCESSOR__
2562: cmn_err (CE_PANIC, "RW_UNLOCK : deadlock!");
2563: #elif defined (__TEST_AND_TEST__)
2564: /*
2565: * To reduce contention, we wait until the test-and-
2566: * set lock is free before attempting to re-acquire
2567: * it.
2568: */
2569:
2570: while (ATOMIC_FETCH_UCHAR (lockp->rw_locked) != 0)
2571: /* DO NOTHING */;
2572: #endif
2573: }
2574:
2575: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_readers);
2576:
2577: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_readers,
2578: ticket_no - 1) != ticket_no ) {
2579: /*
2580: * If we didn't read the same number twice, then the
2581: * test-and-set lock protection isn't doing its job.
2582: */
2583:
2584: cmn_err (CE_PANIC, "RW_UNLOCK : Decrement failure");
2585: }
2586:
2587: /*
2588: * Now free the test-and-set lock.
2589: */
2590:
2591: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2592:
2593: } else if (ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder),
2594: ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_next_ticket)) {
2595: /*
2596: * Release the lock to the next ticket holder or the waiting
2597: * readers if there are no waiting ticket-holders.
2598: */
2599:
2600:
2601: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_lock_holder,
2602: ticket_no + 1) != ticket_no ) {
2603: /*
2604: * If we didn't read the same number twice, then the
2605: * test-and-set lock protection isn't doing its job.
2606: */
2607:
2608: cmn_err (CE_PANIC, "RW_UNLOCK : Increment failure");
2609: }
2610:
2611: } else
2612: cmn_err (CE_PANIC, "RW_UNLOCK : not locked");
2613:
2614:
2615: /*
2616: * And lower out priority level to finish up.
2617: */
2618:
2619: (void) splx (pl);
2620: }
2621:
2622:
2623: /*
2624: *-STATUS:
2625: * DDI/DKI
2626: *
2627: *-NAME:
2628: * RW_WRLOCK () Acquire a read/write lock in write mode.
2629: *
2630: *-SYNOPSIS:
2631: * #include <sys/types.h>
2632: * #include <sys/ksynch.h>
2633: *
2634: * pl_t RW_WRLOCK (rwlock_t * lockp, pl_t pl);
2635: *
2636: *-ARGUMENTS:
2637: * lockp Pointer to the read/write lock to be acquired.
2638: *
2639: * pl The interrupt priority level to be set while the lock
2640: * is held by the caller. Because some implementations
2641: * require that interrupts that might attempt to acquire
2642: * the lock be blocked on which the lock is held,
2643: * portable drivers must specify a "pl" value that is
2644: * sufficient to block out any interrupt handler that
2645: * might attempt to acquire this lock. See the
2646: * description of the "min_pl" argument to RW_ALLOC ()
2647: * for additional discussion. Implementations that do
2648: * not require that the interrupt priority level be
2649: * raised during lock acquisition may choose to ignore
2650: * this argument.
2651: *
2652: *-DESCRIPTION:
2653: * RW_WRLOCK () sets the interrupt priority level in accordance with the
2654: * value specified by "pl" (if required by the implementation) and
2655: * acquires the lock specified by "lockp". If the lock is not currently
2656: * available, the caller will wait until the lock is available in write
2657: * mode. A read/write lock is available in write mode when the lock is
2658: * not held by any context. It is implementation-defined whether the
2659: * caller will block during the wait. Some implementations may cause the
2660: * caller to spin for the duration of the wait, while on others the
2661: * caller may block at some point.
2662: *
2663: *-RETURN VALUE:
2664: * Upon acquiring the lock, RW_WRLOCK () returns the previous interrupt
2665: * priority level.
2666: *
2667: *-LEVEL:
2668: * Base or Interrupt.
2669: *
2670: *-NOTES:
2671: * Read/write locks are not recursive. A call to RW_WRLOCK () attempting
2672: * to acquire a lock that is already held by the calling context may
2673: * result in deadlock.
2674: *
2675: * Calls to RD_WRLOCK () should honor the ordering defined by the lock
2676: * hierarchy [see RW_ALLOC ()] in order to avoid deadlock.
2677: *
2678: * Driver-defined sleep locks may be held across calls to this function.
2679: *
2680: * Driver-defined basic locks and read/write locks may be held across
2681: * calls to this function subject to the hierarchy and recursion
2682: * restrictions described above.
2683: *
2684: * When called from interrupt level, the "pl" argument must not specify
2685: * a priority below the level at which the interrupt handler is running.
2686: *
2687: *-SEE_ALSO:
2688: * RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (),
2689: * RW_TRYWRLOCK (), RW_UNLOCK ()
2690: */
2691:
2692: #if __USE_PROTO__
2693: pl_t (RW_WRLOCK) (rwlock_t * lockp, pl_t pl)
2694: #else
2695: pl_t
2696: RW_WRLOCK __ARGS ((lockp, pl))
2697: rwlock_t * lockp;
2698: pl_t pl;
2699: #endif
2700: {
2701: pl_t prev_pl;
2702: ushort_t ticket_no;
2703:
2704: ASSERT (lockp != NULL);
2705: ASSERT (splcmp (pl, plhi) <= 0);
2706:
2707:
2708: /*
2709: * Enforce minimum-priority assertion, pl >= lockp->rw_min_pl. Note
2710: * that splcmp () abstracts subtraction-for-comparison of priority
2711: * levels, which explains the form of the assertion.
2712: */
2713:
2714: ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
2715:
2716:
2717: /*
2718: * On a uniprocessor, encountering a read/write lock that is already
2719: * locked is *always* an error, even on machines with many different
2720: * interrupt priority levels. The hierarchy-assertion mechanism
2721: * cannot always deal with this, since RW_TRYRDLOCK () can acquire
2722: * locks in a different order.
2723: *
2724: * On a multiprocessor, we can just spin here. Note that since LOCK ()
2725: * is defined as requiring values of "pl" greater than the current
2726: * interrupt priority level, the use of splraise () by
2727: * TEST_AND_SET_LOCK () is legitimate.
2728: */
2729:
2730: prev_pl = TEST_AND_SET_LOCK (lockp->rw_locked, pl, "RW_WRLOCK");
2731:
2732:
2733: /*
2734: * Take a ticket...
2735: */
2736:
2737: ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_next_ticket);
2738:
2739: if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_next_ticket,
2740: ticket_no + 1) != ticket_no) {
2741: /*
2742: * If we didn't read the same number twice, then the
2743: * test-and-set lock protection isn't doing its job.
2744: */
2745:
2746: cmn_err (CE_PANIC, "RW_WRLOCK : ticket increment failure");
2747: }
2748:
2749:
2750: /*
2751: * Allow other CPUs access to the lock data structures by releasing
2752: * the test-and-set lock.
2753: */
2754:
2755: ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
2756:
2757:
2758: /*
2759: * Now, let's wait for our number to come up and for all the readers
2760: * to release their shared locks.
2761: */
2762:
2763: while (ATOMIC_FETCH_USHORT (lockp->rw_lock_holder) != ticket_no ||
2764: ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0) {
2765: /*
2766: * At this point we might want to implement some form of
2767: * proportional backoff to reduce memory traffic. Later.
2768: *
2769: * Another hot contender for this spot is detecting failures
2770: * on other CPUs...
2771: */
2772:
2773: #ifdef __UNIPROCESSOR__
2774: cmn_err (CE_PANIC, "RW_WRLOCK : deadlock on ticket");
2775: #endif
2776: }
2777:
2778:
2779: /*
2780: * Now would be an appropriate time to check that the requested level
2781: * is >= the current level on entry. Strictly speaking, this does not
2782: * have to be true if the processor is currently at base level, but
2783: * for now we'll discourage that behaviour.
2784: */
2785:
2786: ASSERT (splcmp (pl, prev_pl) >= 0);
2787:
2788:
2789: /*
2790: * Test the lock-acquisition-hierarchy assertions.
2791: */
2792:
2793: ASSERT (ddi_cpu_data ()->dc_max_hierarchy < lockp->rw_hierarchy);
2794:
2795: LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
2796:
2797:
2798: /*
2799: * Since it may be useful for post-mortem debugging to record some
2800: * information about the context which acquired the lock, we defer
2801: * to some generic recorder function or macro.
2802: *
2803: * Note that in general it does not appear to be possible to make
2804: * detailed assertions about the relation between the contexts in
2805: * which a lock is acquired and/or released. In particular, it
2806: * might be possible for a basic lock to be tied to some device
2807: * hardware-related operation where a lock might be acquired on one
2808: * CPU and released on another.
2809: *
2810: * In addition, any lock statistics are kept by this operation.
2811: */
2812:
2813: TRACE_RW_LOCK (lockp);
2814:
2815: return prev_pl;
2816: }
2817:
2818:
2819: /*
2820: *-STATUS:
2821: * DDI/DKI
2822: *
2823: *-NAME:
2824: * SLEEP_ALLOC () Allocate and initialize a sleep lock.
2825: *
2826: *-SYNOPSIS:
2827: * #include <sys/types.h>
2828: * #include <sys/kmem.h>
2829: * #include <sys/ksynch.h>
2830: *
2831: * sleep_t * SLEEP_ALLOC (int arg, lkinfo_t * lkinfop, int flag);
2832: *
2833: *-ARGUMENTS:
2834: * arg Placeholder for future use. "arg" must be equal to
2835: * zero.
2836: *
2837: *
2838: * lkinfop Pointer to a lkinfo structure. The lk_name member of
2839: * the lkinfo structure points to a character string
2840: * defining a name that will be associated with the lock
2841: * for the purposes of statistics gathering. The name
2842: * should begin with the driver prefix and should be
2843: * unique to the lock or group of locks for which the
2844: * driver wishes to collect a uniquely identifiable set
2845: * of statistics (ie, if a given name is shared by a
2846: * group of locks, the statistics of the individual locks
2847: * within the group will not be uniquely identifiable).
2848: *
2849: * The only bit flag currently specified within the
2850: * "lk_flags" member of the lkinfo structure is the
2851: * LK_NOSTATS flag, which specifies that statistics are
2852: * not to be collected for this particular lock.
2853: *
2854: * A given lkinfo structure may be shared among multiple
2855: * sleep but a lkinfo structure may not be shared between
2856: * a sleep lock and a basic or read/write lock. The
2857: * called must ensure that the "lk_pad" member of the
2858: * "lkinfo" structure is zeroed out before passing it to
2859: * SLEEP_ALLOC ().
2860: *
2861: * flag Specifies whether the caller is willing to sleep
2862: * waiting for memory. If "flag" is set to KM_SLEEP, the
2863: * caller will sleep if necessary until sufficient memory
2864: * is available. If "flag" is set to KM_NOSLEEP, the
2865: * caller will not sleep, but SLEEP_ALLOC () will return
2866: * NULL if sufficient memory is not immediately
2867: * available.
2868: *
2869: *-DESCRIPTION:
2870: * SLEEP_ALLOC () dynamically allocates and initialises an instance of a
2871: * sleep lock. The lock is initialised to the unlocked state.
2872: *
2873: *-RETURN VALUE:
2874: * Upon successful completion, SLEEP_ALLOC () returns a pointer to the
2875: * newly allocated lock. If KM_NOSLEEP is specified and sufficient
2876: * memory is not immediately available, SLEEP_ALLOC () returns a NULL
2877: * pointer.
2878: *
2879: *-LEVEL:
2880: * Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
2881: * set to KM_NOSLEEP.
2882: *
2883: *-NOTES:
2884: * May sleep if "flag" is set to KM_NOSLEEP.
2885: *
2886: * Driver-defined basic locks and read/write locks may be held across
2887: * calls to this function if "flag" is set to KM_NOSLEEP but may not be
2888: * held if "flag" is KM_SLEEP.
2889: *
2890: * Driver-defined sleep locks may be held across calls to this function
2891: * regardless of the value of "flag".
2892: *
2893: *-SEE_ALSO:
2894: * SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
2895: * SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (),
2896: * SLEEP_UNLOCK (), lkinfo
2897: */
2898:
2899: #if __USE_PROTO__
2900: sleep_t * (SLEEP_ALLOC) (int arg, lkinfo_t * lkinfop, int flag)
2901: #else
2902: sleep_t *
2903: SLEEP_ALLOC __ARGS ((arg, lkinfop, flag))
2904: int arg;
2905: lkinfo_t * lkinfop;
2906: int flag;
2907: #endif
2908: {
2909: sleep_t * lockp;
2910:
2911: ASSERT (arg == 0);
2912: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
2913: ASSERT (lkinfop != NULL);
2914:
2915:
2916: /*
2917: * Allocate and initialise the data, possibly waiting for enough
2918: * memory to become available.
2919: */
2920:
2921: if ((lockp = (sleep_t *) _lock_malloc (sizeof (* lockp),
2922: flag)) != NULL) {
2923: INIT_LNODE (& lockp->sl_node, lkinfop, & sleep_locks, flag);
2924: PLIST_INIT (lockp->sl_plist);
2925: }
2926:
2927: return lockp;
2928: }
2929:
2930:
2931: /*
2932: *-STATUS:
2933: * DDI/DKI
2934: *
2935: *-NAME:
2936: * SLEEP_DEALLOC () Deallocate an instance of a sleep lock.
2937: *
2938: *-SYNOPSIS:
2939: * #include <sys/ksynch.h>
2940: *
2941: * void SLEEP_DEALLOC (sleep_t * lockp);
2942: *
2943: *-ARGUMENTS:
2944: * lockp Pointer to the sleep lock to be deallocated.
2945: *
2946: *-DESCRIPTION:
2947: * SLEEP_DEALLOC () deallocates the sleep lock specified by "lockp".
2948: *
2949: *-RETURN VALUE:
2950: * None.
2951: *
2952: *-LEVEL:
2953: * Base or Interrupt.
2954: *
2955: *-NOTES:
2956: * Does not sleep.
2957: *
2958: * Attempting to deallocate a lock that is currently locked or is being
2959: * waited for is an error and will result in undefined behavior.
2960: *
2961: * Driver-defined basic locks, read/write locks, and sleep locks (other
2962: * than the one being deallocated) may be held across calls to this
2963: * function.
2964: *
2965: *-SEE_ALSO:
2966: * SLEEP_ALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (), SLEEP_LOCKAVAIL (),
2967: * SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (), SLEEP_UNLOCK ()
2968: */
2969:
2970: #if __USE_PROTO__
2971: void (SLEEP_DEALLOC) (sleep_t * lockp)
2972: #else
2973: void
2974: SLEEP_DEALLOC __ARGS ((lockp))
2975: sleep_t * lockp;
2976: #endif
2977: {
2978: ASSERT (lockp != NULL);
2979:
2980: /*
2981: * Remove from the list of all sleep locks and free any statistics
2982: * buffer space before freeing the lock itself.
2983: */
2984:
2985: PLIST_DESTROY (lockp->sl_plist);
2986:
2987: FREE_LNODE (& lockp->sl_node, & sleep_locks);
2988:
2989: _lock_free (lockp, sizeof (* lockp));
2990: }
2991:
2992:
2993: /*
2994: *-STATUS:
2995: * DDI/DKI
2996: *
2997: *-NAME:
2998: * SLEEP_LOCK () Acquire a sleep lock.
2999: *
3000: *-SYNOPSIS:
3001: * #include <sys/ksynch.h>
3002: *
3003: * void SLEEP_LOCK (sleep_t * lockp, int priority);
3004: *
3005: *-ARGUMENTS:
3006: * lockp Pointer to the sleep lock to be acquired.
3007: *
3008: * priority A hint to the scheduling policy as to the relative
3009: * priority the caller wishes to be assigned while
3010: * running in the kernel after waking up. The valid
3011: * values for this argument are as follows:
3012: *
3013: * pridisk Priority appropriate for disk driver
3014: * prinet Priority appropriate for network driver.
3015: * pritty Priority appropriate for terminal driver.
3016: * pritape Priority appropriate for tape driver.
3017: * prihi High priority.
3018: * primed Medium priority.
3019: * prilo Low priority.
3020: *
3021: * Drivers may use these values to request a priority
3022: * appropriate to a given type of device or to request a
3023: * priority that is high, medium or low relative to other
3024: * activities within the kernel.
3025: *
3026: * It is also permissible to specify positive or negative
3027: * offsets from the values defined above. Positive
3028: * offsets result in favourable priority. The maximum
3029: * allowable offset in all cases is 3 (eg. pridisk+3
3030: * and pridisk-3 are valid values by pridisk+4 and
3031: * pridisk-4 are not valid). Offsets can be useful in
3032: * defining the relative importance of different locks or
3033: * resources that may be hald by a given driver. In
3034: * general, a higher relative priority should be used
3035: * when the caller is attempting to acquire a highly-
3036: * contended lock or resource, or when the caller is
3037: * already holding one or more locks or kernel resources
3038: * upon entry to SLEEP_LOCK ().
3039: *
3040: * The exact semantics of the "priority" argument is
3041: * specific to the scheduling class of the caller, and
3042: * some scheduling classes may choose to ignore the
3043: 8 argument for the purposes of assigning a scheduling
3044: * priority.
3045: *
3046: *-DESCRIPTION:
3047: * SLEEP_LOCK () acquires the sleep lock specified by "lockp". If the
3048: * lock is not immediately available, the caller is put to sleep (the
3049: * caller's execution is suspended and other processes may be scheduled)
3050: * until the lock becomes available to the caller, at which point the
3051: * caller wakes up and returns with the lock held.
3052: *
3053: * The caller will not be interrupted by signals while sleeping inside
3054: * SLEEP_LOCK ().
3055: *
3056: *-RETURN VALUE:
3057: * None.
3058: *
3059: *-LEVEL:
3060: * Base level only.
3061: *
3062: *-NOTES:
3063: * May sleep.
3064: *
3065: * Sleep locks are not recursive. A call to SLEEP_LOCK () attempting to
3066: * acquire a lock that is currently held by the calling context will
3067: * result in deadlock.
3068: *
3069: * Driver-defined basic locks and read/write locks may not be held across
3070: * calls to this function.
3071: *
3072: * Driver-defined sleep locks may be held across calls to this function
3073: * subject to the recursion restrictions described above.
3074: *
3075: *-SEE_ALSO:
3076: * SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK_SIG (),
3077: * SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (),
3078: * SLEEP_UNLOCK ()
3079: */
3080:
3081: #if __USE_PROTO__
3082: void (SLEEP_LOCK) (sleep_t * lockp, int priority)
3083: #else
3084: void
3085: SLEEP_LOCK __ARGS ((lockp, priority))
3086: sleep_t * lockp;
3087: int priority;
3088: #endif
3089: {
3090: pl_t prev_pl;
3091:
3092: ASSERT (lockp != NULL);
3093: ASSERT_BASE_LEVEL ();
3094:
3095:
3096: /*
3097: * Take the path of least resistance; if the sleep lock is not
3098: * currently held, then just acquire it and get out.
3099: */
3100:
3101: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) == 0) {
3102: /*
3103: * We successfully acquired it! Just leave after writing in
3104: * the info for SLEEP_LOCKAVAIL ().
3105: */
3106:
3107: lockp->sl_holder = PROC_HANDLE ();
3108: return;
3109: }
3110:
3111:
3112: /*
3113: * OK, we do it the hard way.
3114: *
3115: * The sleep lock might have been unlocked while we waited to lock
3116: * the process list, so we retest the item.
3117: */
3118:
3119: prev_pl = PLIST_LOCK (lockp->sl_plist, "SLEEP_LOCK");
3120:
3121: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) != 0) {
3122: /*
3123: * No, we need to wait. Note the cast to void... we assume
3124: * that MAKE_SLEEPING () will filter out all improper attempts
3125: * to wake us.
3126: *
3127: * We assert that whoever woke us up will have left the sleep
3128: * locked in the "locked" state for us. While *we* won't have
3129: * the process-list locked, someone else might so we can't
3130: * make an assertion on that.
3131: */
3132:
3133: (void) MAKE_SLEEPING (lockp->sl_plist, priority,
3134: SLEEP_NO_SIGNALS);
3135:
3136: ASSERT (lockp->sl_holder == PROC_HANDLE ());
3137: ASSERT (ATOMIC_FETCH_UCHAR (lockp->sl_locked) != 0);
3138:
3139: (void) splx (prev_pl);
3140: } else {
3141: /*
3142: * Write the owner information for SLEEP_LOCKOWNED () and
3143: * release the test-and-set lock on the process list.
3144: */
3145:
3146: lockp->sl_holder = PROC_HANDLE ();
3147:
3148: PLIST_UNLOCK (lockp->sl_plist, prev_pl);
3149: }
3150: }
3151:
3152:
3153: /*
3154: *-STATUS:
3155: * DDI/DKI
3156: *
3157: *-NAME:
3158: * SLEEP_LOCKAVAIL () Query whether a sleep lock is available.
3159: *
3160: *-SYNOPSIS:
3161: * #include <sys/types.h>
3162: * #include <sys/ksynch.h>
3163: *
3164: * bool_t SLEEP_LOCKAVAIL (sleep_t * lockp);
3165: *
3166: *-ARGUMENTS:
3167: * lockp Pointer to the sleep lock to be queried.
3168: *
3169: *-DESCRIPTION:
3170: * SLEEP_LOCKAVAIL () returns an indication of whether the sleep lock
3171: * specified by "lockp" is currently available.
3172: *
3173: * The state of the lock may change and the value returned may no longer
3174: * be valid by the time the caller sees it. The caller is expected to
3175: * understand that this is "stale data" and is either using it as a
3176: * heuristic or has arranged for the data to be meaningful by other
3177: * means.
3178: *
3179: *-RETURN VALUE:
3180: * SLEEP_LOCKAVAIL () returns TRUE (a non-zero value) if the lock was
3181: * available or FALSE (zero) if the lock was not available.
3182: *
3183: *-LEVEL:
3184: * Base or Interrupt.
3185: *
3186: *-NOTES:
3187: * Does not sleep.
3188: *
3189: * Driver-defined basic locks, read/write locks and sleep locks may be
3190: * held across calls to this function.
3191: *
3192: *-SEE_ALSO:
3193: * SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
3194: * SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (), SLEEP_UNLOCK ()
3195: */
3196:
3197: #if __USE_PROTO__
3198: bool_t (SLEEP_LOCKAVAIL) (sleep_t * lockp)
3199: #else
3200: bool_t
3201: SLEEP_LOCKAVAIL __ARGS ((lockp))
3202: sleep_t * lockp;
3203: #endif
3204: {
3205: ASSERT (lockp != NULL);
3206:
3207: return ATOMIC_FETCH_UCHAR (lockp->sl_locked) == 0;
3208: }
3209:
3210:
3211: /*
3212: *-STATUS:
3213: * DDI/DKI
3214: *
3215: *-NAME:
3216: * SLEEP_LOCKOWNED () Query whether a sleep lock is held by the caller.
3217: *
3218: *-SYNOPSIS:
3219: * #include <sys/types.h>
3220: * #include <sys/ksynch.h>
3221: *
3222: * bool_t SLEEP_LOCKOWNED (sleep_t * lockp);
3223: *
3224: *-ARGUMENTS:
3225: * lockp Pointer to the sleep lock to be queried.
3226: *
3227: *-DESCRIPTION:
3228: * SLEEP_LOCKOWNED () returns an indication of whether the sleep lock
3229: * specified by "lockp" is held by the calling context.
3230: *
3231: * SLEEP_LOCKOWNED () is intended for use only within ASSERT ()
3232: * expressions [see ASSERT ()] and other code that is conditionally
3233: * compiled under the DEBUG compilation option. The SLEEP_LOCKOWNED ()
3234: * function is only defined under the DEBUG compilation option, and
3235: * therefore calls to SLEEP_LOCKOWNED () will not compile when DEBUG is
3236: * not defined.
3237: *
3238: *-RETURN VALUE:
3239: * SLEEP_LOCKOWNED () returns TRUE (a non-zero value) if the lock is
3240: * currently held by the calling context or FALSE (zero) if the lock is
3241: * not currently held by the calling context.
3242: *
3243: *-LEVEL:
3244: * Base or Interrupt.
3245: *
3246: *-NOTES:
3247: * Does not sleep.
3248: *
3249: * Driver-defined basic locks, read/write locks and sleep locks may be
3250: * held across calls to this function.
3251: *
3252: *-SEE_ALSO:
3253: * SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
3254: * SLEEP_LOCKAVAIL (), SLEEP_TRYLOCK (), SLEEP_UNLOCK ()
3255: */
3256:
3257: #if __USE_PROTO__
3258: bool_t (SLEEP_LOCKOWNED) (sleep_t * lockp)
3259: #else
3260: bool_t
3261: SLEEP_LOCKOWNED __ARGS ((lockp))
3262: sleep_t * lockp;
3263: #endif
3264: {
3265: ASSERT (lockp != NULL);
3266:
3267: return lockp->sl_holder == PROC_HANDLE ();
3268: }
3269:
3270:
3271: /*
3272: *-STATUS:
3273: * DDI/DKI
3274: *
3275: *-NAME:
3276: * SLEEP_LOCK_SIG () Acquire a sleep lock.
3277: *
3278: *-SYNOPSIS:
3279: * #include <sys/types.h>
3280: * #include <sys/ksynch.h>
3281: *
3282: * bool_t SLEEP_LOCK_SIG (sleep_t * lockp, int priority);
3283: *
3284: *-ARGUMENTS:
3285: * lockp Pointer to the sleep lock to be acquired.
3286: *
3287: * priority A hint to the scheduling policy as to the relative
3288: * priority the caller wishes to be assigned while
3289: * running in the kernel after waking up. The valid
3290: * values for this argument are as follows:
3291: *
3292: * pridisk Priority appropriate for disk driver
3293: * prinet Priority appropriate for network driver.
3294: * pritty Priority appropriate for terminal driver.
3295: * pritape Priority appropriate for tape driver.
3296: * prihi High priority.
3297: * primed Medium priority.
3298: * prilo Low priority.
3299: *
3300: * Drivers may use these values to request a priority
3301: * appropriate to a given type of device or to request a
3302: * priority that is high, medium or low relative to other
3303: * activities within the kernel.
3304: *
3305: * It is also permissible to specify positive or negative
3306: * offsets from the values defined above. Positive
3307: * offsets result in favourable priority. The maximum
3308: * allowable offset in all cases is 3 (eg. pridisk+3
3309: * and pridisk-3 are valid values by pridisk+4 and
3310: * pridisk-4 are not valid). Offsets can be useful in
3311: * defining the relative importance of different locks or
3312: * resources that may be hald by a given driver. In
3313: * general, a higher relative priority should be used
3314: * when the caller is attempting to acquire a highly-
3315: * contended lock or resource, or when the caller is
3316: * already holding one or more locks or kernel resources
3317: * upon entry to SLEEP_LOCK_SIG ().
3318: *
3319: * The exact semantics of the "priority" argument to the
3320: * scheduling class of the caller, and some scheduling
3321: * classes may choose to ignore the argument for the
3322: * purposes of assigning a scheduling priority.
3323: *
3324: *-DESCRIPTION:
3325: * SLEEP_LOCK_SIG () acquires the sleep lock specified by "lockp". If the
3326: * lock is not immediately available, the caller is put to sleep (the
3327: * caller's execution is suspended and other processes may be scheduled)
3328: * until the lock becomes available to the caller, at which point the
3329: * caller wakes up and returns with the lock held.
3330: *
3331: * SLEEP_LOCK_SIG () may be interrupted by a signal, in which case it may
3332: * return early without acquiring the lock.
3333: *
3334: * If the function is interrupted by a job control stop signal (eg
3335: * SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU) which results in the caller
3336: * entering a stopped state, the SLEEP_LOCK_SIG () function will
3337: * transparently retry the lock operation upon continuing (the caller
3338: * will not return without the lock).
3339: *
3340: * If the function is interrupted by a signal other than a job control
3341: * signal, or by a job control signal that does not result in the caller
3342: * stopping (because the signal has a non-default disposition), the
3343: * SLEEP_LOCK_SIG () function will return early without acquiring the
3344: * lock.
3345: *
3346: *-RETURN VALUE:
3347: * SLEEP_LOCK_SIG () returns TRUE (a non-zero value) if the lock is
3348: * successfully acquired or FALSE (zero) if the function returned early
3349: * because of a signal.
3350: *
3351: *-LEVEL:
3352: * Base level only.
3353: *
3354: *-NOTES:
3355: * May sleep.
3356: *
3357: * Sleep locks are not recursive. A call to SLEEP_LOCK_SIG () attempting
3358: * to acquire a lock that is currently held by the calling context will
3359: * result in deadlock.
3360: *
3361: * Driver-defined basic locks and read/write locks may not be held across
3362: * calls to this function.
3363: *
3364: * Driver-defined sleep locks may be held across calls to this function
3365: * subject to the recursion restrictions described above.
3366: *
3367: *-SEE_ALSO:
3368: * SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCKAVAIL (),
3369: * SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (), SLEEP_UNLOCK (), signals
3370: */
3371:
3372: #if __USE_PROTO__
3373: bool_t (SLEEP_LOCK_SIG) (sleep_t * lockp, int priority)
3374: #else
3375: bool_t
3376: SLEEP_LOCK_SIG __ARGS ((lockp, priority))
3377: sleep_t * lockp;
3378: int priority;
3379: #endif
3380: {
3381: pl_t prev_pl;
3382:
3383: ASSERT (lockp != NULL);
3384: ASSERT_BASE_LEVEL ();
3385:
3386: /*
3387: * Take the path of least resistance; if the sleep lock is not
3388: * currently held, then just acquire it and get out.
3389: */
3390:
3391: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) == 0) {
3392: /*
3393: * We successfully acquired it! Just leave after writing in
3394: * the info for SLEEP_LOCKAVAIL ().
3395: */
3396:
3397: lockp->sl_holder = PROC_HANDLE ();
3398: return TRUE;
3399: }
3400:
3401:
3402: /*
3403: * OK, we do it the hard way.
3404: *
3405: * The sleep lock might have been unlocked while we waited to lock
3406: * the process list, so we retest that member.
3407: */
3408:
3409: prev_pl = PLIST_LOCK (lockp->sl_plist, "SLEEP_LOCK");
3410:
3411: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) != 0) {
3412: /*
3413: * No, we need to wait.
3414: */
3415:
3416: if (MAKE_SLEEPING (lockp->sl_plist, priority,
3417: SLEEP_INTERRUPTIBLE) == PROCESS_SIGNALLED) {
3418: /*
3419: * We were signalled. MAKE_SLEEPING () will have
3420: * released the test-and-set lock on the process list,
3421: * so we just have to reset the interrupt priority
3422: * level and return an indication to the caller.
3423: */
3424:
3425: (void) splx (prev_pl);
3426:
3427: return FALSE;
3428: }
3429:
3430: /*
3431: * We assert that whoever woke us up will have left the sleep
3432: * locked in the "locked" state for us. While *we* won't have
3433: * the process-list locked, someone else might so we can't
3434: * make an assertion on that.
3435: */
3436:
3437: ASSERT (lockp->sl_holder == PROC_HANDLE ());
3438: ASSERT (ATOMIC_FETCH_UCHAR (lockp->sl_locked) != 0);
3439:
3440: (void) splx (prev_pl);
3441: } else {
3442: /*
3443: * Write the owner information for SLEEP_LOCKAVAIL () and
3444: * release the test-and-set lock on the process list.
3445: */
3446:
3447: lockp->sl_holder = PROC_HANDLE ();
3448:
3449: PLIST_UNLOCK (lockp->sl_plist, prev_pl);
3450: }
3451:
3452: return TRUE;
3453: }
3454:
3455:
3456: /*
3457: *-STATUS:
3458: * DDI/DKI
3459: *
3460: *-NAME:
3461: * SLEEP_TRYLOCK () Try to acquire a sleep lock.
3462: *
3463: *-SYNOPSIS:
3464: * #include <sys/types.h>
3465: * #include <sys/ksynch.h>
3466: *
3467: * bool_t SLEEP_TRYLOCK (sleep_t * lockp);
3468: *
3469: *-ARGUMENTS:
3470: * lockp Pointer to the sleep lock to be acquired.
3471: *
3472: *-DESCRIPTION:
3473: * If the lock specified by "lockp" is immediately available (can be
3474: * acquired without sleeping) SLEEP_TRYLOCK () acquires the lock. If the
3475: * lock is not immediately available, the function returns without
3476: * acquiring the lock.
3477: *
3478: *-RETURN VALUE:
3479: * SLEEP_TRYLOCK () returns TRUE (a non-zero value) if the lock is
3480: * successfully acquired or FALSE (zero) if the lock is not acquired.
3481: *
3482: *-LEVEL:
3483: * Base or interrupt.
3484: *
3485: *-NOTES:
3486: * Does not sleep.
3487: *
3488: * Driver-defined basic locks, read/write locks and sleep locks may be
3489: * held across calls to this function.
3490: *
3491: *-SEE_ALSO:
3492: * SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
3493: * SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_UNLOCK ()
3494: */
3495:
3496: #if __USE_PROTO__
3497: bool_t (SLEEP_TRYLOCK) (sleep_t * lockp)
3498: #else
3499: bool_t
3500: SLEEP_TRYLOCK __ARGS ((lockp))
3501: sleep_t * lockp;
3502: #endif
3503: {
3504: ASSERT (lockp != NULL);
3505:
3506: if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) == 0) {
3507: lockp->sl_holder = PROC_HANDLE ();
3508: return TRUE;
3509: }
3510:
3511: return FALSE;
3512: }
3513:
3514:
3515: /*
3516: *-STATUS:
3517: * DDI/DKI
3518: *
3519: *-NAME:
3520: * SLEEP_UNLOCK () Release a sleep lock.
3521: *
3522: *-SYNOPSIS:
3523: * #include <sys/ksynch.h>
3524: *
3525: * void SLEEP_UNLOCK (sleep_t * lockp);
3526: *
3527: *-ARGUMENTS:
3528: * lockp Pointer to the sleep lock to be released.
3529: *
3530: *-DESCRIPTION:
3531: * SLEEP_UNLOCK () releases the sleep lock specified by "lockp". If there
3532: * are processes waiting for the lock, one of the waiting processes is
3533: * awakened.
3534: *
3535: *-RETURN VALUE:
3536: * None.
3537: *
3538: *-LEVEL:
3539: * Base or interrupt.
3540: *
3541: *-NOTES:
3542: * Does not sleep.
3543: *
3544: * Driver-defined basic locks, read/write locks and sleep locks may be
3545: * held across calls to this function.
3546: *
3547: *-SEE_ALSO:
3548: * SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
3549: * SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_TRYLOCK ()
3550: */
3551:
3552: #if __USE_PROTO__
3553: void (SLEEP_UNLOCK) (sleep_t * lockp)
3554: #else
3555: void
3556: SLEEP_UNLOCK __ARGS ((lockp))
3557: sleep_t * lockp;
3558: #endif
3559: {
3560: pl_t prev_pl;
3561:
3562: /*
3563: * Make some assertions. Note that we *don't* assert that our
3564: * PROC_HANDLE () matches "sl_holder", since thanks to
3565: * SLEEP_TRYLOCK () allowing interrupt contexts to acquire sleep
3566: * locks we can't rely on that.
3567: */
3568:
3569: ASSERT (lockp != NULL);
3570: ASSERT (ATOMIC_FETCH_UCHAR (lockp->sl_locked));
3571:
3572:
3573: /*
3574: * When we are unlocking the sleep lock, we must lock the process
3575: * list so we can test whether there are any waiting processes to
3576: * be given the lock.
3577: */
3578:
3579: prev_pl = PLIST_LOCK (lockp->sl_plist, "SLEEP_UNLOCK");
3580:
3581:
3582: /*
3583: * If there are no waiters, we unlock the sleep lock, otherwise we
3584: * wake the first waiting process and leave the lock in the locked
3585: * state for the process to simply take over from us later.
3586: *
3587: * In order to cross-check things with the sleep function, we write
3588: * the expected processes' identity into the lock.
3589: */
3590:
3591: if ((lockp->sl_holder = WAKE_ONE (lockp->sl_plist)) == NULL) {
3592: /*
3593: * No waiting processes, give the lock away.
3594: */
3595:
3596: ATOMIC_CLEAR_UCHAR (lockp->sl_locked);
3597: }
3598:
3599: PLIST_UNLOCK (lockp->sl_plist, prev_pl);
3600: }
3601:
3602:
3603: /*
3604: *-STATUS:
3605: * DDI/DKI
3606: *
3607: *-NAME:
3608: * SV_ALLOC () Allocate and initialize a synchronization variable.
3609: *
3610: *-SYNOPSIS:
3611: * #include <sys/kmem.h>
3612: * #include <sys/ksynch.h>
3613: *
3614: * sv_t * SV_ALLOC (int flag);
3615: *
3616: *-ARGUMENTS:
3617: * flag Specifies whether the caller is willing to sleep
3618: * waiting for memory. If "flag" is set to KM_SLEEP, the
3619: * caller will sleep if necessary until sufficient memory
3620: * is available. If "flag" is set to KM_NOSLEEP, the
3621: * caller will not sleep, but SLEEP_ALLOC () will return
3622: * NULL if sufficient memory is not immediately
3623: * available.
3624: *
3625: *-DESCRIPTION:
3626: * SV_ALLOC () dynamically allocates and initialises an instance of a
3627: * synchronization variable.
3628: *
3629: *-RETURN VALUE:
3630: * Upon successful completion, SV_ALLOC () returns a pointer to the newly
3631: * allocated synchronization variable. If KM_NOSLEEP is specified and
3632: * sufficient memory is not immediately available, SV_ALLOC () returns a
3633: * NULL pointer.
3634: *
3635: *-LEVEL:
3636: * Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
3637: * set to KM_NOSLEEP.
3638: *
3639: *-NOTES:
3640: * May sleep if "flag" is set to KM_NOSLEEP.
3641: *
3642: * Driver-defined basic locks and read/write locks may be held across
3643: * calls to this function if "flag" is set to KM_NOSLEEP but may not be
3644: * held if "flag" is KM_SLEEP.
3645: *
3646: * Driver-defined sleep locks may be held across calls to this function
3647: * regardless of the value of "flag".
3648: *
3649: *-SEE_ALSO:
3650: * SV_BROADCAST (), SV_DEALLOC (), SV_SIGNAL (), SV_WAIT (),
3651: * SV_WAIT_SIG ()
3652: */
3653:
3654: #if __USE_PROTO__
3655: sv_t * (SV_ALLOC) (int flag)
3656: #else
3657: sv_t *
3658: SV_ALLOC __ARGS ((flag))
3659: int flag;
3660: #endif
3661: {
3662: sv_t * svp;
3663:
3664: ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
3665:
3666: /*
3667: * Allocate and initialise the data, possibly waiting for enough
3668: * memory to become available.
3669: */
3670:
3671: if ((svp = (sv_t *) _lock_malloc (sizeof (* svp),
3672: flag)) != NULL) {
3673: INIT_LNODE (& svp->sv_node, NULL, & synch_vars, flag);
3674: PLIST_INIT (svp->sv_plist);
3675: }
3676:
3677: return svp;
3678: }
3679:
3680:
3681: /*
3682: *-STATUS:
3683: * DDI/DKI
3684: *
3685: *-NAME:
3686: * SV_BROADCAST () Wake up all processes sleeping on a synchronization
3687: * variable.
3688: *
3689: *-SYNOPSIS:
3690: * #include <sys/ksynch.h>
3691: *
3692: * void * SV_BROADCAST (sv_t * svp, int flags);
3693: *
3694: *-ARGUMENTS:
3695: * svp Pointer to the synchronization variable to be
3696: * broadcast signalled.
3697: *
3698: * flags Bit field for flags. No flags are defined for use in
3699: * drivers and the "flags" argument must be set to zero.
3700: *
3701: *-DESCRIPTION:
3702: * If one or more processes are blocked on the synchronization variable
3703: * specified by "svp", SV_BROADCAST () wakes up all of the blocked
3704: * processes. Note that synchronization variables are stateless, and
3705: * therefore calls to SV_BROADCAST () only affect processes currently
3706: * blocked on the synchronization variable and have not effect on
3707: * processes that block on the synchronization variable at a later time.
3708: *
3709: *-RETURN VALUE:
3710: * None.
3711: *
3712: *-LEVEL:
3713: * Base or interrupt.
3714: *
3715: *-NOTES:
3716: * Does not sleep.
3717: *
3718: * Driver-defined basic locks and read/write locks may be held across
3719: * calls to this function if "flag" is set to KM_NOSLEEP but may not be
3720: * held if "flag" is KM_SLEEP.
3721: *
3722: * Driver-defined basic locks, read/write locks and sleep locks may be
3723: * held across calls to this function.
3724: *
3725: *-SEE_ALSO:
3726: * SV_ALLOC (), SV_DEALLOC (), SV_SIGNAL (), SV_WAIT (), SV_WAIT_SIG ()
3727: */
3728:
3729: #if __USE_PROTO__
3730: void (SV_BROADCAST) (sv_t * svp, int flags)
3731: #else
3732: void
3733: SV_BROADCAST __ARGS ((svp, flags))
3734: sv_t * svp;
3735: int flags;
3736: #endif
3737: {
3738: pl_t prev_pl;
3739:
3740: ASSERT (flags == 0);
3741: ASSERT (svp != NULL);
3742:
3743: /*
3744: * Lock the list (required by WAKE_ALL ()), wake the sleepers, and
3745: * unlock the list.
3746: */
3747:
3748: prev_pl = PLIST_LOCK (svp->sv_plist, "SV_BROADCAST");
3749:
3750: WAKE_ALL (svp->sv_plist);
3751:
3752: PLIST_UNLOCK (svp->sv_plist, prev_pl);
3753: }
3754:
3755:
3756: /*
3757: *-STATUS:
3758: * DDI/DKI
3759: *
3760: *-NAME:
3761: * SV_DEALLOC () Deallocate an instance of a synchronization variable.
3762: *
3763: *-SYNOPSIS:
3764: * #include <sys/ksynch.h>
3765: *
3766: * void SV_DEALLOC (sv_t * svp);
3767: *
3768: *-ARGUMENTS:
3769: * svp Pointer to the synchronization variable to be
3770: * deallocated.
3771: *
3772: *-DESCRIPTION:
3773: * SV_DEALLOC () deallocates the synchronization variable specified by
3774: * "svp".
3775: *
3776: *-RETURN VALUE:
3777: * None.
3778: *
3779: *-LEVEL:
3780: * Base or Interrupt.
3781: *
3782: *-NOTES:
3783: * Does not sleep.
3784: *
3785: * Driver-defined basic locks, read/write locks, and sleep locks may be
3786: * held across calls to this function.
3787: *
3788: *-SEE_ALSO:
3789: * SV_ALLOC (), SV_BROADCAST (), SV_SIGNAL (), SV_WAIT (), SV_WAIT_SIG ()
3790: */
3791:
3792: #if __USE_PROTO__
3793: void (SV_DEALLOC) (sv_t * svp)
3794: #else
3795: void
3796: SV_DEALLOC __ARGS ((svp))
3797: sv_t * svp;
3798: #endif
3799: {
3800: ASSERT (svp != NULL);
3801:
3802: /*
3803: * Remove from the list of all synchronization variables and free any
3804: * statistics buffer space before freeing the lock itself.
3805: */
3806:
3807: PLIST_DESTROY (svp->sv_plist);
3808:
3809: FREE_LNODE (& svp->sv_node, & synch_vars);
3810:
3811: _lock_free (svp, sizeof (* svp));
3812: }
3813:
3814:
3815: /*
3816: *-STATUS:
3817: * DDI/DKI
3818: *
3819: *-NAME:
3820: * SV_SIGNAL () Wake up one process sleeping on a synchronization
3821: * variable.
3822: *
3823: *-SYNOPSIS:
3824: * #include <sys/ksynch.h>
3825: *
3826: * void SV_SIGNAL (sv_t * svp, int flags);
3827: *
3828: *-ARGUMENTS:
3829: * svp Pointer to the synchronization variable to be
3830: * signalled.
3831: *
3832: * flags Bit field for flags. No flags are defined for use in
3833: * drivers and the "flags" argument must be set to zero.
3834: *
3835: *-DESCRIPTION:
3836: * If one or more processes are blocked on the synchronization variable
3837: * specified by "svp", SV_SIGNAL () wakes up a single blocked process.
3838: * Note that synchronization variables are stateless, and therefore
3839: * calls to SV_SIGNAL only affect processes currently blocked on the
3840: * synchronization variable and have no effect on processes that block on
3841: * the synchronization variable at a later time.
3842: *
3843: *-RETURN VALUE:
3844: * None.
3845: *
3846: *-LEVEL:
3847: * Base or Interrupt.
3848: *
3849: *-NOTES:
3850: * Does not sleep.
3851: *
3852: * Driver-defined basic locks, read/write locks, and sleep locks may be
3853: * held across calls to this function.
3854: *
3855: *-SEE_ALSO:
3856: * SV_ALLOC (), SV_BROADCAST (), SV_DEALLOC (), SV_WAIT (),
3857: * SV_WAIT_SIG ()
3858: */
3859:
3860: #if __USE_PROTO__
3861: void (SV_SIGNAL) (sv_t * svp, int flags)
3862: #else
3863: void
3864: SV_SIGNAL __ARGS ((svp, flags))
3865: sv_t * svp;
3866: int flags;
3867: #endif
3868: {
3869: pl_t prev_pl;
3870:
3871: ASSERT (flags == 0);
3872: ASSERT (svp != NULL);
3873:
3874: /*
3875: * Lock the list (required by WAKE_ONE ()), wake a sleeper, and
3876: * unlock the list.
3877: */
3878:
3879: prev_pl = PLIST_LOCK (svp->sv_plist, "SV_SIGNAL");
3880:
3881: (void) WAKE_ONE (svp->sv_plist);
3882:
3883: PLIST_UNLOCK (svp->sv_plist, prev_pl);
3884: }
3885:
3886:
3887: /*
3888: *-STATUS:
3889: * DDI/DKI
3890: *
3891: *-NAME:
3892: * SV_WAIT () Sleep on a synchronization variable.
3893: *
3894: *-SYNOPSIS:
3895: * #include <sys/types.h>
3896: * #include <sys/ksynch.h>
3897: *
3898: * void SV_WAIT (sv_t * svp, int priority, lock_t * lkp);
3899: *
3900: *-ARGUMENTS:
3901: * svp Pointer to the synchronization variable on which to
3902: * sleep.
3903: *
3904: * priority A hint to the scheduling policy as to the relative
3905: * priority the caller wishes to be assigned while
3906: * running in the kernel after waking up. The valid
3907: * values for this argument are as follows:
3908: *
3909: * pridisk Priority appropriate for disk driver
3910: * prinet Priority appropriate for network driver.
3911: * pritty Priority appropriate for terminal driver.
3912: * pritape Priority appropriate for tape driver.
3913: * prihi High priority.
3914: * primed Medium priority.
3915: * prilo Low priority.
3916: *
3917: * Drivers may use these values to request a priority
3918: * appropriate to a given type of device or to request a
3919: * priority that is high, medium or low relative to other
3920: * activities within the kernel.
3921: *
3922: * It is also permissible to specify positive or negative
3923: * offsets from the values defined above. Positive
3924: * offsets result in favourable priority. The maximum
3925: * allowable offset in all cases is 3 (eg. pridisk+3
3926: * and pridisk-3 are valid values by pridisk+4 and
3927: * pridisk-4 are not valid). Offsets can be useful in
3928: * defining the relative importance of different locks or
3929: * resources that may be hald by a given driver. In
3930: * general, a higher relative priority should be used
3931: * when the caller is attempting to acquire a highly-
3932: * contended lock or resource, or when the caller is
3933: * already holding one or more locks or kernel resources
3934: * upon entry to SV_WAIT ().
3935: *
3936: * The exact semantics of the "priority" argument is
3937: * specific to the scheduling class of the caller, and
3938: * some scheduling classes may choose to ignore the
3939: * argument for the purposes of assigning a scheduling
3940: * priority.
3941: *
3942: * lkp Pointer to a basic lock which must be locked when
3943: * SV_WAIT () is called. The basic lock is released when
3944: * the calling process goes to sleep, as described below.
3945: *-DESCRIPTION:
3946: * SV_WAIT () causes the calling process to go to sleep (the caller's
3947: * execution is suspended and other processes may be scheduled) waiting
3948: * for a call to SV_SIGNAL () or SV_BROADCAST () for the synchronization
3949: * variable specified by "svp".
3950: *
3951: * The basic lock specified by "lkp" must be held by the caller upon
3952: * entry. The lock is released and the interrupt priority level is set to
3953: * plbase after the process is queued on the synchronization variable but
3954: * prior to switching context switching to another process. When the
3955: * caller returns from SV_WAIT () the basic lock is not held and the
3956: * interrupt priority level is equal to plbase.
3957: *
3958: * The caller will not be interrupted by signals while sleeping inside
3959: * SV_WAIT ().
3960: *
3961: *-RETURN VALUE:
3962: * None.
3963: *
3964: *-LEVEL:
3965: * Base level only.
3966: *
3967: *-NOTES:
3968: * May sleep.
3969: *
3970: * Driver-defined basic locks and read/write locks may not be held across
3971: * calls to this function.
3972: *
3973: * Driver-defined sleep locks may be held across calls to this function.
3974: *
3975: *-SEE_ALSO:
3976: * SV_ALLOC (), SV_BROADCAST (), SV_DEALLOC (), SV_SIGNAL (),
3977: * SV_WAIT_SIG ()
3978: */
3979:
3980: #if __USE_PROTO__
3981: void (SV_WAIT) (sv_t * svp, int priority, lock_t * lkp)
3982: #else
3983: void
3984: SV_WAIT __ARGS ((svp, priority, lkp))
3985: sv_t * svp;
3986: int priority;
3987: lock_t * lkp;
3988: #endif
3989: {
3990: ASSERT (svp != NULL);
3991: ASSERT (lkp != NULL);
3992: ASSERT_BASE_LEVEL ();
3993:
3994: /*
3995: * First off, we have to lock the process list. After this is done we
3996: * can safely release the client's basic lock, since once we have our
3997: * lock the rest of the wait operation will proceed atomically.
3998: */
3999:
4000: (void) PLIST_LOCK (svp->sv_plist, "SV_WAIT");
4001:
4002: UNLOCK (lkp, plhi);
4003:
4004: (void) MAKE_SLEEPING (svp->sv_plist, priority, SLEEP_NO_SIGNALS);
4005:
4006: (void) splbase (); /* let's make sure... */
4007: }
4008:
4009:
4010: /*
4011: *-STATUS:
4012: * DDI/DKI
4013: *
4014: *-NAME:
4015: * SV_WAIT_SIG () Sleep on a synchronization variable.
4016: *
4017: *-SYNOPSIS:
4018: * #include <sys/types.h>
4019: * #include <sys/ksynch.h>
4020: *
4021: * bool_t SV_WAIT_SIG (sv_t * svp, int priority, lock_t * lkp);
4022: *
4023: *-ARGUMENTS:
4024: * svp Pointer to the synchronization variable on which to
4025: * sleep.
4026: *
4027: * priority A hint to the scheduling policy as to the relative
4028: * priority the caller wishes to be assigned while
4029: * running in the kernel after waking up. The valid
4030: * values for this argument are as follows:
4031: *
4032: * pridisk Priority appropriate for disk driver
4033: * prinet Priority appropriate for network driver.
4034: * pritty Priority appropriate for terminal driver.
4035: * pritape Priority appropriate for tape driver.
4036: * prihi High priority.
4037: * primed Medium priority.
4038: * prilo Low priority.
4039: *
4040: * Drivers may use these values to request a priority
4041: * appropriate to a given type of device or to request a
4042: * priority that is high, medium or low relative to other
4043: * activities within the kernel.
4044: *
4045: * It is also permissible to specify positive or negative
4046: * offsets from the values defined above. Positive
4047: * offsets result in favourable priority. The maximum
4048: * allowable offset in all cases is 3 (eg. pridisk+3
4049: * and pridisk-3 are valid values by pridisk+4 and
4050: * pridisk-4 are not valid). Offsets can be useful in
4051: * defining the relative importance of different locks or
4052: * resources that may be hald by a given driver. In
4053: * general, a higher relative priority should be used
4054: * when the caller is attempting to acquire a highly-
4055: * contended lock or resource, or when the caller is
4056: * already holding one or more locks or kernel resources
4057: * upon entry to SV_WAIT_SIG ().
4058: *
4059: * The exact semantics of the "priority" argument is
4060: * specific to the scheduling class of the caller, and
4061: * some scheduling classes may choose to ignore the
4062: * argument for the purposes of assigning a scheduling
4063: * priority.
4064: *
4065: * lkp Pointer to a basic lock which must be locked when
4066: * SV_WAIT_SIG () is called. The basic lock is released
4067: * when the calling process goes to sleep, as described
4068: * below.
4069: *
4070: *-DESCRIPTION:
4071: * SV_WAIT_SIG () causes the calling process to go to sleep (the caller's
4072: * execution is suspended and other processes may be scheduled) waiting
4073: * for a call to SV_SIGNAL () or SV_BROADCAST () for the synchronization
4074: * variable specified by "svp".
4075: *
4076: * The basic lock specified by "lkp" must be held by the caller upon
4077: * entry. The lock is released and the interrupt priority level is set to
4078: * plbase after the process is queued on the synchronization variable but
4079: * prior to switching context switching to another process. When the
4080: * caller returns from SV_WAIT_SIG () the basic lock is not held and the
4081: * interrupt priority level is equal to plbase.
4082: *
4083: * SV_WAIT_SIG () may be interrupted by a signal, in which case it will
4084: * return early without waiting for a call to SV_SIGNAL () or
4085: * SV_BROADCAST ().
4086: *
4087: * If the function is interrupted by a job control signal (eg SIGSTOP,
4088: * SIGTSTP, SIGTTIN, SIGTTOU) which results in the caller entering a
4089: * stopped state, when continued the SV_WAIT_SIG () function will return
4090: * TRUE as if the process had been awakened by a call to SV_SIGNAL () or
4091: * SV_BROADCAST ().
4092: *
4093: * If the caller is interrupted by a signal other than a job control
4094: * signal, or by a job control signal that does not result in the caller
4095: * stopping (because the signal has a non-default disposition), the
4096: * SV_WAIT_SIG () call will return FALSE.
4097: *
4098: *-RETURN VALUE:
4099: * SV_WAIT_SIG () returns TRUE (a non-zero value) if the caller woke up
4100: * because of a call to SV_SIGNAL () or SV_BROADCAST (), or if the caller
4101: * was stopped and subsequently continued. SV_WAIT_SIG () returns FALSE
4102: * (zero) if the caller woke up and returned early because of a signal
4103: * other than a job control stop signal, or by a job control signal that
4104: * did not result in the caller stopping because the signal has a non-
4105: * default disposition.
4106: *
4107: *-LEVEL:
4108: * Base level only.
4109: *
4110: *-NOTES:
4111: * May sleep.
4112: *
4113: * Driver-defined basic locks and read/write locks may not be held across
4114: * calls to this function.
4115: *
4116: * Driver-defined sleep locks may be held across calls to this function.
4117: *
4118: *-SEE_ALSO:
4119: * SV_ALLOC (), SV_BROADCAST (), SV_DEALLOC (), SV_SIGNAL (), SV_WAIT ()
4120: */
4121:
4122: #if __USE_PROTO__
4123: bool_t (SV_WAIT_SIG) (sv_t * svp, int priority, lock_t * lkp)
4124: #else
4125: bool_t
4126: SV_WAIT_SIG __ARGS ((svp, priority, lkp))
4127: sv_t * svp;
4128: int priority;
4129: lock_t * lkp;
4130: #endif
4131: {
4132: bool_t not_signalled;
4133:
4134: ASSERT (svp != NULL);
4135: ASSERT (lkp != NULL);
4136: ASSERT_BASE_LEVEL ();
4137:
4138: /*
4139: * First off, we have to lock the process list. After this is done we
4140: * can safely release the client's basic lock, since once we have our
4141: * lock the rest of the wait operation will proceed atomically.
4142: */
4143:
4144: (void) PLIST_LOCK (svp->sv_plist, "SV_WAIT_SIG");
4145:
4146: UNLOCK (lkp, plhi);
4147:
4148: not_signalled = MAKE_SLEEPING (svp->sv_plist, priority,
4149: SLEEP_INTERRUPTIBLE) != PROCESS_SIGNALLED;
4150:
4151: (void) splbase (); /* let's make sure */
4152:
4153: return not_signalled;
4154: }
4155:
4156:
4157: /*
4158: * This function exercises some of the most basic facilities of the locking
4159: * system. It is difficult to assure that the code presented in this file
4160: * will work correctly, because the nature of the service provided is a
4161: * temporal guarantee that can't be verified without performing arbitrary
4162: * fine-grained interleavings of at least two execution paths through each
4163: * combination of interacting functions.
4164: *
4165: * So, the best we can do here in a portable fashion is to present some tests
4166: * of the observable properties of the above code, and to (hopefully) exercise
4167: * the ASSERT () statements in the above for some minimal self-checking.
4168: *
4169: * One problem with the use of ASSERT () tests is that it's difficult to
4170: * build negative tests. The argument to this function indicates a negative
4171: * tests that should be performed, presumably in conjunction with some test
4172: * script capable of verifying an exception report against a previous run.
4173: *
4174: * Our tests use a lock interrupt level appropriate to the environment; in
4175: * user-mode tests under Coherent, disabling interrupts is prohibited
4176: */
4177:
4178: #if __COHERENT__
4179: # define test_pl plbase
4180: #else
4181: # define test_pl plhi
4182: #endif
4183:
4184: #if __USE_PROTO__
4185: int (LOCK_TESTS) (int negative)
4186: #else
4187: int
4188: LOCK_TESTS __ARGS ((negative))
4189: int negative;
4190: #endif
4191: {
4192: pl_t prev_pl;
4193:
4194: lock_t * basic_lock;
4195: rwlock_t * rw_lock;
4196: sleep_t * sleep_lock;
4197: sv_t * synch_var;
4198:
4199: static lkinfo_t basic_info = { "test basic lock" };
4200: static lkinfo_t rw_info = { "test read/write lock" };
4201: static lkinfo_t sleep_info = { "test sleep lock" };
4202:
4203: /*
4204: * Allocate some locks that we can play with...
4205: */
4206:
4207: basic_lock = LOCK_ALLOC (32, test_pl, & basic_info, KM_SLEEP);
4208: rw_lock = RW_ALLOC (10, test_pl, & rw_info, KM_SLEEP);
4209: sleep_lock = SLEEP_ALLOC (0, & sleep_info, KM_SLEEP);
4210: synch_var = SV_ALLOC (KM_SLEEP);
4211:
4212:
4213: /*
4214: * Basic locks.
4215: */
4216:
4217: if ((prev_pl = TRYLOCK (basic_lock, test_pl)) == invpl ||
4218: TRYLOCK (basic_lock, test_pl) != invpl)
4219: return -1;
4220:
4221:
4222: UNLOCK (basic_lock, prev_pl);
4223:
4224: prev_pl = LOCK (basic_lock, test_pl);
4225:
4226: if (TRYLOCK (basic_lock, test_pl) != invpl)
4227: return -1;
4228:
4229: UNLOCK (basic_lock, prev_pl);
4230:
4231: /*
4232: * Read/write locks.
4233: */
4234:
4235: if ((prev_pl = RW_TRYRDLOCK (rw_lock, test_pl)) == invpl ||
4236: RW_TRYRDLOCK (rw_lock, test_pl) == invpl ||
4237: RW_TRYWRLOCK (rw_lock, test_pl) != invpl)
4238: return -1;
4239:
4240: (void) RW_RDLOCK (rw_lock, test_pl);
4241:
4242: if (RW_TRYWRLOCK (rw_lock, test_pl) != invpl)
4243: return -1;
4244:
4245: RW_UNLOCK (rw_lock, prev_pl);
4246: RW_UNLOCK (rw_lock, prev_pl);
4247: RW_UNLOCK (rw_lock, prev_pl);
4248:
4249:
4250: if ((prev_pl = RW_TRYWRLOCK (rw_lock, test_pl)) == invpl ||
4251: RW_TRYWRLOCK (rw_lock, test_pl) != invpl ||
4252: RW_TRYRDLOCK (rw_lock, test_pl) != invpl)
4253: return -1;
4254:
4255: RW_UNLOCK (rw_lock, prev_pl);
4256:
4257:
4258: prev_pl = RW_WRLOCK (rw_lock, test_pl);
4259:
4260: if (RW_TRYWRLOCK (rw_lock, test_pl) != invpl ||
4261: RW_TRYRDLOCK (rw_lock, test_pl) != invpl)
4262: return -1;
4263:
4264: RW_UNLOCK (rw_lock, prev_pl);
4265:
4266:
4267: /*
4268: * Sleep locks.
4269: */
4270:
4271: if (SLEEP_LOCKOWNED (sleep_lock) == TRUE ||
4272: SLEEP_LOCKAVAIL (sleep_lock) == FALSE ||
4273: SLEEP_TRYLOCK (sleep_lock) == FALSE ||
4274: SLEEP_LOCKOWNED (sleep_lock) == FALSE ||
4275: SLEEP_LOCKAVAIL (sleep_lock) == TRUE ||
4276: SLEEP_TRYLOCK (sleep_lock) == TRUE)
4277: return -1;
4278:
4279: SLEEP_UNLOCK (sleep_lock);
4280:
4281: if (SLEEP_LOCKOWNED (sleep_lock) == TRUE ||
4282: SLEEP_LOCKAVAIL (sleep_lock) == FALSE ||
4283: SLEEP_LOCK_SIG (sleep_lock, prilo) == FALSE ||
4284: SLEEP_LOCKOWNED (sleep_lock) == FALSE ||
4285: SLEEP_LOCKAVAIL (sleep_lock) == TRUE ||
4286: SLEEP_TRYLOCK (sleep_lock) == TRUE)
4287: return -1;
4288:
4289: SLEEP_UNLOCK (sleep_lock);
4290:
4291: SLEEP_LOCK (sleep_lock, prilo);
4292:
4293: if (SLEEP_LOCKOWNED (sleep_lock) == FALSE ||
4294: SLEEP_LOCKAVAIL (sleep_lock) == TRUE ||
4295: SLEEP_TRYLOCK (sleep_lock) == TRUE)
4296: return -1;
4297:
4298: SLEEP_UNLOCK (sleep_lock);
4299:
4300:
4301: /*
4302: * Synchronisation variables: this is impossible to test without
4303: * access to timeout functions. Once DDI/DKI timeout functions are
4304: * available, we can use those to at least begin to exercise the
4305: * notion of synchronization.
4306: */
4307:
4308:
4309: /*
4310: * Negative testing... need to add this!
4311: */
4312:
4313: /*
4314: * Clean up and bail out.
4315: */
4316:
4317: LOCK_DEALLOC (basic_lock);
4318: RW_DEALLOC (rw_lock);
4319: SLEEP_DEALLOC (sleep_lock);
4320: SV_DEALLOC (synch_var);
4321:
4322: return 0;
4323: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.