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