nptl: Add POSIX-proposed pthread_mutex_clocklock
[external/glibc.git] / nptl / tst-mutex9.c
1 /* Copyright (C) 2003-2019 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <pthread.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/mman.h>
27 #include <sys/time.h>
28 #include <sys/wait.h>
29 #include <support/check.h>
30 #include <support/timespec.h>
31 #include <support/xunistd.h>
32
33
34 /* A bogus clock value that tells run_test to use pthread_mutex_timedlock
35    rather than pthread_mutex_clocklock.  */
36 #define CLOCK_USE_TIMEDLOCK (-1)
37
38 static void
39 do_test_clock (clockid_t clockid)
40 {
41   const clockid_t clockid_for_get =
42     (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
43   size_t ps = sysconf (_SC_PAGESIZE);
44   char tmpfname[] = "/tmp/tst-mutex9.XXXXXX";
45   char data[ps];
46   void *mem;
47   int fd;
48   pthread_mutex_t *m;
49   pthread_mutexattr_t a;
50   pid_t pid;
51
52   fd = mkstemp (tmpfname);
53   if (fd == -1)
54       FAIL_EXIT1 ("cannot open temporary file: %m\n");
55
56   /* Make sure it is always removed.  */
57   unlink (tmpfname);
58
59   /* Create one page of data.  */
60   memset (data, '\0', ps);
61
62   /* Write the data to the file.  */
63   xwrite (fd, data, ps);
64
65   mem = xmmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd);
66
67   m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t))
68                            & ~(__alignof (pthread_mutex_t) - 1));
69
70   TEST_COMPARE (pthread_mutexattr_init (&a), 0);
71
72   TEST_COMPARE (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED), 0);
73
74   TEST_COMPARE (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE), 0);
75
76 #ifdef ENABLE_PI
77   TEST_COMPARE (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT), 0);
78 #endif
79
80   int e;
81   if ((e = pthread_mutex_init (m, &a)) != 0)
82     {
83 #ifdef ENABLE_PI
84       if (e == ENOTSUP)
85         FAIL_UNSUPPORTED ("PI mutexes unsupported");
86 #endif
87       FAIL_EXIT1 ("mutex_init failed");
88     }
89
90   TEST_COMPARE (pthread_mutex_lock (m), 0);
91
92   TEST_COMPARE (pthread_mutexattr_destroy (&a), 0);
93
94   puts ("going to fork now");
95   pid = xfork ();
96   if (pid == 0)
97     {
98       if (pthread_mutex_trylock (m) == 0)
99         FAIL_EXIT1 ("child: mutex_trylock succeeded");
100
101       if (pthread_mutex_unlock (m) == 0)
102         FAIL_EXIT1 ("child: mutex_unlock succeeded");
103
104       const struct timespec ts = timespec_add (xclock_now (clockid_for_get),
105                                                make_timespec (0, 500000000));
106
107       if (clockid == CLOCK_USE_TIMEDLOCK)
108         TEST_COMPARE (pthread_mutex_timedlock (m, &ts), ETIMEDOUT);
109       else
110         TEST_COMPARE (pthread_mutex_clocklock (m, clockid, &ts), ETIMEDOUT);
111
112       alarm (1);
113
114       pthread_mutex_lock (m);
115
116       puts ("child: mutex_lock returned");
117
118       exit (0);
119     }
120
121   sleep (2);
122
123   int status;
124   if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
125     FAIL_EXIT1 ("waitpid failed");
126   if (! WIFSIGNALED (status))
127     FAIL_EXIT1 ("child not killed by signal");
128   TEST_COMPARE (WTERMSIG (status), SIGALRM);
129 }
130
131 static int
132 do_test (void)
133 {
134   do_test_clock (CLOCK_USE_TIMEDLOCK);
135   do_test_clock (CLOCK_REALTIME);
136   do_test_clock (CLOCK_MONOTONIC);
137   return 0;
138 }
139
140 #include <support/test-driver.c>