add os.ForkExec, os.Exec, os.Wait, exec.OpenCmd.
as thread-safe as possible, given the surrounding system.
add stub RWLock implementation.

R=r
DELTA=852  (834 added, 6 deleted, 12 changed)
OCL=25046
CL=25053
diff --git a/src/lib/os/file.go b/src/lib/os/file.go
index d472576..24aab12 100644
--- a/src/lib/os/file.go
+++ b/src/lib/os/file.go
@@ -4,8 +4,10 @@
 
 package os
 
-import syscall "syscall"
-import os "os"
+import (
+	"os";
+	"syscall";
+)
 
 // Auxiliary information if the FD describes a directory
 type dirInfo struct {	// TODO(r): 6g bug means this can't be private
@@ -57,7 +59,17 @@
 )
 
 func Open(name string, mode int, flags int) (fd *FD, err *Error) {
-	r, e := syscall.Open(name, int64(mode), int64(flags));
+	r, e := syscall.Open(name, int64(mode), int64(flags | syscall.O_CLOEXEC));
+	if e != 0 {
+		return nil, ErrnoToError(e);
+	}
+
+	// There's a race here with fork/exec, which we are
+	// content to live with.  See ../syscall/exec.go
+	if syscall.O_CLOEXEC == 0 {	// O_CLOEXEC not supported
+		syscall.CloseOnExec(r);
+	}
+
 	return NewFD(r, name), ErrnoToError(e)
 }
 
@@ -122,10 +134,18 @@
 
 func Pipe() (fd1 *FD, fd2 *FD, err *Error) {
 	var p [2]int64;
+
+	// See ../syscall/exec.go for description of lock.
+	syscall.ForkLock.RLock();
 	r, e := syscall.Pipe(&p);
 	if e != 0 {
+		syscall.ForkLock.RUnlock();
 		return nil, nil, ErrnoToError(e)
 	}
+	syscall.CloseOnExec(p[0]);
+	syscall.CloseOnExec(p[1]);
+	syscall.ForkLock.RUnlock();
+
 	return NewFD(p[0], "|0"), NewFD(p[1], "|1"), nil
 }