This extension provides implementation-agnostic syntax and back-end support for for various parallel programming tools. It also contains several implementations (which are included here for compactness but are independent extensions) as well as some extensions built on top of this system (which again are independent extensions).
There are four pieces of this system that are extensible, allowing new
implementations to be added: parallelism (task spawning and parallel for-loops),
memory synchronization (locks and condition variables), task synchronization
(threads, groups, and sync
), and balancers.
The implementations of task spawning and parallel for-loops are specified using
the ParallelSystem
nonterminal (defined
here)
which has six attributes that must be defined:
parName :: String
: This attribute just provides a name of the implementation, this is used for issuing and looking up unique id numbers to each systemnewProd :: Maybe<(Expr ::= Exprs Location)>
: This attribute provides the implementation ofnew
for this parallel interface; this is attribute will provide initialization code, such as creating the workers for a thread pool or work-stealerdeleteProd :: Maybe<(Stmt ::= Expr)>
: This attribute provides the implementation ofdelete
for this parallel interface; this must provide shutdown behavior, which should initiate the shutdown of any worker-threadsfSpawn :: (Stmt ::= Expr Location SpawnAnnotations)
: This attribute provides the implementation of spawn, the first argument is the expression being spawnedfFor :: (Stmt ::= Stmt Location ParallelAnnotations)
: This attribute provides the implementation of a parallel for-loop, the first argument is the normalized for-loop to be parallelizedtransFunc :: (Decl :: ParallelFunctionDecl)
: This attribute provides for translation of functions (this is used mostly by work-stealers, but can be used by any system). If there is no interesting translation needed, the productionparallelFuncToC
, provided by ableC parallel, can be used.
The implementation of locks and condition variables are specified using the
LockSystem
nonterminal (defined
here)
which has a number of attributes that must be defined. Note that also env
is
an inherited attribute on this nonterminal and there are two other inherited
attributes: locks :: [Expr]
and condvar :: Expr
which are used to provide
a list of locks or a condition variable to the nonterminal, which are then
used by several attributes (as these are defined in that way rather than using
lambdas):
parName :: String
: Like in parallelism, provides a name for each implementation, and used in a few places to determine whether locks and condition variables have the same implementationlockType :: Type
: The C type to give to locks (may depend onenv
)acquireLocks :: Stmt
: Acquires the set of provided locks (vialocks
)releaseLocks :: Stmt
: Releases the set of provided locks (vialocks
)condType :: Type
: The C type to give to condition variables (may depend onenv
)waitCV :: Stmt
: Performs a wait on the provided condition variable (viacondvar
)signalCV :: Stmt
: Signals the provided condition variablebroadcastCV :: Stmt
: Broadcasts on the provided condition variableinitializeLock :: (Expr ::= Expr Exprs Location)
: Used to initialize a lock, the first argument is the left-hand side (we use initialization in this way, rather than directly usingnew
because the POSIX implementation requires a function call with a pointer to the lock to initialize.lockDeleteProd :: Maybe<(Stmt ::= Expr)>
: Implementation ofdelete
for a lockinitializeCondvar :: (Expr ::= Expr Exprs Location)
: Initializes a condition variable, again the first argument is the left-hand side (for the same reasons as this is done on locks)condvarDeleteProd :: Maybe<(Stmt ::= Expr)>
: Implementation ofdelete
for a condition variable
The implementation of task synchronization is specified using the
SyncSystem
nonterminal (defined
here)
which has a number of attributes which must be defined. Note that, like with
memory synchronization, env
is provided on this nonterminal which can be used
and there are threads :: [Expr]
and groups :: [Expr]
inherited attributes
which are used to pass lists of threads and groups which are used in certain
attributes:
parName :: String
: The name of the implementation, as beforethreadType :: Type
: The C type to give threadsgroupType :: Type
: The C type to give groupsinitializeThread :: (Expr ::= Expr Exprs Location)
: Initialize a thread, the first argument is the left-hand side of the initializationthreadDeleteProd :: Maybe<(Stmt ::= Expr)>
: Delete a threadinitializeGroup :: (Expr ::= Expr Exprs Location)
: Initialize a groupgroupDeleteProd :: Maybe<(Stmt ::= Expr)>
: Delete a groupthreadBefrOps :: Stmt
: Generates the "before" statements of the provided threads (viathreads
) which should be executed before a task is createdthreadThrdOps :: Stmt
: Generates the "thread" statement of the provided threads which should be executed before a task commences, but should be done by that thread itself (this is currently not used, but is supported in-case some implementation wants to make use of the TCB of tasks)threadPostOps :: Stmt
: Generates the "post" statement of the provided threads which should be executed once a task completes (but before the task exits)groupBefrOps :: Stmt
: Generates the "before" statements of the provided groups (viagroups
)groupThrdOps :: Stmt
: Generates the "thread" statements of the provided groupsgroupPostOps :: Stmt
: Generates the "post" statements of the provided groupssyncThreads :: Stmt
: Generates a statement to synchronize all of the provided threadssyncGroups :: Stmt
: Generates a statement to synchronize all of the provided groups
BalancerSystem
(defined
here)
parName
: The name, as before; currently not used but provided so that all system nonterminals have this attributenewProd :: Maybe<(Expr ::= Exprs Location)>
: Implementation ofnew
deleteProd :: Maybe<(Stmt ::= Expr)>
: Implementation ofdelete
Implementing higher-level abstractions built on-top of ableC parallel can make use of the abstract productions provided in ableC parallel, or in some cases it may be easier to directly make use of the system nonterminals discussed above and pull attributes from these to generate the appropriate code. In either case the results should be the same, the choice is really based on the style of the extension developer.