2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #if defined(__CYGWIN__) || (defined(__linux__) && (defined(__alpha__) || defined(__hppa))) || defined(__HAIKU__)
22 * In Cygwin, signals must not be delivered to threads doing Win32 waiting
23 * functions. We have to spawn an extra thread specifically for signals.
24 * This piece of code improves signal reliability, but doesn't fix the problem
25 * completely, so we must not use native Win32 threads with cygwin.
27 * Alpha Linux has a bug that it may crash if a thread is spawned and a signal
28 * is received at the same time.
30 * PA-RISC Linux crashes in libgmp if a signal is received.
35 static uchar_efficient_t signal_thread_end;
36 static uchar_efficient_t signal_thread_enabled;
37 static sig_state_t signal_saved_sigset;
38 static pthread_t signal_thread;
39 static pthread_cond_t signal_cond;
40 static pthread_mutex_t signal_mutex;
42 static void *signal_thread_function(void attr_unused *ptr)
45 os_unblock_signals(&signal_saved_sigset);
46 r = pthread_mutex_lock(&signal_mutex);
48 internal(file_line, "pthread_mutex_lock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
49 while (!signal_thread_end) {
50 r = pthread_cond_wait(&signal_cond, &signal_mutex);
51 if (unlikely(r) && unlikely(r != EINTR))
52 internal(file_line, "pthread_cond_wait failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
54 r = pthread_mutex_unlock(&signal_mutex);
56 internal(file_line, "pthread_mutex_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
57 os_block_signals(NULL);
61 static void thread_signal_init(void)
64 signal_thread_end = false;
66 #if defined(__linux__) && defined(__alpha__)
67 if (os_kernel_version("GNU/Linux", "5") ||
68 os_kernel_version("GNU/Linux", "4.16") ||
69 os_kernel_version("GNU/Linux", "4.15.4") ||
70 os_kernel_version("GNU/Linux", "4.14.20") ||
71 os_kernel_version("GNU/Linux", "4.9.82") ||
72 os_kernel_version("GNU/Linux", "4.4.116") ||
73 os_kernel_version("GNU/Linux", "4.1.50") ||
74 os_kernel_version("GNU/Linux", "3.18.95"))
77 #if defined(__linux__) && defined(__hppa)
78 if (os_kernel_version("GNU/Linux", "6") ||
79 os_kernel_version("GNU/Linux", "5.15") ||
80 os_kernel_version("GNU/Linux", "5.14.6") ||
81 os_kernel_version("GNU/Linux", "5.13.19") ||
82 os_kernel_version("GNU/Linux", "5.10.67") ||
83 os_kernel_version("GNU/Linux", "5.4.148") ||
84 os_kernel_version("GNU/Linux", "4.19.207") ||
85 os_kernel_version("GNU/Linux", "4.14.247") ||
86 os_kernel_version("GNU/Linux", "4.9.283") ||
87 os_kernel_version("GNU/Linux", "4.4.284"))
91 r = pthread_mutex_init(&signal_mutex, NULL);
93 fatal("pthread_mutex_init failed at %s: %d, %s", file_line, r, error_decode(error_from_errno(EC_SYSCALL, r)));
94 r = pthread_cond_init(&signal_cond, NULL);
96 fatal("pthread_cond_init failed at %s: %d, %s", file_line, r, error_decode(error_from_errno(EC_SYSCALL, r)));
97 os_block_signals(&signal_saved_sigset);
98 r = pthread_create(&signal_thread, NULL, signal_thread_function, NULL);
100 fatal("pthread_create failed at %s: %d, %s", file_line, r, error_decode(error_from_errno(EC_SYSCALL, r)));
101 signal_thread_enabled = true;
104 static void thread_signal_done(void)
108 if (!signal_thread_enabled)
111 r = pthread_mutex_lock(&signal_mutex);
113 internal(file_line, "pthread_mutex_lock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
114 signal_thread_end = true;
115 r = pthread_mutex_unlock(&signal_mutex);
117 internal(file_line, "pthread_mutex_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
118 r = pthread_cond_signal(&signal_cond);
120 internal(file_line, "pthread_cond_signal failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
121 r = pthread_join(signal_thread, NULL);
123 internal(file_line, "pthread_join failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
124 os_unblock_signals(&signal_saved_sigset);
125 r = pthread_mutex_destroy(&signal_mutex);
127 fatal("pthread_mutex_destroy failed at %s: %d, %s", file_line, r, error_decode(error_from_errno(EC_SYSCALL, r)));
128 r = pthread_cond_destroy(&signal_cond);
130 fatal("pthread_cond_destroy failed at %s: %d, %s", file_line, r, error_decode(error_from_errno(EC_SYSCALL, r)));
135 #define thread_signal_init() do { } while (0)
136 #define thread_signal_done() do { } while (0)