github.com/afumu/libc@v0.0.6/musl/src/signal/sigaction.c (about)

     1  #include <signal.h>
     2  #include <errno.h>
     3  #include <string.h>
     4  #include "syscall.h"
     5  #include "pthread_impl.h"
     6  #include "libc.h"
     7  #include "lock.h"
     8  #include "ksigaction.h"
     9  
    10  static volatile int dummy_lock[1] = { 0 };
    11  
    12  extern hidden volatile int __abort_lock[1];
    13  
    14  weak_alias(dummy_lock, __abort_lock);
    15  
    16  static int unmask_done;
    17  static unsigned long handler_set[_NSIG/(8*sizeof(long))];
    18  
    19  void __get_handler_set(sigset_t *set)
    20  {
    21  	memcpy(set, handler_set, sizeof handler_set);
    22  }
    23  
    24  volatile int __eintr_valid_flag;
    25  
    26  int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
    27  {
    28  	struct k_sigaction ksa, ksa_old;
    29  	unsigned long set[_NSIG/(8*sizeof(long))];
    30  	if (sa) {
    31  		if ((uintptr_t)sa->sa_handler > 1UL) {
    32  			a_or_l(handler_set+(sig-1)/(8*sizeof(long)),
    33  				1UL<<(sig-1)%(8*sizeof(long)));
    34  
    35  			/* If pthread_create has not yet been called,
    36  			 * implementation-internal signals might not
    37  			 * yet have been unblocked. They must be
    38  			 * unblocked before any signal handler is
    39  			 * installed, so that an application cannot
    40  			 * receive an illegal sigset_t (with them
    41  			 * blocked) as part of the ucontext_t passed
    42  			 * to the signal handler. */
    43  			if (!libc.threaded && !unmask_done) {
    44  				__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
    45  					SIGPT_SET, 0, _NSIG/8);
    46  				unmask_done = 1;
    47  			}
    48  
    49  			if (!(sa->sa_flags & SA_RESTART)) {
    50  				a_store(&__eintr_valid_flag, 1);
    51  			}
    52  		}
    53  		/* Changing the disposition of SIGABRT to anything but
    54  		 * SIG_DFL requires a lock, so that it cannot be changed
    55  		 * while abort is terminating the process after simply
    56  		 * calling raise(SIGABRT) failed to do so. */
    57  		if (sa->sa_handler != SIG_DFL && sig == SIGABRT) {
    58  			__block_all_sigs(&set);
    59  			LOCK(__abort_lock);
    60  		}
    61  		ksa.handler = sa->sa_handler;
    62  		ksa.flags = sa->sa_flags | SA_RESTORER;
    63  		ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
    64  		memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);
    65  	}
    66  	int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8);
    67  	if (sig == SIGABRT && sa && sa->sa_handler != SIG_DFL) {
    68  		UNLOCK(__abort_lock);
    69  		__restore_sigs(&set);
    70  	}
    71  	if (old && !r) {
    72  		old->sa_handler = ksa_old.handler;
    73  		old->sa_flags = ksa_old.flags;
    74  		memcpy(&old->sa_mask, &ksa_old.mask, _NSIG/8);
    75  	}
    76  	return __syscall_ret(r);
    77  }
    78  
    79  int __sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
    80  {
    81  	if (sig-32U < 3 || sig-1U >= _NSIG-1) {
    82  		errno = EINVAL;
    83  		return -1;
    84  	}
    85  	return __libc_sigaction(sig, sa, old);
    86  }
    87  
    88  weak_alias(__sigaction, sigaction);