Serpent threads are unlike Python or Unix threads in that they are non-preemptable, meaning that threads run until a command explicitly allows another thread to run. Only one thread runs at once, even if multiple processors are available.
To create a thread, use
fork(), which copies the current stack frame (the current function’s local variables and program counter). The original thread continues executing and the new thread starts executing as if both called
fork(). The difference is that in the original thread,
fork() returns the new thread (a reference to a thread primitive of type
Thread, while in the new thread,
false) and when this thread returns from the function where
fork() was called, the thread terminates.
After creating a new thread with
fork(), the calling thread yields to the new thread. You can also suspend threads to take them off the runnable list so they will not be yielded to (see
suspend(), and you can make a suspended thread runnable again (see
A typical way to create a thread to perform some computation is:
if not fork(): some_computation() // runs on new thread return ... work for main thread continues ...
Alternatively, one can make a function that runs on a separate thread as follows:
def some_computation() if fork(): // create new thread for the work return // caller does none of the work ... some computation here for new thread ...
One could also arrange things to defer computation until after the main thread suspends or yields control:
def some_computation() var caller = threadid() // get the calling thread if fork() return // caller will run this soon after fork() // after fork, new thread will run immediately, // so yield control back to calling thread yieldto(caller) // eventually, control will come back to this new thread: ... some defered computation here for new thread ...
Procs – Preemptable Thread Interface and Functions
Serpent has two types of threads. “Normal” threads are non-preemptable coroutines that share the heap (thus all globals are common to these threads). You can create as many of these threads as you wish. The second form is limited to one additional thread (called a “process” or “proc” to avoid overloading the term “thread”) that loads a file and then periodically calls a function. This proc has an independent heap (thus no variables are shared) and runs at higher priority than the main proc. It can preempt the main proc or run while the main proc is blocked waiting for input or sleeping. The entire preemptive proc interface consists of
All communication between these two procs is through message queues. Two queues are set up and initialized to hold up to 100 strings of up to 100 characters each. Only strings may be sent and received. To build Serpent with these proc functions, link Serpent with the objects obtained from proccreate.cpp and prochack.cpp. (Look for the CMake option USE_PROC to use procs.)
It is strongly recommended that you do not depend heavily on this simple proc interface. It was created to support a course and is not intended for “real” use.
proc_create(period, filename, mempool)
- create a new instance of the Serpent virtual machine
- allocate an initial memory pool (mempool is a hint for the size of the initial memory pool. It is currently ignored. Future implementations will interpret a value of 0 to indicate the default memory pool size, which is currently 1MB.)
- load the file indicated by filename (a string)
- set the variable proc_id in the new proc to an integer (see below)
- return the new proc’s proc_id
- Once a new proc is created and it has finished successfully loading/compiling/executing commands from filename, the proc uses PortTime to wake up every period milliseconds and call
porttime_callback(ms), where ms is the current time in milliseconds.
- enqueue string for receipt by the other proc. Return the number of strings sent (0 if the queue is full, 1 if the send is successful.) proc_id should be the proc id of the caller, not the destination. (Use the global variable
- check the queue and if there is a message from the other proc, return the message as a string. If there is no message, “” (the empty string) is returned. Note that it is possible to send an empty string, but this will be indistinguishable from no message (an empty queue). proc_idshould be the proc id of the caller, not the proc that sent the message. (Use the global variable
Network Interface and Functions
If Serpent is compiled with NETWORK defined, then some basic communications functions are built-in. They are defined in this section.
- Create a socket, bind it to
portno, and listen for client connections. A socket descriptor (number) is returned. -1 is returned to indicate an error.
- Accept a client request on
socket, which was created by
server_create. If the return value is
nil, then no client request is pending (this is a non-blocking call). If the return value is negative, an error occurred. -1 indicates an error was reported from the accept operation. -2 indicates that the socket parameter value is invalid. (Other negative integers should also be treated as errors.) Otherwise, the return value is socket that can be used to read the client request. Under Windows, calling this function initiates a blocking
acceptcall in another thread. In order to call
socket_receive, you must continue (re)calling
server_acceptuntil it returns something other than
nil. To terminate the blocked
accept, try closing the server socket and then re-calling
server_acceptto read the error return.
- Establish a connection with a server using its name and port number. The result is a socket,
nilif no result is available yet (this is a non-blocking call), or -1 if there is an error. If
nilis returned, you must re-call
server_connectuntil a non-
nilresult is obtained.
- Read up to
nbytes of data from
socket. Returns a string if successful,
nilif no input is available (this is a non-blocking call), and otherwise returns an integer error code. The error code -2 is returned if the socket parameter is invalid. The socket is normally obtained from
nilis returned, the read is still in progress, and you must re-call
socket_receiveuntil a non-
nilresult is obtained.
- Send a string to the given socket, which is normally obtained from
server_connect. Returns the number of bytes sent or -1 on error.
- Close a socket.
Windows Shell File Operations
The Win32 version of Serpent includes an interface to “Shell File Operations” that perform tasks such as copying directories. These functions are:
- Copy a directory named by
to_path(both arguments are strings).
- Delete a file or directory named by
- Create a directory named by
- Return the local time as an array of integers, organized as follows: [seconds, minutes, hours, day-of-month, month, year, day-of-week, day-of-year, dst], where dst is 1 for daylight savings time and 0 otherwise.