codegen: introduce cg-spill.inc
[ajla.git] / th_sig.inc
blobc02a7f732751d038b3fbf2991650599c277e1ae5
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
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
9  * version.
10  *
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.
14  *
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/>.
17  */
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.
26  *
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.
29  *
30  * PA-RISC Linux crashes in libgmp if a signal is received.
31  */
33 #include <signal.h>
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)
44         int r;
45         os_unblock_signals(&signal_saved_sigset);
46         r = pthread_mutex_lock(&signal_mutex);
47         if (unlikely(r))
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)));
53         }
54         r = pthread_mutex_unlock(&signal_mutex);
55         if (unlikely(r))
56                 internal(file_line, "pthread_mutex_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
57         os_block_signals(NULL);
58         return NULL;
61 static void thread_signal_init(void)
63         int r;
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"))
75                 return;
76 #endif
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"))
88                 return;
89 #endif
91         r = pthread_mutex_init(&signal_mutex, NULL);
92         if (unlikely(r))
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);
95         if (unlikely(r))
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);
99         if (unlikely(r))
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)
106         int r;
108         if (!signal_thread_enabled)
109                 return;
111         r = pthread_mutex_lock(&signal_mutex);
112         if (unlikely(r))
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);
116         if (unlikely(r))
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);
119         if (unlikely(r))
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);
122         if (unlikely(r))
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);
126         if (unlikely(r))
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);
129         if (unlikely(r))
130                 fatal("pthread_cond_destroy failed at %s: %d, %s", file_line, r, error_decode(error_from_errno(EC_SYSCALL, r)));
133 #else
135 #define thread_signal_init()    do { } while (0)
136 #define thread_signal_done()    do { } while (0)
138 #endif