*** /usr/src/sys/kern/syscalls.master.orig Wed Nov 3 10:00:56 1999 --- /usr/src/sys/kern/syscalls.master Wed Nov 3 19:41:27 1999 *************** *** 485,489 **** 344 STD BSD { int sigreturn(ucontext_t *sigcntxp); } 345 UNIMPL NOHIDE sigtimedwait 346 UNIMPL NOHIDE sigwaitinfo ! 347 STD BSD { int aio_waitcomplete(struct aiocb **aiocbp, int cbpcount, struct timespec *timeout); } --- 485,489 ---- 344 STD BSD { int sigreturn(ucontext_t *sigcntxp); } 345 UNIMPL NOHIDE sigtimedwait 346 UNIMPL NOHIDE sigwaitinfo ! 347 STD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); } *** /usr/src/sys/kern/uipc_socket.c.orig Sat Oct 9 20:42:10 1999 --- /usr/src/sys/kern/uipc_socket.c Mon Nov 1 14:36:24 1999 *************** *** 94,99 **** --- 94,100 ---- bzero(so, sizeof *so); so->so_gencnt = ++so_gencnt; so->so_zone = socket_zone; + TAILQ_INIT(&so->so_aiojobq); } return so; } *** /usr/src/sys/kern/uipc_socket2.c.orig Sat Oct 9 20:42:10 1999 --- /usr/src/sys/kern/uipc_socket2.c Mon Nov 1 14:36:24 1999 *************** *** 50,55 **** --- 50,56 ---- #include #include #include + #include /* for aio_swake proto */ int maxsockets; *************** *** 337,342 **** --- 338,346 ---- pgsigio(so->so_sigio, SIGIO, 0); if (sb->sb_flags & SB_UPCALL) (*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT); + if(sb->sb_flags & SB_AIO) { + aio_swake(so,sb); + } } /* *** /usr/src/sys/kern/vfs_aio.c.orig Wed Nov 3 19:39:58 1999 --- /usr/src/sys/kern/vfs_aio.c Wed Nov 3 19:52:04 1999 *************** *** 33,38 **** --- 33,40 ---- #include #include #include + #include + #include #include #include #include *************** *** 73,79 **** #endif #ifndef TARGET_AIO_PROCS ! #define TARGET_AIO_PROCS 0 #endif #ifndef MAX_BUF_AIO --- 75,81 ---- #endif #ifndef TARGET_AIO_PROCS ! #define TARGET_AIO_PROCS 4 #endif #ifndef MAX_BUF_AIO *************** *** 140,169 **** /* - * Job queue item - */ - - #define AIOCBLIST_CANCELLED 0x1 - #define AIOCBLIST_RUNDOWN 0x4 - #define AIOCBLIST_ASYNCFREE 0x8 - #define AIOCBLIST_DONE 0x10 - - struct aiocblist { - TAILQ_ENTRY (aiocblist) list; /* List of jobs */ - TAILQ_ENTRY (aiocblist) plist; /* List of jobs for proc */ - int jobflags; - int jobstate; - int inputcharge, outputcharge; - struct buf *bp; /* buffer pointer */ - struct proc *userproc; /* User process */ - struct aioproclist *jobaioproc; /* AIO process descriptor */ - struct aio_liojob *lio; /* optional lio job */ - struct aiocb *uuaiocb; /* pointer in userspace of aiocb */ - struct aiocb uaiocb; /* Kernel I/O control block */ - }; - - - /* * AIO process info */ #define AIOP_FREE 0x1 /* proc on free queue */ --- 142,147 ---- *************** *** 211,216 **** --- 189,195 ---- TAILQ_HEAD (,aiocblist) kaio_jobdone; /* done queue for process */ TAILQ_HEAD (,aiocblist) kaio_bufqueue; /* buffer job queue for process */ TAILQ_HEAD (,aiocblist) kaio_bufdone; /* buffer done queue for process */ + TAILQ_HEAD (,aiocblist) kaio_sockqueue; /* queue for aios waiting on sockets */ }; #define KAIO_RUNDOWN 0x1 /* process is being run down */ *************** *** 286,292 **** --- 265,275 ---- TAILQ_INIT(&ki->kaio_bufdone); TAILQ_INIT(&ki->kaio_bufqueue); TAILQ_INIT(&ki->kaio_liojoblist); + TAILQ_INIT(&ki->kaio_sockqueue); } + + while (num_aio_procsp_aioinfo; if (ki == NULL) return; --- 385,394 ---- struct kaioinfo *ki; struct aio_liojob *lj, *ljn; struct aiocblist *aiocbe, *aiocbn; ! struct file *fp; ! struct filedesc *fdp; ! struct socket *so; ! ki = p->p_aioinfo; if (ki == NULL) return; *************** *** 415,420 **** --- 401,445 ---- break; } + /* + * We move any aio ops that are waiting on socket io to the normal job + * queues so they are cleaned up with any others. + */ + + fdp=p->p_fd; + + s = splnet(); + for ( aiocbe = TAILQ_FIRST(&ki->kaio_sockqueue); + aiocbe; + aiocbe = aiocbn) { + aiocbn = TAILQ_NEXT(aiocbe, plist); + fp=fdp->fd_ofiles[aiocbe->uaiocb.aio_fildes]; + /* + * Under some circumstances, the aio_fildes and the file + * structure don't match--this leaves aiocbe's in the TAILQ + * associated with the socket and causes a panic later. + * + * Detect and fix. + */ + if ((fp==NULL) || (fp!=aiocbe->fd_file)) { + fp=aiocbe->fd_file; + } + if (fp) { + so=(struct socket *)fp->f_data; + TAILQ_REMOVE(&so->so_aiojobq,aiocbe,list); + if (TAILQ_EMPTY(&so->so_aiojobq)) { + so->so_snd.sb_flags&=~SB_AIO; + so->so_rcv.sb_flags&=~SB_AIO; + } + } + TAILQ_REMOVE(&ki->kaio_sockqueue,aiocbe,plist); + TAILQ_INSERT_HEAD(&aio_jobs,aiocbe,list); + TAILQ_INSERT_HEAD(&ki->kaio_jobqueue,aiocbe,plist); + } + splx(s); + + + restart1: for ( aiocbe = TAILQ_FIRST(&ki->kaio_jobdone); aiocbe; *************** *** 487,501 **** static struct aiocblist * aio_selectjob(struct aioproclist *aiop) { ! struct aiocblist *aiocbe; aiocbe = TAILQ_FIRST(&aiop->jobtorun); if (aiocbe) { TAILQ_REMOVE(&aiop->jobtorun, aiocbe, list); return aiocbe; ! } ! for (aiocbe = TAILQ_FIRST(&aio_jobs); aiocbe; aiocbe = TAILQ_NEXT(aiocbe, list)) { --- 512,527 ---- static struct aiocblist * aio_selectjob(struct aioproclist *aiop) { ! int s; struct aiocblist *aiocbe; aiocbe = TAILQ_FIRST(&aiop->jobtorun); if (aiocbe) { TAILQ_REMOVE(&aiop->jobtorun, aiocbe, list); return aiocbe; ! } ! ! s=splnet(); for (aiocbe = TAILQ_FIRST(&aio_jobs); aiocbe; aiocbe = TAILQ_NEXT(aiocbe, list)) { *************** *** 507,515 **** --- 533,543 ---- if (ki->kaio_active_count < ki->kaio_maxactive_count) { TAILQ_REMOVE(&aio_jobs, aiocbe, list); + splx(s); return aiocbe; } } + splx(s); return NULL; } *************** *** 546,551 **** --- 574,585 ---- fd = cb->aio_fildes; fp = fdp->fd_ofiles[fd]; + if ((fp==NULL) || (fp!=aiocbe->fd_file)) { + cb->_aiocb_private.error=EBADF; + cb->_aiocb_private.status=-1; + return; + } + aiov.iov_base = (void *) cb->aio_buf; aiov.iov_len = cb->aio_nbytes; *************** *** 584,589 **** --- 618,624 ---- cnt -= auio.uio_resid; cb->_aiocb_private.error = error; cb->_aiocb_private.status = cnt; + return; *************** *** 621,626 **** --- 656,663 ---- aiop->aioprocflags |= AIOP_FREE; TAILQ_INIT(&aiop->jobtorun); + s=splnet(); + /* * Place thread (lightweight process) onto the AIO free thread list */ *************** *** 628,633 **** --- 665,672 ---- wakeup(&aio_freeproc); TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list); + splx(s); + /* * Make up a name for the daemon */ *************** *** 675,683 **** --- 714,724 ---- * Take daemon off of free queue */ if (aiop->aioprocflags & AIOP_FREE) { + s=splnet(); TAILQ_REMOVE(&aio_freeproc, aiop, list); TAILQ_INSERT_TAIL(&aio_activeproc, aiop, list); aiop->aioprocflags &= ~AIOP_FREE; + splx(s); } aiop->aioprocflags &= ~AIOP_SCHED; *************** *** 786,791 **** --- 827,834 ---- * the just finished I/O request into the done queue for the * associated client. */ + + s=splnet(); if (aiocbe->jobflags & AIOCBLIST_ASYNCFREE) { aiocbe->jobflags &= ~AIOCBLIST_ASYNCFREE; TAILQ_INSERT_HEAD(&aio_freejobs, aiocbe, list); *************** *** 795,800 **** --- 838,844 ---- TAILQ_INSERT_TAIL(&ki->kaio_jobdone, aiocbe, plist); } + splx(s); if (aiocbe->jobflags & AIOCBLIST_RUNDOWN) { wakeup(aiocbe); *************** *** 844,854 **** --- 888,900 ---- * If we are the first to be put onto the free queue, wakeup * anyone waiting for a daemon. */ + s=splnet(); TAILQ_REMOVE(&aio_activeproc, aiop, list); if (TAILQ_EMPTY(&aio_freeproc)) wakeup(&aio_freeproc); TAILQ_INSERT_HEAD(&aio_freeproc, aiop, list); aiop->aioprocflags |= AIOP_FREE; + splx(s); /* * If daemon is inactive for a long time, allow it to exit, thereby *************** *** 856,876 **** */ if (((aiop->aioprocflags & AIOP_SCHED) == 0) && tsleep(mycp, PRIBIO, "aiordy", aiod_lifetime)) { if ((TAILQ_FIRST(&aio_jobs) == NULL) && (TAILQ_FIRST(&aiop->jobtorun) == NULL)) { if ((aiop->aioprocflags & AIOP_FREE) && (num_aio_procs > target_aio_procs)) { TAILQ_REMOVE(&aio_freeproc, aiop, list); zfree(aiop_zone, aiop); num_aio_procs--; #if defined(DIAGNOSTIC) if (mycp->p_vmspace->vm_refcnt <= 1) printf("AIOD: bad vm refcnt for exiting daemon: %d\n", mycp->p_vmspace->vm_refcnt); ! #endif exit1(mycp, 0); } } } } } --- 902,925 ---- */ if (((aiop->aioprocflags & AIOP_SCHED) == 0) && tsleep(mycp, PRIBIO, "aiordy", aiod_lifetime)) { + s=splnet(); if ((TAILQ_FIRST(&aio_jobs) == NULL) && (TAILQ_FIRST(&aiop->jobtorun) == NULL)) { if ((aiop->aioprocflags & AIOP_FREE) && (num_aio_procs > target_aio_procs)) { TAILQ_REMOVE(&aio_freeproc, aiop, list); + splx(s); zfree(aiop_zone, aiop); num_aio_procs--; #if defined(DIAGNOSTIC) if (mycp->p_vmspace->vm_refcnt <= 1) printf("AIOD: bad vm refcnt for exiting daemon: %d\n", mycp->p_vmspace->vm_refcnt); ! #endif exit1(mycp, 0); } } + splx(s); } } } *************** *** 1127,1132 **** --- 1176,1225 ---- return (error); } + void + aio_swake(struct socket *so,struct sockbuf *sb) + { + struct aiocblist *cb,*cbn; + struct proc *p; + struct kaioinfo *ki=NULL; + int opcode,wakecount=0; + struct aioproclist *aiop; + + if (sb==&so->so_snd) { + opcode=LIO_WRITE; + so->so_snd.sb_flags&=~SB_AIO; + } else { + opcode=LIO_READ; + so->so_rcv.sb_flags&=~SB_AIO; + } + + for (cb=TAILQ_FIRST(&so->so_aiojobq);cb;cb=cbn) { + cbn=TAILQ_NEXT(cb,list); + if (opcode==cb->uaiocb.aio_lio_opcode) { + p=cb->userproc; + ki=p->p_aioinfo; + TAILQ_REMOVE(&so->so_aiojobq,cb,list); + TAILQ_REMOVE(&ki->kaio_sockqueue,cb,plist); + TAILQ_INSERT_TAIL(&aio_jobs,cb,list); + TAILQ_INSERT_TAIL(&ki->kaio_jobqueue,cb,plist); + wakecount++; + if (cb->jobstate!=JOBST_JOBQGLOBAL) + panic("invalid queue value"); + } + } + + while (wakecount--) { + if ((aiop = TAILQ_FIRST(&aio_freeproc)) != 0) { + TAILQ_REMOVE(&aio_freeproc, aiop, list); + TAILQ_INSERT_TAIL(&aio_activeproc, aiop, list); + aiop->aioprocflags &= ~AIOP_FREE; + wakeup(aiop->aioproc); + } + } + + } + + /* * Queue a new AIO request. Choosing either the threaded or direct physio * VCHR technique is done in this code. *************** *** 1137,1142 **** --- 1230,1237 ---- struct filedesc *fdp; struct file *fp; unsigned int fd; + struct socket *so; + int s; int error; int opcode; *************** *** 1196,1202 **** return EBADF; } ! fp = fdp->fd_ofiles[fd]; if ((fp == NULL) || ((opcode == LIO_WRITE) && ((fp->f_flag & FWRITE) == 0))) { TAILQ_INSERT_HEAD(&aio_freejobs, aiocbe, list); --- 1291,1297 ---- return EBADF; } ! fp = aiocbe->fd_file = fdp->fd_ofiles[fd]; if ((fp == NULL) || ((opcode == LIO_WRITE) && ((fp->f_flag & FWRITE) == 0))) { TAILQ_INSERT_HEAD(&aio_freejobs, aiocbe, list); *************** *** 1255,1260 **** --- 1350,1385 ---- aiocbe->lio = lj; ki = p->p_aioinfo; + if (fp->f_type==DTYPE_SOCKET) { + + /* + * Alternate queueing for socket ops: We reach down into the descriptor + * to get the socket data. We then check to see if the socket is ready + * to be read or written (based on the requested operation). + * + * If it is not ready for io, then queue the aiocbe on the socket, + * and set the flags so we get a call when sbnotify() happens. + */ + so=(struct socket *)fp->f_data; + s=splnet(); + if (((opcode==LIO_READ) && (!soreadable(so))) || + ((opcode==LIO_WRITE) && (!sowriteable(so)))) { + TAILQ_INSERT_TAIL(&so->so_aiojobq,aiocbe,list); + TAILQ_INSERT_TAIL(&ki->kaio_sockqueue,aiocbe,plist); + if (opcode==LIO_READ) { + so->so_rcv.sb_flags|=SB_AIO; + } else { + so->so_snd.sb_flags|=SB_AIO; + } + aiocbe->jobstate = JOBST_JOBQGLOBAL; /* XXX */ + ki->kaio_queue_count++; + num_queue_count++; + splx(s); + return 0; + } + splx(s); + } + if ((error = aio_qphysio(p, aiocbe)) == 0) { return 0; } else if (error > 0) { *************** *** 1273,1280 **** --- 1398,1407 ---- if (lj) { lj->lioj_queue_count++; } + s=splnet(); TAILQ_INSERT_TAIL(&ki->kaio_jobqueue, aiocbe, plist); TAILQ_INSERT_TAIL(&aio_jobs, aiocbe, list); + splx(s); aiocbe->jobstate = JOBST_JOBQGLOBAL; num_queue_count++; *************** *** 1289,1294 **** --- 1416,1422 ---- * correct thing to do. */ retryproc: + s=splnet(); if ((aiop = TAILQ_FIRST(&aio_freeproc)) != NULL) { TAILQ_REMOVE(&aio_freeproc, aiop, list); TAILQ_INSERT_TAIL(&aio_activeproc, aiop, list); *************** *** 1305,1310 **** --- 1433,1439 ---- } num_aio_resv_start--; } + splx(s); return error; } *************** *** 1353,1363 **** jobref = fuword(&ujob->_aiocb_private.kernelinfo); if (jobref == -1 || jobref == 0) return EINVAL; ! for (cb = TAILQ_FIRST(&ki->kaio_jobdone); cb; cb = TAILQ_NEXT(cb, plist)) { if (((intptr_t) cb->uaiocb._aiocb_private.kernelinfo) == jobref) { if (ujob == cb->uuaiocb) { p->p_retval[0] = cb->uaiocb._aiocb_private.status; } else { --- 1482,1494 ---- jobref = fuword(&ujob->_aiocb_private.kernelinfo); if (jobref == -1 || jobref == 0) return EINVAL; ! ! s=splnet(); for (cb = TAILQ_FIRST(&ki->kaio_jobdone); cb; cb = TAILQ_NEXT(cb, plist)) { if (((intptr_t) cb->uaiocb._aiocb_private.kernelinfo) == jobref) { + splx(s); if (ujob == cb->uuaiocb) { p->p_retval[0] = cb->uaiocb._aiocb_private.status; } else { *************** *** 1374,1380 **** return 0; } } ! s = splbio(); for (cb = TAILQ_FIRST(&ki->kaio_bufdone); cb; --- 1505,1512 ---- return 0; } } ! splx(s); ! s = splbio(); for (cb = TAILQ_FIRST(&ki->kaio_bufdone); cb; *************** *** 1452,1457 **** --- 1584,1590 ---- ijoblist[njoblist] = fuword(&cbp->_aiocb_private.kernelinfo); njoblist++; } + if (njoblist == 0) { zfree(aiol_zone, ijoblist); zfree(aiol_zone, ujoblist); *************** *** 1551,1565 **** --- 1684,1702 ---- } } + s=splnet(); + for (cb = TAILQ_FIRST(&ki->kaio_jobqueue); cb; cb = TAILQ_NEXT(cb, plist)) { if (((intptr_t) cb->uaiocb._aiocb_private.kernelinfo) == jobref) { p->p_retval[0] = EINPROGRESS; + splx(s); return 0; } } + splx(s); s = splbio(); for (cb = TAILQ_FIRST(&ki->kaio_bufdone); *************** *** 1917,1931 **** * to do so from a timeout routine, but *not* from an interrupt routine. */ static void ! process_signal(void *ljarg) { ! struct aio_liojob *lj = ljarg; ! if (lj->lioj_signal.sigev_notify == SIGEV_SIGNAL) { ! if (lj->lioj_queue_count == lj->lioj_queue_finished_count) { ! psignal(lj->lioj_ki->kaio_p, lj->lioj_signal.sigev_signo); ! lj->lioj_flags |= LIOJ_SIGNAL_POSTED; } } } /* --- 2054,2078 ---- * to do so from a timeout routine, but *not* from an interrupt routine. */ static void ! process_signal(void *aioj) { ! struct aiocblist *aiocbe = aioj; ! struct aio_liojob *lj = aiocbe->lio; ! struct aiocb *cb = &aiocbe->uaiocb; ! ! if (lj) { ! if (lj->lioj_signal.sigev_notify == SIGEV_SIGNAL) { ! if (lj->lioj_queue_count == lj->lioj_queue_finished_count) { ! psignal(lj->lioj_ki->kaio_p,lj->lioj_signal.sigev_signo); ! lj->lioj_flags |= LIOJ_SIGNAL_POSTED; ! } } } + + if (cb->aio_sigevent.sigev_notify == SIGEV_SIGNAL) { + psignal(aiocbe->userproc,cb->aio_sigevent.sigev_signo); + } + } /* *************** *** 1973,1979 **** if ((lj->lioj_flags & (LIOJ_SIGNAL|LIOJ_SIGNAL_POSTED)) == LIOJ_SIGNAL) { lj->lioj_flags |= LIOJ_SIGNAL_POSTED; ! timeout(process_signal, lj, 0); } } } --- 2120,2126 ---- if ((lj->lioj_flags & (LIOJ_SIGNAL|LIOJ_SIGNAL_POSTED)) == LIOJ_SIGNAL) { lj->lioj_flags |= LIOJ_SIGNAL_POSTED; ! timeout(process_signal, aiocbe, 0); } } } *************** *** 1992,1997 **** --- 2139,2221 ---- wakeup(p); } } + + if (aiocbe->uaiocb. aio_sigevent.sigev_notify == SIGEV_SIGNAL) { + timeout(process_signal, aiocbe, 0); + } } splx(s); } + + int + aio_waitcomplete(struct proc *p, struct aio_waitcomplete_args *uap) + { + struct timeval atv; + struct timespec ts; + struct aiocb **cbptr; + struct kaioinfo *ki; + struct aiocblist *cb=NULL; + int error, s, timo; + + timo = 0; + if (uap->timeout) { + /* + * Get timespec struct + */ + error = copyin((caddr_t) uap->timeout, (caddr_t) &ts, sizeof(ts)); + if (error) + return error; + + if ((ts.tv_nsec < 0) || (ts.tv_nsec >= 1000000000)) + return (EINVAL); + + TIMESPEC_TO_TIMEVAL(&atv, &ts); + if (itimerfix(&atv)) + return (EINVAL); + timo = tvtohz(&atv); + } + + ki = p->p_aioinfo; + if (ki == NULL) + return EAGAIN; + + cbptr = uap->aiocbp; + + while (1) { + if ((cb = TAILQ_FIRST(&ki->kaio_jobdone)) != 0) { + suword(uap->aiocbp,(int)cb->uuaiocb); + p->p_retval[0] = cb->uaiocb._aiocb_private.status; + if (cb->uaiocb.aio_lio_opcode == LIO_WRITE) { + curproc->p_stats->p_ru.ru_oublock += cb->outputcharge; + cb->outputcharge = 0; + } else if (cb->uaiocb.aio_lio_opcode == LIO_READ) { + curproc->p_stats->p_ru.ru_inblock += cb->inputcharge; + cb->inputcharge = 0; + } + aio_free_entry(cb); + return 0; + } + + s=splbio(); + if (( cb = TAILQ_FIRST(&ki->kaio_bufdone)) != 0 ) { + splx(s); + suword(uap->aiocbp,(int)cb->uuaiocb); + p->p_retval[0] = cb->uaiocb._aiocb_private.status; + aio_free_entry(cb); + return 0; + } + splx(s); + + ki->kaio_flags |= KAIO_WAKEUP; + error = tsleep(p, PRIBIO|PCATCH, "aiowc", timo); + + if (error < 0) { + return error; + } else if (error == EINTR) { + return EINTR; + } else if (error == EWOULDBLOCK) { + return EAGAIN; + } + } + } + *** /usr/src/sys/sys/aio.h.orig Wed Nov 3 19:39:38 1999 --- /usr/src/sys/sys/aio.h Wed Nov 3 19:49:11 1999 *************** *** 22,27 **** --- 22,28 ---- #include #include #include + #include /* * Returned by aio_cancel: *************** *** 141,151 **** --- 142,179 ---- */ int aio_error(const struct aiocb *); + int aio_waitcomplete(struct aiocb **, struct timespec *); + __END_DECLS #else + /* + * Job queue item + */ + + #define AIOCBLIST_CANCELLED 0x1 + #define AIOCBLIST_RUNDOWN 0x4 + #define AIOCBLIST_ASYNCFREE 0x8 + #define AIOCBLIST_DONE 0x10 + + struct aiocblist { + TAILQ_ENTRY (aiocblist) list; /* List of jobs */ + TAILQ_ENTRY (aiocblist) plist; /* List of jobs for proc */ + int jobflags; + int jobstate; + int inputcharge, outputcharge; + struct buf *bp; /* buffer pointer */ + struct proc *userproc; /* User process */ + struct file *fd_file; /* pointer to file structure */ + struct aioproclist *jobaioproc; /* AIO process descriptor */ + struct aio_liojob *lio; /* optional lio job */ + struct aiocb *uuaiocb; /* pointer in userspace of aiocb */ + struct aiocb uaiocb; /* Kernel I/O control block */ + }; void aio_proc_rundown(struct proc *p); + + void aio_swake(struct socket *,struct sockbuf *); #endif *** /usr/src/sys/sys/socketvar.h.orig Wed Nov 3 19:39:47 1999 --- /usr/src/sys/sys/socketvar.h Wed Nov 3 19:40:34 1999 *************** *** 80,85 **** --- 80,86 ---- struct sigio *so_sigio; /* information for async I/O or out of band data (SIGURG) */ u_long so_oobmark; /* chars to oob mark */ + TAILQ_HEAD(, aiocblist) so_aiojobq; /* AIO ops waiting on socket */ /* * Variables for socket buffering. */ *************** *** 102,107 **** --- 103,109 ---- #define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ #define SB_UPCALL 0x20 /* someone wants an upcall */ #define SB_NOINTR 0x40 /* operations not interruptible */ + #define SB_AIO 0x80 /* AIO operations queued */ void (*so_upcall) __P((struct socket *, void *, int)); void *so_upcallarg; *************** *** 169,175 **** /* * Do we need to notify the other side when I/O is possible? */ ! #define sb_notify(sb) (((sb)->sb_flags & (SB_WAIT|SB_SEL|SB_ASYNC|SB_UPCALL)) != 0) /* * How much space is there in a socket buffer (so->so_snd or so->so_rcv)? --- 171,177 ---- /* * Do we need to notify the other side when I/O is possible? */ ! #define sb_notify(sb) (((sb)->sb_flags & (SB_WAIT|SB_SEL|SB_ASYNC|SB_UPCALL|SB_AIO)) != 0) /* * How much space is there in a socket buffer (so->so_snd or so->so_rcv)?