diff options
author | Tim Schumacher <timschumi@gmx.de> | 2022-06-12 14:48:28 +0200 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2022-07-22 10:07:15 -0700 |
commit | 899fd74f8ecc7c0b57a555babbad445f87ac36b4 (patch) | |
tree | bb941253403d99995c38c6aa174317fca4c87521 | |
parent | 1269ce0c35fdeeb27d797f878c82d12877add874 (diff) | |
download | serenity-899fd74f8ecc7c0b57a555babbad445f87ac36b4.zip |
LibC: Implement `pthread_cancel`
-rw-r--r-- | Kernel/Thread.cpp | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibC/bits/pthread_cancel.h | 23 | ||||
-rw-r--r-- | Userland/Libraries/LibC/pthread.cpp | 46 | ||||
-rw-r--r-- | Userland/Libraries/LibC/pthread.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibC/signal_numbers.h | 3 |
5 files changed, 71 insertions, 4 deletions
diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index e0cd1073e3..9f7aa6e70d 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -871,6 +871,7 @@ static DefaultSignalAction default_signal_action(u8 signal) case SIGIO: case SIGPROF: case SIGTERM: + case SIGCANCEL: return DefaultSignalAction::Terminate; case SIGCHLD: case SIGURG: diff --git a/Userland/Libraries/LibC/bits/pthread_cancel.h b/Userland/Libraries/LibC/bits/pthread_cancel.h new file mode 100644 index 0000000000..174c1bd9a6 --- /dev/null +++ b/Userland/Libraries/LibC/bits/pthread_cancel.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +// This is our hook for cancellation points. +#ifdef _DYNAMIC_LOADER +inline void __pthread_maybe_cancel(void) +{ +} +#else +void __pthread_maybe_cancel(void); +#endif + +__END_DECLS diff --git a/Userland/Libraries/LibC/pthread.cpp b/Userland/Libraries/LibC/pthread.cpp index 6aa9e2e5cf..29aecba78e 100644 --- a/Userland/Libraries/LibC/pthread.cpp +++ b/Userland/Libraries/LibC/pthread.cpp @@ -12,6 +12,7 @@ #include <AK/StdLibExtras.h> #include <Kernel/API/Syscall.h> #include <LibSystem/syscall.h> +#include <bits/pthread_cancel.h> #include <bits/pthread_integration.h> #include <errno.h> #include <limits.h> @@ -51,6 +52,8 @@ struct CleanupHandler { static thread_local SinglyLinkedList<CleanupHandler> cleanup_handlers; +static __thread bool pending_cancellation = false; + extern "C" { [[noreturn]] static void exit_thread(void* code, void* stack_location, size_t stack_size) @@ -154,6 +157,21 @@ void pthread_exit(void* value_ptr) pthread_exit_without_cleanup_handlers(value_ptr); } +void __pthread_maybe_cancel() +{ + // Check if we have cancellations enabled. + if (s_thread_cancel_state != PTHREAD_CANCEL_ENABLE) + return; + + // Check if a cancellation request is pending. + if (!pending_cancellation) + return; + + // Exit the thread via `pthread_exit`. This handles passing the + // return value and calling the cleanup handlers for us. + pthread_exit(PTHREAD_CANCELED); +} + // https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cleanup_push.html void pthread_cleanup_push(void (*routine)(void*), void* arg) { @@ -481,11 +499,35 @@ int pthread_setschedparam([[maybe_unused]] pthread_t thread, [[maybe_unused]] in return 0; } +static void pthread_cancel_signal_handler(int signal) +{ + // SIGCANCEL is a custom signal that is beyond the usual range of signal numbers. + // Let's make sure we know about it in case we still end up in here, but the signal + // number is being mangled. + VERIFY(signal == SIGCANCEL); + + // Note: We don't handle PTHREAD_CANCEL_ASYNCHRONOUS any different from PTHREAD_CANCEL_DEFERRED, + // since ASYNCHRONOUS just means that the thread can be cancelled at any time (instead of just + // at the next cancellation point) and it seems to be generally discouraged to use it at all. + pending_cancellation = true; +} + // https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cancel.html // NOTE: libgcc expects this function to exist in libpthread, even if it is not implemented. -int pthread_cancel(pthread_t) +int pthread_cancel(pthread_t thread) { - TODO(); + // Set up our signal handler, which listens on SIGCANCEL and flips the cancellation indicator. + // Note that signal handlers are shared across the whole process, so we can just set that up at any time. + static bool set_up_cancel_handler = false; + + if (!set_up_cancel_handler) { + struct sigaction act = {}; + act.sa_handler = pthread_cancel_signal_handler; + sigaction(SIGCANCEL, &act, nullptr); + set_up_cancel_handler = true; + } + + return pthread_kill(thread, SIGCANCEL); } int pthread_setname_np(pthread_t thread, char const* name) diff --git a/Userland/Libraries/LibC/pthread.h b/Userland/Libraries/LibC/pthread.h index 6260cd5454..2f7ff03c23 100644 --- a/Userland/Libraries/LibC/pthread.h +++ b/Userland/Libraries/LibC/pthread.h @@ -33,7 +33,7 @@ int pthread_attr_destroy(pthread_attr_t*); #define PTHREAD_CREATE_JOINABLE 0 #define PTHREAD_CREATE_DETACHED 1 -#define PTHREAD_CANCELED (-1) +#define PTHREAD_CANCELED ((void*)-1) int pthread_attr_getdetachstate(pthread_attr_t const*, int*); int pthread_attr_setdetachstate(pthread_attr_t*, int); diff --git a/Userland/Libraries/LibC/signal_numbers.h b/Userland/Libraries/LibC/signal_numbers.h index ef91bca29a..17ee5bd9d4 100644 --- a/Userland/Libraries/LibC/signal_numbers.h +++ b/Userland/Libraries/LibC/signal_numbers.h @@ -38,4 +38,5 @@ #define SIGIO 29 #define SIGINFO 30 #define SIGSYS 31 -#define NSIG 32 +#define SIGCANCEL 32 +#define NSIG 33 |