Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/concurrency/Paper.tex

    r1e5d0f0c rca0f061f  
    215215{}
    216216\lstnewenvironment{Go}[1][]
    217 {\lstset{language=go,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    218 {}
    219 \lstnewenvironment{python}[1][]
    220 {\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
     217{\lstset{#1}}
    221218{}
    222219
     
    231228}
    232229
    233 \title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
     230\title{\texorpdfstring{Advanced Control-flow in \protect\CFA}{Advanced Control-flow in Cforall}}
    234231
    235232\author[1]{Thierry Delisle}
     
    245242\abstract[Summary]{
    246243\CFA is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language.
    247 This paper discusses some advanced control-flow and concurrency/parallelism features in \CFA, along with the supporting runtime.
    248 These features are created from scratch because they do not exist in ISO C, or are low-level and/or unimplemented, so C programmers continue to rely on library features, like C pthreads.
    249 \CFA introduces language-level control-flow mechanisms, like coroutines, user-level threading, and monitors for mutual exclusion and synchronization.
    250 A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously} (deadlock free), while integrating this capability with monitor synchronization mechanisms.
    251 These features also integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
     244This paper discusses the advanced control-flow features in \CFA, which include concurrency and parallelism, and its supporting runtime system.
     245These features are created from scratch as ISO C's concurrency is low-level and unimplemented, so C programmers continue to rely on the C pthreads library.
     246\CFA provides high-level control-flow mechanisms, like coroutines and user-level threads, and monitors for mutual exclusion and synchronization.
     247A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously} (deadlock free), while integrating this capability with all monitor synchronization mechanisms.
     248All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
    252249Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    253250}%
     
    264261\section{Introduction}
    265262
    266 This paper discusses the design of language-level control-flow and concurrency/parallelism extensions in \CFA and its runtime.
     263This paper discusses the design of advanced, high-level control-flow extensions (especially concurrency and parallelism) in \CFA and its runtime.
    267264\CFA is a modern, polymorphic, non-object-oriented\footnote{
    268265\CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
    269266However, functions \emph{cannot} be nested in structures, so there is no lexical binding between a structure and set of functions (member/method) implemented by an implicit \lstinline@this@ (receiver) parameter.},
    270267backwards-compatible extension of the C programming language~\cite{Moss18}.
    271 Within the \CFA framework, new control-flow features are created from scratch.
    272 ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
    273 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
    274 Furthermore, \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a few locks, which is low-level and error prone;
    275 no high-level language concurrency features are defined.
    276 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach.
    277 Finally, while the \Celeven standard does not state a concurrent threading-model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}.
     268Within the \CFA framework, new control-flow features were created from scratch.
     269ISO \Celeven defines only a subset of the \CFA extensions, and with respect to concurrency~\cite[\S~7.26]{C11}, the features are largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
     270Furthermore, \Celeven and pthreads concurrency is basic, based on thread fork/join in a function and a few locks, which is low-level and error prone;
     271no high-level language concurrency features exist.
     272Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C concurrency approach.
     273Finally, while the \Celeven standard does not state a concurrent threading-model, the historical association with pthreads suggests the threading model is kernel-level threading (1:1)~\cite{ThreadModel}.
    278274
    279275In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
     
    288284
    289285A further effort over the past decade is the development of language memory-models to deal with the conflict between certain language features and compiler/hardware optimizations.
    290 This issue can be rephrased as: some language features are pervasive (language and runtime) and cannot be safely added via a library to prevent invalidation by sequential optimizations~\cite{Buhr95a,Boehm05}.
     286This issue can be rephrased as some features are pervasive (language and runtime) and cannot be safely added via a library to prevent invalidation by sequential optimizations~\cite{Buhr95a,Boehm05}.
    291287The consequence is that a language must be cognizant of these features and provide sufficient tools to program around any safety issues.
    292288For example, C created the @volatile@ qualifier to provide correct execution for @setjmp@/@logjmp@ (concurrency came later).
    293 The common solution is to provide a handful of complex qualifiers and functions (e.g., @volatile@ and atomics) allowing programmers to write consistent/race-free programs, often in the sequentially-consistent memory-model~\cite{Boehm12}.
     289The simplest solution is to provide a handful of complex qualifiers and functions (e.g., @volatile@ and atomics) allowing programmers to write consistent/race-free programs, often in the sequentially-consistent memory-model~\cite{Boehm12}.
    294290
    295291While having a sufficient memory-model allows sound libraries to be constructed, writing these libraries can quickly become awkward and error prone, and using these low-level libraries has the same issues.
    296292Essentially, using low-level explicit locks is the concurrent equivalent of assembler programming.
    297 Just as most assembler programming is replaced with high-level programming, explicit locks can be replaced with high-level concurrency in a programming language.
    298 Then the goal is for the compiler to check for correct usage and follow any complex coding conventions implicitly.
     293Just as most assembler programming is replaced with programming in a high-level language, explicit locks can be replaced with high-level concurrency constructs in a programming language.
     294The goal is to get the compiler to check for correct usage and follow any complex coding conventions implicitly.
    299295The drawback is that language constructs may preclude certain specialized techniques, therefore introducing inefficiency or inhibiting concurrency.
    300296For most concurrent programs, these drawbacks are insignificant in comparison to the speed of composition, and subsequent reliability and maintainability of the high-level concurrent program.
     
    303299As stated, this observation applies to non-concurrent forms of complex control-flow, like exception handling and coroutines.
    304300
    305 Adapting the programming language to these features also allows matching the control-flow model with the programming-language style, versus adopting one general (sound) library/paradigm.
     301Adapting the programming language allows matching the control-flow model with the programming-language style, versus adapting to one general (sound) library/paradigm.
    306302For example, it is possible to provide exceptions, coroutines, monitors, and tasks as specialized types in an object-oriented language, integrating these constructs to allow leveraging the type-system (static type-checking) and all other object-oriented capabilities~\cite{uC++}.
    307303It is also possible to leverage call/return for blocking communication via new control structures, versus switching to alternative communication paradigms, like channels or message passing.
     
    311307however, the reverse is seldom true, i.e., given implicit concurrency, e.g., actors, it is virtually impossible to create explicit concurrency, e.g., blocking thread objects.}
    312308Finally, with extended language features and user-level threading it is possible to discretely fold locking and non-blocking I/O multiplexing into the language's I/O libraries, so threading implicitly dovetails with the I/O subsystem.
    313 \CFA embraces language extensions and user-level threading to provide advanced control-flow (exception handling\footnote{
    314 \CFA exception handling will be presented in a separate paper.
    315 The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}
    316 } and coroutines) and concurrency.
    317 
    318 Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory.
    319 As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
    320 While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (e.g., objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC.
    321 Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base.
    322 \CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems.
    323 
    324 We present comparative examples so the reader can judge if the \CFA control-flow extensions are equivalent or better than those in or proposed for \Celeven, \CC and other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
    325 The detailed contributions of this work are:
     309
     310\CFA embraces language extensions and user-level threading to provide advanced control-flow and concurrency.
     311We attempt to show the \CFA extensions and runtime are demonstrably better than those proposed for \CC and other concurrent, imperative programming languages.
     312The contributions of this work are:
    326313\begin{itemize}
    327314\item
     
    628615
    629616
    630 \section{Coroutines: Stepping Stone}
    631 \label{coroutine}
    632 
     617\section{Coroutines: A Stepping Stone}\label{coroutine}
     618
     619Advanced controlWhile the focus of this discussion is concurrency and parallelism, it is important to address coroutines, which are a significant building block of a concurrency system (but not concurrent among themselves).
    633620Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed.
    634621Hence, unlike a normal routine, a coroutine may not terminate when it returns to its caller, allowing it to be restarted with the values and execution location present at the point of suspension.
     
    654641\centering
    655642\newbox\myboxA
    656 % \begin{lrbox}{\myboxA}
    657 % \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    658 % `int fn1, fn2, state = 1;`   // single global variables
    659 % int fib() {
    660 %       int fn;
    661 %       `switch ( state )` {  // explicit execution state
    662 %         case 1: fn = 0;  fn1 = fn;  state = 2;  break;
    663 %         case 2: fn = 1;  fn2 = fn1;  fn1 = fn;  state = 3;  break;
    664 %         case 3: fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;  break;
    665 %       }
    666 %       return fn;
    667 % }
    668 % int main() {
    669 %
    670 %       for ( int i = 0; i < 10; i += 1 ) {
    671 %               printf( "%d\n", fib() );
    672 %       }
    673 % }
    674 % \end{cfa}
    675 % \end{lrbox}
    676643\begin{lrbox}{\myboxA}
    677644\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    678 #define FIB_INIT { 0, 1 }
    679 typedef struct { int fn1, fn; } Fib;
     645`int f1, f2, state = 1;`   // single global variables
     646int fib() {
     647        int fn;
     648        `switch ( state )` {  // explicit execution state
     649          case 1: fn = 0;  f1 = fn;  state = 2;  break;
     650          case 2: fn = 1;  f2 = f1;  f1 = fn;  state = 3;  break;
     651          case 3: fn = f1 + f2;  f2 = f1;  f1 = fn;  break;
     652        }
     653        return fn;
     654}
     655int main() {
     656
     657        for ( int i = 0; i < 10; i += 1 ) {
     658                printf( "%d\n", fib() );
     659        }
     660}
     661\end{cfa}
     662\end{lrbox}
     663
     664\newbox\myboxB
     665\begin{lrbox}{\myboxB}
     666\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     667#define FIB_INIT `{ 0, 1 }`
     668typedef struct { int f2, f1; } Fib;
    680669int fib( Fib * f ) {
    681670
    682         int ret = f->fn1;
    683         f->fn1 = f->fn;
    684         f->fn = ret + f->fn;
     671        int ret = f->f2;
     672        int fn = f->f1 + f->f2;
     673        f->f2 = f->f1; f->f1 = fn;
     674
    685675        return ret;
    686676}
    687 
    688 
    689 
    690677int main() {
    691678        Fib f1 = FIB_INIT, f2 = FIB_INIT;
    692679        for ( int i = 0; i < 10; i += 1 ) {
    693                 printf( "%d %d\n",
    694                                 fib( &f1 ), fib( &f2 ) );
     680                printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
    695681        }
    696682}
     
    698684\end{lrbox}
    699685
     686\subfloat[3 States: global variables]{\label{f:GlobalVariables}\usebox\myboxA}
     687\qquad
     688\subfloat[1 State: external variables]{\label{f:ExternalState}\usebox\myboxB}
     689\caption{C Fibonacci Implementations}
     690\label{f:C-fibonacci}
     691
     692\bigskip
     693
     694\newbox\myboxA
     695\begin{lrbox}{\myboxA}
     696\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     697`coroutine` Fib { int fn; };
     698void main( Fib & fib ) with( fib ) {
     699        int f1, f2;
     700        fn = 0;  f1 = fn;  `suspend()`;
     701        fn = 1;  f2 = f1;  f1 = fn;  `suspend()`;
     702        for ( ;; ) {
     703                fn = f1 + f2;  f2 = f1;  f1 = fn;  `suspend()`;
     704        }
     705}
     706int next( Fib & fib ) with( fib ) {
     707        `resume( fib );`
     708        return fn;
     709}
     710int main() {
     711        Fib f1, f2;
     712        for ( int i = 1; i <= 10; i += 1 ) {
     713                sout | next( f1 ) | next( f2 );
     714        }
     715}
     716\end{cfa}
     717\end{lrbox}
    700718\newbox\myboxB
    701719\begin{lrbox}{\myboxB}
    702720\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    703 `coroutine` Fib { int fn1; };
    704 void main( Fib & fib ) with( fib ) {
    705         int fn;
    706         [fn1, fn] = [0, 1];
    707         for () {
    708                 `suspend();`
    709                 [fn1, fn] = [fn, fn1 + fn];
     721`coroutine` Fib { int ret; };
     722void main( Fib & f ) with( fib ) {
     723        int fn, f1 = 1, f2 = 0;
     724        for ( ;; ) {
     725                ret = f2;
     726
     727                fn = f1 + f2;  f2 = f1;  f1 = fn; `suspend();`
    710728        }
    711729}
    712 int ?()( Fib & fib ) with( fib ) {
    713         `resume( fib );`  return fn1;
    714 }
    715 int main() {
    716         Fib f1, f2;
    717         for ( 10 ) {
    718                 sout | f1() | f2();
    719 }
     730int next( Fib & fib ) with( fib ) {
     731        `resume( fib );`
     732        return ret;
     733}
     734
     735
     736
     737
    720738
    721739
    722740\end{cfa}
    723741\end{lrbox}
    724 
    725 \newbox\myboxC
    726 \begin{lrbox}{\myboxC}
    727 \begin{python}[aboveskip=0pt,belowskip=0pt]
    728 
    729 def Fib():
    730 
    731     fn1, fn = 0, 1
    732     while True:
    733         `yield fn1`
    734         fn1, fn = fn, fn1 + fn
    735 
    736 
    737 // next prewritten
    738 
    739 
    740 f1 = Fib()
    741 f2 = Fib()
    742 for i in range( 10 ):
    743         print( next( f1 ), next( f2 ) )
    744 
    745 
    746 
    747 \end{python}
    748 \end{lrbox}
    749 
    750 \subfloat[C]{\label{f:GlobalVariables}\usebox\myboxA}
    751 \hspace{3pt}
    752 \vrule
    753 \hspace{3pt}
    754 \subfloat[\CFA]{\label{f:ExternalState}\usebox\myboxB}
    755 \hspace{3pt}
    756 \vrule
    757 \hspace{3pt}
    758 \subfloat[Python]{\label{f:ExternalState}\usebox\myboxC}
    759 \caption{Fibonacci Generator}
    760 \label{f:C-fibonacci}
    761 
    762 % \bigskip
    763 %
    764 % \newbox\myboxA
    765 % \begin{lrbox}{\myboxA}
    766 % \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    767 % `coroutine` Fib { int fn; };
    768 % void main( Fib & fib ) with( fib ) {
    769 %       fn = 0;  int fn1 = fn; `suspend()`;
    770 %       fn = 1;  int fn2 = fn1;  fn1 = fn; `suspend()`;
    771 %       for () {
    772 %               fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `suspend()`; }
    773 % }
    774 % int next( Fib & fib ) with( fib ) { `resume( fib );` return fn; }
    775 % int main() {
    776 %       Fib f1, f2;
    777 %       for ( 10 )
    778 %               sout | next( f1 ) | next( f2 );
    779 % }
    780 % \end{cfa}
    781 % \end{lrbox}
    782 % \newbox\myboxB
    783 % \begin{lrbox}{\myboxB}
    784 % \begin{python}[aboveskip=0pt,belowskip=0pt]
    785 %
    786 % def Fibonacci():
    787 %       fn = 0; fn1 = fn; `yield fn`  # suspend
    788 %       fn = 1; fn2 = fn1; fn1 = fn; `yield fn`
    789 %       while True:
    790 %               fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `yield fn`
    791 %
    792 %
    793 % f1 = Fibonacci()
    794 % f2 = Fibonacci()
    795 % for i in range( 10 ):
    796 %       print( `next( f1 )`, `next( f2 )` ) # resume
    797 %
    798 % \end{python}
    799 % \end{lrbox}
    800 % \subfloat[\CFA]{\label{f:Coroutine3States}\usebox\myboxA}
    801 % \qquad
    802 % \subfloat[Python]{\label{f:Coroutine1State}\usebox\myboxB}
    803 % \caption{Fibonacci input coroutine, 3 states, internal variables}
    804 % \label{f:cfa-fibonacci}
     742\subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA}
     743\qquad\qquad
     744\subfloat[1 State, internal variables]{\label{f:Coroutine1State}\usebox\myboxB}
     745\caption{\CFA Coroutine Fibonacci Implementations}
     746\label{f:cfa-fibonacci}
    805747\end{figure}
    806748
     
    842784\begin{lrbox}{\myboxA}
    843785\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    844 `coroutine` Fmt {
    845         char ch;   // communication variables
    846         int g, b;   // needed in destructor
     786`coroutine` Format {
     787        char ch;   // used for communication
     788        int g, b;  // global because used in destructor
    847789};
    848 void main( Fmt & fmt ) with( fmt ) {
    849         for () {
    850                 for ( g = 0; g < 5; g += 1 ) { // groups
    851                         for ( b = 0; b < 4; b += 1 ) { // blocks
     790void main( Format & fmt ) with( fmt ) {
     791        for ( ;; ) {
     792                for ( g = 0; g < 5; g += 1 ) {      // group
     793                        for ( b = 0; b < 4; b += 1 ) { // block
    852794                                `suspend();`
    853                                 sout | ch; } // print character
    854                         sout | "  "; } // block separator
    855                 sout | nl; }  // group separator
    856 }
    857 void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime
    858 void ^?{}( Fmt & fmt ) with( fmt ) { // destructor
    859         if ( g != 0 || b != 0 ) // special case
    860                 sout | nl; }
    861 void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; }
     795                                sout | ch;              // separator
     796                        }
     797                        sout | "  ";               // separator
     798                }
     799                sout | nl;
     800        }
     801}
     802void ?{}( Format & fmt ) { `resume( fmt );` }
     803void ^?{}( Format & fmt ) with( fmt ) {
     804        if ( g != 0 || b != 0 ) sout | nl;
     805}
     806void format( Format & fmt ) {
     807        `resume( fmt );`
     808}
    862809int main() {
    863         Fmt fmt;
    864         sout | nlOff;   // turn off auto newline
    865         for ( 41 )
    866                 send( fmt, 'a' );
     810        Format fmt;
     811        eof: for ( ;; ) {
     812                sin | fmt.ch;
     813          if ( eof( sin ) ) break eof;
     814                format( fmt );
     815        }
    867816}
    868817\end{cfa}
     
    871820\newbox\myboxB
    872821\begin{lrbox}{\myboxB}
    873 \begin{python}[aboveskip=0pt,belowskip=0pt]
    874 
    875 
    876 
    877 def Fmt():
    878         try:
    879                 while True:
    880                         for g in range( 5 ):
    881                                 for b in range( 4 ):
    882 
    883                                         print( `(yield)`, end='' )
    884                                 print( '  ', end='' )
    885                         print()
    886 
    887 
    888         except GeneratorExit:
    889                 if g != 0 | b != 0:
    890                         print()
    891 
    892 
    893 fmt = Fmt()
    894 `next( fmt )`                    # prime
    895 for i in range( 41 ):
    896         `fmt.send( 'a' );`      # send to yield
    897 
    898 \end{python}
     822\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     823struct Format {
     824        char ch;
     825        int g, b;
     826};
     827void format( struct Format * fmt ) {
     828        if ( fmt->ch != -1 ) {      // not EOF ?
     829                printf( "%c", fmt->ch );
     830                fmt->b += 1;
     831                if ( fmt->b == 4 ) {  // block
     832                        printf( "  " );      // separator
     833                        fmt->b = 0;
     834                        fmt->g += 1;
     835                }
     836                if ( fmt->g == 5 ) {  // group
     837                        printf( "\n" );     // separator
     838                        fmt->g = 0;
     839                }
     840        } else {
     841                if ( fmt->g != 0 || fmt->b != 0 ) printf( "\n" );
     842        }
     843}
     844int main() {
     845        struct Format fmt = { 0, 0, 0 };
     846        for ( ;; ) {
     847                scanf( "%c", &fmt.ch );
     848          if ( feof( stdin ) ) break;
     849                format( &fmt );
     850        }
     851        fmt.ch = -1;
     852        format( &fmt );
     853}
     854\end{cfa}
    899855\end{lrbox}
    900 \subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA}
     856\subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
    901857\qquad
    902 \subfloat[Python]{\label{f:CFmt}\usebox\myboxB}
    903 \caption{Output formatting text}
     858\subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB}
     859\caption{Formatting text into lines of 5 blocks of 4 characters.}
    904860\label{f:fmt-line}
    905861\end{figure}
     
    922878void main( Prod & prod ) with( prod ) {
    923879        // 1st resume starts here
    924         for ( i; N ) {
     880        for ( int i = 0; i < N; i += 1 ) {
    925881                int p1 = random( 100 ), p2 = random( 100 );
    926882                sout | p1 | " " | p2;
     
    938894}
    939895void start( Prod & prod, int N, Cons &c ) {
    940         &prod.c = &c; // reassignable reference
     896        &prod.c = &c;
    941897        prod.[N, receipt] = [N, 0];
    942898        `resume( prod );`
     
    953909        Prod & p;
    954910        int p1, p2, status;
    955         bool done;
     911        _Bool done;
    956912};
    957913void ?{}( Cons & cons, Prod & p ) {
    958         &cons.p = &p; // reassignable reference
     914        &cons.p = &p;
    959915        cons.[status, done ] = [0, false];
    960916}
     
    1013969The program main restarts after the resume in @start@.
    1014970@start@ returns and the program main terminates.
    1015 
    1016 One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
    1017 Many device drivers are a finite state-machine parsing a protocol, e.g.:
    1018 \begin{tabbing}
    1019 \ldots STX \= \ldots message \ldots \= ESC \= ETX \= \ldots message \ldots  \= ETX \= 2-byte crc \= \ldots      \kill
    1020 \ldots STX \> \ldots message \ldots \> ESC \> ETX \> \ldots message \ldots  \> ETX \> 2-byte crc \> \ldots
    1021 \end{tabbing}
    1022 where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.
    1023 Control characters may appear in a message if preceded by an ESC.
    1024 Because FSMs can be complex and occur frequently in important domains, direct support of the coroutine is crucial in a systems programminglanguage.
    1025 
    1026 \begin{figure}
    1027 \begin{cfa}
    1028 enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
    1029 `coroutine` Driver {
    1030         Status status;
    1031         char * msg, byte;
    1032 };
    1033 void ?{}( Driver & d, char * m ) { d.msg = m; }         $\C[3.0in]{// constructor}$
    1034 Status next( Driver & d, char b ) with( d ) {           $\C{// 'with' opens scope}$
    1035         byte = b; `resume( d );` return status;
    1036 }
    1037 void main( Driver & d ) with( d ) {
    1038         enum { STX = '\002', ESC = '\033', ETX = '\003', MaxMsg = 64 };
    1039         unsigned short int crc;                                                 $\C{// error checking}$
    1040   msg: for () {                                                                         $\C{// parse message}$
    1041                 status = CONT;
    1042                 unsigned int lnth = 0, sum = 0;
    1043                 while ( byte != STX ) `suspend();`
    1044           emsg: for () {
    1045                         `suspend();`                                                    $\C{// process byte}$
    1046                         choose ( byte ) {                                               $\C{// switch with default break}$
    1047                           case STX:
    1048                                 status = ESTX; `suspend();` continue msg;
    1049                           case ETX:
    1050                                 break emsg;
    1051                           case ESC:
    1052                                 suspend();
    1053                         } // choose
    1054                         if ( lnth >= MaxMsg ) {                                 $\C{// buffer full ?}$
    1055                                 status = ELNTH; `suspend();` continue msg; }
    1056                         msg[lnth++] = byte;
    1057                         sum += byte;
    1058                 } // for
    1059                 msg[lnth] = '\0';                                                       $\C{// terminate string}\CRT$
    1060                 `suspend();`
    1061                 crc = (unsigned char)byte << 8; // prevent sign extension for signed char
    1062                 `suspend();`
    1063                 status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
    1064                 `suspend();`
    1065         } // for
    1066 }
    1067 \end{cfa}
    1068 \caption{Device driver for simple communication protocol}
    1069 \end{figure}
    1070971
    1071972
Note: See TracChangeset for help on using the changeset viewer.