|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1989, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * (c) UNIX System Laboratories, Inc. ! 30: * All or some portions of this file are derived from material licensed ! 31: * to the University of California by American Telephone and Telegraph ! 32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 33: * the permission of UNIX System Laboratories, Inc. ! 34: * ! 35: * Redistribution and use in source and binary forms, with or without ! 36: * modification, are permitted provided that the following conditions ! 37: * are met: ! 38: * 1. Redistributions of source code must retain the above copyright ! 39: * notice, this list of conditions and the following disclaimer. ! 40: * 2. Redistributions in binary form must reproduce the above copyright ! 41: * notice, this list of conditions and the following disclaimer in the ! 42: * documentation and/or other materials provided with the distribution. ! 43: * 3. All advertising materials mentioning features or use of this software ! 44: * must display the following acknowledgement: ! 45: * This product includes software developed by the University of ! 46: * California, Berkeley and its contributors. ! 47: * 4. Neither the name of the University nor the names of its contributors ! 48: * may be used to endorse or promote products derived from this software ! 49: * without specific prior written permission. ! 50: * ! 51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 61: * SUCH DAMAGE. ! 62: * ! 63: * @(#)sys_generic.c 8.9 (Berkeley) 2/14/95 ! 64: */ ! 65: ! 66: #include <sys/param.h> ! 67: #include <sys/systm.h> ! 68: #include <sys/filedesc.h> ! 69: #include <sys/ioctl.h> ! 70: #include <sys/file.h> ! 71: #include <sys/proc.h> ! 72: #include <sys/socketvar.h> ! 73: #include <sys/uio.h> ! 74: #include <sys/kernel.h> ! 75: #include <sys/stat.h> ! 76: #include <sys/malloc.h> ! 77: #if KTRACE ! 78: #include <sys/ktrace.h> ! 79: #endif ! 80: ! 81: #include <sys/mount.h> ! 82: #include <sys/protosw.h> ! 83: #include <sys/ev.h> ! 84: #include <sys/user.h> ! 85: #include <kern/kdebug.h> ! 86: ! 87: /* ! 88: * Read system call. ! 89: */ ! 90: struct read_args { ! 91: int fd; ! 92: char *cbuf; ! 93: u_int nbyte; ! 94: }; ! 95: /* ARGSUSED */ ! 96: read(p, uap, retval) ! 97: struct proc *p; ! 98: register struct read_args *uap; ! 99: register_t *retval; ! 100: { ! 101: struct uio auio; ! 102: struct iovec aiov; ! 103: ! 104: aiov.iov_base = (caddr_t)uap->cbuf; ! 105: aiov.iov_len = uap->nbyte; ! 106: auio.uio_iov = &aiov; ! 107: auio.uio_iovcnt = 1; ! 108: auio.uio_rw = UIO_READ; ! 109: return (rwuio(p, uap->fd, &auio, UIO_READ, retval)); ! 110: } ! 111: ! 112: struct readv_args { ! 113: int fd; ! 114: struct iovec *iovp; ! 115: u_int iovcnt; ! 116: }; ! 117: readv(p, uap, retval) ! 118: struct proc *p; ! 119: register struct readv_args *uap; ! 120: int *retval; ! 121: { ! 122: struct uio auio; ! 123: register struct iovec *iov; ! 124: int error; ! 125: struct iovec aiov[UIO_SMALLIOV]; ! 126: ! 127: if (uap->iovcnt > UIO_SMALLIOV) { ! 128: if (uap->iovcnt > UIO_MAXIOV) ! 129: return (EINVAL); ! 130: if ((iov = (struct iovec *) ! 131: kalloc(sizeof(struct iovec) * (uap->iovcnt))) == 0) ! 132: return (ENOMEM); ! 133: } else ! 134: iov = aiov; ! 135: auio.uio_iov = iov; ! 136: auio.uio_iovcnt = uap->iovcnt; ! 137: auio.uio_rw = UIO_READ; ! 138: error = copyin((caddr_t)uap->iovp, (caddr_t)iov, ! 139: uap->iovcnt * sizeof (struct iovec)); ! 140: if (!error) ! 141: error = rwuio(p, uap->fd, &auio, UIO_READ, retval); ! 142: if (uap->iovcnt > UIO_SMALLIOV) ! 143: kfree(iov, sizeof(struct iovec)*uap->iovcnt); ! 144: return (error); ! 145: } ! 146: ! 147: /* ! 148: * Write system call ! 149: */ ! 150: struct write_args { ! 151: int fd; ! 152: char *cbuf; ! 153: u_int nbyte; ! 154: }; ! 155: write(p, uap, retval) ! 156: struct proc *p; ! 157: register struct write_args *uap; ! 158: int *retval; ! 159: { ! 160: struct uio auio; ! 161: struct iovec aiov; ! 162: ! 163: aiov.iov_base = uap->cbuf; ! 164: aiov.iov_len = uap->nbyte; ! 165: auio.uio_iov = &aiov; ! 166: auio.uio_iovcnt = 1; ! 167: auio.uio_rw = UIO_WRITE; ! 168: return (rwuio(p, uap->fd, &auio, UIO_WRITE, retval)); ! 169: } ! 170: ! 171: struct writev_args { ! 172: int fd; ! 173: struct iovec *iovp; ! 174: u_int iovcnt; ! 175: }; ! 176: writev(p, uap, retval) ! 177: struct proc *p; ! 178: register struct writev_args *uap; ! 179: int *retval; ! 180: { ! 181: struct uio auio; ! 182: register struct iovec *iov; ! 183: int error; ! 184: struct iovec aiov[UIO_SMALLIOV]; ! 185: ! 186: if (uap->iovcnt > UIO_SMALLIOV) { ! 187: if (uap->iovcnt > UIO_MAXIOV) ! 188: return (EINVAL); ! 189: if ((iov = (struct iovec *) ! 190: kalloc(sizeof(struct iovec) * (uap->iovcnt))) == 0) ! 191: return (ENOMEM); ! 192: } else ! 193: iov = aiov; ! 194: auio.uio_iov = iov; ! 195: auio.uio_iovcnt = uap->iovcnt; ! 196: auio.uio_rw = UIO_WRITE; ! 197: error = copyin((caddr_t)uap->iovp, (caddr_t)iov, ! 198: uap->iovcnt * sizeof (struct iovec)); ! 199: if (!error) ! 200: error = rwuio(p, uap->fd, &auio, UIO_WRITE, retval); ! 201: if (uap->iovcnt > UIO_SMALLIOV) ! 202: kfree(iov, sizeof(struct iovec)*uap->iovcnt); ! 203: return (error); ! 204: } ! 205: ! 206: rwuio(p, fdes, uio, rw, retval) ! 207: struct proc *p; ! 208: int fdes; ! 209: register struct uio *uio; ! 210: enum uio_rw rw; ! 211: int *retval; ! 212: { ! 213: register struct file *fp; ! 214: register struct iovec *iov; ! 215: int i, count, flag, error; ! 216: ! 217: if (error = fdgetf(p, fdes, &fp)) ! 218: return (error); ! 219: ! 220: if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { ! 221: return(EBADF); ! 222: } ! 223: uio->uio_resid = 0; ! 224: uio->uio_segflg = UIO_USERSPACE; ! 225: uio->uio_procp = p; ! 226: iov = uio->uio_iov; ! 227: for (i = 0; i < uio->uio_iovcnt; i++) { ! 228: if (iov->iov_len < 0) { ! 229: return(EINVAL); ! 230: } ! 231: uio->uio_resid += iov->iov_len; ! 232: if (uio->uio_resid < 0) { ! 233: return(EINVAL); ! 234: } ! 235: iov++; ! 236: } ! 237: count = uio->uio_resid; ! 238: if (rw == UIO_READ) { ! 239: if (error = (*fp->f_ops->fo_read)(fp, uio, fp->f_cred)) ! 240: if (uio->uio_resid != count && (error == ERESTART || ! 241: error == EINTR || error == EWOULDBLOCK)) ! 242: error = 0; ! 243: } else { ! 244: if (error = (*fp->f_ops->fo_write)(fp, uio, fp->f_cred)) { ! 245: if (uio->uio_resid != count && (error == ERESTART || ! 246: error == EINTR || error == EWOULDBLOCK)) ! 247: error = 0; ! 248: if (error == EPIPE) ! 249: psignal(p, SIGPIPE); ! 250: } ! 251: } ! 252: *retval = count - uio->uio_resid; ! 253: return(error); ! 254: } ! 255: ! 256: /* ! 257: * Ioctl system call ! 258: */ ! 259: struct ioctl_args { ! 260: int fd; ! 261: u_long com; ! 262: caddr_t data; ! 263: }; ! 264: /* ARGSUSED */ ! 265: ioctl(p, uap, retval) ! 266: struct proc *p; ! 267: register struct ioctl_args *uap; ! 268: register_t *retval; ! 269: { ! 270: register struct file *fp; ! 271: register u_long com; ! 272: register int error; ! 273: register u_int size; ! 274: caddr_t data, memp; ! 275: int tmp; ! 276: #define STK_PARAMS 128 ! 277: char stkbuf[STK_PARAMS]; ! 278: ! 279: if (error = fdgetf(p, uap->fd, &fp)) ! 280: return (error); ! 281: ! 282: if ((fp->f_flag & (FREAD | FWRITE)) == 0) ! 283: return (EBADF); ! 284: ! 285: /*### LD 6/11/97 Hack Alert: this is to get AppleTalk to work ! 286: * while implementing an ATioctl system call ! 287: */ ! 288: #if NETAT ! 289: { ! 290: extern int appletalk_inited; ! 291: ! 292: if (appletalk_inited && ((uap->com & 0x0000FFFF) == 0xff99)) { ! 293: #ifdef APPLETALK_DEBUG ! 294: kprintf("ioctl: special AppleTalk \n"); ! 295: #endif ! 296: error = (*fp->f_ops->fo_ioctl)(fp, uap->com, uap->data, p); ! 297: return(error); ! 298: } ! 299: } ! 300: ! 301: #endif /* NETAT */ ! 302: ! 303: ! 304: switch (com = uap->com) { ! 305: case FIONCLEX: ! 306: *fdflags(p, uap->fd) &= ~UF_EXCLOSE; ! 307: return (0); ! 308: case FIOCLEX: ! 309: *fdflags(p, uap->fd) |= UF_EXCLOSE; ! 310: return (0); ! 311: } ! 312: ! 313: /* ! 314: * Interpret high order word to find amount of data to be ! 315: * copied to/from the user's address space. ! 316: */ ! 317: size = IOCPARM_LEN(com); ! 318: if (size > IOCPARM_MAX) ! 319: return (ENOTTY); ! 320: memp = NULL; ! 321: if (size > sizeof (stkbuf)) { ! 322: if ((memp = (caddr_t)kalloc(size)) == 0) ! 323: return(ENOMEM); ! 324: data = memp; ! 325: } else ! 326: data = stkbuf; ! 327: if (com&IOC_IN) { ! 328: if (size) { ! 329: error = copyin(uap->data, data, (u_int)size); ! 330: if (error) { ! 331: if (memp) ! 332: kfree(memp, size); ! 333: return (error); ! 334: } ! 335: } else ! 336: *(caddr_t *)data = uap->data; ! 337: } else if ((com&IOC_OUT) && size) ! 338: /* ! 339: * Zero the buffer so the user always ! 340: * gets back something deterministic. ! 341: */ ! 342: bzero(data, size); ! 343: else if (com&IOC_VOID) ! 344: *(caddr_t *)data = uap->data; ! 345: ! 346: switch (com) { ! 347: ! 348: case FIONBIO: ! 349: if (tmp = *(int *)data) ! 350: fp->f_flag |= FNONBLOCK; ! 351: else ! 352: fp->f_flag &= ~FNONBLOCK; ! 353: error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); ! 354: break; ! 355: ! 356: case FIOASYNC: ! 357: if (tmp = *(int *)data) ! 358: fp->f_flag |= FASYNC; ! 359: else ! 360: fp->f_flag &= ~FASYNC; ! 361: error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); ! 362: break; ! 363: ! 364: case FIOSETOWN: ! 365: tmp = *(int *)data; ! 366: if (fp->f_type == DTYPE_SOCKET) { ! 367: ((struct socket *)fp->f_data)->so_pgid = tmp; ! 368: error = 0; ! 369: break; ! 370: } ! 371: if (tmp <= 0) { ! 372: tmp = -tmp; ! 373: } else { ! 374: struct proc *p1 = pfind(tmp); ! 375: if (p1 == 0) { ! 376: error = ESRCH; ! 377: break; ! 378: } ! 379: tmp = p1->p_pgrp->pg_id; ! 380: } ! 381: error = (*fp->f_ops->fo_ioctl) ! 382: (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); ! 383: break; ! 384: ! 385: case FIOGETOWN: ! 386: if (fp->f_type == DTYPE_SOCKET) { ! 387: error = 0; ! 388: *(int *)data = ((struct socket *)fp->f_data)->so_pgid; ! 389: break; ! 390: } ! 391: error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p); ! 392: *(int *)data = -*(int *)data; ! 393: break; ! 394: ! 395: default: ! 396: error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); ! 397: /* ! 398: * Copy any data to user, size was ! 399: * already set and checked above. ! 400: */ ! 401: if (error == 0 && (com&IOC_OUT) && size) ! 402: error = copyout(data, uap->data, (u_int)size); ! 403: break; ! 404: } ! 405: if (memp) ! 406: kfree(memp, size); ! 407: return (error); ! 408: } ! 409: ! 410: ! 411: int selwait, nselcoll; ! 412: ! 413: /* ! 414: * Select system call. ! 415: */ ! 416: struct select_args { ! 417: u_int nd; ! 418: fd_set *in; ! 419: fd_set *ou; ! 420: fd_set *ex; ! 421: struct timeval *tv; ! 422: }; ! 423: ! 424: select(p, uap, retval) ! 425: register struct proc *p; ! 426: register struct select_args *uap; ! 427: register_t *retval; ! 428: { ! 429: fd_set ibits[3], obits[3]; ! 430: struct timeval atv; ! 431: int s, ncoll, error = 0, timo; ! 432: u_int ni; ! 433: struct thread *th; ! 434: struct uthread *uth; ! 435: ! 436: th = current_thread(); ! 437: uth = th->_uthread; ! 438: ! 439: bzero((caddr_t)ibits, sizeof(ibits)); ! 440: bzero((caddr_t)obits, sizeof(obits)); ! 441: ! 442: if (uap->nd > FD_SETSIZE) ! 443: return (EINVAL); ! 444: if (uap->nd > p->p_fd->fd_nfiles) { ! 445: /* forgiving; slightly wrong */ ! 446: uap->nd = p->p_fd->fd_nfiles; ! 447: } ! 448: ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask); ! 449: ! 450: #define getbits(name, x) \ ! 451: if (uap->name && (error = copyin((caddr_t)uap->name, \ ! 452: (caddr_t)&ibits[x], ni))) \ ! 453: goto done; ! 454: getbits(in, 0); ! 455: getbits(ou, 1); ! 456: getbits(ex, 2); ! 457: #undef getbits ! 458: if (uap->tv) { ! 459: error = copyin((caddr_t)uap->tv, (caddr_t)&atv, ! 460: sizeof (atv)); ! 461: if (error) ! 462: goto done; ! 463: if (itimerfix(&atv)) { ! 464: error = EINVAL; ! 465: goto done; ! 466: } ! 467: s = splhigh(); ! 468: timeradd(&atv, &time, &atv); ! 469: timo = hzto(&atv); ! 470: splx(s); ! 471: } else ! 472: timo = 0; ! 473: retry: ! 474: ncoll = nselcoll; ! 475: p->p_flag |= P_SELECT; ! 476: error = selscan(p, ibits, obits, uap->nd, retval); ! 477: if (error || *retval) ! 478: goto done; ! 479: s = splhigh(); ! 480: /* this should be timercmp(&time, &atv, >=) */ ! 481: if (uap->tv && (time.tv_sec > atv.tv_sec || ! 482: time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { ! 483: splx(s); ! 484: goto done; ! 485: } ! 486: /* ! 487: * To effect a poll, the timeout argument should be ! 488: * non-nil, pointing to a zero-valued timeval structure. ! 489: */ ! 490: if (uap->tv && (timo == 0)) { ! 491: splx(s); ! 492: goto done; ! 493: } ! 494: if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { ! 495: splx(s); ! 496: goto retry; ! 497: } ! 498: p->p_flag &= ~P_SELECT; ! 499: error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); ! 500: splx(s); ! 501: if (error == 0) ! 502: goto retry; ! 503: done: ! 504: p->p_flag &= ~P_SELECT; ! 505: /* select is not restarted after signals... */ ! 506: if (error == ERESTART) ! 507: error = EINTR; ! 508: if (error == EWOULDBLOCK) ! 509: error = 0; ! 510: #define putbits(name, x) \ ! 511: if (uap->name && (error2 = copyout((caddr_t)&obits[x], \ ! 512: (caddr_t)uap->name, ni))) \ ! 513: error = error2; ! 514: if (error == 0) { ! 515: int error2; ! 516: ! 517: putbits(in, 0); ! 518: putbits(ou, 1); ! 519: putbits(ex, 2); ! 520: #undef putbits ! 521: } ! 522: return (error); ! 523: } ! 524: ! 525: selscan(p, ibits, obits, nfd, retval) ! 526: struct proc *p; ! 527: fd_set *ibits, *obits; ! 528: int nfd; ! 529: register_t *retval; ! 530: { ! 531: register struct filedesc *fdp = p->p_fd; ! 532: register int msk, i, j, fd; ! 533: register fd_mask bits; ! 534: struct file *fp; ! 535: int n = 0; ! 536: static int flag[3] = { FREAD, FWRITE, 0 }; ! 537: ! 538: for (msk = 0; msk < 3; msk++) { ! 539: for (i = 0; i < nfd; i += NFDBITS) { ! 540: bits = ibits[msk].fds_bits[i/NFDBITS]; ! 541: while ((j = ffs(bits)) && (fd = i + --j) < nfd) { ! 542: bits &= ~(1 << j); ! 543: fp = fdp->fd_ofiles[fd]; ! 544: if (fp == NULL || (fdp->fd_ofileflags[fd] & ! 545: UF_RESERVED)) ! 546: return (EBADF); ! 547: if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { ! 548: FD_SET(fd, &obits[msk]); ! 549: n++; ! 550: } ! 551: } ! 552: } ! 553: } ! 554: *retval = n; ! 555: return (0); ! 556: } ! 557: ! 558: /*ARGSUSED*/ ! 559: seltrue(dev, flag, p) ! 560: dev_t dev; ! 561: int flag; ! 562: struct proc *p; ! 563: { ! 564: ! 565: return (1); ! 566: } ! 567: ! 568: /* ! 569: * Record a select request. ! 570: */ ! 571: void ! 572: selrecord(selector, sip) ! 573: struct proc *selector; ! 574: struct selinfo *sip; ! 575: { ! 576: int oldpri = splhigh(); ! 577: thread_t my_thread = current_thread(); ! 578: thread_t selthread; ! 579: ! 580: selthread = sip->si_thread; ! 581: ! 582: if (selthread == my_thread) { ! 583: splx(oldpri); ! 584: return; ! 585: } ! 586: ! 587: if (selthread && selthread->active && ! 588: selthread->wait_event == (caddr_t)&selwait) { ! 589: sip->si_flags |= SI_COLL; ! 590: splx(oldpri); ! 591: } ! 592: else { ! 593: sip->si_thread = my_thread; ! 594: splx(oldpri); ! 595: thread_deallocate(selthread); ! 596: thread_reference(sip->si_thread); ! 597: } ! 598: ! 599: return; ! 600: } ! 601: ! 602: void ! 603: selwakeup(sip) ! 604: register struct selinfo *sip; ! 605: { ! 606: register thread_t the_thread = (thread_t)sip->si_thread; ! 607: int oldpri; ! 608: ! 609: if (the_thread == 0) ! 610: return; ! 611: ! 612: if (sip->si_flags & SI_COLL) { ! 613: nselcoll++; ! 614: sip->si_flags &= ~SI_COLL; ! 615: wakeup((caddr_t)&selwait); ! 616: } ! 617: ! 618: oldpri = splhigh(); ! 619: ! 620: if (the_thread->active) { ! 621: /* protect p_flag minimally at splsched() */ ! 622: if (the_thread->wait_event == &selwait) ! 623: clear_wait(the_thread, THREAD_AWAKENED, TRUE); ! 624: if (the_thread->task->proc) ! 625: the_thread->task->proc->p_flag &= ~P_SELECT; ! 626: } ! 627: ! 628: thread_deallocate_interrupt(the_thread); ! 629: ! 630: sip->si_thread = 0; ! 631: ! 632: splx(oldpri); ! 633: ! 634: } ! 635: ! 636: void selthreadclear(sip) ! 637: register struct selinfo *sip; ! 638: { ! 639: ! 640: if (sip->si_thread) ! 641: thread_deallocate_interrupt(sip->si_thread); ! 642: ! 643: } ! 644: ! 645: ! 646: /* ! 647: * called upon socket close. deque and free all events for ! 648: * the socket ! 649: */ ! 650: evsofree(struct socket *sp) ! 651: { ! 652: struct eventqelt *eqp, *next; ! 653: ! 654: if (sp == NULL) return; ! 655: ! 656: for (eqp = sp->so_evlist.tqh_first; eqp != NULL; eqp = next) { ! 657: next = eqp->ee_slist.tqe_next; ! 658: evprocdeque(eqp->ee_proc, eqp); // remove from proc q if there ! 659: TAILQ_REMOVE(&sp->so_evlist, eqp, ee_slist); // remove from socket q ! 660: FREE(eqp, M_TEMP); ! 661: } ! 662: } ! 663: ! 664: ! 665: #define DBG_EVENT 0x10 ! 666: ! 667: #define DBG_POST 0x10 ! 668: #define DBG_WATCH 0x11 ! 669: #define DBG_WAIT 0x12 ! 670: #define DBG_MOD 0x13 ! 671: #define DBG_EWAKEUP 0x14 ! 672: ! 673: #define DBG_MISC_POST MISCDBG_CODE(DBG_EVENT,DBG_POST) ! 674: #define DBG_MISC_WATCH MISCDBG_CODE(DBG_EVENT,DBG_WATCH) ! 675: #define DBG_MISC_WAIT MISCDBG_CODE(DBG_EVENT,DBG_WAIT) ! 676: #define DBG_MISC_MOD MISCDBG_CODE(DBG_EVENT,DBG_MOD) ! 677: #define DBG_MISC_EWAKEUP MISCDBG_CODE(DBG_EVENT,DBG_EWAKEUP) ! 678: ! 679: ! 680: ! 681: /* ! 682: * enque this event if it's not already queued. wakeup ! 683: the proc if we do queue this event to it. ! 684: */ ! 685: evprocenque(struct eventqelt *eqp) ! 686: { ! 687: struct proc *p; ! 688: ! 689: assert(eqp); ! 690: if (eqp->ee_flags & EV_QUEUED) { ! 691: return; ! 692: } ! 693: eqp->ee_flags |= EV_QUEUED; ! 694: eqp->ee_eventmask = 0; // disarm ! 695: p = eqp->ee_proc; ! 696: TAILQ_INSERT_TAIL(&p->p_evlist, eqp, ee_plist); ! 697: KERNEL_DEBUG(DBG_MISC_EWAKEUP,0,0,0,eqp,0); ! 698: wakeup(&p->p_evlist); ! 699: } ! 700: ! 701: /* ! 702: * given either a sockbuf or a socket run down the ! 703: * event list and queue ready events found ! 704: */ ! 705: postevent(struct socket *sp, struct sockbuf *sb, int event) ! 706: { ! 707: int mask; ! 708: struct eventqelt *evq; ! 709: ! 710: if (sb) sp = sb->sb_so; ! 711: if (!sp || sp->so_evlist.tqh_first == NULL) return; ! 712: ! 713: KERNEL_DEBUG(DBG_MISC_POST|DBG_FUNC_START, 0,0,0,0,0); ! 714: ! 715: for (evq = sp->so_evlist.tqh_first; ! 716: evq != NULL; evq = evq->ee_slist.tqe_next) { ! 717: ! 718: mask = 0; ! 719: ! 720: /* ready for reading: ! 721: - byte cnt >= receive low water mark ! 722: - read-half of conn closed ! 723: - conn pending for listening sock ! 724: - socket error pending ! 725: ! 726: ready for writing ! 727: - byte cnt avail >= send low water mark ! 728: - write half of conn closed ! 729: - socket error pending ! 730: - non-blocking conn completed successfully ! 731: ! 732: exception pending ! 733: - out of band data ! 734: - sock at out of band mark ! 735: ! 736: */ ! 737: switch (event & EV_DMASK) { ! 738: ! 739: case EV_RWBYTES: ! 740: case EV_OOB: ! 741: if (event & EV_OOB) { ! 742: if ((evq->ee_eventmask & EV_EX)) { ! 743: if (sp->so_oobmark || ((sp->so_state & SS_RCVATMARK))) { ! 744: mask |= EV_EX|EV_OOB; ! 745: } ! 746: } ! 747: } ! 748: if (event & EV_RWBYTES) { ! 749: if ((evq->ee_eventmask & EV_RE) && soreadable(sp)) { ! 750: mask |= EV_RE; ! 751: evq->ee_req.er_rcnt = sp->so_rcv.sb_cc; ! 752: } ! 753: ! 754: if ((evq->ee_eventmask & EV_WR) && sowriteable(sp)) { ! 755: mask |= EV_WR; ! 756: evq->ee_req.er_wcnt = sbspace(&sp->so_snd); ! 757: } ! 758: } ! 759: break; ! 760: ! 761: case EV_RCONN: ! 762: if ((evq->ee_eventmask & EV_RE)) { ! 763: evq->ee_req.er_rcnt = sp->so_qlen + 1; // incl this one ! 764: mask |= EV_RE|EV_RCONN; ! 765: } ! 766: break; ! 767: ! 768: case EV_WCONN: ! 769: if ((evq->ee_eventmask & EV_WR)) { ! 770: mask |= EV_WR|EV_WCONN; ! 771: } ! 772: break; ! 773: ! 774: case EV_RCLOSED: ! 775: if ((evq->ee_eventmask & EV_RE)) { ! 776: mask |= EV_RE|EV_RCLOSED; ! 777: break; ! 778: } ! 779: ! 780: case EV_WCLOSED: ! 781: if ((evq->ee_eventmask & EV_WR)) { ! 782: mask |= EV_WR|EV_WCLOSED; ! 783: break; ! 784: } ! 785: ! 786: case EV_FIN: ! 787: if (evq->ee_eventmask & EV_EX) { ! 788: mask |= EV_EX|EV_FIN; ! 789: break; ! 790: } ! 791: ! 792: case EV_RESET: ! 793: if (evq->ee_eventmask & EV_EX) { ! 794: mask |= EV_EX|EV_RESET; ! 795: break; ! 796: } ! 797: ! 798: default: ! 799: return; ! 800: } /* switch */ ! 801: ! 802: if (mask) { ! 803: evq->ee_req.er_eventbits |= mask; ! 804: evprocenque(evq); ! 805: } ! 806: } ! 807: KERNEL_DEBUG(DBG_MISC_POST|DBG_FUNC_END, 0,0,0,0,0); ! 808: } ! 809: ! 810: /* ! 811: * remove and return the first event (eqp=NULL) or a specific ! 812: * event, or return NULL if no events found ! 813: */ ! 814: struct eventqelt * ! 815: evprocdeque(struct proc *p, struct eventqelt *eqp) ! 816: { ! 817: ! 818: ! 819: if (eqp && ((eqp->ee_flags & EV_QUEUED) == NULL)) ! 820: return(NULL); ! 821: if (p->p_evlist.tqh_first == NULL) ! 822: return(NULL); ! 823: if (eqp == NULL) { // remove first ! 824: eqp = p->p_evlist.tqh_first; ! 825: } ! 826: TAILQ_REMOVE(&p->p_evlist, eqp, ee_plist); ! 827: eqp->ee_flags &= ~EV_QUEUED; ! 828: return(eqp); ! 829: } ! 830: ! 831: struct evwatch_args { ! 832: struct eventreq *u_req; ! 833: int u_eventmask; ! 834: }; ! 835: ! 836: ! 837: /* ! 838: * watchevent system call. user passes us an event to watch ! 839: * for. we malloc an event object, initialize it, and queue ! 840: * it to the open socket. when the event occurs, postevent() ! 841: * will enque it back to our proc where we can retrieve it ! 842: * via waitevent(). ! 843: * ! 844: * should this prevent duplicate events on same socket? ! 845: */ ! 846: int ! 847: watchevent(p, uap, retval) ! 848: struct proc *p; ! 849: struct evwatch_args *uap; ! 850: register_t *retval; ! 851: { ! 852: struct eventqelt *eqp = (struct eventqelt *)0; ! 853: struct eventqelt *np; ! 854: struct eventreq *erp; ! 855: struct file *fp; ! 856: struct socket *sp; ! 857: int error; ! 858: ! 859: // get a qelt and fill with users req ! 860: MALLOC(eqp, struct eventqelt *, sizeof(struct eventqelt), M_TEMP, M_WAITOK); ! 861: if (!eqp) panic("can't MALLOC eqp"); ! 862: erp = &eqp->ee_req; ! 863: // get users request pkt ! 864: if (error = copyin((caddr_t)uap->u_req, (caddr_t)erp, ! 865: sizeof(struct eventreq))) { ! 866: FREE(eqp, M_TEMP); ! 867: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 868: return(error); ! 869: } ! 870: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_START, 0, ! 871: erp->er_handle,uap->u_eventmask,eqp,0); ! 872: // validate, freeing qelt if errors ! 873: error = 0; ! 874: if (erp->er_type != EV_FD) { ! 875: error = EINVAL; ! 876: } else if (erp->er_handle < 0) { ! 877: error = EBADF; ! 878: } else if (erp->er_handle > p->p_fd->fd_nfiles) { ! 879: error = EBADF; ! 880: } else if ((fp = *fdfile(p, erp->er_handle)) == NULL) { ! 881: error = EBADF; ! 882: } else if (fp->f_type != DTYPE_SOCKET) { ! 883: error = EINVAL; ! 884: } ! 885: if (error) { ! 886: FREE(eqp,M_TEMP); ! 887: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 888: return(error); ! 889: } ! 890: ! 891: erp->er_rcnt = erp->er_wcnt = erp->er_eventbits = 0; ! 892: eqp->ee_proc = p; ! 893: eqp->ee_eventmask = uap->u_eventmask & EV_MASK; ! 894: eqp->ee_flags = 0; ! 895: ! 896: sp = (struct socket *)fp->f_data; ! 897: assert(sp != NULL); ! 898: ! 899: // only allow one watch per file per proc ! 900: for (np = sp->so_evlist.tqh_first; np != NULL; np = np->ee_slist.tqe_next) { ! 901: if (np->ee_proc == p) { ! 902: FREE(eqp,M_TEMP); ! 903: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 904: return(EINVAL); ! 905: } ! 906: } ! 907: ! 908: TAILQ_INSERT_TAIL(&sp->so_evlist, eqp, ee_slist); ! 909: postevent(sp, 0, EV_RWBYTES); // catch existing events ! 910: KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0); ! 911: return(0); ! 912: } ! 913: ! 914: struct evwait_args { ! 915: struct eventreq *u_req; ! 916: struct timeval *tv; ! 917: }; ! 918: ! 919: /* ! 920: * waitevent system call. ! 921: * grabs the next waiting event for this proc and returns ! 922: * it. if no events, user can request to sleep with timeout ! 923: * or poll mode (tv=NULL); ! 924: */ ! 925: int ! 926: waitevent(p, uap, retval) ! 927: struct proc *p; ! 928: struct evwait_args *uap; ! 929: register_t *retval; ! 930: { ! 931: int error = 0; ! 932: struct eventqelt *eqp; ! 933: int timo; ! 934: struct timeval atv; ! 935: int s; ! 936: ! 937: if (uap->tv) { ! 938: error = copyin((caddr_t)uap->tv, (caddr_t)&atv, ! 939: sizeof (atv)); ! 940: if (error) ! 941: return(error); ! 942: if (itimerfix(&atv)) { ! 943: error = EINVAL; ! 944: return(error); ! 945: } ! 946: s = splhigh(); ! 947: timeradd(&atv, &time, &atv); ! 948: timo = hzto(&atv); ! 949: splx(s); ! 950: } else ! 951: timo = 0; ! 952: ! 953: KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_START, 0,0,0,0,0); ! 954: ! 955: retry: ! 956: s = splhigh(); ! 957: if ((eqp = evprocdeque(p,NULL)) != NULL) { ! 958: splx(s); ! 959: error = copyout((caddr_t)&eqp->ee_req, (caddr_t)uap->u_req, ! 960: sizeof(struct eventreq)); ! 961: KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0, ! 962: eqp->ee_req.er_handle,eqp->ee_req.er_eventbits,eqp,0); ! 963: return(error); ! 964: } else { ! 965: if (uap->tv && (timo == 0)) { ! 966: splx(s); ! 967: *retval = 1; // poll failed ! 968: return(error); ! 969: } ! 970: ! 971: KERNEL_DEBUG(DBG_MISC_WAIT, 1,0,0,0,0); ! 972: error = tsleep(&p->p_evlist, PSOCK | PCATCH, "waitevent", timo); ! 973: KERNEL_DEBUG(DBG_MISC_WAIT, 0,0,2,p->p_evlist.tqh_first,0); ! 974: splx(s); ! 975: if (error == 0) ! 976: goto retry; ! 977: if (error == ERESTART) ! 978: error = EINTR; ! 979: if (error == EWOULDBLOCK) { ! 980: *retval = 1; ! 981: error = 0; ! 982: } ! 983: } ! 984: KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0,0,0,0,0); ! 985: return(error); ! 986: } ! 987: ! 988: struct modwatch_args { ! 989: struct eventreq *u_req; ! 990: int u_eventmask; ! 991: }; ! 992: ! 993: /* ! 994: * modwatch system call. user passes in event to modify. ! 995: * if we find it we reset the event bits and que/deque event ! 996: * it needed. ! 997: */ ! 998: int ! 999: modwatch(p, uap, retval) ! 1000: struct proc *p; ! 1001: struct modwatch_args *uap; ! 1002: register_t *retval; ! 1003: { ! 1004: struct eventreq er; ! 1005: struct eventreq *erp = &er; ! 1006: struct eventqelt *evq; ! 1007: int error; ! 1008: struct file *fp; ! 1009: struct socket *sp; ! 1010: int flag; ! 1011: ! 1012: ! 1013: // get users request pkt ! 1014: if (error = copyin((caddr_t)uap->u_req, (caddr_t)erp, ! 1015: sizeof(struct eventreq))) return(error); ! 1016: ! 1017: if (erp->er_type != EV_FD) return(EINVAL); ! 1018: if (erp->er_handle < 0) return(EBADF); ! 1019: if (erp->er_handle > p->p_fd->fd_nfiles) return(EBADF); ! 1020: if ((fp = *fdfile(p, erp->er_handle)) == NULL) ! 1021: return(EBADF); ! 1022: if (fp->f_type != DTYPE_SOCKET) return(EINVAL); // for now must be sock ! 1023: sp = (struct socket *)fp->f_data; ! 1024: assert(sp != NULL); ! 1025: ! 1026: // locate event if possible ! 1027: for (evq = sp->so_evlist.tqh_first; ! 1028: evq != NULL; evq = evq->ee_slist.tqe_next) { ! 1029: if (evq->ee_proc == p) break; ! 1030: } ! 1031: if (evq == NULL) { ! 1032: return(EINVAL); ! 1033: } ! 1034: ! 1035: ! 1036: if (uap->u_eventmask == EV_RM) { ! 1037: evprocdeque(p, evq); ! 1038: TAILQ_REMOVE(&sp->so_evlist, evq, ee_slist); ! 1039: FREE(evq, M_TEMP); ! 1040: return(0); ! 1041: } ! 1042: ! 1043: switch (uap->u_eventmask & EV_MASK) { ! 1044: ! 1045: case 0: ! 1046: flag = 0; ! 1047: break; ! 1048: ! 1049: case EV_RE: ! 1050: case EV_WR: ! 1051: case EV_RE|EV_WR: ! 1052: flag = EV_RWBYTES; ! 1053: break; ! 1054: ! 1055: case EV_EX: ! 1056: flag = EV_OOB; ! 1057: break; ! 1058: ! 1059: case EV_EX|EV_RE: ! 1060: case EV_EX|EV_WR: ! 1061: case EV_EX|EV_RE|EV_WR: ! 1062: flag = EV_OOB|EV_RWBYTES; ! 1063: break; ! 1064: ! 1065: default: ! 1066: return(EINVAL); ! 1067: } ! 1068: ! 1069: evq->ee_eventmask = uap->u_eventmask & EV_MASK; ! 1070: evprocdeque(p, evq); ! 1071: evq->ee_req.er_eventbits = 0; ! 1072: postevent(sp, 0, flag); ! 1073: return(0); ! 1074: } ! 1075: ! 1076: ! 1077:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.