Ignore:
Timestamp:
Jul 31, 2023, 12:04:38 PM (14 months ago)
Author:
caparsons <caparson@…>
Branches:
master
Children:
d3c3261
Parents:
14c0f7b
Message:

incorporated actor and waituntil comments

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/colby_parsons_MMAth/text/waituntil.tex

    r14c0f7b rf496046  
    382382More detail on channels and their interaction with @waituntil@ appear in Section~\ref{s:wu_chans}.
    383383
    384 The trait is used by having a blocking object return a type that supports the @is_selectable@ trait.
     384The trait can be used directly by having a blocking object support the @is_selectable@ trait, or it can be used indirectly through routines that take the object as an argument.
     385When used indirectly, the object's routine returns a type that supports the @is_selectable@ trait.
    385386This feature leverages \CFA's ability to overload on return type to select the correct overloaded routine for the @waituntil@ context.
    386 A selectable type is needed for types that want to support multiple operations such as channels that allow both reading and writing.
     387Indirect support through routines is needed for types that want to support multiple operations such as channels that allow both reading and writing.
    387388
    388389\section{\lstinline{waituntil} Implementation}
     
    520521This work incurs a high cost for signalling threads and heavily increase contention on internal channel locks.
    521522Furthermore, the @waituntil@ statement is polymorphic and can support resources that do not have internal locks, which also makes this approach infeasible.
    522 As such, the exclusive-or semantics is lost when using both @and@ and @or@ operators since it cannot be supported without significant complexity and significantly affects @waituntil@ performance.
     523As such, the exclusive-or semantics are lost when using both @and@ and @or@ operators since it cannot be supported without significant complexity and significantly affects @waituntil@ performance.
    523524
    524525It was deemed important that exclusive-or semantics are maintained when only @or@ operators are used, so this situation has been special-cased, and is handled by having all clauses race to set a value \emph{before} operating on the channel.
     
    591592If any other threads attempt to set a WUT's race pointer and see a pending value, they wait until the value changes before proceeding to ensure that, in the case the WUT fails, the signal is not lost.
    592593This protocol ensures that signals cannot be lost and that the two races can be resolved in a safe manner.
    593 \PAB{I bet one of the readers is going to ask you to write the pseudo code for this algorithm.}
     594The implementation of this protocol is shown in Figure~\ref{f:WU_DeadlockAvoidance}.
     595
     596\begin{figure}
     597\begin{cfa}
     598bool pending_set_other( select_node & other, select_node & mine ) {
     599    unsigned long int cmp_status = UNSAT;
     600
     601    // Try to set other status, if we succeed break and return true
     602    while( !CAS( other.clause_status, &cmp_status, SAT ) ) {
     603        if ( cmp_status == SAT )
     604            return false; // If other status is SAT we lost so return false
     605
     606        // Toggle own status flag to allow other thread to potentially win
     607        mine.status = UNSAT;
     608
     609        // Reset compare flag
     610        cmp_status = UNSAT;
     611
     612        // Attempt to set own status flag back to PENDING to retry
     613        if ( !CAS( mine.clause_status, &cmp_status, PENDING ) )
     614            return false; // If we fail then we lost so return false
     615       
     616        // Reset compare flag
     617        cmp_status = UNSAT;
     618    }
     619    return true;
     620}
     621\end{cfa}
     622\caption{Exclusive-or \lstinline{waituntil} channel deadlock avoidance protocol}
     623\label{f:WU_DeadlockAvoidance}
     624\end{figure}
    594625
    595626Channels in \CFA have exception-based shutdown mechanisms that the @waituntil@ statement needs to support.
     
    600631
    601632It is trivial to check when a synchronous multiplexing utility is done for the or/xor relationship, since any resource becoming available means that the blocked thread can proceed and the @waituntil@ statement is finished.
    602 In \uC and \CFA, the \gls{synch_multiplex} mechanism have both an and/or relationship, which make the problem of checking for completion of the statement difficult.
    603 \PAB{Show an example of why this is difficult.}
     633In \uC and \CFA, the \gls{synch_multiplex} mechanism have both an and/or relationship, which along with guards, make the problem of checking for completion of the statement difficult.
     634Consider the @waituntil@ in Figure~\ref{f:WU_ComplexPredicate}.
     635When the @waituntil@ thread wakes up, checking if the statement is complete is non-trivial.
     636The predicate that will return if the statement in Figure~\ref{f:WU_ComplexPredicate} is satisfied is the following.
     637\begin{cfa}
     638A && B || C || !GA && B || !GB && A || !GA && !GB && !GC
     639\end{cfa}
     640Which simplifies to:
     641\begin{cfa}
     642( A || !GA ) && ( B || !GB ) || C || !GA && !GB && !GC
     643\end{cfa}
     644Checking a predicate this large with each iteration is expensive so \uC and \CFA both take steps to simplify checking statement completion.
     645
     646\begin{figure}
     647\begin{cfa}
     648when( GA ) waituntil( A ) {}
     649and when( GB ) waituntil( B ) {}
     650or when( GC ) waituntil( C ) {}
     651\end{cfa}
     652\caption{\lstinline{waituntil} with a non-trivial predicate}
     653\label{f:WU_ComplexPredicate}
     654\end{figure}
    604655
    605656In the \uC @_Select@ statement, this problem is solved by constructing a tree of the resources, where the internal nodes are operators and the leaves are booleans storing the state of each resource.
     
    608659Once the root of the tree has both subtrees marked as @true@ then the statement is complete.
    609660As an optimization, when the internal nodes are updated, the subtrees marked as @true@ are pruned and not examined again.
    610 To support statement guards in \uC, the tree prunes a branch if the corresponding guard is false.
    611 \PAB{Show an example.}
     661To support statement guards in \uC, the tree is modified to remove an internal node if a guard is false to maintain the appropriate predicate representation.
     662An diagram of the tree for the statement in Figure~\ref{f:WU_ComplexPredicate} is shown in Figure~\ref{f:uC_select_tree}, alongside the modification of the tree that occurs when @GA@ is @false@.
     663
     664\begin{figure}
     665\begin{center}
     666\input{diagrams/uCpp_select_tree.tikz}
     667\end{center}
     668\caption{\uC select tree modification}
     669\label{f:uC_select_tree}
     670\end{figure}
    612671
    613672The \CFA @waituntil@ statement blocks a thread until a set of resources have become available that satisfy the underlying predicate.
     
    616675Leveraging the compiler, a predicate routine is generated per @waituntil@ that when passes the statuses of the resources, returns @true@ when the @waituntil@ is done, and false otherwise.
    617676To support guards on the \CFA @waituntil@ statement, the status of a resource disabled by a guard is set to a boolean value that ensures that the predicate function behaves as if that resource is no longer part of the predicate.
    618 \PAB{Show an example.}
     677The generated code allows the predicate that is checked with each iteration to be simplified to not check guard values.
     678For example, the following would be generated for the @waituntil@ shown in Figure~\ref{f:WU_ComplexPredicate}.
     679\begin{cfa}
     680// statement completion predicate
     681bool check_completion( select_node * nodes ) {
     682    return nodes[0].status && nodes[1].status || nodes[2].status;
     683}
     684
     685// skip statement if all guards false
     686if ( GA || GB || GC ) {
     687    select_node nodes[3];
     688    nodes[0].status = !GA && GB; // A's status
     689    nodes[1].status = !GB && GA; // B's status
     690    nodes[2].status = !GC;       // C's status
     691
     692    // ... rest of waituntil codegen ...
     693
     694}
     695\end{cfa}
    619696
    620697\uC's @_Select@, supports operators both inside and outside of the \lstinline[language=uC++]{_Select} clauses.
    621698In the following example, the code blocks run once their corresponding predicate inside the round braces is satisfied.
    622 % C_TODO put this is uC++ code style not cfa-style
     699
    623700\begin{lstlisting}[language=uC++,{moredelim=**[is][\color{red}]{@}{@}}]
    624701Future_ISM<int> A, B, C, D;
     
    640717however, that opens the potential for livelock.
    641718Another possibility is to use resource ordering similar to \CFA's @mutex@ statement, but that alone is insufficient, if the resource ordering is not used universally.
    642 Additionally, using resource ordering could conflict with other semantics of the @waituntil@ statement.
    643 For example, consider if the locks in the example must be acquired in the order @D@, @B@, @C@, @A@ because of other @waituntil@ statements.
    644 \PAB{I don't understand: If all the locks are available, it becomes complex to both respect the ordering of the \lstinline{waituntil} when choosing which code block to run and also respect the lock ordering of \lstinline{D}, \lstinline{B}, \lstinline{C}, \lstinline{A} at the same time.}
    645719One other way this could be implemented is to wait until all resources for a given clause are available before proceeding to acquire them, but this also quickly becomes a poor approach.
    646720This approach does not work due to \gls{toctou} issues;
     
    661735\begin{cfa}
    662736bool when_conditions[N];
    663 for ( node in s )                                                                       $\C[3.75in]{// evaluate guards}$
     737for ( node in nodes )                                                                   $\C[3.75in]{// evaluate guards}$
    664738        if ( node has guard )
    665739                when_conditions[node] = node_guard;
     
    667741                when_conditions[node] = true;
    668742
    669 select_nodes s[N];                                                                      $\C{// declare N select nodes}$
     743if ( any when_conditions[node] == true ) {
     744
     745select_nodes nodes[N];                                                                  $\C{// declare N select nodes}$
    670746try {
    671         for ( node in s )                                                               $\C{// register nodes}$
    672                 if ( when_conditions[node] )
    673                         register_select( resource, node );
    674 
    675         // ... set statuses for nodes with when_conditions[node] == false ...
    676 
    677         while ( statement predicate not satisfied ) {   $\C{// check predicate}$
    678                 // block
    679                 for ( resource in waituntil statement ) {       $\C{// run true code blocks}$
    680                         if ( statement predicate is satisfied ) break;
    681                         if ( resource is avail )
    682                                 try {
    683                                         if( on_selected( resource ) )   $\C{// conditionally run block}$
    684                                                 run code block
    685                                 } finally                                                       $\C{// for exception safety}$
    686                                         unregister_select( resource, node ); $\C{// immediate unregister}$
    687                 }
    688         }
     747    // ... set statuses for nodes with when_conditions[node] == false ...
     748
     749    for ( node in nodes )                                                               $\C{// register nodes}$
     750        if ( when_conditions[node] )
     751            register_select( resource, node );
     752
     753    while ( !check_completion( nodes ) ) {      $\C{// check predicate}$
     754        // block
     755        for ( resource in waituntil statement ) {       $\C{// run true code blocks}$
     756            if ( check_completion( nodes ) ) break;
     757            if ( resource is avail )
     758                try {
     759                    if( on_selected( resource ) )       $\C{// conditionally run block}$
     760                        run code block
     761                } finally                                                       $\C{// for exception safety}$
     762                    unregister_select( resource, node ); $\C{// immediate unregister}$
     763        }
     764    }
    689765} finally {                                                                                     $\C{// for exception safety}$
    690         for ( registered nodes in s )                                   $\C{// deregister nodes}$
     766        for ( registered nodes in nodes )                                       $\C{// deregister nodes}$
    691767                if ( when_conditions[node] && unregister_select( resource, node )
    692768                                && on_selected( resource ) )
    693769                        run code block                                                  $\C{// run code block upon unregister}\CRT$
     770}
     771
    694772}
    695773\end{cfa}
Note: See TracChangeset for help on using the changeset viewer.