|
|
1.1 root 1: /*
2: * coh/rlock.c
3: * COHERENT record locking.
4: * Modified 5/92 by steve from tsm's old source.
5: * All record locking functions meet the system V standard.
6: */
7:
8: #include <sys/coherent.h>
9: #include <errno.h>
10: #include <fcntl.h>
11: #include <sys/fd.h>
12: #include <sys/proc.h>
13: #include <sys/rlock.h>
14: #include <sys/sched.h>
15: #include <sys/uproc.h>
16: #include <unistd.h>
17:
18: /* Globals. */
19: RLOCK *freerl;
20: GATE rlgate = { 0, 0};
21: unsigned RLOCKS = 100; /* patchable */
22:
23: /* Forward. */
24: int rlock();
25: int rlinit();
26: static int nextblock();
27: static int nextmeet();
28: static RLOCK *getlock();
29: static RLOCK *freelock();
30: static int extract();
31: static int remlock();
32: static int addlock();
33: static int waitlock();
34: static int waiting();
35:
36: /*
37: * Record locking.
38: */
39: int
40: rlock(fdp, cmd, flp) register FD *fdp; register FLOCK *flp;
41: {
42: register RLOCK *org;
43: register int retval;
44: RLOCK srl;
45: RLOCK *rlp;
46:
47: org = (RLOCK *)&fdp->f_ip->i_rl;
48: retval = -1;
49: srl.rl_proc = SELF;
50: srl.rl_type = flp->l_type==F_RDLCK ? 0:1;
51: srl.rl_start = flp->l_start;
52: if (flp->l_whence == SEEK_CUR)
53: srl.rl_start += fdp->f_seek;
54: else if (flp->l_whence == SEEK_END)
55: srl.rl_start += fdp->f_ip->i_size;
56: srl.rl_end = srl.rl_start;
57: if (flp->l_len > 0)
58: srl.rl_end += flp->l_len - 1;
59: else if (flp->l_len == 0)
60: srl.rl_end = -1;
61: else {
62: srl.rl_start += flp->l_len;
63: srl.rl_end--;
64: }
65: if (srl.rl_start < 0 || srl.rl_end < -1
66: || srl.rl_end != -1 && srl.rl_start > srl.rl_end) {
67: u.u_error = EINVAL;
68: return -1;
69: }
70: lock(rlgate);
71: rlp = org;
72: if (cmd == F_GETLK) {
73: if (!nextblock(&rlp, &srl))
74: flp->l_type = F_UNLCK;
75: else {
76: flp->l_type = rlp->rl_type ? F_WRLCK:F_RDLCK;
77: flp->l_whence = SEEK_SET;
78: flp->l_start = rlp->rl_start;
79: if (rlp->rl_end == -1)
80: flp->l_len = 0;
81: else
82: flp->l_len = rlp->rl_end - flp->l_start + 1;
83: flp->l_pid = rlp->rl_proc->p_pid;
84: }
85: retval = 0;
86: } else if (flp->l_type == F_UNLCK)
87: retval = remlock(org, &srl);
88: else if (srl.rl_type && !fdp->f_flag & IPW
89: || !srl.rl_type && !fdp->f_flag & IPR)
90: u.u_error = EINVAL;
91: else if (cmd == F_SETLKW)
92: retval = waitlock(org, &srl);
93: else if (!nextblock(&rlp, &srl))
94: retval = addlock(org, &srl);
95: else
96: u.u_error = EAGAIN;
97: unlock(rlgate);
98: if (cmd != F_GETLK)
99: wakeup(org);
100: return retval;
101: }
102:
103: /* Allocate and initialize free record lock list. */
104: int
105: rlinit()
106: {
107: register RLOCK *rl;
108:
109: if (RLOCKS == 0) {
110: freerl = NULL;
111: return 0;
112: }
113: freerl = kalloc(RLOCKS * sizeof(RLOCK));
114: if (freerl == NULL)
115: panic("rlinit: no space for RLOCKs");
116: rl = &freerl[RLOCKS-1];
117: rl->rl_next = NULL;
118: while (--rl >= freerl)
119: rl->rl_next = rl+1;
120: return 1;
121: }
122:
123: /*
124: * Record locking subroutines.
125: * Most of them assume that rlgate is locked.
126: * The user is guaranteed no unwanted unlocks regardless of error.
127: * rlgate is locked whenever the lock list contents or free list is used.
128: * Be careful if you change anything that these things remain true.
129: */
130:
131: /*
132: * In nextblock and nextmeet,
133: * list is a ptr to an RLOCK * which is owned by the caller.
134: * This allows calls to proceed down an rlock list.
135: * These routines should NOT be called with *list == NULL.
136: */
137:
138: /* Set *list = next element in list conflicting with lock. */
139: static
140: int
141: nextblock(list, lock) register RLOCK **list, *lock;
142: {
143: while (nextmeet(list, lock)) {
144: if (lock->rl_proc != (*list)->rl_proc
145: && (lock->rl_type || (*list)->rl_type)) {
146: return 1;
147: }
148: }
149: return 0;
150: }
151:
152: /* Set *list = next element of list referencing a loc referenced by lock */
153: static
154: int
155: nextmeet(list, lock) RLOCK **list, *lock;
156: {
157: register RLOCK *block;
158: register long top, bot;
159:
160: top = lock->rl_start;
161: bot = lock->rl_end;
162: for (block = (*list)->rl_next; block != NULL; block = block->rl_next) {
163: if (bot == -1) {
164: if (block->rl_end == -1 || block->rl_end >= top)
165: break;
166: } else if (bot >= block->rl_start)
167: if (block->rl_end == -1 || block->rl_end >= top)
168: break;
169: }
170: if ((*list = block) != NULL)
171: return 1;
172: return 0;
173: }
174:
175: /* Remove and return a lock from the free list. */
176: static
177: RLOCK *
178: getlock()
179: {
180: register RLOCK *rl;
181:
182: rl = freerl;
183: if (rl != NULL)
184: freerl = rl->rl_next;
185: else
186: u.u_error = ENOLCK;
187: return rl;
188: }
189:
190: /*
191: * Remove element from the lock list beginning at org and add it to the free list.
192: * Return pointer to (what used to be) its predecessor.
193: */
194: static
195: RLOCK *
196: freelock(org, elt) register RLOCK *org, *elt;
197: {
198: while (elt != org->rl_next)
199: org = org->rl_next;
200: org->rl_next = elt->rl_next;
201: elt->rl_next = freerl;
202: freerl = elt;
203: return org;
204: }
205:
206: /*
207: * Remove new lock from old.
208: * Returns:
209: * 1 if caller should free old.
210: * 0 if caller should do nothing.
211: * -1 if error (out of locks).
212: */
213: static
214: int
215: extract(old, new) register RLOCK *old, *new;
216: {
217: long tend;
218: register RLOCK *lock;
219:
220: if (new->rl_start <= old->rl_start) {
221: if (new->rl_end == -1
222: || old->rl_end != -1 && new->rl_end >= old->rl_end)
223: return 1;
224: old->rl_start = new->rl_end+1;
225: return 0;
226: }
227: tend = old->rl_end;
228: old->rl_end = new->rl_start - 1;
229: if (new->rl_end == -1
230: || tend != -1 && new->rl_end >= tend)
231: return 0;
232: if ((lock = getlock()) == NULL) {
233: old->rl_end = tend;
234: return -1;
235: }
236: lock->rl_type = old->rl_type;
237: lock->rl_proc = old->rl_proc;
238: lock->rl_start = new->rl_end+1;
239: lock->rl_end = tend;
240: lock->rl_next = old->rl_next;
241: old->rl_next = lock;
242: return 0;
243: }
244:
245: /* Extract lock from each element of list. */
246: static
247: int
248: remlock(list, lock) RLOCK *list; register RLOCK *lock;
249: {
250: RLOCK *org;
251:
252: org = list;
253: while (nextmeet(&list, lock)) {
254: if (list->rl_proc != lock->rl_proc)
255: continue;
256: switch(extract(list, lock)) {
257: case 1:
258: list = freelock(org, list);
259: case 0:
260: break;
261: default:
262: return -1;
263: }
264: }
265: return 0;
266: }
267:
268: /*
269: * Install lock in list.
270: * Combine lock with neighbouring locks of same type and owner.
271: * Get space for new lock (best done here - OK since rllock locked).
272: * Remove old locks (always different type, same owner) and attach new lock.
273: * To avoid removing desired locks, addlock allows redundant locks to appear.
274: * This is always rectified by the future unlock and is rare.
275: */
276: static
277: int
278: addlock(list, lock) RLOCK *list; register RLOCK *lock;
279: {
280: RLOCK *new, *org;
281: register long top, bot;
282:
283: org = list;
284: top = lock->rl_start;
285: bot = lock->rl_end;
286: if (top != 0)
287: lock->rl_start--;
288: if (bot != -1)
289: lock->rl_end++;
290: while (nextmeet(&list, lock)) {
291: if (list->rl_proc != lock->rl_proc
292: || list->rl_type != lock->rl_type)
293: continue;
294: if (list->rl_start < top)
295: top = list->rl_start;
296: if (bot != -1 && (list->rl_end == -1 || list->rl_end >= bot))
297: bot = list->rl_end;
298: list = freelock(org, list);
299: }
300: if ((new = getlock()) == NULL)
301: return -1;
302: new->rl_proc = lock->rl_proc;
303: new->rl_type = lock->rl_type;
304: lock = new;
305: lock->rl_start = top;
306: lock->rl_end = bot;
307: remlock(org, lock);
308: lock->rl_next = org->rl_next;
309: org->rl_next = lock;
310: return 0;
311: }
312:
313: /* Sleep until possible to install rl in list then do so. */
314: #define cleanup() SELF->p_prl = NULL; rl->rl_next = freerl; freerl = rl
315: static
316: int
317: waitlock(list, srl) RLOCK *list, *srl;
318: {
319: register RLOCK *org;
320:
321: org = list;
322: if (nextblock(&list, srl)) {
323: register RLOCK *rl = getlock();
324:
325: if (rl == NULL)
326: return -1;
327: *rl = *srl;
328: rl->rl_next = org;
329: SELF->p_prl = rl;
330: do {
331: do {
332: if (waiting(list->rl_proc)) {
333: u.u_error = EDEADLK;
334: cleanup();
335: return -1;
336: }
337: } while (nextblock(&list, rl));
338: unlock(rlgate);
339: x_sleep(org, primed, slpriSigCatch, "rlock");
340: lock(rlgate);
341: if (SELF->p_ssig && nondsig()) {
342: u.u_error = EINTR;
343: cleanup();
344: return -1;
345: }
346: list = org;
347: } while (nextblock(&list, rl));
348: cleanup();
349: }
350: return addlock(org, srl);
351: }
352:
353: /* True if pp has requested a lock (even indirectly) pending on SELF. */
354: static
355: int
356: waiting(pp) PROC *pp;
357: {
358: RLOCK *list;
359: register RLOCK *lock;
360:
361: lock = pp->p_prl;
362: if (lock == NULL)
363: return 0;
364: list = lock->rl_next;
365: while (nextblock(&list, lock)) {
366: if (list->rl_proc == SELF)
367: return 1;
368: if (waiting(list->rl_proc))
369: return 1;
370: }
371: return 0;
372: }
373:
374: /* end of coh/rlock.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.