4 Copyright (C) Amitay Isaacs 2016
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 * Run this test as follows:
23 * 1. Running all processes at normal priority
25 * $ while true ; do ./bin/test_mutex_raw /tmp/foo 10 0 ; done
27 * 2. Running all processes at real-time priority
29 * # while true ; do ./bin/test_mutex_raw /tmp/foo 10 1 ; done
31 * The test will block after few iterations. At this time none of the
32 * child processes is holding the mutex.
34 * To check which process is holding a lock:
36 * $ ./bin/test_mutex_raw /tmp/foo debug
38 * If no pid is printed, then no process is holding the mutex.
44 #include <sys/types.h>
45 #include <sys/fcntl.h>
55 int pthread_mutex_consistent_np(pthread_mutex_t *);
57 static void set_realtime(void)
64 ret = sched_setscheduler(0, SCHED_FIFO, &p);
66 fprintf(stderr, "Failed to set scheduler to SCHED_FIFO\n");
70 static void high_priority(void)
76 fprintf(stderr, "Failed to set high priority\n");
80 static void run_child(const char *filename)
82 pthread_mutex_t *mutex;
86 fd = open(filename, O_RDWR, 0600);
91 addr = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE,
92 MAP_SHARED|MAP_FILE, fd, 0);
97 mutex = (pthread_mutex_t *)addr;
100 ret = pthread_mutex_lock(mutex);
101 if (ret == EOWNERDEAD) {
102 ret = pthread_mutex_consistent_np(mutex);
103 } else if (ret == EAGAIN) {
107 fprintf(stderr, "pid %u lock failed, ret=%d\n", getpid(), ret);
111 fprintf(stderr, "pid %u locked\n", getpid());
112 kill(getpid(), SIGKILL);
115 #define PRIO_NORMAL 0
116 #define PRIO_REALTIME 1
117 #define PRIO_NICE_20 2
119 int main(int argc, const char **argv)
121 pthread_mutexattr_t ma;
122 pthread_mutex_t *mutex;
127 int priority = PRIO_NORMAL;
129 if (argc < 3 || argc > 4) {
130 fprintf(stderr, "Usage: %s <file> <n> [0|1|2]\n", argv[0]);
131 fprintf(stderr, " %s <file> debug\n", argv[0]);
136 priority = atoi(argv[3]);
139 if (priority == PRIO_REALTIME) {
141 } else if (priority == PRIO_NICE_20) {
145 fd = open(argv[1], O_CREAT|O_RDWR, 0600);
147 fprintf(stderr, "open failed\n");
151 ret = lseek(fd, 0, SEEK_SET);
153 fprintf(stderr, "lseek failed\n");
157 ret = ftruncate(fd, sizeof(pthread_mutex_t));
159 fprintf(stderr, "ftruncate failed\n");
163 addr = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE,
164 MAP_SHARED|MAP_FILE, fd, 0);
166 fprintf(stderr, "mmap failed\n");
170 mutex = (pthread_mutex_t *)addr;
172 if (strcmp(argv[2], "debug") == 0) {
173 ret = pthread_mutex_trylock(mutex);
174 if (ret == EOWNERDEAD) {
175 ret = pthread_mutex_consistent_np(mutex);
177 pthread_mutex_unlock(mutex);
179 } else if (ret == EBUSY) {
180 printf("pid=%u\n", mutex->__data.__owner);
181 } else if (ret == 0) {
182 pthread_mutex_unlock(mutex);
187 ret = pthread_mutexattr_init(&ma);
189 fprintf(stderr, "pthread_mutexattr_init failed\n");
193 ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
195 fprintf(stderr, "pthread_mutexattr_settype failed\n");
199 ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED);
201 fprintf(stderr, "pthread_mutexattr_setpshared failed\n");
205 ret = pthread_mutexattr_setrobust(&ma, PTHREAD_MUTEX_ROBUST);
207 fprintf(stderr, "pthread_mutexattr_setrobust failed\n");
211 ret = pthread_mutex_init(mutex, &ma);
213 fprintf(stderr, "pthread_mutex_init failed\n");
217 ret = pthread_mutex_lock(mutex);
219 fprintf(stderr, "pthread_mutex_lock failed\n");
225 fprintf(stderr, "Creating children\n");
226 num_children = atoi(argv[2]);
228 for (i=0; i<num_children; i++) {
231 fprintf(stderr, "fork() failed\n");
241 fprintf(stderr, "Waiting for children\n");
243 ret = pthread_mutex_unlock(mutex);
245 fprintf(stderr, "pthread_mutex_unlock failed\n");
249 for (i=0; i<num_children; i++) {
252 pid = waitpid(-1, &status, 0);
254 fprintf(stderr, "waitpid() failed\n");