[fuchsia] os: migrate StartProcess to using fdio_spawn
TC-155 #done
Change-Id: Ie6cc2c29d0cab0cb207b095e74e452484dd88de6
diff --git a/src/os/exec_fuchsia.go b/src/os/exec_fuchsia.go
index 52d227a..87d6020 100644
--- a/src/os/exec_fuchsia.go
+++ b/src/os/exec_fuchsia.go
@@ -63,7 +63,7 @@
}
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
- h, err := launchpadLaunchFdio(name, argv, attr)
+ h, err := fdioStartProcess(name, argv, attr)
if err != nil {
return nil, err
}
diff --git a/src/os/exec_fuchsia_cgo.go b/src/os/exec_fuchsia_cgo.go
index ed5f1eb..1039468 100644
--- a/src/os/exec_fuchsia_cgo.go
+++ b/src/os/exec_fuchsia_cgo.go
@@ -6,18 +6,25 @@
package os
-// #cgo fuchsia CFLAGS: -I${SRCDIR}/../../../../../zircon/system/ulib/launchpad/include
-// #cgo fuchsia LDFLAGS: -llaunchpad
-// #include <launchpad/launchpad.h>
-// #include <launchpad/vmo.h>
-// #include <zircon/process.h>
-// #include <zircon/syscalls.h>
+// #cgo fuchsia CFLAGS: -I${SRCDIR}/../../../../../zircon/system/ulib/fdio/include
+// #cgo fuchsia LDFLAGS: -lfdio
+//
// #include <zircon/syscalls/object.h>
// #include <zircon/types.h>
+// #include <lib/fdio/spawn.h>
+// #include <lib/fdio/util.h>
// #include <stdlib.h>
+//
+// static int fsa_get_local_fd(fdio_spawn_action_t *fsa) { return fsa->fd.local_fd; }
+// static int fsa_get_target_fd(fdio_spawn_action_t *fsa) { return fsa->fd.target_fd; }
+//
+// static void fsa_set_local_fd(fdio_spawn_action_t *fsa, int fd) { fsa->fd.local_fd = fd; }
+// static void fsa_set_target_fd(fdio_spawn_action_t *fsa, int fd) { fsa->fd.target_fd = fd; }
import "C"
+
import (
"errors"
+ "strings"
"syscall"
"syscall/zx"
"syscall/zx/fdio"
@@ -25,16 +32,6 @@
"unsafe"
)
-const (
- LaunchpadCloneFdioNamespace = 1
- LaunchpadCloneFdioCwd = 2
- LaunchpadCloneFdioStdio = 4
- LaunchpadCloneFdioAll = 0xff
- LaunchpadCloneEnviron = 0x100
- LaunchpadCloneDefaultJob = 0x200
- LaunchpadCloneAll = 0xffff
-)
-
func makeCStringArray(s []string) []*C.char {
ret := make([]*C.char, len(s)+1)
for i, s := range s {
@@ -52,15 +49,14 @@
}
}
-// Clone an fdio to a C array of handle values and types.
-func cloneHandleToCHandleArray(m fdio.FDIO) (int, []C.zx_handle_t, []C.uint32_t, error) {
- handles, err := m.Clone()
- if err != nil {
- return 0, nil, nil, ErrInvalid
+// asLibfdioFD returns a File as a libfdio file descriptor.
+func asLibfdioFD(f *File) (int, error) {
+ m := syscall.FDIOForFD(int(f.Fd()))
+ if m == nil {
+ return -1, ErrInvalid
}
- handlesC := make([]C.zx_handle_t, fdio.MaxHandles)
- typesC := make([]C.uint32_t, fdio.MaxHandles)
- fdioType := 0
+
+ var fdioType C.uint32_t
switch m.(type) {
case *fdio.RemoteIO:
fdioType = fdio.HandleTypeRemote
@@ -69,145 +65,121 @@
case *fdio.Logger:
fdioType = fdio.HandleTypeLogger
default:
- for _, h := range handles {
- h.Close()
- }
- return 0, nil, nil, ErrInvalid
+ return -1, ErrInvalid
}
+
+ handles, err := m.Clone()
+ if err != nil {
+ return -1, err
+ }
+
+ var handlesC [fdio.MaxHandles]C.zx_handle_t
+ var typesC [fdio.MaxHandles]C.uint32_t
for i, h := range handles {
handlesC[i] = C.zx_handle_t(h)
typesC[i] = C.uint32_t(fdioType)
}
- return len(handles), handlesC, typesC, nil
+
+ var fd C.int
+ status := zx.Status(C.fdio_create_fd(&handlesC[0], &typesC[0], C.size_t(len(handles)), &fd))
+ if status != zx.ErrOk {
+ return -1, errors.New("fdio_create_fd failed")
+ }
+ return int(fd), nil
}
-func closeAll(handles []C.zx_handle_t) {
- for _, h := range handles {
- if h != 0 {
- h := zx.Handle(h)
- h.Close()
+func fdioSpawnActions(attr *ProcAttr) (actions []C.fdio_spawn_action_t, err error) {
+ defer func() {
+ if err != nil {
+ for _, action := range actions {
+ C.close(C.fsa_get_local_fd(&action))
+ }
+ }
+ }()
+
+ for i, f := range attr.Files {
+ if f == nil {
+ continue
+ }
+ fd, err := asLibfdioFD(f)
+ if err != nil {
+ return nil, err
+ }
+ action := C.fdio_spawn_action_t{action: C.FDIO_SPAWN_ACTION_TRANSFER_FD}
+ C.fsa_set_local_fd(&action, C.int(fd))
+ C.fsa_set_target_fd(&action, C.int(i))
+ actions = append(actions, action)
+ }
+
+ return actions, nil
+}
+
+func fdioStartProcess(name string, argv []string, attr *ProcAttr) (zx.Handle, error) {
+ env := attr.Env
+ if env == nil {
+ env = Environ()
+ }
+ if attr.Dir != "" {
+ found := false
+ for i, s := range env {
+ if strings.HasPrefix(s, "PWD=") {
+ found = true
+ env[i] = "PWD=" + attr.Dir
+ break
+ }
+ }
+ if !found {
+ env = append(env, "PWD="+attr.Dir)
}
}
-}
-func launchpadTransferFileToTargetFd(lp *C.launchpad_t, f *File, target int) error {
- if f == nil {
- return nil
- }
- m := syscall.FDIOForFD(int(f.Fd()))
- if m == nil {
- return ErrInvalid
- }
- numHandles, handlesC, typesC, err := cloneHandleToCHandleArray(m)
- if err != nil {
- return err
- }
- for i := 0; i < numHandles; i = i + 1 {
- typesC[i] = typesC[i] | C.uint32_t(target<<16)
- }
-
- status := zx.Status(C.launchpad_add_handles(lp, C.size_t(numHandles), &(handlesC[0]), &(typesC[0])))
- if status != zx.ErrOk {
- closeAll(handlesC)
- return errors.New("transfer file")
- }
- return nil
-}
-
-func launchpadSetWd(lp *C.launchpad_t, dir string) error {
- f, err := Open(dir)
- if err != nil {
- return err
- }
- m := syscall.FDIOForFD(int(f.Fd()))
- if m == nil {
- return ErrNotExist
- }
- numHandles, handlesC, typesC, err := cloneHandleToCHandleArray(m)
- if err != nil {
- return err
- }
- typesC[0] = fdio.HandleTypeCWD
- status := zx.Status(C.launchpad_add_handles(lp, C.size_t(numHandles), &(handlesC[0]), &(typesC[0])))
- if status != zx.ErrOk {
- closeAll(handlesC)
- return errors.New("transfer wd error: " + itoa(int(status)))
- }
- return nil
-}
-
-func launchpadLaunchFdio(name string, argv []string, attr *ProcAttr) (zx.Handle, error) {
nameC := C.CString(name)
defer C.free(unsafe.Pointer(nameC))
argvC := makeCStringArray(argv)
defer freeCStringArray(argvC)
- env := Environ()
- if attr.Env != nil {
- env = attr.Env
- }
envC := makeCStringArray(env)
defer freeCStringArray(envC)
- jobToChild := zx.Handle(0)
- job := zx.Handle(C.zx_job_default())
- if job > 0 {
- err := error(nil)
- jobToChild, err = job.Duplicate(zx.RightSameRights)
- if err != nil {
- return 0, errors.New("duplicating job")
- }
+
+ actions, err := fdioSpawnActions(attr)
+ if err != nil {
+ return 0, err
}
- lp := &C.launchpad_t{}
- status := zx.Status(C.launchpad_create(C.zx_handle_t(jobToChild), nameC, &lp))
+
+ var actions0 *C.fdio_spawn_action_t
+ if len(actions) > 0 {
+ actions0 = &actions[0]
+ }
+
+ var h C.zx_handle_t
+ var errmsg [C.FDIO_SPAWN_ERR_MSG_MAX_LENGTH]C.char
+ status := zx.Status(C.fdio_spawn_etc(
+ C.ZX_HANDLE_INVALID,
+ C.FDIO_SPAWN_CLONE_JOB | C.FDIO_SPAWN_CLONE_LDSVC | C.FDIO_SPAWN_CLONE_NAMESPACE, // TODO(mdempsky): Flags.
+ nameC,
+ &argvC[0],
+ &envC[0],
+ C.size_t(len(actions)),
+ actions0,
+ &h,
+ &errmsg[0],
+ ))
if status != zx.ErrOk {
- return 0, errors.New("launchpad_create")
- }
- defer func() {
- if lp != nil {
- C.launchpad_destroy(lp)
- }
- }()
- status = zx.Status(C.launchpad_load_from_file(lp, nameC))
- if status != zx.ErrOk {
- return 0, errors.New("loading vdso")
- }
- status = zx.Status(C.launchpad_set_args(lp, C.int(len(argvC)-1), &(argvC[0])))
- if status != zx.ErrOk {
- return 0, errors.New("arguments")
- }
- status = zx.Status(C.launchpad_set_environ(lp, &(envC[0])))
- if status != zx.ErrOk {
- return 0, errors.New("environ")
- }
- status = zx.Status(C.launchpad_clone(lp, C.uint32_t(LaunchpadCloneFdioNamespace)))
- if status != zx.ErrOk {
- return 0, errors.New("launchpad_clone")
- }
- if attr.Dir != "" {
- err := launchpadSetWd(lp, attr.Dir)
- if err != nil {
- return 0, err
- }
- } else {
- status = zx.Status(C.launchpad_clone(lp, C.uint32_t(LaunchpadCloneFdioCwd))) // TODO: Go to Attr.Dir
- if status != zx.ErrOk {
- return 0, errors.New("clone_fdio_cwd")
- }
- }
- for i, f := range attr.Files {
- if err := launchpadTransferFileToTargetFd(lp, f, i); err != nil {
- return 0, err
- }
- }
- h := C.zx_handle_t(0)
- status = zx.Status(C.launchpad_go(lp, &h, nil))
- // lp is freed by launchpad_go unconditionally
- lp = nil
- if status < 0 {
- return 0, errors.New("launchpad error")
+ return 0, errors.New("fdio_spawn_etc: " + itoa(int(status)) + ": " + charsAsString(errmsg[:]))
}
return zx.Handle(h), nil
}
+func charsAsString(s []C.char) string {
+ var x []byte
+ for _, c := range s {
+ if c == 0 {
+ break
+ }
+ x = append(x, byte(c))
+ }
+ return string(x)
+}
+
func (p *Process) kill() error {
procHandle := zx.Handle(p.handle)
status := zx.Sys_task_kill(procHandle)
diff --git a/src/syscall/zx/fdio/fdio.go b/src/syscall/zx/fdio/fdio.go
index af255de..dfdffd7 100644
--- a/src/syscall/zx/fdio/fdio.go
+++ b/src/syscall/zx/fdio/fdio.go
@@ -227,9 +227,9 @@
)
const (
- HandleTypeCWD = 0x31
HandleTypeRemote = 0x32
HandleTypePipe = 0x33
HandleTypeEvent = 0x34
HandleTypeLogger = 0x35
+ HandleTypeSocket = 0x36
)