source: doc/papers/concurrency/Paper.tex @ 2296885

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumwith_gc
Last change on this file since 2296885 was 766309d, checked in by Peter A. Buhr <pabuhr@…>, 7 years ago

update C Fibonacci examples, make figures work

  • Property mode set to 100644
File size: 151.2 KB
Line 
1\documentclass[AMA,STIX1COL]{WileyNJD-v2}
2
3\articletype{RESEARCH ARTICLE}%
4
5\received{26 April 2016}
6\revised{6 June 2016}
7\accepted{6 June 2016}
8
9\raggedbottom
10
11%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12
13% Latex packages used in the document.
14\usepackage{epic,eepic}
15\usepackage{xspace}
16\usepackage{comment}
17\usepackage{upquote}                                            % switch curled `'" to straight
18\usepackage{listings}                                           % format program code
19\usepackage[labelformat=simple]{subfig}
20\renewcommand{\thesubfigure}{(\alph{subfigure})}
21\usepackage{siunitx}
22\sisetup{ binary-units=true }
23%\input{style}                                                          % bespoke macros used in the document
24
25\hypersetup{breaklinks=true}
26\definecolor{OliveGreen}{cmyk}{0.64 0 0.95 0.40}
27\definecolor{Mahogany}{cmyk}{0 0.85 0.87 0.35}
28\definecolor{Plum}{cmyk}{0.50 1 0 0}
29
30\usepackage[pagewise]{lineno}
31\renewcommand{\linenumberfont}{\scriptsize\sffamily}
32
33\lefthyphenmin=4                                                        % hyphen only after 4 characters
34\righthyphenmin=4
35
36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37
38% Names used in the document.
39
40\newcommand{\CFAIcon}{\textsf{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}\xspace} % Cforall symbolic name
41\newcommand{\CFA}{\protect\CFAIcon}             % safe for section/caption
42\newcommand{\CFL}{\textrm{Cforall}\xspace}      % Cforall symbolic name
43\newcommand{\Celeven}{\textrm{C11}\xspace}      % C11 symbolic name
44\newcommand{\CC}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}\xspace} % C++ symbolic name
45\newcommand{\CCeleven}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}11\xspace} % C++11 symbolic name
46\newcommand{\CCfourteen}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}14\xspace} % C++14 symbolic name
47\newcommand{\CCseventeen}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}17\xspace} % C++17 symbolic name
48\newcommand{\CCtwenty}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}20\xspace} % C++20 symbolic name
49\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name
50
51%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52
53\newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}}
54\newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}}
55\newcommand{\R}[1]{\Textbf{#1}}
56\newcommand{\B}[1]{{\Textbf[blue]{#1}}}
57\newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}
58\newcommand{\uC}{$\mu$\CC}
59\newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace}
60\newcommand{\TODO}{{\Textbf{TODO}}}
61
62%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63
64% Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore
65% removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR
66% AFTER HYPERREF.
67%\DeclareTextCommandDefault{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.1ex}}}
68\renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
69
70\makeatletter
71% parindent is relative, i.e., toggled on/off in environments like itemize, so store the value for
72% use rather than use \parident directly.
73\newlength{\parindentlnth}
74\setlength{\parindentlnth}{\parindent}
75
76\newcommand{\LstBasicStyle}[1]{{\lst@basicstyle{\lst@basicstyle{#1}}}}
77\newcommand{\LstKeywordStyle}[1]{{\lst@basicstyle{\lst@keywordstyle{#1}}}}
78\newcommand{\LstCommentStyle}[1]{{\lst@basicstyle{\lst@commentstyle{#1}}}}
79
80\newlength{\gcolumnposn}                                        % temporary hack because lstlisting does not handle tabs correctly
81\newlength{\columnposn}
82\setlength{\gcolumnposn}{3.5in}
83\setlength{\columnposn}{\gcolumnposn}
84\newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}}
85\newcommand{\CRT}{\global\columnposn=\gcolumnposn}
86
87% Denote newterms in particular font and index them without particular font and in lowercase, e.g., \newterm{abc}.
88% The option parameter provides an index term different from the new term, e.g., \newterm[\texttt{abc}]{abc}
89% The star version does not lowercase the index information, e.g., \newterm*{IBM}.
90\newcommand{\newtermFontInline}{\emph}
91\newcommand{\newterm}{\@ifstar\@snewterm\@newterm}
92\newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
93\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
94
95% Latin abbreviation
96\newcommand{\abbrevFont}{\textit}                       % set empty for no italics
97\newcommand{\EG}{\abbrevFont{e}.\abbrevFont{g}.}
98\newcommand*{\eg}{%
99        \@ifnextchar{,}{\EG}%
100                {\@ifnextchar{:}{\EG}%
101                        {\EG,\xspace}}%
102}%
103\newcommand{\IE}{\abbrevFont{i}.\abbrevFont{e}.}
104\newcommand*{\ie}{%
105        \@ifnextchar{,}{\IE}%
106                {\@ifnextchar{:}{\IE}%
107                        {\IE,\xspace}}%
108}%
109\newcommand{\ETC}{\abbrevFont{etc}}
110\newcommand*{\etc}{%
111        \@ifnextchar{.}{\ETC}%
112        {\ETC.\xspace}%
113}%
114\newcommand{\ETAL}{\abbrevFont{et}~\abbrevFont{al}}
115\renewcommand*{\etal}{%
116        \@ifnextchar{.}{\protect\ETAL}%
117                {\protect\ETAL.\xspace}%
118}%
119\newcommand{\VIZ}{\abbrevFont{viz}}
120\newcommand*{\viz}{%
121        \@ifnextchar{.}{\VIZ}%
122                {\VIZ.\xspace}%
123}%
124\makeatother
125
126\newenvironment{cquote}{%
127        \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=3pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
128        \item\relax
129}{%
130        \endlist
131}% cquote
132
133% CFA programming language, based on ANSI C (with some gcc additions)
134\lstdefinelanguage{CFA}[ANSI]{C}{
135        morekeywords={
136                _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, _At, __attribute,
137                __attribute__, auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__,
138                __const, __const__, disable, dtype, enable, exception, __extension__, fallthrough, fallthru,
139                finally, forall, ftype, _Generic, _Imaginary, inline, __label__, lvalue, _Noreturn, one_t,
140                otype, restrict, _Static_assert, throw, throwResume, trait, try, ttype, typeof, __typeof,
141                __typeof__, virtual, with, zero_t},
142        morekeywords=[2]{
143                _Atomic, coroutine, is_coroutine, is_monitor, is_thread, monitor, mutex, nomutex, or,
144                resume, suspend, thread, _Thread_local, waitfor, when, yield},
145        moredirectives={defined,include_next}%
146}
147
148\lstset{
149language=CFA,
150columns=fullflexible,
151basicstyle=\linespread{0.9}\sf,                                                 % reduce line spacing and use sanserif font
152stringstyle=\tt,                                                                                % use typewriter font
153tabsize=5,                                                                                              % N space tabbing
154xleftmargin=\parindentlnth,                                                             % indent code to paragraph indentation
155%mathescape=true,                                                                               % LaTeX math escape in CFA code $...$
156escapechar=\$,                                                                                  % LaTeX escape in CFA code
157keepspaces=true,                                                                                %
158showstringspaces=false,                                                                 % do not show spaces with cup
159showlines=true,                                                                                 % show blank lines at end of code
160aboveskip=4pt,                                                                                  % spacing above/below code block
161belowskip=3pt,
162% replace/adjust listing characters that look bad in sanserif
163literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
164        {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
165        {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex{\textgreater}}2,
166moredelim=**[is][\color{red}]{`}{`},
167}% lstset
168
169% uC++ programming language, based on ANSI C++
170\lstdefinelanguage{uC++}[ANSI]{C++}{
171        morekeywords={
172                _Accept, _AcceptReturn, _AcceptWait, _Actor, _At, _CatchResume, _Cormonitor, _Coroutine, _Disable,
173                _Else, _Enable, _Event, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
174                _Resume, _Select, _SporadicTask, _Task, _Timeout, _When, _With, _Throw},
175}
176\lstdefinelanguage{Golang}{
177        morekeywords=[1]{package,import,func,type,struct,return,defer,panic,recover,select,var,const,iota,},
178        morekeywords=[2]{string,uint,uint8,uint16,uint32,uint64,int,int8,int16,int32,int64,
179                bool,float32,float64,complex64,complex128,byte,rune,uintptr, error,interface},
180        morekeywords=[3]{map,slice,make,new,nil,len,cap,copy,close,true,false,delete,append,real,imag,complex,chan,},
181        morekeywords=[4]{for,break,continue,range,goto,switch,case,fallthrough,if,else,default,},
182        morekeywords=[5]{Println,Printf,Error,},
183        sensitive=true,
184        morecomment=[l]{//},
185        morecomment=[s]{/*}{*/},
186        morestring=[b]',
187        morestring=[b]",
188        morestring=[s]{`}{`},
189}
190
191\lstnewenvironment{cfa}[1][]
192{\lstset{#1}}
193{}
194\lstnewenvironment{C++}[1][]                            % use C++ style
195{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
196{}
197\lstnewenvironment{uC++}[1][]
198{\lstset{#1}}
199{}
200\lstnewenvironment{Go}[1][]
201{\lstset{#1}}
202{}
203
204% inline code @...@
205\lstMakeShortInline@%
206
207
208\title{\texorpdfstring{Concurrency in \protect\CFA}{Concurrency in Cforall}}
209
210\author[1]{Thierry Delisle}
211\author[1]{Peter A. Buhr*}
212\authormark{Thierry Delisle \textsc{et al}}
213
214\address[1]{\orgdiv{David R. Cheriton School of Computer Science}, \orgname{University of Waterloo}, \orgaddress{\state{Ontario}, \country{Canada}}}
215
216\corres{*Peter A. Buhr, \email{pabuhr{\char`\@}uwaterloo.ca}}
217\presentaddress{David R. Cheriton School of Computer Science, University of Waterloo, Waterloo, ON, N2L 3G1, Canada}
218
219
220\abstract[Summary]{
221\CFA is a modern, polymorphic, \emph{non-object-oriented} extension of the C programming language.
222This paper discusses the design of the concurrency and parallelism features in \CFA, and the concurrent runtime-system.
223These features are created from scratch as ISO C lacks concurrency, relying largely on pthreads.
224Coroutines and lightweight (user) threads are introduced into the language.
225In addition, monitors are added as a high-level mechanism for mutual exclusion and synchronization.
226A unique contribution is allowing multiple monitors to be safely acquired simultaneously.
227All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
228Finally, experimental results are presented to compare the performance of the new features with similar mechanisms in other concurrent programming-languages.
229}%
230
231\keywords{concurrency, runtime, coroutines, threads, C, Cforall}
232
233
234\begin{document}
235\linenumbers                                            % comment out to turn off line numbering
236
237\maketitle
238
239% ======================================================================
240% ======================================================================
241\section{Introduction}
242% ======================================================================
243% ======================================================================
244
245This paper provides a minimal concurrency \newterm{API} that is simple, efficient and can be used to build other concurrency features.
246While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master.
247An easier approach for programmers is to support higher-level constructs as the basis of concurrency.
248Indeed, for highly productive concurrent programming, high-level approaches are much more popular~\cite{Hochstein05}.
249Examples of high-level approaches are task based~\cite{TBB}, message passing~\cite{Erlang,MPI}, and implicit threading~\cite{OpenMP}.
250
251The terminology used in this paper is as follows.
252A \newterm{thread} is a fundamental unit of execution that runs a sequence of code and requires a stack to maintain state.
253Multiple simultaneous threads gives rise to \newterm{concurrency}, which requires locking to ensure safe access to shared data.
254% Correspondingly, concurrency is defined as the concepts and challenges that occur when multiple independent (sharing memory, timing dependencies, etc.) concurrent threads are introduced.
255\newterm{Locking}, and by extension locks, are defined as a mechanism to prevent progress of threads to provide safety.
256\newterm{Parallelism} is running multiple threads simultaneously.
257Parallelism implies \emph{actual} simultaneous execution, where concurrency only requires \emph{apparent} simultaneous execution.
258As such, parallelism is only observable in differences in performance, which is observed through differences in timing.
259
260Hence, there are two problems to be solved in the design of concurrency for a programming language: concurrency and parallelism.
261While these two concepts are often combined, they are in fact distinct, requiring different tools~\cite{Buhr05a}.
262Concurrency tools handle mutual exclusion and synchronization, while parallelism tools handle performance, cost and resource utilization.
263
264The proposed concurrency API is implemented in a dialect of C, called \CFA.
265The paper discusses how the language features are added to the \CFA translator with respect to parsing, semantic, and type checking, and the corresponding high-perforamnce runtime-library to implement the concurrency features.
266
267% ======================================================================
268% ======================================================================
269\section{\CFA Overview}
270% ======================================================================
271% ======================================================================
272
273The following is a quick introduction to the \CFA language, specifically tailored to the features needed to support concurrency.
274
275\CFA is an extension of ISO-C and therefore supports all of the same paradigms as C.
276It is a non-object-oriented system-language, meaning most of the major abstractions have either no runtime overhead or can be opted out easily.
277Like C, the basics of \CFA revolve around structures and routines, which are thin abstractions over machine code.
278The vast majority of the code produced by the \CFA translator respects memory layouts and calling conventions laid out by C.
279Interestingly, while \CFA is not an object-oriented language, lacking the concept of a receiver (e.g., {\tt this}), it does have some notion of objects\footnote{C defines the term objects as : ``region of data storage in the execution environment, the contents of which can represent
280values''~\cite[3.15]{C11}}, most importantly construction and destruction of objects.
281Most of the following code examples can be found on the \CFA website~\cite{Cforall}.
282
283
284\subsection{References}
285
286Like \CC, \CFA introduces rebind-able references providing multiple dereferencing as an alternative to pointers.
287In regards to concurrency, the semantic difference between pointers and references are not particularly relevant, but since this document uses mostly references, here is a quick overview of the semantics:
288\begin{cfa}
289int x, *p1 = &x, **p2 = &p1, ***p3 = &p2,
290        &r1 = x,    &&r2 = r1,   &&&r3 = r2;
291***p3 = 3;                                                      $\C{// change x}$
292r3    = 3;                                                      $\C{// change x, ***r3}$
293**p3  = ...;                                            $\C{// change p1}$
294*p3   = ...;                                            $\C{// change p2}$
295int y, z, & ar[3] = {x, y, z};          $\C{// initialize array of references}$
296typeof( ar[1]) p;                                       $\C{// is int, referenced object type}$
297typeof(&ar[1]) q;                                       $\C{// is int \&, reference type}$
298sizeof( ar[1]) == sizeof(int);          $\C{// is true, referenced object size}$
299sizeof(&ar[1]) == sizeof(int *);        $\C{// is true, reference size}$
300\end{cfa}
301The important take away from this code example is that a reference offers a handle to an object, much like a pointer, but which is automatically dereferenced for convenience.
302
303% ======================================================================
304\subsection{Overloading}
305
306Another important feature of \CFA is function overloading as in Java and \CC, where routines with the same name are selected based on the number and type of the arguments.
307As well, \CFA uses the return type as part of the selection criteria, as in Ada~\cite{Ada}.
308For routines with multiple parameters and returns, the selection is complex.
309\begin{cfa}
310// selection based on type and number of parameters
311void f(void);                   $\C{// (1)}$
312void f(char);                   $\C{// (2)}$
313void f(int, double);    $\C{// (3)}$
314f();                                    $\C{// select (1)}$
315f('a');                                 $\C{// select (2)}$
316f(3, 5.2);                              $\C{// select (3)}$
317
318// selection based on  type and number of returns
319char   f(int);                  $\C{// (1)}$
320double f(int);                  $\C{// (2)}$
321char   c = f(3);                $\C{// select (1)}$
322double d = f(4);                $\C{// select (2)}$
323\end{cfa}
324This feature is particularly important for concurrency since the runtime system relies on creating different types to represent concurrency objects.
325Therefore, overloading is necessary to prevent the need for long prefixes and other naming conventions that prevent name clashes.
326As seen in section \ref{basics}, routine @main@ is an example that benefits from overloading.
327
328% ======================================================================
329\subsection{Operators}
330Overloading also extends to operators.
331The syntax for denoting operator-overloading is to name a routine with the symbol of the operator and question marks where the arguments of the operation appear, e.g.:
332\begin{cfa}
333int ++? (int op);                       $\C{// unary prefix increment}$
334int ?++ (int op);                       $\C{// unary postfix increment}$
335int ?+? (int op1, int op2);             $\C{// binary plus}$
336int ?<=?(int op1, int op2);             $\C{// binary less than}$
337int ?=? (int & op1, int op2);           $\C{// binary assignment}$
338int ?+=?(int & op1, int op2);           $\C{// binary plus-assignment}$
339
340struct S {int i, j;};
341S ?+?(S op1, S op2) {                           $\C{// add two structures}$
342        return (S){op1.i + op2.i, op1.j + op2.j};
343}
344S s1 = {1, 2}, s2 = {2, 3}, s3;
345s3 = s1 + s2;                                           $\C{// compute sum: s3 == {2, 5}}$
346\end{cfa}
347While concurrency does not use operator overloading directly, this feature is more important as an introduction for the syntax of constructors.
348
349% ======================================================================
350\subsection{Constructors/Destructors}
351Object lifetime is often a challenge in concurrency. \CFA uses the approach of giving concurrent meaning to object lifetime as a means of synchronization and/or mutual exclusion.
352Since \CFA relies heavily on the lifetime of objects, constructors and destructors is a core feature required for concurrency and parallelism. \CFA uses the following syntax for constructors and destructors:
353\begin{cfa}
354struct S {
355        size_t size;
356        int * ia;
357};
358void ?{}(S & s, int asize) {    $\C{// constructor operator}$
359        s.size = asize;                         $\C{// initialize fields}$
360        s.ia = calloc(size, sizeof(S));
361}
362void ^?{}(S & s) {                              $\C{// destructor operator}$
363        free(ia);                                       $\C{// de-initialization fields}$
364}
365int main() {
366        S x = {10}, y = {100};          $\C{// implicit calls: ?\{\}(x, 10), ?\{\}(y, 100)}$
367        ...                                                     $\C{// use x and y}$
368        ^x{}^y{};                            $\C{// explicit calls to de-initialize}$
369        x{20};  y{200};                         $\C{// explicit calls to reinitialize}$
370        ...                                                     $\C{// reuse x and y}$
371}                                                               $\C{// implicit calls: \^?\{\}(y), \^?\{\}(x)}$
372\end{cfa}
373The language guarantees that every object and all their fields are constructed.
374Like \CC, construction of an object is automatically done on allocation and destruction of the object is done on deallocation.
375Allocation and deallocation can occur on the stack or on the heap.
376\begin{cfa}
377{
378        struct S s = {10};      $\C{// allocation, call constructor}$
379        ...
380}                                               $\C{// deallocation, call destructor}$
381struct S * s = new();   $\C{// allocation, call constructor}$
382...
383delete(s);                              $\C{// deallocation, call destructor}$
384\end{cfa}
385Note that like \CC, \CFA introduces @new@ and @delete@, which behave like @malloc@ and @free@ in addition to constructing and destructing objects, after calling @malloc@ and before calling @free@, respectively.
386
387% ======================================================================
388\subsection{Parametric Polymorphism}
389\label{s:ParametricPolymorphism}
390Routines in \CFA can also be reused for multiple types.
391This capability is done using the @forall@ clauses, which allow separately compiled routines to support generic usage over multiple types.
392For example, the following sum function works for any type that supports construction from 0 and addition:
393\begin{cfa}
394// constraint type, 0 and +
395forall(otype T | { void ?{}(T *, zero_t); T ?+?(T, T); })
396T sum(T a[ ], size_t size) {
397        T total = 0;                            $\C{// construct T from 0}$
398        for(size_t i = 0; i < size; i++)
399                total = total + a[i];   $\C{// select appropriate +}$
400        return total;
401}
402
403S sa[5];
404int i = sum(sa, 5);                             $\C{// use S's 0 construction and +}$
405\end{cfa}
406
407Since writing constraints on types can become cumbersome for more constrained functions, \CFA also has the concept of traits.
408Traits are named collection of constraints that can be used both instead and in addition to regular constraints:
409\begin{cfa}
410trait summable( otype T ) {
411        void ?{}(T *, zero_t);          $\C{// constructor from 0 literal}$
412        T ?+?(T, T);                            $\C{// assortment of additions}$
413        T ?+=?(T *, T);
414        T ++?(T *);
415        T ?++(T *);
416};
417forall( otype T | summable(T) ) $\C{// use trait}$
418T sum(T a[], size_t size);
419\end{cfa}
420
421Note that the type use for assertions can be either an @otype@ or a @dtype@.
422Types declared as @otype@ refer to ``complete'' objects, i.e., objects with a size, a default constructor, a copy constructor, a destructor and an assignment operator.
423Using @dtype@, on the other hand, has none of these assumptions but is extremely restrictive, it only guarantees the object is addressable.
424
425% ======================================================================
426\subsection{with Clause/Statement}
427Since \CFA lacks the concept of a receiver, certain functions end up needing to repeat variable names often.
428To remove this inconvenience, \CFA provides the @with@ statement, which opens an aggregate scope making its fields directly accessible (like Pascal).
429\begin{cfa}
430struct S { int i, j; };
431int mem(S & this) with (this)           $\C{// with clause}$
432        i = 1;                                                  $\C{// this->i}$
433        j = 2;                                                  $\C{// this->j}$
434}
435int foo() {
436        struct S1 { ... } s1;
437        struct S2 { ... } s2;
438        with (s1)                                               $\C{// with statement}$
439        {
440                // access fields of s1 without qualification
441                with (s2)                                       $\C{// nesting}$
442                {
443                        // access fields of s1 and s2 without qualification
444                }
445        }
446        with (s1, s2)                                   $\C{// scopes open in parallel}$
447        {
448                // access fields of s1 and s2 without qualification
449        }
450}
451\end{cfa}
452
453For more information on \CFA see \cite{cforall-ug,Schluntz17,www-cfa}.
454
455% ======================================================================
456% ======================================================================
457\section{Concurrency Basics}\label{basics}
458% ======================================================================
459% ======================================================================
460Before any detailed discussion of the concurrency and parallelism in \CFA, it is important to describe the basics of concurrency and how they are expressed in \CFA user code.
461
462\section{Basics of concurrency}
463At its core, concurrency is based on having multiple call-stacks and scheduling among threads of execution executing on these stacks.
464Concurrency without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution.
465
466Execution with a single thread and multiple stacks where the thread is self-scheduling deterministically across the stacks is called coroutining.
467Execution with a single and multiple stacks but where the thread is scheduled by an oracle (non-deterministic from the thread's perspective) across the stacks is called concurrency.
468
469Therefore, a minimal concurrency system can be achieved by creating coroutines (see Section \ref{coroutine}), which instead of context-switching among each other, always ask an oracle where to context-switch next.
470While coroutines can execute on the caller's stack-frame, stack-full coroutines allow full generality and are sufficient as the basis for concurrency.
471The aforementioned oracle is a scheduler and the whole system now follows a cooperative threading-model (a.k.a., non-preemptive scheduling).
472The oracle/scheduler can either be a stack-less or stack-full entity and correspondingly require one or two context-switches to run a different coroutine.
473In any case, a subset of concurrency related challenges start to appear.
474For the complete set of concurrency challenges to occur, the only feature missing is preemption.
475
476A scheduler introduces order of execution uncertainty, while preemption introduces uncertainty about where context switches occur.
477Mutual exclusion and synchronization are ways of limiting non-determinism in a concurrent system.
478Now it is important to understand that uncertainty is desirable; uncertainty can be used by runtime systems to significantly increase performance and is often the basis of giving a user the illusion that tasks are running in parallel.
479Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows.
480
481
482\section{\protect\CFA's Thread Building Blocks}
483
484One of the important features that are missing in C is threading\footnote{While the C11 standard defines a ``threads.h'' header, it is minimal and defined as optional.
485As such, library support for threading is far from widespread.
486At the time of writing the paper, neither \protect\lstinline|gcc| nor \protect\lstinline|clang| support ``threads.h'' in their standard libraries.}.
487On modern architectures, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore modern programming languages must have the proper tools to allow users to write efficient concurrent programs to take advantage of parallelism.
488As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages.
489And being a system-level language means programmers expect to choose precisely which features they need and which cost they are willing to pay.
490
491
492\section{Coroutines: A Stepping Stone}\label{coroutine}
493
494While the main focus of this proposal is concurrency and parallelism, it is important to address coroutines, which are actually a significant building block of a concurrency system. \textbf{Coroutine}s are generalized routines which have predefined points where execution is suspended and can be resumed at a later time.
495Therefore, they need to deal with context switches and other context-management operations.
496This proposal includes coroutines both as an intermediate step for the implementation of threads, and a first-class feature of \CFA.
497Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant.
498The core \textbf{api} of coroutines revolves around two features: independent call-stacks and @suspend@/@resume@.
499
500\begin{figure}
501\begin{center}
502\begin{tabular}{@{}lll@{}}
503\multicolumn{1}{c}{\textbf{callback}} & \multicolumn{1}{c}{\textbf{output array}} & \multicolumn{1}{c}{\textbf{external state}} \\
504\begin{cfa}
505void fib_func(
506        int n, void (* callback)( int )
507) {
508        int fn, f1 = 0, f2 = 1;
509        for ( int i = 0; i < n; i++ ) {
510                callback( f1 );
511                fn = f1 + f2;
512                f1 = f2;  f2 = fn;
513        }
514}
515int main() {
516        void print_fib( int n ) {
517                printf( "%d\n", n );
518        }
519        fib_func( 10, print_fib );
520}
521
522\end{cfa}
523&
524\begin{cfa}
525void fib_array(
526        int n, int * array
527) {
528        int fn, f1 = 0, f2 = 1;
529        for ( int i = 0; i < n; i++ ) {
530                array[i] = f1;
531                fn = f1 + f2;
532                f1 = f2;  f2 = fn;
533        }
534}
535int main() {
536        int a[10];
537        fib_array( 10, a );
538        for ( int i = 0; i < 10; i++ ) {
539                printf( "%d\n", a[i] );
540        }
541}
542\end{cfa}
543&
544\begin{cfa}
545
546typedef struct { int f1, f2; } Fib;
547int fib_state(
548        Fib * fib
549) {
550        int ret = fib->f1;
551        int fn = fib->f1 + fib->f2;
552        fib->f2 = fib->f1; fib->f1 = fn;
553        return ret;
554}
555int main() {
556        Fib fib = { 0, 1 };
557
558        for ( int i = 0; i < 10; i++ ) {
559                printf( "%d\n", fib_state( &fib ) );
560        }
561}
562\end{cfa}
563\end{tabular}
564\end{center}
565\caption{Fibonacci Implementations in C}
566\label{lst:fib-c}
567\end{figure}
568
569A good example of a problem made easier with coroutines is generators, e.g., generating the Fibonacci sequence.
570This problem comes with the challenge of decoupling how a sequence is generated and how it is used.
571Listing \ref{lst:fibonacci-c} shows conventional approaches to writing generators in C.
572All three of these approach suffer from strong coupling.
573The left and centre approaches require that the generator have knowledge of how the sequence is used, while the rightmost approach requires holding internal state between calls on behalf of the generator and makes it much harder to handle corner cases like the Fibonacci seed.
574
575Listing \ref{lst:fibonacci-cfa} is an example of a solution to the Fibonacci problem using \CFA coroutines, where the coroutine stack holds sufficient state for the next generation.
576This solution has the advantage of having very strong decoupling between how the sequence is generated and how it is used.
577Indeed, this version is as easy to use as the @fibonacci_state@ solution, while the implementation is very similar to the @fibonacci_func@ example.
578
579\begin{figure}
580\begin{cfa}
581coroutine Fibonacci { int fn; };                                $\C{// used for communication}$
582
583void ?{}( Fibonacci & fib ) with( fib ) { fn = 0; } $\C{// constructor}$
584
585void main( Fibonacci & fib ) with( fib ) {              $\C{// main called on first resume}$
586        int fn1, fn2;                                                           $\C{// retained between resumes}$
587        fn = 0;  fn1 = fn;                                                      $\C{// 1st case}$
588        suspend();                                                                      $\C{// restart last resume}$
589        fn = 1;  fn2 = fn1;  fn1 = fn;                          $\C{// 2nd case}$
590        suspend();                                                                      $\C{// restart last resume}$
591        for ( ;; ) {
592                fn = fn1 + fn2; fn2 = fn1;  fn1 = fn;   $\C{// general case}$
593                suspend();                                                              $\C{// restart last resume}$
594        }
595}
596int next( Fibonacci & fib ) with( fib ) {
597        resume( fib );                                                          $\C{// restart last suspend}$
598        return fn;
599}
600int main() {
601        Fibonacci f1, f2;
602        for ( int i = 1; i <= 10; i++ ) {
603                sout | next( f1 ) | next( f2 ) | endl;
604        }
605}
606\end{cfa}
607\caption{Coroutine Fibonacci }
608\label{lst:fibonacci-cfa}
609\end{figure}
610
611Listing \ref{lst:fmt-line} shows the @Format@ coroutine for restructuring text into groups of character blocks of fixed size.
612The example takes advantage of resuming coroutines in the constructor to simplify the code and highlights the idea that interesting control flow can occur in the constructor.
613
614\begin{figure}
615\begin{cfa}[tabsize=3,caption={Formatting text into lines of 5 blocks of 4 characters.},label={lst:fmt-line}]
616// format characters into blocks of 4 and groups of 5 blocks per line
617coroutine Format {
618        char ch;                                                                        // used for communication
619        int g, b;                                                               // global because used in destructor
620};
621
622void  ?{}(Format& fmt) {
623        resume( fmt );                                                  // prime (start) coroutine
624}
625
626void ^?{}(Format& fmt) with fmt {
627        if ( fmt.g != 0 || fmt.b != 0 )
628        sout | endl;
629}
630
631void main(Format& fmt) with fmt {
632        for ( ;; ) {                                                    // for as many characters
633                for(g = 0; g < 5; g++) {                // groups of 5 blocks
634                        for(b = 0; b < 4; fb++) {       // blocks of 4 characters
635                                suspend();
636                                sout | ch;                                      // print character
637                        }
638                        sout | "  ";                                    // print block separator
639                }
640                sout | endl;                                            // print group separator
641        }
642}
643
644void prt(Format & fmt, char ch) {
645        fmt.ch = ch;
646        resume(fmt);
647}
648
649int main() {
650        Format fmt;
651        char ch;
652        Eof: for ( ;; ) {                                               // read until end of file
653                sin | ch;                                                       // read one character
654                if(eof(sin)) break Eof;                 // eof ?
655                prt(fmt, ch);                                           // push character for formatting
656        }
657}
658\end{cfa}
659\end{figure}
660
661\subsection{Construction}
662One important design challenge for implementing coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run code after the user-constructor runs to connect the fully constructed object into the system.
663In the case of coroutines, this challenge is simpler since there is no non-determinism from preemption or scheduling.
664However, the underlying challenge remains the same for coroutines and threads.
665
666The runtime system needs to create the coroutine's stack and, more importantly, prepare it for the first resumption.
667The timing of the creation is non-trivial since users expect both to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor.
668There are several solutions to this problem but the chosen option effectively forces the design of the coroutine.
669
670Furthermore, \CFA faces an extra challenge as polymorphic routines create invisible thunks when cast to non-polymorphic routines and these thunks have function scope.
671For example, the following code, while looking benign, can run into undefined behaviour because of thunks:
672
673\begin{cfa}
674// async: Runs function asynchronously on another thread
675forall(otype T)
676extern void async(void (*func)(T*), T* obj);
677
678forall(otype T)
679void noop(T*) {}
680
681void bar() {
682        int a;
683        async(noop, &a); // start thread running noop with argument a
684}
685\end{cfa}
686
687The generated C code\footnote{Code trimmed down for brevity} creates a local thunk to hold type information:
688
689\begin{cfa}
690extern void async(/* omitted */, void (*func)(void*), void* obj);
691
692void noop(/* omitted */, void* obj){}
693
694void bar(){
695        int a;
696        void _thunk0(int* _p0){
697                /* omitted */
698                noop(/* omitted */, _p0);
699        }
700        /* omitted */
701        async(/* omitted */, ((void (*)(void*))(&_thunk0)), (&a));
702}
703\end{cfa}
704The problem in this example is a storage management issue, the function pointer @_thunk0@ is only valid until the end of the block, which limits the viable solutions because storing the function pointer for too long causes undefined behaviour; i.e., the stack-based thunk being destroyed before it can be used.
705This challenge is an extension of challenges that come with second-class routines.
706Indeed, GCC nested routines also have the limitation that nested routine cannot be passed outside of the declaration scope.
707The case of coroutines and threads is simply an extension of this problem to multiple call stacks.
708
709\subsection{Alternative: Composition}
710One solution to this challenge is to use composition/containment, where coroutine fields are added to manage the coroutine.
711
712\begin{cfa}
713struct Fibonacci {
714        int fn; // used for communication
715        coroutine c; // composition
716};
717
718void FibMain(void*) {
719        //...
720}
721
722void ?{}(Fibonacci& this) {
723        this.fn = 0;
724        // Call constructor to initialize coroutine
725        (this.c){myMain};
726}
727\end{cfa}
728The downside of this approach is that users need to correctly construct the coroutine handle before using it.
729Like any other objects, the user must carefully choose construction order to prevent usage of objects not yet constructed.
730However, in the case of coroutines, users must also pass to the coroutine information about the coroutine main, like in the previous example.
731This opens the door for user errors and requires extra runtime storage to pass at runtime information that can be known statically.
732
733\subsection{Alternative: Reserved keyword}
734The next alternative is to use language support to annotate coroutines as follows:
735
736\begin{cfa}
737coroutine Fibonacci {
738        int fn; // used for communication
739};
740\end{cfa}
741The @coroutine@ keyword means the compiler can find and inject code where needed.
742The downside of this approach is that it makes coroutine a special case in the language.
743Users wanting to extend coroutines or build their own for various reasons can only do so in ways offered by the language.
744Furthermore, implementing coroutines without language supports also displays the power of the programming language used.
745While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can still be constructed by users without using the language support.
746The reserved keywords are only present to improve ease of use for the common cases.
747
748\subsection{Alternative: Lambda Objects}
749
750For coroutines as for threads, many implementations are based on routine pointers or function objects~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.
751For example, Boost implements coroutines in terms of four functor object types:
752\begin{cfa}
753asymmetric_coroutine<>::pull_type
754asymmetric_coroutine<>::push_type
755symmetric_coroutine<>::call_type
756symmetric_coroutine<>::yield_type
757\end{cfa}
758Often, the canonical threading paradigm in languages is based on function pointers, @pthread@ being one of the most well-known examples.
759The main problem of this approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type.
760Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda based coroutines adds very little.
761
762A variation of this would be to use a simple function pointer in the same way @pthread@ does for threads:
763\begin{cfa}
764void foo( coroutine_t cid, void* arg ) {
765        int* value = (int*)arg;
766        // Coroutine body
767}
768
769int main() {
770        int value = 0;
771        coroutine_t cid = coroutine_create( &foo, (void*)&value );
772        coroutine_resume( &cid );
773}
774\end{cfa}
775This semantics is more common for thread interfaces but coroutines work equally well.
776As discussed in section \ref{threads}, this approach is superseded by static approaches in terms of expressivity.
777
778\subsection{Alternative: Trait-Based Coroutines}
779
780Finally, the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines.
781This approach defines a coroutine as anything that satisfies the trait @is_coroutine@ (as defined below) and is used as a coroutine.
782
783\begin{cfa}
784trait is_coroutine(dtype T) {
785      void main(T& this);
786      coroutine_desc* get_coroutine(T& this);
787};
788
789forall( dtype T | is_coroutine(T) ) void suspend(T&);
790forall( dtype T | is_coroutine(T) ) void resume (T&);
791\end{cfa}
792This ensures that an object is not a coroutine until @resume@ is called on the object.
793Correspondingly, any object that is passed to @resume@ is a coroutine since it must satisfy the @is_coroutine@ trait to compile.
794The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory layout of a coroutine is trivial when implementing the @get_coroutine@ routine.
795The \CFA keyword @coroutine@ simply has the effect of implementing the getter and forward declarations required for users to implement the main routine.
796
797\begin{center}
798\begin{tabular}{c c c}
799\begin{cfa}[tabsize=3]
800coroutine MyCoroutine {
801        int someValue;
802};
803\end{cfa} & == & \begin{cfa}[tabsize=3]
804struct MyCoroutine {
805        int someValue;
806        coroutine_desc __cor;
807};
808
809static inline
810coroutine_desc* get_coroutine(
811        struct MyCoroutine& this
812) {
813        return &this.__cor;
814}
815
816void main(struct MyCoroutine* this);
817\end{cfa}
818\end{tabular}
819\end{center}
820
821The combination of these two approaches allows users new to coroutining and concurrency to have an easy and concise specification, while more advanced users have tighter control on memory layout and initialization.
822
823\section{Thread Interface}\label{threads}
824The basic building blocks of multithreading in \CFA are \textbf{cfathread}.
825Both user and kernel threads are supported, where user threads are the concurrency mechanism and kernel threads are the parallel mechanism.
826User threads offer a flexible and lightweight interface.
827A thread can be declared using a struct declaration @thread@ as follows:
828
829\begin{cfa}
830thread foo {};
831\end{cfa}
832
833As for coroutines, the keyword is a thin wrapper around a \CFA trait:
834
835\begin{cfa}
836trait is_thread(dtype T) {
837      void ^?{}(T & mutex this);
838      void main(T & this);
839      thread_desc* get_thread(T & this);
840};
841\end{cfa}
842
843Obviously, for this thread implementation to be useful it must run some user code.
844Several other threading interfaces use a function-pointer representation as the interface of threads (for example \Csharp~\cite{Csharp} and Scala~\cite{Scala}).
845However, this proposal considers that statically tying a @main@ routine to a thread supersedes this approach.
846Since the @main@ routine is already a special routine in \CFA (where the program begins), it is a natural extension of the semantics to use overloading to declare mains for different threads (the normal main being the main of the initial thread).
847As such the @main@ routine of a thread can be defined as
848\begin{cfa}
849thread foo {};
850
851void main(foo & this) {
852        sout | "Hello World!" | endl;
853}
854\end{cfa}
855
856In this example, threads of type @foo@ start execution in the @void main(foo &)@ routine, which prints @"Hello World!".@ While this paper encourages this approach to enforce strongly typed programming, users may prefer to use the routine-based thread semantics for the sake of simplicity.
857With the static semantics it is trivial to write a thread type that takes a function pointer as a parameter and executes it on its stack asynchronously.
858\begin{cfa}
859typedef void (*voidFunc)(int);
860
861thread FuncRunner {
862        voidFunc func;
863        int arg;
864};
865
866void ?{}(FuncRunner & this, voidFunc inFunc, int arg) {
867        this.func = inFunc;
868        this.arg  = arg;
869}
870
871void main(FuncRunner & this) {
872        // thread starts here and runs the function
873        this.func( this.arg );
874}
875
876void hello(/*unused*/ int) {
877        sout | "Hello World!" | endl;
878}
879
880int main() {
881        FuncRunner f = {hello, 42};
882        return 0?
883}
884\end{cfa}
885
886A consequence of the strongly typed approach to main is that memory layout of parameters and return values to/from a thread are now explicitly specified in the \textbf{api}.
887
888Of course, for threads to be useful, it must be possible to start and stop threads and wait for them to complete execution.
889While using an \textbf{api} such as @fork@ and @join@ is relatively common in the literature, such an interface is unnecessary.
890Indeed, the simplest approach is to use \textbf{raii} principles and have threads @fork@ after the constructor has completed and @join@ before the destructor runs.
891\begin{cfa}
892thread World;
893
894void main(World & this) {
895        sout | "World!" | endl;
896}
897
898void main() {
899        World w;
900        // Thread forks here
901
902        // Printing "Hello " and "World!" are run concurrently
903        sout | "Hello " | endl;
904
905        // Implicit join at end of scope
906}
907\end{cfa}
908
909This semantic has several advantages over explicit semantics: a thread is always started and stopped exactly once, users cannot make any programming errors, and it naturally scales to multiple threads meaning basic synchronization is very simple.
910
911\begin{cfa}
912thread MyThread {
913        //...
914};
915
916// main
917void main(MyThread& this) {
918        //...
919}
920
921void foo() {
922        MyThread thrds[10];
923        // Start 10 threads at the beginning of the scope
924
925        DoStuff();
926
927        // Wait for the 10 threads to finish
928}
929\end{cfa}
930
931However, one of the drawbacks of this approach is that threads always form a tree where nodes must always outlive their children, i.e., they are always destroyed in the opposite order of construction because of C scoping rules.
932This restriction is relaxed by using dynamic allocation, so threads can outlive the scope in which they are created, much like dynamically allocating memory lets objects outlive the scope in which they are created.
933
934\begin{cfa}
935thread MyThread {
936        //...
937};
938
939void main(MyThread& this) {
940        //...
941}
942
943void foo() {
944        MyThread* long_lived;
945        {
946                // Start a thread at the beginning of the scope
947                MyThread short_lived;
948
949                // create another thread that will outlive the thread in this scope
950                long_lived = new MyThread;
951
952                DoStuff();
953
954                // Wait for the thread short_lived to finish
955        }
956        DoMoreStuff();
957
958        // Now wait for the long_lived to finish
959        delete long_lived;
960}
961\end{cfa}
962
963
964% ======================================================================
965% ======================================================================
966\section{Concurrency}
967% ======================================================================
968% ======================================================================
969Several tools can be used to solve concurrency challenges.
970Since many of these challenges appear with the use of mutable shared state, some languages and libraries simply disallow mutable shared state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}).
971In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms closely relate to networking concepts (channels~\cite{CSP,Go} for example).
972However, in languages that use routine calls as their core abstraction mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine calls).
973This distinction in turn means that, in order to be effective, programmers need to learn two sets of design patterns.
974While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account.
975
976Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects.
977At the lowest level, concurrent paradigms are implemented as atomic operations and locks.
978Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}.
979However, for productivity reasons it is desirable to have a higher-level construct be the core concurrency paradigm~\cite{Hochstein05}.
980
981An approach that is worth mentioning because it is gaining in popularity is transactional memory~\cite{Herlihy93}.
982While this approach is even pursued by system languages like \CC~\cite{Cpp-Transactions}, the performance and feature set is currently too restrictive to be the main concurrency paradigm for system languages, which is why it was rejected as the core paradigm for concurrency in \CFA.
983
984One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared-memory systems, is the \emph{monitor}.
985Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}.
986Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs.
987In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors.
988For these reasons, this project proposes monitors as the core concurrency construct.
989
990\section{Basics}
991Non-determinism requires concurrent systems to offer support for mutual-exclusion and synchronization.
992Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is a group of instructions on an associated portion of data that requires the restricted access.
993On the other hand, synchronization enforces relative ordering of execution and synchronization tools provide numerous mechanisms to establish timing relationships among threads.
994
995\subsection{Mutual-Exclusion}
996As mentioned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once.
997However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use.
998Methods range from low-level locks, which are fast and flexible but require significant attention to be correct, to  higher-level concurrency techniques, which sacrifice some performance in order to improve ease of use.
999Ease of use comes by either guaranteeing some problems cannot occur (e.g., being deadlock free) or by offering a more explicit coupling between data and corresponding critical section.
1000For example, the \CC @std::atomic<T>@ offers an easy way to express mutual-exclusion on a restricted set of operations (e.g., reading/writing large types atomically).
1001Another challenge with low-level locks is composability.
1002Locks have restricted composability because it takes careful organizing for multiple locks to be used while preventing deadlocks.
1003Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.
1004
1005\subsection{Synchronization}
1006As with mutual-exclusion, low-level synchronization primitives often offer good performance and good flexibility at the cost of ease of use.
1007Again, higher-level mechanisms often simplify usage by adding either better coupling between synchronization and data (e.g., message passing) or offering a simpler solution to otherwise involved challenges.
1008As mentioned above, synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}.
1009Most of the time, synchronization happens within a critical section, where threads must acquire mutual-exclusion in a certain order.
1010However, it may also be desirable to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}.
1011Not satisfying this property is called \textbf{barging}.
1012For example, where event \textit{X} tries to effect event \textit{Y} but another thread acquires the critical section and emits \textit{Z} before \textit{Y}.
1013The classic example is the thread that finishes using a resource and unblocks a thread waiting to use the resource, but the unblocked thread must compete to acquire the resource.
1014Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.
1015This challenge is often split into two different methods, barging avoidance and barging prevention.
1016Algorithms that use flag variables to detect barging threads are said to be using barging avoidance, while algorithms that baton-pass locks~\cite{Andrews89} between threads instead of releasing the locks are said to be using barging prevention.
1017
1018% ======================================================================
1019% ======================================================================
1020\section{Monitors}
1021% ======================================================================
1022% ======================================================================
1023A \textbf{monitor} is a set of routines that ensure mutual-exclusion when accessing shared state.
1024More precisely, a monitor is a programming technique that associates mutual-exclusion to routine scopes, as opposed to mutex locks, where mutual-exclusion is defined by lock/release calls independently of any scoping of the calling routine.
1025This strong association eases readability and maintainability, at the cost of flexibility.
1026Note that both monitors and mutex locks, require an abstract handle to identify them.
1027This concept is generally associated with object-oriented languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OO semantics.
1028The only requirement is the ability to declare a handle to a shared object and a set of routines that act on it:
1029\begin{cfa}
1030typedef /*some monitor type*/ monitor;
1031int f(monitor & m);
1032
1033int main() {
1034        monitor m;  // Handle m
1035        f(m);       // Routine using handle
1036}
1037\end{cfa}
1038
1039% ======================================================================
1040% ======================================================================
1041\subsection{Call Semantics} \label{call}
1042% ======================================================================
1043% ======================================================================
1044The above monitor example displays some of the intrinsic characteristics.
1045First, it is necessary to use pass-by-reference over pass-by-value for monitor routines.
1046This semantics is important, because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied.
1047Therefore, monitors are non-copy-able objects (@dtype@).
1048
1049Another aspect to consider is when a monitor acquires its mutual exclusion.
1050For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry.
1051Passthrough can occur for generic helper routines (@swap@, @sort@, etc.) or specific helper routines like the following to implement an atomic counter:
1052
1053\begin{cfa}
1054monitor counter_t { /*...see section $\ref{data}$...*/ };
1055
1056void ?{}(counter_t & nomutex this); // constructor
1057size_t ++?(counter_t & mutex this); // increment
1058
1059// need for mutex is platform dependent
1060void ?{}(size_t * this, counter_t & mutex cnt); // conversion
1061\end{cfa}
1062This counter is used as follows:
1063\begin{center}
1064\begin{tabular}{c @{\hskip 0.35in} c @{\hskip 0.35in} c}
1065\begin{cfa}
1066// shared counter
1067counter_t cnt1, cnt2;
1068
1069// multiple threads access counter
1070thread 1 : cnt1++; cnt2++;
1071thread 2 : cnt1++; cnt2++;
1072thread 3 : cnt1++; cnt2++;
1073        ...
1074thread N : cnt1++; cnt2++;
1075\end{cfa}
1076\end{tabular}
1077\end{center}
1078Notice how the counter is used without any explicit synchronization and yet supports thread-safe semantics for both reading and writing, which is similar in usage to the \CC template @std::atomic@.
1079
1080Here, the constructor (@?{}@) uses the @nomutex@ keyword to signify that it does not acquire the monitor mutual-exclusion when constructing.
1081This semantics is because an object not yet constructed should never be shared and therefore does not require mutual exclusion.
1082Furthermore, it allows the implementation greater freedom when it initializes the monitor locking.
1083The prefix increment operator uses @mutex@ to protect the incrementing process from race conditions.
1084Finally, there is a conversion operator from @counter_t@ to @size_t@.
1085This conversion may or may not require the @mutex@ keyword depending on whether or not reading a @size_t@ is an atomic operation.
1086
1087For maximum usability, monitors use \textbf{multi-acq} semantics, which means a single thread can acquire the same monitor multiple times without deadlock.
1088For example, listing \ref{fig:search} uses recursion and \textbf{multi-acq} to print values inside a binary tree.
1089\begin{figure}
1090\begin{cfa}[caption={Recursive printing algorithm using \textbf{multi-acq}.},label={fig:search}]
1091monitor printer { ... };
1092struct tree {
1093        tree * left, right;
1094        char * value;
1095};
1096void print(printer & mutex p, char * v);
1097
1098void print(printer & mutex p, tree * t) {
1099        print(p, t->value);
1100        print(p, t->left );
1101        print(p, t->right);
1102}
1103\end{cfa}
1104\end{figure}
1105
1106Having both @mutex@ and @nomutex@ keywords can be redundant, depending on the meaning of a routine having neither of these keywords.
1107For example, it is reasonable that it should default to the safest option (@mutex@) when given a routine without qualifiers @void foo(counter_t & this)@, whereas assuming @nomutex@ is unsafe and may cause subtle errors.
1108On the other hand, @nomutex@ is the ``normal'' parameter behaviour, it effectively states explicitly that ``this routine is not special''.
1109Another alternative is making exactly one of these keywords mandatory, which provides the same semantics but without the ambiguity of supporting routines with neither keyword.
1110Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing.
1111While there are several benefits to mandatory keywords, they do bring a few challenges.
1112Mandatory keywords in \CFA would imply that the compiler must know without doubt whether or not a parameter is a monitor or not.
1113Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred.
1114For this reason, \CFA only has the @mutex@ keyword and uses no keyword to mean @nomutex@.
1115
1116The next semantic decision is to establish when @mutex@ may be used as a type qualifier.
1117Consider the following declarations:
1118\begin{cfa}
1119int f1(monitor & mutex m);
1120int f2(const monitor & mutex m);
1121int f3(monitor ** mutex m);
1122int f4(monitor * mutex m []);
1123int f5(graph(monitor *) & mutex m);
1124\end{cfa}
1125The problem is to identify which object(s) should be acquired.
1126Furthermore, each object needs to be acquired only once.
1127In the case of simple routines like @f1@ and @f2@ it is easy to identify an exhaustive list of objects to acquire on entry.
1128Adding indirections (@f3@) still allows the compiler and programmer to identify which object is acquired.
1129However, adding in arrays (@f4@) makes it much harder.
1130Array lengths are not necessarily known in C, and even then, making sure objects are only acquired once becomes none-trivial.
1131This problem can be extended to absurd limits like @f5@, which uses a graph of monitors.
1132To make the issue tractable, this project imposes the requirement that a routine may only acquire one monitor per parameter and it must be the type of the parameter with at most one level of indirection (ignoring potential qualifiers).
1133Also note that while routine @f3@ can be supported, meaning that monitor @**m@ is acquired, passing an array to this routine would be type-safe and yet result in undefined behaviour because only the first element of the array is acquired.
1134However, this ambiguity is part of the C type-system with respects to arrays.
1135For this reason, @mutex@ is disallowed in the context where arrays may be passed:
1136\begin{cfa}
1137int f1(monitor & mutex m);    // Okay : recommended case
1138int f2(monitor * mutex m);    // Not Okay : Could be an array
1139int f3(monitor mutex m []);  // Not Okay : Array of unknown length
1140int f4(monitor ** mutex m);   // Not Okay : Could be an array
1141int f5(monitor * mutex m []); // Not Okay : Array of unknown length
1142\end{cfa}
1143Note that not all array functions are actually distinct in the type system.
1144However, even if the code generation could tell the difference, the extra information is still not sufficient to extend meaningfully the monitor call semantic.
1145
1146Unlike object-oriented monitors, where calling a mutex member \emph{implicitly} acquires mutual-exclusion of the receiver object, \CFA uses an explicit mechanism to specify the object that acquires mutual-exclusion.
1147A consequence of this approach is that it extends naturally to multi-monitor calls.
1148\begin{cfa}
1149int f(MonitorA & mutex a, MonitorB & mutex b);
1150
1151MonitorA a;
1152MonitorB b;
1153f(a,b);
1154\end{cfa}
1155While OO monitors could be extended with a mutex qualifier for multiple-monitor calls, no example of this feature could be found.
1156The capability to acquire multiple locks before entering a critical section is called \emph{\textbf{bulk-acq}}.
1157In practice, writing multi-locking routines that do not lead to deadlocks is tricky.
1158Having language support for such a feature is therefore a significant asset for \CFA.
1159In the case presented above, \CFA guarantees that the order of acquisition is consistent across calls to different routines using the same monitors as arguments.
1160This consistent ordering means acquiring multiple monitors is safe from deadlock when using \textbf{bulk-acq}.
1161However, users can still force the acquiring order.
1162For example, notice which routines use @mutex@/@nomutex@ and how this affects acquiring order:
1163\begin{cfa}
1164void foo(A& mutex a, B& mutex b) { // acquire a & b
1165        ...
1166}
1167
1168void bar(A& mutex a, B& /*nomutex*/ b) { // acquire a
1169        ... foo(a, b); ... // acquire b
1170}
1171
1172void baz(A& /*nomutex*/ a, B& mutex b) { // acquire b
1173        ... foo(a, b); ... // acquire a
1174}
1175\end{cfa}
1176The \textbf{multi-acq} monitor lock allows a monitor lock to be acquired by both @bar@ or @baz@ and acquired again in @foo@.
1177In the calls to @bar@ and @baz@ the monitors are acquired in opposite order.
1178
1179However, such use leads to lock acquiring order problems.
1180In the example above, the user uses implicit ordering in the case of function @foo@ but explicit ordering in the case of @bar@ and @baz@.
1181This subtle difference means that calling these routines concurrently may lead to deadlock and is therefore undefined behaviour.
1182As shown~\cite{Lister77}, solving this problem requires:
1183\begin{enumerate}
1184        \item Dynamically tracking the monitor-call order.
1185        \item Implement rollback semantics.
1186\end{enumerate}
1187While the first requirement is already a significant constraint on the system, implementing a general rollback semantics in a C-like language is still prohibitively complex~\cite{Dice10}.
1188In \CFA, users simply need to be careful when acquiring multiple monitors at the same time or only use \textbf{bulk-acq} of all the monitors.
1189While \CFA provides only a partial solution, most systems provide no solution and the \CFA partial solution handles many useful cases.
1190
1191For example, \textbf{multi-acq} and \textbf{bulk-acq} can be used together in interesting ways:
1192\begin{cfa}
1193monitor bank { ... };
1194
1195void deposit( bank & mutex b, int deposit );
1196
1197void transfer( bank & mutex mybank, bank & mutex yourbank, int me2you) {
1198        deposit( mybank, -me2you );
1199        deposit( yourbank, me2you );
1200}
1201\end{cfa}
1202This example shows a trivial solution to the bank-account transfer problem~\cite{BankTransfer}.
1203Without \textbf{multi-acq} and \textbf{bulk-acq}, the solution to this problem is much more involved and requires careful engineering.
1204
1205
1206\subsection{\protect\lstinline|mutex| statement} \label{mutex-stmt}
1207
1208The call semantics discussed above have one software engineering issue: only a routine can acquire the mutual-exclusion of a set of monitor. \CFA offers the @mutex@ statement to work around the need for unnecessary names, avoiding a major software engineering problem~\cite{2FTwoHardThings}.
1209Table \ref{lst:mutex-stmt} shows an example of the @mutex@ statement, which introduces a new scope in which the mutual-exclusion of a set of monitor is acquired.
1210Beyond naming, the @mutex@ statement has no semantic difference from a routine call with @mutex@ parameters.
1211
1212\begin{table}
1213\begin{center}
1214\begin{tabular}{|c|c|}
1215function call & @mutex@ statement \\
1216\hline
1217\begin{cfa}[tabsize=3]
1218monitor M {};
1219void foo( M & mutex m1, M & mutex m2 ) {
1220        // critical section
1221}
1222
1223void bar( M & m1, M & m2 ) {
1224        foo( m1, m2 );
1225}
1226\end{cfa}&\begin{cfa}[tabsize=3]
1227monitor M {};
1228void bar( M & m1, M & m2 ) {
1229        mutex(m1, m2) {
1230                // critical section
1231        }
1232}
1233
1234
1235\end{cfa}
1236\end{tabular}
1237\end{center}
1238\caption{Regular call semantics vs. \protect\lstinline|mutex| statement}
1239\label{lst:mutex-stmt}
1240\end{table}
1241
1242% ======================================================================
1243% ======================================================================
1244\subsection{Data semantics} \label{data}
1245% ======================================================================
1246% ======================================================================
1247Once the call semantics are established, the next step is to establish data semantics.
1248Indeed, until now a monitor is used simply as a generic handle but in most cases monitors contain shared data.
1249This data should be intrinsic to the monitor declaration to prevent any accidental use of data without its appropriate protection.
1250For example, here is a complete version of the counter shown in section \ref{call}:
1251\begin{cfa}
1252monitor counter_t {
1253        int value;
1254};
1255
1256void ?{}(counter_t & this) {
1257        this.cnt = 0;
1258}
1259
1260int ?++(counter_t & mutex this) {
1261        return ++this.value;
1262}
1263
1264// need for mutex is platform dependent here
1265void ?{}(int * this, counter_t & mutex cnt) {
1266        *this = (int)cnt;
1267}
1268\end{cfa}
1269
1270Like threads and coroutines, monitors are defined in terms of traits with some additional language support in the form of the @monitor@ keyword.
1271The monitor trait is:
1272\begin{cfa}
1273trait is_monitor(dtype T) {
1274        monitor_desc * get_monitor( T & );
1275        void ^?{}( T & mutex );
1276};
1277\end{cfa}
1278Note that the destructor of a monitor must be a @mutex@ routine to prevent deallocation while a thread is accessing the monitor.
1279As with any object, calls to a monitor, using @mutex@ or otherwise, is undefined behaviour after the destructor has run.
1280
1281% ======================================================================
1282% ======================================================================
1283\section{Internal Scheduling} \label{intsched}
1284% ======================================================================
1285% ======================================================================
1286In addition to mutual exclusion, the monitors at the core of \CFA's concurrency can also be used to achieve synchronization.
1287With monitors, this capability is generally achieved with internal or external scheduling as in~\cite{Hoare74}.
1288With \textbf{scheduling} loosely defined as deciding which thread acquires the critical section next, \textbf{internal scheduling} means making the decision from inside the critical section (i.e., with access to the shared state), while \textbf{external scheduling} means making the decision when entering the critical section (i.e., without access to the shared state).
1289Since internal scheduling within a single monitor is mostly a solved problem, this paper concentrates on extending internal scheduling to multiple monitors.
1290Indeed, like the \textbf{bulk-acq} semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side.
1291
1292First, here is a simple example of internal scheduling:
1293
1294\begin{cfa}
1295monitor A {
1296        condition e;
1297}
1298
1299void foo(A& mutex a1, A& mutex a2) {
1300        ...
1301        // Wait for cooperation from bar()
1302        wait(a1.e);
1303        ...
1304}
1305
1306void bar(A& mutex a1, A& mutex a2) {
1307        // Provide cooperation for foo()
1308        ...
1309        // Unblock foo
1310        signal(a1.e);
1311}
1312\end{cfa}
1313There are two details to note here.
1314First, @signal@ is a delayed operation; it only unblocks the waiting thread when it reaches the end of the critical section.
1315This semantics is needed to respect mutual-exclusion, i.e., the signaller and signalled thread cannot be in the monitor simultaneously.
1316The alternative is to return immediately after the call to @signal@, which is significantly more restrictive.
1317Second, in \CFA, while it is common to store a @condition@ as a field of the monitor, a @condition@ variable can be stored/created independently of a monitor.
1318Here routine @foo@ waits for the @signal@ from @bar@ before making further progress, ensuring a basic ordering.
1319
1320An important aspect of the implementation is that \CFA does not allow barging, which means that once function @bar@ releases the monitor, @foo@ is guaranteed to be the next thread to acquire the monitor (unless some other thread waited on the same condition).
1321This guarantee offers the benefit of not having to loop around waits to recheck that a condition is met.
1322The main reason \CFA offers this guarantee is that users can easily introduce barging if it becomes a necessity but adding barging prevention or barging avoidance is more involved without language support.
1323Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in the design and implementation of \CFA concurrency.
1324
1325% ======================================================================
1326% ======================================================================
1327\subsection{Internal Scheduling - Multi-Monitor}
1328% ======================================================================
1329% ======================================================================
1330It is easy to understand the problem of multi-monitor scheduling using a series of pseudo-code examples.
1331Note that for simplicity in the following snippets of pseudo-code, waiting and signalling is done using an implicit condition variable, like Java built-in monitors.
1332Indeed, @wait@ statements always use the implicit condition variable as parameters and explicitly name the monitors (A and B) associated with the condition.
1333Note that in \CFA, condition variables are tied to a \emph{group} of monitors on first use (called branding), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors.
1334The example below shows the simple case of having two threads (one for each column) and a single monitor A.
1335
1336\begin{multicols}{2}
1337thread 1
1338\begin{cfa}
1339acquire A
1340        wait A
1341release A
1342\end{cfa}
1343
1344\columnbreak
1345
1346thread 2
1347\begin{cfa}
1348acquire A
1349        signal A
1350release A
1351\end{cfa}
1352\end{multicols}
1353One thread acquires before waiting (atomically blocking and releasing A) and the other acquires before signalling.
1354It is important to note here that both @wait@ and @signal@ must be called with the proper monitor(s) already acquired.
1355This semantic is a logical requirement for barging prevention.
1356
1357A direct extension of the previous example is a \textbf{bulk-acq} version:
1358\begin{multicols}{2}
1359\begin{cfa}
1360acquire A & B
1361        wait A & B
1362release A & B
1363\end{cfa}
1364\columnbreak
1365\begin{cfa}
1366acquire A & B
1367        signal A & B
1368release A & B
1369\end{cfa}
1370\end{multicols}
1371\noindent This version uses \textbf{bulk-acq} (denoted using the {\sf\&} symbol), but the presence of multiple monitors does not add a particularly new meaning.
1372Synchronization happens between the two threads in exactly the same way and order.
1373The only difference is that mutual exclusion covers a group of monitors.
1374On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate.
1375
1376While deadlock issues can occur when nesting monitors, these issues are only a symptom of the fact that locks, and by extension monitors, are not perfectly composable.
1377For monitors, a well-known deadlock problem is the Nested Monitor Problem~\cite{Lister77}, which occurs when a @wait@ is made by a thread that holds more than one monitor.
1378For example, the following cfa-code runs into the nested-monitor problem:
1379\begin{multicols}{2}
1380\begin{cfa}
1381acquire A
1382        acquire B
1383                wait B
1384        release B
1385release A
1386\end{cfa}
1387
1388\columnbreak
1389
1390\begin{cfa}
1391acquire A
1392        acquire B
1393                signal B
1394        release B
1395release A
1396\end{cfa}
1397\end{multicols}
1398\noindent The @wait@ only releases monitor @B@ so the signalling thread cannot acquire monitor @A@ to get to the @signal@.
1399Attempting release of all acquired monitors at the @wait@ introduces a different set of problems, such as releasing monitor @C@, which has nothing to do with the @signal@.
1400
1401However, for monitors as for locks, it is possible to write a program using nesting without encountering any problems if nesting is done correctly.
1402For example, the next cfa-code snippet acquires monitors {\sf A} then {\sf B} before waiting, while only acquiring {\sf B} when signalling, effectively avoiding the Nested Monitor Problem~\cite{Lister77}.
1403
1404\begin{multicols}{2}
1405\begin{cfa}
1406acquire A
1407        acquire B
1408                wait B
1409        release B
1410release A
1411\end{cfa}
1412
1413\columnbreak
1414
1415\begin{cfa}
1416
1417acquire B
1418        signal B
1419release B
1420
1421\end{cfa}
1422\end{multicols}
1423
1424\noindent However, this simple refactoring may not be possible, forcing more complex restructuring.
1425
1426% ======================================================================
1427% ======================================================================
1428\subsection{Internal Scheduling - In Depth}
1429% ======================================================================
1430% ======================================================================
1431
1432A larger example is presented to show complex issues for \textbf{bulk-acq} and its implementation options are analyzed.
1433Listing \ref{lst:int-bulk-cfa} shows an example where \textbf{bulk-acq} adds a significant layer of complexity to the internal signalling semantics, and listing \ref{lst:int-bulk-cfa} shows the corresponding \CFA code to implement the cfa-code in listing \ref{lst:int-bulk-cfa}.
1434For the purpose of translating the given cfa-code into \CFA-code, any method of introducing a monitor is acceptable, e.g., @mutex@ parameters, global variables, pointer parameters, or using locals with the @mutex@ statement.
1435
1436\begin{figure}
1437\begin{multicols}{2}
1438Waiting thread
1439\begin{cfa}[numbers=left]
1440acquire A
1441        // Code Section 1
1442        acquire A & B
1443                // Code Section 2
1444                wait A & B
1445                // Code Section 3
1446        release A & B
1447        // Code Section 4
1448release A
1449\end{cfa}
1450\columnbreak
1451Signalling thread
1452\begin{cfa}[numbers=left, firstnumber=10,escapechar=|]
1453acquire A
1454        // Code Section 5
1455        acquire A & B
1456                // Code Section 6
1457                |\label{line:signal1}|signal A & B
1458                // Code Section 7
1459        |\label{line:releaseFirst}|release A & B
1460        // Code Section 8
1461|\label{line:lastRelease}|release A
1462\end{cfa}
1463\end{multicols}
1464\begin{cfa}[caption={Internal scheduling with \textbf{bulk-acq}},label={lst:int-bulk-cfa}]
1465\end{cfa}
1466\begin{center}
1467\begin{cfa}[xleftmargin=.4\textwidth]
1468monitor A a;
1469monitor B b;
1470condition c;
1471\end{cfa}
1472\end{center}
1473\begin{multicols}{2}
1474Waiting thread
1475\begin{cfa}
1476mutex(a) {
1477        // Code Section 1
1478        mutex(a, b) {
1479                // Code Section 2
1480                wait(c);
1481                // Code Section 3
1482        }
1483        // Code Section 4
1484}
1485\end{cfa}
1486\columnbreak
1487Signalling thread
1488\begin{cfa}
1489mutex(a) {
1490        // Code Section 5
1491        mutex(a, b) {
1492                // Code Section 6
1493                signal(c);
1494                // Code Section 7
1495        }
1496        // Code Section 8
1497}
1498\end{cfa}
1499\end{multicols}
1500\begin{cfa}[caption={Equivalent \CFA code for listing \ref{lst:int-bulk-cfa}},label={lst:int-bulk-cfa}]
1501\end{cfa}
1502\begin{multicols}{2}
1503Waiter
1504\begin{cfa}[numbers=left]
1505acquire A
1506        acquire A & B
1507                wait A & B
1508        release A & B
1509release A
1510\end{cfa}
1511
1512\columnbreak
1513
1514Signaller
1515\begin{cfa}[numbers=left, firstnumber=6,escapechar=|]
1516acquire A
1517        acquire A & B
1518                signal A & B
1519        release A & B
1520        |\label{line:secret}|// Secretly keep B here
1521release A
1522// Wakeup waiter and transfer A & B
1523\end{cfa}
1524\end{multicols}
1525\begin{cfa}[caption={Listing \ref{lst:int-bulk-cfa}, with delayed signalling comments},label={lst:int-secret}]
1526\end{cfa}
1527\end{figure}
1528
1529The complexity begins at code sections 4 and 8 in listing \ref{lst:int-bulk-cfa}, which are where the existing semantics of internal scheduling needs to be extended for multiple monitors.
1530The root of the problem is that \textbf{bulk-acq} is used in a context where one of the monitors is already acquired, which is why it is important to define the behaviour of the previous cfa-code.
1531When the signaller thread reaches the location where it should ``release @A & B@'' (listing \ref{lst:int-bulk-cfa} line \ref{line:releaseFirst}), it must actually transfer ownership of monitor @B@ to the waiting thread.
1532This ownership transfer is required in order to prevent barging into @B@ by another thread, since both the signalling and signalled threads still need monitor @A@.
1533There are three options:
1534
1535\subsubsection{Delaying Signals}
1536The obvious solution to the problem of multi-monitor scheduling is to keep ownership of all locks until the last lock is ready to be transferred.
1537It can be argued that that moment is when the last lock is no longer needed, because this semantics fits most closely to the behaviour of single-monitor scheduling.
1538This solution has the main benefit of transferring ownership of groups of monitors, which simplifies the semantics from multiple objects to a single group of objects, effectively making the existing single-monitor semantic viable by simply changing monitors to monitor groups.
1539This solution releases the monitors once every monitor in a group can be released.
1540However, since some monitors are never released (e.g., the monitor of a thread), this interpretation means a group might never be released.
1541A more interesting interpretation is to transfer the group until all its monitors are released, which means the group is not passed further and a thread can retain its locks.
1542
1543However, listing \ref{lst:int-secret} shows this solution can become much more complicated depending on what is executed while secretly holding B at line \ref{line:secret}, while avoiding the need to transfer ownership of a subset of the condition monitors.
1544Listing \ref{lst:dependency} shows a slightly different example where a third thread is waiting on monitor @A@, using a different condition variable.
1545Because the third thread is signalled when secretly holding @B@, the goal  becomes unreachable.
1546Depending on the order of signals (listing \ref{lst:dependency} line \ref{line:signal-ab} and \ref{line:signal-a}) two cases can happen:
1547
1548\paragraph{Case 1: thread $\alpha$ goes first.} In this case, the problem is that monitor @A@ needs to be passed to thread $\beta$ when thread $\alpha$ is done with it.
1549\paragraph{Case 2: thread $\beta$ goes first.} In this case, the problem is that monitor @B@ needs to be retained and passed to thread $\alpha$ along with monitor @A@, which can be done directly or possibly using thread $\beta$ as an intermediate.
1550\\
1551
1552Note that ordering is not determined by a race condition but by whether signalled threads are enqueued in FIFO or FILO order.
1553However, regardless of the answer, users can move line \ref{line:signal-a} before line \ref{line:signal-ab} and get the reverse effect for listing \ref{lst:dependency}.
1554
1555In both cases, the threads need to be able to distinguish, on a per monitor basis, which ones need to be released and which ones need to be transferred, which means knowing when to release a group becomes complex and inefficient (see next section) and therefore effectively precludes this approach.
1556
1557\subsubsection{Dependency graphs}
1558
1559
1560\begin{figure}
1561\begin{multicols}{3}
1562Thread $\alpha$
1563\begin{cfa}[numbers=left, firstnumber=1]
1564acquire A
1565        acquire A & B
1566                wait A & B
1567        release A & B
1568release A
1569\end{cfa}
1570\columnbreak
1571Thread $\gamma$
1572\begin{cfa}[numbers=left, firstnumber=6, escapechar=|]
1573acquire A
1574        acquire A & B
1575                |\label{line:signal-ab}|signal A & B
1576        |\label{line:release-ab}|release A & B
1577        |\label{line:signal-a}|signal A
1578|\label{line:release-a}|release A
1579\end{cfa}
1580\columnbreak
1581Thread $\beta$
1582\begin{cfa}[numbers=left, firstnumber=12, escapechar=|]
1583acquire A
1584        wait A
1585|\label{line:release-aa}|release A
1586\end{cfa}
1587\end{multicols}
1588\begin{cfa}[caption={Pseudo-code for the three thread example.},label={lst:dependency}]
1589\end{cfa}
1590\begin{center}
1591\input{dependency}
1592\end{center}
1593\caption{Dependency graph of the statements in listing \ref{lst:dependency}}
1594\label{fig:dependency}
1595\end{figure}
1596
1597In listing \ref{lst:int-bulk-cfa}, there is a solution that satisfies both barging prevention and mutual exclusion.
1598If ownership of both monitors is transferred to the waiter when the signaller releases @A & B@ and then the waiter transfers back ownership of @A@ back to the signaller when it releases it, then the problem is solved (@B@ is no longer in use at this point).
1599Dynamically finding the correct order is therefore the second possible solution.
1600The problem is effectively resolving a dependency graph of ownership requirements.
1601Here even the simplest of code snippets requires two transfers and has a super-linear complexity.
1602This complexity can be seen in listing \ref{lst:explosion}, which is just a direct extension to three monitors, requires at least three ownership transfer and has multiple solutions.
1603Furthermore, the presence of multiple solutions for ownership transfer can cause deadlock problems if a specific solution is not consistently picked; In the same way that multiple lock acquiring order can cause deadlocks.
1604\begin{figure}
1605\begin{multicols}{2}
1606\begin{cfa}
1607acquire A
1608        acquire B
1609                acquire C
1610                        wait A & B & C
1611                release C
1612        release B
1613release A
1614\end{cfa}
1615
1616\columnbreak
1617
1618\begin{cfa}
1619acquire A
1620        acquire B
1621                acquire C
1622                        signal A & B & C
1623                release C
1624        release B
1625release A
1626\end{cfa}
1627\end{multicols}
1628\begin{cfa}[caption={Extension to three monitors of listing \ref{lst:int-bulk-cfa}},label={lst:explosion}]
1629\end{cfa}
1630\end{figure}
1631
1632Given the three threads example in listing \ref{lst:dependency}, figure \ref{fig:dependency} shows the corresponding dependency graph that results, where every node is a statement of one of the three threads, and the arrows the dependency of that statement (e.g., $\alpha1$ must happen before $\alpha2$).
1633The extra challenge is that this dependency graph is effectively post-mortem, but the runtime system needs to be able to build and solve these graphs as the dependencies unfold.
1634Resolving dependency graphs being a complex and expensive endeavour, this solution is not the preferred one.
1635
1636\subsubsection{Partial Signalling} \label{partial-sig}
1637Finally, the solution that is chosen for \CFA is to use partial signalling.
1638Again using listing \ref{lst:int-bulk-cfa}, the partial signalling solution transfers ownership of monitor @B@ at lines \ref{line:signal1} to the waiter but does not wake the waiting thread since it is still using monitor @A@.
1639Only when it reaches line \ref{line:lastRelease} does it actually wake up the waiting thread.
1640This solution has the benefit that complexity is encapsulated into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met.
1641This solution has a much simpler implementation than a dependency graph solving algorithms, which is why it was chosen.
1642Furthermore, after being fully implemented, this solution does not appear to have any significant downsides.
1643
1644Using partial signalling, listing \ref{lst:dependency} can be solved easily:
1645\begin{itemize}
1646        \item When thread $\gamma$ reaches line \ref{line:release-ab} it transfers monitor @B@ to thread $\alpha$ and continues to hold monitor @A@.
1647        \item When thread $\gamma$ reaches line \ref{line:release-a}  it transfers monitor @A@ to thread $\beta$  and wakes it up.
1648        \item When thread $\beta$  reaches line \ref{line:release-aa} it transfers monitor @A@ to thread $\alpha$ and wakes it up.
1649\end{itemize}
1650
1651% ======================================================================
1652% ======================================================================
1653\subsection{Signalling: Now or Later}
1654% ======================================================================
1655% ======================================================================
1656\begin{table}
1657\begin{tabular}{|c|c|}
1658@signal@ & @signal_block@ \\
1659\hline
1660\begin{cfa}[tabsize=3]
1661monitor DatingService {
1662        // compatibility codes
1663        enum{ CCodes = 20 };
1664
1665        int girlPhoneNo
1666        int boyPhoneNo;
1667};
1668
1669condition girls[CCodes];
1670condition boys [CCodes];
1671condition exchange;
1672
1673int girl(int phoneNo, int cfa) {
1674        // no compatible boy ?
1675        if(empty(boys[cfa])) {
1676                wait(girls[cfa]);               // wait for boy
1677                girlPhoneNo = phoneNo;          // make phone number available
1678                signal(exchange);               // wake boy from chair
1679        } else {
1680                girlPhoneNo = phoneNo;          // make phone number available
1681                signal(boys[cfa]);              // wake boy
1682                wait(exchange);         // sit in chair
1683        }
1684        return boyPhoneNo;
1685}
1686int boy(int phoneNo, int cfa) {
1687        // same as above
1688        // with boy/girl interchanged
1689}
1690\end{cfa}&\begin{cfa}[tabsize=3]
1691monitor DatingService {
1692
1693        enum{ CCodes = 20 };    // compatibility codes
1694
1695        int girlPhoneNo;
1696        int boyPhoneNo;
1697};
1698
1699condition girls[CCodes];
1700condition boys [CCodes];
1701// exchange is not needed
1702
1703int girl(int phoneNo, int cfa) {
1704        // no compatible boy ?
1705        if(empty(boys[cfa])) {
1706                wait(girls[cfa]);               // wait for boy
1707                girlPhoneNo = phoneNo;          // make phone number available
1708                signal(exchange);               // wake boy from chair
1709        } else {
1710                girlPhoneNo = phoneNo;          // make phone number available
1711                signal_block(boys[cfa]);                // wake boy
1712
1713                // second handshake unnecessary
1714
1715        }
1716        return boyPhoneNo;
1717}
1718
1719int boy(int phoneNo, int cfa) {
1720        // same as above
1721        // with boy/girl interchanged
1722}
1723\end{cfa}
1724\end{tabular}
1725\caption{Dating service example using \protect\lstinline|signal| and \protect\lstinline|signal_block|. }
1726\label{tbl:datingservice}
1727\end{table}
1728An important note is that, until now, signalling a monitor was a delayed operation.
1729The ownership of the monitor is transferred only when the monitor would have otherwise been released, not at the point of the @signal@ statement.
1730However, in some cases, it may be more convenient for users to immediately transfer ownership to the thread that is waiting for cooperation, which is achieved using the @signal_block@ routine.
1731
1732The example in table \ref{tbl:datingservice} highlights the difference in behaviour.
1733As mentioned, @signal@ only transfers ownership once the current critical section exits; this behaviour requires additional synchronization when a two-way handshake is needed.
1734To avoid this explicit synchronization, the @condition@ type offers the @signal_block@ routine, which handles the two-way handshake as shown in the example.
1735This feature removes the need for a second condition variables and simplifies programming.
1736Like every other monitor semantic, @signal_block@ uses barging prevention, which means mutual-exclusion is baton-passed both on the front end and the back end of the call to @signal_block@, meaning no other thread can acquire the monitor either before or after the call.
1737
1738% ======================================================================
1739% ======================================================================
1740\section{External scheduling} \label{extsched}
1741% ======================================================================
1742% ======================================================================
1743An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}).
1744\begin{table}
1745\begin{tabular}{|c|c|c|}
1746Internal Scheduling & External Scheduling & Go\\
1747\hline
1748\begin{uC++}[tabsize=3]
1749_Monitor Semaphore {
1750        condition c;
1751        bool inUse;
1752public:
1753        void P() {
1754                if(inUse)
1755                        wait(c);
1756                inUse = true;
1757        }
1758        void V() {
1759                inUse = false;
1760                signal(c);
1761        }
1762}
1763\end{uC++}&\begin{uC++}[tabsize=3]
1764_Monitor Semaphore {
1765
1766        bool inUse;
1767public:
1768        void P() {
1769                if(inUse)
1770                        _Accept(V);
1771                inUse = true;
1772        }
1773        void V() {
1774                inUse = false;
1775
1776        }
1777}
1778\end{uC++}&\begin{Go}[tabsize=3]
1779type MySem struct {
1780        inUse bool
1781        c     chan bool
1782}
1783
1784// acquire
1785func (s MySem) P() {
1786        if s.inUse {
1787                select {
1788                case <-s.c:
1789                }
1790        }
1791        s.inUse = true
1792}
1793
1794// release
1795func (s MySem) V() {
1796        s.inUse = false
1797
1798        // This actually deadlocks
1799        // when single thread
1800        s.c <- false
1801}
1802\end{Go}
1803\end{tabular}
1804\caption{Different forms of scheduling.}
1805\label{tbl:sched}
1806\end{table}
1807This method is more constrained and explicit, which helps users reduce the non-deterministic nature of concurrency.
1808Indeed, as the following examples demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occurring.
1809External scheduling can generally be done either in terms of control flow (e.g., Ada with @accept@, \uC with @_Accept@) or in terms of data (e.g., Go with channels).
1810Of course, both of these paradigms have their own strengths and weaknesses, but for this project, control-flow semantics was chosen to stay consistent with the rest of the languages semantics.
1811Two challenges specific to \CFA arise when trying to add external scheduling with loose object definitions and multiple-monitor routines.
1812The previous example shows a simple use @_Accept@ versus @wait@/@signal@ and its advantages.
1813Note that while other languages often use @accept@/@select@ as the core external scheduling keyword, \CFA uses @waitfor@ to prevent name collisions with existing socket \textbf{api}s.
1814
1815For the @P@ member above using internal scheduling, the call to @wait@ only guarantees that @V@ is the last routine to access the monitor, allowing a third routine, say @isInUse()@, acquire mutual exclusion several times while routine @P@ is waiting.
1816On the other hand, external scheduling guarantees that while routine @P@ is waiting, no other routine than @V@ can acquire the monitor.
1817
1818% ======================================================================
1819% ======================================================================
1820\subsection{Loose Object Definitions}
1821% ======================================================================
1822% ======================================================================
1823In \uC, a monitor class declaration includes an exhaustive list of monitor operations.
1824Since \CFA is not object oriented, monitors become both more difficult to implement and less clear for a user:
1825
1826\begin{cfa}
1827monitor A {};
1828
1829void f(A & mutex a);
1830void g(A & mutex a) {
1831        waitfor(f); // Obvious which f() to wait for
1832}
1833
1834void f(A & mutex a, int); // New different F added in scope
1835void h(A & mutex a) {
1836        waitfor(f); // Less obvious which f() to wait for
1837}
1838\end{cfa}
1839
1840Furthermore, external scheduling is an example where implementation constraints become visible from the interface.
1841Here is the cfa-code for the entering phase of a monitor:
1842\begin{center}
1843\begin{tabular}{l}
1844\begin{cfa}
1845        if monitor is free
1846                enter
1847        elif already own the monitor
1848                continue
1849        elif monitor accepts me
1850                enter
1851        else
1852                block
1853\end{cfa}
1854\end{tabular}
1855\end{center}
1856For the first two conditions, it is easy to implement a check that can evaluate the condition in a few instructions.
1857However, a fast check for @monitor accepts me@ is much harder to implement depending on the constraints put on the monitors.
1858Indeed, monitors are often expressed as an entry queue and some acceptor queue as in Figure~\ref{fig:ClassicalMonitor}.
1859
1860\begin{figure}
1861\centering
1862\subfloat[Classical Monitor] {
1863\label{fig:ClassicalMonitor}
1864{\resizebox{0.45\textwidth}{!}{\input{monitor}}}
1865}% subfloat
1866\qquad
1867\subfloat[\textbf{bulk-acq} Monitor] {
1868\label{fig:BulkMonitor}
1869{\resizebox{0.45\textwidth}{!}{\input{ext_monitor}}}
1870}% subfloat
1871\caption{External Scheduling Monitor}
1872\end{figure}
1873
1874There are other alternatives to these pictures, but in the case of the left picture, implementing a fast accept check is relatively easy.
1875Restricted to a fixed number of mutex members, N, the accept check reduces to updating a bitmask when the acceptor queue changes, a check that executes in a single instruction even with a fairly large number (e.g., 128) of mutex members.
1876This approach requires a unique dense ordering of routines with an upper-bound and that ordering must be consistent across translation units.
1877For OO languages these constraints are common, since objects only offer adding member routines consistently across translation units via inheritance.
1878However, in \CFA users can extend objects with mutex routines that are only visible in certain translation unit.
1879This means that establishing a program-wide dense-ordering among mutex routines can only be done in the program linking phase, and still could have issues when using dynamically shared objects.
1880
1881The alternative is to alter the implementation as in Figure~\ref{fig:BulkMonitor}.
1882Here, the mutex routine called is associated with a thread on the entry queue while a list of acceptable routines is kept separate.
1883Generating a mask dynamically means that the storage for the mask information can vary between calls to @waitfor@, allowing for more flexibility and extensions.
1884Storing an array of accepted function pointers replaces the single instruction bitmask comparison with dereferencing a pointer followed by a linear search.
1885Furthermore, supporting nested external scheduling (e.g., listing \ref{lst:nest-ext}) may now require additional searches for the @waitfor@ statement to check if a routine is already queued.
1886
1887\begin{figure}
1888\begin{cfa}[caption={Example of nested external scheduling},label={lst:nest-ext}]
1889monitor M {};
1890void foo( M & mutex a ) {}
1891void bar( M & mutex b ) {
1892        // Nested in the waitfor(bar, c) call
1893        waitfor(foo, b);
1894}
1895void baz( M & mutex c ) {
1896        waitfor(bar, c);
1897}
1898
1899\end{cfa}
1900\end{figure}
1901
1902Note that in the right picture, tasks need to always keep track of the monitors associated with mutex routines, and the routine mask needs to have both a function pointer and a set of monitors, as is discussed in the next section.
1903These details are omitted from the picture for the sake of simplicity.
1904
1905At this point, a decision must be made between flexibility and performance.
1906Many design decisions in \CFA achieve both flexibility and performance, for example polymorphic routines add significant flexibility but inlining them means the optimizer can easily remove any runtime cost.
1907Here, however, the cost of flexibility cannot be trivially removed.
1908In the end, the most flexible approach has been chosen since it allows users to write programs that would otherwise be  hard to write.
1909This decision is based on the assumption that writing fast but inflexible locks is closer to a solved problem than writing locks that are as flexible as external scheduling in \CFA.
1910
1911% ======================================================================
1912% ======================================================================
1913\subsection{Multi-Monitor Scheduling}
1914% ======================================================================
1915% ======================================================================
1916
1917External scheduling, like internal scheduling, becomes significantly more complex when introducing multi-monitor syntax.
1918Even in the simplest possible case, some new semantics needs to be established:
1919\begin{cfa}
1920monitor M {};
1921
1922void f(M & mutex a);
1923
1924void g(M & mutex b, M & mutex c) {
1925        waitfor(f); // two monitors M => unknown which to pass to f(M & mutex)
1926}
1927\end{cfa}
1928The obvious solution is to specify the correct monitor as follows:
1929
1930\begin{cfa}
1931monitor M {};
1932
1933void f(M & mutex a);
1934
1935void g(M & mutex a, M & mutex b) {
1936        // wait for call to f with argument b
1937        waitfor(f, b);
1938}
1939\end{cfa}
1940This syntax is unambiguous.
1941Both locks are acquired and kept by @g@.
1942When routine @f@ is called, the lock for monitor @b@ is temporarily transferred from @g@ to @f@ (while @g@ still holds lock @a@).
1943This behaviour can be extended to the multi-monitor @waitfor@ statement as follows.
1944
1945\begin{cfa}
1946monitor M {};
1947
1948void f(M & mutex a, M & mutex b);
1949
1950void g(M & mutex a, M & mutex b) {
1951        // wait for call to f with arguments a and b
1952        waitfor(f, a, b);
1953}
1954\end{cfa}
1955
1956Note that the set of monitors passed to the @waitfor@ statement must be entirely contained in the set of monitors already acquired in the routine. @waitfor@ used in any other context is undefined behaviour.
1957
1958An important behaviour to note is when a set of monitors only match partially:
1959
1960\begin{cfa}
1961mutex struct A {};
1962
1963mutex struct B {};
1964
1965void g(A & mutex a, B & mutex b) {
1966        waitfor(f, a, b);
1967}
1968
1969A a1, a2;
1970B b;
1971
1972void foo() {
1973        g(a1, b); // block on accept
1974}
1975
1976void bar() {
1977        f(a2, b); // fulfill cooperation
1978}
1979\end{cfa}
1980While the equivalent can happen when using internal scheduling, the fact that conditions are specific to a set of monitors means that users have to use two different condition variables.
1981In both cases, partially matching monitor sets does not wakeup the waiting thread.
1982It is also important to note that in the case of external scheduling the order of parameters is irrelevant; @waitfor(f,a,b)@ and @waitfor(f,b,a)@ are indistinguishable waiting condition.
1983
1984% ======================================================================
1985% ======================================================================
1986\subsection{\protect\lstinline|waitfor| Semantics}
1987% ======================================================================
1988% ======================================================================
1989
1990Syntactically, the @waitfor@ statement takes a function identifier and a set of monitors.
1991While the set of monitors can be any list of expressions, the function name is more restricted because the compiler validates at compile time the validity of the function type and the parameters used with the @waitfor@ statement.
1992It checks that the set of monitors passed in matches the requirements for a function call.
1993Listing \ref{lst:waitfor} shows various usages of the waitfor statement and which are acceptable.
1994The choice of the function type is made ignoring any non-@mutex@ parameter.
1995One limitation of the current implementation is that it does not handle overloading, but overloading is possible.
1996\begin{figure}
1997\begin{cfa}[caption={Various correct and incorrect uses of the waitfor statement},label={lst:waitfor}]
1998monitor A{};
1999monitor B{};
2000
2001void f1( A & mutex );
2002void f2( A & mutex, B & mutex );
2003void f3( A & mutex, int );
2004void f4( A & mutex, int );
2005void f4( A & mutex, double );
2006
2007void foo( A & mutex a1, A & mutex a2, B & mutex b1, B & b2 ) {
2008        A * ap = & a1;
2009        void (*fp)( A & mutex ) = f1;
2010
2011        waitfor(f1, a1);     // Correct : 1 monitor case
2012        waitfor(f2, a1, b1); // Correct : 2 monitor case
2013        waitfor(f3, a1);     // Correct : non-mutex arguments are ignored
2014        waitfor(f1, *ap);    // Correct : expression as argument
2015
2016        waitfor(f1, a1, b1); // Incorrect : Too many mutex arguments
2017        waitfor(f2, a1);     // Incorrect : Too few mutex arguments
2018        waitfor(f2, a1, a2); // Incorrect : Mutex arguments don't match
2019        waitfor(f1, 1);      // Incorrect : 1 not a mutex argument
2020        waitfor(f9, a1);     // Incorrect : f9 function does not exist
2021        waitfor(*fp, a1 );   // Incorrect : fp not an identifier
2022        waitfor(f4, a1);     // Incorrect : f4 ambiguous
2023
2024        waitfor(f2, a1, b2); // Undefined behaviour : b2 not mutex
2025}
2026\end{cfa}
2027\end{figure}
2028
2029Finally, for added flexibility, \CFA supports constructing a complex @waitfor@ statement using the @or@, @timeout@ and @else@.
2030Indeed, multiple @waitfor@ clauses can be chained together using @or@; this chain forms a single statement that uses baton pass to any function that fits one of the function+monitor set passed in.
2031To enable users to tell which accepted function executed, @waitfor@s are followed by a statement (including the null statement @;@) or a compound statement, which is executed after the clause is triggered.
2032A @waitfor@ chain can also be followed by a @timeout@, to signify an upper bound on the wait, or an @else@, to signify that the call should be non-blocking, which checks for a matching function call already arrived and otherwise continues.
2033Any and all of these clauses can be preceded by a @when@ condition to dynamically toggle the accept clauses on or off based on some current state.
2034Listing \ref{lst:waitfor2} demonstrates several complex masks and some incorrect ones.
2035
2036\begin{figure}
2037\lstset{language=CFA,deletedelim=**[is][]{`}{`}}
2038\begin{cfa}
2039monitor A{};
2040
2041void f1( A & mutex );
2042void f2( A & mutex );
2043
2044void foo( A & mutex a, bool b, int t ) {
2045        waitfor(f1, a);                                                 $\C{// Correct : blocking case}$
2046
2047        waitfor(f1, a) {                                                $\C{// Correct : block with statement}$
2048                sout | "f1" | endl;
2049        }
2050        waitfor(f1, a) {                                                $\C{// Correct : block waiting for f1 or f2}$
2051                sout | "f1" | endl;
2052        } or waitfor(f2, a) {
2053                sout | "f2" | endl;
2054        }
2055        waitfor(f1, a); or else;                                $\C{// Correct : non-blocking case}$
2056
2057        waitfor(f1, a) {                                                $\C{// Correct : non-blocking case}$
2058                sout | "blocked" | endl;
2059        } or else {
2060                sout | "didn't block" | endl;
2061        }
2062        waitfor(f1, a) {                                                $\C{// Correct : block at most 10 seconds}$
2063                sout | "blocked" | endl;
2064        } or timeout( 10`s) {
2065                sout | "didn't block" | endl;
2066        }
2067        // Correct : block only if b == true if b == false, don't even make the call
2068        when(b) waitfor(f1, a);
2069
2070        // Correct : block only if b == true if b == false, make non-blocking call
2071        waitfor(f1, a); or when(!b) else;
2072
2073        // Correct : block only of t > 1
2074        waitfor(f1, a); or when(t > 1) timeout(t); or else;
2075
2076        // Incorrect : timeout clause is dead code
2077        waitfor(f1, a); or timeout(t); or else;
2078
2079        // Incorrect : order must be waitfor [or waitfor... [or timeout] [or else]]
2080        timeout(t); or waitfor(f1, a); or else;
2081}
2082\end{cfa}
2083\caption{Correct and incorrect uses of the or, else, and timeout clause around a waitfor statement}
2084\label{lst:waitfor2}
2085\end{figure}
2086
2087% ======================================================================
2088% ======================================================================
2089\subsection{Waiting For The Destructor}
2090% ======================================================================
2091% ======================================================================
2092An interesting use for the @waitfor@ statement is destructor semantics.
2093Indeed, the @waitfor@ statement can accept any @mutex@ routine, which includes the destructor (see section \ref{data}).
2094However, with the semantics discussed until now, waiting for the destructor does not make any sense, since using an object after its destructor is called is undefined behaviour.
2095The simplest approach is to disallow @waitfor@ on a destructor.
2096However, a more expressive approach is to flip ordering of execution when waiting for the destructor, meaning that waiting for the destructor allows the destructor to run after the current @mutex@ routine, similarly to how a condition is signalled.
2097\begin{figure}
2098\begin{cfa}[caption={Example of an executor which executes action in series until the destructor is called.},label={lst:dtor-order}]
2099monitor Executer {};
2100struct  Action;
2101
2102void ^?{}   (Executer & mutex this);
2103void execute(Executer & mutex this, const Action & );
2104void run    (Executer & mutex this) {
2105        while(true) {
2106                   waitfor(execute, this);
2107                or waitfor(^?{}   , this) {
2108                        break;
2109                }
2110        }
2111}
2112\end{cfa}
2113\end{figure}
2114For example, listing \ref{lst:dtor-order} shows an example of an executor with an infinite loop, which waits for the destructor to break out of this loop.
2115Switching the semantic meaning introduces an idiomatic way to terminate a task and/or wait for its termination via destruction.
2116
2117
2118% ######     #    ######     #    #       #       ####### #       ###  #####  #     #
2119% #     #   # #   #     #   # #   #       #       #       #        #  #     # ##   ##
2120% #     #  #   #  #     #  #   #  #       #       #       #        #  #       # # # #
2121% ######  #     # ######  #     # #       #       #####   #        #   #####  #  #  #
2122% #       ####### #   #   ####### #       #       #       #        #        # #     #
2123% #       #     # #    #  #     # #       #       #       #        #  #     # #     #
2124% #       #     # #     # #     # ####### ####### ####### ####### ###  #####  #     #
2125\section{Parallelism}
2126Historically, computer performance was about processor speeds and instruction counts.
2127However, with heat dissipation being a direct consequence of speed increase, parallelism has become the new source for increased performance~\cite{Sutter05, Sutter05b}.
2128In this decade, it is no longer reasonable to create a high-performance application without caring about parallelism.
2129Indeed, parallelism is an important aspect of performance and more specifically throughput and hardware utilization.
2130The lowest-level approach of parallelism is to use \textbf{kthread} in combination with semantics like @fork@, @join@, etc.
2131However, since these have significant costs and limitations, \textbf{kthread} are now mostly used as an implementation tool rather than a user oriented one.
2132There are several alternatives to solve these issues that all have strengths and weaknesses.
2133While there are many variations of the presented paradigms, most of these variations do not actually change the guarantees or the semantics, they simply move costs in order to achieve better performance for certain workloads.
2134
2135\section{Paradigms}
2136\subsection{User-Level Threads}
2137A direct improvement on the \textbf{kthread} approach is to use \textbf{uthread}.
2138These threads offer most of the same features that the operating system already provides but can be used on a much larger scale.
2139This approach is the most powerful solution as it allows all the features of multithreading, while removing several of the more expensive costs of kernel threads.
2140The downside is that almost none of the low-level threading problems are hidden; users still have to think about data races, deadlocks and synchronization issues.
2141These issues can be somewhat alleviated by a concurrency toolkit with strong guarantees, but the parallelism toolkit offers very little to reduce complexity in itself.
2142
2143Examples of languages that support \textbf{uthread} are Erlang~\cite{Erlang} and \uC~\cite{uC++book}.
2144
2145\subsection{Fibers : User-Level Threads Without Preemption} \label{fibers}
2146A popular variant of \textbf{uthread} is what is often referred to as \textbf{fiber}.
2147However, \textbf{fiber} do not present meaningful semantic differences with \textbf{uthread}.
2148The significant difference between \textbf{uthread} and \textbf{fiber} is the lack of \textbf{preemption} in the latter.
2149Advocates of \textbf{fiber} list their high performance and ease of implementation as major strengths, but the performance difference between \textbf{uthread} and \textbf{fiber} is controversial, and the ease of implementation, while true, is a weak argument in the context of language design.
2150Therefore this proposal largely ignores fibers.
2151
2152An example of a language that uses fibers is Go~\cite{Go}
2153
2154\subsection{Jobs and Thread Pools}
2155An approach on the opposite end of the spectrum is to base parallelism on \textbf{pool}.
2156Indeed, \textbf{pool} offer limited flexibility but at the benefit of a simpler user interface.
2157In \textbf{pool} based systems, users express parallelism as units of work, called jobs, and a dependency graph (either explicit or implicit) that ties them together.
2158This approach means users need not worry about concurrency but significantly limit the interaction that can occur among jobs.
2159Indeed, any \textbf{job} that blocks also block the underlying worker, which effectively means the CPU utilization, and therefore throughput, suffers noticeably.
2160It can be argued that a solution to this problem is to use more workers than available cores.
2161However, unless the number of jobs and the number of workers are comparable, having a significant number of blocked jobs always results in idles cores.
2162
2163The gold standard of this implementation is Intel's TBB library~\cite{TBB}.
2164
2165\subsection{Paradigm Performance}
2166While the choice between the three paradigms listed above may have significant performance implications, it is difficult to pin down the performance implications of choosing a model at the language level.
2167Indeed, in many situations one of these paradigms may show better performance but it all strongly depends on the workload.
2168Having a large amount of mostly independent units of work to execute almost guarantees equivalent performance across paradigms and that the \textbf{pool}-based system has the best efficiency thanks to the lower memory overhead (i.e., no thread stack per job).
2169However, interactions among jobs can easily exacerbate contention.
2170User-level threads allow fine-grain context switching, which results in better resource utilization, but a context switch is more expensive and the extra control means users need to tweak more variables to get the desired performance.
2171Finally, if the units of uninterrupted work are large, enough the paradigm choice is largely amortized by the actual work done.
2172
2173\section{The \protect\CFA\ Kernel : Processors, Clusters and Threads}\label{kernel}
2174A \textbf{cfacluster} is a group of \textbf{kthread} executed in isolation. \textbf{uthread} are scheduled on the \textbf{kthread} of a given \textbf{cfacluster}, allowing organization between \textbf{uthread} and \textbf{kthread}.
2175It is important that \textbf{kthread} belonging to a same \textbf{cfacluster} have homogeneous settings, otherwise migrating a \textbf{uthread} from one \textbf{kthread} to the other can cause issues.
2176A \textbf{cfacluster} also offers a pluggable scheduler that can optimize the workload generated by the \textbf{uthread}.
2177
2178\textbf{cfacluster} have not been fully implemented in the context of this paper.
2179Currently \CFA only supports one \textbf{cfacluster}, the initial one.
2180
2181\subsection{Future Work: Machine Setup}\label{machine}
2182While this was not done in the context of this paper, another important aspect of clusters is affinity.
2183While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heterogeneous setups.
2184For example, a system using \textbf{numa} configurations may benefit from users being able to tie clusters and/or kernel threads to certain CPU cores.
2185OS support for CPU affinity is now common~\cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx}, which means it is both possible and desirable for \CFA to offer an abstraction mechanism for portable CPU affinity.
2186
2187\subsection{Paradigms}\label{cfaparadigms}
2188Given these building blocks, it is possible to reproduce all three of the popular paradigms.
2189Indeed, \textbf{uthread} is the default paradigm in \CFA.
2190However, disabling \textbf{preemption} on the \textbf{cfacluster} means \textbf{cfathread} effectively become \textbf{fiber}.
2191Since several \textbf{cfacluster} with different scheduling policy can coexist in the same application, this allows \textbf{fiber} and \textbf{uthread} to coexist in the runtime of an application.
2192Finally, it is possible to build executors for thread pools from \textbf{uthread} or \textbf{fiber}, which includes specialized jobs like actors~\cite{Actors}.
2193
2194
2195
2196\section{Behind the Scenes}
2197There are several challenges specific to \CFA when implementing concurrency.
2198These challenges are a direct result of \textbf{bulk-acq} and loose object definitions.
2199These two constraints are the root cause of most design decisions in the implementation.
2200Furthermore, to avoid contention from dynamically allocating memory in a concurrent environment, the internal-scheduling design is (almost) entirely free of mallocs.
2201This approach avoids the chicken and egg problem~\cite{Chicken} of having a memory allocator that relies on the threading system and a threading system that relies on the runtime.
2202This extra goal means that memory management is a constant concern in the design of the system.
2203
2204The main memory concern for concurrency is queues.
2205All blocking operations are made by parking threads onto queues and all queues are designed with intrusive nodes, where each node has pre-allocated link fields for chaining, to avoid the need for memory allocation.
2206Since several concurrency operations can use an unbound amount of memory (depending on \textbf{bulk-acq}), statically defining information in the intrusive fields of threads is insufficient.The only way to use a variable amount of memory without requiring memory allocation is to pre-allocate large buffers of memory eagerly and store the information in these buffers.
2207Conveniently, the call stack fits that description and is easy to use, which is why it is used heavily in the implementation of internal scheduling, particularly variable-length arrays.
2208Since stack allocation is based on scopes, the first step of the implementation is to identify the scopes that are available to store the information, and which of these can have a variable-length array.
2209The threads and the condition both have a fixed amount of memory, while @mutex@ routines and blocking calls allow for an unbound amount, within the stack size.
2210
2211Note that since the major contributions of this paper are extending monitor semantics to \textbf{bulk-acq} and loose object definitions, any challenges that are not resulting of these characteristics of \CFA are considered as solved problems and therefore not discussed.
2212
2213% ======================================================================
2214% ======================================================================
2215\section{Mutex Routines}
2216% ======================================================================
2217% ======================================================================
2218
2219The first step towards the monitor implementation is simple @mutex@ routines.
2220In the single monitor case, mutual-exclusion is done using the entry/exit procedure in listing \ref{lst:entry1}.
2221The entry/exit procedures do not have to be extended to support multiple monitors.
2222Indeed it is sufficient to enter/leave monitors one-by-one as long as the order is correct to prevent deadlock~\cite{Havender68}.
2223In \CFA, ordering of monitor acquisition relies on memory ordering.
2224This approach is sufficient because all objects are guaranteed to have distinct non-overlapping memory layouts and mutual-exclusion for a monitor is only defined for its lifetime, meaning that destroying a monitor while it is acquired is undefined behaviour.
2225When a mutex call is made, the concerned monitors are aggregated into a variable-length pointer array and sorted based on pointer values.
2226This array persists for the entire duration of the mutual-exclusion and its ordering reused extensively.
2227\begin{figure}
2228\begin{multicols}{2}
2229Entry
2230\begin{cfa}
2231if monitor is free
2232        enter
2233elif already own the monitor
2234        continue
2235else
2236        block
2237increment recursions
2238\end{cfa}
2239\columnbreak
2240Exit
2241\begin{cfa}
2242decrement recursion
2243if recursion == 0
2244        if entry queue not empty
2245                wake-up thread
2246\end{cfa}
2247\end{multicols}
2248\begin{cfa}[caption={Initial entry and exit routine for monitors},label={lst:entry1}]
2249\end{cfa}
2250\end{figure}
2251
2252\subsection{Details: Interaction with polymorphism}
2253Depending on the choice of semantics for when monitor locks are acquired, interaction between monitors and \CFA's concept of polymorphism can be more complex to support.
2254However, it is shown that entry-point locking solves most of the issues.
2255
2256First of all, interaction between @otype@ polymorphism (see Section~\ref{s:ParametricPolymorphism}) and monitors is impossible since monitors do not support copying.
2257Therefore, the main question is how to support @dtype@ polymorphism.
2258It is important to present the difference between the two acquiring options: \textbf{callsite-locking} and entry-point locking, i.e., acquiring the monitors before making a mutex routine-call or as the first operation of the mutex routine-call.
2259For example:
2260\begin{table}
2261\begin{center}
2262\begin{tabular}{|c|c|c|}
2263Mutex & \textbf{callsite-locking} & \textbf{entry-point-locking} \\
2264call & cfa-code & cfa-code \\
2265\hline
2266\begin{cfa}[tabsize=3]
2267void foo(monitor& mutex a){
2268
2269        // Do Work
2270        //...
2271
2272}
2273
2274void main() {
2275        monitor a;
2276
2277        foo(a);
2278
2279}
2280\end{cfa} & \begin{cfa}[tabsize=3]
2281foo(& a) {
2282
2283        // Do Work
2284        //...
2285
2286}
2287
2288main() {
2289        monitor a;
2290        acquire(a);
2291        foo(a);
2292        release(a);
2293}
2294\end{cfa} & \begin{cfa}[tabsize=3]
2295foo(& a) {
2296        acquire(a);
2297        // Do Work
2298        //...
2299        release(a);
2300}
2301
2302main() {
2303        monitor a;
2304
2305        foo(a);
2306
2307}
2308\end{cfa}
2309\end{tabular}
2310\end{center}
2311\caption{Call-site vs entry-point locking for mutex calls}
2312\label{tbl:locking-site}
2313\end{table}
2314
2315Note the @mutex@ keyword relies on the type system, which means that in cases where a generic monitor-routine is desired, writing the mutex routine is possible with the proper trait, e.g.:
2316\begin{cfa}
2317// Incorrect: T may not be monitor
2318forall(dtype T)
2319void foo(T * mutex t);
2320
2321// Correct: this function only works on monitors (any monitor)
2322forall(dtype T | is_monitor(T))
2323void bar(T * mutex t));
2324\end{cfa}
2325
2326Both entry point and \textbf{callsite-locking} are feasible implementations.
2327The current \CFA implementation uses entry-point locking because it requires less work when using \textbf{raii}, effectively transferring the burden of implementation to object construction/destruction.
2328It is harder to use \textbf{raii} for call-site locking, as it does not necessarily have an existing scope that matches exactly the scope of the mutual exclusion, i.e., the function body.
2329For example, the monitor call can appear in the middle of an expression.
2330Furthermore, entry-point locking requires less code generation since any useful routine is called multiple times but there is only one entry point for many call sites.
2331
2332% ======================================================================
2333% ======================================================================
2334\section{Threading} \label{impl:thread}
2335% ======================================================================
2336% ======================================================================
2337
2338Figure \ref{fig:system1} shows a high-level picture if the \CFA runtime system in regards to concurrency.
2339Each component of the picture is explained in detail in the flowing sections.
2340
2341\begin{figure}
2342\begin{center}
2343{\resizebox{\textwidth}{!}{\input{system.pstex_t}}}
2344\end{center}
2345\caption{Overview of the entire system}
2346\label{fig:system1}
2347\end{figure}
2348
2349\subsection{Processors}
2350Parallelism in \CFA is built around using processors to specify how much parallelism is desired. \CFA processors are object wrappers around kernel threads, specifically @pthread@s in the current implementation of \CFA.
2351Indeed, any parallelism must go through operating-system libraries.
2352However, \textbf{uthread} are still the main source of concurrency, processors are simply the underlying source of parallelism.
2353Indeed, processor \textbf{kthread} simply fetch a \textbf{uthread} from the scheduler and run it; they are effectively executers for user-threads.
2354The main benefit of this approach is that it offers a well-defined boundary between kernel code and user code, for example, kernel thread quiescing, scheduling and interrupt handling.
2355Processors internally use coroutines to take advantage of the existing context-switching semantics.
2356
2357\subsection{Stack Management}
2358One of the challenges of this system is to reduce the footprint as much as possible.
2359Specifically, all @pthread@s created also have a stack created with them, which should be used as much as possible.
2360Normally, coroutines also create their own stack to run on, however, in the case of the coroutines used for processors, these coroutines run directly on the \textbf{kthread} stack, effectively stealing the processor stack.
2361The exception to this rule is the Main Processor, i.e., the initial \textbf{kthread} that is given to any program.
2362In order to respect C user expectations, the stack of the initial kernel thread, the main stack of the program, is used by the main user thread rather than the main processor, which can grow very large.
2363
2364\subsection{Context Switching}
2365As mentioned in section \ref{coroutine}, coroutines are a stepping stone for implementing threading, because they share the same mechanism for context-switching between different stacks.
2366To improve performance and simplicity, context-switching is implemented using the following assumption: all context-switches happen inside a specific function call.
2367This assumption means that the context-switch only has to copy the callee-saved registers onto the stack and then switch the stack registers with the ones of the target coroutine/thread.
2368Note that the instruction pointer can be left untouched since the context-switch is always inside the same function.
2369Threads, however, do not context-switch between each other directly.
2370They context-switch to the scheduler.
2371This method is called a 2-step context-switch and has the advantage of having a clear distinction between user code and the kernel where scheduling and other system operations happen.
2372Obviously, this doubles the context-switch cost because threads must context-switch to an intermediate stack.
2373The alternative 1-step context-switch uses the stack of the ``from'' thread to schedule and then context-switches directly to the ``to'' thread.
2374However, the performance of the 2-step context-switch is still superior to a @pthread_yield@ (see section \ref{results}).
2375Additionally, for users in need for optimal performance, it is important to note that having a 2-step context-switch as the default does not prevent \CFA from offering a 1-step context-switch (akin to the Microsoft @SwitchToFiber@~\cite{switchToWindows} routine).
2376This option is not currently present in \CFA, but the changes required to add it are strictly additive.
2377
2378\subsection{Preemption} \label{preemption}
2379Finally, an important aspect for any complete threading system is preemption.
2380As mentioned in section \ref{basics}, preemption introduces an extra degree of uncertainty, which enables users to have multiple threads interleave transparently, rather than having to cooperate among threads for proper scheduling and CPU distribution.
2381Indeed, preemption is desirable because it adds a degree of isolation among threads.
2382In a fully cooperative system, any thread that runs a long loop can starve other threads, while in a preemptive system, starvation can still occur but it does not rely on every thread having to yield or block on a regular basis, which reduces significantly a programmer burden.
2383Obviously, preemption is not optimal for every workload.
2384However any preemptive system can become a cooperative system by making the time slices extremely large.
2385Therefore, \CFA uses a preemptive threading system.
2386
2387Preemption in \CFA\footnote{Note that the implementation of preemption is strongly tied with the underlying threading system.
2388For this reason, only the Linux implementation is cover, \CFA does not run on Windows at the time of writting} is based on kernel timers, which are used to run a discrete-event simulation.
2389Every processor keeps track of the current time and registers an expiration time with the preemption system.
2390When the preemption system receives a change in preemption, it inserts the time in a sorted order and sets a kernel timer for the closest one, effectively stepping through preemption events on each signal sent by the timer.
2391These timers use the Linux signal {\tt SIGALRM}, which is delivered to the process rather than the kernel-thread.
2392This results in an implementation problem, because when delivering signals to a process, the kernel can deliver the signal to any kernel thread for which the signal is not blocked, i.e.:
2393\begin{quote}
2394A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked.
2395If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
2396SIGNAL(7) - Linux Programmer's Manual
2397\end{quote}
2398For the sake of simplicity, and in order to prevent the case of having two threads receiving alarms simultaneously, \CFA programs block the {\tt SIGALRM} signal on every kernel thread except one.
2399
2400Now because of how involuntary context-switches are handled, the kernel thread handling {\tt SIGALRM} cannot also be a processor thread.
2401Hence, involuntary context-switching is done by sending signal {\tt SIGUSR1} to the corresponding proces\-sor and having the thread yield from inside the signal handler.
2402This approach effectively context-switches away from the signal handler back to the kernel and the signal handler frame is eventually unwound when the thread is scheduled again.
2403As a result, a signal handler can start on one kernel thread and terminate on a second kernel thread (but the same user thread).
2404It is important to note that signal handlers save and restore signal masks because user-thread migration can cause a signal mask to migrate from one kernel thread to another.
2405This behaviour is only a problem if all kernel threads, among which a user thread can migrate, differ in terms of signal masks\footnote{Sadly, official POSIX documentation is silent on what distinguishes ``async-signal-safe'' functions from other functions.}.
2406However, since the kernel thread handling preemption requires a different signal mask, executing user threads on the kernel-alarm thread can cause deadlocks.
2407For this reason, the alarm thread is in a tight loop around a system call to @sigwaitinfo@, requiring very little CPU time for preemption.
2408One final detail about the alarm thread is how to wake it when additional communication is required (e.g., on thread termination).
2409This unblocking is also done using {\tt SIGALRM}, but sent through the @pthread_sigqueue@.
2410Indeed, @sigwait@ can differentiate signals sent from @pthread_sigqueue@ from signals sent from alarms or the kernel.
2411
2412\subsection{Scheduler}
2413Finally, an aspect that was not mentioned yet is the scheduling algorithm.
2414Currently, the \CFA scheduler uses a single ready queue for all processors, which is the simplest approach to scheduling.
2415Further discussion on scheduling is present in section \ref{futur:sched}.
2416
2417% ======================================================================
2418% ======================================================================
2419\section{Internal Scheduling} \label{impl:intsched}
2420% ======================================================================
2421% ======================================================================
2422The following figure is the traditional illustration of a monitor (repeated from page~\pageref{fig:ClassicalMonitor} for convenience):
2423
2424\begin{figure}
2425\begin{center}
2426{\resizebox{0.4\textwidth}{!}{\input{monitor}}}
2427\end{center}
2428\caption{Traditional illustration of a monitor}
2429\end{figure}
2430
2431This picture has several components, the two most important being the entry queue and the AS-stack.
2432The entry queue is an (almost) FIFO list where threads waiting to enter are parked, while the acceptor/signaller (AS) stack is a FILO list used for threads that have been signalled or otherwise marked as running next.
2433
2434For \CFA, this picture does not have support for blocking multiple monitors on a single condition.
2435To support \textbf{bulk-acq} two changes to this picture are required.
2436First, it is no longer helpful to attach the condition to \emph{a single} monitor.
2437Secondly, the thread waiting on the condition has to be separated across multiple monitors, seen in figure \ref{fig:monitor_cfa}.
2438
2439\begin{figure}
2440\begin{center}
2441{\resizebox{0.8\textwidth}{!}{\input{int_monitor}}}
2442\end{center}
2443\caption{Illustration of \CFA Monitor}
2444\label{fig:monitor_cfa}
2445\end{figure}
2446
2447This picture and the proper entry and leave algorithms (see listing \ref{lst:entry2}) is the fundamental implementation of internal scheduling.
2448Note that when a thread is moved from the condition to the AS-stack, it is conceptually split into N pieces, where N is the number of monitors specified in the parameter list.
2449The thread is woken up when all the pieces have popped from the AS-stacks and made active.
2450In this picture, the threads are split into halves but this is only because there are two monitors.
2451For a specific signalling operation every monitor needs a piece of thread on its AS-stack.
2452
2453\begin{figure}
2454\begin{multicols}{2}
2455Entry
2456\begin{cfa}
2457if monitor is free
2458        enter
2459elif already own the monitor
2460        continue
2461else
2462        block
2463increment recursion
2464
2465\end{cfa}
2466\columnbreak
2467Exit
2468\begin{cfa}
2469decrement recursion
2470if recursion == 0
2471        if signal_stack not empty
2472                set_owner to thread
2473                if all monitors ready
2474                        wake-up thread
2475
2476        if entry queue not empty
2477                wake-up thread
2478\end{cfa}
2479\end{multicols}
2480\begin{cfa}[caption={Entry and exit routine for monitors with internal scheduling},label={lst:entry2}]
2481\end{cfa}
2482\end{figure}
2483
2484The solution discussed in \ref{intsched} can be seen in the exit routine of listing \ref{lst:entry2}.
2485Basically, the solution boils down to having a separate data structure for the condition queue and the AS-stack, and unconditionally transferring ownership of the monitors but only unblocking the thread when the last monitor has transferred ownership.
2486This solution is deadlock safe as well as preventing any potential barging.
2487The data structures used for the AS-stack are reused extensively for external scheduling, but in the case of internal scheduling, the data is allocated using variable-length arrays on the call stack of the @wait@ and @signal_block@ routines.
2488
2489\begin{figure}
2490\begin{center}
2491{\resizebox{0.8\textwidth}{!}{\input{monitor_structs.pstex_t}}}
2492\end{center}
2493\caption{Data structures involved in internal/external scheduling}
2494\label{fig:structs}
2495\end{figure}
2496
2497Figure \ref{fig:structs} shows a high-level representation of these data structures.
2498The main idea behind them is that, a thread cannot contain an arbitrary number of intrusive ``next'' pointers for linking onto monitors.
2499The @condition node@ is the data structure that is queued onto a condition variable and, when signalled, the condition queue is popped and each @condition criterion@ is moved to the AS-stack.
2500Once all the criteria have been popped from their respective AS-stacks, the thread is woken up, which is what is shown in listing \ref{lst:entry2}.
2501
2502% ======================================================================
2503% ======================================================================
2504\section{External Scheduling}
2505% ======================================================================
2506% ======================================================================
2507Similarly to internal scheduling, external scheduling for multiple monitors relies on the idea that waiting-thread queues are no longer specific to a single monitor, as mentioned in section \ref{extsched}.
2508For internal scheduling, these queues are part of condition variables, which are still unique for a given scheduling operation (i.e., no signal statement uses multiple conditions).
2509However, in the case of external scheduling, there is no equivalent object which is associated with @waitfor@ statements.
2510This absence means the queues holding the waiting threads must be stored inside at least one of the monitors that is acquired.
2511These monitors being the only objects that have sufficient lifetime and are available on both sides of the @waitfor@ statement.
2512This requires an algorithm to choose which monitor holds the relevant queue.
2513It is also important that said algorithm be independent of the order in which users list parameters.
2514The proposed algorithm is to fall back on monitor lock ordering (sorting by address) and specify that the monitor that is acquired first is the one with the relevant waiting queue.
2515This assumes that the lock acquiring order is static for the lifetime of all concerned objects but that is a reasonable constraint.
2516
2517This algorithm choice has two consequences:
2518\begin{itemize}
2519        \item The queue of the monitor with the lowest address is no longer a true FIFO queue because threads can be moved to the front of the queue.
2520These queues need to contain a set of monitors for each of the waiting threads.
2521Therefore, another thread whose set contains the same lowest address monitor but different lower priority monitors may arrive first but enter the critical section after a thread with the correct pairing.
2522        \item The queue of the lowest priority monitor is both required and potentially unused.
2523Indeed, since it is not known at compile time which monitor is the monitor which has the lowest address, every monitor needs to have the correct queues even though it is possible that some queues go unused for the entire duration of the program, for example if a monitor is only used in a specific pair.
2524\end{itemize}
2525Therefore, the following modifications need to be made to support external scheduling:
2526\begin{itemize}
2527        \item The threads waiting on the entry queue need to keep track of which routine they are trying to enter, and using which set of monitors.
2528The @mutex@ routine already has all the required information on its stack, so the thread only needs to keep a pointer to that information.
2529        \item The monitors need to keep a mask of acceptable routines.
2530This mask contains for each acceptable routine, a routine pointer and an array of monitors to go with it.
2531It also needs storage to keep track of which routine was accepted.
2532Since this information is not specific to any monitor, the monitors actually contain a pointer to an integer on the stack of the waiting thread.
2533Note that if a thread has acquired two monitors but executes a @waitfor@ with only one monitor as a parameter, setting the mask of acceptable routines to both monitors will not cause any problems since the extra monitor will not change ownership regardless.
2534This becomes relevant when @when@ clauses affect the number of monitors passed to a @waitfor@ statement.
2535        \item The entry/exit routines need to be updated as shown in listing \ref{lst:entry3}.
2536\end{itemize}
2537
2538\subsection{External Scheduling - Destructors}
2539Finally, to support the ordering inversion of destructors, the code generation needs to be modified to use a special entry routine.
2540This routine is needed because of the storage requirements of the call order inversion.
2541Indeed, when waiting for the destructors, storage is needed for the waiting context and the lifetime of said storage needs to outlive the waiting operation it is needed for.
2542For regular @waitfor@ statements, the call stack of the routine itself matches this requirement but it is no longer the case when waiting for the destructor since it is pushed on to the AS-stack for later.
2543The @waitfor@ semantics can then be adjusted correspondingly, as seen in listing \ref{lst:entry-dtor}
2544
2545\begin{figure}
2546\begin{multicols}{2}
2547Entry
2548\begin{cfa}
2549if monitor is free
2550        enter
2551elif already own the monitor
2552        continue
2553elif matches waitfor mask
2554        push criteria to AS-stack
2555        continue
2556else
2557        block
2558increment recursion
2559\end{cfa}
2560\columnbreak
2561Exit
2562\begin{cfa}
2563decrement recursion
2564if recursion == 0
2565        if signal_stack not empty
2566                set_owner to thread
2567                if all monitors ready
2568                        wake-up thread
2569                endif
2570        endif
2571
2572        if entry queue not empty
2573                wake-up thread
2574        endif
2575\end{cfa}
2576\end{multicols}
2577\begin{cfa}[caption={Entry and exit routine for monitors with internal scheduling and external scheduling},label={lst:entry3}]
2578\end{cfa}
2579\end{figure}
2580
2581\begin{figure}
2582\begin{multicols}{2}
2583Destructor Entry
2584\begin{cfa}
2585if monitor is free
2586        enter
2587elif already own the monitor
2588        increment recursion
2589        return
2590create wait context
2591if matches waitfor mask
2592        reset mask
2593        push self to AS-stack
2594        baton pass
2595else
2596        wait
2597increment recursion
2598\end{cfa}
2599\columnbreak
2600Waitfor
2601\begin{cfa}
2602if matching thread is already there
2603        if found destructor
2604                push destructor to AS-stack
2605                unlock all monitors
2606        else
2607                push self to AS-stack
2608                baton pass
2609        endif
2610        return
2611endif
2612if non-blocking
2613        Unlock all monitors
2614        Return
2615endif
2616
2617push self to AS-stack
2618set waitfor mask
2619block
2620return
2621\end{cfa}
2622\end{multicols}
2623\begin{cfa}[caption={Pseudo code for the \protect\lstinline|waitfor| routine and the \protect\lstinline|mutex| entry routine for destructors},label={lst:entry-dtor}]
2624\end{cfa}
2625\end{figure}
2626
2627
2628% ======================================================================
2629% ======================================================================
2630\section{Putting It All Together}
2631% ======================================================================
2632% ======================================================================
2633
2634
2635\section{Threads As Monitors}
2636As it was subtly alluded in section \ref{threads}, @thread@s in \CFA are in fact monitors, which means that all monitor features are available when using threads.
2637For example, here is a very simple two thread pipeline that could be used for a simulator of a game engine:
2638\begin{figure}
2639\begin{cfa}[caption={Toy simulator using \protect\lstinline|thread|s and \protect\lstinline|monitor|s.},label={lst:engine-v1}]
2640// Visualization declaration
2641thread Renderer {} renderer;
2642Frame * simulate( Simulator & this );
2643
2644// Simulation declaration
2645thread Simulator{} simulator;
2646void render( Renderer & this );
2647
2648// Blocking call used as communication
2649void draw( Renderer & mutex this, Frame * frame );
2650
2651// Simulation loop
2652void main( Simulator & this ) {
2653        while( true ) {
2654                Frame * frame = simulate( this );
2655                draw( renderer, frame );
2656        }
2657}
2658
2659// Rendering loop
2660void main( Renderer & this ) {
2661        while( true ) {
2662                waitfor( draw, this );
2663                render( this );
2664        }
2665}
2666\end{cfa}
2667\end{figure}
2668One of the obvious complaints of the previous code snippet (other than its toy-like simplicity) is that it does not handle exit conditions and just goes on forever.
2669Luckily, the monitor semantics can also be used to clearly enforce a shutdown order in a concise manner:
2670\begin{figure}
2671\begin{cfa}[caption={Same toy simulator with proper termination condition.},label={lst:engine-v2}]
2672// Visualization declaration
2673thread Renderer {} renderer;
2674Frame * simulate( Simulator & this );
2675
2676// Simulation declaration
2677thread Simulator{} simulator;
2678void render( Renderer & this );
2679
2680// Blocking call used as communication
2681void draw( Renderer & mutex this, Frame * frame );
2682
2683// Simulation loop
2684void main( Simulator & this ) {
2685        while( true ) {
2686                Frame * frame = simulate( this );
2687                draw( renderer, frame );
2688
2689                // Exit main loop after the last frame
2690                if( frame->is_last ) break;
2691        }
2692}
2693
2694// Rendering loop
2695void main( Renderer & this ) {
2696        while( true ) {
2697                   waitfor( draw, this );
2698                or waitfor( ^?{}, this ) {
2699                        // Add an exit condition
2700                        break;
2701                }
2702
2703                render( this );
2704        }
2705}
2706
2707// Call destructor for simulator once simulator finishes
2708// Call destructor for renderer to signify shutdown
2709\end{cfa}
2710\end{figure}
2711
2712\section{Fibers \& Threads}
2713As mentioned in section \ref{preemption}, \CFA uses preemptive threads by default but can use fibers on demand.
2714Currently, using fibers is done by adding the following line of code to the program~:
2715\begin{cfa}
2716unsigned int default_preemption() {
2717        return 0;
2718}
2719\end{cfa}
2720This function is called by the kernel to fetch the default preemption rate, where 0 signifies an infinite time-slice, i.e., no preemption.
2721However, once clusters are fully implemented, it will be possible to create fibers and \textbf{uthread} in the same system, as in listing \ref{lst:fiber-uthread}
2722\begin{figure}
2723\lstset{language=CFA,deletedelim=**[is][]{`}{`}}
2724\begin{cfa}[caption={Using fibers and \textbf{uthread} side-by-side in \CFA},label={lst:fiber-uthread}]
2725// Cluster forward declaration
2726struct cluster;
2727
2728// Processor forward declaration
2729struct processor;
2730
2731// Construct clusters with a preemption rate
2732void ?{}(cluster& this, unsigned int rate);
2733// Construct processor and add it to cluster
2734void ?{}(processor& this, cluster& cluster);
2735// Construct thread and schedule it on cluster
2736void ?{}(thread& this, cluster& cluster);
2737
2738// Declare two clusters
2739cluster thread_cluster = { 10`ms };                     // Preempt every 10 ms
2740cluster fibers_cluster = { 0 };                         // Never preempt
2741
2742// Construct 4 processors
2743processor processors[4] = {
2744        //2 for the thread cluster
2745        thread_cluster;
2746        thread_cluster;
2747        //2 for the fibers cluster
2748        fibers_cluster;
2749        fibers_cluster;
2750};
2751
2752// Declares thread
2753thread UThread {};
2754void ?{}(UThread& this) {
2755        // Construct underlying thread to automatically
2756        // be scheduled on the thread cluster
2757        (this){ thread_cluster }
2758}
2759
2760void main(UThread & this);
2761
2762// Declares fibers
2763thread Fiber {};
2764void ?{}(Fiber& this) {
2765        // Construct underlying thread to automatically
2766        // be scheduled on the fiber cluster
2767        (this.__thread){ fibers_cluster }
2768}
2769
2770void main(Fiber & this);
2771\end{cfa}
2772\end{figure}
2773
2774
2775% ======================================================================
2776% ======================================================================
2777\section{Performance Results} \label{results}
2778% ======================================================================
2779% ======================================================================
2780\section{Machine Setup}
2781Table \ref{tab:machine} shows the characteristics of the machine used to run the benchmarks.
2782All tests were made on this machine.
2783\begin{table}
2784\begin{center}
2785\begin{tabular}{| l | r | l | r |}
2786\hline
2787Architecture            & x86\_64                       & NUMA node(s)  & 8 \\
2788\hline
2789CPU op-mode(s)          & 32-bit, 64-bit                & Model name    & AMD Opteron\texttrademark  Processor 6380 \\
2790\hline
2791Byte Order                      & Little Endian                 & CPU Freq              & 2.5\si{\giga\hertz} \\
2792\hline
2793CPU(s)                  & 64                            & L1d cache     & \SI{16}{\kibi\byte} \\
2794\hline
2795Thread(s) per core      & 2                             & L1i cache     & \SI{64}{\kibi\byte} \\
2796\hline
2797Core(s) per socket      & 8                             & L2 cache              & \SI{2048}{\kibi\byte} \\
2798\hline
2799Socket(s)                       & 4                             & L3 cache              & \SI{6144}{\kibi\byte} \\
2800\hline
2801\hline
2802Operating system                & Ubuntu 16.04.3 LTS    & Kernel                & Linux 4.4-97-generic \\
2803\hline
2804Compiler                        & GCC 6.3               & Translator    & CFA 1 \\
2805\hline
2806Java version            & OpenJDK-9             & Go version    & 1.9.2 \\
2807\hline
2808\end{tabular}
2809\end{center}
2810\caption{Machine setup used for the tests}
2811\label{tab:machine}
2812\end{table}
2813
2814\section{Micro Benchmarks}
2815All benchmarks are run using the same harness to produce the results, seen as the @BENCH()@ macro in the following examples.
2816This macro uses the following logic to benchmark the code:
2817\begin{cfa}
2818#define BENCH(run, result) \
2819        before = gettime(); \
2820        run; \
2821        after  = gettime(); \
2822        result = (after - before) / N;
2823\end{cfa}
2824The method used to get time is @clock_gettime(CLOCK_THREAD_CPUTIME_ID);@.
2825Each benchmark is using many iterations of a simple call to measure the cost of the call.
2826The specific number of iterations depends on the specific benchmark.
2827
2828\subsection{Context-Switching}
2829The first interesting benchmark is to measure how long context-switches take.
2830The simplest approach to do this is to yield on a thread, which executes a 2-step context switch.
2831Yielding causes the thread to context-switch to the scheduler and back, more precisely: from the \textbf{uthread} to the \textbf{kthread} then from the \textbf{kthread} back to the same \textbf{uthread} (or a different one in the general case).
2832In order to make the comparison fair, coroutines also execute a 2-step context-switch by resuming another coroutine which does nothing but suspending in a tight loop, which is a resume/suspend cycle instead of a yield.
2833Listing \ref{lst:ctx-switch} shows the code for coroutines and threads with the results in table \ref{tab:ctx-switch}.
2834All omitted tests are functionally identical to one of these tests.
2835The difference between coroutines and threads can be attributed to the cost of scheduling.
2836\begin{figure}
2837\begin{multicols}{2}
2838\CFA Coroutines
2839\begin{cfa}
2840coroutine GreatSuspender {};
2841void main(GreatSuspender& this) {
2842        while(true) { suspend(); }
2843}
2844int main() {
2845        GreatSuspender s;
2846        resume(s);
2847        BENCH(
2848                for(size_t i=0; i<n; i++) {
2849                        resume(s);
2850                },
2851                result
2852        )
2853        printf("%llu\n", result);
2854}
2855\end{cfa}
2856\columnbreak
2857\CFA Threads
2858\begin{cfa}
2859
2860
2861
2862
2863int main() {
2864
2865
2866        BENCH(
2867                for(size_t i=0; i<n; i++) {
2868                        yield();
2869                },
2870                result
2871        )
2872        printf("%llu\n", result);
2873}
2874\end{cfa}
2875\end{multicols}
2876\begin{cfa}[caption={\CFA benchmark code used to measure context-switches for coroutines and threads.},label={lst:ctx-switch}]
2877\end{cfa}
2878\end{figure}
2879
2880\begin{table}
2881\begin{center}
2882\begin{tabular}{| l | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] |}
2883\cline{2-4}
2884\multicolumn{1}{c |}{} & \multicolumn{1}{c |}{ Median } &\multicolumn{1}{c |}{ Average } & \multicolumn{1}{c |}{ Standard Deviation} \\
2885\hline
2886Kernel Thread   & 241.5 & 243.86        & 5.08 \\
2887\CFA Coroutine  & 38            & 38            & 0    \\
2888\CFA Thread             & 103           & 102.96        & 2.96 \\
2889\uC Coroutine   & 46            & 45.86 & 0.35 \\
2890\uC Thread              & 98            & 99.11 & 1.42 \\
2891Goroutine               & 150           & 149.96        & 3.16 \\
2892Java Thread             & 289           & 290.68        & 8.72 \\
2893\hline
2894\end{tabular}
2895\end{center}
2896\caption{Context Switch comparison.
2897All numbers are in nanoseconds(\si{\nano\second})}
2898\label{tab:ctx-switch}
2899\end{table}
2900
2901\subsection{Mutual-Exclusion}
2902The next interesting benchmark is to measure the overhead to enter/leave a critical-section.
2903For monitors, the simplest approach is to measure how long it takes to enter and leave a monitor routine.
2904Listing \ref{lst:mutex} shows the code for \CFA.
2905To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured.
2906The results can be shown in table \ref{tab:mutex}.
2907
2908\begin{figure}
2909\begin{cfa}[caption={\CFA benchmark code used to measure mutex routines.},label={lst:mutex}]
2910monitor M {};
2911void __attribute__((noinline)) call( M & mutex m /*, m2, m3, m4*/ ) {}
2912
2913int main() {
2914        M m/*, m2, m3, m4*/;
2915        BENCH(
2916                for(size_t i=0; i<n; i++) {
2917                        call(m/*, m2, m3, m4*/);
2918                },
2919                result
2920        )
2921        printf("%llu\n", result);
2922}
2923\end{cfa}
2924\end{figure}
2925
2926\begin{table}
2927\begin{center}
2928\begin{tabular}{| l | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] |}
2929\cline{2-4}
2930\multicolumn{1}{c |}{} & \multicolumn{1}{c |}{ Median } &\multicolumn{1}{c |}{ Average } & \multicolumn{1}{c |}{ Standard Deviation} \\
2931\hline
2932C routine                                               & 2             & 2             & 0    \\
2933FetchAdd + FetchSub                             & 26            & 26            & 0    \\
2934Pthreads Mutex Lock                             & 31            & 31.86 & 0.99 \\
2935\uC @monitor@ member routine            & 30            & 30            & 0    \\
2936\CFA @mutex@ routine, 1 argument        & 41            & 41.57 & 0.9  \\
2937\CFA @mutex@ routine, 2 argument        & 76            & 76.96 & 1.57 \\
2938\CFA @mutex@ routine, 4 argument        & 145           & 146.68        & 3.85 \\
2939Java synchronized routine                       & 27            & 28.57 & 2.6  \\
2940\hline
2941\end{tabular}
2942\end{center}
2943\caption{Mutex routine comparison.
2944All numbers are in nanoseconds(\si{\nano\second})}
2945\label{tab:mutex}
2946\end{table}
2947
2948\subsection{Internal Scheduling}
2949The internal-scheduling benchmark measures the cost of waiting on and signalling a condition variable.
2950Listing \ref{lst:int-sched} shows the code for \CFA, with results table \ref{tab:int-sched}.
2951As with all other benchmarks, all omitted tests are functionally identical to one of these tests.
2952
2953\begin{figure}
2954\begin{cfa}[caption={Benchmark code for internal scheduling},label={lst:int-sched}]
2955volatile int go = 0;
2956condition c;
2957monitor M {};
2958M m1;
2959
2960void __attribute__((noinline)) do_call( M & mutex a1 ) { signal(c); }
2961
2962thread T {};
2963void ^?{}( T & mutex this ) {}
2964void main( T & this ) {
2965        while(go == 0) { yield(); }
2966        while(go == 1) { do_call(m1); }
2967}
2968int  __attribute__((noinline)) do_wait( M & mutex a1 ) {
2969        go = 1;
2970        BENCH(
2971                for(size_t i=0; i<n; i++) {
2972                        wait(c);
2973                },
2974                result
2975        )
2976        printf("%llu\n", result);
2977        go = 0;
2978        return 0;
2979}
2980int main() {
2981        T t;
2982        return do_wait(m1);
2983}
2984\end{cfa}
2985\end{figure}
2986
2987\begin{table}
2988\begin{center}
2989\begin{tabular}{| l | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] |}
2990\cline{2-4}
2991\multicolumn{1}{c |}{} & \multicolumn{1}{c |}{ Median } &\multicolumn{1}{c |}{ Average } & \multicolumn{1}{c |}{ Standard Deviation} \\
2992\hline
2993Pthreads Condition Variable                     & 5902.5        & 6093.29       & 714.78 \\
2994\uC @signal@                                    & 322           & 323   & 3.36   \\
2995\CFA @signal@, 1 @monitor@      & 352.5 & 353.11        & 3.66   \\
2996\CFA @signal@, 2 @monitor@      & 430           & 430.29        & 8.97   \\
2997\CFA @signal@, 4 @monitor@      & 594.5 & 606.57        & 18.33  \\
2998Java @notify@                           & 13831.5       & 15698.21      & 4782.3 \\
2999\hline
3000\end{tabular}
3001\end{center}
3002\caption{Internal scheduling comparison.
3003All numbers are in nanoseconds(\si{\nano\second})}
3004\label{tab:int-sched}
3005\end{table}
3006
3007\subsection{External Scheduling}
3008The Internal scheduling benchmark measures the cost of the @waitfor@ statement (@_Accept@ in \uC).
3009Listing \ref{lst:ext-sched} shows the code for \CFA, with results in table \ref{tab:ext-sched}.
3010As with all other benchmarks, all omitted tests are functionally identical to one of these tests.
3011
3012\begin{figure}
3013\begin{cfa}[caption={Benchmark code for external scheduling},label={lst:ext-sched}]
3014volatile int go = 0;
3015monitor M {};
3016M m1;
3017thread T {};
3018
3019void __attribute__((noinline)) do_call( M & mutex a1 ) {}
3020
3021void ^?{}( T & mutex this ) {}
3022void main( T & this ) {
3023        while(go == 0) { yield(); }
3024        while(go == 1) { do_call(m1); }
3025}
3026int  __attribute__((noinline)) do_wait( M & mutex a1 ) {
3027        go = 1;
3028        BENCH(
3029                for(size_t i=0; i<n; i++) {
3030                        waitfor(call, a1);
3031                },
3032                result
3033        )
3034        printf("%llu\n", result);
3035        go = 0;
3036        return 0;
3037}
3038int main() {
3039        T t;
3040        return do_wait(m1);
3041}
3042\end{cfa}
3043\end{figure}
3044
3045\begin{table}
3046\begin{center}
3047\begin{tabular}{| l | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] |}
3048\cline{2-4}
3049\multicolumn{1}{c |}{} & \multicolumn{1}{c |}{ Median } &\multicolumn{1}{c |}{ Average } & \multicolumn{1}{c |}{ Standard Deviation} \\
3050\hline
3051\uC @Accept@                                    & 350           & 350.61        & 3.11  \\
3052\CFA @waitfor@, 1 @monitor@     & 358.5 & 358.36        & 3.82  \\
3053\CFA @waitfor@, 2 @monitor@     & 422           & 426.79        & 7.95  \\
3054\CFA @waitfor@, 4 @monitor@     & 579.5 & 585.46        & 11.25 \\
3055\hline
3056\end{tabular}
3057\end{center}
3058\caption{External scheduling comparison.
3059All numbers are in nanoseconds(\si{\nano\second})}
3060\label{tab:ext-sched}
3061\end{table}
3062
3063\subsection{Object Creation}
3064Finally, the last benchmark measures the cost of creation for concurrent objects.
3065Listing \ref{lst:creation} shows the code for @pthread@s and \CFA threads, with results shown in table \ref{tab:creation}.
3066As with all other benchmarks, all omitted tests are functionally identical to one of these tests.
3067The only note here is that the call stacks of \CFA coroutines are lazily created, therefore without priming the coroutine, the creation cost is very low.
3068
3069\begin{figure}
3070\begin{center}
3071@pthread@
3072\begin{cfa}
3073int main() {
3074        BENCH(
3075                for(size_t i=0; i<n; i++) {
3076                        pthread_t thread;
3077                        if(pthread_create(&thread,NULL,foo,NULL)<0) {
3078                                perror( "failure" );
3079                                return 1;
3080                        }
3081
3082                        if(pthread_join(thread, NULL)<0) {
3083                                perror( "failure" );
3084                                return 1;
3085                        }
3086                },
3087                result
3088        )
3089        printf("%llu\n", result);
3090}
3091\end{cfa}
3092
3093
3094
3095\CFA Threads
3096\begin{cfa}
3097int main() {
3098        BENCH(
3099                for(size_t i=0; i<n; i++) {
3100                        MyThread m;
3101                },
3102                result
3103        )
3104        printf("%llu\n", result);
3105}
3106\end{cfa}
3107\end{center}
3108\caption{Benchmark code for \protect\lstinline|pthread|s and \CFA to measure object creation}
3109\label{lst:creation}
3110\end{figure}
3111
3112\begin{table}
3113\begin{center}
3114\begin{tabular}{| l | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] | S[table-format=5.2,table-number-alignment=right] |}
3115\cline{2-4}
3116\multicolumn{1}{c |}{} & \multicolumn{1}{c |}{ Median } &\multicolumn{1}{c |}{ Average } & \multicolumn{1}{c |}{ Standard Deviation} \\
3117\hline
3118Pthreads                        & 26996 & 26984.71      & 156.6  \\
3119\CFA Coroutine Lazy     & 6             & 5.71  & 0.45   \\
3120\CFA Coroutine Eager    & 708           & 706.68        & 4.82   \\
3121\CFA Thread                     & 1173.5        & 1176.18       & 15.18  \\
3122\uC Coroutine           & 109           & 107.46        & 1.74   \\
3123\uC Thread                      & 526           & 530.89        & 9.73   \\
3124Goroutine                       & 2520.5        & 2530.93       & 61,56  \\
3125Java Thread                     & 91114.5       & 92272.79      & 961.58 \\
3126\hline
3127\end{tabular}
3128\end{center}
3129\caption{Creation comparison.
3130All numbers are in nanoseconds(\si{\nano\second}).}
3131\label{tab:creation}
3132\end{table}
3133
3134
3135
3136\section{Conclusion}
3137This paper has achieved a minimal concurrency \textbf{api} that is simple, efficient and usable as the basis for higher-level features.
3138The approach presented is based on a lightweight thread-system for parallelism, which sits on top of clusters of processors.
3139This M:N model is judged to be both more efficient and allow more flexibility for users.
3140Furthermore, this document introduces monitors as the main concurrency tool for users.
3141This paper also offers a novel approach allowing multiple monitors to be accessed simultaneously without running into the Nested Monitor Problem~\cite{Lister77}.
3142It also offers a full implementation of the concurrency runtime written entirely in \CFA, effectively the largest \CFA code base to date.
3143
3144
3145% ======================================================================
3146% ======================================================================
3147\section{Future Work}
3148% ======================================================================
3149% ======================================================================
3150
3151\subsection{Performance} \label{futur:perf}
3152This paper presents a first implementation of the \CFA concurrency runtime.
3153Therefore, there is still significant work to improve performance.
3154Many of the data structures and algorithms may change in the future to more efficient versions.
3155For example, the number of monitors in a single \textbf{bulk-acq} is only bound by the stack size, this is probably unnecessarily generous.
3156It may be possible that limiting the number helps increase performance.
3157However, it is not obvious that the benefit would be significant.
3158
3159\subsection{Flexible Scheduling} \label{futur:sched}
3160An important part of concurrency is scheduling.
3161Different scheduling algorithms can affect performance (both in terms of average and variation).
3162However, no single scheduler is optimal for all workloads and therefore there is value in being able to change the scheduler for given programs.
3163One solution is to offer various tweaking options to users, allowing the scheduler to be adjusted to the requirements of the workload.
3164However, in order to be truly flexible, it would be interesting to allow users to add arbitrary data and arbitrary scheduling algorithms.
3165For example, a web server could attach Type-of-Service information to threads and have a ``ToS aware'' scheduling algorithm tailored to this specific web server.
3166This path of flexible schedulers will be explored for \CFA.
3167
3168\subsection{Non-Blocking I/O} \label{futur:nbio}
3169While most of the parallelism tools are aimed at data parallelism and control-flow parallelism, many modern workloads are not bound on computation but on IO operations, a common case being web servers and XaaS (anything as a service).
3170These types of workloads often require significant engineering around amortizing costs of blocking IO operations.
3171At its core, non-blocking I/O is an operating system level feature that allows queuing IO operations (e.g., network operations) and registering for notifications instead of waiting for requests to complete.
3172In this context, the role of the language makes Non-Blocking IO easily available and with low overhead.
3173The current trend is to use asynchronous programming using tools like callbacks and/or futures and promises, which can be seen in frameworks like Node.js~\cite{NodeJs} for JavaScript, Spring MVC~\cite{SpringMVC} for Java and Django~\cite{Django} for Python.
3174However, while these are valid solutions, they lead to code that is harder to read and maintain because it is much less linear.
3175
3176\subsection{Other Concurrency Tools} \label{futur:tools}
3177While monitors offer a flexible and powerful concurrent core for \CFA, other concurrency tools are also necessary for a complete multi-paradigm concurrency package.
3178Examples of such tools can include simple locks and condition variables, futures and promises~\cite{promises}, executors and actors.
3179These additional features are useful when monitors offer a level of abstraction that is inadequate for certain tasks.
3180
3181\subsection{Implicit Threading} \label{futur:implcit}
3182Simpler applications can benefit greatly from having implicit parallelism.
3183That is, parallelism that does not rely on the user to write concurrency.
3184This type of parallelism can be achieved both at the language level and at the library level.
3185The canonical example of implicit parallelism is parallel for loops, which are the simplest example of a divide and conquer algorithms~\cite{uC++book}.
3186Table \ref{lst:parfor} shows three different code examples that accomplish point-wise sums of large arrays.
3187Note that none of these examples explicitly declare any concurrency or parallelism objects.
3188
3189\begin{table}
3190\begin{center}
3191\begin{tabular}[t]{|c|c|c|}
3192Sequential & Library Parallel & Language Parallel \\
3193\begin{cfa}[tabsize=3]
3194void big_sum(
3195        int* a, int* b,
3196        int* o,
3197        size_t len)
3198{
3199        for(
3200                int i = 0;
3201                i < len;
3202                ++i )
3203        {
3204                o[i]=a[i]+b[i];
3205        }
3206}
3207
3208
3209
3210
3211
3212int* a[10000];
3213int* b[10000];
3214int* c[10000];
3215//... fill in a & b
3216big_sum(a,b,c,10000);
3217\end{cfa} &\begin{cfa}[tabsize=3]
3218void big_sum(
3219        int* a, int* b,
3220        int* o,
3221        size_t len)
3222{
3223        range ar(a, a+len);
3224        range br(b, b+len);
3225        range or(o, o+len);
3226        parfor( ai, bi, oi,
3227        [](     int* ai,
3228                int* bi,
3229                int* oi)
3230        {
3231                oi=ai+bi;
3232        });
3233}
3234
3235
3236int* a[10000];
3237int* b[10000];
3238int* c[10000];
3239//... fill in a & b
3240big_sum(a,b,c,10000);
3241\end{cfa}&\begin{cfa}[tabsize=3]
3242void big_sum(
3243        int* a, int* b,
3244        int* o,
3245        size_t len)
3246{
3247        parfor (ai,bi,oi)
3248            in (a, b, o )
3249        {
3250                oi = ai + bi;
3251        }
3252}
3253
3254
3255
3256
3257
3258
3259
3260int* a[10000];
3261int* b[10000];
3262int* c[10000];
3263//... fill in a & b
3264big_sum(a,b,c,10000);
3265\end{cfa}
3266\end{tabular}
3267\end{center}
3268\caption{For loop to sum numbers: Sequential, using library parallelism and language parallelism.}
3269\label{lst:parfor}
3270\end{table}
3271
3272Implicit parallelism is a restrictive solution and therefore has its limitations.
3273However, it is a quick and simple approach to parallelism, which may very well be sufficient for smaller applications and reduces the amount of boilerplate needed to start benefiting from parallelism in modern CPUs.
3274
3275
3276% A C K N O W L E D G E M E N T S
3277% -------------------------------
3278\section{Acknowledgements}
3279
3280Thanks to Aaron Moss, Rob Schluntz and Andrew Beach for their work on the \CFA project as well as all the discussions which helped concretize the ideas in this paper.
3281Partial funding was supplied by the Natural Sciences and Engineering Research Council of Canada and a corporate partnership with Huawei Ltd.
3282
3283
3284% B I B L I O G R A P H Y
3285% -----------------------------
3286%\bibliographystyle{plain}
3287\bibliography{pl,local}
3288
3289\end{document}
3290
3291% Local Variables: %
3292% tab-width: 4 %
3293% fill-column: 120 %
3294% compile-command: "make" %
3295% End: %
Note: See TracBrowser for help on using the repository browser.