#line 335 "/home/travis/build/felix-lang/felix/src/packages/program.fdoc"
  
  class PosixProcess {
    open PosixSignal;
  
    instance Process_class[Posix, process_status_t]
    {
      gen popen_in: string -> Cstdio::ifile = 'popen($1.c_str(), "r")'
        requires C89_headers::stdio_h;
      gen pclose: Cstdio::ifile -> process_status_t = "pclose($1)";
    }
    inherit Process_class[Posix, process_status_t];
  
    type process_status_t = "int" requires Posix_headers::sys_wait_h;
    ctor int:process_status_t = "$1";
    ctor process_status_t : int = "$1";
    fun int_of_process_status_t: process_status_t -> int = "(int)$1";
  
    fun WIFCONTINUED: process_status_t -> bool = "WIFCONTINUED($1)!=0";
    fun WIFEXITED: process_status_t -> bool = "WIFEXITED($1)!=0";
    fun WIFSIGNALED: process_status_t -> bool = "WIFSIGNALED($1)!=0";
    fun WIFSTOPPED: process_status_t -> bool = "WIFSTOPPED($1)!=0";
  
    fun WEXITSTATUS: process_status_t -> int = "WEXITSTATUS($1)";
    fun WTERMSIG: process_status_t -> signal_t = "WTERMSIG($1)";
    fun WSTOPSIG: process_status_t -> signal_t = "WSTOPSIG($1)";
  
    // OSX only, not in Posix
    fun  WCOREDUMP: process_status_t -> int = "WCOREDUMP($1)";
  
  
    fun str(x:process_status_t) = {
      if WIFEXITED x do
         val e = x.WEXITSTATUS;
         return "Exit " + str e + ": " +e.errno_t.strerror;
      elif WIFSIGNALED x do
         val s = x.WTERMSIG;
         return "SIGNAL " + s.int.str + ": " + s.str;
      else
         return "Unknown temination status " + x.int.str;
      done
    }
  
    const environ: + (+char) = "environ" requires Posix_headers::unistd_h;
  
    type exec_result_t = "int";
    const bad_exec: exec_result_t = "-1";
    fun == : exec_result_t * exec_result_t -> bool= "$1==$2";
  
    gen execv:+char *  + (+char) -> exec_result_t = "execv($1, $2)" requires Posix_headers::unistd_h;
    gen execvp:+char *  + (+char) -> exec_result_t = "execvp($1, $2)" requires Posix_headers::unistd_h;
    gen execve:+char *  + (+char) * + (+char) -> exec_result_t = "execve($1, $2, $3)" requires Posix_headers::unistd_h;
  
    // do NOT try to fork Felix programs, it doesn't work
    // because of threads already running. We use fork only
    // to preceed exec() calls.
    type pid_t = "pid_t" requires Posix_headers::unistd_h;
  
    instance Str[pid_t] {
      fun str: pid_t -> string = "::flx::rtl::strutil::str<int>($1)" requires package "flx_strutil";
    }
  
    ctor int: pid_t = "((int)$1)";
    const child_process : pid_t = "0";
    const bad_process : pid_t = "-1";
    fun == : pid_t * pid_t -> bool= "$1==$2";
  
    gen fork: unit -> pid_t = "fork()" requires Posix_headers::unistd_h;
  
    union spawn_result_t =
    // returned to parent process
    | BadFork of errno_t
    | ProcessId of pid_t
  
    // returned to child proces
    | BadExec of errno_t
    | BadSetup of int
    ;
  
    gen spawnv(file: string, argv:+ (+char), setup:1->int) : spawn_result_t = {
      var x = fork();
      if x == child_process do  // CHILD
        var result = #setup;
        if result != 0 do
          return BadSetup result;
        done
        var y = execv(file.cstr, argv);
        if y == bad_exec do
          return BadExec errno;
        else
          return ProcessId x; // never taken! fool type system
        done
      elif x == bad_process do // PARENT
        return BadFork errno;
      else
        return ProcessId x;
      done
    }
  
    gen spawnvp(file: string, argv:+ (+char), setup:1->int) : spawn_result_t = {
      var x = fork();
      if x == child_process do // CHILD
        var result = #setup;
        if result != 0 do
          return BadSetup result;
        done
        var y = execvp(file.cstr, argv);
        if y == bad_exec do
          return BadExec errno;
        else
          return ProcessId x; // never taken! fool type system
        done
      elif x == bad_process do  // PARENT
        return BadFork errno;
      else
        return ProcessId x;
      done
    }
  
    gen spawnve(file: string, argv:+ (+char), env: + (+char), setup:1->int) : spawn_result_t = {
      var x = fork();
      if x == child_process do // CHILD
        var result = #setup;
        if result != 0 do
          return BadSetup result;
        done
        var y = execve(file.cstr, argv, env);
        if y == bad_exec do
          return BadExec errno;
        else
          return ProcessId x; // never taken! fool type system
        done
      elif x == bad_process do // PARENT
        return BadFork errno;
      else
        return ProcessId x;
      done
    }
  
    type process_status_options_t = "int";
    const WCONTINUED: process_status_options_t;
    const WNOHANG: process_status_options_t;
    const WUNTRACED: process_status_options_t;
    const WNONE: process_status_options_t="0";
    fun \| : process_status_options_t * process_status_options_t -> process_status_options_t = "$1|$2";
  
    gen waitpid: pid_t * &process_status_t * process_status_options_t -> pid_t requires Posix_headers::sys_wait_h;
  
    gen waitpid(pid:pid_t) = {
      var status: process_status_t;
      var pid' = waitpid(pid,&status,WNONE);
      if pid' == bad_process do
        println$ "Waitpid failed .. fix me!";
        System::exit 1;
      else
        return status;
      done
    }
  
    union ProcesStatus= | Running | Stopped of process_status_t;
  
    gen checkpid(pid:pid_t) = {
      var status: process_status_t;
      var pid' = waitpid(pid,&status,WNOHANG);
      if pid' == bad_process do
        println$ "Waitpid failed .. fix me!";
        System::exit 1;
      elif pid'.int == 0 do
        return Running;
      else
        return Stopped status;
      done
    }
  
    gen kill: pid_t * signal_t -> int;
    const OUR_PROCESS_GROUP: pid_t = "0";
  
  }