diff options
author | kmacy <kmacy@FreeBSD.org> | 2012-02-23 18:37:30 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2012-02-23 18:37:30 +0000 |
commit | a5c27d1ee09335bcd4404b5178206c7ce94ecf3e (patch) | |
tree | 8bf54dce4a89197401de4325a0cf13b1ffdf3ded /sys/kern/sys_pipe.c | |
parent | a99e9d281db6624cf9b88f07759a77f7b2d96a33 (diff) | |
download | FreeBSD-src-a5c27d1ee09335bcd4404b5178206c7ce94ecf3e.zip FreeBSD-src-a5c27d1ee09335bcd4404b5178206c7ce94ecf3e.tar.gz |
merge pipe and fifo implementations
Also reviewed by: jhb, jilles (initial revision)
Tested by: pho, jilles
Submitted by: gianni
Reviewed by: bde
Diffstat (limited to 'sys/kern/sys_pipe.c')
-rw-r--r-- | sys/kern/sys_pipe.c | 192 |
1 files changed, 145 insertions, 47 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 0cb4fce..4f0217d 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1996 John S. Dyson + * Copyright (c) 2012 Giovanni Trematerra * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -128,6 +129,8 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_page.h> #include <vm/uma.h> +#include <fs/fifofs/fifo.h> + /* * Use this define if you want to disable *fancy* VM things. Expect an * approx 30% decrease in transfer rate. This could be useful for @@ -135,6 +138,9 @@ __FBSDID("$FreeBSD$"); */ /* #define PIPE_NODIRECT */ +#define PIPE_PEER(pipe) \ + (((pipe)->pipe_state & PIPE_NAMED) ? (pipe) : ((pipe)->pipe_peer)) + /* * interfaces to the outside world */ @@ -147,7 +153,7 @@ static fo_kqfilter_t pipe_kqfilter; static fo_stat_t pipe_stat; static fo_close_t pipe_close; -static struct fileops pipeops = { +struct fileops pipeops = { .fo_read = pipe_read, .fo_write = pipe_write, .fo_truncate = pipe_truncate, @@ -162,9 +168,16 @@ static struct fileops pipeops = { }; static void filt_pipedetach(struct knote *kn); +static void filt_pipedetach_notsup(struct knote *kn); +static int filt_pipenotsup(struct knote *kn, long hint); static int filt_piperead(struct knote *kn, long hint); static int filt_pipewrite(struct knote *kn, long hint); +static struct filterops pipe_nfiltops = { + .f_isfd = 1, + .f_detach = filt_pipedetach_notsup, + .f_event = filt_pipenotsup +}; static struct filterops pipe_rfiltops = { .f_isfd = 1, .f_detach = filt_pipedetach, @@ -208,6 +221,7 @@ static void pipeinit(void *dummy __unused); static void pipeclose(struct pipe *cpipe); static void pipe_free_kmem(struct pipe *cpipe); static int pipe_create(struct pipe *pipe, int backing); +static int pipe_paircreate(struct thread *td, struct pipepair **p_pp); static __inline int pipelock(struct pipe *cpipe, int catch); static __inline void pipeunlock(struct pipe *cpipe); static __inline void pipeselwakeup(struct pipe *cpipe); @@ -317,20 +331,14 @@ pipe_zone_fini(void *mem, int size) mtx_destroy(&pp->pp_mtx); } -/* - * The pipe system call for the DTYPE_PIPE type of pipes. If we fail, let - * the zone pick up the pieces via pipeclose(). - */ -int -kern_pipe(struct thread *td, int fildes[2]) +static int +pipe_paircreate(struct thread *td, struct pipepair **p_pp) { - struct filedesc *fdp = td->td_proc->p_fd; - struct file *rf, *wf; struct pipepair *pp; struct pipe *rpipe, *wpipe; - int fd, error; + int error; - pp = uma_zalloc(pipe_zone, M_WAITOK); + *p_pp = pp = uma_zalloc(pipe_zone, M_WAITOK); #ifdef MAC /* * The MAC label is shared between the connected endpoints. As a @@ -356,7 +364,59 @@ kern_pipe(struct thread *td, int fildes[2]) rpipe->pipe_state |= PIPE_DIRECTOK; wpipe->pipe_state |= PIPE_DIRECTOK; + return (0); +} + +int +pipe_named_ctor(struct pipe **ppipe, struct thread *td) +{ + struct pipepair *pp; + int error; + + error = pipe_paircreate(td, &pp); + if (error != 0) + return (error); + pp->pp_rpipe.pipe_state |= PIPE_NAMED; + *ppipe = &pp->pp_rpipe; + return (0); +} + +void +pipe_dtor(struct pipe *dpipe) +{ + ino_t ino; + + ino = dpipe->pipe_ino; + funsetown(&dpipe->pipe_sigio); + pipeclose(dpipe); + if (dpipe->pipe_state & PIPE_NAMED) { + dpipe = dpipe->pipe_peer; + funsetown(&dpipe->pipe_sigio); + pipeclose(dpipe); + } + if (ino != 0 && ino != (ino_t)-1) + free_unr(pipeino_unr, ino); +} + +/* + * The pipe system call for the DTYPE_PIPE type of pipes. If we fail, let + * the zone pick up the pieces via pipeclose(). + */ +int +kern_pipe(struct thread *td, int fildes[2]) +{ + struct filedesc *fdp; + struct file *rf, *wf; + struct pipe *rpipe, *wpipe; + struct pipepair *pp; + int fd, error; + fdp = td->td_proc->p_fd; + error = pipe_paircreate(td, &pp); + if (error != 0) + return (error); + rpipe = &pp->pp_rpipe; + wpipe = &pp->pp_wpipe; error = falloc(td, &rf, &fd, 0); if (error) { pipeclose(rpipe); @@ -582,11 +642,12 @@ pipe_read(fp, uio, active_cred, flags, td) struct thread *td; int flags; { - struct pipe *rpipe = fp->f_data; + struct pipe *rpipe; int error; int nread = 0; u_int size; + rpipe = fp->f_data; PIPE_LOCK(rpipe); ++rpipe->pipe_busy; error = pipelock(rpipe, 1); @@ -960,13 +1021,12 @@ pipe_write(fp, uio, active_cred, flags, td) struct thread *td; int flags; { - int error = 0; + int error; size_t desiredsize, orig_resid; struct pipe *wpipe, *rpipe; rpipe = fp->f_data; - wpipe = rpipe->pipe_peer; - + wpipe = PIPE_PEER(rpipe); PIPE_LOCK(rpipe); error = pipelock(wpipe, 1); if (error) { @@ -1243,6 +1303,9 @@ pipe_truncate(fp, length, active_cred, td) struct thread *td; { + /* For named pipes call the vnode operation. */ + if (fp->f_vnode != NULL) + return (vnops.fo_truncate(fp, length, active_cred, td)); return (EINVAL); } @@ -1285,6 +1348,11 @@ pipe_ioctl(fp, cmd, data, active_cred, td) break; case FIONREAD: + if (!(fp->f_flag & FREAD)) { + *(int *)data = 0; + PIPE_UNLOCK(mpipe); + return (0); + } if (mpipe->pipe_state & PIPE_DIRECTW) *(int *)data = mpipe->pipe_map.cnt; else @@ -1327,26 +1395,28 @@ pipe_poll(fp, events, active_cred, td) struct ucred *active_cred; struct thread *td; { - struct pipe *rpipe = fp->f_data; + struct pipe *rpipe; struct pipe *wpipe; - int revents = 0; + int levents, revents; #ifdef MAC int error; #endif - wpipe = rpipe->pipe_peer; + revents = 0; + rpipe = fp->f_data; + wpipe = PIPE_PEER(rpipe); PIPE_LOCK(rpipe); #ifdef MAC error = mac_pipe_check_poll(active_cred, rpipe->pipe_pair); if (error) goto locked_error; #endif - if (events & (POLLIN | POLLRDNORM)) + if (fp->f_flag & FREAD && events & (POLLIN | POLLRDNORM)) if ((rpipe->pipe_state & PIPE_DIRECTW) || (rpipe->pipe_buffer.cnt > 0)) revents |= events & (POLLIN | POLLRDNORM); - if (events & (POLLOUT | POLLWRNORM)) + if (fp->f_flag & FWRITE && events & (POLLOUT | POLLWRNORM)) if (wpipe->pipe_present != PIPE_ACTIVE || (wpipe->pipe_state & PIPE_EOF) || (((wpipe->pipe_state & PIPE_DIRECTW) == 0) && @@ -1354,6 +1424,12 @@ pipe_poll(fp, events, active_cred, td) wpipe->pipe_buffer.size == 0))) revents |= events & (POLLOUT | POLLWRNORM); + levents = events & + (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND); + if (rpipe->pipe_state & PIPE_NAMED && fp->f_flag & FREAD && levents && + fifo_iseof(fp)) + events |= POLLINIGNEOF; + if ((events & POLLINIGNEOF) == 0) { if (rpipe->pipe_state & PIPE_EOF) { revents |= (events & (POLLIN | POLLRDNORM)); @@ -1364,13 +1440,13 @@ pipe_poll(fp, events, active_cred, td) } if (revents == 0) { - if (events & (POLLIN | POLLRDNORM)) { + if (fp->f_flag & FREAD && events & (POLLIN | POLLRDNORM)) { selrecord(td, &rpipe->pipe_sel); if (SEL_WAITING(&rpipe->pipe_sel)) rpipe->pipe_state |= PIPE_SEL; } - if (events & (POLLOUT | POLLWRNORM)) { + if (fp->f_flag & FWRITE && events & (POLLOUT | POLLWRNORM)) { selrecord(td, &wpipe->pipe_sel); if (SEL_WAITING(&wpipe->pipe_sel)) wpipe->pipe_state |= PIPE_SEL; @@ -1410,6 +1486,13 @@ pipe_stat(fp, ub, active_cred, td) return (error); } #endif + + /* For named pipes ask the underlying filesystem. */ + if (pipe->pipe_state & PIPE_NAMED) { + PIPE_UNLOCK(pipe); + return (vnops.fo_stat(fp, ub, active_cred, td)); + } + /* * Lazily allocate an inode number for the pipe. Most pipe * users do not call fstat(2) on the pipe, which means that @@ -1456,12 +1539,12 @@ pipe_close(fp, td) struct file *fp; struct thread *td; { - struct pipe *cpipe = fp->f_data; + if (fp->f_vnode != NULL) + return vnops.fo_close(fp, td); fp->f_ops = &badfileops; + pipe_dtor(fp->f_data); fp->f_data = NULL; - funsetown(&cpipe->pipe_sigio); - pipeclose(cpipe); return (0); } @@ -1498,7 +1581,6 @@ pipeclose(cpipe) { struct pipepair *pp; struct pipe *ppipe; - ino_t ino; KASSERT(cpipe != NULL, ("pipeclose: cpipe == NULL")); @@ -1557,12 +1639,6 @@ pipeclose(cpipe) knlist_destroy(&cpipe->pipe_sel.si_note); /* - * Postpone the destroy of the fake inode number allocated for - * our end, until pipe mtx is unlocked. - */ - ino = cpipe->pipe_ino; - - /* * If both endpoints are now closed, release the memory for the * pipe pair. If not, unlock. */ @@ -1574,9 +1650,6 @@ pipeclose(cpipe) uma_zfree(pipe_zone, cpipe->pipe_pair); } else PIPE_UNLOCK(cpipe); - - if (ino != 0 && ino != (ino_t)-1) - free_unr(pipeino_unr, ino); } /*ARGSUSED*/ @@ -1585,7 +1658,20 @@ pipe_kqfilter(struct file *fp, struct knote *kn) { struct pipe *cpipe; - cpipe = kn->kn_fp->f_data; + /* + * If a filter is requested that is not supported by this file + * descriptor, don't return an error, but also don't ever generate an + * event. + */ + if ((kn->kn_filter == EVFILT_READ) && !(fp->f_flag & FREAD)) { + kn->kn_fop = &pipe_nfiltops; + return (0); + } + if ((kn->kn_filter == EVFILT_WRITE) && !(fp->f_flag & FWRITE)) { + kn->kn_fop = &pipe_nfiltops; + return (0); + } + cpipe = fp->f_data; PIPE_LOCK(cpipe); switch (kn->kn_filter) { case EVFILT_READ: @@ -1598,13 +1684,14 @@ pipe_kqfilter(struct file *fp, struct knote *kn) PIPE_UNLOCK(cpipe); return (EPIPE); } - cpipe = cpipe->pipe_peer; + cpipe = PIPE_PEER(cpipe); break; default: PIPE_UNLOCK(cpipe); return (EINVAL); } + kn->kn_hook = cpipe; knlist_add(&cpipe->pipe_sel.si_note, kn, 1); PIPE_UNLOCK(cpipe); return (0); @@ -1613,11 +1700,9 @@ pipe_kqfilter(struct file *fp, struct knote *kn) static void filt_pipedetach(struct knote *kn) { - struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data; + struct pipe *cpipe = kn->kn_hook; PIPE_LOCK(cpipe); - if (kn->kn_filter == EVFILT_WRITE) - cpipe = cpipe->pipe_peer; knlist_remove(&cpipe->pipe_sel.si_note, kn, 1); PIPE_UNLOCK(cpipe); } @@ -1626,7 +1711,7 @@ filt_pipedetach(struct knote *kn) static int filt_piperead(struct knote *kn, long hint) { - struct pipe *rpipe = kn->kn_fp->f_data; + struct pipe *rpipe = kn->kn_hook; struct pipe *wpipe = rpipe->pipe_peer; int ret; @@ -1651,15 +1736,15 @@ filt_piperead(struct knote *kn, long hint) static int filt_pipewrite(struct knote *kn, long hint) { - struct pipe *rpipe = kn->kn_fp->f_data; - struct pipe *wpipe = rpipe->pipe_peer; - - PIPE_LOCK(rpipe); + struct pipe *wpipe; + + wpipe = kn->kn_hook; + PIPE_LOCK(wpipe); if (wpipe->pipe_present != PIPE_ACTIVE || (wpipe->pipe_state & PIPE_EOF)) { kn->kn_data = 0; kn->kn_flags |= EV_EOF; - PIPE_UNLOCK(rpipe); + PIPE_UNLOCK(wpipe); return (1); } kn->kn_data = (wpipe->pipe_buffer.size > 0) ? @@ -1667,6 +1752,19 @@ filt_pipewrite(struct knote *kn, long hint) if (wpipe->pipe_state & PIPE_DIRECTW) kn->kn_data = 0; - PIPE_UNLOCK(rpipe); + PIPE_UNLOCK(wpipe); return (kn->kn_data >= PIPE_BUF); } + +static void +filt_pipedetach_notsup(struct knote *kn) +{ + +} + +static int +filt_pipenotsup(struct knote *kn, long hint) +{ + + return (0); +} |