2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2017 Joyent, Inc.
25 * ISO/IEC C11 thread support.
27 * In illumos, the underlying implementation of lock related routines is the
28 * same between pthreads and traditional SunOS routines. The same is true with
29 * the C11 routines. Their types are actually just typedef's to other things.
30 * Thus in the implementation here, we treat this as a wrapper around existing
31 * thread related routines and don't sweet the extra indirection.
33 * Note that in many places the C standard doesn't allow for errors to be
34 * returned. In those cases, if we have an instance of programmer error
35 * (something resulting in EINVAL), we opt to abort the program as we don't have
36 * much other recourse available.
40 call_once(once_flag
*flag
, void (*func
)(void))
42 if (pthread_once(flag
, func
) != 0)
47 cnd_broadcast(cnd_t
*cnd
)
51 ret
= pthread_cond_broadcast(cnd
);
53 return (thrd_success
);
59 cnd_destroy(cnd_t
*cnd
)
61 if (pthread_cond_destroy(cnd
) != 0)
70 ret
= pthread_cond_init(cnd
, NULL
);
72 return (thrd_success
);
77 cnd_signal(cnd_t
*cnd
)
81 ret
= pthread_cond_signal(cnd
);
83 return (thrd_success
);
90 cnd_timedwait(cnd_t
*_RESTRICT_KYWD cnd
, mtx_t
*_RESTRICT_KYWD mtx
,
91 const struct timespec
*_RESTRICT_KYWD ts
)
95 ret
= pthread_cond_timedwait(cnd
, mtx
, ts
);
97 return (thrd_success
);
99 return (thrd_timedout
);
105 cnd_wait(cnd_t
*cnd
, mtx_t
*mtx
)
109 ret
= pthread_cond_wait(cnd
, mtx
);
111 return (thrd_success
);
116 mtx_destroy(mtx_t
*mtx
)
118 if (pthread_mutex_destroy(mtx
) != 0)
123 mtx_init(mtx_t
*mtx
, int type
)
130 mtype
= USYNC_THREAD
;
132 case mtx_plain
| mtx_recursive
:
133 case mtx_timed
| mtx_recursive
:
134 mtype
= USYNC_THREAD
| LOCK_RECURSIVE
;
141 * Here, we buck the trend and use the traditional SunOS routine. It's
142 * much simpler than fighting with pthread attributes.
144 if (mutex_init((mutex_t
*)mtx
, mtype
, NULL
) == 0)
145 return (thrd_success
);
152 if (pthread_mutex_lock(mtx
) == 0)
153 return (thrd_success
);
158 mtx_timedlock(mtx_t
*_RESTRICT_KYWD mtx
,
159 const struct timespec
*_RESTRICT_KYWD abstime
)
163 ret
= pthread_mutex_timedlock(mtx
, abstime
);
164 if (ret
== ETIMEDOUT
)
165 return (thrd_timedout
);
168 return (thrd_success
);
172 mtx_trylock(mtx_t
*mtx
)
176 ret
= pthread_mutex_trylock(mtx
);
178 return (thrd_success
);
179 else if (ret
== EBUSY
)
186 mtx_unlock(mtx_t
*mtx
)
188 if (pthread_mutex_unlock(mtx
) == 0)
189 return (thrd_success
);
194 thrd_create(thrd_t
*thr
, thrd_start_t func
, void *arg
)
198 ret
= pthread_create(thr
, NULL
, (void *(*)(void *))func
, arg
);
200 return (thrd_success
);
201 else if (ret
== -1 && errno
== EAGAIN
)
210 return (pthread_self());
214 thrd_detach(thrd_t thr
)
216 if (pthread_detach(thr
) == 0)
217 return (thrd_success
);
222 thrd_equal(thrd_t t1
, thrd_t t2
)
224 return (pthread_equal(t1
, t2
));
230 pthread_exit((void *)(uintptr_t)res
);
234 thrd_join(thrd_t thrd
, int *res
)
238 if (pthread_join(thrd
, &es
) != 0)
241 *res
= (uintptr_t)es
;
242 return (thrd_success
);
246 * thrd_sleep has somewhat odd standardized return values. It doesn't use the
247 * same returns values as the thrd_* family of functions at all.
250 thrd_sleep(const struct timespec
*rqtp
, struct timespec
*rmtp
)
253 if ((ret
= nanosleep(rqtp
, rmtp
)) == 0)
255 if (ret
== -1 && errno
== EINTR
)
267 tss_create(tss_t
*key
, tss_dtor_t dtor
)
269 if (pthread_key_create(key
, dtor
) == 0)
270 return (thrd_success
);
275 tss_delete(tss_t key
)
277 if (pthread_key_delete(key
) != 0)
284 return (pthread_getspecific(key
));
288 tss_set(tss_t key
, void *val
)
290 if (pthread_setspecific(key
, val
) == 0)
291 return (thrd_success
);