summaryrefslogtreecommitdiff
path: root/minix/lib/libsys/sef_signal.c
blob: b0c5387eea55238df0a1c61ec413906b46082ae1 (plain)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "syslib.h"
#include <assert.h>
#include <signal.h>
#include <minix/sysutil.h>

/* SEF Signal callbacks. */
static struct sef_signal_cbs {
    sef_cb_signal_handler_t             sef_cb_signal_handler;
    sef_cb_signal_manager_t             sef_cb_signal_manager;
} sef_signal_cbs = {
    SEF_CB_SIGNAL_HANDLER_DEFAULT,
    SEF_CB_SIGNAL_MANAGER_DEFAULT
};

/* SEF Signal prototypes for sef_receive(). */
int do_sef_signal_request(message *m_ptr);

/* Debug. */
EXTERN char* sef_debug_header(void);

/* Information about SELF. */
EXTERN endpoint_t sef_self_endpoint;

/*===========================================================================*
 *                         process_sigmgr_signals               	     *
 *===========================================================================*/
static void process_sigmgr_signals(void)
{
/* A signal manager has pending signals in the kernel. Process them. */
  endpoint_t target;
  sigset_t set;
  int signo, r;

  while (TRUE) {
      /* Get an arbitrary pending signal. */
      if((r=sys_getksig(&target, &set)) != OK)
          panic("SEF: sys_getksig failed: %d", r);

      if (target == NONE) {
          /* Stop if there are no more pending signals. */
          break;
      } else {
          /* Process every signal in the signal set. */
          r = OK;
          for (signo = SIGS_FIRST; signo <= SIGS_LAST; signo++) {
              int s = sigismember(&set, signo);
              assert(s >= 0);
              if(s) {
                  /* Let the callback code process the signal. */
                  r = sef_signal_cbs.sef_cb_signal_manager(target, signo);

                  /* Stop if process is gone. */
                  if(r == EDEADEPT) {
                      break;
                  }
              }
          }
          /* Tell the kernel we are done if the target is still alive. */
          if(r == OK) {
              if((r=sys_endksig(target)) != OK)
                  panic("SEF: sys_endksig failed :%d", r);
          }
      }
  }
}

/*===========================================================================*
 *                         process_sigmgr_self_signals               	     *
 *===========================================================================*/
static void process_sigmgr_self_signals(sigset_t set)
{
/* A signal manager has pending signals for itself. Process them. */
  int signo;

  for (signo = SIGS_FIRST; signo <= SIGS_LAST; signo++) {
      int s = sigismember(&set, signo);
      assert(s >= 0);
      if(s) {
          /* Let the callback code process the signal. */
          sef_signal_cbs.sef_cb_signal_handler(signo);
      }
  }
}

/*===========================================================================*
 *                           do_sef_signal_request             		     *
 *===========================================================================*/
int do_sef_signal_request(message *m_ptr)
{
/* Handle a SEF Signal request. */
  int signo;
  sigset_t set;

  if(m_ptr->m_source == SYSTEM) {
      /* Handle kernel signals. */
      set = m_ptr->m_notify.sigset;
      for (signo = SIGK_FIRST; signo <= SIGK_LAST; signo++) {
          int s = sigismember(&set, signo);
          assert(s >= 0);
          if (s) {
              /* Let the callback code handle the kernel signal. */
              sef_signal_cbs.sef_cb_signal_handler(signo);

              /* Handle SIGKSIG for a signal manager. */
              if(signo == SIGKSIG) {
                  process_sigmgr_signals();
              }
              /* Handle SIGKSIGSM for a signal manager. */
              else if(signo == SIGKSIGSM) {
                  process_sigmgr_self_signals(set);
              }
          }
      }
  }
  else {
      /* Handle system signals from a signal manager. */
      signo = m_ptr->m_pm_lsys_sigs_signal.num;

      /* Debug. */
#if SEF_SIGNAL_DEBUG
      sef_signal_debug_begin();
      sef_signal_dprint("%s. Got a SEF Signal request for signal %d! About to handle signal.\n", 
          sef_debug_header(), signo);
      sef_signal_debug_end();
#endif

      /* Let the callback code handle the signal. */
      sef_signal_cbs.sef_cb_signal_handler(signo);
  }

  /* Return OK not to let anybody else intercept the request. */
  return OK;
}

/*===========================================================================*
 *                        sef_setcb_signal_handler                           *
 *===========================================================================*/
void sef_setcb_signal_handler(sef_cb_signal_handler_t cb)
{
  assert(cb != NULL);
  sef_signal_cbs.sef_cb_signal_handler = cb;
}

/*===========================================================================*
 *                        sef_setcb_signal_manager                           *
 *===========================================================================*/
void sef_setcb_signal_manager(sef_cb_signal_manager_t cb)
{
  assert(cb != NULL);
  sef_signal_cbs.sef_cb_signal_manager = cb;
}

/*===========================================================================*
 *       	          sef_cb_signal_handler_null                         *
 *===========================================================================*/
void sef_cb_signal_handler_null(int signo)
{
}

/*===========================================================================*
 *       	          sef_cb_signal_manager_null                         *
 *===========================================================================*/
int sef_cb_signal_manager_null(endpoint_t target, int signo)
{
  return OK;
}

/*===========================================================================*
 *       	          sef_cb_signal_handler_term                         *
 *===========================================================================*/
void sef_cb_signal_handler_term(int signo)
{
  /* Terminate in case of SIGTERM, ignore other signals. */
  if(signo == SIGTERM) {
      sef_exit(1);
  }
}

/*===========================================================================*
 *      	      sef_cb_signal_handler_posix_default                    *
 *===========================================================================*/
void sef_cb_signal_handler_posix_default(int signo)
{
  switch(signo) {
      /* Ignore when possible. */
      case SIGCHLD:
      case SIGWINCH:
      case SIGCONT:
      case SIGTSTP:
      case SIGTTIN:
      case SIGTTOU:
      break;

      /* Terminate in any other case unless it is a kernel signal. */
      default:
          if(!IS_SIGK(signo)) {
              sef_exit(1);
          }
      break;
  }
}