LCOV - code coverage report
Current view: top level - lib/tevent - tevent_signal.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 159 203 78.3 %
Date: 2024-04-21 15:09:00 Functions: 11 13 84.6 %

          Line data    Source code
       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             : #define TEVENT_DEPRECATED 1
      30             : #include "tevent.h"
      31             : #include "tevent_internal.h"
      32             : #include "tevent_util.h"
      33             : 
      34             : /* maximum number of SA_SIGINFO signals to hold in the queue.
      35             :   NB. This *MUST* be a power of 2, in order for the ring buffer
      36             :   wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
      37             :   for this. */
      38             : 
      39             : #define TEVENT_SA_INFO_QUEUE_COUNT 256
      40             : 
      41           0 : size_t tevent_num_signals(void)
      42             : {
      43           0 :         return TEVENT_NUM_SIGNALS;
      44             : }
      45             : 
      46           0 : size_t tevent_sa_info_queue_count(void)
      47             : {
      48           0 :         return TEVENT_SA_INFO_QUEUE_COUNT;
      49             : }
      50             : 
      51             : struct tevent_sigcounter {
      52             :         uint32_t count;
      53             :         uint32_t seen;
      54             : };
      55             : 
      56             : #if defined(HAVE___SYNC_FETCH_AND_ADD)
      57             : #define TEVENT_SIG_INCREMENT(s) __sync_fetch_and_add(&((s).count), 1)
      58             : #elif defined(HAVE_ATOMIC_ADD_32)
      59             : #define TEVENT_SIG_INCREMENT(s) atomic_add_32(&((s).count), 1)
      60             : #else
      61             : #define TEVENT_SIG_INCREMENT(s) (s).count++
      62             : #endif
      63             : #define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
      64             : #define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
      65             : 
      66             : struct tevent_common_signal_list {
      67             :         struct tevent_common_signal_list *prev, *next;
      68             :         struct tevent_signal *se;
      69             : };
      70             : 
      71             : /*
      72             :   the poor design of signals means that this table must be static global
      73             : */
      74             : static struct tevent_sig_state {
      75             :         struct tevent_common_signal_list *sig_handlers[TEVENT_NUM_SIGNALS+1];
      76             :         struct sigaction *oldact[TEVENT_NUM_SIGNALS+1];
      77             :         struct tevent_sigcounter signal_count[TEVENT_NUM_SIGNALS+1];
      78             :         struct tevent_sigcounter got_signal;
      79             : #ifdef SA_SIGINFO
      80             :         /* with SA_SIGINFO we get quite a lot of info per signal */
      81             :         siginfo_t *sig_info[TEVENT_NUM_SIGNALS+1];
      82             :         struct tevent_sigcounter sig_blocked[TEVENT_NUM_SIGNALS+1];
      83             : #endif
      84             : } *sig_state;
      85             : 
      86             : /*
      87             :   return number of sigcounter events not processed yet
      88             : */
      89  2413611358 : static uint32_t tevent_sig_count(struct tevent_sigcounter s)
      90             : {
      91  2413611358 :         return s.count - s.seen;
      92             : }
      93             : 
      94             : /*
      95             :   signal handler - redirects to registered signals
      96             : */
      97    36279634 : static void tevent_common_signal_handler(int signum)
      98             : {
      99     2882503 :         struct tevent_common_signal_list *sl;
     100    36279634 :         struct tevent_context *ev = NULL;
     101    36279634 :         int saved_errno = errno;
     102             : 
     103    36279634 :         TEVENT_SIG_INCREMENT(sig_state->signal_count[signum]);
     104    36279634 :         TEVENT_SIG_INCREMENT(sig_state->got_signal);
     105             : 
     106             :         /* Write to each unique event context. */
     107    72559272 :         for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
     108    36279638 :                 if (sl->se->event_ctx && sl->se->event_ctx != ev) {
     109    36279634 :                         ev = sl->se->event_ctx;
     110    36279634 :                         tevent_common_wakeup(ev);
     111             :                 }
     112             :         }
     113             : 
     114    36279634 :         errno = saved_errno;
     115    36279634 : }
     116             : 
     117             : #ifdef SA_SIGINFO
     118             : /*
     119             :   signal handler with SA_SIGINFO - redirects to registered signals
     120             : */
     121     1317003 : static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
     122             :                                               void *uctx)
     123             : {
     124     1317003 :         uint32_t count = tevent_sig_count(sig_state->signal_count[signum]);
     125             :         /* sig_state->signal_count[signum].seen % TEVENT_SA_INFO_QUEUE_COUNT
     126             :          * is the base of the unprocessed signals in the ringbuffer. */
     127     1317003 :         uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
     128             :                                 TEVENT_SA_INFO_QUEUE_COUNT;
     129     1317003 :         sig_state->sig_info[signum][ofs] = *info;
     130             : 
     131     1317003 :         tevent_common_signal_handler(signum);
     132             : 
     133             :         /* handle SA_SIGINFO */
     134     1317003 :         if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
     135             :                 /* we've filled the info array - block this signal until
     136             :                    these ones are delivered */
     137             : #ifdef HAVE_UCONTEXT_T
     138             :                 /*
     139             :                  * This is the only way for this to work.
     140             :                  * By default signum is blocked inside this
     141             :                  * signal handler using a temporary mask,
     142             :                  * but what we really need to do now is
     143             :                  * block it in the callers mask, so it
     144             :                  * stays blocked when the temporary signal
     145             :                  * handler mask is replaced when we return
     146             :                  * from here. The callers mask can be found
     147             :                  * in the ucontext_t passed in as the
     148             :                  * void *uctx argument.
     149             :                  */
     150           0 :                 ucontext_t *ucp = (ucontext_t *)uctx;
     151           0 :                 sigaddset(&ucp->uc_sigmask, signum);
     152             : #else
     153             :                 /*
     154             :                  * WARNING !!! WARNING !!!!
     155             :                  *
     156             :                  * This code doesn't work.
     157             :                  * By default signum is blocked inside this
     158             :                  * signal handler, but calling sigprocmask
     159             :                  * modifies the temporary signal mask being
     160             :                  * used *inside* this handler, which will be
     161             :                  * replaced by the callers signal mask once
     162             :                  * we return from here. See Samba
     163             :                  * bug #9550 for details.
     164             :                  */
     165             :                 sigset_t set;
     166             :                 sigemptyset(&set);
     167             :                 sigaddset(&set, signum);
     168             :                 sigprocmask(SIG_BLOCK, &set, NULL);
     169             : #endif
     170           0 :                 TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
     171             :         }
     172     1317003 : }
     173             : #endif
     174             : 
     175      256267 : static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
     176             : {
     177      256267 :         if (sig_state->sig_handlers[sl->se->signum]) {
     178      256267 :                 DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
     179             :         }
     180      256267 :         return 0;
     181             : }
     182             : 
     183             : /*
     184             :   destroy a signal event
     185             : */
     186      256267 : static int tevent_signal_destructor(struct tevent_signal *se)
     187             : {
     188      256267 :         if (se->destroyed) {
     189           0 :                 tevent_common_check_double_free(se, "tevent_signal double free");
     190           0 :                 goto done;
     191             :         }
     192      256267 :         se->destroyed = true;
     193             : 
     194      256267 :         TALLOC_FREE(se->additional_data);
     195             : 
     196      256267 :         if (se->event_ctx != NULL) {
     197      158047 :                 tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_DETACH);
     198      158047 :                 DLIST_REMOVE(se->event_ctx->signal_events, se);
     199             :         }
     200             : 
     201      256267 :         if (sig_state->sig_handlers[se->signum] == NULL) {
     202             :                 /* restore old handler, if any */
     203      255443 :                 if (sig_state->oldact[se->signum]) {
     204      255443 :                         sigaction(se->signum, sig_state->oldact[se->signum], NULL);
     205      255443 :                         TALLOC_FREE(sig_state->oldact[se->signum]);
     206             :                 }
     207             : #ifdef SA_SIGINFO
     208      255443 :                 if (se->sa_flags & SA_SIGINFO) {
     209          21 :                         if (sig_state->sig_info[se->signum]) {
     210          21 :                                 TALLOC_FREE(sig_state->sig_info[se->signum]);
     211             :                         }
     212             :                 }
     213             : #endif
     214             :         }
     215             : 
     216      256267 :         se->event_ctx = NULL;
     217      256267 : done:
     218      256267 :         if (se->busy) {
     219          32 :                 return -1;
     220             :         }
     221      256227 :         se->wrapper = NULL;
     222             : 
     223      256227 :         return 0;
     224             : }
     225             : 
     226             : /*
     227             :   add a signal event
     228             :   return NULL on failure (memory allocation error)
     229             : */
     230      257917 : struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
     231             :                                                TALLOC_CTX *mem_ctx,
     232             :                                                int signum,
     233             :                                                int sa_flags,
     234             :                                                tevent_signal_handler_t handler,
     235             :                                                void *private_data,
     236             :                                                const char *handler_name,
     237             :                                                const char *location)
     238             : {
     239        4540 :         struct tevent_signal *se;
     240        4540 :         struct tevent_common_signal_list *sl;
     241        4540 :         sigset_t set, oldset;
     242        4540 :         int ret;
     243             : 
     244      257917 :         ret = tevent_common_wakeup_init(ev);
     245      257917 :         if (ret != 0) {
     246           0 :                 errno = ret;
     247           0 :                 return NULL;
     248             :         }
     249             : 
     250      257917 :         if (signum >= TEVENT_NUM_SIGNALS) {
     251           0 :                 errno = EINVAL;
     252           0 :                 return NULL;
     253             :         }
     254             : 
     255             :         /* the sig_state needs to be on a global context as it can last across
     256             :            multiple event contexts */
     257      257917 :         if (sig_state == NULL) {
     258       49023 :                 sig_state = talloc_zero(NULL, struct tevent_sig_state);
     259       49023 :                 if (sig_state == NULL) {
     260           0 :                         return NULL;
     261             :                 }
     262             :         }
     263             : 
     264      257917 :         se = talloc_zero(mem_ctx?mem_ctx:ev, struct tevent_signal);
     265      257917 :         if (se == NULL) return NULL;
     266             : 
     267      257917 :         sl = talloc_zero(se, struct tevent_common_signal_list);
     268      257917 :         if (!sl) {
     269           0 :                 talloc_free(se);
     270           0 :                 return NULL;
     271             :         }
     272      257917 :         sl->se = se;
     273             : 
     274      257917 :         *se = (struct tevent_signal) {
     275             :                 .event_ctx      = ev,
     276             :                 .signum         = signum,
     277             :                 .sa_flags       = sa_flags,
     278             :                 .handler        = handler,
     279             :                 .private_data   = private_data,
     280             :                 .handler_name   = handler_name,
     281             :                 .location       = location,
     282             :                 .additional_data= sl,
     283             :         };
     284             : 
     285             :         /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
     286      257917 :         if (!talloc_reference(se, sig_state)) {
     287           0 :                 talloc_free(se);
     288           0 :                 return NULL;
     289             :         }
     290             : 
     291             :         /* only install a signal handler if not already installed */
     292      257917 :         if (sig_state->sig_handlers[signum] == NULL) {
     293        4472 :                 struct sigaction act;
     294      257093 :                 ZERO_STRUCT(act);
     295      257093 :                 act.sa_handler = tevent_common_signal_handler;
     296      257093 :                 act.sa_flags = sa_flags;
     297             : #ifdef SA_SIGINFO
     298      257093 :                 if (sa_flags & SA_SIGINFO) {
     299          21 :                         act.sa_handler   = NULL;
     300          21 :                         act.sa_sigaction = tevent_common_signal_handler_info;
     301          21 :                         if (sig_state->sig_info[signum] == NULL) {
     302          42 :                                 sig_state->sig_info[signum] =
     303          21 :                                         talloc_zero_array(sig_state, siginfo_t,
     304             :                                                           TEVENT_SA_INFO_QUEUE_COUNT);
     305          21 :                                 if (sig_state->sig_info[signum] == NULL) {
     306           0 :                                         talloc_free(se);
     307           0 :                                         return NULL;
     308             :                                 }
     309             :                         }
     310             :                 }
     311             : #endif
     312      257093 :                 sig_state->oldact[signum] = talloc_zero(sig_state, struct sigaction);
     313      257093 :                 if (sig_state->oldact[signum] == NULL) {
     314           0 :                         talloc_free(se);
     315           0 :                         return NULL;
     316             :                 }
     317      257093 :                 if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
     318           0 :                         talloc_free(sig_state->oldact[signum]);
     319           0 :                         sig_state->oldact[signum] = NULL;
     320           0 :                         talloc_free(se);
     321           0 :                         return NULL;
     322             :                 }
     323             :         }
     324             : 
     325      257917 :         DLIST_ADD(se->event_ctx->signal_events, se);
     326             : 
     327             :         /* Make sure the signal doesn't come in while we're mangling list. */
     328      257917 :         sigemptyset(&set);
     329      257917 :         sigaddset(&set, signum);
     330      257917 :         sigprocmask(SIG_BLOCK, &set, &oldset);
     331      257917 :         tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_ATTACH);
     332      257917 :         DLIST_ADD(sig_state->sig_handlers[signum], sl);
     333      257917 :         sigprocmask(SIG_SETMASK, &oldset, NULL);
     334             : 
     335      257917 :         talloc_set_destructor(se, tevent_signal_destructor);
     336      257917 :         talloc_set_destructor(sl, tevent_common_signal_list_destructor);
     337             : 
     338      257917 :         return se;
     339             : }
     340             : 
     341    36277838 : int tevent_common_invoke_signal_handler(struct tevent_signal *se,
     342             :                                         int signum, int count, void *siginfo,
     343             :                                         bool *removed)
     344             : {
     345    36277838 :         struct tevent_context *handler_ev = se->event_ctx;
     346    36277838 :         bool remove = false;
     347             : 
     348    36277838 :         if (removed != NULL) {
     349     1317003 :                 *removed = false;
     350             :         }
     351             : 
     352    36277838 :         if (se->event_ctx == NULL) {
     353           0 :                 return 0;
     354             :         }
     355             : 
     356    36277838 :         se->busy = true;
     357    36277838 :         if (se->wrapper != NULL) {
     358           8 :                 handler_ev = se->wrapper->wrap_ev;
     359             : 
     360           8 :                 tevent_wrapper_push_use_internal(handler_ev, se->wrapper);
     361           8 :                 se->wrapper->ops->before_signal_handler(
     362           0 :                                                 se->wrapper->wrap_ev,
     363           0 :                                                 se->wrapper->private_state,
     364           0 :                                                 se->wrapper->main_ev,
     365             :                                                 se,
     366             :                                                 signum,
     367             :                                                 count,
     368             :                                                 siginfo,
     369             :                                                 se->handler_name,
     370             :                                                 se->location);
     371             :         }
     372    36277838 :         tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
     373    36277838 :         se->handler(handler_ev, se, signum, count, siginfo, se->private_data);
     374    36277732 :         if (se->wrapper != NULL) {
     375           8 :                 se->wrapper->ops->after_signal_handler(
     376           0 :                                                 se->wrapper->wrap_ev,
     377           0 :                                                 se->wrapper->private_state,
     378           0 :                                                 se->wrapper->main_ev,
     379             :                                                 se,
     380             :                                                 signum,
     381             :                                                 count,
     382             :                                                 siginfo,
     383             :                                                 se->handler_name,
     384             :                                                 se->location);
     385           8 :                 tevent_wrapper_pop_use_internal(handler_ev, se->wrapper);
     386             :         }
     387    36277732 :         se->busy = false;
     388             : 
     389             : #ifdef SA_RESETHAND
     390    36277732 :         if (se->sa_flags & SA_RESETHAND) {
     391           4 :                 remove = true;
     392             :         }
     393             : #endif
     394             : 
     395    36277732 :         if (se->destroyed) {
     396           9 :                 talloc_set_destructor(se, NULL);
     397           9 :                 remove = true;
     398             :         }
     399             : 
     400    36277732 :         if (remove) {
     401          13 :                 TALLOC_FREE(se);
     402          13 :                 if (removed != NULL) {
     403           0 :                         *removed = true;
     404             :                 }
     405             :         }
     406             : 
     407    33395226 :         return 0;
     408             : }
     409             : 
     410             : /*
     411             :   check if a signal is pending
     412             :   return != 0 if a signal was pending
     413             : */
     414   345999313 : int tevent_common_check_signal(struct tevent_context *ev)
     415             : {
     416    11165929 :         int i;
     417             : 
     418   345999313 :         if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
     419   301438021 :                 return 0;
     420             :         }
     421             : 
     422  2447255116 :         for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
     423   108019776 :                 struct tevent_common_signal_list *sl, *next;
     424  2412294355 :                 struct tevent_sigcounter counter = sig_state->signal_count[i];
     425  2412294355 :                 uint32_t count = tevent_sig_count(counter);
     426   108019776 :                 int ret;
     427             : #ifdef SA_SIGINFO
     428             :                 /* Ensure we null out any stored siginfo_t entries
     429             :                  * after processing for debugging purposes. */
     430  2412294355 :                 bool clear_processed_siginfo = false;
     431             : #endif
     432             : 
     433  2412294355 :                 if (count == 0) {
     434  2376016489 :                         continue;
     435             :                 }
     436    72555598 :                 for (sl=sig_state->sig_handlers[i];sl;sl=next) {
     437    36277838 :                         struct tevent_signal *se = sl->se;
     438             : 
     439    36277838 :                         next = sl->next;
     440             : 
     441             : #ifdef SA_SIGINFO
     442    36277838 :                         if (se->sa_flags & SA_SIGINFO) {
     443             :                                 uint32_t j;
     444             : 
     445     2634002 :                                 clear_processed_siginfo = true;
     446             : 
     447     2634006 :                                 for (j=0;j<count;j++) {
     448             :                                         /* sig_state->signal_count[i].seen
     449             :                                          * % TEVENT_SA_INFO_QUEUE_COUNT is
     450             :                                          * the base position of the unprocessed
     451             :                                          * signals in the ringbuffer. */
     452     1317003 :                                         uint32_t ofs = (counter.seen + j)
     453             :                                                 % TEVENT_SA_INFO_QUEUE_COUNT;
     454     1317003 :                                         bool removed = false;
     455             : 
     456     2634002 :                                         ret = tevent_common_invoke_signal_handler(
     457             :                                                 se, i, 1,
     458     1317003 :                                                 (void*)&sig_state->sig_info[i][ofs],
     459             :                                                 &removed);
     460     1317003 :                                         if (ret != 0) {
     461           0 :                                                 tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
     462             :                                         }
     463     1317003 :                                         if (removed) {
     464           0 :                                                 break;
     465             :                                         }
     466             :                                 }
     467     1317003 :                                 continue;
     468             :                         }
     469             : #endif
     470             : 
     471    34960835 :                         ret = tevent_common_invoke_signal_handler(se, i, count,
     472             :                                                                   NULL, NULL);
     473    34960729 :                         if (ret != 0) {
     474           0 :                                 tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
     475             :                         }
     476             :                 }
     477             : 
     478             : #ifdef SA_SIGINFO
     479    36277760 :                 if (clear_processed_siginfo && sig_state->sig_info[i] != NULL) {
     480             :                         uint32_t j;
     481     2634006 :                         for (j=0;j<count;j++) {
     482     1317003 :                                 uint32_t ofs = (counter.seen + j)
     483             :                                         % TEVENT_SA_INFO_QUEUE_COUNT;
     484     1317003 :                                 memset((void*)&sig_state->sig_info[i][ofs],
     485             :                                         '\0',
     486             :                                         sizeof(siginfo_t));
     487             :                         }
     488             :                 }
     489             : #endif
     490             : 
     491    36277760 :                 TEVENT_SIG_SEEN(sig_state->signal_count[i], count);
     492    36277760 :                 TEVENT_SIG_SEEN(sig_state->got_signal, count);
     493             : 
     494             : #ifdef SA_SIGINFO
     495    36277760 :                 if (TEVENT_SIG_PENDING(sig_state->sig_blocked[i])) {
     496             :                         /* We'd filled the queue, unblock the
     497             :                            signal now the queue is empty again.
     498             :                            Note we MUST do this after the
     499             :                            TEVENT_SIG_SEEN(sig_state->signal_count[i], count)
     500             :                            call to prevent a new signal running
     501             :                            out of room in the sig_state->sig_info[i][]
     502             :                            ring buffer. */
     503           0 :                         sigset_t set;
     504           0 :                         sigemptyset(&set);
     505           0 :                         sigaddset(&set, i);
     506           0 :                         TEVENT_SIG_SEEN(sig_state->sig_blocked[i],
     507             :                                  tevent_sig_count(sig_state->sig_blocked[i]));
     508           0 :                         sigprocmask(SIG_UNBLOCK, &set, NULL);
     509             :                 }
     510             : #endif
     511             :         }
     512             : 
     513    33395257 :         return 1;
     514             : }
     515             : 
     516       98220 : void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
     517             : {
     518       98220 :         tevent_signal_destructor(se);
     519       98220 :         talloc_set_destructor(se, NULL);
     520       98220 :         return;
     521             : }
     522             : 
     523         347 : void tevent_signal_set_tag(struct tevent_signal *se, uint64_t tag)
     524             : {
     525         347 :         if (se == NULL) {
     526           0 :                 return;
     527             :         }
     528             : 
     529         347 :         se->tag = tag;
     530             : }
     531             : 
     532          50 : uint64_t tevent_signal_get_tag(const struct tevent_signal *se)
     533             : {
     534          50 :         if (se == NULL) {
     535           0 :                 return 0;
     536             :         }
     537             : 
     538          50 :         return se->tag;
     539             : }

Generated by: LCOV version 1.14