IO-SocketAlarm
view release on metacpan or search on metacpan
SocketAlarm.xs view on Meta::CPAN
MAGIC *magic;
if (sa->owner)
croak("BUG: already attached to perl object");
sa->owner= obj_inner_sv;
magic= sv_magicext((SV*) sa->owner, NULL, PERL_MAGIC_ext, &socketalarm_magic_vt, (const char*) sa, 0);
#ifdef USE_ITHREADS
magic->mg_flags |= MGf_DUP;
#else
(void)magic; // suppress 'unused' warning
#endif
}
// Return existing Watch object, or create a new one.
// Returned SV has a non-mortal refcount, which is what the typemap
// wants for returning a "struct socketalarm*" to perl-land
static SV* wrap_socketalarm(struct socketalarm *sa) {
SV *obj;
HV *hv;
// Since this is used in typemap, handle NULL gracefully
if (!sa)
return &PL_sv_undef;
// If there is already a node object, return a new reference to it.
if (sa->owner)
return newRV_inc((SV*) sa->owner);
// else create a node object
hv= newHV();
obj= newRV_noinc((SV*) hv);
sv_bless(obj, gv_stashpv("IO::SocketAlarm", GV_ADD));
attach_magic_socketalarm((SV*) hv, sa);
return obj;
}
#define EXPORT_ENUM(x) newCONSTSUB(stash, #x, new_enum_dualvar(aTHX_ x, newSVpvs_share(#x)))
static SV * new_enum_dualvar(pTHX_ IV ival, SV *name) {
SvUPGRADE(name, SVt_PVNV);
SvIV_set(name, ival);
SvIOK_on(name);
SvREADONLY_on(name);
return name;
}
/*------------------------------------------------------------------------------------
* Perl API
*/
MODULE = IO::SocketAlarm PACKAGE = IO::SocketAlarm
void
_init_socketalarm(self, sock_sv, eventmask_sv, actions_sv)
SV *self
SV *sock_sv
SV *eventmask_sv
SV *actions_sv
INIT:
int sock_fd= fileno_from_sv(sock_sv);
int eventmask= EVENT_DEFAULTS;
struct stat statbuf;
struct socketalarm *sa;
SV **action_list= NULL;
SSize_t n_actions= 0;
PPCODE:
if (!sv_isobject(self))
croak("Not an object");
if ((sa= get_magic_socketalarm(self, 0)))
croak("Already initialized");
if (!(sock_fd >= 0 && fstat(sock_fd, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)))
croak("Not an open socket");
if (eventmask_sv && SvOK(eventmask_sv))
eventmask= SvIV(eventmask_sv);
if (actions_sv && SvOK(actions_sv)) {
action_list= unwrap_array(actions_sv, &n_actions);
if (!action_list)
croak("Actions must be an arrayref (or undefined)");
}
sa= socketalarm_new(sock_fd, &statbuf, eventmask, action_list, n_actions);
attach_magic_socketalarm(SvRV(self), sa);
XSRETURN(1); // return $self
int
socket(alarm)
struct socketalarm *alarm
CODE:
RETVAL= alarm->watch_fd;
OUTPUT:
RETVAL
int
events(alarm)
struct socketalarm *alarm
CODE:
RETVAL= alarm->event_mask;
OUTPUT:
RETVAL
void
actions(alarm)
struct socketalarm *alarm
PPCODE:
if (!alarm->actions_av);
socketalarm__build_actions(alarm);
ST(0)= sv_2mortal(newRV_inc((SV*) alarm->actions_av));
XSRETURN(1);
int
action_count(alarm)
struct socketalarm *alarm
CODE:
RETVAL= alarm->action_count;
OUTPUT:
RETVAL
int
cur_action(alarm)
struct socketalarm *alarm
CODE:
watch_list_item_get_status(alarm, &RETVAL);
OUTPUT:
RETVAL
bool
start(alarm)
struct socketalarm *alarm
CODE:
RETVAL= watch_list_add(alarm);
OUTPUT:
RETVAL
bool
cancel(alarm)
struct socketalarm *alarm
CODE:
RETVAL= watch_list_remove(alarm);
OUTPUT:
RETVAL
SV*
stringify(alarm)
struct socketalarm *alarm
INIT:
SV *out= sv_2mortal(newSVpvn("",0));
Size_t i;
CODE:
sv_catpvf(out, "watch fd: %d\n", alarm->watch_fd);
sv_catpvf(out, "event mask:%s%s\n",
alarm->event_mask & EVENT_SHUT? " SHUT":"",
alarm->event_mask & EVENT_CLOSE? " CLOSE":""
);
sv_catpv(out, "actions:\n");
for (i= 0; i < alarm->action_count; i++) {
char buf[256];
snprint_action(buf, sizeof(buf), alarm->actions+i);
sv_catpvf(out, "%4d: %s\n", (int)i, buf);
}
SvREFCNT_inc(out);
RETVAL= out;
OUTPUT:
RETVAL
void
_terminate_all()
PPCODE:
shutdown_watch_thread();
MODULE = IO::SocketAlarm PACKAGE = IO::SocketAlarm::Util
struct socketalarm *
socketalarm(sock_sv, ...)
SV *sock_sv
INIT:
int sock_fd= fileno_from_sv(sock_sv);
int eventmask= EVENT_DEFAULTS;
int action_ofs= 1;
struct stat statbuf;
CODE:
if (!(sock_fd >= 0 && fstat(sock_fd, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)))
croak("Not an open socket");
if (items > 1) {
// must either be a scalar, a scalar followed by actions specs, or action specs
if (SvOK(ST(1)) && looks_like_number(ST(1))) {
eventmask= SvIV(ST(1));
action_ofs++;
}
}
RETVAL= socketalarm_new(sock_fd, &statbuf, eventmask, &(ST(action_ofs)), items - action_ofs);
watch_list_add(RETVAL);
OUTPUT:
RETVAL
bool
is_socket(fd_sv)
SV *fd_sv
INIT:
int fd= fileno_from_sv(fd_sv);
struct stat statbuf;
CODE:
RETVAL= fd >= 0 && fstat(fd, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode);
OUTPUT:
RETVAL
SV *
get_fd_table_str(max_fd=1024)
int max_fd
INIT:
SV *out= newSVpvn("",0);
size_t avail= 0, needed= 1023;
CODE:
// FD status could change between calls, changing the length requirement, so loop.
// 'avail' count includes the NUL byte, and 'needed' does not.
while (avail <= needed) {
sv_grow(out, needed+1);
avail= needed+1;
needed= snprint_fd_table(SvPVX(out), avail, max_fd);
}
SvCUR_set(out, needed);
RETVAL= out;
OUTPUT:
RETVAL
# For unit test purposes only, export _poll that polls on a single file
# descriptor to verify the statuses for sockets in various states.
void
_poll(fd, events, timeout)
int fd
SV *events;
int timeout;
INIT:
int ret;
struct pollfd pollbuf;
PPCODE:
pollbuf.fd= fd;
pollbuf.events= SvIV(events);
pollbuf.revents= 0;
ret= poll(&pollbuf, 1, timeout);
EXTEND(SP, 2);
PUSHs(sv_2mortal(newSViv(ret)));
PUSHs(sv_2mortal(newSViv(ret < 0? errno : ret > 0? pollbuf.revents : 0)));
#-----------------------------------------------------------------------------
# Constants
#
BOOT:
HV* stash= gv_stashpvn("IO::SocketAlarm::Util", 21, GV_ADD);
EXPORT_ENUM(EVENT_SHUT);
EXPORT_ENUM(EVENT_EOF);
EXPORT_ENUM(EVENT_IN);
EXPORT_ENUM(EVENT_PRI);
EXPORT_ENUM(EVENT_CLOSE);
EXPORT_ENUM(POLLIN);
EXPORT_ENUM(POLLOUT);
EXPORT_ENUM(POLLPRI);
EXPORT_ENUM(POLLERR);
EXPORT_ENUM(POLLHUP);
#ifdef POLLRDHUP
EXPORT_ENUM(POLLRDHUP);
#endif
EXPORT_ENUM(POLLNVAL);
PROTOTYPES: DISABLE
( run in 1.649 second using v1.01-cache-2.11-cpan-71847e10f99 )