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]);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to