system.spawn

Synopsis

local system = require "system"
system.spawn(opts: table) -> subprocess

Description

Creates a new process.

Named parameters

program: string|filesystem.path|file_descriptor
string

A simple filename. The system searches for this file in the list of directories specified by PATH (in the same way as for execvp(3)).

filesystem.path

The path (which can be absolute or relative) of the executable.

file_descriptor

A file descriptor to the executable. See fexecve(3).

arguments: string[]|nil

A table of strings that will be used as the created process' argv. On nil, an empty argv will be used.

Don’t forget to include the name of the program as the first argument.
environment: { [string]: string }|nil

A table of strings that will be used as the created process' envp. On nil, an empty envp will be used.

stdin,stdout,stderr: "share"|file_descriptor|nil
"share"

The spawned process will share the specified standard handle (stdin, stdout, or stderr) with the caller process.

file_descriptor

Use the file descriptor as the specified standard handle (stdin, stdout, or stderr) for the spawned process.

nil

Create and use a closed pipe end as the specified standard handle (stdin, stdout, or stderr) for the spawned process.

extra_fds: { [integer]: file_descriptor }|nil

Extra file descriptors for the child to inherit. Parent and child processes don’t need to share the same numeric value reference for a given file description. The file descriptor number used in the child process will be the one specified in the key portion of the dictionary argument. Only file descriptors numbered from 3 to 9 are acceptable (i.e. the same limitations of low fds that you’re likely to face on older UNIX shells). If you need to pass more than 10 file descriptors — stdin, stdout, stderr, plus these extra 7 file descriptors — use another interface (e.g. SCM_RIGHTS).

signal_on_gcreaper: integer = system.signal.SIGTERM

Each process is responsible for reaping its own children. A process that fails to reap its children will soon exhaust its OS-provided resources. For short-lived programs that’s hardly a problem given the process quits and its children are re-parented to the next subreaper in the chain (usually the init process). However for a concurrency runtime such as Emilua we expect other concurrent tasks to remain unaffected by the one failing task (be it a single fiber or the whole VM). Emilua will then transparently reap any child process for which its handle has been GC’ed. signal_on_gcreaper allows the user to specify a signal to be sent to the child that’s about to be reaped at this occasion.

By default, the signal system.signal.SIGTERM will be sent to the child and then the main Emilua process will — indefinitely, non-blockingly, and non-pollingly — await for all of its children to finish even if there’s no longer any Lua program being executed. Use the more dangerous system.signal.SIGKILL if you don’t want the main Emilua process to wait long for the child. Use 0 if you don’t want the Emilua reaper to send any signal before awaiting for the child.

Ideally the system kernel would expose some re-parent syscall, but until then (if ever), signal_on_gcreaper will be necessary.
scheduler.policy: string|nil

Values acceptable on Linux for non-real-time policies are:

"other"

See SCHED_OTHER.

"batch"

See SCHED_BATCH.

"idle"

See SCHED_IDLE.

Values acceptable on Linux for real-time policies are:

"fifo"

See SCHED_FIFO. Must also set scheduler.priority.

"rr"

See SCHED_RR. Must also set scheduler.priority.

scheduler.priority: integer|nil

The interpretation of this parameter is dependant on scheduler.policy.

scheduler.reset_on_fork: boolean = false

If true, grandchildren created as a result of a call to fork(2) from the direct child will not inherit privileged scheduling policies. If set, must also set scheduler.policy.

start_new_session: boolean = false

Whether to create a new session and become the session leader. On true, calls setsid() on the child.

set_ctty: file_descriptor|nil

Set the controlling terminal for the child. It is an error to specify set_ctty, but omit start_new_session.

It’s an error to specify both set_ctty and foreground.
process_group: integer|nil

Set the process group (it calls setpgid() on the child). On 0, the child’s process group ID is made the same as its process ID.

foreground: "stdin"|"stdout"|"stderr"|file_descriptor|nil

Make the child be the foreground job for the specified controlling terminal by calling tcsetpgrp() (SIGTTOU will be blocked for the duration of the call). It is an error to specify foreground, but omit process_group.

"stdin", "stdout", and "stderr" can only be specified if parent and child share the same file for the specified standard handle.
It’s an error to specify both foreground and set_ctty.
ruid: integer|nil

Set the real user ID.

euid: integer|nil

Set the effective user ID. If the set-user-ID permission bit is enabled on the executable file, its effect will override this setting (see execve(2)).

rgid: integer|nil

Set the real group ID.

egid: integer|nil

Set the effective group ID. If the set-group-ID permission bit is enabled on the executable file, its effect will override this setting (see execve(2)).

extra_groups: integer[]|nil

Set the supplementary group IDs.

umask: integer|nil

See umask(3p).

working_directory: filesystem.path|file_descriptor|nil

Sets the working directory for the spawned program.

pdeathsig: integer|nil

Signal that the process will get when its parent dies. If the executable file contains set-user-ID, set-group-ID, or contains associated capabilities, pdeathsig will be cleared.

“Parent” is a difficult term to define here. For Linux, that’s not the process, but the thread. For Emilua, the thread will exist for at least as long as the calling Lua VM exists (even if the Lua VM might jump between threads). The thread will also exist for even longer, for as long as other Lua VMs are using it.
nsenter_user: file_descriptor|nil

Enter in this Linux user namespace. When nsenter_user is specified, Emilua always enter in the user namespace before any other namespace.

nsenter_mount: file_descriptor|nil

Enter in this Linux mount namespace.

nsenter_uts: file_descriptor|nil

Enter in this Linux UTS namespace.

nsenter_ipc: file_descriptor|nil

Enter in this Linux IPC namespace.

nsenter_net: file_descriptor|nil

Enter in this Linux net namespace.

subprocess functions

wait(self)

Wait for the process to finish, and then reap it. Information regarding termination status is stored in exit_code and exit_signal.

If your code fails to call wait(), the Emilua runtime will reap the process in your stead as soon as the GC collects self and the underlying subprocess finishes. It’s important to reap children processes to free OS-associated resources.

kill(self, signal: integer)

Send a signal to the process.

You may specify 0 (the null signal) to not send any signal, but still let the OS to perform permission checks (reported as raised errors).

cap_get(self) → system.linux_capabilities

See cap_get_pid(3).

subprocess properties

exit_code: integer

The process return code as passed to exit(3). If the process was terminated by a signal, this will be 128 + exit_signal (as done in BASH).

You can only access this field for wait()'ed processes.

exit_signal: integer|nil

The signal that terminated the process. If the process was not terminated by a signal, this will be nil.

You can only access this field for wait()'ed processes.

pid: integer

The process id used by the OS to represent this child process (e.g. the number that shows up in /proc on some UNIX systems).

You can only access this field for non-wait()'ed processes.