1: /*
2: * Rewritten for 2.11BSD. Feb 20 1995, Steven Schultz (sms@wlv.iipo.gtegsc.com)
3: *
4: * The lock table is allocated external to the kernel (in pdp/machdep2.c at
5: * kernel startup time) because 8 concurrent Ingres sessions would have cost
6: * over 500 bytes of D space.
7: */
8:
9: #include "ingres.h"
10: #if NINGRES > 0
11:
12: #include "param.h"
13: #include <sys/file.h>
14: #include <sys/user.h>
15: #include <sys/proc.h>
16: #include <sys/uio.h>
17: #include <machine/seg.h>
18: #include <sys/ingreslock.h>
19:
20: /*
21: * Wait channels for locktable. We need something which is even, unique and
22: * not mapped out to sleep on when waiting for a lock.
23: */
24: int Locksleep[IL_NLOCKS];
25: segm Locktabseg;
26: struct Lockform *Locktab = (struct Lockform *)SEG5;
27:
28: /*
29: * array of number of locks which can be set for each lock.
30: * It looks tempting to make this an array of char or u_char. DON'T. The
31: * entries are used as wait channel addresses and must be 'even'.
32: */
33: int Lockset[] =
34: {
35: IL_NLOCKS,
36: IL_PLOCKS,
37: IL_RLOCKS,
38: IL_DLOCKS
39: };
40:
41: #define keycomp(a,b) bcmp(a,b,KEYSIZE)
42:
43: ingres_open(dev, flag, mode)
44: dev_t dev;
45: int flag;
46: int mode;
47: {
48:
49: if ((flag & FWRITE) == 0)
50: return(EBADF);
51: if (Locktabseg.se_addr == 0)
52: return(ENOMEM);
53: return(0);
54: }
55:
56: /*
57: * ingres_write() : write driver
58: * 1. copy Lock request info to lockbuf
59: * 2. follow action in l_act
60: * 3. Error return conditions
61: * -1: lockrequest fails(only on act=1)
62: * -2: attempt to release a lock not set
63: * by calling program
64: * -3: illegal action requested
65: *
66: * Install the line "ingres_rma(p->p_pid)" in the routine
67: * "exit" (in sys/kern_exit.c) after "p->p_stat = SZOMB".
68: */
69:
70: ingres_write(dev, uio, flag)
71: dev_t dev;
72: struct uio *uio;
73: int flag;
74: {
75: struct Lockreq lockbuf;
76: register struct Lockreq *ll;
77: register int i;
78: int error = 0, blockflag;
79:
80: if (uio->uio_resid != sizeof (struct ulock))
81: return(EINVAL);
82: error = uiomove(&lockbuf.lr_req, sizeof (struct ulock), uio);
83: if (error)
84: return(error);
85: lockbuf.lr_pid = u.u_procp->p_pid;
86: ll = &lockbuf;
87: if ((ll->lr_act < A_RLS1)
88: && ((ll->lr_type < T_CS) || (ll->lr_type > T_DB )
89: || (ll->lr_mod < M_EXCL) || (ll->lr_mod > M_SHARE )))
90: return(EINVAL);
91:
92: /*
93: * At this point we are in the high kernel and do not need to save seg5
94: * before changing it. Making sure that 'normalseg5' is called before doing
95: * a sleep() or return() is sufficient.
96: *
97: * It is simpler to map the lock table once here rather than in each routine
98: * called below.
99: */
100: ingres_maplock();
101:
102: switch(ll->lr_act)
103: {
104: case A_RTN:
105: /*
106: * attempt to set lock.
107: * error return if failure.
108: */
109: blockflag = FALSE;
110: for ( i = 0; i <= ll->lr_type; i++)
111: if (Lockset[i] == 0)
112: blockflag = TRUE;
113: if (blockflag || ingres_unique(ll) >= 0)
114: error = -1;
115: else
116: ingres_enter(ll);
117: break;
118:
119: case A_SLP:
120: /* attempt to set lock.
121: * sleep on blocking address if failure.
122: */
123: do
124: {
125: do
126: {
127: blockflag = TRUE;
128: for ( i = 0; i <= ll->lr_type; i++)
129: if (Lockset[i] == 0)
130: {
131: normalseg5();
132: sleep(&Lockset[i],LOCKPRI);
133: ingres_maplock();
134: blockflag = FALSE;
135: }
136: }
137: while (!blockflag);
138: if (( i = ingres_unique(ll)) >= 0 )
139: {
140: blockflag = FALSE;
141: Locktab[i].l_wflag = W_ON;
142: normalseg5();
143: sleep(&Locksleep[i],LOCKPRI);
144: ingres_maplock();
145: }
146: }
147: while (!blockflag);
148: ingres_enter(ll);
149: break;
150:
151: case A_RLS1:
152: /* remove 1 lock */
153: if ((i = ingres_find(ll)) >= 0)
154: ingres_rm(i,ll->lr_pid);
155: else
156: error = -2;
157: break;
158:
159: case A_RLSA:
160: /* remove all locks for this process id*/
161: ingres_rma(ll->lr_pid); /* does a normalseg5() */
162: break;
163:
164: case A_ABT: /* abort all locks */
165: ingres_abt();
166: break;
167:
168: default :
169: error = -3;
170: break;
171: }
172: normalseg5();
173: return(error);
174: }
175:
176: /*
177: * ingres_unique- check for match on key
178: *
179: * return index of Locktab if match found
180: * else return -1
181: */
182:
183: static
184: ingres_unique(q)
185: register struct Lockreq *q;
186: {
187: register int k;
188: register struct Lockform *p = Locktab;
189:
190: for (k = 0; k < IL_NLOCKS; k++, p++)
191: {
192: if ((p->l_mod != M_EMTY)
193: && (keycomp(p->l_key,q->lr_key) == 0)
194: && (p->l_type == q->lr_type)
195: && ((p->l_mod == M_EXCL) || (q->lr_mod == M_EXCL)))
196: return(k);
197: }
198: return(-1);
199: }
200:
201: static
202: ingres_find(q)
203: register struct Lockreq *q;
204: {
205: register int k;
206: register struct Lockform *p = Locktab;
207:
208: for (k = 0; k < IL_NLOCKS; k++, p++)
209: {
210: if ((p->l_mod != M_EMTY)
211: && (keycomp(p->l_key,q->lr_key) == 0)
212: && (p->l_type == q->lr_type)
213: && (p->l_pid == q->lr_pid))
214: return(k);
215: }
216: return(-1);
217: }
218:
219: /*
220: * remove the lth Lock
221: * if the correct user is requesting the move.
222: */
223:
224: static void
225: ingres_rm(l,llpid)
226: int l, llpid;
227: {
228: register struct Lockform *a = &Locktab[l];
229: register int k;
230:
231: if (a->l_pid == llpid && a->l_mod != M_EMTY)
232: {
233: a->l_mod = M_EMTY;
234: a->l_pid = 0;
235: if (a->l_wflag == W_ON)
236: {
237: a->l_wflag = W_OFF;
238: wakeup(&Locksleep[l]);
239: }
240: for (k = 0; k <= a->l_type; k++)
241: {
242: Lockset[k]++;
243: if (Lockset[k] == 1)
244: wakeup(&Lockset[k]);
245: }
246: }
247: }
248:
249: /*
250: * ingres_rma releases all locks for a given process id(pd).
251: */
252:
253: ingres_rma(pd)
254: int pd;
255: {
256: register int i;
257: register struct Lockform *p = Locktab;
258: /*
259: * Have to map the lock table because we can be called from kern_exit.c
260: * when a process exits.
261: */
262: ingres_maplock();
263:
264: /*
265: * Replicate the pid check here to avoid function calls. If this process
266: * has no Ingres locks outstanding then we avoid IL_NLOCKS function calls
267: * and returns.
268: */
269: for (i = 0; i < IL_NLOCKS; i++, p++)
270: {
271: if (p->l_pid == pd && (p->l_mod != M_EMTY))
272: ingres_rm(i,pd);
273: }
274: normalseg5();
275: }
276:
277: /*
278: * enter Lockbuf in locktable
279: * return position in Locktable
280: * error return of -1
281: */
282:
283: static
284: ingres_enter(ll)
285: struct Lockreq *ll;
286: {
287: register int k, l;
288: register struct Lockform *p = Locktab;
289:
290: for (k = 0; k < IL_NLOCKS; k++, p++)
291: {
292: if (p->l_mod == M_EMTY)
293: {
294: p->l_pid = ll->lr_pid;
295: p->l_type = ll->lr_type;
296: p->l_mod = ll->lr_mod;
297: bcopy(ll->lr_key, p->l_key, KEYSIZE);
298: for (l = 0; l <= ll->lr_type; l++)
299: Lockset[l]--;
300: return(k);
301: }
302: }
303: return (-1);
304: }
305:
306: /*
307: * ingres_abt - abort all locks
308: */
309:
310: static void
311: ingres_abt()
312: {
313: register int k;
314:
315: for (k = 0; k < IL_NLOCKS; k++)
316: wakeup( &Locktab[k] );
317: for (k = 0; k < 4; k++)
318: wakeup( &Lockset[k]);
319: bzero(Locktab, LOCKTABSIZE);
320: Lockset[0] = IL_NLOCKS;
321: Lockset[1] = IL_PLOCKS;
322: Lockset[2] = IL_RLOCKS;
323: Lockset[3] = IL_DLOCKS;
324: }
325: #endif /* NINGRES > 0 */
Defined functions
Defined variables
Defined macros