This patch:
- implements Apache::SubProcess::spawn_proc_prog (which allows to run a
  program in a spawned process and provides in/out/err pipes to it)

Issues:
- optional functions use explodes during compilation under 5.6.1 (have no
  idea why, it compiles cleanly with bleadperl)
- need more error checkings

Index: xs/maps/modperl_functions.map
===================================================================
RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_functions.map,v
retrieving revision 1.29
diff -u -r1.29 modperl_functions.map
--- xs/maps/modperl_functions.map       2001/11/15 18:19:56     1.29
+++ xs/maps/modperl_functions.map       2001/12/14 18:14:40
@@ -90,3 +90,7 @@
 PACKAGE=Apache
 DEFINE_LOG_MARK   | MPXS_Apache_LOG_MARK       | ...
 DEFINE_warn       | MPXS_Apache__Log_log_error | ...
+
+MODULE=Apache::SubProcess
+ # ap_subprocess_ won't work
+ modperl_spawn_proc_prog | MPXS_ | ... | spawn_proc_prog

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ t/response/TestApache/subprocess.pm Sat Dec 15 01:37:01 2001
@@ -0,0 +1,116 @@
+package TestApache::subprocess;
+
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Const -compile => 'OK';
+#use APR::Const -compile => 'SUCCESS';
+
+use Apache::Test;
+use Apache::TestUtil;
+use File::Spec::Functions qw(catfile catdir);
+
+
+use Apache::SubProcess ();
+
+# XXX: this should go away, when send_fd() is implemented
+use Apache::compat;
+
+my %scripts = (
+     argv   => 'print STDOUT "@ARGV";',
+     env    => 'print STDOUT $ENV{SubProcess}',
+     in_out => 'print STDOUT scalar <STDIN>;',
+     in_err => 'print STDERR scalar <STDIN>;',
+    );
+
+sub APACHE_TEST_CONFIGURE {
+    my ($class, $self) = @_;
+
+    my $vars = $self->{vars};
+
+    my $target_dir = catdir $vars->{documentroot}, "util";
+
+    while (my($file, $code) = each %scripts) {
+        $file = catfile $target_dir, "$file.pl";
+        $self->write_perlscript($file, "$code\n");
+    }
+}
+
+sub handler {
+    my $r = shift;
+
+    my $cfg = Apache::Test::config();
+    my $vars = $cfg->{vars};
+    plan $r, tests => 4;
+    my $target_dir = catfile $vars->{documentroot}, "util";
+    my $id = 0;
+
+    {
+        # test: passing argv + scalar context
+        $id++;
+        my $command = catfile $target_dir, "argv.pl";
+        my @argv = ('ok', $id);
+        my $in = Apache::SubProcess::spawn_proc_prog($r, $command, \@argv);
+        ok t_cmp(\@argv,
+                 [split / /, <$in>],
+                 "testing argv"
+                );
+    }
+
+    {
+        # test: passing env to subprocess through subprocess_env
+        $id++;
+        t_debug("testing subprocess_env");
+        my $command = catfile $target_dir, "env.pl";
+        $r->subprocess_env->set(SubProcess => "ok $id\n");
+        my $in = Apache::SubProcess::spawn_proc_prog($r, $command);
+        $r->send_fd($in);
+        $r->rflush;
+    }
+
+    {
+        # test: subproc's stdin -> stdout + list context
+        $id++;
+        my $command = catfile $target_dir, "in_out.pl";
+        my ($in, $out, $err) =
+            Apache::SubProcess::spawn_proc_prog($r, $command);
+        print $out "ok $id\n";
+        $r->send_fd($in);
+    }
+
+    {
+        # test: subproc's stdin -> stderr + list context
+        $id++;
+        my $command = catfile $target_dir, "in_err.pl";
+        my ($in, $out, $err) =
+            Apache::SubProcess::spawn_proc_prog($r, $command);
+        print $out "ok $id\n";
+        $r->send_fd($err);
+    }
+
+# these are wannabe's
+#    ok t_cmp(
+#             Apache::SUCCESS,
+#             Apache::SubProcess::spawn_proc_sub($r, $sub, \@args),
+#             "spawn a subprocess and run a subroutine in it"
+#            );
+
+#    ok t_cmp(
+#             Apache::SUCCESS,
+#             Apache::SubProcess::spawn_thread_prog($r, $command, \@argv),
+#             "spawn thread and run a program in it"
+#            );
+
+#     ok t_cmp(
+#             Apache::SUCCESS,
+#             Apache::SubProcess::spawn_thread_sub($r, $sub, \@args),
+#             "spawn thread and run a subroutine in it"
+#            );
+
+   Apache::OK;
+}
+
+
+1;
+__DATA__
+PerlModule Apache::SubProcess

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/Apache/SubProcess/Apache__SubProcess.h   Sat Dec 15 01:47:40 2001
@@ -0,0 +1,178 @@
+#include "../../APR/PerlIO/apr_perlio.h"
+
+#ifndef MP_SOURCE_SCAN
+#include "apr_optional.h"
+#endif
+
+#ifndef MP_SOURCE_SCAN
+static APR_OPTIONAL_FN_TYPE(apr_perlio_apr_file_to_glob) *apr_file_to_glob;
+#endif
+
+/* XXX: probably needs a lot more error checkings */
+
+typedef struct {
+    apr_int32_t    in_pipe;
+    apr_int32_t    out_pipe;
+    apr_int32_t    err_pipe;
+    apr_cmdtype_e  cmd_type;
+} exec_info;
+
+
+#define FAILED(command) ((rc = command) != APR_SUCCESS)
+
+static int modperl_spawn_proc_prog(request_rec *r,
+                                          const char *command,
+                                          const char ***argv,
+                                          apr_file_t **script_in,
+                                          apr_file_t **script_out,
+                                          apr_file_t **script_err)
+{
+    exec_info e_info;
+    apr_pool_t *p;
+    const char * const *env;
+
+    apr_procattr_t *procattr;
+    apr_proc_t *procnew;
+    apr_status_t rc = APR_SUCCESS;
+
+    e_info.in_pipe   = APR_CHILD_BLOCK;
+    e_info.out_pipe  = APR_CHILD_BLOCK;
+    e_info.err_pipe  = APR_CHILD_BLOCK;
+    e_info.cmd_type  = APR_PROGRAM;
+
+    p = r->main ? r->main->pool : r->pool;
+
+    *script_out = NULL;
+    *script_in  = NULL;
+    *script_err = NULL;
+
+    env = (const char* const*)ap_create_environment(p, r->subprocess_env);
+
+    if ( FAILED(apr_procattr_create(&procattr, p)) ||
+         FAILED(apr_procattr_io_set(procattr, e_info.in_pipe,
+                                    e_info.out_pipe, e_info.err_pipe)) ||
+         FAILED(apr_procattr_dir_set(procattr,
+                                     ap_make_dirstr_parent(r->pool,
+                                                           r->filename))) ||
+         FAILED(apr_procattr_cmdtype_set(procattr, e_info.cmd_type))) {
+        /* Something bad happened, tell the world. */
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
+                      "couldn't set child process attributes: %s",
+                      r->filename);
+        return rc;
+    }
+
+    procnew = apr_pcalloc(p, sizeof(*procnew));
+    if FAILED(ap_os_create_privileged_process(r, procnew, command,
+                                              *argv, env, procattr, p)) {
+        /* Bad things happened. Everyone should have cleaned up. */
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
+                      "couldn't create child process: %d: %s", rc, r->filename);
+        return rc;
+    }
+
+    apr_pool_note_subprocess(p, procnew, kill_after_timeout);
+
+    *script_in = procnew->out;
+    if (!script_in)
+        return APR_EBADF;
+    apr_file_pipe_timeout_set(*script_in,
+                              (int)(r->server->timeout * APR_USEC_PER_SEC));
+
+    *script_out = procnew->in;
+    if (!script_out)
+        return APR_EBADF;
+    apr_file_pipe_timeout_set(*script_out,
+                              (int)(r->server->timeout * APR_USEC_PER_SEC));
+
+    *script_err = procnew->err;
+    if (!*script_err)
+        return APR_EBADF;
+    apr_file_pipe_timeout_set(*script_err,
+                              (int)(r->server->timeout * APR_USEC_PER_SEC));
+
+    return rc;
+}
+
+
+static XS(MPXS_modperl_spawn_proc_prog)
+{
+    dXSARGS;
+
+    /* XXX: more args here! */
+    if (items < 2) {
+        Perl_croak(aTHX_ "Usage: XXX");
+    }
+
+    SP -= items;
+    {
+        apr_file_t *script_in, *script_out, *script_err;
+        apr_status_t rc;
+        const char **argv;
+        int i;
+        AV *av_argv;
+        request_rec *r = modperl_xs_sv2request_rec(aTHX_ ST(0), NULL, cv);
+        const char *command = (const char *)SvPV_nolen(ST(1));
+
+        if (items == 3) {
+            /* XXX: should test if it a ref to an array before deref it */
+            av_argv = (AV*)SvRV(ST(2));
+        }
+        else {
+            av_argv = newAV();
+        }
+
+        /* ap_os_create_privileged_process expects ARGV as char
+         * **argv, with terminating NULL and the program itself as a
+         * first item.
+         */
+        argv = apr_palloc(r->pool,
+                          ( 3 + av_len(av_argv) ) * sizeof(char*) );
+        argv[0] = command;
+        for (i = 0; i <= av_len(av_argv); i++) {
+            argv[i+1] = (const char *)SvPV_nolen(AvARRAY(av_argv)[i]);
+            Perl_warn(aTHX_ "arg: %d %s\n", i, argv[i+1]);
+        }
+        argv[i+1] = NULL;
+
+/*         for (i=0; i<=av_len(av_argv)+2; i++) { */
+/*             Perl_warn(aTHX_ "arg: %d %s\n", i, argv[i]); */
+/*         } */
+
+        rc = modperl_spawn_proc_prog(r, command, &argv,
+                                            &script_in, &script_out,
+                                            &script_err);
+        if (rc == APR_SUCCESS) {
+            apr_file_to_glob =
+                APR_RETRIEVE_OPTIONAL_FN(apr_perlio_apr_file_to_glob);
+
+            if (GIMME == G_SCALAR) {
+                /* need to do lots of error checking before putting on
+                 * stack */
+                XPUSHs(apr_file_to_glob(aTHX_ script_in,
+                                        r->pool, APR_PERLIO_HOOK_READ));
+                rc = apr_file_close(script_out);
+                if (rc != APR_SUCCESS) {
+                    XSRETURN_UNDEF;
+                }
+                rc = apr_file_close(script_err);
+                if (rc != APR_SUCCESS) {
+                    XSRETURN_UNDEF;
+                }
+            }
+            else {
+                XPUSHs(apr_file_to_glob(aTHX_ script_in,
+                                        r->pool, APR_PERLIO_HOOK_READ));
+                XPUSHs(apr_file_to_glob(aTHX_ script_out,
+                                        r->pool, APR_PERLIO_HOOK_WRITE));
+                XPUSHs(apr_file_to_glob(aTHX_ script_err,
+                                        r->pool, APR_PERLIO_HOOK_READ));
+            }
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    }
+
+    PUTBACK;
+}

--- /dev/null   Thu Jan  1 07:30:00 1970
+++ xs/Apache/SubProcess/SubProcess_pm  Fri Dec 14 13:14:04 2001
@@ -0,0 +1 @@
+use APR::PerlIO ();



_____________________________________________________________________
Stas Bekman             JAm_pH      --   Just Another mod_perl Hacker
http://stason.org/      mod_perl Guide   http://perl.apache.org/guide
mailto:[EMAIL PROTECTED]  http://ticketmaster.com http://apacheweek.com
http://singlesheaven.com http://perl.apache.org http://perlmonth.com/


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to