sysv_sem.c revision 1.3 1 1.1 cgd /*
2 1.1 cgd * Implementation of SVID semaphores
3 1.1 cgd *
4 1.1 cgd * Author: Daniel Boulet
5 1.1 cgd *
6 1.1 cgd * This software is provided ``AS IS'' without any warranties of any kind.
7 1.1 cgd */
8 1.1 cgd
9 1.1 cgd #ifdef SYSVSEM
10 1.1 cgd
11 1.3 mycroft #include <sys/param.h>
12 1.3 mycroft #include <sys/systm.h>
13 1.3 mycroft #include <sys/kernel.h>
14 1.3 mycroft #include <sys/proc.h>
15 1.3 mycroft #include <sys/sem.h>
16 1.3 mycroft #include <sys/malloc.h>
17 1.1 cgd
18 1.1 cgd static int semctl(), semget(), semop(), semconfig();
19 1.1 cgd int (*semcalls[])() = { semctl, semget, semop, semconfig };
20 1.1 cgd int semtot = 0;
21 1.1 cgd
22 1.1 cgd static struct proc *semlock_holder = NULL;
23 1.1 cgd
24 1.1 cgd int
25 1.1 cgd seminit()
26 1.1 cgd {
27 1.1 cgd register int i;
28 1.1 cgd vm_offset_t whocares1, whocares2;
29 1.1 cgd
30 1.1 cgd if ( sema == NULL ) {
31 1.1 cgd panic("sema is NULL");
32 1.1 cgd }
33 1.1 cgd for ( i = 0; i < seminfo.semmni; i += 1 ) {
34 1.1 cgd sema[i].sem_base = 0;
35 1.1 cgd sema[i].sem_perm.mode = 0;
36 1.1 cgd }
37 1.1 cgd if ( semu == NULL ) {
38 1.1 cgd panic("semu is NULL");
39 1.1 cgd }
40 1.1 cgd for ( i = 0; i < seminfo.semmnu; i += 1 ) {
41 1.1 cgd register struct sem_undo *suptr = SEMU(i);
42 1.1 cgd suptr->un_proc = NULL;
43 1.1 cgd }
44 1.1 cgd semu_list = NULL;
45 1.1 cgd }
46 1.1 cgd
47 1.1 cgd /*
48 1.1 cgd * Entry point for all SEM calls
49 1.1 cgd */
50 1.1 cgd
51 1.1 cgd struct semsys_args {
52 1.1 cgd u_int which;
53 1.1 cgd };
54 1.1 cgd
55 1.1 cgd int
56 1.1 cgd semsys(p, uap, retval)
57 1.1 cgd struct proc *p;
58 1.1 cgd struct semsys_args *uap;
59 1.1 cgd int *retval;
60 1.1 cgd {
61 1.1 cgd while ( semlock_holder != NULL && semlock_holder != p ) {
62 1.1 cgd /* printf("semaphore facility locked - sleeping ...\n"); */
63 1.1 cgd sleep( (caddr_t)&semlock_holder, (PZERO - 4) );
64 1.1 cgd }
65 1.1 cgd
66 1.1 cgd if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
67 1.1 cgd return (EINVAL);
68 1.1 cgd return ((*semcalls[uap->which])(p, &uap[1], retval));
69 1.1 cgd }
70 1.1 cgd
71 1.1 cgd /*
72 1.1 cgd * Lock or unlock the entire semaphore facility.
73 1.1 cgd *
74 1.1 cgd * This will probably eventually evolve into a general purpose semaphore
75 1.1 cgd * facility status enquiry mechanism (I don't like the "read /dev/kmem"
76 1.1 cgd * approach currently taken by ipcs and the amount of info that we want
77 1.1 cgd * to be able to extract for ipcs is probably beyond what the capability
78 1.1 cgd * of the getkerninfo facility.
79 1.1 cgd *
80 1.1 cgd * At the time that the current version of semconfig was written, ipcs is
81 1.1 cgd * the only user of the semconfig facility. It uses it to ensure that the
82 1.1 cgd * semaphore facility data structures remain static while it fishes around
83 1.1 cgd * in /dev/kmem.
84 1.1 cgd */
85 1.1 cgd
86 1.1 cgd struct semconfig_args {
87 1.1 cgd semconfig_ctl_t flag;
88 1.1 cgd };
89 1.1 cgd
90 1.1 cgd int
91 1.1 cgd semconfig(p, uap, retval)
92 1.1 cgd struct proc *p;
93 1.1 cgd struct semconfig_args *uap;
94 1.1 cgd int *retval;
95 1.1 cgd {
96 1.1 cgd int eval = 0;
97 1.1 cgd
98 1.1 cgd switch ( uap->flag ) {
99 1.1 cgd case SEM_CONFIG_FREEZE:
100 1.1 cgd semlock_holder = p;
101 1.1 cgd break;
102 1.1 cgd case SEM_CONFIG_THAW:
103 1.1 cgd semlock_holder = NULL;
104 1.1 cgd wakeup( (caddr_t)&semlock_holder );
105 1.1 cgd break;
106 1.1 cgd default:
107 1.1 cgd printf("semconfig: unknown flag parameter value (%d) - ignored\n",uap->flag);
108 1.1 cgd eval = EINVAL;
109 1.1 cgd break;
110 1.1 cgd }
111 1.1 cgd
112 1.1 cgd *retval = 0;
113 1.1 cgd return(eval);
114 1.1 cgd }
115 1.1 cgd
116 1.1 cgd /*
117 1.1 cgd * Allocate a new sem_undo structure for a process
118 1.1 cgd * (returns ptr to structure or NULL if no more room)
119 1.1 cgd */
120 1.1 cgd
121 1.1 cgd struct sem_undo *
122 1.1 cgd semu_alloc(struct proc *p)
123 1.1 cgd {
124 1.1 cgd register int i;
125 1.1 cgd register struct sem_undo *suptr;
126 1.1 cgd register struct sem_undo **supptr;
127 1.1 cgd int attempt;
128 1.1 cgd
129 1.1 cgd /*
130 1.1 cgd * Try twice to allocate something.
131 1.1 cgd * (we'll purge any empty structures after the first pass so
132 1.1 cgd * two passes are always enough)
133 1.1 cgd */
134 1.1 cgd
135 1.1 cgd for ( attempt = 0; attempt < 2; attempt += 1 ) {
136 1.1 cgd
137 1.1 cgd /*
138 1.1 cgd * Look for a free structure.
139 1.1 cgd * Fill it in and return it if we find one.
140 1.1 cgd */
141 1.1 cgd
142 1.1 cgd for ( i = 0; i < seminfo.semmnu; i += 1 ) {
143 1.1 cgd suptr = SEMU(i);
144 1.1 cgd if ( suptr->un_proc == NULL ) {
145 1.1 cgd suptr->un_next = semu_list;
146 1.1 cgd semu_list = suptr;
147 1.1 cgd suptr->un_cnt = 0;
148 1.1 cgd suptr->un_proc = p;
149 1.1 cgd return(suptr);
150 1.1 cgd }
151 1.1 cgd }
152 1.1 cgd
153 1.1 cgd /*
154 1.1 cgd * We didn't find a free one, if this is the first attempt
155 1.1 cgd * then try to free some structures.
156 1.1 cgd */
157 1.1 cgd
158 1.1 cgd if ( attempt == 0 ) {
159 1.1 cgd
160 1.1 cgd /* All the structures are in use - try to free some */
161 1.1 cgd
162 1.1 cgd int did_something = 0;
163 1.1 cgd
164 1.1 cgd supptr = &semu_list;
165 1.1 cgd while ( (suptr = *supptr) != NULL ) {
166 1.1 cgd if ( suptr->un_cnt == 0 ) {
167 1.1 cgd suptr->un_proc = NULL;
168 1.1 cgd *supptr = suptr->un_next;
169 1.1 cgd did_something = 1;
170 1.1 cgd } else {
171 1.1 cgd supptr = &(suptr->un_next);
172 1.1 cgd }
173 1.1 cgd }
174 1.1 cgd
175 1.1 cgd /* If we didn't free anything then just give-up */
176 1.1 cgd
177 1.1 cgd if ( !did_something ) {
178 1.1 cgd return(NULL);
179 1.1 cgd }
180 1.1 cgd
181 1.1 cgd } else {
182 1.1 cgd
183 1.1 cgd /*
184 1.1 cgd * The second pass failed even though we freed
185 1.1 cgd * something after the first pass!
186 1.1 cgd * This is IMPOSSIBLE!
187 1.1 cgd */
188 1.1 cgd
189 1.1 cgd panic("semu_alloc - second attempt failed");
190 1.1 cgd
191 1.1 cgd }
192 1.1 cgd
193 1.1 cgd }
194 1.1 cgd
195 1.1 cgd }
196 1.1 cgd
197 1.1 cgd /*
198 1.1 cgd * Adjust a particular entry for a particular proc
199 1.1 cgd */
200 1.1 cgd
201 1.1 cgd int
202 1.1 cgd semundo_adjust(register struct proc *p,struct sem_undo **supptr,int semid,int semnum,int adjval)
203 1.1 cgd {
204 1.1 cgd register struct sem_undo *suptr;
205 1.1 cgd register struct undo *sunptr;
206 1.1 cgd int i;
207 1.1 cgd
208 1.1 cgd /* Look for and remember the sem_undo if the caller doesn't provide it */
209 1.1 cgd
210 1.1 cgd suptr = *supptr;
211 1.1 cgd if ( suptr == NULL ) {
212 1.1 cgd /* printf("adjust: need to find suptr\n"); */
213 1.1 cgd for ( suptr = semu_list; suptr != NULL; suptr = suptr->un_next ) {
214 1.1 cgd if ( suptr->un_proc == p ) {
215 1.1 cgd /* printf("adjust: found suptr @%08x\n",suptr); */
216 1.1 cgd *supptr = suptr;
217 1.1 cgd break;
218 1.1 cgd }
219 1.1 cgd }
220 1.1 cgd if ( suptr == NULL ) {
221 1.1 cgd if ( adjval == 0 ) {
222 1.1 cgd return(0); /* Don't create it if it doesn't exist */
223 1.1 cgd }
224 1.1 cgd suptr = semu_alloc(p);
225 1.1 cgd if ( suptr == NULL ) {
226 1.1 cgd return(ENOSPC);
227 1.1 cgd }
228 1.1 cgd /* printf("adjust: allocated suptr @%08x\n",suptr); */
229 1.1 cgd *supptr = suptr;
230 1.1 cgd }
231 1.1 cgd }
232 1.1 cgd
233 1.1 cgd /* Look for the requested entry and adjust it (delete if adjval becomes 0) */
234 1.1 cgd
235 1.1 cgd sunptr = &(suptr->un_ent[0]);
236 1.1 cgd for ( i = 0; i < suptr->un_cnt; i += 1, sunptr += 1 ) {
237 1.1 cgd
238 1.1 cgd if ( sunptr->un_id == semid && sunptr->un_num == semnum ) {
239 1.1 cgd
240 1.1 cgd /* Found the right entry - adjust it */
241 1.1 cgd
242 1.1 cgd if ( adjval == 0 ) {
243 1.1 cgd sunptr->un_adjval = 0;
244 1.1 cgd } else {
245 1.1 cgd /* printf("adjust: %08x %d:%d(%d) += %d\n",suptr->un_proc,semid,semnum,sunptr->un_adjval,adjval); */
246 1.1 cgd sunptr->un_adjval += adjval;
247 1.1 cgd }
248 1.1 cgd if ( sunptr->un_adjval == 0 ) {
249 1.1 cgd /* printf("adjust: %08x deleting entry %d:%d\n",suptr->un_proc,semid,semnum); */
250 1.1 cgd suptr->un_cnt -= 1;
251 1.1 cgd if ( i < suptr->un_cnt ) {
252 1.1 cgd suptr->un_ent[i] = suptr->un_ent[suptr->un_cnt];
253 1.1 cgd }
254 1.1 cgd }
255 1.1 cgd return(0);
256 1.1 cgd
257 1.1 cgd }
258 1.1 cgd }
259 1.1 cgd
260 1.1 cgd /* Didn't find the right entry - create it */
261 1.1 cgd
262 1.1 cgd if ( adjval == 0 ) {
263 1.1 cgd return(0);
264 1.1 cgd }
265 1.1 cgd if ( suptr->un_cnt == SEMUME ) {
266 1.1 cgd return(EINVAL);
267 1.1 cgd } else {
268 1.1 cgd /* printf("adjust: %08x allocating entry %d as %d:%d(%d)\n",suptr->un_proc,suptr->un_cnt,semid,semnum,adjval); */
269 1.1 cgd sunptr = &(suptr->un_ent[suptr->un_cnt]);
270 1.1 cgd suptr->un_cnt += 1;
271 1.1 cgd sunptr->un_adjval = adjval;
272 1.1 cgd sunptr->un_id = semid; sunptr->un_num = semnum;
273 1.1 cgd }
274 1.1 cgd return(0);
275 1.1 cgd }
276 1.1 cgd
277 1.1 cgd
278 1.1 cgd void
279 1.1 cgd semundo_clear(int semid,int semnum)
280 1.1 cgd {
281 1.1 cgd register struct sem_undo *suptr;
282 1.1 cgd
283 1.1 cgd for ( suptr = semu_list; suptr != NULL; suptr = suptr->un_next ) {
284 1.1 cgd
285 1.1 cgd register struct undo *sunptr = &(suptr->un_ent[0]);
286 1.1 cgd register int i = 0;
287 1.1 cgd
288 1.1 cgd while ( i < suptr->un_cnt ) {
289 1.1 cgd int advance = 1;
290 1.1 cgd
291 1.1 cgd if ( sunptr->un_id == semid ) {
292 1.1 cgd if ( semnum == -1 || sunptr->un_num == semnum ) {
293 1.1 cgd /* printf("clear: %08x %d:%d(%d)\n",suptr->un_proc,semid,sunptr->un_num,sunptr->un_adjval); */
294 1.1 cgd suptr->un_cnt -= 1;
295 1.1 cgd if ( i < suptr->un_cnt ) {
296 1.1 cgd suptr->un_ent[i] = suptr->un_ent[suptr->un_cnt];
297 1.1 cgd advance = 0;
298 1.1 cgd }
299 1.1 cgd }
300 1.1 cgd if ( semnum != -1 ) {
301 1.1 cgd break;
302 1.1 cgd }
303 1.1 cgd }
304 1.1 cgd
305 1.1 cgd if ( advance ) {
306 1.1 cgd i += 1;
307 1.1 cgd sunptr += 1;
308 1.1 cgd }
309 1.1 cgd
310 1.1 cgd }
311 1.1 cgd
312 1.1 cgd }
313 1.1 cgd
314 1.1 cgd }
315 1.1 cgd
316 1.1 cgd struct semctl_args {
317 1.1 cgd int semid;
318 1.1 cgd int semnum;
319 1.1 cgd int cmd;
320 1.1 cgd union semun *arg;
321 1.1 cgd };
322 1.1 cgd
323 1.1 cgd int
324 1.1 cgd semctl(p, uap, retval)
325 1.1 cgd struct proc *p;
326 1.1 cgd register struct semctl_args *uap;
327 1.1 cgd int *retval;
328 1.1 cgd {
329 1.1 cgd int semid = uap->semid;
330 1.1 cgd int semnum = uap->semnum;
331 1.1 cgd int cmd = uap->cmd;
332 1.1 cgd union semun *arg = uap->arg;
333 1.1 cgd union semun real_arg;
334 1.1 cgd struct ucred *cred = p->p_ucred;
335 1.1 cgd int i, rval, eval;
336 1.1 cgd struct semid_ds sbuf;
337 1.1 cgd register struct semid_ds *semaptr;
338 1.1 cgd
339 1.1 cgd #ifdef SEM_DEBUG
340 1.1 cgd printf("call to semctl(%d,%d,%d,0x%x)\n",semid,semnum,cmd,arg);
341 1.1 cgd #endif
342 1.1 cgd
343 1.1 cgd semid = IPCID_TO_IX(semid);
344 1.1 cgd
345 1.1 cgd if ( semid < 0 || semid >= seminfo.semmsl ) {
346 1.1 cgd /* printf("semid out of range (0<=%d<%d)\n",semid,seminfo.semmsl); */
347 1.1 cgd return(EINVAL);
348 1.1 cgd }
349 1.1 cgd
350 1.1 cgd semaptr = &sema[semid];
351 1.1 cgd
352 1.1 cgd if ( semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid) ) {
353 1.1 cgd /* printf("invalid sequence number\n"); */
354 1.1 cgd return(EINVAL);
355 1.1 cgd }
356 1.1 cgd
357 1.1 cgd if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) {
358 1.1 cgd /* printf("no such semaphore id\n"); */
359 1.1 cgd return(EINVAL);
360 1.1 cgd }
361 1.1 cgd
362 1.1 cgd eval = 0;
363 1.1 cgd rval = 0;
364 1.1 cgd
365 1.1 cgd switch (cmd) {
366 1.1 cgd
367 1.1 cgd case IPC_RMID:
368 1.1 cgd if ( cred->cr_uid != 0
369 1.1 cgd && semaptr->sem_perm.cuid != cred->cr_uid
370 1.1 cgd && semaptr->sem_perm.uid != cred->cr_uid ) {
371 1.1 cgd return(EPERM);
372 1.1 cgd }
373 1.1 cgd semaptr->sem_perm.cuid = cred->cr_uid;
374 1.1 cgd semaptr->sem_perm.uid = cred->cr_uid;
375 1.1 cgd semtot -= semaptr->sem_nsems;
376 1.1 cgd for ( i = semaptr->sem_base - sem; i < semtot; i += 1 ) {
377 1.1 cgd /* printf("0x%x = 0x%x; ",&sem[i],&sem[i + semaptr->sem_nsems]); */
378 1.1 cgd sem[i] = sem[i + semaptr->sem_nsems];
379 1.1 cgd }
380 1.1 cgd /* printf("\n"); */
381 1.1 cgd for ( i = 0; i < seminfo.semmni; i += 1 ) {
382 1.1 cgd if ( (sema[i].sem_perm.mode & SEM_ALLOC)
383 1.1 cgd && sema[i].sem_base > semaptr->sem_base ) {
384 1.1 cgd /* printf("sema[%d].sem_base was 0x%x",i,sema[i].sem_base); */
385 1.1 cgd sema[i].sem_base -= semaptr->sem_nsems;
386 1.1 cgd /* printf(", now 0x%x\n",sema[i].sem_base); */
387 1.1 cgd }
388 1.1 cgd }
389 1.1 cgd semaptr->sem_perm.mode = 0;
390 1.1 cgd
391 1.1 cgd /* Delete any undo entries for this semid */
392 1.1 cgd
393 1.1 cgd semundo_clear(semid,-1);
394 1.1 cgd
395 1.1 cgd /* Make sure that anybody who is waiting notices the deletion */
396 1.1 cgd
397 1.1 cgd wakeup( (caddr_t)semaptr );
398 1.1 cgd
399 1.1 cgd break;
400 1.1 cgd
401 1.1 cgd case IPC_SET:
402 1.1 cgd /* printf("IPC_SET\n"); */
403 1.1 cgd if ( cred->cr_uid != 0
404 1.1 cgd && semaptr->sem_perm.cuid != cred->cr_uid
405 1.1 cgd && semaptr->sem_perm.uid != cred->cr_uid ) {
406 1.1 cgd return(EPERM);
407 1.1 cgd }
408 1.1 cgd if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) {
409 1.1 cgd return(eval);
410 1.1 cgd }
411 1.1 cgd if ( (eval = copyin(real_arg.buf, (caddr_t)&sbuf, sizeof(sbuf)) ) != 0 ) {
412 1.1 cgd return(eval);
413 1.1 cgd }
414 1.1 cgd semaptr->sem_perm.uid = sbuf.sem_perm.uid;
415 1.1 cgd semaptr->sem_perm.gid = sbuf.sem_perm.gid;
416 1.1 cgd semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777)
417 1.1 cgd | (sbuf.sem_perm.mode & 0777);
418 1.1 cgd semaptr->sem_ctime = time.tv_sec;
419 1.1 cgd break;
420 1.1 cgd
421 1.1 cgd case IPC_STAT:
422 1.1 cgd /* printf("IPC_STAT\n"); */
423 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) {
424 1.1 cgd return(eval);
425 1.1 cgd }
426 1.1 cgd rval = 0;
427 1.1 cgd if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) {
428 1.1 cgd return(eval);
429 1.1 cgd }
430 1.1 cgd eval = copyout((caddr_t)semaptr, real_arg.buf, sizeof(struct semid_ds)) ;
431 1.1 cgd break;
432 1.1 cgd
433 1.1 cgd case GETNCNT:
434 1.1 cgd /* printf("GETNCNT(%d)\n",semnum); */
435 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) {
436 1.1 cgd return(eval);
437 1.1 cgd }
438 1.1 cgd if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL);
439 1.1 cgd rval = semaptr->sem_base[semnum].semncnt;
440 1.1 cgd break;
441 1.1 cgd
442 1.1 cgd case GETPID:
443 1.1 cgd /* printf("GETPID(%d)\n",semnum); */
444 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) {
445 1.1 cgd return(eval);
446 1.1 cgd }
447 1.1 cgd if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL);
448 1.1 cgd rval = semaptr->sem_base[semnum].sempid;
449 1.1 cgd break;
450 1.1 cgd
451 1.1 cgd case GETVAL:
452 1.1 cgd /* printf("GETVAL(%d)\n",semnum); */
453 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) {
454 1.1 cgd return(eval);
455 1.1 cgd }
456 1.1 cgd if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL);
457 1.1 cgd rval = semaptr->sem_base[semnum].semval;
458 1.1 cgd break;
459 1.1 cgd
460 1.1 cgd case GETALL:
461 1.1 cgd /* printf("GETALL\n"); */
462 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) {
463 1.1 cgd return(eval);
464 1.1 cgd }
465 1.1 cgd rval = 0;
466 1.1 cgd if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) {
467 1.1 cgd /* printf("initial copyin failed (addr=0x%x)\n",arg); */
468 1.1 cgd return(eval);
469 1.1 cgd }
470 1.1 cgd /* printf("%d semaphores\n",semaptr->sem_nsems); */
471 1.1 cgd for ( i = 0; i < semaptr->sem_nsems; i += 1 ) {
472 1.1 cgd /* printf("copyout to 0x%x\n",&real_arg.array[i]); */
473 1.1 cgd eval =
474 1.1 cgd copyout((caddr_t)&semaptr->sem_base[i].semval,
475 1.1 cgd &real_arg.array[i],
476 1.1 cgd sizeof(real_arg.array[0]));
477 1.1 cgd if ( eval != 0 ) {
478 1.1 cgd /* printf("copyout to 0x%x failed\n",&real_arg.array[i]); */
479 1.1 cgd break;
480 1.1 cgd }
481 1.1 cgd }
482 1.1 cgd break;
483 1.1 cgd
484 1.1 cgd case GETZCNT:
485 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) {
486 1.1 cgd return(eval);
487 1.1 cgd }
488 1.1 cgd /* printf("GETZCNT(%d)\n",semnum); */
489 1.1 cgd if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL);
490 1.1 cgd rval = semaptr->sem_base[semnum].semzcnt;
491 1.1 cgd break;
492 1.1 cgd
493 1.1 cgd case SETVAL:
494 1.1 cgd #ifdef SEM_DEBUG
495 1.1 cgd printf("SETVAL(%d)\n",semnum);
496 1.1 cgd #endif
497 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)) ) {
498 1.1 cgd return(eval);
499 1.1 cgd }
500 1.1 cgd if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL);
501 1.1 cgd rval = 0;
502 1.1 cgd if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) {
503 1.1 cgd return(eval);
504 1.1 cgd }
505 1.1 cgd #ifdef SEM_DEBUG
506 1.1 cgd printf("semaptr=%x, sem_base=%x, semptr=%x, oldval=%d, ",
507 1.1 cgd semaptr,semaptr->sem_base,&semaptr->sem_base[semnum],semaptr->sem_base[semnum].semval);
508 1.1 cgd #endif
509 1.1 cgd semaptr->sem_base[semnum].semval = real_arg.val;
510 1.1 cgd #ifdef SEM_DEBUG
511 1.1 cgd printf(" newval=%d\n", semaptr->sem_base[semnum].semval);
512 1.1 cgd #endif
513 1.1 cgd semundo_clear(semid,semnum);
514 1.1 cgd wakeup( (caddr_t)semaptr ); /* somebody else might care */
515 1.1 cgd break;
516 1.1 cgd
517 1.1 cgd case SETALL:
518 1.1 cgd /* printf("SETALL\n"); */
519 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)) ) {
520 1.1 cgd return(eval);
521 1.1 cgd }
522 1.1 cgd rval = 0;
523 1.1 cgd if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) {
524 1.1 cgd return(eval);
525 1.1 cgd }
526 1.1 cgd for ( i = 0; i < semaptr->sem_nsems; i += 1 ) {
527 1.1 cgd eval =
528 1.1 cgd copyin(&real_arg.array[i],
529 1.1 cgd (caddr_t)&semaptr->sem_base[i].semval,
530 1.1 cgd sizeof(real_arg.array[0]));
531 1.1 cgd if ( eval != 0 ) {
532 1.1 cgd break;
533 1.1 cgd }
534 1.1 cgd }
535 1.1 cgd semundo_clear(semid,-1);
536 1.1 cgd wakeup( (caddr_t)semaptr ); /* somebody else might care */
537 1.1 cgd break;
538 1.1 cgd default:
539 1.1 cgd /* printf("invalid command %d\n",cmd); */
540 1.1 cgd return(EINVAL);
541 1.1 cgd }
542 1.1 cgd
543 1.1 cgd if ( eval == 0 ) {
544 1.1 cgd *retval = rval;
545 1.1 cgd }
546 1.1 cgd return(eval);
547 1.1 cgd }
548 1.1 cgd
549 1.1 cgd struct semget_args {
550 1.1 cgd key_t key;
551 1.1 cgd int nsems;
552 1.1 cgd int semflg;
553 1.1 cgd };
554 1.1 cgd
555 1.1 cgd int
556 1.1 cgd semget(p, uap, retval)
557 1.1 cgd struct proc *p;
558 1.1 cgd register struct semget_args *uap;
559 1.1 cgd int *retval;
560 1.1 cgd {
561 1.1 cgd int semid, eval;
562 1.1 cgd int key = uap->key;
563 1.1 cgd int nsems = uap->nsems;
564 1.1 cgd int semflg = uap->semflg;
565 1.1 cgd struct ucred *cred = p->p_ucred;
566 1.1 cgd
567 1.1 cgd #ifdef SEM_DEBUG
568 1.1 cgd printf("semget(0x%x,%d,0%o)\n",key,nsems,semflg);
569 1.1 cgd #endif
570 1.1 cgd
571 1.1 cgd if ( key == IPC_PRIVATE ) {
572 1.1 cgd #ifdef SEM_DEBUG
573 1.1 cgd printf("private key\n");
574 1.1 cgd #endif
575 1.1 cgd semid = seminfo.semmni;
576 1.1 cgd } else {
577 1.1 cgd for ( semid = 0; semid < seminfo.semmni; semid += 1 ) {
578 1.1 cgd if ( (sema[semid].sem_perm.mode & SEM_ALLOC)
579 1.1 cgd && sema[semid].sem_perm.key == key ) {
580 1.1 cgd break;
581 1.1 cgd }
582 1.1 cgd }
583 1.1 cgd if ( semid < seminfo.semmni ) {
584 1.1 cgd #ifdef SEM_DEBUG
585 1.1 cgd printf("found public key\n");
586 1.1 cgd #endif
587 1.1 cgd if ( (eval = ipcaccess(&sema[semid].sem_perm, semflg & 0700, cred)) ) {
588 1.1 cgd return(eval);
589 1.1 cgd }
590 1.1 cgd if ( nsems > 0 && sema[semid].sem_nsems < nsems ) {
591 1.1 cgd #ifdef SEM_DEBUG
592 1.1 cgd printf("too small\n");
593 1.1 cgd #endif
594 1.1 cgd return(EINVAL);
595 1.1 cgd }
596 1.1 cgd if ( (semflg & IPC_CREAT) && (semflg & IPC_EXCL) ) {
597 1.1 cgd #ifdef SEM_DEBUG
598 1.1 cgd printf("not exclusive\n");
599 1.1 cgd #endif
600 1.1 cgd return(EEXIST);
601 1.1 cgd }
602 1.1 cgd } else {
603 1.1 cgd #ifdef SEM_DEBUG
604 1.1 cgd printf("didn't find public key\n");
605 1.1 cgd #endif
606 1.1 cgd }
607 1.1 cgd }
608 1.1 cgd
609 1.1 cgd if ( semid == seminfo.semmni ) {
610 1.1 cgd #ifdef SEM_DEBUG
611 1.1 cgd printf("need to allocate the semid_ds\n");
612 1.1 cgd #endif
613 1.1 cgd if ( key == IPC_PRIVATE || (semflg & IPC_CREAT) ) {
614 1.1 cgd if ( nsems <= 0 || nsems > seminfo.semmsl ) {
615 1.1 cgd #ifdef SEM_DEBUG
616 1.1 cgd printf("nsems out of range (0<%d<=%d)\n",nsems,seminfo.semmsl);
617 1.1 cgd #endif
618 1.1 cgd return(EINVAL);
619 1.1 cgd }
620 1.1 cgd if ( nsems > seminfo.semmns - semtot ) {
621 1.1 cgd #ifdef SEM_DEBUG
622 1.1 cgd printf("not enough semaphores left (need %d, got %d)\n",
623 1.1 cgd nsems,seminfo.semmns - semtot);
624 1.1 cgd #endif
625 1.1 cgd return(ENOSPC);
626 1.1 cgd }
627 1.1 cgd for ( semid = 0; semid < seminfo.semmni; semid += 1 ) {
628 1.1 cgd if ( (sema[semid].sem_perm.mode & SEM_ALLOC) == 0 ) {
629 1.1 cgd break;
630 1.1 cgd }
631 1.1 cgd }
632 1.1 cgd if ( semid == seminfo.semmni ) {
633 1.1 cgd #ifdef SEM_DEBUG
634 1.1 cgd printf("no more semid_ds's available\n");
635 1.1 cgd #endif
636 1.1 cgd return(ENOSPC);
637 1.1 cgd }
638 1.1 cgd #ifdef SEM_DEBUG
639 1.1 cgd printf("semid %d is available\n",semid);
640 1.1 cgd #endif
641 1.1 cgd sema[semid].sem_perm.key = key;
642 1.1 cgd sema[semid].sem_perm.cuid = cred->cr_uid;
643 1.1 cgd sema[semid].sem_perm.uid = cred->cr_uid;
644 1.1 cgd sema[semid].sem_perm.cgid = cred->cr_gid;
645 1.1 cgd sema[semid].sem_perm.gid = cred->cr_gid;
646 1.1 cgd sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
647 1.1 cgd sema[semid].sem_perm.seq = (sema[semid].sem_perm.seq + 1) & 0x7fff; /* avoid semid overflows */
648 1.1 cgd sema[semid].sem_nsems = nsems;
649 1.1 cgd sema[semid].sem_otime = 0;
650 1.1 cgd sema[semid].sem_ctime = time.tv_sec;
651 1.1 cgd sema[semid].sem_base = &sem[semtot];
652 1.1 cgd semtot += nsems;
653 1.1 cgd bzero(sema[semid].sem_base,sizeof(sema[semid].sem_base[0])*nsems);
654 1.1 cgd #ifdef SEM_DEBUG
655 1.1 cgd printf("sembase = 0x%x, next = 0x%x\n",sema[semid].sem_base,&sem[semtot]);
656 1.1 cgd #endif
657 1.1 cgd } else {
658 1.1 cgd #ifdef SEM_DEBUG
659 1.1 cgd printf("didn't find it and wasn't asked to create it\n");
660 1.1 cgd #endif
661 1.1 cgd return(ENOENT);
662 1.1 cgd }
663 1.1 cgd }
664 1.1 cgd
665 1.1 cgd *retval = IXSEQ_TO_IPCID(semid,sema[semid].sem_perm); /* Convert to one origin */
666 1.1 cgd return(0);
667 1.1 cgd }
668 1.1 cgd
669 1.1 cgd struct semop_args {
670 1.1 cgd int semid;
671 1.1 cgd struct sembuf *sops;
672 1.1 cgd int nsops;
673 1.1 cgd };
674 1.1 cgd
675 1.1 cgd int
676 1.1 cgd semop(p, uap, retval)
677 1.1 cgd struct proc *p;
678 1.1 cgd register struct semop_args *uap;
679 1.1 cgd int *retval;
680 1.1 cgd {
681 1.1 cgd int semid = uap->semid;
682 1.1 cgd int nsops = uap->nsops;
683 1.1 cgd struct sembuf sops[MAX_SOPS];
684 1.1 cgd register struct semid_ds *semaptr;
685 1.1 cgd register struct sembuf *sopptr;
686 1.1 cgd register struct sem *semptr;
687 1.1 cgd struct sem_undo *suptr = NULL;
688 1.1 cgd struct ucred *cred = p->p_ucred;
689 1.1 cgd int i, j, eval;
690 1.1 cgd int all_ok, do_wakeup, do_undos;
691 1.1 cgd
692 1.1 cgd #ifdef SEM_DEBUG
693 1.1 cgd printf("call to semop(%d,0x%x,%d)\n",semid,sops,nsops);
694 1.1 cgd #endif
695 1.1 cgd
696 1.1 cgd semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
697 1.1 cgd
698 1.1 cgd if ( semid < 0 || semid >= seminfo.semmsl ) {
699 1.1 cgd /* printf("semid out of range (0<=%d<%d)\n",semid,seminfo.semmsl); */
700 1.1 cgd return(EINVAL);
701 1.1 cgd }
702 1.1 cgd
703 1.1 cgd semaptr = &sema[semid];
704 1.1 cgd if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) {
705 1.1 cgd /* printf("no such semaphore id\n"); */
706 1.1 cgd return(EINVAL);
707 1.1 cgd }
708 1.1 cgd
709 1.1 cgd if ( semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid) ) {
710 1.1 cgd /* printf("invalid sequence number\n"); */
711 1.1 cgd return(EINVAL);
712 1.1 cgd }
713 1.1 cgd
714 1.1 cgd if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)) ) {
715 1.1 cgd #ifdef SEM_DEBUG
716 1.1 cgd printf("eval = %d from ipaccess\n",eval);
717 1.1 cgd #endif
718 1.1 cgd return(eval);
719 1.1 cgd }
720 1.1 cgd
721 1.1 cgd if ( nsops > MAX_SOPS ) {
722 1.1 cgd #ifdef SEM_DEBUG
723 1.1 cgd printf("too many sops (max=%d, nsops=%d)\n",MAX_SOPS,nsops);
724 1.1 cgd #endif
725 1.1 cgd return(E2BIG);
726 1.1 cgd }
727 1.1 cgd
728 1.1 cgd if ( (eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0 ) {
729 1.1 cgd #ifdef SEM_DEBUG
730 1.1 cgd printf("eval = %d from copyin(%08x, %08x, %d)\n",eval,uap->sops,&sops,nsops * sizeof(sops[0]));
731 1.1 cgd #endif
732 1.1 cgd return(eval);
733 1.1 cgd }
734 1.1 cgd
735 1.1 cgd /*
736 1.1 cgd * Loop trying to satisfy the vector of requests.
737 1.1 cgd * If we reach a point where we must wait, any requests already
738 1.1 cgd * performed are rolled back and we go to sleep until some other
739 1.1 cgd * process wakes us up. At this point, we start all over again.
740 1.1 cgd *
741 1.1 cgd * This ensures that from the perspective of other tasks, a set
742 1.1 cgd * of requests is atomic (never partially satisfied).
743 1.1 cgd */
744 1.1 cgd
745 1.1 cgd do_undos = 0;
746 1.1 cgd
747 1.1 cgd while (1) {
748 1.1 cgd
749 1.1 cgd do_wakeup = 0;
750 1.1 cgd
751 1.1 cgd for ( i = 0; i < nsops; i += 1 ) {
752 1.1 cgd
753 1.1 cgd sopptr = &sops[i];
754 1.1 cgd
755 1.2 cgd if ( sopptr->sem_num >= semaptr->sem_nsems ) {
756 1.1 cgd return(EFBIG);
757 1.1 cgd }
758 1.1 cgd
759 1.1 cgd semptr = &semaptr->sem_base[sopptr->sem_num];
760 1.1 cgd
761 1.1 cgd #ifdef SEM_DEBUG
762 1.1 cgd printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
763 1.1 cgd semaptr,semaptr->sem_base,semptr,
764 1.1 cgd sopptr->sem_num,semptr->semval,sopptr->sem_op,
765 1.1 cgd (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
766 1.1 cgd #endif
767 1.1 cgd
768 1.1 cgd if ( sopptr->sem_op < 0 ) {
769 1.1 cgd
770 1.1 cgd if ( semptr->semval + sopptr->sem_op < 0 ) {
771 1.1 cgd #ifdef SEM_DEBUG
772 1.1 cgd printf("semop: can't do it now\n");
773 1.1 cgd #endif
774 1.1 cgd break;
775 1.1 cgd } else {
776 1.1 cgd semptr->semval += sopptr->sem_op;
777 1.1 cgd if ( semptr->semval == 0 && semptr->semzcnt > 0 ) {
778 1.1 cgd do_wakeup = 1;
779 1.1 cgd }
780 1.1 cgd }
781 1.1 cgd if ( sopptr->sem_flg & SEM_UNDO ) {
782 1.1 cgd do_undos = 1;
783 1.1 cgd }
784 1.1 cgd
785 1.1 cgd } else if ( sopptr->sem_op == 0 ) {
786 1.1 cgd
787 1.1 cgd if ( semptr->semval > 0 ) {
788 1.1 cgd #ifdef SEM_DEBUG
789 1.1 cgd printf("semop: not zero now\n");
790 1.1 cgd #endif
791 1.1 cgd break;
792 1.1 cgd }
793 1.1 cgd
794 1.1 cgd } else {
795 1.1 cgd
796 1.1 cgd if ( semptr->semncnt > 0 ) {
797 1.1 cgd do_wakeup = 1;
798 1.1 cgd }
799 1.1 cgd semptr->semval += sopptr->sem_op;
800 1.1 cgd if ( sopptr->sem_flg & SEM_UNDO ) {
801 1.1 cgd do_undos = 1;
802 1.1 cgd }
803 1.1 cgd
804 1.1 cgd }
805 1.1 cgd }
806 1.1 cgd
807 1.1 cgd /*
808 1.1 cgd * Did we get through the entire vector?
809 1.1 cgd */
810 1.1 cgd
811 1.1 cgd if ( i < nsops ) {
812 1.1 cgd
813 1.1 cgd /*
814 1.1 cgd * No ... rollback anything that we've already done
815 1.1 cgd */
816 1.1 cgd
817 1.1 cgd #ifdef SEM_DEBUG
818 1.1 cgd printf("semop: rollback 0 through %d\n",i-1);
819 1.1 cgd #endif
820 1.1 cgd for ( j = 0; j < i; j += 1 ) {
821 1.1 cgd semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op;
822 1.1 cgd }
823 1.1 cgd
824 1.1 cgd /*
825 1.1 cgd * If the request that we couldn't satisfy has the NOWAIT
826 1.1 cgd * flag set then return with EAGAIN.
827 1.1 cgd */
828 1.1 cgd
829 1.1 cgd if ( sopptr->sem_flg & IPC_NOWAIT ) {
830 1.1 cgd return(EAGAIN);
831 1.1 cgd }
832 1.1 cgd
833 1.1 cgd if ( sopptr->sem_op == 0 ) {
834 1.1 cgd semptr->semzcnt += 1;
835 1.1 cgd } else {
836 1.1 cgd semptr->semncnt += 1;
837 1.1 cgd }
838 1.1 cgd
839 1.1 cgd #ifdef SEM_DEBUG
840 1.1 cgd printf("semop: good night!\n");
841 1.1 cgd #endif
842 1.1 cgd eval = tsleep( (caddr_t)semaptr, (PZERO - 4) | PCATCH, "sem wait", 0 );
843 1.1 cgd #ifdef SEM_DEBUG
844 1.1 cgd printf("semop: good morning (eval=%d)!\n",eval);
845 1.1 cgd #endif
846 1.1 cgd
847 1.1 cgd suptr = NULL; /* The sem_undo may have been reallocated */
848 1.1 cgd
849 1.1 cgd if ( eval != 0 ) {
850 1.1 cgd /* printf("semop: interrupted system call\n"); */
851 1.1 cgd return( EINTR );
852 1.1 cgd }
853 1.1 cgd #ifdef SEM_DEBUG
854 1.1 cgd printf("semop: good morning!\n");
855 1.1 cgd #endif
856 1.1 cgd
857 1.1 cgd /*
858 1.1 cgd * Make sure that the semaphore still exists
859 1.1 cgd */
860 1.1 cgd
861 1.1 cgd if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0
862 1.1 cgd || semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid) ) {
863 1.1 cgd
864 1.1 cgd /* printf("semaphore id deleted\n"); */
865 1.1 cgd /* The man page says to return EIDRM. */
866 1.1 cgd /* Unfortunately, BSD doesn't define that code! */
867 1.1 cgd #ifdef EIDRM
868 1.1 cgd return(EIDRM);
869 1.1 cgd #else
870 1.1 cgd return(EINVAL);
871 1.1 cgd #endif
872 1.1 cgd }
873 1.1 cgd
874 1.1 cgd /*
875 1.1 cgd * The semaphore is still alive. Readjust the count of
876 1.1 cgd * waiting processes.
877 1.1 cgd */
878 1.1 cgd
879 1.1 cgd if ( sopptr->sem_op == 0 ) {
880 1.1 cgd semptr->semzcnt -= 1;
881 1.1 cgd } else {
882 1.1 cgd semptr->semncnt -= 1;
883 1.1 cgd }
884 1.1 cgd
885 1.1 cgd
886 1.1 cgd } else {
887 1.1 cgd
888 1.1 cgd /*
889 1.1 cgd * Yes ... we're done.
890 1.1 cgd * Process any SEM_UNDO requests.
891 1.1 cgd */
892 1.1 cgd
893 1.1 cgd if ( do_undos ) {
894 1.1 cgd
895 1.1 cgd for ( i = 0; i < nsops; i += 1 ) {
896 1.1 cgd
897 1.1 cgd /* We only need to deal with SEM_UNDO's for non-zero op's */
898 1.1 cgd int adjval;
899 1.1 cgd
900 1.1 cgd if ( (sops[i].sem_flg & SEM_UNDO) != 0 && (adjval = sops[i].sem_op) != 0 ) {
901 1.1 cgd
902 1.1 cgd eval = semundo_adjust(p,&suptr,semid,sops[i].sem_num,-adjval);
903 1.1 cgd if ( eval != 0 ) {
904 1.1 cgd
905 1.1 cgd /*
906 1.1 cgd * Oh-Oh! We ran out of either sem_undo's or undo's.
907 1.1 cgd * Rollback the adjustments to this point and then
908 1.1 cgd * rollback the semaphore ups and down so we can
909 1.1 cgd * return with an error with all structures restored.
910 1.1 cgd * We rollback the undo's in the exact reverse order that
911 1.1 cgd * we applied them. This guarantees that we won't run
912 1.1 cgd * out of space as we roll things back out.
913 1.1 cgd */
914 1.1 cgd
915 1.1 cgd for ( j = i - 1; j >= 0; j -= 1 ) {
916 1.1 cgd
917 1.1 cgd if ( (sops[i].sem_flg & SEM_UNDO) != 0 && (adjval = sops[i].sem_op) != 0 ) {
918 1.1 cgd
919 1.1 cgd if ( semundo_adjust(p,&suptr,semid,sops[j].sem_num,adjval) != 0 ) {
920 1.1 cgd
921 1.1 cgd /* This is impossible! */
922 1.1 cgd panic("semop - can't undo undos");
923 1.1 cgd
924 1.1 cgd }
925 1.1 cgd }
926 1.1 cgd
927 1.1 cgd } /* loop backwards through sops */
928 1.1 cgd
929 1.1 cgd for ( j = 0; j < nsops; j += 1 ) {
930 1.1 cgd semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op;
931 1.1 cgd }
932 1.1 cgd
933 1.1 cgd #ifdef SEM_DEBUG
934 1.1 cgd printf("eval = %d from semundo_adjust\n",eval);
935 1.1 cgd #endif
936 1.1 cgd return( eval );
937 1.1 cgd
938 1.1 cgd } /* semundo_adjust failed */
939 1.1 cgd
940 1.1 cgd } /* if ( SEM_UNDO && adjval != 0 ) */
941 1.1 cgd
942 1.1 cgd } /* loop through the sops */
943 1.1 cgd
944 1.1 cgd } /* if ( do_undos ) */
945 1.1 cgd
946 1.1 cgd /* We're definitely done - set the sempid's */
947 1.1 cgd
948 1.1 cgd for ( i = 0; i < nsops; i += 1 ) {
949 1.1 cgd
950 1.1 cgd sopptr = &sops[i];
951 1.1 cgd semptr = &semaptr->sem_base[sopptr->sem_num];
952 1.1 cgd semptr->sempid = p->p_pid;
953 1.1 cgd
954 1.1 cgd }
955 1.1 cgd
956 1.1 cgd /* Do a wakeup if any semaphore was up'd. */
957 1.1 cgd
958 1.1 cgd if ( do_wakeup ) {
959 1.1 cgd #ifdef SEM_DEBUG
960 1.1 cgd printf("semop: doing wakeup\n");
961 1.1 cgd #ifdef SEM_WAKEUP
962 1.1 cgd sem_wakeup( (caddr_t)semaptr );
963 1.1 cgd #else
964 1.1 cgd wakeup( (caddr_t)semaptr );
965 1.1 cgd #endif
966 1.1 cgd printf("semop: back from wakeup\n");
967 1.1 cgd #else
968 1.1 cgd wakeup( (caddr_t)semaptr );
969 1.1 cgd #endif
970 1.1 cgd }
971 1.1 cgd #ifdef SEM_DEBUG
972 1.1 cgd printf("semop: done\n");
973 1.1 cgd #endif
974 1.1 cgd *retval = 0;
975 1.1 cgd return(0);
976 1.1 cgd
977 1.1 cgd }
978 1.1 cgd
979 1.1 cgd }
980 1.1 cgd
981 1.1 cgd panic("semop: how did we get here???");
982 1.1 cgd }
983 1.1 cgd
984 1.1 cgd /*
985 1.1 cgd * Go through the undo structures for this process and apply the
986 1.1 cgd * adjustments to semaphores.
987 1.1 cgd */
988 1.1 cgd
989 1.1 cgd semexit(p)
990 1.1 cgd struct proc *p;
991 1.1 cgd {
992 1.1 cgd register struct sem_undo *suptr;
993 1.1 cgd register struct sem_undo **supptr;
994 1.1 cgd int did_something;
995 1.1 cgd
996 1.1 cgd /*
997 1.1 cgd * If somebody else is holding the global semaphore facility lock
998 1.1 cgd * then sleep until it is released.
999 1.1 cgd */
1000 1.1 cgd
1001 1.1 cgd while ( semlock_holder != NULL && semlock_holder != p ) {
1002 1.1 cgd #ifdef SEM_DEBUG
1003 1.1 cgd printf("semaphore facility locked - sleeping ...\n");
1004 1.1 cgd #endif
1005 1.1 cgd sleep( (caddr_t)&semlock_holder, (PZERO - 4) );
1006 1.1 cgd }
1007 1.1 cgd
1008 1.1 cgd did_something = 0;
1009 1.1 cgd
1010 1.1 cgd /*
1011 1.1 cgd * Go through the chain of undo vectors looking for one
1012 1.1 cgd * associated with this process.
1013 1.1 cgd */
1014 1.1 cgd
1015 1.1 cgd for ( supptr = &semu_list;
1016 1.1 cgd (suptr = *supptr) != NULL;
1017 1.1 cgd supptr = &(suptr->un_next)
1018 1.1 cgd ) {
1019 1.1 cgd
1020 1.1 cgd if ( suptr->un_proc == p ) {
1021 1.1 cgd
1022 1.1 cgd #ifdef SEM_DEBUG
1023 1.1 cgd printf("proc @%08x has undo structure with %d entries\n",p,suptr->un_cnt);
1024 1.1 cgd #endif
1025 1.1 cgd
1026 1.1 cgd /*
1027 1.1 cgd * If there are any active undo elements then process them.
1028 1.1 cgd */
1029 1.1 cgd
1030 1.1 cgd if ( suptr->un_cnt > 0 ) {
1031 1.1 cgd
1032 1.1 cgd int ix;
1033 1.1 cgd
1034 1.1 cgd for ( ix = 0; ix < suptr->un_cnt; ix += 1 ) {
1035 1.1 cgd
1036 1.1 cgd int semid = suptr->un_ent[ix].un_id;
1037 1.1 cgd int semnum = suptr->un_ent[ix].un_num;
1038 1.1 cgd int adjval = suptr->un_ent[ix].un_adjval;
1039 1.1 cgd struct semid_ds *semaptr;
1040 1.1 cgd
1041 1.1 cgd semaptr = &sema[semid];
1042 1.1 cgd if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) {
1043 1.1 cgd panic("semexit - semid not allocated");
1044 1.1 cgd }
1045 1.1 cgd if ( semnum >= semaptr->sem_nsems ) {
1046 1.1 cgd panic("semexit - semnum out of range");
1047 1.1 cgd }
1048 1.1 cgd
1049 1.1 cgd #ifdef SEM_DEBUG
1050 1.1 cgd printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",suptr->un_proc,
1051 1.1 cgd suptr->un_ent[ix].un_id,suptr->un_ent[ix].un_num,suptr->un_ent[ix].un_adjval,
1052 1.1 cgd semaptr->sem_base[semnum].semval);
1053 1.1 cgd #endif
1054 1.1 cgd
1055 1.1 cgd if ( adjval < 0 ) {
1056 1.1 cgd if ( semaptr->sem_base[semnum].semval < -adjval ) {
1057 1.1 cgd semaptr->sem_base[semnum].semval = 0;
1058 1.1 cgd } else {
1059 1.1 cgd semaptr->sem_base[semnum].semval += adjval;
1060 1.1 cgd }
1061 1.1 cgd } else {
1062 1.1 cgd semaptr->sem_base[semnum].semval += adjval;
1063 1.1 cgd }
1064 1.1 cgd
1065 1.1 cgd /* printf("semval now %d\n",semaptr->sem_base[semnum].semval); */
1066 1.1 cgd
1067 1.1 cgd #ifdef SEM_WAKEUP
1068 1.1 cgd sem_wakeup((caddr_t)semaptr); /* A little sloppy (we should KNOW if anybody is waiting). */
1069 1.1 cgd #else
1070 1.1 cgd wakeup((caddr_t)semaptr); /* A little sloppy (we should KNOW if anybody is waiting). */
1071 1.1 cgd #endif
1072 1.1 cgd #ifdef SEM_DEBUG
1073 1.1 cgd printf("semexit: back from wakeup\n");
1074 1.1 cgd #endif
1075 1.1 cgd
1076 1.1 cgd }
1077 1.1 cgd
1078 1.1 cgd }
1079 1.1 cgd
1080 1.1 cgd /*
1081 1.1 cgd * Deallocate the undo vector.
1082 1.1 cgd */
1083 1.1 cgd
1084 1.1 cgd #ifdef SEM_DEBUG
1085 1.1 cgd printf("removing vector\n");
1086 1.1 cgd #endif
1087 1.1 cgd suptr->un_proc = NULL;
1088 1.1 cgd *supptr = suptr->un_next;
1089 1.1 cgd
1090 1.1 cgd /* Done. */
1091 1.1 cgd
1092 1.1 cgd break;
1093 1.1 cgd
1094 1.1 cgd
1095 1.1 cgd }
1096 1.1 cgd
1097 1.1 cgd }
1098 1.1 cgd
1099 1.1 cgd /*
1100 1.1 cgd * If the exiting process is holding the global semaphore facility
1101 1.1 cgd * lock then release it.
1102 1.1 cgd */
1103 1.1 cgd
1104 1.1 cgd if ( semlock_holder == p ) {
1105 1.1 cgd semlock_holder = NULL;
1106 1.1 cgd wakeup( (caddr_t)&semlock_holder );
1107 1.1 cgd }
1108 1.1 cgd }
1109 1.1 cgd #endif
1110