exec_linux.mx raw

   1  // Copyright 2009 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build linux && !baremetal && !moxie.wasm && !nintendoswitch
   6  
   7  package os
   8  
   9  import (
  10  	"errors"
  11  	"runtime"
  12  	"syscall"
  13  )
  14  
  15  // The only signal values guaranteed to be present in the os package on all
  16  // systems are os.Interrupt (send the process an interrupt) and os.Kill (force
  17  // the process to exit). On Windows, sending os.Interrupt to a process with
  18  // os.Process.Signal is not implemented; it will return an error instead of
  19  // sending a signal.
  20  var (
  21  	Interrupt Signal = syscall.SIGINT
  22  	Kill      Signal = syscall.SIGKILL
  23  )
  24  
  25  // Keep compatible with golang and always succeed and return new proc with pid on Linux.
  26  func findProcess(pid int) (*Process, error) {
  27  	return &Process{Pid: pid}, nil
  28  }
  29  
  30  func (p *Process) release() error {
  31  	// NOOP for unix.
  32  	p.Pid = -1
  33  	// no need for a finalizer anymore
  34  	runtime.SetFinalizer(p, nil)
  35  	return nil
  36  }
  37  
  38  // This function is a wrapper around the forkExec function, which is a wrapper around the fork and execve system calls.
  39  // The StartProcess function creates a new process by forking the current process and then calling execve to replace the current process with the new process.
  40  // It thereby replaces the newly created process with the specified command and arguments.
  41  // Differences to upstream golang implementation (https://cs.opensource.google/go/go/+/master:src/syscall/exec_unix.go;l=143):
  42  // * No setting of Process Attributes
  43  // * Ignoring Ctty
  44  // * No ForkLocking (might be introduced by #4273)
  45  // * No parent-child communication via pipes (TODO)
  46  // * No waiting for crashes child processes to prohibit zombie process accumulation / Wait status checking (TODO)
  47  func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
  48  	if argv == nil {
  49  		return 0, errors.New("exec: no argv")
  50  	}
  51  
  52  	if len(argv) == 0 {
  53  		return 0, errors.New("exec: no argv")
  54  	}
  55  
  56  	if attr == nil {
  57  		attr = new(ProcAttr)
  58  	}
  59  
  60  	p, err := fork()
  61  	if err != nil {
  62  		return 0, err
  63  	}
  64  
  65  	if p == 0 {
  66  		// Child process: replace with the new binary.
  67  		err = execve(argv0, argv, attr.Env)
  68  		// execve only returns on failure — child must exit to avoid
  69  		// two copies of the parent running.
  70  		libc_exit(127)
  71  		// unreachable
  72  	}
  73  
  74  	// Parent process: return child PID.
  75  	return int(p), nil
  76  }
  77  
  78  // In Golang, the idiomatic way to create a new process is to use the StartProcess function.
  79  // Since the Model of operating system processes in moxie differs from the one in Golang, we need to implement the StartProcess function differently.
  80  // The startProcess function is a wrapper around the forkExec function, which is a wrapper around the fork and execve system calls.
  81  // The StartProcess function creates a new process by forking the current process and then calling execve to replace the current process with the new process.
  82  // It thereby replaces the newly created process with the specified command and arguments.
  83  func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
  84  	if attr != nil {
  85  		if attr.Dir != "" {
  86  			return nil, ErrNotImplementedDir
  87  		}
  88  
  89  		if attr.Sys != nil {
  90  			return nil, ErrNotImplementedSys
  91  		}
  92  
  93  		if len(attr.Files) != 0 {
  94  			return nil, ErrNotImplementedFiles
  95  		}
  96  	}
  97  
  98  	pid, err := forkExec(name, argv, attr)
  99  	if err != nil {
 100  		return nil, err
 101  	}
 102  
 103  	return findProcess(pid)
 104  }
 105