svn commit: r192949 - head/tools/regression/file/flock

Zachary Loafman zml at FreeBSD.org
Thu May 28 02:39:08 UTC 2009


Author: zml
Date: Thu May 28 02:39:07 2009
New Revision: 192949
URL: http://svn.freebsd.org/changeset/base/192949

Log:
  Add a regression test for multiple threads of the same process acquiring the same fcntl lock.
  
  Approved by:        dfr (mentor)

Modified:
  head/tools/regression/file/flock/Makefile
  head/tools/regression/file/flock/flock.c

Modified: head/tools/regression/file/flock/Makefile
==============================================================================
--- head/tools/regression/file/flock/Makefile	Thu May 28 02:17:58 2009	(r192948)
+++ head/tools/regression/file/flock/Makefile	Thu May 28 02:39:07 2009	(r192949)
@@ -4,4 +4,6 @@ PROG=	flock
 NO_MAN=
 WARNS?=	6
 
+LDADD+=	-lpthread
+
 .include <bsd.prog.mk>

Modified: head/tools/regression/file/flock/flock.c
==============================================================================
--- head/tools/regression/file/flock/flock.c	Thu May 28 02:17:58 2009	(r192948)
+++ head/tools/regression/file/flock/flock.c	Thu May 28 02:39:07 2009	(r192949)
@@ -37,6 +37,7 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pthread.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1401,6 +1402,112 @@ test15(int fd, __unused int argc, const 
 #endif
 }
 
+struct test_ctx {
+	struct flock tc_fl;
+	int tc_fd;
+};
+
+static void *
+test16_func(void *tc_in)
+{
+	uintptr_t error;
+	struct test_ctx *tc = tc_in;
+
+	error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
+
+	pthread_exit((void *)error);
+}
+
+#define THREADS 10
+
+/*
+ * Test 16 - F_SETLKW from two threads
+ *
+ * If two threads within a process are blocked on a lock and the lock
+ * is granted, make sure things are sane.
+ */
+static int
+test16(int fd, __unused int argc, const __unused char **argv)
+{
+	/*
+	 * We create a child process to hold the lock which we will
+	 * test. We use a pipe to communicate with the child.
+	 */
+	int pid;
+	int pfd[2];
+	struct test_ctx tc = { .tc_fd = fd };
+	char ch;
+	int i;
+	int error;
+	pthread_t thr[THREADS];
+
+	if (pipe(pfd) < 0)
+		err(1, "pipe");
+
+	tc.tc_fl.l_start = 0;
+	tc.tc_fl.l_len = 0;
+	tc.tc_fl.l_type = F_WRLCK;
+	tc.tc_fl.l_whence = SEEK_SET;
+
+	pid = fork();
+	if (pid < 0)
+		err(1, "fork");
+
+	if (pid == 0) {
+		/*
+		 * We are the child. We set a write lock and then
+		 * write one byte back to the parent to tell it. The
+		 * parent will kill us when its done.
+		 */
+		if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
+			err(1, "F_SETLK (child)");
+		if (write(pfd[1], "a", 1) < 0)
+			err(1, "writing to pipe (child)");
+		pause();
+		exit(0);
+	}
+
+	/*
+	 * Wait until the child has set its lock and then perform the
+	 * test.
+	 */
+	if (read(pfd[0], &ch, 1) != 1)
+		err(1, "reading from pipe (child)");
+
+	/*
+	 * fcntl should wait until the alarm and then return -1 with
+	 * errno set to EINTR.
+	 */
+	printf("16 - F_SETLKW on locked region by two threads: ");
+
+	for (i = 0; i < THREADS; i++) {
+		error = pthread_create(&thr[i], NULL, test16_func, &tc);
+		if (error)
+			err(1, "pthread_create");
+	}
+
+	/*
+	 * Sleep, then kill the child. This makes me a little sad, but it's
+	 * tricky to tell whether the threads are all really blocked by this
+	 * point.
+	 */
+	sleep(1);
+	kill(pid, SIGTERM);
+	safe_waitpid(pid);
+	close(pfd[0]);
+	close(pfd[1]);
+
+	for (i = 0; i < THREADS; i++) {
+		void *res;
+		error = pthread_join(thr[i], &res);
+		if (error)
+			err(1, "pthread_join");
+		FAIL((uintptr_t)res != 0);
+	}
+
+	SUCCEED;
+}
+
 struct test {
 	int (*testfn)(int, int, const char **);	/* function to perform the test */
 	int num;		/* test number */
@@ -1423,6 +1530,7 @@ struct test tests[] = {
 	{	test13,		13,	1	},
 	{	test14,		14,	0	},
 	{	test15,		15,	1	},
+	{	test16,		16,	1	},
 };
 int test_count = sizeof(tests) / sizeof(tests[0]);
 


More information about the svn-src-all mailing list