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>