ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Async-Interrupt/Interrupt.xs
Revision: 1.1
Committed: Thu Jul 2 13:41:44 2009 UTC (14 years, 11 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5     typedef volatile sig_atomic_t atomic_t;
6    
7     static int *sig_pending, *psig_pend; /* make local copies because of missing THX */
8     static Sighandler_t old_sighandler;
9     static atomic_t async_pending;
10    
11     static int
12     extract_fd (SV *fh, int wr)
13     {
14     int fd = PerlIO_fileno (wr ? IoOFP (sv_2io (fh)) : IoIFP (sv_2io (fh)));
15    
16     if (fd < 0)
17     croak ("illegal fh argument, either not an OS file or read/write mode mismatch");
18    
19     return fd;
20     }
21    
22     static SV *
23     get_cb (SV *cb_sv)
24     {
25     HV *st;
26     GV *gvp;
27     CV *cv;
28    
29     if (!SvOK (cb_sv))
30     return 0;
31    
32     cv = sv_2cv (cb_sv, &st, &gvp, 0);
33    
34     if (!cv)
35     croak ("Async::Interrupt callback must be undef or a CODE reference");
36    
37     return (SV *)cv;
38     }
39    
40     static AV *asyncs;
41    
42     struct async {
43     SV *cb;
44     void (*c_cb)(pTHX_ void *c_data, int value);
45     void *c_data;
46     SV *fh;
47    
48     int fd;
49     atomic_t value;
50     atomic_t signalled;
51     };
52    
53     /* the main workhorse to signal */
54     static void
55     async_signal (void *signal_arg, int value)
56     {
57     struct async *async = (struct async *)signal_arg;
58    
59     async->value = value;
60    
61     if (!async->signalled)
62     {
63     async->signalled = 1;
64    
65     if (async->fd >= 0)
66     write (async->fd, async, 1);
67     }
68    
69     async_pending = 1;
70     psig_pend [9] = 1;
71     *sig_pending = 1;
72     }
73    
74     static void
75     async_handle (void)
76     {
77     async_pending = 0;
78     }
79    
80     #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
81     static Signal_t async_sighandler (int signum, siginfo_t *si, void *sarg)
82     {
83     if (signum == 9)
84     async_handle ();
85     else
86     old_sighandler (signum, si, sarg);
87     }
88     #else
89     static Signal_t async_sighandler (int)
90     {
91     if (signum == 9)
92     async_handle ();
93     else
94     old_sighandler (signum);
95     }
96     #endif
97    
98    
99     MODULE = Async::Interrupt PACKAGE = Async::Interrupt
100    
101     BOOT:
102     old_sighandler = PL_sighandlerp;
103     PL_sighandlerp = async_sighandler;
104     sig_pending = &PL_sig_pending;
105     psig_pend = PL_psig_pend;
106     asyncs = newAV ();
107    
108     SV *
109     _alloc (SV *cb, void *c_cb, void *c_data, SV *fh)
110     CODE:
111     {
112     SV *cv = SvOK (cb) ? SvREFCNT_inc_NN (get_cb (cb)) : 0;
113     int fd = SvOK (fh) ? extract_fd (fh, 1) : -1;
114    
115     struct async *async;
116     Newz (0, async, 1, struct async);
117    
118     async->fh = fd >= 0 ? newSVsv (fh) : 0;
119     async->fd = fd;
120     async->cb = cb;
121     async->c_cb = c_cb;
122     async->c_data = c_data;
123    
124     RETVAL = newSViv (PTR2IV (async));
125     av_push (asyncs, RETVAL);
126    
127     RETVAL = newRV_noinc (RETVAL);
128     }
129     OUTPUT:
130     RETVAL
131    
132     void
133     signal_cb (SV *self)
134     PPCODE:
135     EXTEND (SP, 2);
136     PUSHs (sv_2mortal (newSViv (PTR2IV (async_signal))));
137     PUSHs (sv_2mortal (newSViv (SvIV (SvRV (self)))));
138    
139     void
140     signal (SV *self, int value = 0)
141     CODE:
142     async_signal (INT2PTR (void *, SvIV (SvRV (self))), value);
143    
144     void
145     DESTROY (SV *self)
146     CODE:
147     {
148     int i;
149     SV *async_sv = SvRV (self);
150     struct async *async = INT2PTR (struct async *, SvIV (async_sv));
151    
152     for (i = AvFILLp (asyncs); i > 0; --i)
153     if (AvARRAY (asyncs)[i] == async_sv)
154     {
155     if (i < AvFILLp (asyncs))
156     AvARRAY (asyncs)[i] == AvARRAY (asyncs)[AvFILLp (asyncs)];
157    
158     assert (av_pop (asyncs) == async_sv);
159     goto found;
160     }
161    
162     if (!PL_dirty)
163     warn ("Async::Interrupt::DESTROY could not find async object in list of asyncs, please report!");
164    
165     found:
166     SvREFCNT_dec (async->fh);
167     SvREFCNT_dec (async->cb);
168    
169     Safefree (async);
170     }
171