Files
RedBear-OS/local/recipes/tools/diffutils/source/gnulib-tests/glthread/thread.c
T
vasilito 068a1ca63e bootloader: rebase onto upstream 1.0.0, sync firmware-loader version
Bootloader fork rebase:
- Base changed from 0.1.0 pre-patched archive to upstream 1.0.0 tag (c7eeb9f)
- Applied 0001-redbear-local-forks.patch (Cargo.toml crate path redirects)
- Applied fix-uefi-alloc-panic.patch equivalents (4 panic!() -> graceful
  error handling in src/main.rs)
- Applied P5-live-preload-cap-1gib.patch (1 GiB cap on live image preload)
- Skipped: P0 GPT partition scan (requires new module + integration),
  P1 timeout/default-resolution, P2 live preload guard (subsumed by
  panic fixes + cap), P3 live image safe read, P4 large ISO boot,
  redox.patch — to be applied in dedicated rebase session.

firmware-loader/Cargo.toml: version 0.1.0 -> 0.3.0 (sync with other
Red Bear custom crates which are at 0.3.0).

fork-upstream-map.toml: bootloader back from PENDING_REBASE to 1.0.0
since the partial rebase matches upstream 1.0.0 content.

fork-upstream-map.toml: base restored to 'main' tracked (was correctly
tracked by build-redbear.sh).
2026-07-11 09:47:59 +03:00

218 lines
5.6 KiB
C

/* Creating and controlling threads.
Copyright (C) 2005-2025 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
#include <config.h>
/* Specification. */
#include "glthread/thread.h"
#include <stdlib.h>
/* ========================================================================= */
#if USE_ISOC_THREADS
struct thrd_with_exitvalue
{
thrd_t volatile tid;
void * volatile exitvalue;
};
/* The Thread-Specific Storage (TSS) key that allows to access each thread's
'struct thrd_with_exitvalue *' pointer. */
static tss_t thrd_with_exitvalue_key;
/* Initializes thrd_with_exitvalue_key.
This function must only be called once. */
static void
do_init_thrd_with_exitvalue_key (void)
{
if (tss_create (&thrd_with_exitvalue_key, NULL) != thrd_success)
abort ();
}
/* Initializes thrd_with_exitvalue_key. */
static void
init_thrd_with_exitvalue_key (void)
{
static once_flag once = ONCE_FLAG_INIT;
call_once (&once, do_init_thrd_with_exitvalue_key);
}
typedef union
{
struct thrd_with_exitvalue t;
struct
{
thrd_t tid; /* reserve memory for t.tid */
void *(*mainfunc) (void *);
void *arg;
} a;
}
main_arg_t;
static int
thrd_main_func (void *pmarg)
{
/* Unpack the object that combines mainfunc and arg. */
main_arg_t *main_arg = (main_arg_t *) pmarg;
void *(*mainfunc) (void *) = main_arg->a.mainfunc;
void *arg = main_arg->a.arg;
if (tss_set (thrd_with_exitvalue_key, &main_arg->t) != thrd_success)
abort ();
/* Execute mainfunc, with arg as argument. */
{
void *exitvalue = mainfunc (arg);
/* Store the exitvalue, for use by glthread_join(). */
main_arg->t.exitvalue = exitvalue;
return 0;
}
}
int
glthread_create (gl_thread_t *threadp, void *(*mainfunc) (void *), void *arg)
{
init_thrd_with_exitvalue_key ();
{
/* Combine mainfunc and arg in a single object.
A stack-allocated object does not work, because it would be out of
existence when thrd_create returns before thrd_main_func is
entered. So, allocate it in the heap. */
main_arg_t *main_arg = (main_arg_t *) malloc (sizeof (main_arg_t));
if (main_arg == NULL)
return ENOMEM;
main_arg->a.mainfunc = mainfunc;
main_arg->a.arg = arg;
switch (thrd_create ((thrd_t *) &main_arg->t.tid, thrd_main_func, main_arg))
{
case thrd_success:
break;
case thrd_nomem:
free (main_arg);
return ENOMEM;
default:
free (main_arg);
return EAGAIN;
}
*threadp = &main_arg->t;
return 0;
}
}
gl_thread_t
gl_thread_self (void)
{
init_thrd_with_exitvalue_key ();
{
gl_thread_t thread =
(struct thrd_with_exitvalue *) tss_get (thrd_with_exitvalue_key);
if (thread == NULL)
{
/* This happens only in threads that have not been created through
glthread_create(), such as the main thread. */
for (;;)
{
thread =
(struct thrd_with_exitvalue *)
malloc (sizeof (struct thrd_with_exitvalue));
if (thread != NULL)
break;
/* Memory allocation failed. There is not much we can do. Have to
busy-loop, waiting for the availability of memory. */
{
struct timespec ts =
{
.tv_sec = 1,
.tv_nsec = 0
};
thrd_sleep (&ts, NULL);
}
}
thread->tid = thrd_current ();
thread->exitvalue = NULL; /* just to be deterministic */
if (tss_set (thrd_with_exitvalue_key, thread) != thrd_success)
abort ();
}
return thread;
}
}
int
glthread_join (gl_thread_t thread, void **return_value_ptr)
{
/* On Solaris 11.4, thrd_join crashes when the second argument we pass is
NULL. */
int dummy;
if (thread == gl_thread_self ())
return EINVAL;
if (thrd_join (thread->tid, &dummy) != thrd_success)
return EINVAL;
if (return_value_ptr != NULL)
*return_value_ptr = thread->exitvalue;
free (thread);
return 0;
}
_Noreturn void
gl_thread_exit (void *return_value)
{
gl_thread_t thread = gl_thread_self ();
thread->exitvalue = return_value;
thrd_exit (0);
}
#endif
/* ========================================================================= */
#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
#include <pthread.h>
#if defined PTW32_VERSION || defined __MVS__
const gl_thread_t gl_null_thread /* = { .p = NULL } */;
#endif
#endif
/* ========================================================================= */
#if USE_WINDOWS_THREADS
#endif
/* ========================================================================= */
gl_thread_t
gl_thread_create (void *(*func) (void *arg), void *arg)
{
gl_thread_t thread;
int ret;
ret = glthread_create (&thread, func, arg);
if (ret != 0)
abort ();
return thread;
}