Skip Menu |

This queue is for tickets about the IO-Epoll CPAN distribution.

Report information
The Basics
Id: 42730
Status: resolved
Priority: 0/
Queue: IO-Epoll

People
Owner: Nobody in particular
Requestors: leonerd-cpan [...] leonerd.org.uk
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Wrap epoll_pwait() and provide IO::Ppoll-like wrapping
This patch adds a new syscall function, epoll_pwait(), and extends the high-level API object methods to cover those methods added by IO::Ppoll, which covers the signal mask in the same way. This allows an IO::Epoll object to perform signal-safe polling in a manner identical to IO::Ppoll. -- Paul Evans
Subject: IO-Epoll_pwait_IO-Ppoll.diff
=== modified file 'Epoll.xs' --- Epoll.xs 2008-11-21 19:49:40 +0000 +++ Epoll.xs 2008-11-23 17:42:03 +0000 @@ -62,4 +62,50 @@ free(events); } OUTPUT: - RETVAL \ No newline at end of file + RETVAL + +SV * +epoll_pwait(epfd,maxevents,timeout,sigmask) + int epfd + int maxevents + int timeout + SV *sigmask +CODE: + struct epoll_event *events; + sigset_t *sigmask_real; + int ret, i; + + if(SvOK(sigmask)) { + if(!sv_derived_from(sigmask, "POSIX::SigSet")) + Perl_croak(aTHX_ "epoll_pwait: sigmask is not of type POSIX::SigSet"); + + /* This code borrowed from POSIX.xs */ + IV tmp = SvIV((SV*)SvRV(sigmask)); + sigmask_real = INT2PTR(sigset_t*, tmp); + } + else { + sigmask_real = NULL; + } + + events = (struct epoll_event *)malloc(maxevents * sizeof(struct epoll_event)); + if (!events) { + errno = ENOMEM; + XSRETURN_UNDEF; + } + ret = epoll_pwait(epfd, events, maxevents, timeout, sigmask_real); + if (ret < 0) { + free(events); + XSRETURN_UNDEF; + } else { + AV *results = (AV*)sv_2mortal((SV*)newAV()); + for (i = 0; i < ret; i++) { + AV *ev = (AV*)sv_2mortal((SV*)newAV()); + av_push(ev, newSVnv(events[i].data.fd)); + av_push(ev, newSVnv(events[i].events)); + av_push(results, newRV((SV*) ev)); + } + RETVAL = newRV((SV *)results); + free(events); + } +OUTPUT: + RETVAL === modified file 'lib/IO/Epoll.pm' --- lib/IO/Epoll.pm 2008-11-23 17:35:55 +0000 +++ lib/IO/Epoll.pm 2008-11-23 17:42:03 +0000 @@ -36,6 +36,7 @@ epoll_create epoll_ctl epoll_wait + epoll_pwait ) ], 'compat' => [ qw( POLLIN @@ -71,6 +72,7 @@ epoll_create epoll_ctl epoll_wait + epoll_pwait ); our $VERSION = '0.01'; @@ -109,11 +111,12 @@ # [1] maps fd's to returned masks # [2] maps fd's to handles # [3] is the epoll fd +# [4] is the signal mask, if used. If present will use epoll_pwait() instead of epoll_wait() sub new { my $package = shift; - my $self = bless [ {}, {}, {}, undef ] => $package; + my $self = bless [ {}, {}, {}, undef, undef ] => $package; $self->[3] = epoll_create(15); if ($self->[3] < 0) { @@ -181,7 +184,7 @@ my $msec = defined $timeout ? $timeout * 1000 : -1; - my $ret = epoll_wait($self->[3], $maxevents, $msec); + my $ret = epoll_pwait($self->[3], $maxevents, $msec, $self->[4]); return -1 unless defined $ret; foreach my $event (@$ret) { @@ -237,6 +240,47 @@ POSIX::close($self->[3]); } +# IO::Ppoll API extension + +sub sigmask +{ + my $self = shift; + + if( my ( $newmask ) = @_ ) { + $self->[4] = $newmask; + } + else { + $self->[4] ||= POSIX::SigSet->new(); + return $self->[4]; + } +} + +sub sigmask_add +{ + my $self = shift; + my @signals = @_; + + my $sigmask = $self->sigmask; + $sigmask->addset( $_ ) foreach @signals; +} + +sub sigmask_del +{ + my $self = shift; + my @signals = @_; + + my $sigmask = $self->sigmask; + $sigmask->delset( $_ ) foreach @signals; +} + +sub sigmask_ismember +{ + my $self = shift; + my ( $signal ) = @_; + + return $self->sigmask->ismember( $signal ); +} + # IO::Poll compatibility constants sub POLLNVAL () { 0 }; @@ -291,10 +335,11 @@ watched file descriptors. You will need at least version 2.5.44 of Linux to use this module, and you might need to upgrade your C library. -The C<epoll(2)> API comprises three system calls: C<epoll_create(2)>, -C<epoll_ctl(2)> and C<epoll_wait(2)>. C<IO::Epoll> provides a low-level -API which closely matches the underlying system calls. It also provides -a higher-level layer designed to emulate the behavior of C<IO::Poll>. +The C<epoll(2)> API comprises four system calls: C<epoll_create(2)>, +C<epoll_ctl(2)>, C<epoll_wait(2)> and C<epoll_pwait(2)>. C<IO::Epoll> +provides a low-level API which closely matches the underlying system calls. +It also provides a higher-level layer designed to emulate the behavior of +C<IO::Poll> and C<IO::Ppoll>. =head1 LOW-LEVEL API @@ -365,6 +410,17 @@ On error, C<epoll_wait> returns undef and sets C<errno> appropriately. +=head2 epoll_pwait + +Wait for events on the C<epoll> file descriptor C<$epfd>. + + $ret = epoll_pwait($epfd, $maxevents, $timeout, $sigmask) + +Identical to C<epoll_wait>, except that the kernel will atomically swap the +current signal mask for the process to that supplied in C<$sigmask>, wait for +events, then restore it to what it was originally. The C<$sigmask> parameter +should be undef, or an instance of C<POSIX::SigSet>. + =back =head1 HIGH LEVEL API @@ -411,6 +467,39 @@ =back +=head1 IO::Ppoll METHODS + +IO::Epoll also provides methods compatible with IO::Ppoll. When any of these +methods are called, the IO::Epoll object switches up to IO::Ppoll-compatible +mode, and will use the C<epoll_pwait(2)> system call when the C<poll> method +is invoked. + +=over 4 + +=item sigmask + +Returns the C<POSIX::SigSet> object in which the signal mask is stored. Since +this is a reference to the object used in the call to C<epoll_pwait(2)>, any +modifications made to it will be reflected in the signal mask given to the +system call. + +=item sigmask_add ( SIGNALS ) + +Adds the given signals to the signal mask. These signals will be blocked +during the C<poll> call. + +=item sigmask_del ( SIGNALS ) + +Removes the given signals from the signal mask. These signals will not be +blocked during the C<poll> call, and may be delivered while C<poll> is +waiting. + +=item sigmask_ismember ( SIGNAL ) + +Tests if the given signal is present in the signal mask. + +=back + =head1 Exportable constants @@ -446,8 +535,8 @@ =head1 SEE ALSO -C<IO::Poll> C<IO::Select> C<epoll(4)> C<epoll_create(2)> C<epoll_ctl(2)> -C<epoll_wait(2)> +C<IO::Poll> C<IO::Select> C<IO::Ppoll> C<epoll(4)> C<epoll_create(2)> +C<epoll_ctl(2)> C<epoll_wait(2)> C<epoll_pwait(2)> =head1 AUTHOR === added file 't/IO-Ppoll-compat.t' --- t/IO-Ppoll-compat.t 1970-01-01 00:00:00 +0000 +++ t/IO-Ppoll-compat.t 2008-11-23 17:42:03 +0000 @@ -0,0 +1,59 @@ +#!/usr/bin/perl -w + +use strict; + +use Test::More tests => 10; + +use IO::Epoll; + +use POSIX qw( + sigprocmask SIG_BLOCK + SIGHUP SIGTERM SIGUSR1 SIGUSR2 + EINTR +); + +my $epoll = IO::Epoll->new(); + +ok( !$epoll->sigmask_ismember( SIGHUP ), 'SIGHUP not in initial set' ); + +$epoll->sigmask_add( SIGHUP ); + +ok( $epoll->sigmask_ismember( SIGHUP ), 'SIGHUP now in set' ); + +$epoll->sigmask_del( SIGHUP ); + +ok( !$epoll->sigmask_ismember( SIGHUP ), 'SIGHUP no longer in set' ); + +my $SIGHUP_count = 0; +$SIG{HUP} = sub { $SIGHUP_count++ }; + +kill SIGHUP, $$; + +is( $SIGHUP_count, 1, 'Caught SIGHUP before sigprocmask' ); + +sigprocmask( SIG_BLOCK, POSIX::SigSet->new( SIGHUP ) ); + +kill SIGHUP, $$; + +is( $SIGHUP_count, 1, 'Not caught SIGHUP after sigprocmask' ); + +my $ret = $epoll->poll( 0.1 ); +my $dollarbang = $!+0; + +is( $ret, -1, 'poll() returns undef' ); +is( $dollarbang, EINTR, 'poll() failed with EINTR' ); + +is( $SIGHUP_count, 2, 'Caught SIGHUP after poll' ); + +sigprocmask( SIG_BLOCK, POSIX::SigSet->new( SIGTERM ) ); +$epoll->sigmask_add( SIGTERM ); + +my $SIGTERM_count = 0; +$SIG{TERM} = sub { $SIGTERM_count++ }; + +kill SIGTERM, $$; + +$ret = $epoll->poll( 0.1 ); + +is( $ret, 0, 'poll() returns 0' ); +is( $SIGTERM_count, 0, 'Not caught SIGTERM after poll()' );
On Fri Jan 23 13:07:35 2009, PEVANS wrote: Show quoted text
> This patch adds a new syscall function, epoll_pwait(), and extends the > high-level API object methods to cover those methods added by IO::Ppoll, > which covers the signal mask in the same way. > > This allows an IO::Epoll object to perform signal-safe polling in a > manner identical to IO::Ppoll.
Now fixed in 0.02 from CPAN. Thanks. -- Paul Evans