1fc2512cfSRobert Mustacchi /*
2fc2512cfSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3fc2512cfSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4fc2512cfSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5fc2512cfSRobert Mustacchi  * 1.0 of the CDDL.
6fc2512cfSRobert Mustacchi  *
7fc2512cfSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8fc2512cfSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9fc2512cfSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10fc2512cfSRobert Mustacchi  */
11fc2512cfSRobert Mustacchi 
12fc2512cfSRobert Mustacchi /*
13cdcc9e2cSRobert Mustacchi  * Copyright 2017 Joyent, Inc.
14fc2512cfSRobert Mustacchi  */
15fc2512cfSRobert Mustacchi 
16fc2512cfSRobert Mustacchi #include <pthread.h>
17fc2512cfSRobert Mustacchi #include <thread.h>
18fc2512cfSRobert Mustacchi #include <synch.h>
19fc2512cfSRobert Mustacchi #include <threads.h>
20fc2512cfSRobert Mustacchi #include <errno.h>
21fc2512cfSRobert Mustacchi #include <unistd.h>
22fc2512cfSRobert Mustacchi #include <stdlib.h>
23fc2512cfSRobert Mustacchi 
24fc2512cfSRobert Mustacchi /*
25fc2512cfSRobert Mustacchi  * ISO/IEC C11 thread support.
26fc2512cfSRobert Mustacchi  *
27fc2512cfSRobert Mustacchi  * In illumos, the underlying implementation of lock related routines is the
28fc2512cfSRobert Mustacchi  * same between pthreads and traditional SunOS routines. The same is true with
29fc2512cfSRobert Mustacchi  * the C11 routines. Their types are actually just typedef's to other things.
30fc2512cfSRobert Mustacchi  * Thus in the implementation here, we treat this as a wrapper around existing
31fc2512cfSRobert Mustacchi  * thread related routines and don't sweet the extra indirection.
32fc2512cfSRobert Mustacchi  *
33fc2512cfSRobert Mustacchi  * Note that in many places the C standard doesn't allow for errors to be
34fc2512cfSRobert Mustacchi  * returned. In those cases, if we have an instance of programmer error
35fc2512cfSRobert Mustacchi  * (something resulting in EINVAL), we opt to abort the program as we don't have
36fc2512cfSRobert Mustacchi  * much other recourse available.
37fc2512cfSRobert Mustacchi  */
38fc2512cfSRobert Mustacchi 
39fc2512cfSRobert Mustacchi void
call_once(once_flag * flag,void (* func)(void))40fc2512cfSRobert Mustacchi call_once(once_flag *flag, void (*func)(void))
41fc2512cfSRobert Mustacchi {
42fc2512cfSRobert Mustacchi 	if (pthread_once(flag, func) != 0)
43fc2512cfSRobert Mustacchi 		abort();
44fc2512cfSRobert Mustacchi }
45fc2512cfSRobert Mustacchi 
46fc2512cfSRobert Mustacchi int
cnd_broadcast(cnd_t * cnd)47fc2512cfSRobert Mustacchi cnd_broadcast(cnd_t *cnd)
48fc2512cfSRobert Mustacchi {
49fc2512cfSRobert Mustacchi 	int ret;
50fc2512cfSRobert Mustacchi 
51fc2512cfSRobert Mustacchi 	ret = pthread_cond_broadcast(cnd);
52fc2512cfSRobert Mustacchi 	if (ret == 0)
53fc2512cfSRobert Mustacchi 		return (thrd_success);
54fc2512cfSRobert Mustacchi 	else
55fc2512cfSRobert Mustacchi 		return (thrd_error);
56fc2512cfSRobert Mustacchi }
57fc2512cfSRobert Mustacchi 
58fc2512cfSRobert Mustacchi void
cnd_destroy(cnd_t * cnd)59fc2512cfSRobert Mustacchi cnd_destroy(cnd_t *cnd)
60fc2512cfSRobert Mustacchi {
61fc2512cfSRobert Mustacchi 	if (pthread_cond_destroy(cnd) != 0)
62fc2512cfSRobert Mustacchi 		abort();
63fc2512cfSRobert Mustacchi }
64fc2512cfSRobert Mustacchi 
65fc2512cfSRobert Mustacchi int
cnd_init(cnd_t * cnd)66fc2512cfSRobert Mustacchi cnd_init(cnd_t *cnd)
67fc2512cfSRobert Mustacchi {
68fc2512cfSRobert Mustacchi 	int ret;
69fc2512cfSRobert Mustacchi 
70fc2512cfSRobert Mustacchi 	ret = pthread_cond_init(cnd, NULL);
71fc2512cfSRobert Mustacchi 	if (ret == 0)
72fc2512cfSRobert Mustacchi 		return (thrd_success);
73fc2512cfSRobert Mustacchi 	return (thrd_error);
74fc2512cfSRobert Mustacchi }
75fc2512cfSRobert Mustacchi 
76fc2512cfSRobert Mustacchi int
cnd_signal(cnd_t * cnd)77fc2512cfSRobert Mustacchi cnd_signal(cnd_t *cnd)
78fc2512cfSRobert Mustacchi {
79fc2512cfSRobert Mustacchi 	int ret;
80fc2512cfSRobert Mustacchi 
81fc2512cfSRobert Mustacchi 	ret = pthread_cond_signal(cnd);
82fc2512cfSRobert Mustacchi 	if (ret == 0)
83fc2512cfSRobert Mustacchi 		return (thrd_success);
84fc2512cfSRobert Mustacchi 	else
85fc2512cfSRobert Mustacchi 		return (thrd_error);
86fc2512cfSRobert Mustacchi }
87fc2512cfSRobert Mustacchi 
88fc2512cfSRobert Mustacchi /* ARGSUSED */
89fc2512cfSRobert Mustacchi int
cnd_timedwait(cnd_t * _RESTRICT_KYWD cnd,mtx_t * _RESTRICT_KYWD mtx,const struct timespec * _RESTRICT_KYWD ts)90fc2512cfSRobert Mustacchi cnd_timedwait(cnd_t *_RESTRICT_KYWD cnd, mtx_t *_RESTRICT_KYWD mtx,
91fc2512cfSRobert Mustacchi     const struct timespec *_RESTRICT_KYWD ts)
92fc2512cfSRobert Mustacchi {
93fc2512cfSRobert Mustacchi 	int ret;
94fc2512cfSRobert Mustacchi 
95fc2512cfSRobert Mustacchi 	ret = pthread_cond_timedwait(cnd, mtx, ts);
96fc2512cfSRobert Mustacchi 	if (ret == 0)
97fc2512cfSRobert Mustacchi 		return (thrd_success);
98fc2512cfSRobert Mustacchi 	if (ret == ETIMEDOUT)
99fc2512cfSRobert Mustacchi 		return (thrd_timedout);
100fc2512cfSRobert Mustacchi 	return (thrd_error);
101fc2512cfSRobert Mustacchi }
102fc2512cfSRobert Mustacchi 
103fc2512cfSRobert Mustacchi /* ARGSUSED */
104fc2512cfSRobert Mustacchi int
cnd_wait(cnd_t * cnd,mtx_t * mtx)105fc2512cfSRobert Mustacchi cnd_wait(cnd_t *cnd, mtx_t *mtx)
106fc2512cfSRobert Mustacchi {
107fc2512cfSRobert Mustacchi 	int ret;
108fc2512cfSRobert Mustacchi 
109fc2512cfSRobert Mustacchi 	ret = pthread_cond_wait(cnd, mtx);
110fc2512cfSRobert Mustacchi 	if (ret == 0)
111fc2512cfSRobert Mustacchi 		return (thrd_success);
112fc2512cfSRobert Mustacchi 	return (thrd_error);
113fc2512cfSRobert Mustacchi }
114fc2512cfSRobert Mustacchi 
115fc2512cfSRobert Mustacchi void
mtx_destroy(mtx_t * mtx)116fc2512cfSRobert Mustacchi mtx_destroy(mtx_t *mtx)
117fc2512cfSRobert Mustacchi {
118fc2512cfSRobert Mustacchi 	if (pthread_mutex_destroy(mtx) != 0)
119fc2512cfSRobert Mustacchi 		abort();
120fc2512cfSRobert Mustacchi }
121fc2512cfSRobert Mustacchi 
122fc2512cfSRobert Mustacchi int
mtx_init(mtx_t * mtx,int type)123fc2512cfSRobert Mustacchi mtx_init(mtx_t *mtx, int type)
124fc2512cfSRobert Mustacchi {
125fc2512cfSRobert Mustacchi 	int mtype;
126fc2512cfSRobert Mustacchi 
127fc2512cfSRobert Mustacchi 	switch (type) {
128fc2512cfSRobert Mustacchi 	case mtx_plain:
129fc2512cfSRobert Mustacchi 	case mtx_timed:
130fc2512cfSRobert Mustacchi 		mtype = USYNC_THREAD;
131fc2512cfSRobert Mustacchi 		break;
132fc2512cfSRobert Mustacchi 	case mtx_plain | mtx_recursive:
133fc2512cfSRobert Mustacchi 	case mtx_timed | mtx_recursive:
134fc2512cfSRobert Mustacchi 		mtype = USYNC_THREAD | LOCK_RECURSIVE;
135fc2512cfSRobert Mustacchi 		break;
136fc2512cfSRobert Mustacchi 	default:
137fc2512cfSRobert Mustacchi 		return (thrd_error);
138fc2512cfSRobert Mustacchi 	}
139fc2512cfSRobert Mustacchi 
140fc2512cfSRobert Mustacchi 	/*
141fc2512cfSRobert Mustacchi 	 * Here, we buck the trend and use the traditional SunOS routine. It's
142fc2512cfSRobert Mustacchi 	 * much simpler than fighting with pthread attributes.
143fc2512cfSRobert Mustacchi 	 */
144fc2512cfSRobert Mustacchi 	if (mutex_init((mutex_t *)mtx, mtype, NULL) == 0)
145fc2512cfSRobert Mustacchi 		return (thrd_success);
146fc2512cfSRobert Mustacchi 	return (thrd_error);
147fc2512cfSRobert Mustacchi }
148fc2512cfSRobert Mustacchi 
149fc2512cfSRobert Mustacchi int
mtx_lock(mtx_t * mtx)150fc2512cfSRobert Mustacchi mtx_lock(mtx_t *mtx)
151fc2512cfSRobert Mustacchi {
152fc2512cfSRobert Mustacchi 	if (pthread_mutex_lock(mtx) == 0)
153fc2512cfSRobert Mustacchi 		return (thrd_success);
154fc2512cfSRobert Mustacchi 	return (thrd_error);
155fc2512cfSRobert Mustacchi }
156fc2512cfSRobert Mustacchi 
157fc2512cfSRobert Mustacchi int
mtx_timedlock(mtx_t * _RESTRICT_KYWD mtx,const struct timespec * _RESTRICT_KYWD abstime)158fc2512cfSRobert Mustacchi mtx_timedlock(mtx_t *_RESTRICT_KYWD mtx,
159cdcc9e2cSRobert Mustacchi     const struct timespec *_RESTRICT_KYWD abstime)
160fc2512cfSRobert Mustacchi {
161fc2512cfSRobert Mustacchi 	int ret;
162fc2512cfSRobert Mustacchi 
163fc2512cfSRobert Mustacchi 	ret = pthread_mutex_timedlock(mtx, abstime);
164fc2512cfSRobert Mustacchi 	if (ret == ETIMEDOUT)
165fc2512cfSRobert Mustacchi 		return (thrd_timedout);
166fc2512cfSRobert Mustacchi 	else if (ret != 0)
167fc2512cfSRobert Mustacchi 		return (thrd_error);
168fc2512cfSRobert Mustacchi 	return (thrd_success);
169fc2512cfSRobert Mustacchi }
170fc2512cfSRobert Mustacchi 
171fc2512cfSRobert Mustacchi int
mtx_trylock(mtx_t * mtx)172fc2512cfSRobert Mustacchi mtx_trylock(mtx_t *mtx)
173fc2512cfSRobert Mustacchi {
174fc2512cfSRobert Mustacchi 	int ret;
175fc2512cfSRobert Mustacchi 
176fc2512cfSRobert Mustacchi 	ret = pthread_mutex_trylock(mtx);
177fc2512cfSRobert Mustacchi 	if (ret == 0)
178fc2512cfSRobert Mustacchi 		return (thrd_success);
179fc2512cfSRobert Mustacchi 	else if (ret == EBUSY)
180fc2512cfSRobert Mustacchi 		return (thrd_busy);
181fc2512cfSRobert Mustacchi 	else
182fc2512cfSRobert Mustacchi 		return (thrd_error);
183fc2512cfSRobert Mustacchi }
184fc2512cfSRobert Mustacchi 
185fc2512cfSRobert Mustacchi int
mtx_unlock(mtx_t * mtx)186fc2512cfSRobert Mustacchi mtx_unlock(mtx_t *mtx)
187fc2512cfSRobert Mustacchi {
188fc2512cfSRobert Mustacchi 	if (pthread_mutex_unlock(mtx) == 0)
189fc2512cfSRobert Mustacchi 		return (thrd_success);
190fc2512cfSRobert Mustacchi 	return (thrd_error);
191fc2512cfSRobert Mustacchi }
192fc2512cfSRobert Mustacchi 
193fc2512cfSRobert Mustacchi int
thrd_create(thrd_t * thr,thrd_start_t func,void * arg)194fc2512cfSRobert Mustacchi thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
195fc2512cfSRobert Mustacchi {
196fc2512cfSRobert Mustacchi 	int ret;
197fc2512cfSRobert Mustacchi 
198*adc04c2dSToomas Soome 	ret = pthread_create(thr, NULL,
199*adc04c2dSToomas Soome 	    (void *(*)(void *))(uintptr_t)func, arg);
200fc2512cfSRobert Mustacchi 	if (ret == 0)
201fc2512cfSRobert Mustacchi 		return (thrd_success);
202fc2512cfSRobert Mustacchi 	else if (ret == -1 && errno == EAGAIN)
203fc2512cfSRobert Mustacchi 		return (thrd_nomem);
204fc2512cfSRobert Mustacchi 	else
205fc2512cfSRobert Mustacchi 		return (thrd_error);
206fc2512cfSRobert Mustacchi }
207fc2512cfSRobert Mustacchi 
208fc2512cfSRobert Mustacchi thrd_t
thrd_current(void)209fc2512cfSRobert Mustacchi thrd_current(void)
210fc2512cfSRobert Mustacchi {
211fc2512cfSRobert Mustacchi 	return (pthread_self());
212fc2512cfSRobert Mustacchi }
213fc2512cfSRobert Mustacchi 
214fc2512cfSRobert Mustacchi int
thrd_detach(thrd_t thr)215fc2512cfSRobert Mustacchi thrd_detach(thrd_t thr)
216fc2512cfSRobert Mustacchi {
217fc2512cfSRobert Mustacchi 	if (pthread_detach(thr) == 0)
218fc2512cfSRobert Mustacchi 		return (thrd_success);
219fc2512cfSRobert Mustacchi 	return (thrd_error);
220fc2512cfSRobert Mustacchi }
221fc2512cfSRobert Mustacchi 
222fc2512cfSRobert Mustacchi int
thrd_equal(thrd_t t1,thrd_t t2)223fc2512cfSRobert Mustacchi thrd_equal(thrd_t t1, thrd_t t2)
224fc2512cfSRobert Mustacchi {
225cdcc9e2cSRobert Mustacchi 	return (pthread_equal(t1, t2));
226fc2512cfSRobert Mustacchi }
227fc2512cfSRobert Mustacchi 
228fc2512cfSRobert Mustacchi _NORETURN_KYWD void
thrd_exit(int res)229fc2512cfSRobert Mustacchi thrd_exit(int res)
230fc2512cfSRobert Mustacchi {
231fc2512cfSRobert Mustacchi 	pthread_exit((void *)(uintptr_t)res);
232fc2512cfSRobert Mustacchi }
233fc2512cfSRobert Mustacchi 
234fc2512cfSRobert Mustacchi int
thrd_join(thrd_t thrd,int * res)235fc2512cfSRobert Mustacchi thrd_join(thrd_t thrd, int *res)
236fc2512cfSRobert Mustacchi {
237fc2512cfSRobert Mustacchi 	void *es;
238fc2512cfSRobert Mustacchi 
239fc2512cfSRobert Mustacchi 	if (pthread_join(thrd, &es) != 0)
240fc2512cfSRobert Mustacchi 		return (thrd_error);
241fc2512cfSRobert Mustacchi 	if (res != NULL)
242fc2512cfSRobert Mustacchi 		*res = (uintptr_t)es;
243fc2512cfSRobert Mustacchi 	return (thrd_success);
244fc2512cfSRobert Mustacchi }
245fc2512cfSRobert Mustacchi 
246fc2512cfSRobert Mustacchi /*
247fc2512cfSRobert Mustacchi  * thrd_sleep has somewhat odd standardized return values. It doesn't use the
248fc2512cfSRobert Mustacchi  * same returns values as the thrd_* family of functions at all.
249fc2512cfSRobert Mustacchi  */
250fc2512cfSRobert Mustacchi int
thrd_sleep(const struct timespec * rqtp,struct timespec * rmtp)251fc2512cfSRobert Mustacchi thrd_sleep(const struct timespec *rqtp, struct timespec *rmtp)
252fc2512cfSRobert Mustacchi {
253fc2512cfSRobert Mustacchi 	int ret;
254fc2512cfSRobert Mustacchi 	if ((ret = nanosleep(rqtp, rmtp)) == 0)
255fc2512cfSRobert Mustacchi 		return (0);
256fc2512cfSRobert Mustacchi 	if (ret == -1 && errno == EINTR)
257fc2512cfSRobert Mustacchi 		return (-1);
258fc2512cfSRobert Mustacchi 	return (-2);
259fc2512cfSRobert Mustacchi }
260fc2512cfSRobert Mustacchi 
261fc2512cfSRobert Mustacchi void
thrd_yield(void)262fc2512cfSRobert Mustacchi thrd_yield(void)
263fc2512cfSRobert Mustacchi {
264fc2512cfSRobert Mustacchi 	thr_yield();
265fc2512cfSRobert Mustacchi }
266fc2512cfSRobert Mustacchi 
267fc2512cfSRobert Mustacchi int
tss_create(tss_t * key,tss_dtor_t dtor)268fc2512cfSRobert Mustacchi tss_create(tss_t *key, tss_dtor_t dtor)
269fc2512cfSRobert Mustacchi {
270fc2512cfSRobert Mustacchi 	if (pthread_key_create(key, dtor) == 0)
271fc2512cfSRobert Mustacchi 		return (thrd_success);
272fc2512cfSRobert Mustacchi 	return (thrd_error);
273fc2512cfSRobert Mustacchi }
274fc2512cfSRobert Mustacchi 
275fc2512cfSRobert Mustacchi void
tss_delete(tss_t key)276fc2512cfSRobert Mustacchi tss_delete(tss_t key)
277fc2512cfSRobert Mustacchi {
278fc2512cfSRobert Mustacchi 	if (pthread_key_delete(key) != 0)
279fc2512cfSRobert Mustacchi 		abort();
280fc2512cfSRobert Mustacchi }
281fc2512cfSRobert Mustacchi 
282fc2512cfSRobert Mustacchi void *
tss_get(tss_t key)283fc2512cfSRobert Mustacchi tss_get(tss_t key)
284fc2512cfSRobert Mustacchi {
285fc2512cfSRobert Mustacchi 	return (pthread_getspecific(key));
286fc2512cfSRobert Mustacchi }
287fc2512cfSRobert Mustacchi 
288fc2512cfSRobert Mustacchi int
tss_set(tss_t key,void * val)289fc2512cfSRobert Mustacchi tss_set(tss_t key, void *val)
290fc2512cfSRobert Mustacchi {
291fc2512cfSRobert Mustacchi 	if (pthread_setspecific(key, val) == 0)
292fc2512cfSRobert Mustacchi 		return (thrd_success);
293fc2512cfSRobert Mustacchi 	return (thrd_error);
294fc2512cfSRobert Mustacchi }
295