From fc6f0665bae406f564e6eb6e1deea849d368a708 Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Mon, 26 Dec 2011 21:51:53 +0000 Subject: [PATCH] Add libstdthreads. This library implements the C11 threads interface on top of the pthreads library. As discussed on the lists, the preferred way to implement this, is as a separate library. It is unlikely that these functions will be used a lot in the future. It would have been easier if the C11 working group standardized (a subset of) pthreads and clock_nanosleep(). Having it as a separate library allows the embedded people to omit it from their system. Discussed on: arch@, threads@ --- contrib/groff/tmac/doc-syms | 1 + contrib/groff/tmac/groff_mdoc.man | 2 + lib/Makefile | 1 + lib/libstdthreads/Makefile | 41 +++++ lib/libstdthreads/Symbol.map | 31 ++++ lib/libstdthreads/call_once.c | 44 +++++ lib/libstdthreads/cnd.c | 98 +++++++++++ lib/libstdthreads/mtx.c | 116 +++++++++++++ lib/libstdthreads/thrd.c | 127 +++++++++++++++ lib/libstdthreads/thrd_create.3 | 260 ++++++++++++++++++++++++++++++ lib/libstdthreads/threads.h | 106 ++++++++++++ lib/libstdthreads/tss.c | 69 ++++++++ 12 files changed, 896 insertions(+) create mode 100644 lib/libstdthreads/Makefile create mode 100644 lib/libstdthreads/Symbol.map create mode 100644 lib/libstdthreads/call_once.c create mode 100644 lib/libstdthreads/cnd.c create mode 100644 lib/libstdthreads/mtx.c create mode 100644 lib/libstdthreads/thrd.c create mode 100644 lib/libstdthreads/thrd_create.3 create mode 100644 lib/libstdthreads/threads.h create mode 100644 lib/libstdthreads/tss.c diff --git a/contrib/groff/tmac/doc-syms b/contrib/groff/tmac/doc-syms index 00731469c9c9..72846d406f1a 100644 --- a/contrib/groff/tmac/doc-syms +++ b/contrib/groff/tmac/doc-syms @@ -814,6 +814,7 @@ .ds doc-str-Lb-librt \*[Px] \*[doc-str-Lb]Real-time Library (librt, \-lrt) .ds doc-str-Lb-libsdp Bluetooth Service Discovery Protocol User Library (libsdp, \-lsdp) .ds doc-str-Lb-libssp Buffer Overflow Protection Library (libssp, \-lssp) +.ds doc-str-Lb-libstdthreads C11 Threads Library (libstdthreads, \-lstdthreads) .ds doc-str-Lb-libSystem System Library (libSystem, \-lSystem) .ds doc-str-Lb-libtermcap Termcap Access Library (libtermcap, \-ltermcap) .ds doc-str-Lb-libterminfo Terminal Information Library (libterminfo, \-lterminfo) diff --git a/contrib/groff/tmac/groff_mdoc.man b/contrib/groff/tmac/groff_mdoc.man index 136745db94da..305a0417df44 100644 --- a/contrib/groff/tmac/groff_mdoc.man +++ b/contrib/groff/tmac/groff_mdoc.man @@ -1797,6 +1797,8 @@ and their results are: .Lb libsdp .It Li libssp .Lb libssp +.It Li libstdthreads +.Lb libstdthreads .It Li libSystem .Lb libSystem .It Li libtermcap diff --git a/lib/Makefile b/lib/Makefile index ad647ec5457b..d01fa47823d2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -101,6 +101,7 @@ SUBDIR= ${SUBDIR_ORDERED} \ ${_libsmdb} \ ${_libsmutil} \ libstand \ + libstdthreads \ ${_libtelnet} \ ${_libthr} \ libthread_db \ diff --git a/lib/libstdthreads/Makefile b/lib/libstdthreads/Makefile new file mode 100644 index 000000000000..544eeb0f12f1 --- /dev/null +++ b/lib/libstdthreads/Makefile @@ -0,0 +1,41 @@ +# $FreeBSD$ + +LIB= stdthreads +SHLIB_MAJOR= 0 + +INCS= threads.h +SRCS= threads.h call_once.c cnd.c mtx.c thrd.c tss.c + +MAN= thrd_create.3 +MLINKS= thrd_create.3 call_once.3 \ + thrd_create.3 cnd_broadcast.3 \ + thrd_create.3 cnd_destroy.3 \ + thrd_create.3 cnd_init.3 \ + thrd_create.3 cnd_signal.3 \ + thrd_create.3 cnd_timedwait.3 \ + thrd_create.3 cnd_wait.3 \ + thrd_create.3 mtx_destroy.3 \ + thrd_create.3 mtx_init.3 \ + thrd_create.3 mtx_lock.3 \ + thrd_create.3 mtx_timedlock.3 \ + thrd_create.3 mtx_trylock.3 \ + thrd_create.3 mtx_unlock.3 \ + thrd_create.3 thrd_current.3 \ + thrd_create.3 thrd_detach.3 \ + thrd_create.3 thrd_equal.3 \ + thrd_create.3 thrd_exit.3 \ + thrd_create.3 thrd_join.3 \ + thrd_create.3 thrd_sleep.3 \ + thrd_create.3 thrd_yield.3 \ + thrd_create.3 tss_create.3 \ + thrd_create.3 tss_delete.3 \ + thrd_create.3 tss_get.3 \ + thrd_create.3 tss_set.3 + +DPADD= ${LIBPTHREAD} +LDADD= -lpthread + +VERSION_DEF= ${.CURDIR}/../libc/Versions.def +SYMBOL_MAPS= ${.CURDIR}/Symbol.map + +.include diff --git a/lib/libstdthreads/Symbol.map b/lib/libstdthreads/Symbol.map new file mode 100644 index 000000000000..0fe6eacda4e4 --- /dev/null +++ b/lib/libstdthreads/Symbol.map @@ -0,0 +1,31 @@ +/* + * $FreeBSD$ + */ + +FBSD_1.3 { + call_once; + cnd_broadcast; + cnd_destroy; + cnd_init; + cnd_signal; + cnd_timedwait; + cnd_wait; + mtx_destroy; + mtx_init; + mtx_lock; + mtx_timedlock; + mtx_trylock; + mtx_unlock; + thrd_create; + thrd_current; + thrd_detach; + thrd_equal; + thrd_exit; + thrd_join; + thrd_sleep; + thrd_yield; + tss_create; + tss_delete; + tss_get; + tss_set; +}; diff --git a/lib/libstdthreads/call_once.c b/lib/libstdthreads/call_once.c new file mode 100644 index 000000000000..70ce8de1e991 --- /dev/null +++ b/lib/libstdthreads/call_once.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "threads.h" + +void +call_once(once_flag *flag, void (*func)(void)) +{ + + (void)pthread_once((pthread_once_t *)flag, func); +} + +_Static_assert(sizeof(once_flag) == sizeof(pthread_once_t), + "once_flag must be of the same size as pthread_once_t"); diff --git a/lib/libstdthreads/cnd.c b/lib/libstdthreads/cnd.c new file mode 100644 index 000000000000..145960df84ba --- /dev/null +++ b/lib/libstdthreads/cnd.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "threads.h" + +int +cnd_broadcast(cnd_t *cond) +{ + + if (pthread_cond_broadcast(cond) != 0) + return (thrd_error); + return (thrd_success); +} + +void +cnd_destroy(cnd_t *cond) +{ + + (void)pthread_cond_destroy(cond); +} + +int +cnd_init(cnd_t *cond) +{ + + switch (pthread_cond_init(cond, NULL)) { + case 0: + return (thrd_success); + case ENOMEM: + return (thrd_nomem); + default: + return (thrd_error); + } +} + +int +cnd_signal(cnd_t *cond) +{ + + if (pthread_cond_signal(cond) != 0) + return (thrd_error); + return (thrd_success); +} + +int +cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, + const struct timespec *restrict ts) +{ + + switch (pthread_cond_timedwait(cond, mtx, ts)) { + case 0: + return (thrd_success); + case ETIMEDOUT: + return (thrd_timedout); + default: + return (thrd_error); + } +} + +int +cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + + if (pthread_cond_wait(cond, mtx) != 0) + return (thrd_error); + return (thrd_success); +} diff --git a/lib/libstdthreads/mtx.c b/lib/libstdthreads/mtx.c new file mode 100644 index 000000000000..6c9166da71b4 --- /dev/null +++ b/lib/libstdthreads/mtx.c @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "threads.h" + +void +mtx_destroy(mtx_t *mtx) +{ + + (void)pthread_mutex_destroy(mtx); +} + +int +mtx_init(mtx_t *mtx, int type) +{ + pthread_mutexattr_t attr; + int mt; + + switch (type) { + case mtx_plain: + case mtx_timed: + mt = PTHREAD_MUTEX_NORMAL; + break; + case mtx_plain | mtx_recursive: + case mtx_timed | mtx_recursive: + mt = PTHREAD_MUTEX_RECURSIVE; + break; + default: + return (thrd_error); + } + + if (pthread_mutexattr_init(&attr) != 0) + return (thrd_error); + if (pthread_mutexattr_settype(&attr, mt) != 0) + return (thrd_error); + if (pthread_mutex_init(mtx, &attr) != 0) + return (thrd_error); + return (thrd_success); +} + +int +mtx_lock(mtx_t *mtx) +{ + + if (pthread_mutex_lock(mtx) != 0) + return (thrd_error); + return (thrd_success); +} + +int +mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts) +{ + + switch (pthread_mutex_timedlock(mtx, ts)) { + case 0: + return (thrd_success); + case ETIMEDOUT: + return (thrd_timedout); + default: + return (thrd_error); + } +} + +int +mtx_trylock(mtx_t *mtx) +{ + + switch (pthread_mutex_lock(mtx)) { + case 0: + return (thrd_success); + case EBUSY: + return (thrd_busy); + default: + return (thrd_error); + } +} + +int +mtx_unlock(mtx_t *mtx) +{ + + if (pthread_mutex_unlock(mtx) != 0) + return (thrd_error); + return (thrd_success); +} diff --git a/lib/libstdthreads/thrd.c b/lib/libstdthreads/thrd.c new file mode 100644 index 000000000000..f0ce55a567c4 --- /dev/null +++ b/lib/libstdthreads/thrd.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "threads.h" + +struct thrd_param { + thrd_start_t func; + void *arg; +}; + +static void * +thrd_entry(void *arg) +{ + struct thrd_param tp; + + tp = *(struct thrd_param *)arg; + free(arg); + return ((void *)(intptr_t)tp.func(tp.arg)); +} + +int +thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + struct thrd_param *tp; + + /* + * Work around return type inconsistency. Wrap execution using + * a function conforming to pthread_create()'s start_routine. + */ + tp = malloc(sizeof(*tp)); + if (tp == NULL) + return (thrd_nomem); + tp->func = func; + tp->arg = arg; + if (pthread_create(thr, NULL, thrd_entry, tp) != 0) { + free(tp); + return (thrd_error); + } + return (thrd_success); +} + +thrd_t +thrd_current(void) +{ + + return (pthread_self()); +} + +int +thrd_detach(thrd_t thr) +{ + + if (pthread_detach(thr) != 0) + return (thrd_error); + return (thrd_success); +} + +int +thrd_equal(thrd_t thr0, thrd_t thr1) +{ + + return (pthread_equal(thr0, thr1)); +} + +_Noreturn void +thrd_exit(int res) +{ + + pthread_exit((void *)(intptr_t)res); +} + +int +thrd_join(thrd_t thr, int *res) +{ + void *value_ptr; + + if (pthread_join(thr, &value_ptr) != 0) + return (thrd_error); + *res = (intptr_t)value_ptr; + return (thrd_success); +} + +int +thrd_sleep(const struct timespec *duration, struct timespec *remaining) +{ + + return (nanosleep(duration, remaining)); +} + +void +thrd_yield(void) +{ + + pthread_yield(); +} diff --git a/lib/libstdthreads/thrd_create.3 b/lib/libstdthreads/thrd_create.3 new file mode 100644 index 000000000000..ede0d7f2d8fd --- /dev/null +++ b/lib/libstdthreads/thrd_create.3 @@ -0,0 +1,260 @@ +.\" Copyright (c) 2011 Ed Schouten +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd December 26, 2011 +.Dt THRD_CREATE 3 +.Os +.Sh NAME +.Nm call_once , +.Nm cnd_broadcast , +.Nm cnd_destroy , +.Nm cnd_init , +.Nm cnd_signal , +.Nm cnd_timedwait , +.Nm cnd_wait , +.Nm mtx_destroy , +.Nm mtx_init , +.Nm mtx_lock , +.Nm mtx_timedlock , +.Nm mtx_trylock , +.Nm mtx_unlock , +.Nm thrd_create , +.Nm thrd_current , +.Nm thrd_detach , +.Nm thrd_equal , +.Nm thrd_exit , +.Nm thrd_join , +.Nm thrd_sleep , +.Nm thrd_yield , +.Nm tss_create , +.Nm tss_delete , +.Nm tss_get , +.Nm tss_set +.Nd C11 threads interface +.Sh LIBRARY +.Lb libstdthreads +.Sh SYNOPSIS +.In threads.h +.Ft void +.Fn call_once "once_flag *flag" "void (*func)(void)" +.Ft int +.Fn cnd_broadcast "cnd_t *cond" +.Ft void +.Fn cnd_destroy "cnd_t *cond" +.Ft int +.Fn cnd_init "cnd_t *cond" +.Ft int +.Fn cnd_signal "cnd_t *cond" +.Ft int +.Fn cnd_timedwait "cnd_t * restrict cond" "mtx_t * restrict mtx" "const struct timespec * restrict ts" +.Ft int +.Fn cnd_wait "cnd_t *cond" "mtx_t *mtx" +.Ft void +.Fn mtx_destroy "mtx_t *mtx" +.Ft int +.Fn mtx_init "mtx_t *mtx" "int type" +.Ft int +.Fn mtx_lock "mtx_t *mtx" +.Ft int +.Fn mtx_timedlock "mtx_t * restrict mtx" "const struct timespec * restrict ts" +.Ft int +.Fn mtx_trylock "mtx_t *mtx" +.Ft int +.Fn mtx_unlock "mtx_t *mtx" +.Ft int +.Fn thrd_create "thrd_t *thr" "int (*func)(void *)" "void *arg" +.Ft thrd_t +.Fn thrd_current "void" +.Ft int +.Fn thrd_detach "thrd_t thr" +.Ft int +.Fn thrd_equal "thrd_t thr0" "thrd_t thr1" +.Ft _Noreturn void +.Fn thrd_exit "int res" +.Ft int +.Fn thrd_join "thrd_t thr" "int *res" +.Ft int +.Fn thrd_sleep "const struct timespec *duration" "struct timespec *remaining" +.Ft void +.Fn thrd_yield "void" +.Ft int +.Fn tss_create "tss_t *key" "void (*dtor)(void *)" +.Ft void +.Fn tss_delete "tss_t key" +.Ft void * +.Fn tss_get "tss_t key" +.Ft int +.Fn tss_set "tss_t key" "void *val" +.Sh DESCRIPTION +As of +.St -isoC-11 , +the C standard includes an API for writing multithreaded applications. +Since POSIX.1 already includes a threading API that is used by virtually +any multithreaded application, the interface provided by the C standard +can be considered superfluous. +.Pp +In this implementation, the threading interface is therefore implemented +as a light-weight layer on top of existing interfaces. +The functions to which these routines are mapped, are listed in the +following table. +Please refer to the documentation of the POSIX equivalent functions for +more information. +.Bl -column ".Fn mtx_timedlock" ".Xr pthread_mutex_timedlock 3" -offset indent +.It Em Function Ta Em POSIX equivalent +.It Fn call_once Ta Xr pthread_once 3 +.It Fn cnd_broadcast Ta Xr pthread_cond_broadcast 3 +.It Fn cnd_destroy Ta Xr pthread_cond_destroy 3 +.It Fn cnd_init Ta Xr pthread_cond_init 3 +.It Fn cnd_signal Ta Xr pthread_cond_signal 3 +.It Fn cnd_timedwait Ta Xr pthread_cond_timedwait 3 +.It Fn cnd_wait Ta Xr pthread_cond_wait 3 +.It Fn mtx_destroy Ta Xr pthread_mutex_destroy 3 +.It Fn mtx_init Ta Xr pthread_mutex_init 3 +.It Fn mtx_lock Ta Xr pthread_mutex_lock 3 +.It Fn mtx_timedlock Ta Xr pthread_mutex_timedlock 3 +.It Fn mtx_trylock Ta Xr pthread_mutex_trylock 3 +.It Fn mtx_unlock Ta Xr pthread_mutex_unlock 3 +.It Fn thrd_create Ta Xr pthread_create 3 +.It Fn thrd_current Ta Xr pthread_self 3 +.It Fn thrd_detach Ta Xr pthread_detach 3 +.It Fn thrd_equal Ta Xr pthread_equal 3 +.It Fn thrd_exit Ta Xr pthread_exit 3 +.It Fn thrd_join Ta Xr pthread_join 3 +.It Fn thrd_sleep Ta Xr nanosleep 2 +.It Fn thrd_yield Ta Xr pthread_yield 3 +.It Fn tss_create Ta Xr pthread_key_create 3 +.It Fn tss_delete Ta Xr pthread_key_delete 3 +.It Fn tss_get Ta Xr pthread_getspecific 3 +.It Fn tss_set Ta Xr pthread_setspecific 3 +.El +.Sh DIFFERENCES WITH POSIX EQUIVALENTS +The +.Fn thrd_exit +function returns an integer value to the thread calling +.Fn thrd_join , +whereas the +.Fn pthread_exit +function uses a pointer. +.Pp +The mutex created by +.Fn mtx_init +can be of +.Fa type +.Dv mtx_plain +or +.Dv mtx_timed +to distinguish between a mutex that supports +.Fn mtx_timedlock . +This type can be +.Em or'd +with +.Dv mtx_recursive +to create a mutex that allows recursive acquisition. +These properties are normally set using +.Fn pthread_mutex_init Ns 's +.Fa attr +parameter. +.Sh RETURN VALUES +If successful, the +.Fn cnd_broadcast , +.Fn cnd_init , +.Fn cnd_signal , +.Fn cnd_timedwait , +.Fn cnd_wait , +.Fn mtx_init , +.Fn mtx_lock , +.Fn mtx_timedlock , +.Fn mtx_trylock , +.Fn mtx_unlock , +.Fn thrd_create , +.Fn thrd_detach , +.Fn thrd_equal , +.Fn thrd_join , +.Fn thrd_sleep , +.Fn tss_create +and +.Fn tss_set +functions return +.Dv thrd_success . +Otherwise an error code will be returned to indicate the error. +.Pp +The +.Fn thrd_current +function returns the thread ID of the calling thread. +.Pp +The +.Fn tss_get +function returns the thread-specific data value associated with the +given +.Fa key . +If no thread-specific data value is associated with +.Fa key , +then the value NULL is returned. +.Sh ERRORS +The +.Fn cnd_init +and +.Fn thrd_create +functions will fail if: +.Bl -tag -width thrd_timedout +.It Dv thrd_nomem +The system has insufficient memory. +.El +.Pp +The +.Fn cnd_timedwait +and +.Fn mtx_timedlock +functions will fail if: +.Bl -tag -width thrd_timedout +.It Dv thrd_timedout +The system time has reached or exceeded the time specified in +.Fa ts +before the operation could be completed. +.El +.Pp +The +.Fn mtx_trylock +function will fail if: +.Bl -tag -width thrd_timedout +.It Dv thrd_busy +The mutex is already locked. +.El +.Pp +In all other cases, these functions may fail by returning general error +code +.Dv thrd_error . +.Sh SEE ALSO +.Xr nanosleep 2 , +.Xr pthread 3 +.Sh STANDARDS +These functions are expected to conform to +.St -isoC-11 . +.Sh HISTORY +These functions appeared in +.Fx 10.0 . +.Sh AUTHORS +.An Ed Schouten Aq ed@FreeBSD.org diff --git a/lib/libstdthreads/threads.h b/lib/libstdthreads/threads.h new file mode 100644 index 000000000000..aba9ca13df3c --- /dev/null +++ b/lib/libstdthreads/threads.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _THREADS_H_ +#define _THREADS_H_ + +#include + +/* + * The C11 threads interface. + * + * This interface is implemented as a light-weight wrapper around + * . To prevent namespace pollution, the once_flag object, + * its corresponding ONCE_FLAG_INIT and TSS_DTOR_ITERATIONS have been + * copied from this header file. They must be kept in sync. + */ + +typedef struct pthread_cond *cnd_t; +typedef struct pthread_mutex *mtx_t; +typedef struct pthread *thrd_t; +typedef int tss_t; + +typedef struct { + int __state; + mtx_t __mutex; +} once_flag; + +typedef void (*tss_dtor_t)(void *); +typedef int (*thrd_start_t)(void *); + +enum { + mtx_plain = 0x1, + mtx_recursive = 0x2, + mtx_timed = 0x4 +}; + +enum { + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_success = 4, + thrd_timedout = 5 +}; + +#if !defined(__cplusplus) || __cplusplus < 201103L +#define thread_local _Thread_local +#endif +#define ONCE_FLAG_INIT { 0, NULL } +#define TSS_DTOR_ITERATIONS 4 + +__BEGIN_DECLS +void call_once(once_flag *, void (*)(void)); +int cnd_broadcast(cnd_t *); +void cnd_destroy(cnd_t *); +int cnd_init(cnd_t *); +int cnd_signal(cnd_t *); +int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict, + const struct timespec *__restrict); +int cnd_wait(cnd_t *, mtx_t *); +void mtx_destroy(mtx_t *); +int mtx_init(mtx_t *, int); +int mtx_lock(mtx_t *); +int mtx_timedlock(mtx_t *__restrict, const struct timespec *__restrict); +int mtx_trylock(mtx_t *); +int mtx_unlock(mtx_t *); +int thrd_create(thrd_t *, thrd_start_t, void *); +thrd_t thrd_current(void); +int thrd_detach(thrd_t); +int thrd_equal(thrd_t, thrd_t); +_Noreturn void + thrd_exit(int); +int thrd_join(thrd_t, int *); +int thrd_sleep(const struct timespec *, struct timespec *); +void thrd_yield(void); +int tss_create(tss_t *, tss_dtor_t); +void tss_delete(tss_t); +void * tss_get(tss_t); +int tss_set(tss_t, void *); +__END_DECLS + +#endif /* !_THREADS_H_ */ diff --git a/lib/libstdthreads/tss.c b/lib/libstdthreads/tss.c new file mode 100644 index 000000000000..ef78b4bd41f1 --- /dev/null +++ b/lib/libstdthreads/tss.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "threads.h" + +int +tss_create(tss_t *key, tss_dtor_t dtor) +{ + + if (pthread_key_create(key, dtor) != 0) + return (thrd_error); + return (thrd_success); +} + +void +tss_delete(tss_t key) +{ + + (void)pthread_key_delete(key); +} + +void * +tss_get(tss_t key) +{ + + return (pthread_getspecific(key)); +} + +int +tss_set(tss_t key, void *val) +{ + + if (pthread_setspecific(key, val) != 0) + return (thrd_error); + return (thrd_success); +} + +_Static_assert(TSS_DTOR_ITERATIONS == PTHREAD_DESTRUCTOR_ITERATIONS, + "TSS_DTOR_ITERATIONS must be identical to PTHREAD_DESTRUCTOR_ITERATIONS");