This patch provides basic support for the apr_poll function. It's my first ever work on the guts of mod_perl, so please let me know if there are obvious things that need to be changed or reorganized to fit the mould.
It's good, Ken. I've done some tweaks (mostly style) and pasted a cleaned up version below.
- please post those to the dev list in the future - please use cvs diff to generate patches if possible - please use the style guide http://perl.apache.org/docs/2.0/devel/core/coding_style.html
The APR::Poll::poll method takes four parameters:
pool: an Apache::Pool socket: the Apache::Socket that you want to poll timeout: the number of microseconds to wait for data reqevents: a bitmap specifying the kinds of events for which you'd like to poll. APR::POLLIN - ready to read (i.e. inbound data has arrived) APR::POLLOUT - ready to write APR::POLLPRI - priority data available APR::POLLERR - an error is pending APR::POLLHUP - hangup occurred APR::POLLNVAL - invalid descriptor (what?)
I was thinking, would it be better to make it an APR::Socket method?
$socket->poll($c->pool, 1_000_000, APR::POLLIN);
looks more intuitive to me. Especially since you've hardcoded the fd type to be socket:
fd.desc_type = APR_POLL_SOCKET;
diff mod_perl-1.99_16/t/protocol/TestProtocol/echo_nonblock.pm mod_perl-1.99_16.withpoll/t/protocol/TestProtocol/echo_nonblock.pm
+ # starting from Apache 2.0.49 several platforms require you to set + # the socket to a blocking IO mode + my $nonblocking = $socket->opt_get(APR::SO_NONBLOCK); + unless($nonblocking) { + $socket->opt_set(APR::SO_NONBLOCK => 1); + + # test that we really *are* in the blocking mode + $socket->opt_get(APR::SO_NONBLOCK) + or die "failed to set nonblocking mode"; + }
I've replaced that with an explicit setting to a non-blocking mode.
Here is the patch:
Index: xs/maps/apr_functions.map =================================================================== RCS file: /home/cvs/modperl-2.0/xs/maps/apr_functions.map,v retrieving revision 1.85 diff -u -u -r1.85 apr_functions.map --- xs/maps/apr_functions.map 25 Aug 2004 22:32:01 -0000 1.85 +++ xs/maps/apr_functions.map 28 Aug 2004 14:03:03 -0000 @@ -3,16 +3,18 @@ # for mapping see %ModPerl::MapUtil::disabled_map in # lib/ModPerl/MapUtil.pm
-!MODULE=APR::Poll - apr_poll_socket_add - apr_poll_socket_clear - apr_poll_data_get - apr_poll_revents_get - apr_poll_socket_mask - apr_poll - apr_poll_socket_remove - apr_poll_data_set - apr_poll_setup +MODULE=APR::Poll + mpxs_APR__Poll_poll | | SV *:CLASS, apr_pool_t *:pool, \ + apr_socket_t *:socket, apr_interval_time_t:timeout, \ + apr_int16_t:reqevents +? apr_poll_socket_add +? apr_poll_socket_clear +? apr_poll_data_get +? apr_poll_revents_get +? apr_poll_socket_mask +? apr_poll_socket_remove +? apr_poll_data_set +? apr_poll_setup
!MODULE=APR::Time
-apr_ctime
Index: xs/tables/current/ModPerl/FunctionTable.pm
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
retrieving revision 1.176
diff -u -u -r1.176 FunctionTable.pm
--- xs/tables/current/ModPerl/FunctionTable.pm 25 Aug 2004 22:32:01 -0000 1.176
+++ xs/tables/current/ModPerl/FunctionTable.pm 28 Aug 2004 14:03:03 -0000
@@ -2,7 +2,7 @@
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # ! WARNING: generated by ModPerl::ParseSource/0.01 -# ! Wed Aug 25 14:56:13 2004 +# ! Sat Aug 28 09:47:20 2004 # ! do NOT edit, any changes will be lost ! # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -5516,6 +5516,32 @@ { 'type' => 'apr_pool_t *', 'name' => 'p' + } + ] + }, + { + 'return_type' => 'apr_status_t', + 'name' => 'mpxs_APR__Poll_poll', + 'args' => [ + { + 'type' => 'SV *', + 'name' => 'CLASS' + }, + { + 'type' => 'apr_pool_t *', + 'name' => 'pool' + }, + { + 'type' => 'apr_socket_t *', + 'name' => 'socket' + }, + { + 'type' => 'apr_interval_time_t', + 'name' => 'timeout' + }, + { + 'type' => 'apr_int16_t', + 'name' => 'reqevents' } ] },
--- /dev/null 1969-12-31 19:00:00.000000000 -0500
+++ t/protocol/echo_nonblock.t 2004-08-28 09:31:49.481052060 -0400
@@ -0,0 +1,26 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Test;
+use Apache::TestUtil;
+use Apache::TestRequest ();
+
+plan tests => 3;
+
+my $socket = Apache::TestRequest::vhost_socket('TestProtocol::echo_nonblock');
+
+ok $socket;
+
+my $reply;
+
+print $socket "nonblocking\n";
+chomp($reply = <$socket> || '');
+ok t_cmp $reply, 'nonblocking', "no timeout";
+
+# Wait two seconds so that the server will time out.
+sleep 2;
+
+print $socket "should timeout\n";
+chomp($reply = <$socket> || '');
+ok t_cmp $reply, 'TIMEUP', "timed out";
+
--- /dev/null 1969-12-31 19:00:00.000000000 -0500
+++ t/protocol/TestProtocol/echo_nonblock.pm 2004-08-28 09:58:18.955647897 -0400
@@ -0,0 +1,51 @@
+package TestProtocol::echo_nonblock;
+
+# this test reads from/writes to the socket doing nonblocking IO
+# using the APR::Poll interface.
+#
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Connection ();
+use APR::Socket ();
+use APR::Poll ();
+
+use Apache::TestTrace;
+
+use Apache::Const -compile => 'OK';
+use APR::Const -compile => qw(SO_NONBLOCK TIMEUP SUCCESS POLLIN);
+
+use constant BUFF_LEN => 1024;
+
+sub handler {
+ my $c = shift;
+ my $socket = $c->client_socket;
+
+ $socket->opt_set(APR::SO_NONBLOCK => 1);
+ while (1) {
+ # Wait up to one second for data to arrive.
+ my $rc = APR::Poll->poll($c->pool, $socket,
+ 1_000_000, APR::POLLIN);
+ if ($rc == APR::SUCCESS) {
+ if ($socket->recv(my $buf, BUFF_LEN)) {
+ debug "no timeout";
+ $socket->send($buf);
+ }
+ else {
+ last;
+ }
+ }
+ elsif ($rc == APR::TIMEUP) {
+ debug "timeout";
+ $socket->send("TIMEUP\n");
+ }
+ else {
+ die "poll error: $rc: " . APR::Error::strerror($rc);
+ }
+ }
+
+ Apache::OK;
+}
+
+1;
--- /dev/null 1969-12-31 19:00:00.000000000 -0500 +++ xs/APR/Poll/APR__Poll.h 2004-08-28 09:52:53.208612601 -0400 @@ -0,0 +1,46 @@ +/* Copyright 2004 MailChannels Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This is a very simplistic implementation of the APR::Poll interface. + * We only expose a bastardized version of the apr_poll() function, which + * in this case just allows you to poll one particular socket with + * a combination of polling options and a specified timeout. + * + * The pollset_* methods have not been included (they allow you to poll + * multiple sockets at one time. Nor has the ability to poll a file been + * provided because it's assumed that within, say, a protocol handler, + * you'd probably never need to. + * + * -- Ken Simpson, August 27, 2004. <[EMAIL PROTECTED]> + */ + +static MP_INLINE +apr_status_t mpxs_APR__Poll_poll(SV *CLASS, apr_pool_t *pool, + apr_socket_t *socket, apr_interval_time_t timeout, + apr_int16_t reqevents) +{ + apr_pollfd_t fd; + apr_int32_t nsds; + + /* Set up the aprset parameter, which tells apr_poll what to poll */ + fd.desc_type = APR_POLL_SOCKET; + fd.reqevents = reqevents; + fd.rtnevents = 0; /* XXX: not really necessary to set this */ + fd.p = pool; + fd.desc.s = socket; + + /* Poll the socket */ + return apr_poll(&fd, 1, &nsds, timeout); +}
-- __________________________________________________________________ Stas Bekman JAm_pH ------> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
-- Report problems: http://perl.apache.org/bugs/ Mail list info: http://perl.apache.org/maillist/modperl.html List etiquette: http://perl.apache.org/maillist/email-etiquette.html