Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

sigsafe.c

Go to the documentation of this file.
00001 
00010 #include "sigsafe_internal.h"
00011 #ifdef _THREAD_SAFE
00012 #include <pthread.h>
00013 #endif
00014 #include <assert.h>
00015 #include <stdlib.h>
00016 #include <errno.h>
00017 
00018 #ifdef _THREAD_SAFE
00019 PRIVATE_DEC(pthread_key_t sigsafe_key_) = 0;
00020 static pthread_once_t sigsafe_once = PTHREAD_ONCE_INIT;
00021 #else
00022 PRIVATE_DEC(struct sigsafe_tsd_* sigsafe_data_) = 0;
00023 static int sigsafe_inited;
00024 #endif
00025 
00026 static sigsafe_user_handler_t user_handlers[SIGSAFE_SIGMAX];
00027 
00028 #define SYSCALL(name, args) \
00029         PRIVATE_DEF(void sigsafe_##name##_minjmp_(void)); \
00030         PRIVATE_DEF(void sigsafe_##name##_maxjmp_(void)); \
00031         PRIVATE_DEF(void sigsafe_##name##_jmpto_ (void));
00032 #define MACH_SYSCALL(name, args) SYSCALL(name, args)
00033 #include "syscalls.h"
00034 #undef SYSCALL
00035 
00036 #define SYSCALL(name, args) \
00037         { sigsafe_##name##_minjmp_, \
00038           sigsafe_##name##_maxjmp_, \
00039           sigsafe_##name##_jmpto_ },
00040 PRIVATE_DEC(struct sigsafe_syscall_ sigsafe_syscalls_[]) = {
00041 #include "syscalls.h"
00042     { NULL, NULL, NULL }
00043 };
00044 #undef SYSCALL
00045 #undef MACH_SYSCALL
00046 
00047 #ifdef SIGSAFE_NO_SIGINFO
00048 static void sighandler(int signum, int code, struct sigcontext *ctx) {
00049 #else
00050 static void sighandler(int signum, siginfo_t *siginfo, ucontext_t *ctx) {
00051 #endif
00052 #ifdef _THREAD_SAFE
00053     struct sigsafe_tsd_ *sigsafe_data_ = pthread_getspecific(sigsafe_key_);
00054 #endif
00055     assert(0 < signum && signum <= SIGSAFE_SIGMAX);
00056 #ifdef SIGSAFE_DEBUG_SIGNAL
00057     write(2, "[S]", 3);
00058 #endif
00059     if (sigsafe_data_ != NULL) {
00060         if (user_handlers[signum - 1] != NULL) {
00061 #ifdef SIGSAFE_NO_SIGINFO
00062             user_handlers[signum - 1](signum, code, ctx,
00063                                       sigsafe_data_->user_data);
00064 #else
00065             user_handlers[signum - 1](signum, siginfo, ctx,
00066                                       sigsafe_data_->user_data);
00067 #endif
00068         }
00069         sigsafe_data_->signal_received = 1;
00070         sigsafe_handler_for_platform_(ctx);
00071     }
00072 }
00073 
00074 #ifdef _THREAD_SAFE
00075 static void tsd_destructor(void* tsd_v) {
00076     struct sigsafe_tsd_ *sigsafe_data_ = (struct sigsafe_tsd_*) tsd_v;
00077     if (sigsafe_data_->destructor != NULL) {
00078         sigsafe_data_->destructor(sigsafe_data_->user_data);
00079     }
00080     free(sigsafe_data_);
00081 }
00082 #endif
00083 
00084 static void sigsafe_init(void) {
00085     /* "volatile" so our seemingly-useless references aren't optimized away. */
00086     volatile void *fp;
00087 
00088 #ifdef _THREAD_SAFE
00089     pthread_key_create(&sigsafe_key_, &tsd_destructor);
00090 #endif
00091 
00092     /*
00093      * XXX
00094      * bbraun and landorf on #opendarwin tell me that dyld commonly deadlocks
00095      * in the signal handlers; it is not reentrant. Workaround: ensure all
00096      * symbols we reference in our signal handler are evaluated beforehand.
00097      * Should test this and note it in the documentation, so the userhandler
00098      * does the same thing.
00099      */
00100 #ifdef _THREAD_SAFE
00101     fp = &pthread_getspecific;
00102 #endif
00103     fp = &sigsafe_handler_for_platform_;
00104     fp = &write;
00105 }
00106 
00107 int sigsafe_install_handler(int signum, sigsafe_user_handler_t handler) {
00108     struct sigaction sa;
00109 
00110     assert(0 < signum && signum <= SIGSAFE_SIGMAX);
00111 #ifdef _THREAD_SAFE
00112     pthread_once(&sigsafe_once, &sigsafe_init);
00113 #else
00114     if (!sigsafe_inited) {
00115         sigsafe_inited = 1;
00116         sigsafe_init();
00117     }
00118 #endif
00119     user_handlers[signum - 1] = handler;
00120 #ifdef SIGSAFE_NO_SIGINFO
00121     sa.sa_handler = (void (*)(int)) &sighandler;
00122     sa.sa_flags = SA_RESTART;
00123 #else
00124     sa.sa_sigaction = (void*) &sighandler;
00125     sa.sa_flags = SA_RESTART | SA_SIGINFO;
00126 #endif
00127 
00128     /*
00129      * Mask all signals to ensure a sigsafe handler never interrupts another.
00130      */
00131     sigfillset(&sa.sa_mask);
00132 
00133     if (sigaction(signum, &sa, NULL) != 0) {
00134         return -errno;
00135     }
00136     return 0;
00137 }
00138 
00139 int sigsafe_install_tsd(intptr_t user_data, void (*destructor)(intptr_t)) {
00140 #ifdef _THREAD_SAFE
00141     struct sigsafe_tsd_ *sigsafe_data_ = NULL;
00142     int retval;
00143 
00144     assert(pthread_getspecific(sigsafe_key_) == NULL);
00145 #else
00146     assert(sigsafe_data_ == NULL);
00147 #endif
00148 
00149     sigsafe_data_ = (struct sigsafe_tsd_*) malloc(sizeof(struct sigsafe_tsd_));
00150     if (sigsafe_data_ == NULL) {
00151         return -ENOMEM;
00152     }
00153 
00154     sigsafe_data_->signal_received = 0;
00155     sigsafe_data_->user_data = user_data;
00156     sigsafe_data_->destructor = destructor;
00157 
00158 #ifdef _THREAD_SAFE
00159     retval = pthread_setspecific(sigsafe_key_, sigsafe_data_);
00160     if (retval != 0) {
00161         free(sigsafe_data_);
00162         return -retval;
00163     }
00164 #endif
00165 
00166     return 0;
00167 }
00168 
00169 intptr_t sigsafe_clear_received(void) {
00170 #ifdef _THREAD_SAFE
00171     struct sigsafe_tsd_ *sigsafe_data_;
00172 
00173     sigsafe_data_ = (struct sigsafe_tsd_*) pthread_getspecific(sigsafe_key_);
00174 #endif
00175     assert(sigsafe_data_ != NULL);
00176     sigsafe_data_->signal_received = 0;
00177     return sigsafe_data_->user_data;
00178 }

Generated on Fri Feb 4 11:13:32 2005 for sigsafe by doxygen 1.3.5