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