root/lib/tevent/tevent_signal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sig_count
  2. tevent_common_signal_handler
  3. tevent_common_signal_handler_info
  4. tevent_common_signal_list_destructor
  5. tevent_signal_destructor
  6. signal_pipe_handler
  7. tevent_common_add_signal
  8. tevent_common_check_signal
  9. tevent_cleanup_pending_signal_handlers

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    common events code for signal events
   5 
   6    Copyright (C) Andrew Tridgell        2007
   7 
   8      ** NOTE! The following LGPL license applies to the tevent
   9      ** library. This does NOT imply that all of Samba is released
  10      ** under the LGPL
  11 
  12    This library is free software; you can redistribute it and/or
  13    modify it under the terms of the GNU Lesser General Public
  14    License as published by the Free Software Foundation; either
  15    version 3 of the License, or (at your option) any later version.
  16 
  17    This library is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20    Lesser General Public License for more details.
  21 
  22    You should have received a copy of the GNU Lesser General Public
  23    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  24 */
  25 
  26 #include "replace.h"
  27 #include "system/filesys.h"
  28 #include "system/wait.h"
  29 #include "tevent.h"
  30 #include "tevent_internal.h"
  31 #include "tevent_util.h"
  32 
  33 #define NUM_SIGNALS 64
  34 
  35 /* maximum number of SA_SIGINFO signals to hold in the queue.
  36   NB. This *MUST* be a power of 2, in order for the ring buffer
  37   wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
  38   for this. */
  39 
  40 #define SA_INFO_QUEUE_COUNT 64
  41 
  42 struct sigcounter {
  43         uint32_t count;
  44         uint32_t seen;
  45 };
  46 
  47 #define SIG_INCREMENT(s) (s).count++
  48 #define SIG_SEEN(s, n) (s).seen += (n)
  49 #define SIG_PENDING(s) ((s).seen != (s).count)
  50 
  51 struct tevent_common_signal_list {
  52         struct tevent_common_signal_list *prev, *next;
  53         struct tevent_signal *se;
  54 };
  55 
  56 /*
  57   the poor design of signals means that this table must be static global
  58 */
  59 static struct sig_state {
  60         struct tevent_common_signal_list *sig_handlers[NUM_SIGNALS+1];
  61         struct sigaction *oldact[NUM_SIGNALS+1];
  62         struct sigcounter signal_count[NUM_SIGNALS+1];
  63         struct sigcounter got_signal;
  64 #ifdef SA_SIGINFO
  65         /* with SA_SIGINFO we get quite a lot of info per signal */
  66         siginfo_t *sig_info[NUM_SIGNALS+1];
  67         struct sigcounter sig_blocked[NUM_SIGNALS+1];
  68 #endif
  69 } *sig_state;
  70 
  71 /*
  72   return number of sigcounter events not processed yet
  73 */
  74 static uint32_t sig_count(struct sigcounter s)
     /* [<][>][^][v][top][bottom][index][help] */
  75 {
  76         return s.count - s.seen;
  77 }
  78 
  79 /*
  80   signal handler - redirects to registered signals
  81 */
  82 static void tevent_common_signal_handler(int signum)
     /* [<][>][^][v][top][bottom][index][help] */
  83 {
  84         char c = 0;
  85         ssize_t res;
  86         struct tevent_common_signal_list *sl;
  87         struct tevent_context *ev = NULL;
  88         int saved_errno = errno;
  89 
  90         SIG_INCREMENT(sig_state->signal_count[signum]);
  91         SIG_INCREMENT(sig_state->got_signal);
  92 
  93         /* Write to each unique event context. */
  94         for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
  95                 if (sl->se->event_ctx && sl->se->event_ctx != ev) {
  96                         ev = sl->se->event_ctx;
  97                         /* doesn't matter if this pipe overflows */
  98                         res = write(ev->pipe_fds[1], &c, 1);
  99                 }
 100         }
 101 
 102         errno = saved_errno;
 103 }
 104 
 105 #ifdef SA_SIGINFO
 106 /*
 107   signal handler with SA_SIGINFO - redirects to registered signals
 108 */
 109 static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
     /* [<][>][^][v][top][bottom][index][help] */
 110                                               void *uctx)
 111 {
 112         uint32_t count = sig_count(sig_state->signal_count[signum]);
 113         /* sig_state->signal_count[signum].seen % SA_INFO_QUEUE_COUNT
 114          * is the base of the unprocessed signals in the ringbuffer. */
 115         uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
 116                                 SA_INFO_QUEUE_COUNT;
 117         sig_state->sig_info[signum][ofs] = *info;
 118 
 119         tevent_common_signal_handler(signum);
 120 
 121         /* handle SA_SIGINFO */
 122         if (count+1 == SA_INFO_QUEUE_COUNT) {
 123                 /* we've filled the info array - block this signal until
 124                    these ones are delivered */
 125                 sigset_t set;
 126                 sigemptyset(&set);
 127                 sigaddset(&set, signum);
 128                 sigprocmask(SIG_BLOCK, &set, NULL);
 129                 SIG_INCREMENT(sig_state->sig_blocked[signum]);
 130         }
 131 }
 132 #endif
 133 
 134 static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
     /* [<][>][^][v][top][bottom][index][help] */
 135 {
 136         if (sig_state->sig_handlers[sl->se->signum]) {
 137                 DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
 138         }
 139         return 0;
 140 }
 141 
 142 /*
 143   destroy a signal event
 144 */
 145 static int tevent_signal_destructor(struct tevent_signal *se)
     /* [<][>][^][v][top][bottom][index][help] */
 146 {
 147         struct tevent_common_signal_list *sl;
 148         sl = talloc_get_type(se->additional_data,
 149                              struct tevent_common_signal_list);
 150 
 151         if (se->event_ctx) {
 152                 DLIST_REMOVE(se->event_ctx->signal_events, se);
 153         }
 154 
 155         talloc_free(sl);
 156 
 157         if (sig_state->sig_handlers[se->signum] == NULL) {
 158                 /* restore old handler, if any */
 159                 if (sig_state->oldact[se->signum]) {
 160                         sigaction(se->signum, sig_state->oldact[se->signum], NULL);
 161                         sig_state->oldact[se->signum] = NULL;
 162                 }
 163 #ifdef SA_SIGINFO
 164                 if (se->sa_flags & SA_SIGINFO) {
 165                         if (sig_state->sig_info[se->signum]) {
 166                                 talloc_free(sig_state->sig_info[se->signum]);
 167                                 sig_state->sig_info[se->signum] = NULL;
 168                         }
 169                 }
 170 #endif
 171         }
 172 
 173         return 0;
 174 }
 175 
 176 /*
 177   this is part of the pipe hack needed to avoid the signal race condition
 178 */
 179 static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
     /* [<][>][^][v][top][bottom][index][help] */
 180                                 uint16_t flags, void *_private)
 181 {
 182         char c[16];
 183         ssize_t res;
 184         /* its non-blocking, doesn't matter if we read too much */
 185         res = read(fde->fd, c, sizeof(c));
 186 }
 187 
 188 /*
 189   add a signal event
 190   return NULL on failure (memory allocation error)
 191 */
 192 struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
     /* [<][>][^][v][top][bottom][index][help] */
 193                                                TALLOC_CTX *mem_ctx,
 194                                                int signum,
 195                                                int sa_flags,
 196                                                tevent_signal_handler_t handler,
 197                                                void *private_data,
 198                                                const char *handler_name,
 199                                                const char *location)
 200 {
 201         struct tevent_signal *se;
 202         struct tevent_common_signal_list *sl;
 203         sigset_t set, oldset;
 204 
 205         if (signum >= NUM_SIGNALS) {
 206                 errno = EINVAL;
 207                 return NULL;
 208         }
 209 
 210         /* the sig_state needs to be on a global context as it can last across
 211            multiple event contexts */
 212         if (sig_state == NULL) {
 213                 sig_state = talloc_zero(talloc_autofree_context(), struct sig_state);
 214                 if (sig_state == NULL) {
 215                         return NULL;
 216                 }
 217         }
 218 
 219         se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
 220         if (se == NULL) return NULL;
 221 
 222         se->event_ctx           = ev;
 223         se->signum              = signum;
 224         se->sa_flags            = sa_flags;
 225         se->handler             = handler;
 226         se->private_data        = private_data;
 227         se->handler_name        = handler_name;
 228         se->location            = location;
 229         se->additional_data     = NULL;
 230 
 231         sl = talloc(se, struct tevent_common_signal_list);
 232         if (!sl) {
 233                 talloc_free(se);
 234                 return NULL;
 235         }
 236         sl->se = se;
 237         se->additional_data     = sl;
 238 
 239         /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
 240         if (!talloc_reference(se, sig_state)) {
 241                 talloc_free(se);
 242                 return NULL;
 243         }
 244 
 245         /* we need to setup the pipe hack handler if not already
 246            setup */
 247         if (ev->pipe_fde == NULL) {
 248                 if (pipe(ev->pipe_fds) == -1) {
 249                         talloc_free(se);
 250                         return NULL;
 251                 }
 252                 ev_set_blocking(ev->pipe_fds[0], false);
 253                 ev_set_blocking(ev->pipe_fds[1], false);
 254                 ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
 255                                              TEVENT_FD_READ,
 256                                              signal_pipe_handler, NULL);
 257                 if (!ev->pipe_fde) {
 258                         close(ev->pipe_fds[0]);
 259                         close(ev->pipe_fds[1]);
 260                         talloc_free(se);
 261                         return NULL;
 262                 }
 263         }
 264 
 265         /* only install a signal handler if not already installed */
 266         if (sig_state->sig_handlers[signum] == NULL) {
 267                 struct sigaction act;
 268                 ZERO_STRUCT(act);
 269                 act.sa_handler = tevent_common_signal_handler;
 270                 act.sa_flags = sa_flags;
 271 #ifdef SA_SIGINFO
 272                 if (sa_flags & SA_SIGINFO) {
 273                         act.sa_handler   = NULL;
 274                         act.sa_sigaction = tevent_common_signal_handler_info;
 275                         if (sig_state->sig_info[signum] == NULL) {
 276                                 sig_state->sig_info[signum] = talloc_zero_array(sig_state, siginfo_t, SA_INFO_QUEUE_COUNT);
 277                                 if (sig_state->sig_info[signum] == NULL) {
 278                                         talloc_free(se);
 279                                         return NULL;
 280                                 }
 281                         }
 282                 }
 283 #endif
 284                 sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
 285                 if (sig_state->oldact[signum] == NULL) {
 286                         talloc_free(se);
 287                         return NULL;                    
 288                 }
 289                 if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
 290                         talloc_free(se);
 291                         return NULL;
 292                 }
 293         }
 294 
 295         DLIST_ADD(se->event_ctx->signal_events, se);
 296 
 297         /* Make sure the signal doesn't come in while we're mangling list. */
 298         sigemptyset(&set);
 299         sigaddset(&set, signum);
 300         sigprocmask(SIG_BLOCK, &set, &oldset);
 301         DLIST_ADD(sig_state->sig_handlers[signum], sl);
 302         sigprocmask(SIG_SETMASK, &oldset, NULL);
 303 
 304         talloc_set_destructor(se, tevent_signal_destructor);
 305         talloc_set_destructor(sl, tevent_common_signal_list_destructor);
 306 
 307         return se;
 308 }
 309 
 310 
 311 /*
 312   check if a signal is pending
 313   return != 0 if a signal was pending
 314 */
 315 int tevent_common_check_signal(struct tevent_context *ev)
     /* [<][>][^][v][top][bottom][index][help] */
 316 {
 317         int i;
 318 
 319         if (!sig_state || !SIG_PENDING(sig_state->got_signal)) {
 320                 return 0;
 321         }
 322         
 323         for (i=0;i<NUM_SIGNALS+1;i++) {
 324                 struct tevent_common_signal_list *sl, *next;
 325                 struct sigcounter counter = sig_state->signal_count[i];
 326                 uint32_t count = sig_count(counter);
 327 #ifdef SA_SIGINFO
 328                 /* Ensure we null out any stored siginfo_t entries
 329                  * after processing for debugging purposes. */
 330                 bool clear_processed_siginfo = false;
 331 #endif
 332 
 333                 if (count == 0) {
 334                         continue;
 335                 }
 336                 for (sl=sig_state->sig_handlers[i];sl;sl=next) {
 337                         struct tevent_signal *se = sl->se;
 338                         next = sl->next;
 339 #ifdef SA_SIGINFO
 340                         if (se->sa_flags & SA_SIGINFO) {
 341                                 uint32_t j;
 342 
 343                                 clear_processed_siginfo = true;
 344 
 345                                 for (j=0;j<count;j++) {
 346                                         /* sig_state->signal_count[i].seen
 347                                          * % SA_INFO_QUEUE_COUNT is
 348                                          * the base position of the unprocessed
 349                                          * signals in the ringbuffer. */
 350                                         uint32_t ofs = (counter.seen + j)
 351                                                 % SA_INFO_QUEUE_COUNT;
 352                                         se->handler(ev, se, i, 1,
 353                                                     (void*)&sig_state->sig_info[i][ofs], 
 354                                                     se->private_data);
 355                                 }
 356                                 if (se->sa_flags & SA_RESETHAND) {
 357                                         talloc_free(se);
 358                                 }
 359                                 continue;
 360                         }
 361 #endif
 362                         se->handler(ev, se, i, count, NULL, se->private_data);
 363                         if (se->sa_flags & SA_RESETHAND) {
 364                                 talloc_free(se);
 365                         }
 366                 }
 367 
 368 #ifdef SA_SIGINFO
 369                 if (clear_processed_siginfo) {
 370                         uint32_t j;
 371                         for (j=0;j<count;j++) {
 372                                 uint32_t ofs = (counter.seen + j)
 373                                         % SA_INFO_QUEUE_COUNT;
 374                                 memset((void*)&sig_state->sig_info[i][ofs],
 375                                         '\0',
 376                                         sizeof(siginfo_t));
 377                         }
 378                 }
 379 #endif
 380 
 381                 SIG_SEEN(sig_state->signal_count[i], count);
 382                 SIG_SEEN(sig_state->got_signal, count);
 383 
 384 #ifdef SA_SIGINFO
 385                 if (SIG_PENDING(sig_state->sig_blocked[i])) {
 386                         /* We'd filled the queue, unblock the
 387                            signal now the queue is empty again.
 388                            Note we MUST do this after the
 389                            SIG_SEEN(sig_state->signal_count[i], count)
 390                            call to prevent a new signal running
 391                            out of room in the sig_state->sig_info[i][]
 392                            ring buffer. */
 393                         sigset_t set;
 394                         sigemptyset(&set);
 395                         sigaddset(&set, i);
 396                         SIG_SEEN(sig_state->sig_blocked[i],
 397                                  sig_count(sig_state->sig_blocked[i]));
 398                         sigprocmask(SIG_UNBLOCK, &set, NULL);
 399                 }
 400 #endif
 401         }
 402 
 403         return 1;
 404 }
 405 
 406 void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
     /* [<][>][^][v][top][bottom][index][help] */
 407 {
 408         struct tevent_common_signal_list *sl;
 409         sl = talloc_get_type(se->additional_data,
 410                              struct tevent_common_signal_list);
 411 
 412         tevent_common_signal_list_destructor(sl);
 413 
 414         if (sig_state->sig_handlers[se->signum] == NULL) {
 415                 if (sig_state->oldact[se->signum]) {
 416                         sigaction(se->signum, sig_state->oldact[se->signum], NULL);
 417                         sig_state->oldact[se->signum] = NULL;
 418                 }
 419         }
 420         return;
 421 }

/* [<][>][^][v][top][bottom][index][help] */