1 /* 2 * Copyright (c) 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code contains ideas from software contributed to Berkeley by 6 * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating 7 * System project at Carnegie-Mellon University. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)lock.h 8.8 (Berkeley) 05/11/95 12 */ 13 14 #ifndef _LOCK_H_ 15 #define _LOCK_H_ 16 17 /* 18 * The general lock structure. Provides for multiple shared locks, 19 * upgrading from shared to exclusive, and sleeping until the lock 20 * can be gained. The simple_lock is defined in <machine/param.h>. 21 */ 22 struct lock { 23 struct simple_lock lk_interlock; /* lock on remaining fields */ 24 u_int lk_flags; /* see below */ 25 int lk_sharecount; /* # of accepted shared locks */ 26 int lk_waitcount; /* # of processes sleeping for lock */ 27 short lk_exclusivecount; /* # of recursive exclusive locks */ 28 short lk_prio; /* priority at which to sleep */ 29 char *lk_wmesg; /* resource sleeping (for tsleep) */ 30 int lk_timo; /* maximum sleep time (for tsleep) */ 31 pid_t lk_lockholder; /* pid of exclusive lock holder */ 32 }; 33 /* 34 * Lock request types: 35 * LK_SHARED - get one of many possible shared locks. If a process 36 * holding an exclusive lock requests a shared lock, the exclusive 37 * lock(s) will be downgraded to shared locks. 38 * LK_EXCLUSIVE - stop further shared locks, when they are cleared, 39 * grant a pending upgrade if it exists, then grant an exclusive 40 * lock. Only one exclusive lock may exist at a time, except that 41 * a process holding an exclusive lock may get additional exclusive 42 * locks if it explicitly sets the LK_CANRECURSE flag in the lock 43 * request, or if the LK_CANRECUSE flag was set when the lock was 44 * initialized. 45 * LK_UPGRADE - the process must hold a shared lock that it wants to 46 * have upgraded to an exclusive lock. Other processes may get 47 * exclusive access to the resource between the time that the upgrade 48 * is requested and the time that it is granted. 49 * LK_EXCLUPGRADE - the process must hold a shared lock that it wants to 50 * have upgraded to an exclusive lock. If the request succeeds, no 51 * other processes will have gotten exclusive access to the resource 52 * between the time that the upgrade is requested and the time that 53 * it is granted. However, if another process has already requested 54 * an upgrade, the request will fail (see error returns below). 55 * LK_DOWNGRADE - the process must hold an exclusive lock that it wants 56 * to have downgraded to a shared lock. If the process holds multiple 57 * (recursive) exclusive locks, they will all be downgraded to shared 58 * locks. 59 * LK_RELEASE - release one instance of a lock. 60 * LK_DRAIN - wait for all activity on the lock to end, then mark it 61 * decommissioned. This feature is used before freeing a lock that 62 * is part of a piece of memory that is about to be freed. 63 * 64 * These are flags that are passed to the lockmgr routine. 65 */ 66 #define LK_TYPE_MASK 0x00000007 /* type of lock sought */ 67 #define LK_SHARED 0x00000001 /* shared lock */ 68 #define LK_EXCLUSIVE 0x00000002 /* exclusive lock */ 69 #define LK_UPGRADE 0x00000003 /* shared-to-exclusive upgrade */ 70 #define LK_EXCLUPGRADE 0x00000004 /* first shared-to-exclusive upgrade */ 71 #define LK_DOWNGRADE 0x00000005 /* exclusive-to-shared downgrade */ 72 #define LK_RELEASE 0x00000006 /* release any type of lock */ 73 #define LK_DRAIN 0x00000007 /* wait for all lock activity to end */ 74 /* 75 * External lock flags. 76 * 77 * These flags may be set in lock_init to set their mode permanently, 78 * or passed in as arguments to the lock manager. 79 */ 80 #define LK_EXTFLG_MASK 0x000000f0 /* mask of external flags */ 81 #define LK_NOWAIT 0x00000010 /* do not sleep to await lock */ 82 #define LK_SLEEPFAIL 0x00000020 /* sleep, then return failure */ 83 #define LK_CANRECURSE 0x00000040 /* allow recursive exclusive lock */ 84 /* 85 * Internal lock flags. 86 * 87 * These flags are used internally to the lock manager. 88 */ 89 #define LK_WANT_UPGRADE 0x00000100 /* waiting for share-to-excl upgrade */ 90 #define LK_WANT_EXCL 0x00000200 /* exclusive lock sought */ 91 #define LK_HAVE_EXCL 0x00000400 /* exclusive lock obtained */ 92 #define LK_WAITDRAIN 0x00000800 /* process waiting for lock to drain */ 93 #define LK_DRAINED 0x00001000 /* lock has been decommissioned */ 94 /* 95 * Control flags 96 * 97 * Non-persistent external flags. 98 */ 99 #define LK_INTERLOCK 0x00010000 /* unlock passed simple lock after 100 getting lk_interlock */ 101 #define LK_RETRY 0x00020000 /* vn_lock: retry until locked */ 102 103 /* 104 * Lock return status. 105 * 106 * Successfully obtained locks return 0. Locks will always succeed 107 * unless one of the following is true: 108 * LK_FORCEUPGRADE is requested and some other process has already 109 * requested a lock upgrade (returns EBUSY). 110 * LK_WAIT is set and a sleep would be required (returns EBUSY). 111 * LK_SLEEPFAIL is set and a sleep was done (returns ENOLCK). 112 * PCATCH is set in lock priority and a signal arrives (returns 113 * either EINTR or ERESTART if system calls is to be restarted). 114 * Non-null lock timeout and timeout expires (returns EWOULDBLOCK). 115 * A failed lock attempt always returns a non-zero error value. No lock 116 * is held after an error return (in particular, a failed LK_UPGRADE 117 * or LK_FORCEUPGRADE will have released its shared access lock). 118 */ 119 120 /* 121 * Indicator that no process holds exclusive lock 122 */ 123 #define LK_KERNPROC ((pid_t) -2) 124 #define LK_NOPROC ((pid_t) -1) 125 126 void lockinit __P((struct lock *, int prio, char *wmesg, int timo, 127 int flags)); 128 int lockmgr __P((__volatile struct lock *, u_int flags, 129 struct simple_lock *, pid_t pid)); 130 int lockstatus __P((struct lock *)); 131 132 #ifdef DEBUG 133 void simple_unlock __P((__volatile struct simple_lock *alp)); 134 int simple_lock_try __P((__volatile struct simple_lock *alp)); 135 void simple_lock __P((__volatile struct simple_lock *alp)); 136 void simple_lock_init __P((struct simple_lock *alp)); 137 #else /* !DEBUG */ 138 #if NCPUS == 1 /* no multiprocessor locking is necessary */ 139 #define simple_lock_init(alp) 140 #define simple_lock(alp) 141 #define simple_lock_try(alp) (1) /* always succeeds */ 142 #define simple_unlock(alp) 143 #endif /* NCPUS == 1 */ 144 #endif /* !DEBUG */ 145 146 #endif /* !_LOCK_H_ */ 147