Pyr8 User's Manual

« HTTP Server API | The Utilities API »

The Threading API

The pyr8 Threading API provides access to threads and thread management including process creation, termination, and other operations. In most operating systems, process management is handled within a single flat process namespace, to wit the “process table.” In pyr8, processes are managed in a structure symmetric to a filesystem’s structure. Every thread object is contained within a threadpool object, which may also contain thread subpools. Each of those may have its own threads and so forth in the usual way. As a result, no additional permissions system is provided for management of threads.

Before pyr8 can initialize any threads, it must be able to access and create a capability for the server’s initialization script. By default, the pyr8 server looks in the local file “pyr8rc” in the current directory. This can be set with a command line flag as shown belown.

bash pyr8 --pyr8rc=/path/to/rc/file

If this file cannot be opened and read, the pyr8 server will crash before any threads are created.

First, the root threadpool is created and then a single thread is created within it. This is known as the “init thread” for the server. The init thread is instantiated as if with a call to fork passed the following arguments:

  1. The contents of the pyr8rc are provided as the source code for the thread.
  2. All startup capabilities are provided to the thread.

The StringChannel Class

StringChannels can be viewed as shared queues for sending and receiving messages between processes in pyr8. Messages are constrained to be strings, for now, and so complex structures must be serialized to be sent as messages, e.g. to JSON.

Every channel is either alive or dead. Messages can only be sent on live channels, but messages can be received on dead channels.

Methods

cap(): Capability<StringChannel>
Returns a C++-backed capability object for this string channel.
live(): boolean
Returns true if and only if the channel is live.
notify(): boolean
Notifies all threads waiting in a recv() call on this channel.
notifyOne(): boolean
Notifies at least one thread waiting in a recv() call on this channel.
poll(): string | undefined
Polls for a message, returning it if one is available, or returning undefined otherwise. Note that the empty string is a valid message.
recv(): string | undefined
Receives a message from this channel. Blocks until notify() is called.
send(message: string): void
Calls sendEventually(message) then notify().
sendEventually(message: string): void
Pushes a message onto this channel's queue.
terminate(): boolean
Terminates this channel, making it dead.

When the standard library has been loaded, the functionality of StringChannel is provided by the Channel delegate class.

The following methods of the Channel class have signatures that differ from the StringChannel class:

poll(): string | object | undefined
Polls for a message, returning the decoded message if one is available, or returning undefined otherwise. See sendEventually for the encoding.
recv(): string | object | undefined
Blocks until notify() is called, then calls poll.
send(message: string | object): void
Calls sendEventually(message) then notify().
sendEventually(message: string | object): void
Pushes a message onto this channel's queue.

To send strings, it sends JSON.stringify([‘string’, message]).

To send objects, the standard library first checks if the object is a delegate created by the standard library. If so, it looks up the id of the wrapped object and sends JSON.stringify([‘cap’, id]).

If not, it sends JSON.stringify([‘object’, message]).

The Thread Class

Methods

cap(): Capability<Thread>
Returns a C++-backed capability object for the given thread.
channel(): StringChannel
Gets the string channel associated with this thread.
eval(code: string): void
Evaluates code in the given thread. If the thread is already running, this method blocks until the thread finishes executing.
join(): boolean
Joins the given thread. If successful, after this call returns, the thread target is no longer running and no longer contained within the given threadpool. This method is synchronized, but does not invalidate references: calling join does not prevent memory leaks.

When the standard library has been loaded, the Thread delegate class does not have the cap method, and the channel() method returns a Channel instead of a StringChannel.

The ThreadPool Class

Methods

cap(): Capability<ThreadPool>
Returns a C++-backed capability object for this thread pool.
fork(code: string, caps: object<Capability<any>>, createUtils: boolean): Thread
Forks a new thread, endows it with the given capabilities, assigns a new channel to the thread (see thread.channel()), optionally creates a utils object, and runs the given code.
forkPool(): ThreadPool
Creates a thread subpool.
joinpool(target: ThreadPool): void
Joins all threads within the target thread subpool and deletes target.
list(): array<Thread>
Lists the threads directly contained by this thread pool.
listPools(): array<ThreadPool>
Lists the thread pools directly contained by this thread pool.
localThread(): Thread
Gets the thread for the currently running code.

When the standard library has been loaded, the ThreadPool delegate class does not have the cap method. The fork method allows a caps argument with arbitrary structure built from object and array literals, strings, booleans, numbers, null, and delegates. It also prefixes the provided code with code to load the standard library.

« HTTP Server API | The Utilities API »