PERFORCE change 163701 for review

Zhao Shuai zhaoshuai at FreeBSD.org
Sun Jun 7 11:22:39 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=163701

Change 163701 by zhaoshuai at zhaoshuai on 2009/06/07 11:21:54

	add O_NONBLOCK handling in fifo_open()

Affected files ...

.. //depot/projects/soc2009/fifo/sys/fs/fifofs/fifo_vnops.c#9 edit

Differences ...

==== //depot/projects/soc2009/fifo/sys/fs/fifofs/fifo_vnops.c#9 (text+ko) ====

@@ -40,6 +40,8 @@
 #include <sys/filedesc.h>
 #include <sys/filio.h>
 #include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/unistd.h>
 #include <sys/vnode.h>
@@ -114,6 +116,9 @@
 	.vop_write =		VOP_PANIC,
 };
 
+struct mtx fifo_mtx;
+MTX_SYSINIT(fifo, &fifo_mtx, "fifo mutex", MTX_DEF);
+
 /*
  * Open called to set up a new instance of a fifo or
  * to find an active instance of a fifo.
@@ -155,15 +160,77 @@
 	/*
 	 * General access to fi_readers and fi_writers is protected using
 	 * the vnode lock.
+	 *
+	 * Protect the increment of fi_readers and fi_writers and the
+	 * associated calls to wakeup() with the fifo mutex in addition
+	 * to the vnode lock.  This allows the vnode lock to be dropped
+	 * for the msleep() calls below, and using the fifo mutex with
+	 * msleep() prevents the wakeup from being missed.
 	 */
-	if (ap->a_mode & FREAD)
+	mtx_lock(&fifo_mtx);
+	if (ap->a_mode & FREAD) {
 		fip->fi_readers++;
+		if (fip->fi_readers == 1 && fip->fi_writers > 0) 
+			wakeup(&fip->fi_writers);
+	}
 	if (ap->a_mode & FWRITE) {
 		if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) 
 			return (ENXIO);
 		fip->fi_writers++;		
+		if (fip->fi_writers == 1 && fip->fi_readers > 0)
+			wakeup(&fip->fi_readers);
 	}
-
+	if ((ap->a_mode & O_NONBLOCK) == 0) {
+		if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
+			VOP_UNLOCK(vp, 0);
+			error = msleep(&fip->fi_readers, &fifo_mtx, 
+			    PDROP | PCATCH, "fifoor", 0);
+			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+			if (error) {
+				fip->fi_readers--;
+				if (fip->fi_readers == 0) {
+					generic_pipe_close(fip->fi_rpipe);
+					if (fip->fi_writers == 0) {
+					 	generic_pipe_close(fip->fi_wpipe);
+						vp->v_fifoinfo = NULL;
+					 	free(fip, M_VNODE);
+					}
+				}
+				return (error);
+			}
+			mtx_lock(&fifo_mtx);
+			/*
+			 * We must have got woken up because we had a writer.
+			 * That (and not still having one) is the condition
+			 * that we must wait for.
+			 */ 
+		}
+		if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
+			VOP_UNLOCK(vp, 0);
+			error = msleep(&fip->fi_writers, &fifo_mtx,
+			    PDROP | PCATCH, "fifoow", 0);
+			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+			if (error) {
+				fip->fi_writers--;
+				if (fip->fi_writers == 0) {
+					generic_pipe_close(fip->fi_wpipe);
+					if (fip->fi_readers == 0) {
+						generic_pipe_close(fip->fi_rpipe);
+						vp->v_fifoinfo = NULL;
+						free(fip, M_VNODE);
+					}
+				}
+				return (error);
+			}
+			/*
+			 * We must have got woken up because we had
+			 * a reader.  That (and not still having one)
+			 * is the condition that we must wait for.
+			 */
+			mtx_lock(&fifo_mtx);
+		}
+	}
+	mtx_unlock(&fifo_mtx);
 	KASSERT(fp != NULL, ("can't fifo/vnode bypass"));
 	KASSERT(fp->f_ops == &badfileops, ("not badfileops in fifo_open"));
 	finit(fp, fp->f_flag, DTYPE_FIFO, fip, &fifo_ops_f);


More information about the p4-projects mailing list