A long-lived thread consists of a sequence of atomic thread invokations separated by calls to split-phase operations. Each long-lived thread has a context, which contains its input arguments and other working variables that are shared by its atomic threads. The macros provides syntactic constructs for writing long-lived threads as if they were normal functions. The details of atomic thread decomposition and context management are hidden from the user.
A long-lived thread starts with the declaration of its input arguments using MP_declThread (or MP_declAtomicThread). Its body starts with MP_beginThread (or MP_beginAtomicThread), and ends with MP_endThread. The working variables are declared with MP_localVars, which immediately follows MP_beginThread. In the thread body, any input argument x is addressed as in->x, and any working variable y is addressed as local->y. MP_localVars, MP_splitOp, MP_splitOpCond, MP_syncCtr, and MP_syncCtrCond mark the beginning of new atomic threads, each of which can declare its own local variables (not visible to other atomic threads).
A example long-lived thread is given below:
MP_declThread(myThread, int myArg, ...) MP_beginThread(myThread) MP_localVars(int myVar, ...) int i; ... MP_splitOp(in->myArg, local->myVar, i, ...) int i; ... MP_stop MP_endThread
The macros are written using the macro preprocessor gm4. There should be no semicolons after the macro calls. Due to the limitations of the preprocessor appraach, the macro calls cannot be nested inside any C conditionals or loops. The current implementation also requires that the last word of each formal argument declaration be the variable name.
Declare the input arguments of the long-lived thread name. All input arguments must be addressed with the prefix in-> in the thread body.
Threads written using the macros must be allocated using MP_allocThread.
Declare the input arguments of a atomic thread name. MP_declAtomicThread is the same as MP_declThread, except that the thread must run to completion (that is, it cannot call Rts_continueThread). Atomic threads require less state and run more efficiently.
Begin the body of the long-lived thread name.
The thread's arguments must be declared by MP_declThread before its body begins.
Begin the body of the thread name. MP_beginAtomicThread is the same as MP_beginThread, except that the thread must run to completion (that is, it cannot call Rts_continueThread). See MP_declAtomicThread.
Declare the working variables of the current thread. All working variables must be addressed with the prefix local-> in the thread body.
MP_localVars must immediately follow MP_beginThread or MP_beginAtomicThread.
Call the split-phase operation op and wait until it completes. The actual argument list contains all but the last counter argument of the split-phase operations (the counter is automatically generated by the macro). If op returns OK, the current thread continues execution without yielding control to another thread, that is, atomicity is preserved across the call. Otherwise, the runtime system schedules another thread for execution while the calling thread is waiting.
If condition evaluates to a nonzero value, call the split-phase operation op and wait until it completes. Otherwise, the current thread continues execution without yielding control to another thread, that is, atomicity is preserved across the call. When condition is true, MP_splitOpCond behaves like MP_splitOP.
Mark the beginning of a loop.
There can be at most one loop entry per atomic thread in a long-lived thread. Loops cannot be nested.
Jump to the beginning of the closet loop (marked by MP_repeatBegin). Atomicity is not preserved across loop iterations, that is, the current thread may yield control when performing a jump.
Loops cannot be nested, although there can be more than one MP_repeat that jump to the same loop entry.
If condition evaluates to a non-zero value, jump to the beginning of the closet loop (marked by MP_repeatBegin). Atomicity is not preserved across loop iterations, that is, the current thread may yield control when performing a jump. MP_repeatCond does nothing if condition evaluates to 0.
Wait until the value of the counter ctr reaches value. If the current value of ctr is no less than value, the calling thread continues execution without yielding control to another thread, that is, atomicity is preserved across the call. Otherwise, the runtime system schedules another ready thread while the calling thread is waiting.
If condition evaluates to a non-zero value, wait until the value of the counter ctr reaches value. If the current value of ctr is no less than value, or condition evaluates to zero, the calling thread continues execution without yielding control to another thread, that is, atomicity is preserved across the call. Otherwise, the runtime system schedules another ready thread while the calling thread is waiting.
Terminate the execution of the current thread.
Create a thread and return its handle in *tidPtr. The thread is deposited by scheduler when enabled. It executes the function f with the given actual arguments. MP_allocThread is the same as Rts_allocThread except that the thread state is automatically generated and managed by the macros.
MP_allocThread can only be called on threads written with the macros. The thread f must have been declared using MP_declThread or MP_declAtomicThread.
Create and enable a thread on the remote processor proc. The new thread is deposited by scheduler, and it executes the function f with the given actual arguments. MP_invokeRemoteThread is the same as Rts_invokeRemoteThread except that the thread state is managed by the macros.
MP_invokeRemoteThread can only be called on threads written with the macros. The thread f must have been declared using MP_declThread or MP_declAtomicThread.
Create and enable a thread on the remote processor proc. The new thread is deposited by scheduler, and it executes the function f with the given actual arguments, plus a variable size argument copied from the buffer buf with size size. When f executes, the macro MP_varArg returns a pointer to the variable size argument.
MP_invokeRemoteThread_Var can only be called on threads written with the macros. The thread f must have been declared using MP_declThread or MP_declAtomicThread.
Returns the address of the variable size argument for the current thread.
Return the field field in the context of a existing thread. The thread has name name and handle tid. The macro is usually used by a thread scheduler to make scheduling decisions based on the thread state.
The thread tid must have been created, but not yet enabled.
End the body of the current thread.