File Coverage

c/signal.c
Criterion Covered Total %
statement 93 96 96.8
branch 30 46 65.2
condition n/a
subroutine n/a
pod n/a
total 123 142 86.6


line stmt bran cond sub pod time code
1             #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
2              
3             // Fix signal macro compatibility with signal.h of MS VC++:
4             #ifdef WIN32
5             #define signal win32_signal
6             #endif
7              
8             #include
9              
10             // Get back Perl marcro value defined ad XSUB.h:
11             #ifdef WIN32
12             #define signal PerlProc_signal
13             #endif
14              
15             #endif
16              
17             static struct pe_watcher_vtbl pe_signal_vtbl;
18              
19             /* GLOBALS: Sigvalid Sigring Sigstat Sigslot */
20              
21             static U32 Sigvalid[1+NSIG/32]; /*assume 32bit; doesn't matter*/
22             #define PE_SIGVALID(sig) (Sigvalid[sig>>5] & (1 << ((sig) & 0x1f)))
23             #define PE_SIGVALID_off(sig) Sigvalid[sig>>5] &= ~(1 << ((sig) & 0x1f))
24              
25             struct pe_sig_stat {
26             U32 Hits;
27             U16 hits[NSIG];
28             };
29             typedef struct pe_sig_stat pe_sig_stat;
30              
31             static int Sigslot;
32             static pe_sig_stat Sigstat[2];
33              
34             static pe_ring Sigring[NSIG];
35              
36             /* /GLOBALS */
37              
38 2           static Signal_t process_sighandler(int sig) {
39 2           pe_sig_stat *st = &Sigstat[Sigslot];
40 2           ++st->Hits;
41 2           ++st->hits[sig];
42 2           }
43              
44 4           static pe_watcher *pe_signal_allocate(HV *stash, SV *temple) {
45             pe_signal *ev;
46 4           EvNew(5, ev, 1, pe_signal);
47 4           ev->base.vtbl = &pe_signal_vtbl;
48 4           PE_RING_INIT(&ev->sring, ev);
49 4           ev->signal = 0;
50 4           pe_watcher_init(&ev->base, stash, temple);
51 4           WaREPEAT_on(ev);
52 4           WaINVOKE1_off(ev);
53 4           return (pe_watcher*) ev;
54             }
55              
56 4           static void pe_signal_dtor(pe_watcher *ev) {
57 4           pe_watcher_dtor(ev);
58 4           EvFree(5, ev);
59 4           }
60              
61 2           static char *pe_signal_start(pe_watcher *_ev, int repeat) {
62 2           pe_signal *ev = (pe_signal*) _ev;
63 2           int sig = ev->signal;
64 2 50         if (!_ev->callback)
65 0           return "without callback";
66 2 100         if (sig == 0)
67 1           return "without signal";
68 1 50         if (PE_RING_EMPTY(&Sigring[sig]))
69 1           rsignal(sig, (Sighandler_t)process_sighandler);
70 1           PE_RING_UNSHIFT(&ev->sring, &Sigring[sig]);
71 1           return 0;
72             }
73              
74 1           static void pe_signal_stop(pe_watcher *_ev) {
75 1           pe_signal *ev = (pe_signal*) _ev;
76 1           int sig = ev->signal;
77 1 50         PE_RING_DETACH(&ev->sring);
78 1 50         if (PE_RING_EMPTY(&Sigring[sig])) {
79 1           rsignal(sig, (Sighandler_t)SIG_DFL);
80 1           Sigstat[0].hits[sig] = 0;
81 1           Sigstat[1].hits[sig] = 0;
82             }
83 1           }
84              
85 2           WKEYMETH(_signal_signal) {
86 2           pe_signal *sg = (pe_signal*) ev;
87 2 100         if (nval) {
88             STRLEN n_a;
89 1           int active = WaPOLLING(ev);
90 1 50         int sig = whichsig(SvPV(nval, n_a));
91             /*warn("whichsig(%s) = %d", SvPV(nval,na), sig); /**/
92 1 50         if (sig == 0)
93 0 0         croak("Unrecognized signal '%s'", SvPV(nval, n_a));
94 1 50         if (!PE_SIGVALID(sig))
95 0 0         croak("Signal '%s' cannot be caught", SvPV(nval, n_a));
96 1 50         if (active) pe_watcher_off(ev);
97 1           sg->signal = sig;
98 1 50         if (active) pe_watcher_on(ev, 0);
99             }
100             {
101 2           dSP;
102 2 50         XPUSHs(sg->signal > 0?
    50          
103             sv_2mortal(newSVpv(PL_sig_name[sg->signal],0)) : &PL_sv_undef);
104 2           PUTBACK;
105             }
106 2           }
107              
108 1           static void _signal_asynccheck(pe_sig_stat *st) {
109             int xx, got;
110             pe_watcher *wa;
111              
112 65 100         for (xx = 1; xx < NSIG; xx++) {
113 64 100         if (!st->hits[xx])
114 63           continue;
115 1           got = st->hits[xx];
116 1           wa = (pe_watcher*) Sigring[xx].next->self;
117 2 100         while (wa) {
118 1           pe_event *ev = (*wa->vtbl->new_event)(wa);
119 1           ev->hits += got;
120 1           queueEvent(ev);
121 1           wa = (pe_watcher*) ((pe_signal*)wa)->sring.next->self;
122             }
123 1           st->hits[xx] = 0;
124             }
125 1           Zero(st, 1, struct pe_sig_stat);
126 1           }
127              
128             /* This implementation gives no race conditions, assuming
129             no kernel-level threads. */
130 193350           static void pe_signal_asynccheck() {
131             pe_sig_stat *st;
132              
133 193350           Sigslot = 1;
134 193350           st = &Sigstat[0];
135 193350 100         if (st->Hits) _signal_asynccheck(st);
136              
137 193350           Sigslot = 0;
138 193350           st = &Sigstat[1];
139 193350 50         if (st->Hits) _signal_asynccheck(st);
140 193350           }
141              
142 24           static void boot_signal() {
143             int xx;
144             int sig;
145             char **sigp;
146             /* it is crufty to hardcode this list */
147             static char *nohandle[] = { "KILL", "STOP", "ZERO", 0 };
148 24           pe_watcher_vtbl *vt = &pe_signal_vtbl;
149 24           Zero(&Sigstat[0], 1, pe_sig_stat);
150 24           Zero(&Sigstat[1], 1, pe_sig_stat);
151 24           Sigslot = 0;
152 1584 100         for (xx=0; xx < NSIG; xx++) {
153 1560           PE_RING_INIT(&Sigring[xx], 0);
154             }
155 24           memset(Sigvalid, ~0, sizeof(Sigvalid));
156            
157 24           PE_SIGVALID_off(0);
158 24           sigp = nohandle;
159 96 100         while (*sigp) {
160 72           sig = whichsig(*sigp);
161 72 100         if (sig) PE_SIGVALID_off(sig);
162 72           ++sigp;
163             }
164 24           memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
165 24           vt->dtor = pe_signal_dtor;
166 24           vt->start = pe_signal_start;
167 24           vt->stop = pe_signal_stop;
168 24           pe_register_vtbl(vt, gv_stashpv("Event::signal",1), &event_vtbl);
169 24           }