#include "xshelper.h" static void setup_sigset(pTHX_ sigset_t* const sigmask, SV* const arg) { SvGETMAGIC(arg); #if PERL_BCDVERSION > 0x5015002 if( sv_isobject(arg) && sv_derived_from(arg, "POSIX::SigSet") && SvPOK(SvRV(arg)) ) { *sigmask = *(sigset_t*)SvPV_nolen(SvRV(arg)); #else if( sv_isobject(arg) && sv_derived_from(arg, "POSIX::SigSet") && SvIOK(SvRV(arg)) ) { *sigmask = *(sigset_t*)SvIV( SvRV(arg) ); #endif } else if(SvOK(arg)) { if(SvROK(arg) && SvTYPE(SvRV(arg)) == SVt_PVAV) { AV* const av = (AV*)SvRV(arg); I32 const len = av_len(av) + 1; I32 i; sigemptyset(sigmask); for(i = 0; i < len; i++) { SV** const svp = av_fetch(av, i, FALSE); if(svp) { if(looks_like_number(*svp)) { sigaddset(sigmask, (int)SvIV(*svp)); } else { int signum; STRLEN len; const char* name = SvPV_const(*svp, len); if(len > 3 && strncmp(name, "SIG", 3) == 0) { name += 3; } signum = whichsig( (char*)name); if(signum < 0) { if(ckWARN( packWARN(WARN_MISC) )) { warner(packWARN(WARN_MISC), "POSIX::pselect: unrecognized signal name \"%s\"", name); } } else { sigaddset(sigmask, signum); } } } } } else { croak("POSIX::pselect: sigset must be an ARRAY reference or POSIX::SigSet object"); } } } /* stolen from pp_sselect() at pp_sys.c */ static XS(XS_POSIX__pselect) { dVAR; dXSARGS; dXSTARG; I32 i; I32 j; char *s; SV *sv; NV value; I32 maxlen = 0; I32 nfound; struct timespec timebuf; struct timespec *tbuf = &timebuf; sigset_t sigmask; I32 growsize; char *fd_sets[4]; #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678 I32 masksize; I32 offset; I32 k; # if BYTEORDER & 0xf0000 # define ORDERBYTE (0x88888888 - BYTEORDER) # else # define ORDERBYTE (0x4444 - BYTEORDER) # endif #endif if (items != 5) croak("Usage: pselect(rfdset, wfdset, efdset, timeout, sigmask)"); SP -= 5; /* r, w, e, timeout, sigset */ for (i = 1; i <= 3; i++) { SV * const sv = SP[i]; if (!SvOK(sv)) continue; if (SvREADONLY(sv)) { if (SvIsCOW(sv)) sv_force_normal_flags(sv, 0); if (SvREADONLY(sv) && !(SvPOK(sv) && SvCUR(sv) == 0)) croak("%s", PL_no_modify); } if (!SvPOK(sv)) { if(ckWARN( packWARN(WARN_MISC) )) { warner(packWARN(WARN_MISC), "POSIX::pselect: Non-string passed as bitmask"); } SvPV_force_nolen(sv); /* force string conversion */ } j = SvCUR(sv); if (maxlen < j) maxlen = j; } /* little endians can use vecs directly */ #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678 # ifdef NFDBITS # ifndef NBBY # define NBBY 8 # endif masksize = NFDBITS / NBBY; # else masksize = sizeof(long); /* documented int, everyone seems to use long */ # endif Zero(&fd_sets[0], 4, char*); #endif # if SELECT_MIN_BITS == 1 growsize = sizeof(fd_set); # else # if defined(__GLIBC__) && defined(__FD_SETSIZE) # undef SELECT_MIN_BITS # define SELECT_MIN_BITS __FD_SETSIZE # endif /* If SELECT_MIN_BITS is greater than one we most probably will want * to align the sizes with SELECT_MIN_BITS/8 because for example * in many little-endian (Intel, Alpha) systems (Linux, OS/2, Digital * UNIX, Solaris, NeXT, Darwin) the smallest quantum select() operates * on (sets/tests/clears bits) is 32 bits. */ growsize = maxlen + (SELECT_MIN_BITS/8 - (maxlen % (SELECT_MIN_BITS/8))); # endif sv = SP[4]; if (SvOK(sv)) { value = SvNV(sv); if (value < 0.0) value = 0.0; timebuf.tv_sec = (long)value; value -= (NV)timebuf.tv_sec; timebuf.tv_nsec = (long)(value * 1000000000.0); //timebuf.tv_usec = (long)(value * 1000000.0); } else tbuf = NULL; setup_sigset(aTHX_ &sigmask, SP[5]); for (i = 1; i <= 3; i++) { sv = SP[i]; if (!SvOK(sv) || SvCUR(sv) == 0) { fd_sets[i] = 0; continue; } assert(SvPOK(sv)); j = SvLEN(sv); if (j < growsize) { Sv_Grow(sv, growsize); } j = SvCUR(sv); s = SvPVX(sv) + j; while (++j <= growsize) { *s++ = '\0'; } #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678 s = SvPVX(sv); Newx(fd_sets[i], growsize, char); for (offset = 0; offset < growsize; offset += masksize) { for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4)) fd_sets[i][j+offset] = s[(k % masksize) + offset]; } #else fd_sets[i] = SvPVX(sv); #endif } nfound = pselect( maxlen * 8, (fd_set*) fd_sets[1], (fd_set*) fd_sets[2], (fd_set*) fd_sets[3], tbuf, &sigmask); for (i = 1; i <= 3; i++) { if (fd_sets[i]) { sv = SP[i]; #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678 s = SvPVX(sv); for (offset = 0; offset < growsize; offset += masksize) { for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4)) s[(k % masksize) + offset] = fd_sets[i][j+offset]; } Safefree(fd_sets[i]); #endif SvSETMAGIC(sv); } } PUSHi(nfound); if (GIMME == G_ARRAY && tbuf) { value = (NV)(timebuf.tv_sec) + (NV)(timebuf.tv_nsec) / 1000000000.0; mPUSHn(value); } PUTBACK; } MODULE = POSIX::pselect PACKAGE = POSIX::pselect PROTOTYPES: DISABLE BOOT: { newXS("POSIX::pselect::pselect", XS_POSIX__pselect, (char*)__FILE__); }