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.3 by root, Tue Jul 14 00:32:27 2009 UTC vs.
Revision 1.18 by root, Tue Feb 20 06:05:19 2018 UTC

1#ifndef SCHMORP_PERL_H_ 1#ifndef SCHMORP_PERL_H_
2#define SCHMORP_PERL_H_ 2#define SCHMORP_PERL_H_
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 * perl header files MUST already be included.
6 */ 7 */
7 8
9#include <signal.h>
10#include <errno.h>
11
12#if defined(WIN32 ) || defined(_MINIX)
13# define SCHMORP_H_PREFER_SELECT 1
14#endif
15
16#if !SCHMORP_H_PREFER_SELECT
17# include <poll.h>
18#endif
19
8/* useful stuff, used by schmorp mostly */ 20/* useful stuff, used by schmorp mostly */
21
22#include "patchlevel.h"
9 23
10#define PERL_VERSION_ATLEAST(a,b,c) \ 24#define PERL_VERSION_ATLEAST(a,b,c) \
11 (PERL_REVISION > (a) \ 25 (PERL_REVISION > (a) \
12 || (PERL_REVISION == (a) \ 26 || (PERL_REVISION == (a) \
13 && (PERL_VERSION > (b) \ 27 && (PERL_VERSION > (b) \
14 || (PERL_VERSION == (b) && PERL_SUBVERSION >= (c))))) 28 || (PERL_VERSION == (b) && PERL_SUBVERSION >= (c)))))
15 29
30#ifndef PERL_MAGIC_ext
31# define PERL_MAGIC_ext '~'
32#endif
33
16#if !PERL_VERSION_ATLEAST (5,6,0) 34#if !PERL_VERSION_ATLEAST (5,6,0)
17# ifndef PL_ppaddr 35# ifndef PL_ppaddr
18# define PL_ppaddr ppaddr 36# define PL_ppaddr ppaddr
19# endif 37# endif
20# ifndef call_sv 38# ifndef call_sv
31# endif 49# endif
32# ifndef IS_PADCONST 50# ifndef IS_PADCONST
33# define IS_PADCONST(v) 0 51# define IS_PADCONST(v) 0
34# endif 52# endif
35#endif 53#endif
54
55/* use NV for 32 bit perls as it allows larger offsets */
56#if IVSIZE >= 8
57typedef IV VAL64;
58# define SvVAL64(sv) SvIV (sv)
59# define newSVval64(i64) newSViv (i64)
60#else
61typedef NV VAL64;
62# define SvVAL64(sv) SvNV (sv)
63# define newSVval64(i64) newSVnv (i64)
64#endif
65
66/* typemap for the above */
67/*
68VAL64 T_VAL64
69
70INPUT
71
72T_VAL64
73 $var = ($type)SvVAL64 ($arg);
74
75OUTPUT
76
77T_VAL64
78 $arg = newSVval64 ($var);
79*/
36 80
37/* 5.11 */ 81/* 5.11 */
38#ifndef CxHASARGS 82#ifndef CxHASARGS
39# define CxHASARGS(cx) (cx)->blk_sub.hasargs 83# define CxHASARGS(cx) (cx)->blk_sub.hasargs
40#endif 84#endif
72#ifndef SIG_SIZE 116#ifndef SIG_SIZE
73 /* kudos to Slaven Rezic for the idea */ 117 /* kudos to Slaven Rezic for the idea */
74 static char sig_size [] = { SIG_NUM }; 118 static char sig_size [] = { SIG_NUM };
75# define SIG_SIZE (sizeof (sig_size) + 1) 119# define SIG_SIZE (sizeof (sig_size) + 1)
76#endif 120#endif
121 dTHX;
77 int signum; 122 int signum;
78 123
79 SvGETMAGIC (sig); 124 SvGETMAGIC (sig);
80 125
81 for (signum = 1; signum < SIG_SIZE; ++signum) 126 for (signum = 1; signum < SIG_SIZE; ++signum)
94s_signum_croak (SV *sig) 139s_signum_croak (SV *sig)
95{ 140{
96 int signum = s_signum (sig); 141 int signum = s_signum (sig);
97 142
98 if (signum < 0) 143 if (signum < 0)
144 {
145 dTHX;
99 croak ("%s: invalid signal name or number", SvPV_nolen (sig)); 146 croak ("%s: invalid signal name or number", SvPV_nolen (sig));
147 }
100 148
101 return signum; 149 return signum;
102} 150}
103 151
104static int 152static int
105s_fileno (SV *fh, int wr) 153s_fileno (SV *fh, int wr)
106{ 154{
155 dTHX;
107 SvGETMAGIC (fh); 156 SvGETMAGIC (fh);
108 157
109 if (SvROK (fh)) 158 if (SvROK (fh))
110 { 159 {
111 fh = SvRV (fh); 160 fh = SvRV (fh);
125s_fileno_croak (SV *fh, int wr) 174s_fileno_croak (SV *fh, int wr)
126{ 175{
127 int fd = s_fileno (fh, wr); 176 int fd = s_fileno (fh, wr);
128 177
129 if (fd < 0) 178 if (fd < 0)
179 {
180 dTHX;
130 croak ("%s: illegal fh argument, either not an OS file or read/write mode mismatch", SvPV_nolen (fh)); 181 croak ("%s: illegal fh argument, either not an OS file or read/write mode mismatch", SvPV_nolen (fh));
182 }
131 183
132 return fd; 184 return fd;
133} 185}
134 186
135static SV * 187static SV *
136s_get_cv (SV *cb_sv) 188s_get_cv (SV *cb_sv)
137{ 189{
190 dTHX;
138 HV *st; 191 HV *st;
139 GV *gvp; 192 GV *gvp;
140 193
141 SvGETMAGIC (cb_sv);
142 return SvOK (cb_sv) ? sv_2cv (cb_sv, &st, &gvp, 0) : 0; 194 return (SV *)sv_2cv (cb_sv, &st, &gvp, 0);
143} 195}
144 196
145static SV * 197static SV *
146s_get_cv_croak (SV *cb_sv) 198s_get_cv_croak (SV *cb_sv)
147{ 199{
148 SV *cv = s_get_cv (cb_sv); 200 SV *cv = s_get_cv (cb_sv);
149 201
150 if (!cv) 202 if (!cv)
203 {
204 dTHX;
151 croak ("%s: callback must be a CODE reference or another callable object", SvPV_nolen (cb_sv)); 205 croak ("%s: callback must be a CODE reference or another callable object", SvPV_nolen (cb_sv));
206 }
152 207
153 return cv; 208 return cv;
154} 209}
155 210
156/*****************************************************************************/ 211/*****************************************************************************/
174 S_GENSUB_ARG = arg; 229 S_GENSUB_ARG = arg;
175 230
176 return newRV_noinc ((SV *)cv); 231 return newRV_noinc ((SV *)cv);
177} 232}
178 233
234/*****************************************************************************/
235/* portable pipe/socketpair */
236
237#if defined(USE_SOCKETS_AS_HANDLES) || PERL_VERSION_ATLEAST(5,18,0)
238# define S_TO_HANDLE(x) ((HANDLE)win32_get_osfhandle (x))
239#else
240# define S_TO_HANDLE(x) ((HANDLE)x)
241#endif
242
243#ifdef _WIN32
244/* taken almost verbatim from libev's ev_win32.c */
245/* oh, the humanity! */
246static int
247s_pipe (int filedes [2])
248{
249 dTHX;
250
251 struct sockaddr_in addr = { 0 };
252 int addr_size = sizeof (addr);
253 struct sockaddr_in adr2;
254 int adr2_size = sizeof (adr2);
255 SOCKET listener;
256 SOCKET sock [2] = { -1, -1 };
257
258 if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
259 return -1;
260
261 addr.sin_family = AF_INET;
262 addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
263 addr.sin_port = 0;
264
265 if (bind (listener, (struct sockaddr *)&addr, addr_size))
266 goto fail;
267
268 if (getsockname (listener, (struct sockaddr *)&addr, &addr_size))
269 goto fail;
270
271 if (listen (listener, 1))
272 goto fail;
273
274 if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
275 goto fail;
276
277 if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
278 goto fail;
279
280 if ((sock [1] = accept (listener, 0, 0)) < 0)
281 goto fail;
282
283 /* windows vista returns fantasy port numbers for getpeername.
284 * example for two interconnected tcp sockets:
285 *
286 * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364
287 * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363
288 * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363
289 * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365
290 *
291 * wow! tridirectional sockets!
292 *
293 * this way of checking ports seems to work:
294 */
295 if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size))
296 goto fail;
297
298 if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size))
299 goto fail;
300
301 errno = WSAEINVAL;
302 if (addr_size != adr2_size
303 || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */
304 || addr.sin_port != adr2.sin_port)
305 goto fail;
306
307 closesocket (listener);
308
309#if defined(USE_SOCKETS_AS_HANDLES) || PERL_VERSION_ATLEAST(5,18,0)
310 /* when select isn't winsocket, we also expect socket, connect, accept etc.
311 * to work on fds */
312 filedes [0] = sock [0];
313 filedes [1] = sock [1];
314#else
315 filedes [0] = _open_osfhandle (sock [0], 0);
316 filedes [1] = _open_osfhandle (sock [1], 0);
317#endif
318
319 return 0;
320
321fail:
322 closesocket (listener);
323
324 if (sock [0] != INVALID_SOCKET) closesocket (sock [0]);
325 if (sock [1] != INVALID_SOCKET) closesocket (sock [1]);
326
327 return -1;
328}
329
330#define s_socketpair(domain,type,protocol,filedes) s_pipe (filedes)
331
332static int
333s_fd_blocking (int fd, int blocking)
334{
335 u_long nonblocking = !blocking;
336
337 return ioctlsocket ((SOCKET)S_TO_HANDLE (fd), FIONBIO, &nonblocking);
338}
339
340#define s_fd_prepare(fd) s_fd_blocking (fd, 0)
341
342#else
343
344#define s_socketpair(domain,type,protocol,filedes) socketpair (domain, type, protocol, filedes)
345#define s_pipe(filedes) pipe (filedes)
346
347static int
348s_fd_blocking (int fd, int blocking)
349{
350 return fcntl (fd, F_SETFL, blocking ? 0 : O_NONBLOCK);
351}
352
353static int
354s_fd_prepare (int fd)
355{
356 return s_fd_blocking (fd, 0)
357 || fcntl (fd, F_SETFD, FD_CLOEXEC);
358}
359
360#endif
361
362#if HAVE_EVENTFD
363# include <sys/eventfd.h>
364#else
365# if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7))
366# define SCHMORP_H_HAVE_EVENTFD 1
367/* our minimum requirement is glibc 2.7 which has the stub, but not the header */
368# include <stdint.h>
369# ifdef __cplusplus
370extern "C" {
371# endif
372 int eventfd (unsigned int initval, int flags);
373# ifdef __cplusplus
374}
375# endif
376# else
377# define eventfd(initval,flags) -1
179#endif 378# endif
379#endif
180 380
381typedef struct {
382 int fd[2]; /* read, write fd, might be equal */
383 int len; /* write length (1 pipe/socket, 8 eventfd) */
384} s_epipe;
385
386static int
387s_epipe_new (s_epipe *epp)
388{
389 s_epipe ep;
390
391 ep.fd [0] = ep.fd [1] = eventfd (0, 0);
392
393 if (ep.fd [0] >= 0)
394 {
395 s_fd_prepare (ep.fd [0]);
396 ep.len = 8;
397 }
398 else
399 {
400 if (s_pipe (ep.fd))
401 return -1;
402
403 if (s_fd_prepare (ep.fd [0])
404 || s_fd_prepare (ep.fd [1]))
405 {
406 dTHX;
407
408 close (ep.fd [0]);
409 close (ep.fd [1]);
410 return -1;
411 }
412
413 ep.len = 1;
414 }
415
416 *epp = ep;
417 return 0;
418}
419
420static void
421s_epipe_destroy (s_epipe *epp)
422{
423 dTHX;
424
425 close (epp->fd [0]);
426
427 if (epp->fd [1] != epp->fd [0])
428 close (epp->fd [1]);
429
430 epp->len = 0;
431}
432
433static void
434s_epipe_signal (s_epipe *epp)
435{
436#ifdef _WIN32
437 /* perl overrides send with a function that crashes in other threads.
438 * unfortunately, it overrides it with an argument-less macro, so
439 * there is no way to force usage of the real send function.
440 * incompetent windows programmers - is this redundant?
441 */
442 DWORD dummy;
443 WriteFile (S_TO_HANDLE (epp->fd [1]), (LPCVOID)&dummy, 1, &dummy, 0);
444#else
445# if SCHMORP_H_HAVE_EVENTFD
446 static uint64_t counter = 1;
447# else
448 static char counter [8];
449# endif
450 /* some modules accept fd's from outside, support eventfd here */
451 if (write (epp->fd [1], &counter, epp->len) < 0
452 && errno == EINVAL
453 && epp->len != 8)
454 write (epp->fd [1], &counter, (epp->len = 8));
455#endif
456}
457
458static void
459s_epipe_drain (s_epipe *epp)
460{
461 dTHX;
462 char buf [9];
463
464#ifdef _WIN32
465 recv (epp->fd [0], buf, sizeof (buf), 0);
466#else
467 read (epp->fd [0], buf, sizeof (buf));
468#endif
469}
470
471/* like new, but dups over old */
472static int
473s_epipe_renew (s_epipe *epp)
474{
475 dTHX;
476 s_epipe epn;
477
478 if (epp->fd [1] != epp->fd [0])
479 close (epp->fd [1]);
480
481 if (s_epipe_new (&epn))
482 return -1;
483
484 if (epp->len)
485 {
486 if (dup2 (epn.fd [0], epp->fd [0]) < 0)
487 croak ("unable to dup over old event pipe"); /* should not croak */
488
489 close (epn.fd [0]);
490
491 if (epn.fd [0] == epn.fd [1])
492 epn.fd [1] = epp->fd [0];
493
494 epn.fd [0] = epp->fd [0];
495 }
496
497 *epp = epn;
498
499 return 0;
500}
501
502#define s_epipe_fd(epp) ((epp)->fd [0])
503
504static int
505s_epipe_wait (s_epipe *epp)
506{
507 dTHX;
508#if SCHMORP_H_PREFER_SELECT
509 fd_set rfd;
510 int fd = s_epipe_fd (epp);
511
512 FD_ZERO (&rfd);
513 FD_SET (fd, &rfd);
514
515 return PerlSock_select (fd + 1, &rfd, 0, 0, 0);
516#else
517 /* poll is preferable on posix systems */
518 struct pollfd pfd;
519
520 pfd.fd = s_epipe_fd (epp);
521 pfd.events = POLLIN;
522
523 return poll (&pfd, 1, -1);
524#endif
525}
526
527#endif
528

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines