1570af302Sopenharmony_ci/* testing pthread mutex behaviour with various attributes */
2570af302Sopenharmony_ci#include <pthread.h>
3570af302Sopenharmony_ci#include <semaphore.h>
4570af302Sopenharmony_ci#include <stdio.h>
5570af302Sopenharmony_ci#include <errno.h>
6570af302Sopenharmony_ci#include <string.h>
7570af302Sopenharmony_ci#include "test.h"
8570af302Sopenharmony_ci
9570af302Sopenharmony_ci#define T(f) if ((r=(f))) t_error(#f " failed: %s\n", strerror(r))
10570af302Sopenharmony_ci#define E(f) if (f) t_error(#f " failed: %s\n", strerror(errno))
11570af302Sopenharmony_ci
12570af302Sopenharmony_cistatic void *relock(void *arg)
13570af302Sopenharmony_ci{
14570af302Sopenharmony_ci	void **a = arg;
15570af302Sopenharmony_ci	int r;
16570af302Sopenharmony_ci
17570af302Sopenharmony_ci	T(pthread_mutex_lock(a[0]));
18570af302Sopenharmony_ci	E(sem_post(a[1]));
19570af302Sopenharmony_ci	*(int*)a[2] = pthread_mutex_lock(a[0]);
20570af302Sopenharmony_ci	E(sem_post(a[1]));
21570af302Sopenharmony_ci
22570af302Sopenharmony_ci	T(pthread_mutex_unlock(a[0]));
23570af302Sopenharmony_ci	if (*(int*)a[2] == 0)
24570af302Sopenharmony_ci		T(pthread_mutex_unlock(a[0]));
25570af302Sopenharmony_ci	return 0;
26570af302Sopenharmony_ci}
27570af302Sopenharmony_ci
28570af302Sopenharmony_cistatic int test_relock(int mtype)
29570af302Sopenharmony_ci{
30570af302Sopenharmony_ci	struct timespec ts;
31570af302Sopenharmony_ci	pthread_t t;
32570af302Sopenharmony_ci	pthread_mutex_t m;
33570af302Sopenharmony_ci	pthread_mutexattr_t ma;
34570af302Sopenharmony_ci	sem_t s;
35570af302Sopenharmony_ci	int i;
36570af302Sopenharmony_ci	int r;
37570af302Sopenharmony_ci	void *p;
38570af302Sopenharmony_ci	void *a[] = {&m,&s,&i};
39570af302Sopenharmony_ci
40570af302Sopenharmony_ci	T(pthread_mutexattr_init(&ma));
41570af302Sopenharmony_ci	T(pthread_mutexattr_settype(&ma, mtype));
42570af302Sopenharmony_ci	T(pthread_mutex_init(a[0], &ma));
43570af302Sopenharmony_ci	T(pthread_mutexattr_destroy(&ma));
44570af302Sopenharmony_ci	E(sem_init(a[1], 0, 0));
45570af302Sopenharmony_ci	T(pthread_create(&t, 0, relock, a));
46570af302Sopenharmony_ci	E(sem_wait(a[1]));
47570af302Sopenharmony_ci	E(clock_gettime(CLOCK_REALTIME, &ts));
48570af302Sopenharmony_ci	ts.tv_nsec += 100*1000*1000;
49570af302Sopenharmony_ci	if (ts.tv_nsec >= 1000*1000*1000) {
50570af302Sopenharmony_ci		ts.tv_nsec -= 1000*1000*1000;
51570af302Sopenharmony_ci		ts.tv_sec += 1;
52570af302Sopenharmony_ci	}
53570af302Sopenharmony_ci	r = sem_timedwait(a[1],&ts);
54570af302Sopenharmony_ci	if (r == -1) {
55570af302Sopenharmony_ci		if (errno != ETIMEDOUT)
56570af302Sopenharmony_ci			t_error("sem_timedwait failed with unexpected error: %s\n", strerror(errno));
57570af302Sopenharmony_ci		/* leave the deadlocked relock thread running */
58570af302Sopenharmony_ci		return -1;
59570af302Sopenharmony_ci	}
60570af302Sopenharmony_ci	T(pthread_join(t, &p));
61570af302Sopenharmony_ci	T(pthread_mutex_destroy(a[0]));
62570af302Sopenharmony_ci	E(sem_destroy(a[1]));
63570af302Sopenharmony_ci	return i;
64570af302Sopenharmony_ci}
65570af302Sopenharmony_ci
66570af302Sopenharmony_cistatic void *unlock(void *arg)
67570af302Sopenharmony_ci{
68570af302Sopenharmony_ci	void **a = arg;
69570af302Sopenharmony_ci
70570af302Sopenharmony_ci	*(int*)a[1] = pthread_mutex_unlock(a[0]);
71570af302Sopenharmony_ci	return 0;
72570af302Sopenharmony_ci}
73570af302Sopenharmony_ci
74570af302Sopenharmony_cistatic int test_unlock(int mtype)
75570af302Sopenharmony_ci{
76570af302Sopenharmony_ci	pthread_t t;
77570af302Sopenharmony_ci	pthread_mutex_t m;
78570af302Sopenharmony_ci	pthread_mutexattr_t ma;
79570af302Sopenharmony_ci	int i;
80570af302Sopenharmony_ci	int r;
81570af302Sopenharmony_ci	void *p;
82570af302Sopenharmony_ci	void *a[] = {&m,&i};
83570af302Sopenharmony_ci
84570af302Sopenharmony_ci	T(pthread_mutexattr_init(&ma));
85570af302Sopenharmony_ci	T(pthread_mutexattr_settype(&ma, mtype));
86570af302Sopenharmony_ci	T(pthread_mutex_init(a[0], &ma));
87570af302Sopenharmony_ci	T(pthread_mutexattr_destroy(&ma));
88570af302Sopenharmony_ci	T(pthread_create(&t, 0, unlock, a));
89570af302Sopenharmony_ci	T(pthread_join(t, &p));
90570af302Sopenharmony_ci	T(pthread_mutex_destroy(a[0]));
91570af302Sopenharmony_ci	return i;
92570af302Sopenharmony_ci}
93570af302Sopenharmony_ci
94570af302Sopenharmony_cistatic int test_unlock_other(int mtype)
95570af302Sopenharmony_ci{
96570af302Sopenharmony_ci	pthread_t t;
97570af302Sopenharmony_ci	pthread_mutex_t m;
98570af302Sopenharmony_ci	pthread_mutexattr_t ma;
99570af302Sopenharmony_ci	int i;
100570af302Sopenharmony_ci	int r;
101570af302Sopenharmony_ci	void *p;
102570af302Sopenharmony_ci	void *a[] = {&m,&i};
103570af302Sopenharmony_ci
104570af302Sopenharmony_ci	T(pthread_mutexattr_init(&ma));
105570af302Sopenharmony_ci	T(pthread_mutexattr_settype(&ma, mtype));
106570af302Sopenharmony_ci	T(pthread_mutex_init(a[0], &ma));
107570af302Sopenharmony_ci	T(pthread_mutexattr_destroy(&ma));
108570af302Sopenharmony_ci	T(pthread_mutex_lock(a[0]));
109570af302Sopenharmony_ci	T(pthread_create(&t, 0, unlock, a));
110570af302Sopenharmony_ci	T(pthread_join(t, &p));
111570af302Sopenharmony_ci	T(pthread_mutex_unlock(a[0]));
112570af302Sopenharmony_ci	T(pthread_mutex_destroy(a[0]));
113570af302Sopenharmony_ci	return i;
114570af302Sopenharmony_ci}
115570af302Sopenharmony_ci
116570af302Sopenharmony_cistatic void test_mutexattr()
117570af302Sopenharmony_ci{
118570af302Sopenharmony_ci	pthread_mutex_t m;
119570af302Sopenharmony_ci	pthread_mutexattr_t a;
120570af302Sopenharmony_ci	int r;
121570af302Sopenharmony_ci	int i;
122570af302Sopenharmony_ci
123570af302Sopenharmony_ci	T(pthread_mutexattr_init(&a));
124570af302Sopenharmony_ci	T(pthread_mutexattr_gettype(&a, &i));
125570af302Sopenharmony_ci	if (i != PTHREAD_MUTEX_DEFAULT)
126570af302Sopenharmony_ci		t_error("default mutex type is %d, wanted PTHREAD_MUTEX_DEFAULT (%d)\n", i, PTHREAD_MUTEX_DEFAULT);
127570af302Sopenharmony_ci	T(pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK));
128570af302Sopenharmony_ci	T(pthread_mutexattr_gettype(&a, &i));
129570af302Sopenharmony_ci	if (i != PTHREAD_MUTEX_ERRORCHECK)
130570af302Sopenharmony_ci		t_error("setting error check mutex type failed failed: got %d, wanted %d\n", i, PTHREAD_MUTEX_ERRORCHECK);
131570af302Sopenharmony_ci	T(pthread_mutexattr_destroy(&a));
132570af302Sopenharmony_ci}
133570af302Sopenharmony_ci
134570af302Sopenharmony_ciint main(void)
135570af302Sopenharmony_ci{
136570af302Sopenharmony_ci	int i;
137570af302Sopenharmony_ci
138570af302Sopenharmony_ci	test_mutexattr();
139570af302Sopenharmony_ci
140570af302Sopenharmony_ci	i = test_relock(PTHREAD_MUTEX_NORMAL);
141570af302Sopenharmony_ci	if (i != -1)
142570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_NORMAL relock did not deadlock, got %s\n", strerror(i));
143570af302Sopenharmony_ci	i = test_relock(PTHREAD_MUTEX_ERRORCHECK);
144570af302Sopenharmony_ci	if (i != EDEADLK)
145570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_ERRORCHECK relock did not return EDEADLK, got %s\n", i==-1?"deadlock":strerror(i));
146570af302Sopenharmony_ci	i = test_relock(PTHREAD_MUTEX_RECURSIVE);
147570af302Sopenharmony_ci	if (i != 0)
148570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_RECURSIVE relock did not succed, got %s\n", i==-1?"deadlock":strerror(i));
149570af302Sopenharmony_ci
150570af302Sopenharmony_ci	i = test_unlock(PTHREAD_MUTEX_ERRORCHECK);
151570af302Sopenharmony_ci	if (i != EPERM)
152570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_ERRORCHECK unlock did not return EPERM, got %s\n", strerror(i));
153570af302Sopenharmony_ci	i = test_unlock(PTHREAD_MUTEX_RECURSIVE);
154570af302Sopenharmony_ci	if (i != EPERM)
155570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_RECURSIVE unlock did not return EPERM, got %s\n", strerror(i));
156570af302Sopenharmony_ci
157570af302Sopenharmony_ci	i = test_unlock_other(PTHREAD_MUTEX_ERRORCHECK);
158570af302Sopenharmony_ci	if (i != EPERM)
159570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_ERRORCHECK unlock did not return EPERM, got %s\n", strerror(i));
160570af302Sopenharmony_ci	i = test_unlock_other(PTHREAD_MUTEX_RECURSIVE);
161570af302Sopenharmony_ci	if (i != EPERM)
162570af302Sopenharmony_ci		t_error("PTHREAD_MUTEX_RECURSIVE unlock did not return EPERM, got %s\n", strerror(i));
163570af302Sopenharmony_ci
164570af302Sopenharmony_ci	return t_status;
165570af302Sopenharmony_ci}
166