1/* testing pthread mutex behaviour with various attributes */
2#include <pthread.h>
3#include <semaphore.h>
4#include <stdio.h>
5#include <errno.h>
6#include <string.h>
7#include "test.h"
8
9#define T(f) if ((r=(f))) t_error(#f " failed: %s\n", strerror(r))
10#define E(f) if (f) t_error(#f " failed: %s\n", strerror(errno))
11
12static void *relock(void *arg)
13{
14	void **a = arg;
15	int r;
16
17	T(pthread_mutex_lock(a[0]));
18	E(sem_post(a[1]));
19	*(int*)a[2] = pthread_mutex_lock(a[0]);
20	E(sem_post(a[1]));
21
22	T(pthread_mutex_unlock(a[0]));
23	if (*(int*)a[2] == 0)
24		T(pthread_mutex_unlock(a[0]));
25	return 0;
26}
27
28static int test_relock(int mtype)
29{
30	struct timespec ts;
31	pthread_t t;
32	pthread_mutex_t m;
33	pthread_mutexattr_t ma;
34	sem_t s;
35	int i;
36	int r;
37	void *p;
38	void *a[] = {&m,&s,&i};
39
40	T(pthread_mutexattr_init(&ma));
41	T(pthread_mutexattr_settype(&ma, mtype));
42	T(pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT));
43	T(pthread_mutex_init(a[0], &ma));
44	T(pthread_mutexattr_destroy(&ma));
45	E(sem_init(a[1], 0, 0));
46	T(pthread_create(&t, 0, relock, a));
47	E(sem_wait(a[1]));
48	E(clock_gettime(CLOCK_REALTIME, &ts));
49	ts.tv_nsec += 100*1000*1000;
50	if (ts.tv_nsec >= 1000*1000*1000) {
51		ts.tv_nsec -= 1000*1000*1000;
52		ts.tv_sec += 1;
53	}
54	r = sem_timedwait(a[1],&ts);
55	if (r == -1) {
56		if (errno != ETIMEDOUT)
57			t_error("sem_timedwait failed with unexpected error: %s\n", strerror(errno));
58		/* leave the deadlocked relock thread running */
59		return -1;
60	}
61	T(pthread_join(t, &p));
62	T(pthread_mutex_destroy(a[0]));
63	E(sem_destroy(a[1]));
64	return i;
65}
66
67static void *unlock(void *arg)
68{
69	void **a = arg;
70
71	*(int*)a[1] = pthread_mutex_unlock(a[0]);
72	return 0;
73}
74
75static int test_unlock(int mtype)
76{
77	pthread_t t;
78	pthread_mutex_t m;
79	pthread_mutexattr_t ma;
80	int i;
81	int r;
82	void *p;
83	void *a[] = {&m,&i};
84
85	T(pthread_mutexattr_init(&ma));
86	T(pthread_mutexattr_settype(&ma, mtype));
87	T(pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT));
88	T(pthread_mutex_init(a[0], &ma));
89	T(pthread_mutexattr_destroy(&ma));
90	T(pthread_create(&t, 0, unlock, a));
91	T(pthread_join(t, &p));
92	T(pthread_mutex_destroy(a[0]));
93	return i;
94}
95
96static int test_unlock_other(int mtype)
97{
98	pthread_t t;
99	pthread_mutex_t m;
100	pthread_mutexattr_t ma;
101	int i;
102	int r;
103	void *p;
104	void *a[] = {&m,&i};
105
106	T(pthread_mutexattr_init(&ma));
107	T(pthread_mutexattr_settype(&ma, mtype));
108	T(pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT));
109	T(pthread_mutex_init(a[0], &ma));
110	T(pthread_mutexattr_destroy(&ma));
111	T(pthread_mutex_lock(a[0]));
112	T(pthread_create(&t, 0, unlock, a));
113	T(pthread_join(t, &p));
114	T(pthread_mutex_unlock(a[0]));
115	T(pthread_mutex_destroy(a[0]));
116	return i;
117}
118
119static void test_mutexattr()
120{
121	pthread_mutex_t m;
122	pthread_mutexattr_t a;
123	int r;
124	int i;
125
126	T(pthread_mutexattr_init(&a));
127	T(pthread_mutexattr_gettype(&a, &i));
128	if (i != PTHREAD_MUTEX_DEFAULT)
129		t_error("default mutex type is %d, wanted PTHREAD_MUTEX_DEFAULT (%d)\n", i, PTHREAD_MUTEX_DEFAULT);
130	T(pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK));
131	T(pthread_mutexattr_gettype(&a, &i));
132	if (i != PTHREAD_MUTEX_ERRORCHECK)
133		t_error("setting error check mutex type failed failed: got %d, wanted %d\n", i, PTHREAD_MUTEX_ERRORCHECK);
134	T(pthread_mutexattr_destroy(&a));
135}
136
137int main(void)
138{
139	int i;
140
141	test_mutexattr();
142
143	i = test_relock(PTHREAD_MUTEX_NORMAL);
144	if (i != -1)
145		t_error("PTHREAD_MUTEX_NORMAL relock did not deadlock, got %s\n", strerror(i));
146	i = test_relock(PTHREAD_MUTEX_ERRORCHECK);
147	if (i != EDEADLK)
148		t_error("PTHREAD_MUTEX_ERRORCHECK relock did not return EDEADLK, got %s\n", i==-1?"deadlock":strerror(i));
149	i = test_relock(PTHREAD_MUTEX_RECURSIVE);
150	if (i != 0)
151		t_error("PTHREAD_MUTEX_RECURSIVE relock did not succed, got %s\n", i==-1?"deadlock":strerror(i));
152
153	i = test_unlock(PTHREAD_MUTEX_ERRORCHECK);
154	if (i != EPERM)
155		t_error("PTHREAD_MUTEX_ERRORCHECK unlock did not return EPERM, got %s\n", strerror(i));
156	i = test_unlock(PTHREAD_MUTEX_RECURSIVE);
157	if (i != EPERM)
158		t_error("PTHREAD_MUTEX_RECURSIVE unlock did not return EPERM, got %s\n", strerror(i));
159
160	i = test_unlock_other(PTHREAD_MUTEX_ERRORCHECK);
161	if (i != EPERM)
162		t_error("PTHREAD_MUTEX_ERRORCHECK unlock did not return EPERM, got %s\n", strerror(i));
163	i = test_unlock_other(PTHREAD_MUTEX_RECURSIVE);
164	if (i != EPERM)
165		t_error("PTHREAD_MUTEX_RECURSIVE unlock did not return EPERM, got %s\n", strerror(i));
166
167	return t_status;
168}
169