hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2007 Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
 *
 * This library 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 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#include <pthread.h>
#include <signal.h>
#include <asm/xenomai/syscall.h>
#include "internal.h"
 
#if !HAVE_BACKTRACE
static inline int backtrace(void **buffer, int size)
{
   /* Not all *libcs support backtrace(). */
   return 0;
}
#else
#include <execinfo.h>
#endif
 
static struct sigaction sigshadow_action_orig;
 
/*
 * The following handler is part of the inner user-interface: should
 * remain extern.
 */
int cobalt_sigshadow_handler(int sig, siginfo_t *si, void *ctxt)
{
   void *frames[SIGSHADOW_BACKTRACE_DEPTH];
   int action, arg, nr, skip;
 
   if (si->si_code != SI_QUEUE)
       return 0;
 
   action = sigshadow_action(si->si_int);
 
   switch (action) {
   case SIGSHADOW_ACTION_HARDEN:
       XENOMAI_SYSCALL1(sc_cobalt_migrate, COBALT_PRIMARY);
       break;
   case SIGSHADOW_ACTION_BACKTRACE:
       arg = sigshadow_arg(si->si_int);
       nr = backtrace(frames, sizeof(frames) / sizeof(frames[0]));
       /* Skip the sighandler context. */
       skip = nr > 3 ? 3 : 0;
       XENOMAI_SYSCALL3(sc_cobalt_backtrace, nr - skip, frames + skip, arg);
       break;
   case SIGSHADOW_ACTION_HOME:
       /*
        * We have been asked to call home from the current
        * context: sending a query for retrieving our handle
        * will just do this.
        */
       cobalt_get_current_slow();
       break;
   default:
       return 0;
   }
 
   return 1;
}
 
static void sigshadow_handler(int sig, siginfo_t *si, void *ctxt)
{
   const struct sigaction *const sa = &sigshadow_action_orig;
   sigset_t saved_sigset;
 
   if (cobalt_sigshadow_handler(sig, si, ctxt))
       return;
 
   /* Not a signal sent by the Cobalt core */
   if (((sa->sa_flags & SA_SIGINFO) == 0 && sa->sa_handler == NULL)
       || ((sa->sa_flags & SA_SIGINFO) && sa->sa_sigaction == NULL))
       return;
 
   pthread_sigmask(SIG_SETMASK, &sa->sa_mask, &saved_sigset);
 
   if (!(sa->sa_flags & SA_SIGINFO))
       sa->sa_handler(sig);
   else
       sa->sa_sigaction(sig, si, ctxt);
 
   pthread_sigmask(SIG_SETMASK, &saved_sigset, NULL);
}
 
static void install_sigshadow(void)
{
   void *dummy[SIGSHADOW_BACKTRACE_DEPTH];
   struct sigaction new_sigshadow_action;
   sigset_t saved_sigset;
   sigset_t mask_sigset;
 
   /*
    * Kickstart backtrace() so that it may call malloc() from a
    * safe context right now, not later on from the sigshadow
    * handler.
    */
   backtrace(dummy, SIGSHADOW_BACKTRACE_DEPTH);
 
   sigemptyset(&mask_sigset);
   sigaddset(&mask_sigset, SIGSHADOW);
 
   new_sigshadow_action.sa_flags = SA_SIGINFO | SA_RESTART;
   new_sigshadow_action.sa_sigaction = sigshadow_handler;
   sigemptyset(&new_sigshadow_action.sa_mask);
   pthread_sigmask(SIG_BLOCK, &mask_sigset, &saved_sigset);
 
   sigaction(SIGSHADOW,
         &new_sigshadow_action, &sigshadow_action_orig);
 
   if ((sigshadow_action_orig.sa_flags & SA_NODEFER) == 0)
       sigaddset(&sigshadow_action_orig.sa_mask, SIGSHADOW);
 
   pthread_sigmask(SIG_SETMASK, &saved_sigset, NULL);
}
 
void cobalt_sigshadow_install_once(void)
{
   static pthread_once_t once = PTHREAD_ONCE_INIT;
   pthread_once(&once, install_sigshadow);
}