fork

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2021 License: BSD-3-Clause Imports: 7 Imported by: 0

README

go-fork

Go fork is a package to provide fork-like emulation for Go. In reality, it's not very fork-like, but provides for a common thing fork() is used for, namely making a subroutine (goroutine) run in a new process spaces.

Go, by its natively threaded nature, is not fork-safe. This pkg does not implement a real fork.

Instead, this package makes a way to reroute go to execute a goroutine other than main() in a new process. This allows easy creation of some fork-like behaviors without actually using forks.

Moreover, while go-fork children do not share any memory space with go-fork parents, the parent can pass arbitrary data to go-fork via function arguments.

Here are a couple of particularly important diffierence between real forks and go-forks:

  • Go fork does not continue execution from the fork, but rather starts the specified goroutine from whatever point fork.Init() is called (usually early in main() or in init()).
  • Go fork doesn't share memory, file pointers, mutexes, or really anything with the child process. It passes function arguments to the child by encoding them to/decoding them from a temporary file.

How it works

To use go-fork you must do two things:

  1. Register functions to be forkable (this must be done before trying to fork).b
  2. Call fork.Init() somewhere early in the code. If the process is a child, execution will be taken over from this point, and the code will os.Exit when it's done, never returning execution to anything after fork.Init() is called.

It should be noted that go-fork is not able to detect function calling errors at build time. Errors like incorrect argument assignments are runtime errors.

go-fork determines that an run is a fork by looking for special values in its environment, which it will immediately unset once read.

go-fork passes arguments by encoding/gob endoding/decoding them in a temporary file. This fill will be cleaned up immediately after it is read.

Example:

func init() {
	fork.RegisterFunc("child", child)
	fork.Init()
}

func child(n int) {
	fmt.Printf("child(%d) pid: %d\n", n, os.Getpid())
}

func main() {
	fmt.Printf("main() pid: %d\n", os.Getpid())
	if err := fork.Fork("child", 1); err != nil {
		log.Fatalf("failed to fork: %v", err)
	}
}

This will output:

$ go run example/example.go 
main() pid: 164120
child(1) pid: 164125

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Fork

func Fork(name string, args ...interface{}) (err error)

Fork calls a registered fork

func Init

func Init()

Init should be called at the point that forks should begin to execute. This should likely be very early in main() or within init() (to skip main entirely)

At the point where this is called, either:

We are identified as a fork, we execute that function, and exit. or, we are not identified as afork and simply return.

func Register

func Register(f *Function)

Register records a Fork in the internal fork map. Register must be called before Fork on agiven function (func init() is a common place)

func RegisterFunc

func RegisterFunc(n string, fn interface{})

RegisterFunc records a function as a fork in the internal fork map. Register must be called before Fork on agiven function (func init() is a common place)

Types

type Function

type Function struct {
	// SysProcAttr holds optional, operating system-sepcific attributes.
	SysProcAttr *syscall.SysProcAttr
	// Process will hold the os.Process once the Fork has been Run().
	Process *os.Process
	// ProcessState will hold the os.ProcessState after Wait() has been called.
	ProcessState *os.ProcessState
	// Name is the string we use to identify this func
	Name string
	// Where to send stdout (default: os.Stdout)
	Stdout *os.File
	// Where to send stderr (default: os.Stderr)
	Stderr *os.File
	// Where to get stdin (default: os.Stdin)
	Stdin *os.File
	// contains filtered or unexported fields
}

A Function struct describes a fork process. Usually this is only used internally, but if you want a bit more control of the sub-process, say, to assing new namespaces to the child, this will provide it.

A Fork is a wrapper around an `exec.Cmd` with some of parts the data structure exposed (that we don't need to control directly).

func NewFork

func NewFork(n string, fn interface{}, args ...string) (f *Function)

NewFork createas and initializes a Fork A Fork object can be manipluated to control how a process is launched. E.g. you can set new namespaces in the SysProcAttr property...

     or, you can set custom args with the (optional) variatic args aparameters.
     If you set args, the first should be the program name (Args[0]), which may
		Which may or may not match the  executable.

If no args are specified, args is set to []string{os.Args[0]}

func (*Function) Fork

func (f *Function) Fork(args ...interface{}) (err error)

Fork starts a process and prepares it to call the defined fork

func (*Function) Wait

func (f *Function) Wait() (err error)

Wait provides a wrapper around exec.Cmd.Wait()

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL