1570af302Sopenharmony_ci#include <pthread.h>
2570af302Sopenharmony_ci#include <string.h>
3570af302Sopenharmony_ci#include <errno.h>
4570af302Sopenharmony_ci#include "test.h"
5570af302Sopenharmony_ci
6570af302Sopenharmony_ci#define TEST(r, f, m) ( \
7570af302Sopenharmony_ci	((r) = (f)) == 0 || (t_error("%s failed: (pshared==%d, pi==%d) %s (" m ")\n", #f, pshared, pi, strerror(r)), 0) )
8570af302Sopenharmony_ci#define TESTX(r, f, x, m) ( \
9570af302Sopenharmony_ci	((r) = (f)) == (x) || (t_error("%s failed: (pshared==%d, pi==%d) got %d \"%s\" want %d \"%s\" (" m ")\n", #f, pshared, pi, r, strerror(r), x, strerror(x)), 0) )
10570af302Sopenharmony_ci
11570af302Sopenharmony_cistatic void *start_lock(void *arg)
12570af302Sopenharmony_ci{
13570af302Sopenharmony_ci	pthread_mutex_lock(arg);
14570af302Sopenharmony_ci	return 0;
15570af302Sopenharmony_ci}
16570af302Sopenharmony_ci
17570af302Sopenharmony_cistatic void *start_wait(void *arg)
18570af302Sopenharmony_ci{
19570af302Sopenharmony_ci	void **args = arg;
20570af302Sopenharmony_ci	pthread_mutex_lock(args[1]);
21570af302Sopenharmony_ci	pthread_barrier_wait(args[0]);
22570af302Sopenharmony_ci	nanosleep(&(struct timespec){ .tv_nsec = 10000000 }, 0);
23570af302Sopenharmony_ci	return 0;
24570af302Sopenharmony_ci}
25570af302Sopenharmony_ci
26570af302Sopenharmony_civoid f(int pshared, int pi)
27570af302Sopenharmony_ci{
28570af302Sopenharmony_ci	pthread_t td;
29570af302Sopenharmony_ci	int r;
30570af302Sopenharmony_ci	void *res;
31570af302Sopenharmony_ci	pthread_barrier_t barrier2;
32570af302Sopenharmony_ci	pthread_mutexattr_t mtx_a;
33570af302Sopenharmony_ci	pthread_mutex_t mtx;
34570af302Sopenharmony_ci
35570af302Sopenharmony_ci	TEST(r, pthread_barrier_init(&barrier2, 0, 2), "creating barrier");
36570af302Sopenharmony_ci
37570af302Sopenharmony_ci	/* Robust mutexes */
38570af302Sopenharmony_ci	TEST(r, pthread_mutexattr_init(&mtx_a), "initializing mutex attr");
39570af302Sopenharmony_ci	TEST(r, pthread_mutexattr_setrobust(&mtx_a, PTHREAD_MUTEX_ROBUST), "setting robust attribute");
40570af302Sopenharmony_ci	if (pshared)
41570af302Sopenharmony_ci		TEST(r, pthread_mutexattr_setpshared(&mtx_a, PTHREAD_PROCESS_SHARED), "setting pshared attribute");
42570af302Sopenharmony_ci	if (pi)
43570af302Sopenharmony_ci		TEST(r, pthread_mutexattr_setprotocol(&mtx_a, PTHREAD_PRIO_INHERIT), "setting PI attribute");
44570af302Sopenharmony_ci	TEST(r, pthread_mutex_init(&mtx, &mtx_a), "initializing robust mutex");
45570af302Sopenharmony_ci	TEST(r, pthread_mutex_lock(&mtx), "locking robust mutex");
46570af302Sopenharmony_ci	TEST(r, pthread_mutex_unlock(&mtx), "unlocking robust mutex");
47570af302Sopenharmony_ci	TEST(r, pthread_create(&td, 0, start_lock, &mtx), "failed to create thread");
48570af302Sopenharmony_ci	TEST(r, pthread_join(td, &res), "joining thread");
49570af302Sopenharmony_ci	TESTX(r, pthread_mutex_lock(&mtx), EOWNERDEAD, "locking orphaned robust mutex");
50570af302Sopenharmony_ci	TEST(r, pthread_mutex_unlock(&mtx), "unlocking orphaned robust mutex");
51570af302Sopenharmony_ci	TESTX(r, pthread_mutex_lock(&mtx), ENOTRECOVERABLE, "re-locking orphaned robust mutex");
52570af302Sopenharmony_ci	TEST(r, pthread_mutex_destroy(&mtx), "destroying unrecoverable mutex");
53570af302Sopenharmony_ci
54570af302Sopenharmony_ci	TEST(r, pthread_mutex_init(&mtx, &mtx_a), "initializing robust mutex");
55570af302Sopenharmony_ci	TEST(r, pthread_create(&td, 0, start_lock, &mtx), "failed to create thread");
56570af302Sopenharmony_ci	TEST(r, pthread_join(td, &res), "joining thread");
57570af302Sopenharmony_ci	TESTX(r, pthread_mutex_lock(&mtx), EOWNERDEAD, "locking orphaned robust mutex");
58570af302Sopenharmony_ci	TEST(r, pthread_mutex_consistent(&mtx), "");
59570af302Sopenharmony_ci	TEST(r, pthread_mutex_unlock(&mtx), "unlocking orphaned robust mutex");
60570af302Sopenharmony_ci	TEST(r, pthread_mutex_lock(&mtx), "re-locking orphaned robust mutex");
61570af302Sopenharmony_ci	TEST(r, pthread_mutex_destroy(&mtx), "destroying mutex");
62570af302Sopenharmony_ci
63570af302Sopenharmony_ci	TEST(r, pthread_mutex_init(&mtx, &mtx_a), "");
64570af302Sopenharmony_ci	TEST(r, pthread_create(&td, 0, start_wait, (void *[]){ &barrier2, &mtx }), "");
65570af302Sopenharmony_ci	r = pthread_barrier_wait(&barrier2);
66570af302Sopenharmony_ci	if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
67570af302Sopenharmony_ci		t_error("pthread_barrier_wait failed: got %d \"%s\", wanted either 0 or %d\n",
68570af302Sopenharmony_ci			r, strerror(r), PTHREAD_BARRIER_SERIAL_THREAD);
69570af302Sopenharmony_ci	TEST(r, pthread_barrier_destroy(&barrier2), "");
70570af302Sopenharmony_ci	TESTX(r, pthread_mutex_lock(&mtx), EOWNERDEAD, "");
71570af302Sopenharmony_ci	TEST(r, pthread_join(td, &res), "");
72570af302Sopenharmony_ci	TEST(r, pthread_mutex_consistent(&mtx), "");
73570af302Sopenharmony_ci	TEST(r, pthread_mutex_unlock(&mtx), "");
74570af302Sopenharmony_ci	TEST(r, pthread_mutex_destroy(&mtx), "");
75570af302Sopenharmony_ci}
76570af302Sopenharmony_ci
77570af302Sopenharmony_ciint main(void)
78570af302Sopenharmony_ci{
79570af302Sopenharmony_ci	for (int pshared=0; pshared<=1; pshared++)
80570af302Sopenharmony_ci		for (int pi=0; pi<=1; pi++)
81570af302Sopenharmony_ci			f(pshared, pi);
82570af302Sopenharmony_ci	return t_status;
83570af302Sopenharmony_ci}
84