From bdd35de71298fada56724f1fb07d4b9e864eb2c9 Mon Sep 17 00:00:00 2001 From: Dominic Martinez Date: Mon, 18 Apr 2022 10:17:01 -0400 Subject: [PATCH] libroot: Add support for C11 threads (except gcc2). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some programs use C11 threads instead of POSIX threads, so this change implements a light wrapper around POSIX threads that conforms to the C11 spec. This code was primarily taken from FreeBSD, with minor modifications: - The header file was trimmed to only include functions in the C11 spec, and changed to match the format of other Haiku header files - The thrd_yield function was implemented with its POSIX equivalent sched_yield instead of the non-standard pthread_yield - The thrd_create function was changed to return thrd_busy on an EAGAIN error code instead of unconditionally returning thrd_error The respective files can be found in the FreeBSD source tree at: - lib/libstdthreads/threads.h - lib/libstdthreads/thrd.c TODO: - untested (is a unit test in order?) Change-Id: I422f96f4854cd686f9637fc2e98cb03ce06a764a Reviewed-on: https://review.haiku-os.org/c/haiku/+/5213 Reviewed-by: Jérôme Duval Tested-by: Commit checker robot --- headers/posix/stdc-predef.h | 14 ---- headers/posix/threads.h | 71 ++++++++++++++++ src/system/libroot/posix/Jamfile | 9 ++ src/system/libroot/posix/threads.c | 129 +++++++++++++++++++++++++++++ 4 files changed, 209 insertions(+), 14 deletions(-) delete mode 100644 headers/posix/stdc-predef.h create mode 100644 headers/posix/threads.h create mode 100644 src/system/libroot/posix/threads.c diff --git a/headers/posix/stdc-predef.h b/headers/posix/stdc-predef.h deleted file mode 100644 index fc51da35d7..0000000000 --- a/headers/posix/stdc-predef.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2021 Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - */ -#ifndef _STDC_PREDEF_H -#define _STDC_PREDEF_H - - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -# define __STDC_NO_THREADS__ 1 -#endif - - -#endif /* _STDC_PREDEF_H */ diff --git a/headers/posix/threads.h b/headers/posix/threads.h new file mode 100644 index 0000000000..3d8c9c1d17 --- /dev/null +++ b/headers/posix/threads.h @@ -0,0 +1,71 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2011 Ed Schouten + * Copyright (c) 2022 Dominic Martinez + * 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$ + */ + +#if __GNUC__ > 2 /* not available on gcc2 */ + +#ifndef _THREADS_H_ +#define _THREADS_H_ + +#include +#include + +typedef pthread_t thrd_t; +typedef int (*thrd_start_t)(void *); + +enum { + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_success = 4, + thrd_timedout = 5 +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int thrd_create(thrd_t *thread, 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); + +#ifdef __cplusplus +} +#endif + +#endif /* _THREADS_H_ */ + +#endif /* __GNUC__ > 2 */ diff --git a/src/system/libroot/posix/Jamfile b/src/system/libroot/posix/Jamfile index 568e09073e..90446f4ef2 100644 --- a/src/system/libroot/posix/Jamfile +++ b/src/system/libroot/posix/Jamfile @@ -17,6 +17,14 @@ for architectureObject in [ MultiArchSubDirSetup ] { } else { PWD_BACKEND = pwd.cpp grp.cpp shadow.cpp user_group_common.cpp ; } + + + local threadsLib = threads.c ; + if $(HAIKU_CC_IS_LEGACY_GCC_$(architecture)) = 1 { + # the threads library is not available on gcc2 + threadsLib = ; + } + MergeObject <$(architecture)>posix_main.o : assert.cpp dlfcn.c @@ -36,6 +44,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { spawn.cpp syslog.cpp termios.c + $(threadsLib) utime.c utmpx.cpp ; diff --git a/src/system/libroot/posix/threads.c b/src/system/libroot/posix/threads.c new file mode 100644 index 0000000000..42316cc463 --- /dev/null +++ b/src/system/libroot/posix/threads.c @@ -0,0 +1,129 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2011 Ed Schouten + * Copyright (c) 2022 Dominic Martinez + * 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 + +#include +#include +#include + +#include + +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; + int error; + + /* + * 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; + + error = pthread_create(thr, NULL, thrd_entry, tp); + if (error != 0) { + free(tp); + if (error == EAGAIN) + return (thrd_busy); + 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); + if (res != NULL) + *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) +{ + sched_yield(); +}