diff --git a/lib/modules/Process.pmod b/lib/modules/Process.pmod index 690c2219e5891775139e6f5f47705f038306feaf..8a6413b42c230eb33513020fc7e189365518e7cc 100644 --- a/lib/modules/Process.pmod +++ b/lib/modules/Process.pmod @@ -114,3 +114,114 @@ constant fork = predef::fork; constant exece = predef::exece; + +class Spawn +{ + object stdin; + object stdout; + object stderr; + array(object) fd; + + int pid; + + private int low_spawn(array(void|object(Stdio.File)) fdp, + array(void|object(Stdio.File)) fd_to_close, + string cmd, void|string *args, + void|mapping(string:string) env, + string|void cwd) + { + object(Stdio.File) pie,pied; /* interprocess communication */ + int pid; + + pie=Stdio.File(); + pied=pie->pipe(); + + if(!(pid=fork())) + { + mixed err=catch + { + if(cwd && !cd(cwd)) + { + throw(({"pike: cannot change cwd to "+cwd+ + ": "+strerror(errno())+"\n", + backtrace()})); + } + + if (sizeof(fdp)>0 && fdp[0]) fdp[0]->dup2(Stdio.File("stdin")); + if (sizeof(fdp)>1 && fdp[1]) fdp[1]->dup2(Stdio.File("stdout")); + if (sizeof(fdp)>2 && fdp[2]) fdp[2]->dup2(Stdio.File("stderr")); + /* dup2 fdd[3..] here FIXME FIXME */ + foreach (fd_to_close,object f) + if (objectp(f)) { f->close(); destruct(f); } + pie->close(); + destruct(pie); + + pied->set_close_on_exec(1); + + if (env) + exece(cmd,args||({}),env); + else + exece(cmd,args||({})); + + throw(({"pike: failed to exece "+cmd+ + ": "+strerror(errno())+"\n", + backtrace()})); + }; + + pied->write(encode_value(err)); + exit(1); + } + + foreach (fdp,object f) if (objectp(f)) { f->close(); destruct(f); } + + pied->close(); + destruct(pied); + + mixed err=pie->read(); + if (err && err!="") throw(decode_value(err)); + + pie->close(); + destruct(pie); + + return pid; + } + + void create(string cmd, + void|array(string) args, + void|mapping(string:string) env, + string|void cwd, + void|array(object(Stdio.File)|void) ownpipes, + void|array(object(Stdio.File)|void) fds_to_close) + { + if (!ownpipes) + { + stdin=Stdio.File(); + stdout=Stdio.File(); + stderr=Stdio.File(); + fd=({stdin->pipe(),stdout->pipe(),stderr->pipe()}); + fds_to_close=({stdin,stdout,stderr}); + } + else + { + fd=ownpipes; + if (sizeof(fd)>0) stdin=fd[0]; else stdin=0; + if (sizeof(fd)>1) stdout=fd[1]; else stdout=0; + if (sizeof(fd)>2) stderr=fd[2]; else stderr=0; + } + pid=low_spawn(fd,fds_to_close||({}),cmd,args,env,cwd); + } + + int kill(int signal) + { + return predef::kill(pid,signal); + } + + void wait() + { + while (kill(0)) sleep(0.01); + } + + // void set_done_callback(function foo,mixed ... args); + // int result(); + // array rusage(); +} diff --git a/tutorial/tutorial.wmml b/tutorial/tutorial.wmml index a0dd6b4ae30a5e0965011728c85191f054be060e..d06bb8266a5786f6c4df3c7c7dfcf28eb49a41fa 100644 --- a/tutorial/tutorial.wmml +++ b/tutorial/tutorial.wmml @@ -5838,6 +5838,83 @@ exec("/bin/echo","hello","world");<br> </man_example> </function> + +<class name=Process.Spawn + title="spawn off another program with control structure"> +<man_syntax> +object Process.Spawn(string program, + void|array(string) args, + void|mapping(string:string) env, + void|string cwd); <br> +or +object Process.Spawn(string program, + void|array(string) args, + void|mapping(string:string) env, + void|string cwd, + array(void|object(Stdio.file)) fds, + void|array(void|object(Stdio.file)) fds_to_close); + +</man_syntax> +<man_description> +Spawn off another program (<tt>program</tt>) and creates +the control structure. This does not spawn off a shell to +find the program, therefore must <tt>program</tt> be the full +path the the program.<p> + +<tt>args</tt> is per default no argument(s),<p> + +<tt>env</tt> is reset to the given mapping, or kept if the +argument is <tt>0</tt>. + +<tt>fds</tt> is your stdin, stdout and stderr. Default +is local pipes (see <link to=stdin>stdin</link> et al). + +<tt>fds_to_close</tt> is file descriptors that are closed +in the forked branch when the program is executed (ie, the +other end of the pipes). +</man_description> + +<variable name=stdin,stdout,stderr,fd title="pipes to the program"> +<man_syntax> +object(Stdio.File) stdin;<br> +object(Stdio.File) stdout;<br> +object(Stdio.File) stderr;<br> +array(void|object(Stdio.File)) fd;<br> +</man_syntax> +<man_description> +Pipes to the spawned program (if set). fd[0]==stdin, etc. +</man_description> +</variable> + +<variable name=pid title="spawned program pid"> +<man_syntax> +int pid; +</man_syntax> +<man_description> +pid of the spawned program. +</man_description> +</variable> + +<method name=wait title="wait for the spawned program to finish"> +<man_syntax> +void wait(); +</man_syntax> +<man_description> +Returns when the program has exited. +</man_description> +</method> + +<method name=kill title="send a signal to the program"> +<man_syntax> +int kill(int signal); +</man_syntax> +<man_description> +Sends a signal to the program. +</man_description> +</method> + +</class> + </section> </module>