068a1ca63e
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).
218 lines
5.6 KiB
C
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;
|
|
}
|