]> sourceware.org Git - glibc.git/commitdiff
nptl: Set sem_open as a non cancellation point (BZ #15765)
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Sat, 20 Aug 2016 14:23:08 +0000 (11:23 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Thu, 15 Sep 2016 14:14:25 +0000 (11:14 -0300)
This patch changes sem_open to not act as a cancellation point.
Cancellation is disable at start and reenable in function exit.
It fixes BZ #15765.

Tested on x86_64 and i686.

[BZ #15765]
* nptl/Makefile (tests): Add tst-sem16.
* nptl/tst-sem16.c: New file.
* nptl/sem_open.c (sem_open): Disable asynchronous cancellation.

ChangeLog
nptl/Makefile
nptl/sem_open.c
nptl/tst-sem16.c [new file with mode: 0644]

index 6ad743abface108ab5268fe692a53a8346eb80e2..1d3bc508803c53e6297d506fe25c727494e53ad2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2016-09-15  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
 
+       [BZ #15765]
+       * nptl/Makefile (tests): Add tst-sem16.
+       * nptl/tst-sem16.c: New file.
+       * nptl/sem_open.c (sem_open): Disable asynchronous cancellation.
+
        * nptl/sem_open.c (sem_open): Init pad value to 0.
        * sysdeps/sparc/sparc32/sem_open.c: Remove file.
        * sysdeps/sparc/sparc32/sparcv9/sem_open.c: Likewise.
index e8de1bc7e190ed6005e109b066a071540610bda5..e9485dfdb32b2062e7bcabefd0b5f5e541a185ca 100644 (file)
@@ -246,7 +246,7 @@ tests = tst-typesizes \
        tst-key1 tst-key2 tst-key3 tst-key4 \
        tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
        tst-sem8 tst-sem9 tst-sem10 tst-sem11 tst-sem12 tst-sem13 tst-sem14 \
-       tst-sem15 \
+       tst-sem15 tst-sem16 \
        tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 tst-barrier5 \
        tst-align tst-align3 \
        tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
index 5b45fadd719de88f4378bad10cc8cf514ce66cc5..d10828637a47cddb5250c7896ef23a831d64378e 100644 (file)
@@ -31,7 +31,7 @@
 #include "semaphoreP.h"
 #include <shm-directory.h>
 #include <futex-internal.h>
-
+#include <libc-lock.h>
 
 /* Comparison function for search of existing mapping.  */
 int
@@ -153,6 +153,13 @@ sem_open (const char *name, int oflag, ...)
   /* Create the name of the final file in local variable SHM_NAME.  */
   SHM_GET_NAME (EINVAL, SEM_FAILED, SEM_SHM_PREFIX);
 
+  /* Disable asynchronous cancellation.  */
+#ifdef __libc_ptf_call
+  int state;
+  __libc_ptf_call (__pthread_setcancelstate,
+                   (PTHREAD_CANCEL_DISABLE, &state), 0);
+#endif
+
   /* If the semaphore object has to exist simply open it.  */
   if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0)
     {
@@ -193,7 +200,8 @@ sem_open (const char *name, int oflag, ...)
       if (value > SEM_VALUE_MAX)
        {
          __set_errno (EINVAL);
-         return SEM_FAILED;
+         result = SEM_FAILED;
+         goto out;
        }
 
       /* Create the initial file content.  */
@@ -233,7 +241,10 @@ sem_open (const char *name, int oflag, ...)
             mode cannot later be set since then we cannot apply the
             file create mask.  */
          if (__mktemp (tmpfname) == NULL)
-           return SEM_FAILED;
+           {
+             result = SEM_FAILED;
+             goto out;
+           }
 
          /* Open the file.  Make sure we do not overwrite anything.  */
          fd = __libc_open (tmpfname, O_RDWR | O_CREAT | O_EXCL, mode);
@@ -247,7 +258,8 @@ sem_open (const char *name, int oflag, ...)
                  __set_errno (EAGAIN);
                }
 
-             return SEM_FAILED;
+             result = SEM_FAILED;
+             goto out;
            }
 
          /* We got a file.  */
@@ -308,5 +320,10 @@ sem_open (const char *name, int oflag, ...)
       errno = save;
     }
 
+out:
+#ifdef __libc_ptf_call
+  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
+#endif
+
   return result;
 }
diff --git a/nptl/tst-sem16.c b/nptl/tst-sem16.c
new file mode 100644 (file)
index 0000000..7006754
--- /dev/null
@@ -0,0 +1,130 @@
+/* Test for sem_open cancellation handling: BZ #15765.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <sys/mman.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static sem_t sem;      /* Use to sync with thread start.  */
+static const char pipe_name[] = "/glibc-tst-sem16";
+
+static void
+remove_sem (int status, void *arg)
+{
+  sem_unlink (arg);
+}
+
+static void *
+tf (void *arg)
+{
+  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, 0);
+
+  if (sem_wait (&sem) != 0)
+    {
+      printf ("error: sem_wait failed: %m");
+      exit (1);
+    }
+
+  if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0) != 0)
+    {
+      printf ("error: pthread_setcancelstate failed: %m");
+      exit (1);
+    }
+
+  /* Neither sem_unlink or sem_open should act on thread cancellation.  */
+  sem_unlink (pipe_name);
+  on_exit (remove_sem, (void *) pipe_name);
+
+  sem_t *s = sem_open (pipe_name, O_CREAT, 0600, 1);
+  if (s == SEM_FAILED)
+    {
+      int exit_code;
+      if (errno == ENOSYS || errno == EACCES)
+       exit_code = 77;
+      else
+       exit_code = 1;
+      exit (exit_code);
+    }
+
+  if (pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, 0) != 0)
+    {
+      printf ("error: pthread_setcancelstate failed: %m");
+      exit (1);
+    }
+
+  if (sem_close (s) != 0)
+    {
+      printf ("error: sem_close failed: %m");
+      exit (1);
+    }
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t td;
+
+  if (sem_init (&sem, 0, 0))
+    {
+      printf ("error: sem_init failed: %m\n");
+      exit (1);
+    }
+
+  if (pthread_create (&td, NULL, tf, NULL) != 0)
+    {
+      printf ("error: pthread_create failed: %m\n");
+      exit (1);
+    }
+
+  if (pthread_cancel (td) != 0)
+    {
+      printf ("error: pthread_cancel failed: %m\n");
+      exit (1);
+    }
+
+  if (sem_post (&sem) != 0)
+    {
+      printf ("error: sem_post failed: %m\n");
+      exit (1);
+    }
+
+  void *r;
+  if (pthread_join (td, &r) != 0)
+    {
+      printf ("error: pthread_join failed: %m\n");
+      exit (1);
+    }
+
+  if (r == PTHREAD_CANCELED)
+    {
+      puts ("error: pthread_join returned PTHREAD_CANCELED");
+      exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include <test-skeleton.c>
This page took 0.175051 seconds and 5 git commands to generate.