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.

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?)

For the most part, you'll probably just be using APR::POLLIN.

For an example of usage, check out
t/protocol/TestProtocol/echo_nonblocking.pm. Or, in a pinch:

 use Apache::Connection ();
 use APR::Socket ();
 use APR::Poll ();
 use APR::Const -compile qw(POLLIN SUCCESS TIMEUP);

 # Assume $c is an Apache::Connection
 my $s = $c->client_socket();
 
 # Wait up to one second to see if inbound data is waiting on the
 # socket:
 my $rc = APR::Poll->poll($c->pool, $s, 1_000_000, APR::POLLIN);

 if($rc == APR::TIMEUP) {
   # No data was available before our 1 second ran out
 elsif($rc == APR::SUCCESS) {
   # Ahaa -- data is available. Now we can receive on the socket.
   $s->recv(...);
 }

Now, onwards with Apache::SMTP!

diff mod_perl-1.99_16/t/protocol/TestProtocol/echo_nonblock.pm 
mod_perl-1.99_16.withpoll/t/protocol/TestProtocol/echo_nonblock.pm
--- mod_perl-1.99_16/t/protocol/TestProtocol/echo_nonblock.pm   Wed Dec 31 16:00:00 
1969
+++ mod_perl-1.99_16.withpoll/t/protocol/TestProtocol/echo_nonblock.pm  Fri Aug 27 
21:31:49 2004
@@ -0,0 +1,64 @@
+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::Const -compile => 'OK';
+use APR::Const    -compile => qw(SO_NONBLOCK TIMEUP SUCCESS POLLIN);
+
+use constant BUFF_LEN => 1024;
+
+sub handler {
+    my Apache::Connection $c = shift;
+    my APR::Socket $socket = $c->client_socket;
+
+    # 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";
+    }
+
+    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) {
+            my $buf;
+            if($socket->recv($buf, BUFF_LEN)) {
+                warn "no timeout";
+                $socket->send($buf);
+            }
+            else {
+                last;
+            }
+        }
+        elsif($rc == APR::TIMEUP) {
+            warn "timeout";
+            $socket->send("TIMEUP\n");
+        }
+        else {
+            die "poll error: $rc: " . APR::Error::strerror($rc);
+        }
+    }
+
+    Apache::OK;
+}
+
+1;

diff mod_perl-1.99_16/t/protocol/echo_nonblock.t 
mod_perl-1.99_16.withpoll/t/protocol/echo_nonblock.t
--- mod_perl-1.99_16/t/protocol/echo_nonblock.t Wed Dec 31 16:00:00 1969
+++ mod_perl-1.99_16.withpoll/t/protocol/echo_nonblock.t        Fri Aug 27 21:32:44 
2004
@@ -0,0 +1,27 @@
+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";
+$reply = <$socket>;
+chomp($reply);
+ok t_cmp($reply, 'nonblocking');
+
+# 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');
+

diff mod_perl-1.99_16/xs/APR/Poll/APR__Poll.h 
mod_perl-1.99_16.withpoll/xs/APR/Poll/APR__Poll.h
--- mod_perl-1.99_16/xs/APR/Poll/APR__Poll.h    Wed Dec 31 16:00:00 1969
+++ mod_perl-1.99_16.withpoll/xs/APR/Poll/APR__Poll.h   Fri Aug 27 21:17:12 2004
@@ -0,0 +1,49 @@
+/* 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
+int mpxs_apr_poll(pTHX_ 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;
+  apr_status_t rv;
+
+  /* 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 */
+  rv = apr_poll(&fd, 1, &nsds, timeout);
+
+  return rv;
+}

diff mod_perl-1.99_16/xs/maps/apr_functions.map 
mod_perl-1.99_16.withpoll/xs/maps/apr_functions.map
--- mod_perl-1.99_16/xs/maps/apr_functions.map  Fri Aug 20 14:11:00 2004
+++ mod_perl-1.99_16.withpoll/xs/maps/apr_functions.map Fri Aug 27 21:46:41 2004
@@ -635,3 +635,8 @@
 -apr_os_proc_mutex_put
 -apr_os_shm_get
 -apr_os_shm_put
+
+MODULE=APR::Poll
+ apr_poll | mpxs_ | \
+   SV *:CLASS, apr_pool_t *:pool, apr_socket_t *:socket, \
+   apr_interval_time_t:timeout, apr_int16_t:reqevents | poll

-- 
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

Reply via email to