Ignore:
File:
1 edited

Legend:

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

    rca0f061f r1e5d0f0c  
    215215{}
    216216\lstnewenvironment{Go}[1][]
    217 {\lstset{#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}}
    218221{}
    219222
     
    228231}
    229232
    230 \title{\texorpdfstring{Advanced Control-flow in \protect\CFA}{Advanced Control-flow in Cforall}}
     233\title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
    231234
    232235\author[1]{Thierry Delisle}
     
    242245\abstract[Summary]{
    243246\CFA is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language.
    244 This paper discusses the advanced control-flow features in \CFA, which include concurrency and parallelism, and its supporting runtime system.
    245 These 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.
    247 A 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.
    248 All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
     247This paper discusses some advanced control-flow and concurrency/parallelism features in \CFA, along with the supporting runtime.
     248These 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.
     250A 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.
     251These features also integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
    249252Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    250253}%
     
    261264\section{Introduction}
    262265
    263 This paper discusses the design of advanced, high-level control-flow extensions (especially concurrency and parallelism) in \CFA and its runtime.
     266This paper discusses the design of language-level control-flow and concurrency/parallelism extensions in \CFA and its runtime.
    264267\CFA is a modern, polymorphic, non-object-oriented\footnote{
    265268\CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
    266269However, 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.},
    267270backwards-compatible extension of the C programming language~\cite{Moss18}.
    268 Within the \CFA framework, new control-flow features were created from scratch.
    269 ISO \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}.
    270 Furthermore, \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;
    271 no high-level language concurrency features exist.
    272 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 C concurrency approach.
    273 Finally, 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}.
     271Within the \CFA framework, new control-flow features are created from scratch.
     272ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
     273However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
     274Furthermore, \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;
     275no high-level language concurrency features are defined.
     276Interestingly, 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.
     277Finally, 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}.
    274278
    275279In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
     
    284288
    285289A 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.
    286 This 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}.
     290This 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}.
    287291The consequence is that a language must be cognizant of these features and provide sufficient tools to program around any safety issues.
    288292For example, C created the @volatile@ qualifier to provide correct execution for @setjmp@/@logjmp@ (concurrency came later).
    289 The 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}.
     293The 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}.
    290294
    291295While 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.
    292296Essentially, using low-level explicit locks is the concurrent equivalent of assembler programming.
    293 Just 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.
    294 The goal is to get the compiler to check for correct usage and follow any complex coding conventions implicitly.
     297Just as most assembler programming is replaced with high-level programming, explicit locks can be replaced with high-level concurrency in a programming language.
     298Then the goal is for the compiler to check for correct usage and follow any complex coding conventions implicitly.
    295299The drawback is that language constructs may preclude certain specialized techniques, therefore introducing inefficiency or inhibiting concurrency.
    296300For 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.
     
    299303As stated, this observation applies to non-concurrent forms of complex control-flow, like exception handling and coroutines.
    300304
    301 Adapting the programming language allows matching the control-flow model with the programming-language style, versus adapting to one general (sound) library/paradigm.
     305Adapting 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.
    302306For 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++}.
    303307It 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.
     
    307311however, 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.}
    308312Finally, 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.
    309 
    310 \CFA embraces language extensions and user-level threading to provide advanced control-flow and concurrency.
    311 We attempt to show the \CFA extensions and runtime are demonstrably better than those proposed for \CC and other concurrent, imperative programming languages.
    312 The contributions of this work are:
     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.
     315The 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
     318Most 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.
     319As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
     320While \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.
     321Hence, 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
     324We 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.
     325The detailed contributions of this work are:
    313326\begin{itemize}
    314327\item
     
    615628
    616629
    617 \section{Coroutines: A Stepping Stone}\label{coroutine}
    618 
    619 Advanced 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).
     630\section{Coroutines: Stepping Stone}
     631\label{coroutine}
     632
    620633Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed.
    621634Hence, 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.
     
    641654\centering
    642655\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}
    643676\begin{lrbox}{\myboxA}
    644677\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    645 `int f1, f2, state = 1;`   // single global variables
    646 int 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 }
     678#define FIB_INIT { 0, 1 }
     679typedef struct { int fn1, fn; } Fib;
     680int fib( Fib * f ) {
     681
     682        int ret = f->fn1;
     683        f->fn1 = f->fn;
     684        f->fn = ret + f->fn;
     685        return ret;
     686}
     687
     688
     689
    655690int main() {
    656 
     691        Fib f1 = FIB_INIT, f2 = FIB_INIT;
    657692        for ( int i = 0; i < 10; i += 1 ) {
    658                 printf( "%d\n", fib() );
     693                printf( "%d %d\n",
     694                                fib( &f1 ), fib( &f2 ) );
    659695        }
    660696}
     
    665701\begin{lrbox}{\myboxB}
    666702\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    667 #define FIB_INIT `{ 0, 1 }`
    668 typedef struct { int f2, f1; } Fib;
    669 int fib( Fib * f ) {
    670 
    671         int ret = f->f2;
    672         int fn = f->f1 + f->f2;
    673         f->f2 = f->f1; f->f1 = fn;
    674 
    675         return ret;
    676 }
    677 int main() {
    678         Fib f1 = FIB_INIT, f2 = FIB_INIT;
    679         for ( int i = 0; i < 10; i += 1 ) {
    680                 printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
     703`coroutine` Fib { int fn1; };
     704void main( Fib & fib ) with( fib ) {
     705        int fn;
     706        [fn1, fn] = [0, 1];
     707        for () {
     708                `suspend();`
     709                [fn1, fn] = [fn, fn1 + fn];
    681710        }
    682711}
    683 \end{cfa}
    684 \end{lrbox}
    685 
    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; };
    698 void 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 }
    706 int next( Fib & fib ) with( fib ) {
    707         `resume( fib );`
    708         return fn;
     712int ?()( Fib & fib ) with( fib ) {
     713        `resume( fib );`  return fn1;
    709714}
    710715int main() {
    711716        Fib f1, f2;
    712         for ( int i = 1; i <= 10; i += 1 ) {
    713                 sout | next( f1 ) | next( f2 );
    714         }
    715 }
     717        for ( 10 ) {
     718                sout | f1() | f2();
     719}
     720
     721
    716722\end{cfa}
    717723\end{lrbox}
    718 \newbox\myboxB
    719 \begin{lrbox}{\myboxB}
    720 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    721 `coroutine` Fib { int ret; };
    722 void 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();`
    728         }
    729 }
    730 int next( Fib & fib ) with( fib ) {
    731         `resume( fib );`
    732         return ret;
    733 }
    734 
    735 
    736 
    737 
    738 
    739 
    740 \end{cfa}
     724
     725\newbox\myboxC
     726\begin{lrbox}{\myboxC}
     727\begin{python}[aboveskip=0pt,belowskip=0pt]
     728
     729def 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
     740f1 = Fib()
     741f2 = Fib()
     742for i in range( 10 ):
     743        print( next( f1 ), next( f2 ) )
     744
     745
     746
     747\end{python}
    741748\end{lrbox}
    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}
     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}
    747805\end{figure}
    748806
     
    784842\begin{lrbox}{\myboxA}
    785843\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    786 `coroutine` Format {
    787         char ch;   // used for communication
    788         int g, b;  // global because used in destructor
     844`coroutine` Fmt {
     845        char ch;   // communication variables
     846        int g, b;   // needed in destructor
    789847};
    790 void 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
     848void 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
    794852                                `suspend();`
    795                                 sout | ch;              // separator
    796                         }
    797                         sout | "  ";               // separator
    798                 }
    799                 sout | nl;
    800         }
    801 }
    802 void ?{}( Format & fmt ) { `resume( fmt );` }
    803 void ^?{}( Format & fmt ) with( fmt ) {
    804         if ( g != 0 || b != 0 ) sout | nl;
    805 }
    806 void format( Format & fmt ) {
    807         `resume( fmt );`
    808 }
     853                                sout | ch; } // print character
     854                        sout | "  "; } // block separator
     855                sout | nl; }  // group separator
     856}
     857void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime
     858void ^?{}( Fmt & fmt ) with( fmt ) { // destructor
     859        if ( g != 0 || b != 0 ) // special case
     860                sout | nl; }
     861void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; }
    809862int main() {
    810         Format fmt;
    811         eof: for ( ;; ) {
    812                 sin | fmt.ch;
    813           if ( eof( sin ) ) break eof;
    814                 format( fmt );
    815         }
     863        Fmt fmt;
     864        sout | nlOff;   // turn off auto newline
     865        for ( 41 )
     866                send( fmt, 'a' );
    816867}
    817868\end{cfa}
     
    820871\newbox\myboxB
    821872\begin{lrbox}{\myboxB}
    822 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    823 struct Format {
    824         char ch;
    825         int g, b;
    826 };
    827 void 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 }
    844 int 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}
     873\begin{python}[aboveskip=0pt,belowskip=0pt]
     874
     875
     876
     877def 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
     893fmt = Fmt()
     894`next( fmt )`                    # prime
     895for i in range( 41 ):
     896        `fmt.send( 'a' );`      # send to yield
     897
     898\end{python}
    855899\end{lrbox}
    856 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
     900\subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA}
    857901\qquad
    858 \subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB}
    859 \caption{Formatting text into lines of 5 blocks of 4 characters.}
     902\subfloat[Python]{\label{f:CFmt}\usebox\myboxB}
     903\caption{Output formatting text}
    860904\label{f:fmt-line}
    861905\end{figure}
     
    878922void main( Prod & prod ) with( prod ) {
    879923        // 1st resume starts here
    880         for ( int i = 0; i < N; i += 1 ) {
     924        for ( i; N ) {
    881925                int p1 = random( 100 ), p2 = random( 100 );
    882926                sout | p1 | " " | p2;
     
    894938}
    895939void start( Prod & prod, int N, Cons &c ) {
    896         &prod.c = &c;
     940        &prod.c = &c; // reassignable reference
    897941        prod.[N, receipt] = [N, 0];
    898942        `resume( prod );`
     
    909953        Prod & p;
    910954        int p1, p2, status;
    911         _Bool done;
     955        bool done;
    912956};
    913957void ?{}( Cons & cons, Prod & p ) {
    914         &cons.p = &p;
     958        &cons.p = &p; // reassignable reference
    915959        cons.[status, done ] = [0, false];
    916960}
     
    9691013The program main restarts after the resume in @start@.
    9701014@start@ returns and the program main terminates.
     1015
     1016One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
     1017Many 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}
     1022where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.
     1023Control characters may appear in a message if preceded by an ESC.
     1024Because 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}
     1028enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
     1029`coroutine` Driver {
     1030        Status status;
     1031        char * msg, byte;
     1032};
     1033void ?{}( Driver & d, char * m ) { d.msg = m; }         $\C[3.0in]{// constructor}$
     1034Status next( Driver & d, char b ) with( d ) {           $\C{// 'with' opens scope}$
     1035        byte = b; `resume( d );` return status;
     1036}
     1037void 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}
    9711070
    9721071
Note: See TracChangeset for help on using the changeset viewer.