diff options
author | alfred <alfred@FreeBSD.org> | 2002-01-13 11:58:06 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2002-01-13 11:58:06 +0000 |
commit | 844237b3960bfbf49070d6371a84f67f9e3366f6 (patch) | |
tree | 598e20df363e602313c7ad93de8f8c4b4240d61d /sys/kern/sys_pipe.c | |
parent | 8cd61193307ff459ae72eb7aa6a734eb5e3b427e (diff) | |
download | FreeBSD-src-844237b3960bfbf49070d6371a84f67f9e3366f6.zip FreeBSD-src-844237b3960bfbf49070d6371a84f67f9e3366f6.tar.gz |
SMP Lock struct file, filedesc and the global file list.
Seigo Tanimura (tanimura) posted the initial delta.
I've polished it quite a bit reducing the need for locking and
adapting it for KSE.
Locks:
1 mutex in each filedesc
protects all the fields.
protects "struct file" initialization, while a struct file
is being changed from &badfileops -> &pipeops or something
the filedesc should be locked.
1 mutex in each struct file
protects the refcount fields.
doesn't protect anything else.
the flags used for garbage collection have been moved to
f_gcflag which was the FILLER short, this doesn't need
locking because the garbage collection is a single threaded
container.
could likely be made to use a pool mutex.
1 sx lock for the global filelist.
struct file * fhold(struct file *fp);
/* increments reference count on a file */
struct file * fhold_locked(struct file *fp);
/* like fhold but expects file to locked */
struct file * ffind_hold(struct thread *, int fd);
/* finds the struct file in thread, adds one reference and
returns it unlocked */
struct file * ffind_lock(struct thread *, int fd);
/* ffind_hold, but returns file locked */
I still have to smp-safe the fget cruft, I'll get to that asap.
Diffstat (limited to 'sys/kern/sys_pipe.c')
-rw-r--r-- | sys/kern/sys_pipe.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index fd16065..49f1959 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -205,27 +205,33 @@ pipe(td, uap) * to avoid races against processes which manage to dup() the read * side while we are blocked trying to allocate the write side. */ + FILE_LOCK(rf); rf->f_flag = FREAD | FWRITE; rf->f_type = DTYPE_PIPE; rf->f_data = (caddr_t)rpipe; rf->f_ops = &pipeops; + FILE_UNLOCK(rf); error = falloc(td, &wf, &fd); if (error) { + FILEDESC_LOCK(fdp); if (fdp->fd_ofiles[td->td_retval[0]] == rf) { fdp->fd_ofiles[td->td_retval[0]] = NULL; + FILEDESC_UNLOCK(fdp); fdrop(rf, td); - } + } else + FILEDESC_UNLOCK(fdp); fdrop(rf, td); /* rpipe has been closed by fdrop(). */ pipeclose(wpipe); return (error); } + FILE_LOCK(wf); wf->f_flag = FREAD | FWRITE; wf->f_type = DTYPE_PIPE; wf->f_data = (caddr_t)wpipe; wf->f_ops = &pipeops; + FILE_UNLOCK(wf); td->td_retval[1] = fd; - rpipe->pipe_peer = wpipe; wpipe->pipe_peer = rpipe; fdrop(rf, td); @@ -495,9 +501,12 @@ pipe_read(fp, uio, cred, flags, td) * Handle non-blocking mode operation or * wait for more data. */ + FILE_LOCK(fp); if (fp->f_flag & FNONBLOCK) { + FILE_UNLOCK(fp); error = EAGAIN; } else { + FILE_UNLOCK(fp); rpipe->pipe_state |= PIPE_WANTR; if ((error = tsleep(rpipe, PRIBIO | PCATCH, "piperd", 0)) == 0) @@ -825,15 +834,18 @@ pipe_write(fp, uio, cred, flags, td) * The direct write mechanism will detect the reader going * away on us. */ + FILE_LOCK(fp); if ((uio->uio_iov->iov_len >= PIPE_MINDIRECT) && (fp->f_flag & FNONBLOCK) == 0 && (wpipe->pipe_map.kva || (amountpipekva < LIMITPIPEKVA)) && (uio->uio_iov->iov_len >= PIPE_MINDIRECT)) { + FILE_UNLOCK(fp); error = pipe_direct_write( wpipe, uio); if (error) break; continue; - } + } else + FILE_UNLOCK(fp); #endif /* @@ -961,10 +973,13 @@ pipe_write(fp, uio, cred, flags, td) /* * don't block on non-blocking I/O */ + FILE_LOCK(fp); if (fp->f_flag & FNONBLOCK) { + FILE_UNLOCK(fp); error = EAGAIN; break; } + FILE_UNLOCK(fp); /* * We have no more space and have something to offer, @@ -1236,8 +1251,9 @@ pipeclose(cpipe) static int pipe_kqfilter(struct file *fp, struct knote *kn) { - struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data; + struct pipe *cpipe; + cpipe = (struct pipe *)kn->kn_fp->f_data; switch (kn->kn_filter) { case EVFILT_READ: kn->kn_fop = &pipe_rfiltops; |