1 /* $NetBSD: sys_generic.c,v 1.19 1995/03/21 13:33:34 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)sys_generic.c 8.5 (Berkeley) 1/21/94 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/filedesc.h> 46 #include <sys/ioctl.h> 47 #include <sys/file.h> 48 #include <sys/proc.h> 49 #include <sys/socketvar.h> 50 #include <sys/uio.h> 51 #include <sys/kernel.h> 52 #include <sys/stat.h> 53 #include <sys/malloc.h> 54 #ifdef KTRACE 55 #include <sys/ktrace.h> 56 #endif 57 58 #include <sys/mount.h> 59 #include <sys/syscallargs.h> 60 61 /* 62 * Read system call. 63 */ 64 /* ARGSUSED */ 65 read(p, uap, retval) 66 struct proc *p; 67 register struct read_args /* { 68 syscallarg(int) fd; 69 syscallarg(char *) buf; 70 syscallarg(u_int) nbyte; 71 } */ *uap; 72 register_t *retval; 73 { 74 register struct file *fp; 75 register struct filedesc *fdp = p->p_fd; 76 struct uio auio; 77 struct iovec aiov; 78 long cnt, error = 0; 79 #ifdef KTRACE 80 struct iovec ktriov; 81 #endif 82 83 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || 84 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || 85 (fp->f_flag & FREAD) == 0) 86 return (EBADF); 87 aiov.iov_base = (caddr_t)SCARG(uap, buf); 88 aiov.iov_len = SCARG(uap, nbyte); 89 auio.uio_iov = &aiov; 90 auio.uio_iovcnt = 1; 91 auio.uio_resid = SCARG(uap, nbyte); 92 auio.uio_rw = UIO_READ; 93 auio.uio_segflg = UIO_USERSPACE; 94 auio.uio_procp = p; 95 if (auio.uio_resid < 0) 96 return EINVAL; 97 #ifdef KTRACE 98 /* 99 * if tracing, save a copy of iovec 100 */ 101 if (KTRPOINT(p, KTR_GENIO)) 102 ktriov = aiov; 103 #endif 104 cnt = SCARG(uap, nbyte); 105 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) 106 if (auio.uio_resid != cnt && (error == ERESTART || 107 error == EINTR || error == EWOULDBLOCK)) 108 error = 0; 109 cnt -= auio.uio_resid; 110 #ifdef KTRACE 111 if (KTRPOINT(p, KTR_GENIO) && error == 0) 112 ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov, 113 cnt, error); 114 #endif 115 *retval = cnt; 116 return (error); 117 } 118 119 /* 120 * Scatter read system call. 121 */ 122 readv(p, uap, retval) 123 struct proc *p; 124 register struct readv_args /* { 125 syscallarg(int) fd; 126 syscallarg(struct iovec *) iovp; 127 syscallarg(u_int) iovcnt; 128 } */ *uap; 129 register_t *retval; 130 { 131 register struct file *fp; 132 register struct filedesc *fdp = p->p_fd; 133 struct uio auio; 134 register struct iovec *iov; 135 struct iovec *needfree; 136 struct iovec aiov[UIO_SMALLIOV]; 137 long i, cnt, error = 0; 138 u_int iovlen; 139 #ifdef KTRACE 140 struct iovec *ktriov = NULL; 141 #endif 142 143 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || 144 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || 145 (fp->f_flag & FREAD) == 0) 146 return (EBADF); 147 /* note: can't use iovlen until iovcnt is validated */ 148 iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec); 149 if (SCARG(uap, iovcnt) > UIO_SMALLIOV) { 150 if (SCARG(uap, iovcnt) > UIO_MAXIOV) 151 return (EINVAL); 152 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); 153 needfree = iov; 154 } else { 155 iov = aiov; 156 needfree = NULL; 157 } 158 auio.uio_iov = iov; 159 auio.uio_iovcnt = SCARG(uap, iovcnt); 160 auio.uio_rw = UIO_READ; 161 auio.uio_segflg = UIO_USERSPACE; 162 auio.uio_procp = p; 163 if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen)) 164 goto done; 165 auio.uio_resid = 0; 166 for (i = 0; i < SCARG(uap, iovcnt); i++) { 167 if (iov->iov_len < 0) { 168 error = EINVAL; 169 goto done; 170 } 171 auio.uio_resid += iov->iov_len; 172 if (auio.uio_resid < 0) { 173 error = EINVAL; 174 goto done; 175 } 176 iov++; 177 } 178 #ifdef KTRACE 179 /* 180 * if tracing, save a copy of iovec 181 */ 182 if (KTRPOINT(p, KTR_GENIO)) { 183 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 184 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); 185 } 186 #endif 187 cnt = auio.uio_resid; 188 if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred)) 189 if (auio.uio_resid != cnt && (error == ERESTART || 190 error == EINTR || error == EWOULDBLOCK)) 191 error = 0; 192 cnt -= auio.uio_resid; 193 #ifdef KTRACE 194 if (ktriov != NULL) { 195 if (error == 0) 196 ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov, 197 cnt, error); 198 FREE(ktriov, M_TEMP); 199 } 200 #endif 201 *retval = cnt; 202 done: 203 if (needfree) 204 FREE(needfree, M_IOV); 205 return (error); 206 } 207 208 /* 209 * Write system call 210 */ 211 write(p, uap, retval) 212 struct proc *p; 213 register struct write_args /* { 214 syscallarg(int) fd; 215 syscallarg(char *) buf; 216 syscallarg(u_int) nbyte; 217 } */ *uap; 218 register_t *retval; 219 { 220 register struct file *fp; 221 register struct filedesc *fdp = p->p_fd; 222 struct uio auio; 223 struct iovec aiov; 224 long cnt, error = 0; 225 #ifdef KTRACE 226 struct iovec ktriov; 227 #endif 228 229 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || 230 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || 231 (fp->f_flag & FWRITE) == 0) 232 return (EBADF); 233 aiov.iov_base = (caddr_t)SCARG(uap, buf); 234 aiov.iov_len = SCARG(uap, nbyte); 235 auio.uio_iov = &aiov; 236 auio.uio_iovcnt = 1; 237 auio.uio_resid = SCARG(uap, nbyte); 238 auio.uio_rw = UIO_WRITE; 239 auio.uio_segflg = UIO_USERSPACE; 240 auio.uio_procp = p; 241 if (auio.uio_resid < 0) 242 return EINVAL; 243 #ifdef KTRACE 244 /* 245 * if tracing, save a copy of iovec 246 */ 247 if (KTRPOINT(p, KTR_GENIO)) 248 ktriov = aiov; 249 #endif 250 cnt = SCARG(uap, nbyte); 251 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { 252 if (auio.uio_resid != cnt && (error == ERESTART || 253 error == EINTR || error == EWOULDBLOCK)) 254 error = 0; 255 if (error == EPIPE) 256 psignal(p, SIGPIPE); 257 } 258 cnt -= auio.uio_resid; 259 #ifdef KTRACE 260 if (KTRPOINT(p, KTR_GENIO) && error == 0) 261 ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE, 262 &ktriov, cnt, error); 263 #endif 264 *retval = cnt; 265 return (error); 266 } 267 268 /* 269 * Gather write system call 270 */ 271 writev(p, uap, retval) 272 struct proc *p; 273 register struct writev_args /* { 274 syscallarg(int) fd; 275 syscallarg(struct iovec *) iovp; 276 syscallarg(u_int) iovcnt; 277 } */ *uap; 278 register_t *retval; 279 { 280 register struct file *fp; 281 register struct filedesc *fdp = p->p_fd; 282 struct uio auio; 283 register struct iovec *iov; 284 struct iovec *needfree; 285 struct iovec aiov[UIO_SMALLIOV]; 286 long i, cnt, error = 0; 287 u_int iovlen; 288 #ifdef KTRACE 289 struct iovec *ktriov = NULL; 290 #endif 291 292 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || 293 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || 294 (fp->f_flag & FWRITE) == 0) 295 return (EBADF); 296 /* note: can't use iovlen until iovcnt is validated */ 297 iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec); 298 if (SCARG(uap, iovcnt) > UIO_SMALLIOV) { 299 if (SCARG(uap, iovcnt) > UIO_MAXIOV) 300 return (EINVAL); 301 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); 302 needfree = iov; 303 } else { 304 iov = aiov; 305 needfree = NULL; 306 } 307 auio.uio_iov = iov; 308 auio.uio_iovcnt = SCARG(uap, iovcnt); 309 auio.uio_rw = UIO_WRITE; 310 auio.uio_segflg = UIO_USERSPACE; 311 auio.uio_procp = p; 312 if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen)) 313 goto done; 314 auio.uio_resid = 0; 315 for (i = 0; i < SCARG(uap, iovcnt); i++) { 316 if (iov->iov_len < 0) { 317 error = EINVAL; 318 goto done; 319 } 320 auio.uio_resid += iov->iov_len; 321 if (auio.uio_resid < 0) { 322 error = EINVAL; 323 goto done; 324 } 325 iov++; 326 } 327 #ifdef KTRACE 328 /* 329 * if tracing, save a copy of iovec 330 */ 331 if (KTRPOINT(p, KTR_GENIO)) { 332 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 333 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); 334 } 335 #endif 336 cnt = auio.uio_resid; 337 if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) { 338 if (auio.uio_resid != cnt && (error == ERESTART || 339 error == EINTR || error == EWOULDBLOCK)) 340 error = 0; 341 if (error == EPIPE) 342 psignal(p, SIGPIPE); 343 } 344 cnt -= auio.uio_resid; 345 #ifdef KTRACE 346 if (ktriov != NULL) { 347 if (error == 0) 348 ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE, 349 ktriov, cnt, error); 350 FREE(ktriov, M_TEMP); 351 } 352 #endif 353 *retval = cnt; 354 done: 355 if (needfree) 356 FREE(needfree, M_IOV); 357 return (error); 358 } 359 360 /* 361 * Ioctl system call 362 */ 363 /* ARGSUSED */ 364 ioctl(p, uap, retval) 365 struct proc *p; 366 register struct ioctl_args /* { 367 syscallarg(int) fd; 368 syscallarg(u_long) com; 369 syscallarg(caddr_t) data; 370 } */ *uap; 371 register_t *retval; 372 { 373 register struct file *fp; 374 register struct filedesc *fdp; 375 register u_long com; 376 register int error; 377 register u_int size; 378 caddr_t data, memp; 379 int tmp; 380 #define STK_PARAMS 128 381 char stkbuf[STK_PARAMS]; 382 383 fdp = p->p_fd; 384 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 385 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 386 return (EBADF); 387 388 if ((fp->f_flag & (FREAD | FWRITE)) == 0) 389 return (EBADF); 390 391 switch (com = SCARG(uap, com)) { 392 case FIONCLEX: 393 fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE; 394 return (0); 395 case FIOCLEX: 396 fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE; 397 return (0); 398 } 399 400 /* 401 * Interpret high order word to find amount of data to be 402 * copied to/from the user's address space. 403 */ 404 size = IOCPARM_LEN(com); 405 if (size > IOCPARM_MAX) 406 return (ENOTTY); 407 memp = NULL; 408 if (size > sizeof (stkbuf)) { 409 memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK); 410 data = memp; 411 } else 412 data = stkbuf; 413 if (com&IOC_IN) { 414 if (size) { 415 error = copyin(SCARG(uap, data), data, (u_int)size); 416 if (error) { 417 if (memp) 418 free(memp, M_IOCTLOPS); 419 return (error); 420 } 421 } else 422 *(caddr_t *)data = SCARG(uap, data); 423 } else if ((com&IOC_OUT) && size) 424 /* 425 * Zero the buffer so the user always 426 * gets back something deterministic. 427 */ 428 bzero(data, size); 429 else if (com&IOC_VOID) 430 *(caddr_t *)data = SCARG(uap, data); 431 432 switch (com) { 433 434 case FIONBIO: 435 if (tmp = *(int *)data) 436 fp->f_flag |= FNONBLOCK; 437 else 438 fp->f_flag &= ~FNONBLOCK; 439 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 440 break; 441 442 case FIOASYNC: 443 if (tmp = *(int *)data) 444 fp->f_flag |= FASYNC; 445 else 446 fp->f_flag &= ~FASYNC; 447 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 448 break; 449 450 case FIOSETOWN: 451 tmp = *(int *)data; 452 if (fp->f_type == DTYPE_SOCKET) { 453 ((struct socket *)fp->f_data)->so_pgid = tmp; 454 error = 0; 455 break; 456 } 457 if (tmp <= 0) { 458 tmp = -tmp; 459 } else { 460 struct proc *p1 = pfind(tmp); 461 if (p1 == 0) { 462 error = ESRCH; 463 break; 464 } 465 tmp = p1->p_pgrp->pg_id; 466 } 467 error = (*fp->f_ops->fo_ioctl) 468 (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); 469 break; 470 471 case FIOGETOWN: 472 if (fp->f_type == DTYPE_SOCKET) { 473 error = 0; 474 *(int *)data = ((struct socket *)fp->f_data)->so_pgid; 475 break; 476 } 477 error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p); 478 *(int *)data = -*(int *)data; 479 break; 480 481 default: 482 error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); 483 /* 484 * Copy any data to user, size was 485 * already set and checked above. 486 */ 487 if (error == 0 && (com&IOC_OUT) && size) 488 error = copyout(data, SCARG(uap, data), (u_int)size); 489 break; 490 } 491 if (memp) 492 free(memp, M_IOCTLOPS); 493 return (error); 494 } 495 496 int selwait, nselcoll; 497 498 /* 499 * Select system call. 500 */ 501 select(p, uap, retval) 502 register struct proc *p; 503 register struct select_args /* { 504 syscallarg(u_int) nd; 505 syscallarg(fd_set *) in; 506 syscallarg(fd_set *) ou; 507 syscallarg(fd_set *) ex; 508 syscallarg(struct timeval *) tv; 509 } */ *uap; 510 register_t *retval; 511 { 512 fd_set ibits[3], obits[3]; 513 struct timeval atv; 514 int s, ncoll, error = 0, timo; 515 u_int ni; 516 517 bzero((caddr_t)ibits, sizeof(ibits)); 518 bzero((caddr_t)obits, sizeof(obits)); 519 if (SCARG(uap, nd) > FD_SETSIZE) 520 return (EINVAL); 521 if (SCARG(uap, nd) > p->p_fd->fd_nfiles) { 522 /* forgiving; slightly wrong */ 523 SCARG(uap, nd) = p->p_fd->fd_nfiles; 524 } 525 ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask); 526 527 #define getbits(name, x) \ 528 if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \ 529 (caddr_t)&ibits[x], ni))) \ 530 goto done; 531 getbits(in, 0); 532 getbits(ou, 1); 533 getbits(ex, 2); 534 #undef getbits 535 536 if (SCARG(uap, tv)) { 537 error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv, 538 sizeof (atv)); 539 if (error) 540 goto done; 541 if (itimerfix(&atv)) { 542 error = EINVAL; 543 goto done; 544 } 545 s = splclock(); 546 timeradd(&atv, &time, &atv); 547 timo = hzto(&atv); 548 /* 549 * Avoid inadvertently sleeping forever. 550 */ 551 if (timo == 0) 552 timo = 1; 553 splx(s); 554 } else 555 timo = 0; 556 retry: 557 ncoll = nselcoll; 558 p->p_flag |= P_SELECT; 559 error = selscan(p, ibits, obits, SCARG(uap, nd), retval); 560 if (error || *retval) 561 goto done; 562 s = splhigh(); 563 /* this should be timercmp(&time, &atv, >=) */ 564 if (SCARG(uap, tv) && (time.tv_sec > atv.tv_sec || 565 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) { 566 splx(s); 567 goto done; 568 } 569 if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { 570 splx(s); 571 goto retry; 572 } 573 p->p_flag &= ~P_SELECT; 574 error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo); 575 splx(s); 576 if (error == 0) 577 goto retry; 578 done: 579 p->p_flag &= ~P_SELECT; 580 /* select is not restarted after signals... */ 581 if (error == ERESTART) 582 error = EINTR; 583 if (error == EWOULDBLOCK) 584 error = 0; 585 #define putbits(name, x) \ 586 if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \ 587 (caddr_t)SCARG(uap, name), ni))) \ 588 error = error2; 589 if (error == 0) { 590 int error2; 591 592 putbits(in, 0); 593 putbits(ou, 1); 594 putbits(ex, 2); 595 #undef putbits 596 } 597 return (error); 598 } 599 600 selscan(p, ibits, obits, nfd, retval) 601 struct proc *p; 602 fd_set *ibits, *obits; 603 int nfd; 604 register_t *retval; 605 { 606 register struct filedesc *fdp = p->p_fd; 607 register int msk, i, j, fd; 608 register fd_mask bits; 609 struct file *fp; 610 int n = 0; 611 static int flag[3] = { FREAD, FWRITE, 0 }; 612 613 for (msk = 0; msk < 3; msk++) { 614 for (i = 0; i < nfd; i += NFDBITS) { 615 bits = ibits[msk].fds_bits[i/NFDBITS]; 616 while ((j = ffs(bits)) && (fd = i + --j) < nfd) { 617 bits &= ~(1 << j); 618 fp = fdp->fd_ofiles[fd]; 619 if (fp == NULL) 620 return (EBADF); 621 if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) { 622 FD_SET(fd, &obits[msk]); 623 n++; 624 } 625 } 626 } 627 } 628 *retval = n; 629 return (0); 630 } 631 632 /*ARGSUSED*/ 633 seltrue(dev, flag, p) 634 dev_t dev; 635 int flag; 636 struct proc *p; 637 { 638 639 return (1); 640 } 641 642 /* 643 * Record a select request. 644 */ 645 void 646 selrecord(selector, sip) 647 struct proc *selector; 648 struct selinfo *sip; 649 { 650 struct proc *p; 651 pid_t mypid; 652 653 mypid = selector->p_pid; 654 if (sip->si_pid == mypid) 655 return; 656 if (sip->si_pid && (p = pfind(sip->si_pid)) && 657 p->p_wchan == (caddr_t)&selwait) 658 sip->si_flags |= SI_COLL; 659 else 660 sip->si_pid = mypid; 661 } 662 663 /* 664 * Do a wakeup when a selectable event occurs. 665 */ 666 void 667 selwakeup(sip) 668 register struct selinfo *sip; 669 { 670 register struct proc *p; 671 int s; 672 673 if (sip->si_pid == 0) 674 return; 675 if (sip->si_flags & SI_COLL) { 676 nselcoll++; 677 sip->si_flags &= ~SI_COLL; 678 wakeup((caddr_t)&selwait); 679 } 680 p = pfind(sip->si_pid); 681 sip->si_pid = 0; 682 if (p != NULL) { 683 s = splhigh(); 684 if (p->p_wchan == (caddr_t)&selwait) { 685 if (p->p_stat == SSLEEP) 686 setrunnable(p); 687 else 688 unsleep(p); 689 } else if (p->p_flag & P_SELECT) 690 p->p_flag &= ~P_SELECT; 691 splx(s); 692 } 693 } 694