#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX) // Fix signal macro compatibility with signal.h of MS VC++: #ifdef WIN32 #define signal win32_signal #endif #include // Get back Perl marcro value defined ad XSUB.h: #ifdef WIN32 #define signal PerlProc_signal #endif #endif static struct pe_watcher_vtbl pe_signal_vtbl; /* GLOBALS: Sigvalid Sigring Sigstat Sigslot */ static U32 Sigvalid[1+NSIG/32]; /*assume 32bit; doesn't matter*/ #define PE_SIGVALID(sig) (Sigvalid[sig>>5] & (1 << ((sig) & 0x1f))) #define PE_SIGVALID_off(sig) Sigvalid[sig>>5] &= ~(1 << ((sig) & 0x1f)) struct pe_sig_stat { U32 Hits; U16 hits[NSIG]; }; typedef struct pe_sig_stat pe_sig_stat; static int Sigslot; static pe_sig_stat Sigstat[2]; static pe_ring Sigring[NSIG]; /* /GLOBALS */ static Signal_t process_sighandler(int sig) { pe_sig_stat *st = &Sigstat[Sigslot]; ++st->Hits; ++st->hits[sig]; } static pe_watcher *pe_signal_allocate(HV *stash, SV *temple) { pe_signal *ev; EvNew(5, ev, 1, pe_signal); ev->base.vtbl = &pe_signal_vtbl; PE_RING_INIT(&ev->sring, ev); ev->signal = 0; pe_watcher_init(&ev->base, stash, temple); WaREPEAT_on(ev); WaINVOKE1_off(ev); return (pe_watcher*) ev; } static void pe_signal_dtor(pe_watcher *ev) { pe_watcher_dtor(ev); EvFree(5, ev); } static char *pe_signal_start(pe_watcher *_ev, int repeat) { pe_signal *ev = (pe_signal*) _ev; int sig = ev->signal; if (!_ev->callback) return "without callback"; if (sig == 0) return "without signal"; if (PE_RING_EMPTY(&Sigring[sig])) rsignal(sig, (Sighandler_t)process_sighandler); PE_RING_UNSHIFT(&ev->sring, &Sigring[sig]); return 0; } static void pe_signal_stop(pe_watcher *_ev) { pe_signal *ev = (pe_signal*) _ev; int sig = ev->signal; PE_RING_DETACH(&ev->sring); if (PE_RING_EMPTY(&Sigring[sig])) { rsignal(sig, (Sighandler_t)SIG_DFL); Sigstat[0].hits[sig] = 0; Sigstat[1].hits[sig] = 0; } } WKEYMETH(_signal_signal) { pe_signal *sg = (pe_signal*) ev; if (nval) { STRLEN n_a; int active = WaPOLLING(ev); int sig = whichsig(SvPV(nval, n_a)); /*warn("whichsig(%s) = %d", SvPV(nval,na), sig); /**/ if (sig == 0) croak("Unrecognized signal '%s'", SvPV(nval, n_a)); if (!PE_SIGVALID(sig)) croak("Signal '%s' cannot be caught", SvPV(nval, n_a)); if (active) pe_watcher_off(ev); sg->signal = sig; if (active) pe_watcher_on(ev, 0); } { dSP; XPUSHs(sg->signal > 0? sv_2mortal(newSVpv(PL_sig_name[sg->signal],0)) : &PL_sv_undef); PUTBACK; } } static void _signal_asynccheck(pe_sig_stat *st) { int xx, got; pe_watcher *wa; for (xx = 1; xx < NSIG; xx++) { if (!st->hits[xx]) continue; got = st->hits[xx]; wa = (pe_watcher*) Sigring[xx].next->self; while (wa) { pe_event *ev = (*wa->vtbl->new_event)(wa); ev->hits += got; queueEvent(ev); wa = (pe_watcher*) ((pe_signal*)wa)->sring.next->self; } st->hits[xx] = 0; } Zero(st, 1, struct pe_sig_stat); } /* This implementation gives no race conditions, assuming no kernel-level threads. */ static void pe_signal_asynccheck() { pe_sig_stat *st; Sigslot = 1; st = &Sigstat[0]; if (st->Hits) _signal_asynccheck(st); Sigslot = 0; st = &Sigstat[1]; if (st->Hits) _signal_asynccheck(st); } static void boot_signal() { int xx; int sig; char **sigp; /* it is crufty to hardcode this list */ static char *nohandle[] = { "KILL", "STOP", "ZERO", 0 }; pe_watcher_vtbl *vt = &pe_signal_vtbl; Zero(&Sigstat[0], 1, pe_sig_stat); Zero(&Sigstat[1], 1, pe_sig_stat); Sigslot = 0; for (xx=0; xx < NSIG; xx++) { PE_RING_INIT(&Sigring[xx], 0); } memset(Sigvalid, ~0, sizeof(Sigvalid)); PE_SIGVALID_off(0); sigp = nohandle; while (*sigp) { sig = whichsig(*sigp); if (sig) PE_SIGVALID_off(sig); ++sigp; } memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_signal_dtor; vt->start = pe_signal_start; vt->stop = pe_signal_stop; pe_register_vtbl(vt, gv_stashpv("Event::signal",1), &event_vtbl); }