18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 PathScale, Inc 68c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include <stdarg.h> 118c2ecf20Sopenharmony_ci#include <errno.h> 128c2ecf20Sopenharmony_ci#include <signal.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <strings.h> 158c2ecf20Sopenharmony_ci#include <as-layout.h> 168c2ecf20Sopenharmony_ci#include <kern_util.h> 178c2ecf20Sopenharmony_ci#include <os.h> 188c2ecf20Sopenharmony_ci#include <sysdep/mcontext.h> 198c2ecf20Sopenharmony_ci#include <um_malloc.h> 208c2ecf20Sopenharmony_ci#include <sys/ucontext.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_civoid (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { 238c2ecf20Sopenharmony_ci [SIGTRAP] = relay_signal, 248c2ecf20Sopenharmony_ci [SIGFPE] = relay_signal, 258c2ecf20Sopenharmony_ci [SIGILL] = relay_signal, 268c2ecf20Sopenharmony_ci [SIGWINCH] = winch, 278c2ecf20Sopenharmony_ci [SIGBUS] = bus_handler, 288c2ecf20Sopenharmony_ci [SIGSEGV] = segv_handler, 298c2ecf20Sopenharmony_ci [SIGIO] = sigio_handler, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct uml_pt_regs r; 358c2ecf20Sopenharmony_ci int save_errno = errno; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci r.is_user = 0; 388c2ecf20Sopenharmony_ci if (sig == SIGSEGV) { 398c2ecf20Sopenharmony_ci /* For segfaults, we want the data from the sigcontext. */ 408c2ecf20Sopenharmony_ci get_regs_from_mc(&r, mc); 418c2ecf20Sopenharmony_ci GET_FAULTINFO_FROM_MC(r.faultinfo, mc); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* enable signals if sig isn't IRQ signal */ 458c2ecf20Sopenharmony_ci if ((sig != SIGIO) && (sig != SIGWINCH)) 468c2ecf20Sopenharmony_ci unblock_signals_trace(); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci (*sig_info[sig])(sig, si, &r); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci errno = save_errno; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * These are the asynchronous signals. SIGPROF is excluded because we want to 558c2ecf20Sopenharmony_ci * be able to profile all of UML, not just the non-critical sections. If 568c2ecf20Sopenharmony_ci * profiling is not thread-safe, then that is not my problem. We can disable 578c2ecf20Sopenharmony_ci * profiling when SMP is enabled in that case. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#define SIGIO_BIT 0 608c2ecf20Sopenharmony_ci#define SIGIO_MASK (1 << SIGIO_BIT) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define SIGALRM_BIT 1 638c2ecf20Sopenharmony_ci#define SIGALRM_MASK (1 << SIGALRM_BIT) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int signals_enabled; 668c2ecf20Sopenharmony_cistatic unsigned int signals_pending; 678c2ecf20Sopenharmony_cistatic unsigned int signals_active = 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid sig_handler(int sig, struct siginfo *si, mcontext_t *mc) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int enabled; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci enabled = signals_enabled; 748c2ecf20Sopenharmony_ci if (!enabled && (sig == SIGIO)) { 758c2ecf20Sopenharmony_ci signals_pending |= SIGIO_MASK; 768c2ecf20Sopenharmony_ci return; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci block_signals_trace(); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci sig_handler_common(sig, si, mc); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci set_signals_trace(enabled); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void timer_real_alarm_handler(mcontext_t *mc) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct uml_pt_regs regs; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (mc != NULL) 918c2ecf20Sopenharmony_ci get_regs_from_mc(®s, mc); 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci memset(®s, 0, sizeof(regs)); 948c2ecf20Sopenharmony_ci timer_handler(SIGALRM, NULL, ®s); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_civoid timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int enabled; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci enabled = signals_enabled; 1028c2ecf20Sopenharmony_ci if (!signals_enabled) { 1038c2ecf20Sopenharmony_ci signals_pending |= SIGALRM_MASK; 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci block_signals_trace(); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci signals_active |= SIGALRM_MASK; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci timer_real_alarm_handler(mc); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci signals_active &= ~SIGALRM_MASK; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci set_signals_trace(enabled); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_civoid deliver_alarm(void) { 1198c2ecf20Sopenharmony_ci timer_alarm_handler(SIGALRM, NULL, NULL); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_civoid timer_set_signal_handler(void) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci set_handler(SIGALRM); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_civoid set_sigstack(void *sig_stack, int size) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci stack_t stack = { 1308c2ecf20Sopenharmony_ci .ss_flags = 0, 1318c2ecf20Sopenharmony_ci .ss_sp = sig_stack, 1328c2ecf20Sopenharmony_ci .ss_size = size - sizeof(void *) 1338c2ecf20Sopenharmony_ci }; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (sigaltstack(&stack, NULL) != 0) 1368c2ecf20Sopenharmony_ci panic("enabling signal stack failed, errno = %d\n", errno); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic void sigusr1_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci uml_pm_wake(); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_civoid register_pm_wake_signal(void) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci set_handler(SIGUSR1); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { 1508c2ecf20Sopenharmony_ci [SIGSEGV] = sig_handler, 1518c2ecf20Sopenharmony_ci [SIGBUS] = sig_handler, 1528c2ecf20Sopenharmony_ci [SIGILL] = sig_handler, 1538c2ecf20Sopenharmony_ci [SIGFPE] = sig_handler, 1548c2ecf20Sopenharmony_ci [SIGTRAP] = sig_handler, 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci [SIGIO] = sig_handler, 1578c2ecf20Sopenharmony_ci [SIGWINCH] = sig_handler, 1588c2ecf20Sopenharmony_ci [SIGALRM] = timer_alarm_handler, 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci [SIGUSR1] = sigusr1_handler, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void hard_handler(int sig, siginfo_t *si, void *p) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci ucontext_t *uc = p; 1668c2ecf20Sopenharmony_ci mcontext_t *mc = &uc->uc_mcontext; 1678c2ecf20Sopenharmony_ci unsigned long pending = 1UL << sig; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci do { 1708c2ecf20Sopenharmony_ci int nested, bail; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * pending comes back with one bit set for each 1748c2ecf20Sopenharmony_ci * interrupt that arrived while setting up the stack, 1758c2ecf20Sopenharmony_ci * plus a bit for this interrupt, plus the zero bit is 1768c2ecf20Sopenharmony_ci * set if this is a nested interrupt. 1778c2ecf20Sopenharmony_ci * If bail is true, then we interrupted another 1788c2ecf20Sopenharmony_ci * handler setting up the stack. In this case, we 1798c2ecf20Sopenharmony_ci * have to return, and the upper handler will deal 1808c2ecf20Sopenharmony_ci * with this interrupt. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci bail = to_irq_stack(&pending); 1838c2ecf20Sopenharmony_ci if (bail) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci nested = pending & 1; 1878c2ecf20Sopenharmony_ci pending &= ~1; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci while ((sig = ffs(pending)) != 0){ 1908c2ecf20Sopenharmony_ci sig--; 1918c2ecf20Sopenharmony_ci pending &= ~(1 << sig); 1928c2ecf20Sopenharmony_ci (*handlers[sig])(sig, (struct siginfo *)si, mc); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * Again, pending comes back with a mask of signals 1978c2ecf20Sopenharmony_ci * that arrived while tearing down the stack. If this 1988c2ecf20Sopenharmony_ci * is non-zero, we just go back, set up the stack 1998c2ecf20Sopenharmony_ci * again, and handle the new interrupts. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci if (!nested) 2028c2ecf20Sopenharmony_ci pending = from_irq_stack(nested); 2038c2ecf20Sopenharmony_ci } while (pending); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_civoid set_handler(int sig) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct sigaction action; 2098c2ecf20Sopenharmony_ci int flags = SA_SIGINFO | SA_ONSTACK; 2108c2ecf20Sopenharmony_ci sigset_t sig_mask; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci action.sa_sigaction = hard_handler; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* block irq ones */ 2158c2ecf20Sopenharmony_ci sigemptyset(&action.sa_mask); 2168c2ecf20Sopenharmony_ci sigaddset(&action.sa_mask, SIGIO); 2178c2ecf20Sopenharmony_ci sigaddset(&action.sa_mask, SIGWINCH); 2188c2ecf20Sopenharmony_ci sigaddset(&action.sa_mask, SIGALRM); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (sig == SIGSEGV) 2218c2ecf20Sopenharmony_ci flags |= SA_NODEFER; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (sigismember(&action.sa_mask, sig)) 2248c2ecf20Sopenharmony_ci flags |= SA_RESTART; /* if it's an irq signal */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci action.sa_flags = flags; 2278c2ecf20Sopenharmony_ci action.sa_restorer = NULL; 2288c2ecf20Sopenharmony_ci if (sigaction(sig, &action, NULL) < 0) 2298c2ecf20Sopenharmony_ci panic("sigaction failed - errno = %d\n", errno); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci sigemptyset(&sig_mask); 2328c2ecf20Sopenharmony_ci sigaddset(&sig_mask, sig); 2338c2ecf20Sopenharmony_ci if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0) 2348c2ecf20Sopenharmony_ci panic("sigprocmask failed - errno = %d\n", errno); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint change_sig(int signal, int on) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci sigset_t sigset; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci sigemptyset(&sigset); 2428c2ecf20Sopenharmony_ci sigaddset(&sigset, signal); 2438c2ecf20Sopenharmony_ci if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) 2448c2ecf20Sopenharmony_ci return -errno; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_civoid block_signals(void) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci signals_enabled = 0; 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * This must return with signals disabled, so this barrier 2548c2ecf20Sopenharmony_ci * ensures that writes are flushed out before the return. 2558c2ecf20Sopenharmony_ci * This might matter if gcc figures out how to inline this and 2568c2ecf20Sopenharmony_ci * decides to shuffle this code into the caller. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci barrier(); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_civoid unblock_signals(void) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci int save_pending; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (signals_enabled == 1) 2668c2ecf20Sopenharmony_ci return; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci signals_enabled = 1; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * We loop because the IRQ handler returns with interrupts off. So, 2728c2ecf20Sopenharmony_ci * interrupts may have arrived and we need to re-enable them and 2738c2ecf20Sopenharmony_ci * recheck signals_pending. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci while (1) { 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * Save and reset save_pending after enabling signals. This 2788c2ecf20Sopenharmony_ci * way, signals_pending won't be changed while we're reading it. 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * Setting signals_enabled and reading signals_pending must 2818c2ecf20Sopenharmony_ci * happen in this order, so have the barrier here. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci barrier(); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci save_pending = signals_pending; 2868c2ecf20Sopenharmony_ci if (save_pending == 0) 2878c2ecf20Sopenharmony_ci return; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci signals_pending = 0; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* 2928c2ecf20Sopenharmony_ci * We have pending interrupts, so disable signals, as the 2938c2ecf20Sopenharmony_ci * handlers expect them off when they are called. They will 2948c2ecf20Sopenharmony_ci * be enabled again above. We need to trace this, as we're 2958c2ecf20Sopenharmony_ci * expected to be enabling interrupts already, but any more 2968c2ecf20Sopenharmony_ci * tracing that happens inside the handlers we call for the 2978c2ecf20Sopenharmony_ci * pending signals will mess up the tracing state. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci signals_enabled = 0; 3008c2ecf20Sopenharmony_ci um_trace_signals_off(); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * Deal with SIGIO first because the alarm handler might 3048c2ecf20Sopenharmony_ci * schedule, leaving the pending SIGIO stranded until we come 3058c2ecf20Sopenharmony_ci * back here. 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * SIGIO's handler doesn't use siginfo or mcontext, 3088c2ecf20Sopenharmony_ci * so they can be NULL. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (save_pending & SIGIO_MASK) 3118c2ecf20Sopenharmony_ci sig_handler_common(SIGIO, NULL, NULL); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Do not reenter the handler */ 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if ((save_pending & SIGALRM_MASK) && (!(signals_active & SIGALRM_MASK))) 3168c2ecf20Sopenharmony_ci timer_real_alarm_handler(NULL); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Rerun the loop only if there is still pending SIGIO and not in TIMER handler */ 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK)) 3218c2ecf20Sopenharmony_ci return; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Re-enable signals and trace that we're doing so. */ 3248c2ecf20Sopenharmony_ci um_trace_signals_on(); 3258c2ecf20Sopenharmony_ci signals_enabled = 1; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ciint get_signals(void) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci return signals_enabled; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciint set_signals(int enable) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int ret; 3378c2ecf20Sopenharmony_ci if (signals_enabled == enable) 3388c2ecf20Sopenharmony_ci return enable; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ret = signals_enabled; 3418c2ecf20Sopenharmony_ci if (enable) 3428c2ecf20Sopenharmony_ci unblock_signals(); 3438c2ecf20Sopenharmony_ci else block_signals(); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint set_signals_trace(int enable) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci int ret; 3518c2ecf20Sopenharmony_ci if (signals_enabled == enable) 3528c2ecf20Sopenharmony_ci return enable; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = signals_enabled; 3558c2ecf20Sopenharmony_ci if (enable) 3568c2ecf20Sopenharmony_ci unblock_signals_trace(); 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci block_signals_trace(); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciint os_is_signal_stack(void) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci stack_t ss; 3668c2ecf20Sopenharmony_ci sigaltstack(NULL, &ss); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return ss.ss_flags & SS_ONSTACK; 3698c2ecf20Sopenharmony_ci} 370