thox native process runtime API

When started, a thox process has access to a given set of functions and constants; this document describes them.

Todo

When started, every process should have access to the native functions to the current Lua function, e.g. those described in the Lua 5.3 manual.

Maybe make a table and check which utilities are available or not.

Events

class os.Event

An event as seen by the user process.

type: string

The event type; see derivative classes.

Events can be one of the following:

class os.CallEvent: Event

An event emitted when receiving a call from another process through RPC.

type: string

The event type, set to "call".

cid: number

The Call IDentifier (CID) to which to answer.

ctx: number

The context identifier from which the call was emitted.

name: string

The name which was used to emit the call to the current process.

pid: number

The Process IDentifier (PID) of the process which has emitted the call.

args: table

The arguments to the function, as a sequence.

class os.AnswerEvent: Event

An event emitted when receiving an answer to a call emitted previously.

type: string

The event type, set to "answer".

cid: number

The Call IDentifier (CID) of the answered call.

status_code: number

The status code bundled with the answer; see Status codes for more information.

args: table

The arguments returned by the process.

class os.OpenEvent: Event

An event produced when a process opens a context owned by the current process (when not shared by the current process).

type: string

The event type, set to "open".

ctx: number

The identifier of the context which was shared.

pid: number

The Process IDentifier (PID) of the process which has gained access to the context.

class os.CloseEvent: Event

An event produced when a process closes a context owned by the current process (when not closed by the current process).

type: string

The event type, set to "close".

ctx: number

The identifier of the context which was shared.

pid: number

The Process IDentifier (PID) of the process which has gained access to the context.

These events are produced by the following function:

os.pull([filter[, ...]])

Pull the next event out of the event queue for the process.

The filters are tables containing expected values to filter the event with.

For example, the following snippet waits for either:

  • an answer for the calls 4 and 5;

  • a new call.

local event = os.pull({type = "answer", cid = 4},
        {type = "answer", cid = 5}, {type = "call"})

When requiring a specific event, other events will stay in the queue for the next call asking specifically for it in the queue.

Parameters

filter (table) – The filter as a table with the expected values.

Returns

The next event out of the event queue.

Return type

An Event.

Asynchronous RPC

os.call(ctx, name, ...)

Emits a call to the given name on the given context.

If the name ends with an underscore (see Remote Procedure Names (RPN)), then the first returned value after the status code will either be nil or the number of a context shared with the current process.

Parameters
  • ctx (number) – A valid context identifier.

  • name (str) – A valid procedure name.

Returns

The generated Call IDentifier (CID), or nil if an error has occurred.

Return type

number

os.answer(cid, status, ...)

Answer a call with arguments.

If the name of the related call ends with an underscore (see Remote Procedure Names (RPN)), then the first returned value after the status code must be either nil or the number of the context to share.

The status code should be 0 in case of success or an other value in case of failure; see Status codes for more information.

Parameters
  • cid (number) – A valid Call IDentifier (CID).

  • status (number) – The status code for the call.

os.transmit(ctx, name, cid[, pid])

Transmit a call to another process bound to a given name on a given context.

This function is an optimization: instead of having to make the call to the parent process and waiting for the answer to retransmit it to the end process, this actually sends the same call event (with the context and name replaced to correspond to this function’s arguments) to the bound process, which will then answer directly to the client process; the CID is therefore closed from the current process’s point of view when the call is transmitted.

The pid parameter serves mostly when the call is not transmitted to the context owner specifically. This mostly serves for context-managing processes that support bindings, for them to transmit calls to children on a context they have created.

Todo

For now, we stay on the os.transmit logic, but soon we’ll see that this approach may be slow when there are multiple levels of sandboxing. So what we could do is, have a nftables-like approach where a process owning a context configures routing for calls on the context (based on origin, name, why not arguments as well?), and the kernel doesn’t need to call this process to route, whereas with the os.transmit we need to and this may be slow.

However this is the complicated approach, for now we’ll stick with the simpler approach as a PoC.

Parameters
  • ctx (number) – A valid context identifier.

  • name (str) – A valid RPC name.

  • cid (number) – A valid Call IDentifier (CID).

  • pid (number) – The optional PID of the process to which the call should be transmitted on the given context.

Synchronous RPC

class os.RPCProxy

An RPC proxy object, which allows you to make synchronous RPC calls, on a given context. By calling this object, you emit a system call to the given name, and wait for an answer.

Examples usages of this object are the following:

local status, div, rem = os.rpc.math.div(10, 3)

-- is the equivalent of:

local status, div, rem

do
        local cid = os.call(0, "math.div", 10, 3)
        local status

        status, div, rem = os.pull({
                type = "answer", cid = cid})
end
any: RPCProxy

Indexing the object gives you an RPC proxy object, on the same context and with a prefixed name, which you can call the same.

This class is instanciated as the following object:

class os.rpc: RPCProxy

The basic RPC proxy object, with a blank namespace.

Other functions

os.capture(co, ...)

Equivalent of the coroutine.resume() function, but it captures system calls.

Parameters

co (thread) – The coroutine to resume.

Returns

The status of the coroutine, accompagnied with various data.