ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/IO-AIO/schmorp.h
(Generate patch)

Comparing IO-AIO/schmorp.h (file contents):
Revision 1.2 by root, Tue Jul 14 00:14:27 2009 UTC vs.
Revision 1.5 by root, Wed Jul 15 01:36:04 2009 UTC

3 3
4/* WARNING 4/* WARNING
5 * This header file is a shared resource between many modules. 5 * This header file is a shared resource between many modules.
6 */ 6 */
7 7
8#include <signal.h>
9
10#ifndef _WIN32
11# include <poll.h>
12#endif
13
8/* useful stuff, used by schmorp mostly */ 14/* useful stuff, used by schmorp mostly */
15
16#include "patchlevel.h"
9 17
10#define PERL_VERSION_ATLEAST(a,b,c) \ 18#define PERL_VERSION_ATLEAST(a,b,c) \
11 (PERL_REVISION > (a) \ 19 (PERL_REVISION > (a) \
12 || (PERL_REVISION == (a) \ 20 || (PERL_REVISION == (a) \
13 && (PERL_VERSION > (b) \ 21 && (PERL_VERSION > (b) \
72#ifndef SIG_SIZE 80#ifndef SIG_SIZE
73 /* kudos to Slaven Rezic for the idea */ 81 /* kudos to Slaven Rezic for the idea */
74 static char sig_size [] = { SIG_NUM }; 82 static char sig_size [] = { SIG_NUM };
75# define SIG_SIZE (sizeof (sig_size) + 1) 83# define SIG_SIZE (sizeof (sig_size) + 1)
76#endif 84#endif
85 dTHX;
77 int signum; 86 int signum;
78 87
79 SvGETMAGIC (sig); 88 SvGETMAGIC (sig);
80 89
81 for (signum = 1; signum < SIG_SIZE; ++signum) 90 for (signum = 1; signum < SIG_SIZE; ++signum)
94s_signum_croak (SV *sig) 103s_signum_croak (SV *sig)
95{ 104{
96 int signum = s_signum (sig); 105 int signum = s_signum (sig);
97 106
98 if (signum < 0) 107 if (signum < 0)
108 {
109 dTHX;
99 croak ("%s: invalid signal name or number", SvPV_nolen (sig)); 110 croak ("%s: invalid signal name or number", SvPV_nolen (sig));
111 }
100 112
101 return signum; 113 return signum;
102} 114}
103 115
104static int 116static int
105s_fileno (SV *fh, int wr) 117s_fileno (SV *fh, int wr)
106{ 118{
119 dTHX;
107 SvGETMAGIC (fh); 120 SvGETMAGIC (fh);
108 121
109 if (SvROK (fh)) 122 if (SvROK (fh))
110 { 123 {
111 fh = SvRV (fh); 124 fh = SvRV (fh);
125s_fileno_croak (SV *fh, int wr) 138s_fileno_croak (SV *fh, int wr)
126{ 139{
127 int fd = s_fileno (fh, wr); 140 int fd = s_fileno (fh, wr);
128 141
129 if (fd < 0) 142 if (fd < 0)
143 {
144 dTHX;
130 croak ("%s: illegal fh argument, either not an OS file or read/write mode mismatch", SvPV_nolen (fh)); 145 croak ("%s: illegal fh argument, either not an OS file or read/write mode mismatch", SvPV_nolen (fh));
146 }
131 147
132 return fd; 148 return fd;
133} 149}
134 150
135static SV * 151static SV *
136s_get_cv (SV *cb_sv) 152s_get_cv (SV *cb_sv)
137{ 153{
154 dTHX;
138 HV *st; 155 HV *st;
139 GV *gvp; 156 GV *gvp;
157
140 CV *cv = sv_2cv (cb_sv, &st, &gvp, 0); 158 return (SV *)sv_2cv (cb_sv, &st, &gvp, 0);
141
142 return (SV *)cv;
143} 159}
144 160
145static SV * 161static SV *
146s_get_cv_croak (SV *cb_sv) 162s_get_cv_croak (SV *cb_sv)
147{ 163{
148 cb_sv = s_get_cv (cb_sv); 164 SV *cv = s_get_cv (cb_sv);
149 165
150 if (!cb_sv) 166 if (!cv)
167 {
168 dTHX;
151 croak ("%s: callback must be a CODE reference or another callable object", SvPV_nolen (cb_sv)); 169 croak ("%s: callback must be a CODE reference or another callable object", SvPV_nolen (cb_sv));
170 }
152 171
153 return cb_sv; 172 return cv;
154} 173}
155 174
156/*****************************************************************************/ 175/*****************************************************************************/
157/* gensub: simple closure generation utility */ 176/* gensub: simple closure generation utility */
158 177
174 S_GENSUB_ARG = arg; 193 S_GENSUB_ARG = arg;
175 194
176 return newRV_noinc ((SV *)cv); 195 return newRV_noinc ((SV *)cv);
177} 196}
178 197
198/** portable pipe/socketpair */
199
200#ifdef USE_SOCKETS_AS_HANDLES
201# define S_TO_SOCKET(x) (win32_get_osfhandle (x))
202#else
203# define S_TO_SOCKET(x) (x)
204#endif
205
206#ifdef _WIN32
207/* taken almost verbatim from libev's ev_win32.c */
208/* oh, the humanity! */
209static int
210s_pipe (int filedes [2])
211{
212 struct sockaddr_in addr = { 0 };
213 int addr_size = sizeof (addr);
214 struct sockaddr_in adr2;
215 int adr2_size = sizeof (adr2);
216 SOCKET listener;
217 SOCKET sock [2] = { -1, -1 };
218
219 if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
220 return -1;
221
222 addr.sin_family = AF_INET;
223 addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
224 addr.sin_port = 0;
225
226 if (bind (listener, (struct sockaddr *)&addr, addr_size))
227 goto fail;
228
229 if (getsockname (listener, (struct sockaddr *)&addr, &addr_size))
230 goto fail;
231
232 if (listen (listener, 1))
233 goto fail;
234
235 if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
236 goto fail;
237
238 if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
239 goto fail;
240
241 if ((sock [1] = accept (listener, 0, 0)) < 0)
242 goto fail;
243
244 /* windows vista returns fantasy port numbers for getpeername.
245 * example for two interconnected tcp sockets:
246 *
247 * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364
248 * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363
249 * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363
250 * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365
251 *
252 * wow! tridirectional sockets!
253 *
254 * this way of checking ports seems to work:
255 */
256 if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size))
257 goto fail;
258
259 if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size))
260 goto fail;
261
262 errno = WSAEINVAL;
263 if (addr_size != adr2_size
264 || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */
265 || addr.sin_port != adr2.sin_port)
266 goto fail;
267
268 closesocket (listener);
269
270#ifdef USE_SOCKETS_AS_HANDLES
271 /* when select isn't winsocket, we also expect socket, connect, accept etc.
272 * to work on fds */
273 filedes [0] = sock [0];
274 filedes [1] = sock [1];
275#else
276 filedes [0] = _open_osfhandle (sock [0], 0);
277 filedes [1] = _open_osfhandle (sock [1], 0);
278#endif
279
280 return 0;
281
282fail:
283 closesocket (listener);
284
285 if (sock [0] != INVALID_SOCKET) closesocket (sock [0]);
286 if (sock [1] != INVALID_SOCKET) closesocket (sock [1]);
287
288 return -1;
289}
290
291#define s_socketpair(domain,type,protocol,filedes) s_pipe (filedes)
292
293static int
294s_fd_blocking (int fd, int blocking)
295{
296 blocking = !blocking;
297
298 return ioctlsocket (S_TO_SOCKET (fd), FIONBIO, &blocking);
299}
300
301#define s_fd_prepare(fd) s_fd_blocking (fd, 0)
302
303#else
304
305#define s_socketpair(domain,type,protocol,filedes) socketpair (domain, type, protocol, filedes)
306#define s_pipe(filedes) pipe (filedes)
307
308static int
309s_fd_blocking (int fd, int blocking)
310{
311 return fcntl (fd, F_SETFL, blocking ? 0 : O_NONBLOCK);
312}
313
314static int
315s_fd_prepare (int fd)
316{
317 return s_fd_blocking (fd, 0)
318 || fcntl (fd, F_SETFD, FD_CLOEXEC);
319}
320
321#endif
322
323#if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7))
324/* our minimum requirement is glibc 2.7 which has the stub, but not the header */
325# include <stdint.h>
326# ifdef __cplusplus
327extern "C" {
179#endif 328# endif
329 int eventfd (unsigned int initval, int flags);
330# ifdef __cplusplus
331}
332# endif
333#else
334# define eventfd(initval,flags) -1
335#endif
180 336
337typedef struct {
338 int fd[2]; /* read, write fd, might be equal */
339 int len; /* write length (1 pipe/socket, 8 eventfd) */
340 volatile sig_atomic_t sent;
341} s_epipe;
342
343static int
344s_epipe_new (s_epipe *epp)
345{
346 s_epipe ep;
347
348 ep.fd [0] = ep.fd [1] = eventfd (0, 0);
349
350 if (ep.fd [0] >= 0)
351 {
352 s_fd_prepare (ep.fd [0]);
353 ep.len = 8;
354 }
355 else
356 {
357 if (s_pipe (ep.fd))
358 return -1;
359
360 if (s_fd_prepare (ep.fd [0])
361 || s_fd_prepare (ep.fd [1]))
362 {
363 close (ep.fd [0]);
364 close (ep.fd [1]);
365 return -1;
366 }
367
368 ep.len = 1;
369 }
370
371 ep.sent = 0;
372 *epp = ep;
373 return 0;
374}
375
376static void
377s_epipe_destroy (s_epipe *epp)
378{
379 close (epp->fd [0]);
380
381 if (epp->fd [1] != epp->fd [0])
382 close (epp->fd [1]);
383
384 epp->len = 0;
385}
386
387static void
388s_epipe_signal (s_epipe *epp)
389{
390 if (epp->sent)
391 return;
392
393 epp->sent = 1;
394#ifdef _WIN32
395 send (epp->fd [1], epp, 1);
396#else
397 static uint64_t counter = 1;
398 write (epp->fd [1], &counter, epp->len);
399#endif
400}
401
402static void
403s_epipe_drain (s_epipe *epp)
404{
405 char buf [9];
406
407#ifdef _WIN32
408 PerlSock_recv (epp->fd [0], buf, sizeof (buf), 0);
409#else
410 read (epp->fd [0], buf, sizeof (buf));
411#endif
412
413 epp->sent = 0;
414}
415
416/* like new, but dups over old */
417static int
418s_epipe_renew (s_epipe *epp)
419{
420 s_epipe epn;
421
422 if (epp->fd [1] != epp->fd [0])
423 close (epp->fd [1]);
424
425 if (s_epipe_new (&epn))
426 return -1;
427
428 if (epp->len)
429 {
430 if (dup2 (S_TO_SOCKET (epn.fd [0]), S_TO_SOCKET (epp->fd [0])) < 0)
431 croak ("unable to dup over old event pipe"); /* should not croak */
432
433 if (epp->fd [1] != epp->fd [0])
434 close (epn.fd [0]);
435
436 epn.fd [0] = epp->fd [0];
437 }
438
439 *epp = epn;
440
441 return 0;
442}
443
444#define s_epipe_fd(epp) ((epp)->fd [0])
445
446static int
447s_epipe_wait (s_epipe *epp)
448{
449#ifdef _WIN32
450 fd_set rfd;
451
452 FD_ZERO (&rfd);
453 FD_SET (s_epipe_fd (epp), &rfd);
454
455 return PerlSock_select (s_epipe_fd (epp) + 1, &rfd, 0, 0, 0);
456#else
457 /* poll is preferable on posix systems */
458 struct pollfd pfd;
459
460 pfd.fd = s_epipe_fd (epp);
461 pfd.events = POLLIN;
462
463 return poll (&pfd, 1, 0);
464#endif
465}
466
467#endif
468

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines