Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] View of /sml/trunk/src/system/Basis/Implementation/Unix/unix.sml
ViewVC logotype

View of /sml/trunk/src/system/Basis/Implementation/Unix/unix.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1506 - (download) (annotate)
Thu Jun 17 22:19:15 2004 UTC (16 years, 8 months ago) by mblume
File size: 5809 byte(s)
structure Unix now up to (the broken) spec
(* unix.sml
 *
 * COPYRIGHT (c) 1995 AT&T Bell Laboratories.
 *
 *)

structure Unix : UNIX =
  struct

    structure P = Posix.Process
    structure PS = POSIX_Signal
    structure PE = Posix.ProcEnv
    structure PF = Posix.FileSys
    structure PIO = Posix.IO
    structure SS = Substring

    type signal = PS.signal
    datatype exit_status = datatype P.exit_status

    datatype ('a, 'b) proc =
	     PROC of { base: string,
		       pid  : P.pid,
		       infd : PIO.file_desc,
		       outfd: PIO.file_desc,
		       (* The following two elements are a temporary
			* hack until the general interface is sorted out.
			* The idea is to have "reap" close the most recently
			* created stream.  If no stream has been created,
			* then the file descriptors get closed directly. *)
		       closein: (unit -> unit) ref,
		       closeout: (unit -> unit) ref,
		       exit_status: OS.Process.status option ref }

    val fromStatus = P.fromStatus

    fun protect f x = let
          val _ = Signals.maskSignals Signals.MASKALL
          val y = (f x) handle ex => 
                    (Signals.unmaskSignals Signals.MASKALL; raise ex)
          in
            Signals.unmaskSignals Signals.MASKALL; y
          end

    fun fdTextReader (name : string, fd : PIO.file_desc) =
	  PosixTextPrimIO.mkReader {
              initBlkMode = true,
              name = name,
              fd = fd
            }

    fun fdBinReader (name : string, fd : PIO.file_desc) =
	  PosixBinPrimIO.mkReader {
              initBlkMode = true,
              name = name,
              fd = fd
            }

    fun fdTextWriter (name, fd) =
          PosixTextPrimIO.mkWriter {
	      appendMode = false,
              initBlkMode = true,
              name = name,
              chunkSize=4096,
              fd = fd
            }

    fun fdBinWriter (name, fd) =
          PosixBinPrimIO.mkWriter {
	      appendMode = false,
              initBlkMode = true,
              name = name,
              chunkSize=4096,
              fd = fd
            }

    fun openTextOutFD (name, fd) =
	  TextIO.mkOutstream (
	    TextIO.StreamIO.mkOutstream (
	      fdTextWriter (name, fd), IO.BLOCK_BUF))

    fun openBinOutFD (name, fd) =
	  BinIO.mkOutstream (
	    BinIO.StreamIO.mkOutstream (
	      fdBinWriter (name, fd), IO.BLOCK_BUF))

    fun openTextInFD (name, fd) =
	  TextIO.mkInstream (
	    TextIO.StreamIO.mkInstream (
	      fdTextReader (name, fd), ""))

    fun openBinInFD (name, fd) =
	  BinIO.mkInstream (
	    BinIO.StreamIO.mkInstream (
	      fdBinReader (name, fd), Byte.stringToBytes ""))

    fun setcloser (r, f, s) = (r := (fn () => f s); s)

    fun textInstreamOf (PROC { base, infd, closein, ... }) =
	setcloser (closein, TextIO.closeIn,
		   openTextInFD (base ^ "_exec_txt_in", infd))
    fun binInstreamOf (PROC { base, infd, closein, ... }) =
	setcloser (closein, BinIO.closeIn,
		   openBinInFD (base ^ "_exec_bin_in", infd))
    fun textOutstreamOf (PROC { base, outfd, closeout, ... }) =
	setcloser (closeout, TextIO.closeOut,
		   openTextOutFD (base ^ "_exec_txt_out", outfd))
    fun binOutstreamOf (PROC { base, outfd, closeout, ... }) =
	setcloser (closeout, BinIO.closeOut,
		   openBinOutFD (base ^ "_exec_bin_out", outfd))

    fun streamsOf p = (textInstreamOf p, textOutstreamOf p)

    fun executeInEnv (cmd, argv, env) =
	let val p1 = PIO.pipe ()
            val p2 = PIO.pipe ()
            fun closep () =
		(PIO.close (#outfd p1); 
                 PIO.close (#infd p1);
                 PIO.close (#outfd p2); 
                 PIO.close (#infd p2))
            val base = SS.string(SS.taker (fn c => c <> #"/") (SS.all cmd))
            fun startChild () =
		case protect P.fork () of
		    SOME pid =>  pid           (* parent *)
		  | NONE =>
		    let val oldin = #infd p1
			val newin = Posix.FileSys.wordToFD 0w0
			val oldout = #outfd p2
			val newout = Posix.FileSys.wordToFD 0w1
                    in
			PIO.close (#outfd p1);
			PIO.close (#infd p2);
			if (oldin = newin) then ()
			else (PIO.dup2{old = oldin, new = newin};
                              PIO.close oldin);
			if (oldout = newout) then ()
			else (PIO.dup2{old = oldout, new = newout};
                              PIO.close oldout);
			P.exece (cmd, base::argv, env)
		    end
            val _ = TextIO.flushOut TextIO.stdOut
            val pid = (startChild ()) handle ex => (closep(); raise ex)
	    val infd = #infd p2
	    val outfd = #outfd p1
	in
            (* close the child-side fds *)
            PIO.close (#outfd p2);
            PIO.close (#infd p1);
            (* set the fds close on exec *)
            PIO.setfd (#infd p2, PIO.FD.flags [PIO.FD.cloexec]);
            PIO.setfd (#outfd p1, PIO.FD.flags [PIO.FD.cloexec]);
            PROC { base = base, pid = pid, infd = infd, outfd = outfd,
		   closein = ref (fn () => PIO.close infd),
		   closeout = ref (fn () => PIO.close outfd),
		   exit_status = ref NONE }
	end

    fun execute (cmd, argv) = executeInEnv (cmd, argv, PE.environ())

    fun kill (PROC{pid,...},signal) = P.kill (P.K_PROC pid, signal)

    fun reap (PROC { exit_status = ref (SOME s), ... }) = s
      | reap (PROC { exit_status, pid, closein, closeout, ... }) =
	let
            (* protect is probably too much; typically, one
             * would only mask SIGINT, SIGQUIT and SIGHUP
             *)
            fun waitProc () =
		case #2(protect P.waitpid (P.W_CHILD pid,[])) of
		    W_EXITED => 0
		  | W_EXITSTATUS s => Word8Imp.toInt s
		  | W_SIGNALED (PS.SIG s) => 256 + s
		  | W_STOPPED (PS.SIG s) => (* should not happen! *) 512 + s
	    val _ = !closein ()
	    val _ = !closeout () handle _ => ()
	    val s = waitProc ()
        in
	    exit_status := SOME s;
	    s
        end

    val exit = P.exit

  end (* structure Unix *)


root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0