diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-11-03 05:25:26 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-11-03 05:25:26 +0000 |
commit | 064df4ad12d353b290a021dc6da0d558ecd2c84d (patch) | |
tree | aabc154a0a412514eccf26165fbb7dc044736967 /sys | |
parent | 301b115d609d2595189bf67894c5e3db2fd34cb0 (diff) | |
download | FreeBSD-src-064df4ad12d353b290a021dc6da0d558ecd2c84d.zip FreeBSD-src-064df4ad12d353b290a021dc6da0d558ecd2c84d.tar.gz |
Support sending realtime signal information via signal queue, realtime
signal memory is pre-allocated, so kernel can always notify user code.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_aio.c | 48 |
1 files changed, 40 insertions, 8 deletions
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index b39f1a6..534b87d 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -196,6 +196,7 @@ struct aiocblist { struct aiocb *uuaiocb; /* Pointer in userspace of aiocb */ struct knlist klist; /* list of knotes */ struct aiocb uaiocb; /* Kernel I/O control block */ + ksiginfo_t ksi; /* Realtime signal info */ }; /* jobflags */ @@ -225,7 +226,8 @@ struct aio_liojob { int lioj_total_count; struct sigevent lioj_signal; /* signal on all I/O done */ TAILQ_ENTRY(aio_liojob) lioj_list; - struct knlist klist; /* list of knotes */ + struct knlist klist; /* list of knotes */ + ksiginfo_t lioj_ksi; /* Realtime signal info */ }; #define LIOJ_SIGNAL 0x1 /* signal on all done (lio) */ #define LIOJ_SIGNAL_POSTED 0x2 /* signal has been posted */ @@ -454,6 +456,18 @@ aio_init_aioinfo(struct proc *p) aio_newproc(); } +static int +aio_sendsig(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + if (!KSI_ONQ(ksi)) { + ksi->ksi_code = SI_ASYNCIO; + ksi->ksi_flags |= KSI_EXT | KSI_INS; + return (psignal_event(p, sigev, ksi)); + } + return (0); +} + /* * Free a job entry. Wait for completion if it is currently active, but don't * delay forever. If we delay, we return a flag that says that we have to @@ -552,11 +566,17 @@ aio_free_entry(struct aiocblist *aiocbe) } if (lj && (lj->lioj_buffer_count == 0) && (lj->lioj_queue_count == 0)) { TAILQ_REMOVE(&ki->kaio_liojoblist, lj, lioj_list); + PROC_LOCK(p); + sigqueue_take(&lj->lioj_ksi); + PROC_UNLOCK(p); uma_zfree(aiolio_zone, lj); } aiocbe->jobstate = JOBST_NULL; fdrop(aiocbe->fd_file, curthread); crfree(aiocbe->cred); + PROC_LOCK(p); + sigqueue_take(&aiocbe->ksi); + PROC_UNLOCK(p); uma_zfree(aiocb_zone, aiocbe); return (0); } @@ -828,9 +848,10 @@ aio_bio_done_notify( struct proc *userp, struct aiocblist *aiocbe, int type){ if ((lj->lioj_flags & (LIOJ_SIGNAL|LIOJ_SIGNAL_POSTED)) == LIOJ_SIGNAL - && lj->lioj_signal.sigev_notify == SIGEV_SIGNAL) { + && (lj->lioj_signal.sigev_notify == SIGEV_SIGNAL || + lj->lioj_signal.sigev_notify == SIGEV_THREAD_ID)) { PROC_LOCK(userp); - psignal(userp, lj->lioj_signal.sigev_signo); + aio_sendsig(userp, &lj->lioj_signal, &lj->lioj_ksi); PROC_UNLOCK(userp); lj->lioj_flags |= LIOJ_SIGNAL_POSTED; } @@ -843,9 +864,10 @@ aio_bio_done_notify( struct proc *userp, struct aiocblist *aiocbe, int type){ } } - if (aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_SIGNAL) { + if (aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_SIGNAL || + aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_THREAD_ID) { PROC_LOCK(userp); - psignal(userp, aiocbe->uaiocb.aio_sigevent.sigev_signo); + aio_sendsig(userp, &aiocbe->uaiocb.aio_sigevent, &aiocbe->ksi); PROC_UNLOCK(userp); } } @@ -894,8 +916,10 @@ aio_daemon(void *uproc) * Get rid of our current filedescriptors. AIOD's don't need any * filedescriptors, except as temporarily inherited from the client. */ + mtx_lock(&Giant); fdfree(td); + mtx_unlock(&Giant); /* The daemon resides in its own pgrp. */ MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); @@ -1377,12 +1401,15 @@ _aio_aqueue(struct thread *td, struct aiocb *job, struct aio_liojob *lj, uma_zfree(aiocb_zone, aiocbe); return (error); } - if (aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_SIGNAL && + if ((aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_SIGNAL || + aiocbe->uaiocb.aio_sigevent.sigev_notify == SIGEV_THREAD_ID) && !_SIG_VALID(aiocbe->uaiocb.aio_sigevent.sigev_signo)) { uma_zfree(aiocb_zone, aiocbe); return (EINVAL); } + ksiginfo_init(&aiocbe->ksi); + /* Save userspace address of the job info. */ aiocbe->uuaiocb = job; @@ -1830,9 +1857,13 @@ aio_cancel(struct thread *td, struct aio_cancel_args *uap) cancelled++; /* XXX cancelled, knote? */ if (cbe->uaiocb.aio_sigevent.sigev_notify == - SIGEV_SIGNAL) { + SIGEV_SIGNAL || + cbe->uaiocb.aio_sigevent.sigev_notify == + SIGEV_THREAD_ID) { PROC_LOCK(cbe->userproc); - psignal(cbe->userproc, cbe->uaiocb.aio_sigevent.sigev_signo); + aio_sendsig(cbe->userproc, + &cbe->uaiocb.aio_sigevent, + &cbe->ksi); PROC_UNLOCK(cbe->userproc); } if (uap->aiocbp) @@ -2066,6 +2097,7 @@ do_lio_listio(struct thread *td, struct lio_listio_args *uap, int oldsigev) lj->lioj_queue_finished_count = 0; lj->lioj_total_count = nent; knlist_init(&lj->klist, NULL, NULL, NULL, NULL); + ksiginfo_init(&lj->lioj_ksi); kev.ident = 0; |