Changes in / [8d66610:5407cdc]


Ignore:
Files:
3 added
24 deleted
69 edited

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.tex

    r8d66610 r5407cdc  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sat May  8 08:48:37 2021
    14 %% Update Count     : 540
     13%% Last Modified On : Sun Feb 14 15:52:46 2021
     14%% Update Count     : 524
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    3838\usepackage{xspace}
    3939\newcommand{\CFAIcon}{\textsf{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}} % Cforall icon
    40 \newcommand{\CFA}{\protect\CFAIcon\xspace}                              % CFA symbolic name
    41 \newcommand{\CFL}{\textrm{Cforall}\xspace}                              % Cforall non-icon name
    42 \newcommand{\Celeven}{\textrm{C11}\xspace}                              % C11 symbolic name
     40\newcommand{\CFA}{\protect\CFAIcon\xspace}                      % CFA symbolic name
     41\newcommand{\CFL}{\textrm{Cforall}\xspace}                      % Cforall non-icon name
     42\newcommand{\Celeven}{\textrm{C11}\xspace}                      % C11 symbolic name
    4343\newcommand{\CCIcon}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}} % C++ icon
    44 \newcommand{\CC}[1][]{\protect\CCIcon{#1}\xspace}               % C++ symbolic name
     44\newcommand{\CC}{\protect\CCIcon\xspace}                        % C++ symbolic name
    4545% numbers disallowed in latex variables names => use number names
    46 \newcommand{\CCeleven}{\protect\CCIcon{11}\xspace}              % C++11 symbolic name
    47 \newcommand{\CCfourteen}{\protect\CCIcon{14}\xspace}    % C++14 symbolic name
    48 \newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace}   % C++17 symbolic name
    49 \newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace}              % C++20 symbolic name
     46\newcommand{\CCeleven}{\protect\CCIcon{11}\xspace}      % C++11 symbolic name
     47\newcommand{\CCfourteen}{\protect\CCIcon{14}\xspace} % C++14 symbolic name
     48\newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace} % C++17 symbolic name
     49\newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace}      % C++20 symbolic name
    5050\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name
    5151
     
    102102\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-2.5ex \@plus -1ex \@minus -.2ex}{1.0ex \@plus .2ex}{\normalfont\normalsize\bfseries}}
    103103\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}{-2.0ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries}}
    104 \renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
    105104
    106105% index macros
     
    153152% Latin abbreviation
    154153\newcommand{\abbrevFont}{\textit}                       % set empty for no italics
    155 % If not followed by a comma or colon, add a comma.
    156 \newcommand{\CheckCommaColon}{\@ifnextchar{,}{}{\@ifnextchar{:}{}{,\xspace}}}
    157 % If not followed by a period, add a period.
    158 \newcommand{\CheckPeriod}{\@ifnextchar{.}{}{.\xspace}}
    159 
    160154\@ifundefined{eg}{
    161155\newcommand{\EG}{\abbrevFont{e}.\abbrevFont{g}.}
    162 \newcommand{\eg}{\EG\CheckCommaColon}
    163 }{}%
     156\newcommand*{\eg}{%
     157        \@ifnextchar{,}{\EG}%
     158                {\@ifnextchar{:}{\EG}%
     159                        {\EG,\xspace}}%
     160}}{}%
    164161\@ifundefined{ie}{
    165162\newcommand{\IE}{\abbrevFont{i}.\abbrevFont{e}.}
    166 \newcommand{\ie}{\IE\CheckCommaColon}
    167 }{}%
     163\newcommand*{\ie}{%
     164        \@ifnextchar{,}{\IE}%
     165                {\@ifnextchar{:}{\IE}%
     166                        {\IE,\xspace}}%
     167}}{}%
    168168\@ifundefined{etc}{
    169169\newcommand{\ETC}{\abbrevFont{etc}}
    170 \newcommand{\etc}{\ETC\CheckPeriod}
    171 }{}%
     170\newcommand*{\etc}{%
     171        \@ifnextchar{.}{\ETC}%
     172        {\ETC.\xspace}%
     173}}{}%
    172174\@ifundefined{etal}{
    173175\newcommand{\ETAL}{\abbrevFont{et}~\abbrevFont{al}}
    174 \newcommand{\etal}{\ETAL\CheckPeriod}
    175 }{}%
     176\newcommand*{\etal}{%
     177        \@ifnextchar{.}{\protect\ETAL}%
     178                {\protect\ETAL.\xspace}%
     179}}{}%
    176180\@ifundefined{viz}{
    177181\newcommand{\VIZ}{\abbrevFont{viz}}
    178 \newcommand{\viz}{\VIZ\CheckPeriod}
    179 }{}%
     182\newcommand*{\viz}{%
     183        \@ifnextchar{.}{\VIZ}%
     184                {\VIZ.\xspace}%
     185}}{}%
    180186\makeatother
    181187
     
    278284showlines=true,                                                 % show blank lines at end of code
    279285aboveskip=4pt,                                                  % spacing above/below code block
    280 belowskip=2pt,
     286belowskip=0pt,
    281287numberstyle=\footnotesize\sf,                   % numbering style
    282288% replace/adjust listing characters that look bad in sanserif
     
    291297\lstset{
    292298language=CFA,
    293 %moredelim=**[is][\color{red}]{@}{@},   % red highlighting @...@
    294 moredelim=**[is][\color{red}]{®}{®},    % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
     299moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     300%moredelim=**[is][\color{red}]{®}{®},   % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
    295301%moredelim=**[is][\color{blue}]{ß}{ß},  % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
    296302%moredelim=**[is][\color{OliveGreen}]{¢}{¢}, % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"
  • doc/theses/andrew_beach_MMath/Makefile

    r8d66610 r5407cdc  
    3434        ${LATEX} ${BASE}
    3535        ${BIBTEX} ${BUILD}/${BASE}
     36        ${LATEX} ${BASE}
    3637        ${GLOSSARY} ${BUILD}/${BASE}
    3738        ${LATEX} ${BASE}
  • doc/theses/andrew_beach_MMath/cfalab.sty

    r8d66610 r5407cdc  
    11% Package for CFA Research Lab.
    2 % (Now more a personal collection and testing grounds for common.sty.)
    32%
    4 % This is a collection of commands everyone working on CFA related documents
    5 % should find useful. So mostly programming language related tools.
     3% Made by combining and updating various macro files people had made.
    64%
    75% Internal commands are prefixed with "\cfalab@".
     
    1210
    1311% Other packages required.
    14 %
    15 % Access to new basic LaTeX tools and other low level commands.
    1612\RequirePackage{etoolbox}
    17 % Code formatting tools and environments.
    1813\RequirePackage{listings}
    19 % Automatically adds spaces.
    2014\RequirePackage{xspace}
    2115
    22 % Tip for commands that end with \xspace: if the default is not correct then
    23 % follow the command with {} to disable \xspace, use '{} ' to force add a
    24 % space and '{}<whatever-follows>' to force remove one.
    25 %
    26 % \CFA
     16% Symbols: All symbols are zero argument robust commands with special rules
     17% about the space following the c.s. token. Normally the space might be
     18% re-added according to the rules of the xspace package. They may be followed
     19% by a star (which the command will consume) to disable this behaviour.
     20
     21% \newsymbolcmd{<command>}{<replacement text>}
     22%     Defines <command> to be a symbol that has the given <replacement text>.
     23\newrobustcmd*\newsymbolcmd[2]{\newrobustcmd{#1}{\cfalab@symbol{#2}}}
     24\def\cfalab@symbol#1{\@ifnextchar*{#1\cfalab@eatstar}{#1\xspace}}
     25\def\cfalab@eatstar*{}
     26
    2727% Cforall with the forall symbol.
    28 \newrobustcmd\CFA{\textsf{C\raisebox{\depth}{\rotatebox{180}{A}}}\xspace}
    29 % \Cpp[<std>]
    30 % C++ symbol name. You may optionally provide <std> to specify a standard.
    31 \newrobustcmd\Cpp[1][\xspace]{C++#1}
     28\newsymbolcmd\CFA{\textsf{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}}
     29% C++ with kerning. (No standard number support.)
     30\newsymbolcmd\CPP{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}}
    3231
    33 % This is executed very early in the \begin{document} code, before the
    34 % document's contents but after packages are loaded.
     32% This is executed very early in the \begin{document} code.
    3533\AtEndPreamble{
    3634  \@ifpackageloaded{hyperref}{
     
    3836    \pdfstringdefDisableCommands{
    3937      \def\CFA{CFA}
    40       \def\Cpp{C++}
    41       \def\lstinline{}
    42       \def\code#1#2{#2}
     38      \def\CPP{C++}
    4339    }
    4440  }{}
    4541}
    46 
    47 % \colour{<colour>}{<text>}
    48 % Just \color but using the LaTeX style instead of TeX style command.
    49 \newcommand*\colour[2]{{\color{#1}#2}}
    50 
    51 % \code{<language>}{<code>}
    52 % Use the listings package to format the snipit of <code> in <language>.
    53 \newrobustcmd*\code[2]{\lstinline[language=#1]{#2}}
    54 
    55 % \begin{cfa}[<options>]
    56 % \end{cfa}
    57 % Use the listings package to format a block of CFA code.
    58 % Extra listings options can be passed in as an optional argument.
    59 \lstnewenvironment{cfa}[1][]{\lstset{language=CFA}\lstset{#1}}{}
    60 
    61 % \settextunderscore{(new|old)}
    62 % Redefines the underscore either as a new repersentation or the old one.
    63 % Not that some other packages (ex. hyperref) can override this. Set it up
    64 % after loading them.
    65 \let\cfalab@textunderscore@old=\textunderscore
    66 \newcommand\cfalab@textunderscore@new{%
    67     \leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
    68 \newcommand\settextunderscore[1]{%
    69     \renewcommand\textunderscore{\csuse{cfalab@textunderscore@#1}}}
    7042
    7143% The CFA listings language. Based off of ANCI C and including GCC extensions.
     
    8961\lstset{defaultdialect={[UW]CFA}}
    9062
    91 % Create an internal paragraph indent amount. This is used internally to
    92 % mimic the standard indent even when it has been overriden in the document.
    93 \newlength\cfalab@parindent
    94 \deflength\cfalab@parindent{\parindent}
    95 
    96 % The cfacommon style has many useful defaults for CFA and other types of
    97 % code. Use the listings option "style=cfacommon" to load them.
    98 \lstdefinestyle{cfacommon}{
    99   columns=fullflexible,
    100   basicstyle=\linespread{0.9}\sf,
    101   stringstyle=\tt,
    102   tabsize=5,
    103   % Indent code to paragraph indentation.
    104   xleftmargin=\cfalab@parindent,
    105   % Allow ASCII characters in the range 128-255.
    106   extendedchars=true,
    107   % This allows you to use "math mode" to insert LaTeX into the code.
    108   % Use \( and \) if you need to insert math mode inside that code.
    109   escapechar=\$,
    110   % Disable LaTeX math escape in CFA code $...$
    111   mathescape=false,
    112   keepspaces=true,
    113   % Do not show spaces with cup.
    114   showstringspaces=false,
    115   % Show blank lines at end of code.
    116   showlines=true,
    117   % Spacing above/below code block.
    118   aboveskip=4pt,belowskip=0pt,
    119   numberstyle=\footnotesize\sf,
    120   % Replace/adjust listing characters that look bad in sanserif.
    121   literate={-}{\makebox[1ex][c]{\raisebox{0.7ex}{\rule{0.75ex}{0.1ex}}}}1
    122     {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1
    123     {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    124     {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2
    125     {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2,
     63% The cfalab style defines some common settings useful in different languages.
     64\lstdefinestyle{cfalab}{%
     65    columns=fullflexible,
     66    basicstyle=\linespread{0.9}\tt,
     67    stringstyle=\tt,
    12668}
    12769
    128 % common.tex Compatablity ===================================================
    129 % Below this line is for compatability with the old common.tex file.
     70% \code*[<escape character>]{<code>}
     71%     Use the listings package to format a snipit of <code>.
     72%     The <escape character> must be a character that does not appear in
     73%     <code> and defaults to a backtick.
     74\newcommand*\codeC[2][\`]{\lstinline[language=C]#1#2#1}
     75\newcommand*\codeCFA[2][\`]{\lstinline[language=CFA]#1#2#1}
    13076
    131 % Backwards compatable way to activate the cfacommon style.
    132 \newcommand{\CFAStyle}{\lstset{style=cfacommon}}
    133 
    134 % A couple of abbreviations are provided. Just ones someone liked.
    135 %
    136 % Abbreviation formatting commands (renew to customize):
    137 \newcommand{\abbrevFont}{\textit}
    138 %
    139 % Abbreviations that, if not followed by a comma or colon, add a comma.
    140 \newrobustcmd*\cfalab@abbrev@comma{%
    141   \@ifnextchar{,}{}{\@ifnextchar{:}{}{,\xspace}}}
    142 \providerobustcmd*\eg{\abbrevFont{e}.\abbrevFont{g}.\cfalab@abbrev@comma}
    143 \providerobustcmd*\ie{\abbrevFont{i}.\abbrevFont{e}.\cfalab@abbrev@comma}
    144 %
    145 % Abbreviations that, if not followed by a period, add a period.
    146 \newrobustcmd*\cfalab@abbrev@period{\@ifnextchar{.}{}{.\xspace}}
    147 \providerobustcmd*\etc{\abbrevFont{etc}\cfalab@abbrev@period}
    148 \providerobustcmd*\etal{\abbrevFont{et}~\abbrevFont{al}\cfalab@abbrev@period}
    149 \providerobustcmd*\viz{\abbrevFont{viz}\cfalab@abbrev@period}
     77% \settextunderscore{(new|old)}
     78%     Redefines the underscore either as a new repersentation or the old one.
     79%     Not that some other packages (ex. hyperref) can override this. Set it
     80%     up after loading them.
     81\let\cfalab@textunderscore@old=\textunderscore
     82\newcommand\cfalab@textunderscore@new{%
     83    \leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}}
     84\newcommand\settextunderscore[1]{%
     85    \renewcommand\textunderscore{\csuse{cfalab@textunderscore@#1}}}
    15086
    15187\endinput
  • doc/theses/andrew_beach_MMath/existing.tex

    r8d66610 r5407cdc  
    1616to be defined~\cite{Moss18}.
    1717\begin{cfa}
    18 char i; int i; double i;
    19 int f(); double f();
    20 void g( int ); void g( double );
     18char i; int i; double i;                        $\C[3.75in]{// variable overload}$
     19int f(); double f();                            $\C{// return overload}$
     20void g( int ); void g( double );        $\C{// parameter overload}\CRT$
    2121\end{cfa}
    2222This feature requires name mangling so the assembly symbols are unique for
     
    2626mangling is:
    2727\begin{cfa}
    28 // name mangling on by default
     28// name mangling
    2929int i; // _X1ii_1
    30 extern "C" {  // disables name mangling
     30@extern "C"@ {  // no name mangling
    3131        int j; // j
    32         extern "Cforall" {  // enables name mangling
     32        @extern "Cforall"@ {  // name mangling
    3333                int k; // _X1ki_1
    3434        }
    35         // revert to no name mangling
    36 }
    37 // revert to name mangling
     35        // no name mangling
     36}
     37// name mangling
    3838\end{cfa}
    3939Both forms of @extern@ affect all the declarations within their nested lexical
     
    5050\begin{cfa}
    5151int i, j;
    52 int & ri = i, && rri = ri;
     52int @&@ ri = i, @&&@ rri = ri;
    5353rri = 3;  // auto-dereference assign to i
    54 &ri = &j; // rebindable
     54@&@ri = @&@j; // rebindable
    5555ri = 5;   // assign to j
    5656\end{cfa}
     
    6464
    6565In general, operator names in \CFA are constructed by bracketing an operator
    66 token with @?@, which indicates the position of the arguments. For example,
    67 infixed multiplication is @?*?@ while prefix dereference is @*?@.
    68 This syntax make it easy to tell the difference between prefix operations
    69 (such as @++?@) and post-fix operations (@?++@).
     66token with @?@, which indicates the position of the arguments. For example, infixed
     67multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it
     68easy to tell the difference between prefix operations (such as @++?@) and
     69post-fix operations (@?++@).
    7070
    7171The special name for a constructor is @?{}@, which comes from the
    72 initialization syntax in C. That initialation syntax is also the operator
    73 form. \CFA will generate a constructor call each time a variable is declared,
    74 passing the initialization arguments to the constructort.
    75 \begin{cfa}
    76 struct Example { ... };
    77 void ?{}(Example & this) { ... }
     72initialization syntax in C. The special name for a destructor is @^{}@, where
     73the @^@ has no special meaning.
     74% I don't like the \^{} symbol but $^\wedge$ isn't better.
     75\begin{cfa}
     76struct T { ... };
     77void ?@{}@(@T &@ this, ...) { ... }  // constructor
     78void ?@^{}@(@T &@ this, ...) { ... } // destructor
    7879{
    79         Example a;
    80         Example b = {};
    81 }
    82 void ?{}(Example & this, char first, int num) { ... }
    83 {
    84         Example c = {'a', 2};
    85 }
    86 \end{cfa}
    87 Both @a@ and @b@ will be initalized with the first constructor (there is no
    88 general way to skip initialation) while @c@ will be initalized with the
    89 second.
    90 
    91 % I don't like the \^{} symbol but $^\wedge$ isn't better.
    92 Similarly destructors use the special name @^?{}@ (the @^@ has no special
    93 meaning). They can be called explicatly as well but normally they are
    94 implicitly called on a variable when it goes out of scope.
    95 \begin{cfa}
    96 void ^?{}(Example & this) { ... }
    97 {
    98     Example d;
    99 } // <- implicit destructor call
    100 \end{cfa}
    101 No operator name is restricted in what function signatures they may be bound
    102 to although most of the forms cannot be called in operator form. Some
    103 ``near-misses" will generate warnings.
    104 
    105 Whenever a type is defined, \CFA will create a default zero-argument
    106 constructor, a copy constructor, a series of argument-per-field constructors
    107 and a destructor. All user constructors are defined after this.
    108 Because operators are never part of the type definition they may be added
    109 at any time, including on built-in types.
     80        T s = @{@ ... @}@;  // same constructor/initialization braces
     81} // destructor call automatically generated
     82\end{cfa}
     83The first parameter is a reference parameter to the type for the
     84constructor/destructor. Destructors may have multiple parameters.  The compiler
     85implicitly matches an overloaded constructor @void ^?{}(T &, ...);@ to an
     86object declaration with associated initialization, and generates a construction
     87call after the object is allocated. When an object goes out of scope, the
     88matching overloaded destructor @void ^?{}(T &);@ is called.  Without explicit
     89definition, \CFA creates a default and copy constructor, destructor and
     90assignment (like \Cpp). It is possible to define constructors/destructors for
     91basic and existing types (unlike \Cpp).
    11092
    11193\section{Polymorphism}
     
    123105works on any type @T@:
    124106\begin{cfa}
    125 forall( T ) T identity( T val ) { return val; }
    126 int forty_two = identity( 42 );
    127 char capital_a = identity( 'A' );
    128 \end{cfa}
    129 Each use of a polymorphic declaration will resolve its polymorphic parameters
    130 (in this case, just @T@) to concrete types (@int@ in the first use and @char@
    131 in the second).
     107@forall( T )@ @T@ identity( @T@ val ) { return val; }
     108int forty_two = identity( 42 ); // T bound to int, forty_two == 42
     109\end{cfa}
    132110
    133111To allow a polymorphic function to be separately compiled, the type @T@ must be
     
    137115types used in a function, \eg:
    138116\begin{cfa}
    139 forall( T | { void do_once(T); })
     117forall( T @| { void do_once(T); }@) // assertion
    140118void do_twice(T value) {
    141119        do_once(value);
    142120        do_once(value);
    143121}
    144 \end{cfa}
     122void do_once(@int@ i) { ... }  // provide assertion
     123@int@ i;
     124do_twice(i); // implicitly pass assertion do_once to do_twice
     125\end{cfa}
     126Any object with a type fulfilling the assertion may be passed as an argument to
     127a @do_twice@ call.
    145128
    146129A polymorphic function can be used in the same way as a normal function.  The
     
    149132all the variables replaced with the concrete types from the arguments) is
    150133defined at a call site.
    151 \begin{cfa}
    152 void do_once(int i) { ... }
    153 int i;
    154 do_twice(i);
    155 \end{cfa}
    156 Any object with a type fulfilling the assertion may be passed as an argument to
    157 a @do_twice@ call.
    158134
    159135Note, a function named @do_once@ is not required in the scope of @do_twice@ to
     
    162138call.
    163139\begin{cfa}
    164 void do_once(double y) { ... }
     140void do_once(double y) { ... } // global
    165141int quadruple(int x) {
    166         void do_once(int y) { y = y * 2; }
    167         do_twice(x);
     142        void do_once(int y) { y = y * 2; } // local
     143        do_twice(x); // using local "do_once"
    168144        return x;
    169145}
     
    174150function. The matched assertion function is then passed as a function pointer
    175151to @do_twice@ and called within it.
    176 The global definition of @do_once@ is ignored.
    177152
    178153To avoid typing long lists of assertions, constraints can be collect into
     
    186161and the @forall@ list in the previous example is replaced with the trait.
    187162\begin{cfa}
    188 forall(dtype T | done_once(T))
     163forall(dtype T | @done_once(T)@)
    189164\end{cfa}
    190165In general, a trait can contain an arbitrary number of assertions, both
     
    197172declarations instead of parameters, returns, and local variable declarations.
    198173\begin{cfa}
    199 forall(dtype T)
     174forall(dtype @T@)
    200175struct node {
    201         node(T) * next;  // generic linked node
    202         T * data;
    203 }
    204 node(int) inode;
    205 \end{cfa}
    206 The generic type @node(T)@ is an example of a polymorphic type usage.  Like \Cpp
    207 template usage, a polymorphic type usage must specify a type parameter.
     176        node(@T@) * next;  // generic linked node
     177        @T@ * data;
     178}
     179node(@int@) inode;
     180\end{cfa}
     181The generic type @node(T)@ is an example of a polymorphic-type usage.  Like \Cpp
     182template usage, a polymorphic-type usage must specify a type parameter.
    208183
    209184There are many other polymorphism features in \CFA but these are the ones used
     
    244219Each coroutine has a @main@ function, which takes a reference to a coroutine
    245220object and returns @void@.
    246 \begin{cfa}
    247 void main(CountUp & this) {
    248     for (unsigned int next = 0 ; true ; ++next) {
    249                 next = up;
    250                 suspend;$\label{suspend}$
     221\begin{cfa}[numbers=left]
     222void main(@CountUp & this@) { // argument matches trait is_coroutine
     223        unsigned int up = 0;  // retained between calls
     224        while (true) {
     225                next = up; // make "up" available outside function
     226                @suspend;@$\label{suspend}$
     227                up += 1;
    251228        }
    252229}
     
    277254@mutex@.
    278255\begin{cfa}
    279 void example(MonitorA & mutex argA, MonitorB & mutex argB);
     256void example(MonitorA & @mutex@ argA, MonitorB & @mutex@ argB);
    280257\end{cfa}
    281258When the function is called, it implicitly acquires the monitor lock for all of
  • doc/theses/andrew_beach_MMath/features.tex

    r8d66610 r5407cdc  
    2020\subparagraph{Raise}
    2121The raise is the starting point for exception handling. It marks the beginning
    22 of exception handling by raising an excepion, which passes it to
     22of exception handling by \newterm{raising} an excepion, which passes it to
    2323the EHM.
    2424
    2525Some well known examples include the @throw@ statements of \Cpp and Java and
    26 the \code{Python}{raise} statement from Python. In real systems a raise may
    27 preform some other work (such as memory management) but for the
    28 purposes of this overview that can be ignored.
     26the \codePy{raise} statement from Python. In real systems a raise may preform
     27some other work (such as memory management) but for the purposes of this
     28overview that can be ignored.
    2929
    3030\subparagraph{Handle}
     
    9393A handler labelled with any given exception can handle exceptions of that
    9494type or any child type of that exception. The root of the exception hierarchy
    95 (here \code{C}{exception}) acts as a catch-all, leaf types catch single types
     95(here \codeC{exception}) acts as a catch-all, leaf types catch single types
    9696and the exceptions in the middle can be used to catch different groups of
    9797related exceptions.
     
    101101between different sub-hierarchies.
    102102This design is used in \CFA even though it is not a object-orientated
    103 language; so different tools are used to create the hierarchy.
     103language using different tools to create the hierarchy.
    104104
    105105% Could I cite the rational for the Python IO exception rework?
     
    123123\section{Virtuals}
    124124Virtual types and casts are not part of \CFA's EHM nor are they required for
    125 any EHM.
    126 However the \CFA uses a hierarchy built with the virtual system as the basis
    127 for exceptions and exception matching.
    128 
    129 The virtual system would have ideally been part of \CFA before the work
    130 on exception handling began, but unfortunately it was not.
    131 Because of this only the features and framework needed for the EHM were
    132 designed and implemented. Other features were considered to ensure that
    133 the structure could accomidate other desirable features but they were not
    134 implemented.
    135 The rest of this section will only discuss the finalized portion of the
    136 virtual system.
     125any EHM. But \CFA uses a hierarchial system of exceptions and this feature
     126is leveraged to create that.
     127
     128% Maybe talk about why the virtual system is so minimal.
     129% Created for but not a part of the exception system.
    137130
    138131The virtual system supports multiple ``trees" of types. Each tree is
     
    150143It is important to note that these are virtual members, not virtual methods
    151144of object-orientated programming, and can be of any type.
    152 \CFA still supports virtual methods as a special case of virtual members.
    153 Function pointers that take a pointer to the virtual type will be modified
    154 with each level of inheritance so that refers to the new type.
    155 This means an object can always be passed to a function in its virtual table
    156 as if it were a method.
     145However, since \CFA has function pointers and they are allowed, virtual
     146members can be used to mimic virtual methods.
    157147
    158148Each virtual type has a unique id.
     
    185175While much of the virtual infrastructure is created, it is currently only used
    186176internally for exception handling. The only user-level feature is the virtual
    187 cast, which is the same as the \Cpp \code{C++}{dynamic_cast}.
     177cast, which is the same as the \Cpp \lstinline[language=C++]|dynamic_cast|.
    188178\label{p:VirtualCast}
    189179\begin{cfa}
     
    207197\begin{cfa}
    208198trait is_exception(exceptT &, virtualT &) {
    209         // Numerous imaginary assertions.
     199        virtualT const & get_exception_vtable(exceptT *);
    210200};
    211201\end{cfa}
    212202The trait is defined over two types, the exception type and the virtual table
    213 type. Each exception type should have but a single virtual table type.
    214 Now there are no actual assertions in this trait because the trait system
    215 actually can't express them (adding such assertions would be part of
    216 completing the virtual system). The imaginary assertions would probably come
    217 from a trait defined by the virtual system, and state that the exception type
    218 is a virtual type, is a decendent of @exception_t@ (the base exception type)
    219 and note its virtual table type.
     203type. This should be one-to-one: each exception type has only one virtual
     204table type and vice versa. The only assertion in the trait is
     205@get_exception_vtable@, which takes a pointer of the exception type and
     206returns a reference to the virtual table type instance.
     207
     208% TODO: This section, and all references to get_exception_vtable, are
     209% out-of-data. Perhaps wait until the update is finished before rewriting it.
     210The function @get_exception_vtable@ is actually a constant function.
     211Regardless of the value passed in (including the null pointer) it should
     212return a reference to the virtual table instance for that type.
     213The reason it is a function instead of a constant is that it make type
     214annotations easier to write as you can use the exception type instead of the
     215virtual table type; which usually has a mangled name.
     216% Also \CFA's trait system handles functions better than constants and doing
     217% it this way reduce the amount of boiler plate we need.
    220218
    221219% I did have a note about how it is the programmer's responsibility to make
     
    237235Both traits ensure a pair of types are an exception type and its virtual table
    238236and defines one of the two default handlers. The default handlers are used
    239 as fallbacks and are discussed in detail in \vref{s:ExceptionHandling}.
     237as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}.
    240238
    241239However, all three of these traits can be tricky to use directly.
     
    353351for particular exception type.
    354352The global default termination handler performs a cancellation
    355 (see \vref{s:Cancellation}) on the current stack with the copied exception.
     353\see{\VRef{s:Cancellation}} on the current stack with the copied exception.
    356354
    357355\subsection{Resumption}
     
    428426
    429427\subsubsection{Resumption Marking}
    430 \label{s:ResumptionMarking}
    431428A key difference between resumption and termination is that resumption does
    432429not unwind the stack. A side effect that is that when a handler is matched
     
    475472The symmetry between resumption termination is why this pattern was picked.
    476473Other patterns, such as marking just the handlers that caught, also work but
    477 lack the symmetry means there are more rules to remember.
     474lack the symmetry means there are less rules to remember.
    478475
    479476\section{Conditional Catch}
     
    560557\end{cfa}
    561558If there are further handlers after this handler only the first version will
    562 check them. If multiple handlers on a single try block that could handle the
    563 same exception the translations get more complex but they are equivilantly
     559check them. If multiple handlers on a single try block could handle the same
     560exception the translations get more complex but they are equivilantly
    564561powerful.
    565562
     
    636633and the current stack is
    637634unwound. After that it depends one which stack is being cancelled.
    638 
    639 \paragraph{Main Stack}
     635\begin{description}
     636\item[Main Stack:]
    640637The main stack is the one used by the program main at the start of execution,
    641638and is the only stack in a sequential program.
     
    648645to, so it would have be explicitly managed.
    649646
    650 \paragraph{Thread Stack}
     647\item[Thread Stack:]
    651648A thread stack is created for a \CFA @thread@ object or object that satisfies
    652649the @is_thread@ trait.
     
    674671Also you can always add an explicit join if that is the desired behaviour.
    675672
    676 \paragraph{Coroutine Stack}
     673\item[Coroutine Stack:]
    677674A coroutine stack is created for a @coroutine@ object or object that
    678675satisfies the @is_coroutine@ trait.
     
    688685(in terms of coroutine state) called resume on this coroutine, so the message
    689686is passed to the latter.
     687\end{description}
  • doc/theses/andrew_beach_MMath/future.tex

    r8d66610 r5407cdc  
    110110\section{Zero-Cost Try}
    111111\CFA does not have zero-cost try-statements because the compiler generates C
    112 code rather than assembler code (see \vpageref{p:zero-cost}). When the compiler
     112code rather than assembler code \see{\VPageref{p:zero-cost}}. When the compiler
    113113does create its own assembly (or LLVM byte-code), then zero-cost try-statements
    114114are possible. The downside of zero-cost try-statements is the LSDA complexity,
  • doc/theses/andrew_beach_MMath/implement.tex

    r8d66610 r5407cdc  
    99% Virtual table rules. Virtual tables, the pointer to them and the cast.
    1010While the \CFA virtual system currently has only one public feature, virtual
    11 cast (see the virtual cast feature \vpageref{p:VirtualCast}),
    12 substantial structure is required to support it,
    13 and provide features for exception handling and the standard library.
     11cast \see{\VPageref{p:VirtualCast}}, substantial structure is required to
     12support it, and provide features for exception handling and the standard
     13library.
    1414
    1515\subsection{Virtual Type}
    16 Virtual types only have one change to their structure: the addition of a
    17 pointer to the virtual table, which is called the \emph{virtual-table pointer}.
    18 Internally, the field is called @virtual_table@.
    19 The field is fixed after construction. It is always the first field in the
    20 structure so that its location is always known.
    21 \todo{Talk about constructors for virtual types (after they are working).}
    22 
    23 This is what binds an instance of a virtual type to a virtual table. This
    24 pointer can be used as an identity check. It can also be used to access the
    25 virtual table and the virtual members there.
    26 
    27 \subsection{Type Id}
    28 Every virtual type has a unique id.
    29 Type ids can be compared for equality (the types reperented are the same)
    30 or used to access the type's type information.
    31 The type information currently is only the parent's type id or, if the
    32 type has no parent, zero.
    33 
    34 The id's are implemented as pointers to the type's type information instance.
    35 Derefencing the pointer gets the type information.
    36 By going back-and-forth between the type id and
    37 the type info one can find every ancestor of a virtual type.
    38 It also pushes the issue of creating a unique value (for
    39 the type id) to the problem of creating a unique instance (for type
    40 information) which the linker can solve.
    41 
    42 Advanced linker support is required because there is no place that appears
    43 only once to attach the type information to. There should be one structure
    44 definition but it is included in multiple translation units. Each virtual
    45 table definition should be unique but there are an arbitrary number of thoses.
    46 So the special section prefix \texttt{.gnu.linkonce} is used.
    47 With a unique suffix (making the entire section name unique) the linker will
    48 remove multiple definition making sure only one version exists after linking.
    49 Then it is just a matter of making sure there is a unique name for each type.
    50 
    51 This is done in three phases.
    52 The first phase is to generate a new structure definition to store the type
    53 information. The layout is the same in each case, just the parent's type id,
    54 but the types are changed.
    55 The structure's name is change, it is based off the virtual type's name, and
    56 the type of the parent's type id.
    57 If the virtual type is polymorphic then the type information structure is
    58 polymorphic as well, with the same polymorphic arguments.
    59 
    60 The second phase is to generate an instance of the type information with a
    61 almost unique name, generated by mangling the virtual type name.
    62 
    63 The third phase is implicit with \CFA's overloading scheme. \CFA mangles
    64 names with type information so that all of the symbols exported to the linker
    65 are unique even if in \CFA code they are the same. Having two declarations
    66 with the same name and same type is forbidden because it is impossible for
    67 overload resolution to pick between them. This is why a unique type is
    68 generated for each virtual type.
    69 Polymorphic information is included in this mangling so polymorphic
    70 types will have seperate instances for each set of polymorphic arguments.
    71 
    72 \begin{cfa}
    73 struct TYPE_ID_TYPE {
    74         PARENT_ID_TYPE const * parent;
    75 };
    76 
    77 __attribute__((cfa_linkonce))
    78 TYPE_ID_TYPE const TYPE_ID_NAME = {
    79         &PARENT_ID_NAME,
    80 };
    81 \end{cfa}
    82 
    83 \subsubsection{cfa\_linkonce Attribute}
    84 Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}.
    85 This attribute can be put on an object or function definition
    86 (any global declaration with a name and a type).
    87 This allows you to define that object or function multiple times.
    88 All definitions should have the link-once attribute on them and all should
    89 be identical.
    90 
    91 The simplist way to use it is to put a definition in a header where the
    92 forward declaration would usually go.
    93 This is how it is used for type-id instances. There was is no unique location
    94 associated with a type except for the type definition which is in a header.
    95 This allows the unique type-id object to be generated there.
    96 
    97 Internally @cfa_linkonce@ removes all @section@ attributes
    98 from the declaration (as well as itself) and replaces them with
    99 @section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the
    100 mangled name of the object.
    101 The prefix \texttt{.gnu.linkonce} in section names is recognized by the
    102 linker. If two of these sections with the same name, including everything
    103 that comes after the special prefix, then only one will be used and the other
    104 will be discarded.
     16Virtual types only have one change to their structure, the addition of a
     17pointer to the virtual table. This is always the first field so that
     18if it is cast to a supertype the field's location is still known.
     19
     20This field is set as part of all new generated constructors.
     21\todo{They only come as part exceptions and don't work.}
     22After the object is created the field is constant.
     23
     24However it can be read from, internally it is just a regular field called
     25@virtual_table@. Dereferencing it gives the virtual table and access to the
     26type's virtual members.
    10527
    10628\subsection{Virtual Table}
    107 Each virtual type has a virtual table type that stores its type id and
    108 virtual members.
    109 Each virtual type instance is bound to a table instance that is filled with
    110 the values of virtual members.
    111 Both the layout of the fields and their value are decided by the rules given
    112 below.
    113 
    114 The layout always comes in three parts.
    115 The first section is just the type id at the head of the table. It is always
    116 there to ensure that
    117 The second section are all the virtual members of the parent, in the same
    118 order as they appear in the parent's virtual table. Note that the type may
    119 change slightly as references to the ``this" will change. This is limited to
    120 inside pointers/references and via function pointers so that the size (and
    121 hence the offsets) are the same.
    122 The third section is similar to the second except that it is the new virtual
    123 members introduced at this level in the hierarchy.
    124 
    125 \begin{figure}
    126 \begin{cfa}
    127 type_id
    128 parent_field0
    129 ...
    130 parent_fieldN
     29Every time a virtual type is defined the new virtual table type must also be
     30defined.
     31
     32The unique instance is important because the address of the virtual table
     33instance is used as the identifier for the virtual type. So a pointer to the
     34virtual table and the ID for the virtual type are interchangable.
     35\todo{Unique instances might be going so we will have to talk about the new
     36system instead.}
     37
     38The first step in putting it all together is to create the virtual table type.
     39The virtual table type is just a structure and can be described in terms of
     40its fields. The first field is always the parent type ID (or a pointer to
     41the parent virtual table) or 0 (the null pointer).
     42Next are other fields on the parent virtual table are repeated.
     43Finally are the fields used to store any new virtual members of the new
     44The virtual type
     45
     46The virtual system is accessed through a private constant field inserted at the
     47beginning of every virtual type, called the virtual-table pointer. This field
     48points at a type's virtual table and is assigned during the object's
     49construction. The address of a virtual table acts as the unique identifier for
     50the virtual type, and the first field of a virtual table is a pointer to the
     51parent virtual-table or @0p@. The remaining fields are duplicated from the
     52parent tables in this type's inheritance chain, followed by any fields this type
     53introduces. Parent fields are duplicated so they can be changed (all virtual
     54members are overridable), so that references to the dispatched type
     55are replaced with the current virtual type.
     56% These are always taken by pointer or reference.
     57
     58% Simple ascii diragram:
     59\begin{verbatim}
     60parent_pointer  \
     61parent_field0   |
     62...             | Same layout as parent.
     63parent_fieldN   /
    13164child_field0
    13265...
    13366child_fieldN
    134 \end{cfa}
    135 \caption{Virtual Table Layout}
    136 \label{f:VirtualTableLayout}
    137 \todo*{Improve the Virtual Table Layout diagram.}
    138 \end{figure}
    139 
    140 The first and second sections together mean that every virtual table has a
    141 prefix that has the same layout and types as its parent virtual table.
    142 This, combined with the fixed offset to the virtual table pointer, means that
    143 for any virtual type it doesn't matter if we have it or any of its
    144 descendants, it is still always safe to access the virtual table through
    145 the virtual table pointer.
    146 From there it is safe to check the type id to identify the exact type of the
    147 underlying object, access any of the virtual members and pass the object to
    148 any of the method-like virtual members.
    149 
    150 When a virtual table is declared the user decides where to declare it and its
    151 name. The initialization of the virtual table is entirely automatic based on
    152 the context of the declaration.
    153 
    154 The type id is always fixed, each virtual table type will always have one
    155 exactly one possible type id.
    156 The virtual members are usually filled in by resolution. The best match for
    157 a given name and type at the declaration site is filled in.
    158 There are two exceptions to that rule: the @size@ field is the type's size
    159 and is set to the result of a @sizeof@ expression, the @align@ field is the
    160 type's alignment and similarly uses an @alignof@ expression.
    161 
    162 \subsubsection{Concurrency Integration}
     67\end{verbatim}
     68\todo{Refine the diagram}
     69
     70% For each virtual type, a virtual table is constructed. This is both a new type
     71% and an instance of that type. Other instances of the type could be created
     72% but the system doesn't use them. So this section will go over the creation of
     73% the type and the instance.
     74
     75A virtual table is created when the virtual type is created. The name of the
     76type is created by mangling the name of the base type. The name of the instance
     77is also generated by name mangling. The fields are initialized automatically.
     78The parent field is initialized by getting the type of the parent field and
     79using that to calculate the mangled name of the parent's virtual table type.
     80There are two special fields that are included like normal fields but have
     81special initialization rules: the @size@ field is the type's size and is
     82initialized with a @sizeof@ expression, the @align@ field is the type's
     83alignment and uses an @alignof@ expression. The remaining fields are resolved
     84to a name matching the field's name and type using the normal visibility and
     85overload resolution rules of the type system.
     86
     87These operations are split up into several groups depending on where they take
     88place which varies for monomorphic and polymorphic types. The first devision is
     89between the declarations and the definitions. Declarations, such as a function
     90signature or a aggregate's name, must always be visible but may be repeated in
     91the form of forward declarations in headers. Definitions, such as function
     92bodies and a aggregate's layout, can be separately compiled but must occur
     93exactly once in a source file.
     94
     95\begin{sloppypar}
     96The declarations include the virtual type definition and forward declarations
     97of the virtual table instance, constructor, message function and
     98@get_exception_vtable@. The definition includes the storage and initialization
     99of the virtual table instance and the bodies of the three functions.
     100\end{sloppypar}
     101
     102Monomorphic instances put all of these two groups in one place each.
     103Polymorphic instances also split out the core declarations and definitions from
     104the per-instance information. The virtual table type and most of the functions
     105are polymorphic so they are all part of the core. The virtual table instance
     106and the @get_exception_vtable@ function.
     107
     108\begin{sloppypar}
    163109Coroutines and threads need instances of @CoroutineCancelled@ and
    164110@ThreadCancelled@ respectively to use all of their functionality. When a new
     
    166112the instance is created as well. The definition of the virtual table is created
    167113at the definition of the main function.
    168 
    169 \begin{figure}
    170 \begin{cfa}
    171 coroutine Example {
    172         // fields
    173 }
    174 \end{cfa}
    175 
    176 \begin{cfa}
    177 __attribute__((cfa_linkonce))
    178 struct __cfatid_struct_CoroutineCancelled(Example)
    179                 __cfatid_CoroutineCancelled = {
    180         &EXCEPTION_TYPE_ID,
    181 };
    182 extern CoroutineCancelled_vtable _default_vtable_object_declaration;
    183 extern CoroutineCancelled_vtable & _default_vtable;
    184 \end{cfa}
    185 
    186 \begin{cfa}
    187 void main(Example & this) {
    188         // body
    189 }
    190 \end{cfa}
    191 
    192 \begin{cfa}
    193 CoroutineCancelled_vtable _default_vtable_object_declaration = {
    194         __cfatid_CoroutineCancelled,
    195         // Virtual member initialization.
    196 };
    197 
    198 CoroutineCancelled_vtable & _default_vtable =
    199         &_default_vtable_object_declaration;
    200 \end{cfa}
    201 \caption{Concurrency Transformations}
    202 \label{f:ConcurrencyTransformations}
    203 \end{figure}
    204 \todo{Improve Concurrency Transformations figure.}
     114\end{sloppypar}
    205115
    206116\subsection{Virtual Cast}
     
    209119% The C-cast is just to make sure the generated code is correct so the rest of
    210120% the section is about that function.
    211 The function is implemented in the standard library and has the following
    212 signature:
     121The function is
    213122\begin{cfa}
    214123void * __cfa__virtual_cast(
    215         struct __cfavir_type_td parent,
    216         struct __cfavir_type_id const * child );
     124        struct __cfa__parent_vtable const * parent,
     125        struct __cfa__parent_vtable const * const * child );
    217126\end{cfa}
    218 The type id of target type of the virtual cast is passed in as @parent@ and
    219 the cast target is passed in as @child@.
    220 
    221 For C generation both arguments and the result are wrapped with type casts.
    222 There is also an internal store inside the compiler to make sure that the
    223 target type is a virtual type.
    224 % It also checks for conflicting definitions.
    225 
    226 The virtual cast either returns the original pointer as a new type or null.
    227 So the function just does the parent check and returns the approprate value.
    228 The parent check is a simple linear search of child's ancestors using the
    229 type information.
     127and it is implemented in the standard library. The structure reperents the
     128head of a vtable which is the pointer to the parent virtual table. The
     129@parent@ points directly at the parent type virtual table while the @child@
     130points at the object of the (possibe) child type.
     131
     132In terms of the virtual cast expression, @parent@ comes from looking up the
     133type being cast to and @child@ is the result of the expression being cast.
     134Because the complier outputs C code, some type C type casts are also used.
     135The last bit of glue is an map that saves every virtual type the compiler
     136sees. This is used to check the type used in a virtual cast is a virtual
     137type and to get its virtual table.
     138(It also checks for conflicting definitions.)
     139
     140Inside the function it is a simple conditional. If the type repersented by
     141@parent@ is or is an ancestor of the type repersented by @*child@ (it
     142requires one more level of derefence to pass through the object) then @child@
     143is returned, otherwise the null pointer is returned.
     144
     145The check itself is preformed is a simple linear search. If the child
     146virtual table or any of its ancestors (which are retreved through the first
     147field of every virtual table) are the same as the parent virtual table then
     148the cast succeeds.
    230149
    231150\section{Exceptions}
     
    242161
    243162Stack unwinding is the process of removing stack frames (activations) from the
    244 stack. On function entry and return, unwinding is handled directly by the
    245 call/return code embedded in the function.
    246 In many cases the position of the instruction pointer (relative to parameter
    247 and local declarations) is enough to know the current size of the stack
    248 frame.
    249 
    250 Usually, the stack-frame size is known statically based on parameter and
    251 local variable declarations. Even with dynamic stack-size the information
    252 to determain how much of the stack has to be removed is still contained
    253 within the function.
     163stack. On function entry and return, unwinding is handled directly by the code
     164embedded in the function. Usually, the stack-frame size is known statically
     165based on parameter and local variable declarations. For dynamically-sized
     166local variables, a runtime computation is necessary to know the frame
     167size. Finally, a function's frame-size may change during execution as local
     168variables (static or dynamic sized) go in and out of scope.
    254169Allocating/deallocating stack space is usually an $O(1)$ operation achieved by
    255170bumping the hardware stack-pointer up or down as needed.
    256 Constructing/destructing values on the stack takes longer put in terms of
    257 figuring out what needs to be done is of similar complexity.
    258 
    259 Unwinding across multiple stack frames is more complex because that
    260 information is no longer contained within the current function.
    261 With seperate compilation a function has no way of knowing what its callers
    262 are so it can't know how large those frames are.
    263 Without altering the main code path it is also hard to pass that work off
    264 to the caller.
     171
     172Unwinding across multiple stack frames is more complex because individual stack
     173management code associated with each frame is bypassed. That is, the location
     174of a function's frame-management code is largely unknown and dispersed
     175throughout the function, hence the current frame size managed by that code is
     176also unknown. Hence, code unwinding across frames does not have direct
     177knowledge about what is on the stack, and hence, how much of the stack needs to
     178be removed.
     179
     180% At a very basic level this can be done with @setjmp@ \& @longjmp@ which simply
     181% move the top of the stack, discarding everything on the stack above a certain
     182% point. However this ignores all the cleanup code that should be run when
     183% certain sections of the stack are removed (for \CFA these are from destructors
     184% and finally clauses) and also requires that the point to which the stack is
     185% being unwound is known ahead of time. libunwind is used to address both of
     186% these problems.
    265187
    266188The traditional unwinding mechanism for C is implemented by saving a snap-shot
     
    269191reseting to a snap-shot of an arbitrary but existing function frame on the
    270192stack. It is up to the programmer to ensure the snap-shot is valid when it is
    271 reset and that all required clean-up from the unwound stacks is preformed.
    272 This approach is fragile and forces a work onto the surounding code.
    273 
    274 With respect to that work forced onto the surounding code,
    275 many languages define clean-up actions that must be taken when certain
    276 sections of the stack are removed. Such as when the storage for a variable
    277 is removed from the stack or when a try statement with a finally clause is
    278 (conceptually) popped from the stack.
    279 None of these should be handled by the user, that would contradict the
    280 intention of these features, so they need to be handled automatically.
    281 
    282 To safely remove sections of the stack the language must be able to find and
    283 run these clean-up actions even when removing multiple functions unknown at
    284 the beginning of the unwinding.
     193reset, making this unwinding approach fragile with potential errors that are
     194difficult to debug because the stack becomes corrupted.
     195
     196However, many languages define cleanup actions that must be taken when objects
     197are deallocated from the stack or blocks end, such as running a variable's
     198destructor or a @try@ statement's @finally@ clause. Handling these mechanisms
     199requires walking the stack and checking each stack frame for these potential
     200actions.
     201
     202For exceptions, it must be possible to walk the stack frames in search of @try@
     203statements to match and execute a handler. For termination exceptions, it must
     204also be possible to unwind all stack frames from the throw to the matching
     205catch, and each of these frames must be checked for cleanup actions. Stack
     206walking is where most of the complexity and expense of exception handling
     207appears.
    285208
    286209One of the most popular tools for stack management is libunwind, a low-level
     
    292215\subsection{libunwind Usage}
    293216Libunwind, accessed through @unwind.h@ on most platforms, is a C library that
    294 provides \Cpp-style stack-unwinding. Its operation is divided into two phases:
     217provides \CC-style stack-unwinding. Its operation is divided into two phases:
    295218search and cleanup. The dynamic target search -- phase 1 -- is used to scan the
    296219stack and decide where unwinding should stop (but no unwinding occurs). The
     
    303226LSDA can contain any information but conventionally it is a table with entries
    304227representing regions of the function and what has to be done there during
    305 unwinding. These regions are bracketed by instruction addresses. If the
     228unwinding. These regions are bracketed by the instruction pointer. If the
    306229instruction pointer is within a region's start/end, then execution is currently
    307230executing in that region. Regions are used to mark out the scopes of objects
     
    315238
    316239The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and
    317 attaches a personality function to each function.
    318 In plain C (which \CFA currently compiles down to) this
     240attaches its personality function. However, this
    319241flag only handles the cleanup attribute:
     242\todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive
     243and that's all I know.}
    320244\begin{cfa}
    321245void clean_up( int * var ) { ... }
    322246int avar __attribute__(( cleanup(clean_up) ));
    323247\end{cfa}
    324 The attribue is used on a variable and specifies a function,
    325 in this case @clean_up@, run when the variable goes out of scope.
    326 This is enough to mimic destructors, but not try statements which can effect
    327 the unwinding.
    328 
    329 To get full unwinding support all of this has to be done directly with
    330 assembly and assembler directives. Partiularly the cfi directives
    331 \texttt{.cfi\_lsda} and \texttt{.cfi\_personality}.
     248which is used on a variable and specifies a function, in this case @clean_up@,
     249run when the variable goes out of scope.
     250The function is passed a pointer to the object being removed from the stack
     251so it can be used to mimic destructors.
     252However, this feature cannot be used to mimic @try@ statements as it cannot
     253control the unwinding.
    332254
    333255\subsection{Personality Functions}
     
    346268\end{lstlisting}
    347269The @action@ argument is a bitmask of possible actions:
    348 \begin{enumerate}[topsep=5pt]
     270\begin{enumerate}
    349271\item
    350272@_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function
     
    369291@_UA_FORCE_UNWIND@ specifies a forced unwind call. Forced unwind only performs
    370292the cleanup phase and uses a different means to decide when to stop
    371 (see \vref{s:ForcedUnwind}).
     293\see{\VRef{s:ForcedUnwind}}.
    372294\end{enumerate}
    373295
    374296The @exception_class@ argument is a copy of the
    375 \code{C}{exception}'s @exception_class@ field.
    376 This a number that identifies the exception handling mechanism that created
    377 the
    378 
    379 The \code{C}{exception} argument is a pointer to the user
    380 provided storage object. It has two public fields: the @exception_class@,
    381 which is described above, and the @exception_cleanup@ function.
    382 The clean-up function is used by the EHM to clean-up the exception if it
    383 should need to be freed at an unusual time, it takes an argument that says
    384 why it had to be cleaned up.
     297\lstinline[language=C]|exception|'s @exception_class@ field.
     298
     299The \lstinline[language=C]|exception| argument is a pointer to the user
     300provided storage object. It has two public fields, the exception class, which
     301is actually just a number, identifying the exception handling mechanism that
     302created it, and the cleanup function. The cleanup function is called if
     303required by the exception.
    385304
    386305The @context@ argument is a pointer to an opaque type passed to helper
     
    390309that can be passed several places in libunwind. It includes a number of
    391310messages for special cases (some of which should never be used by the
    392 personality function) and error codes. However, unless otherwise noted, the
     311personality function) and error codes but unless otherwise noted the
    393312personality function should always return @_URC_CONTINUE_UNWIND@.
    394313
     
    405324@_URC_END_OF_STACK@.
    406325
    407 Second, when a handler is matched, raise exception moves to the clean-up
    408 phase and walks the stack a second time.
     326Second, when a handler is matched, raise exception continues onto the cleanup
     327phase.
    409328Once again, it calls the personality functions of each stack frame from newest
    410329to oldest. This pass stops at the stack frame containing the matching handler.
     
    419338Forced Unwind is the other central function in libunwind.
    420339\begin{cfa}
    421 _Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *,
     340_Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *,
    422341        _Unwind_Stop_Fn, void *);
    423342\end{cfa}
     
    461380Each stack must have its own exception context. In a sequential \CFA program,
    462381there is only one stack with a single global exception-context. However, when
    463 the library @libcfathread@ is linked, there are multiple stacks and each
     382the library @libcfathread@ is linked, there are multiple stacks where each
    464383needs its own exception context.
    465384
    466 The exception context should be retrieved by calling the function
     385General access to the exception context is provided by function
    467386@this_exception_context@. For sequential execution, this function is defined as
    468387a weak symbol in the \CFA system-library, @libcfa@. When a \CFA program is
     
    471390
    472391The sequential @this_exception_context@ returns a hard-coded pointer to the
    473 global exception context.
     392global execption context.
    474393The concurrent version adds the exception context to the data stored at the
    475 base of each stack. When @this_exception_context@ is called, it retrieves the
     394base of each stack. When @this_exception_context@ is called it retrieves the
    476395active stack and returns the address of the context saved there.
    477396
     
    480399% catches. Talk about GCC nested functions.
    481400
    482 \CFA termination exceptions use libunwind heavily because they match \Cpp
    483 \Cpp exceptions closely. The main complication for \CFA is that the
     401Termination exceptions use libunwind heavily because it matches the intended
     402use from \CC exceptions closely. The main complication for \CFA is that the
    484403compiler generates C code, making it very difficult to generate the assembly to
    485404form the LSDA for try blocks or destructors.
     
    492411per-exception storage.
    493412
    494 \begin{figure}
     413[Quick ASCII diagram to get started.]
    495414\begin{verbatim}
    496415Fixed Header  | _Unwind_Exception   <- pointer target
     
    501420              V ...
    502421\end{verbatim}
    503 \caption{Exception Layout}
    504 \label{f:ExceptionLayout}
    505 \end{figure}
    506 \todo*{Convert the exception layout to an actual diagram.}
    507 
    508 Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}).
    509 The first component is a fixed-sized data structure that contains the
     422
     423Exceptions are stored in variable-sized blocks.
     424The first component is a fixed sized data structure that contains the
    510425information for libunwind and the exception system. The second component is an
    511426area of memory big enough to store the exception. Macros with pointer arthritic
     
    513428@_Unwind_Exception@ to the entire node.
    514429
    515 Multipe exceptions can exist at the same time because exceptions can be
    516 raised inside handlers, destructors and finally blocks.
    517 Figure~\vref{f:MultipleExceptions} shows a program that has multiple
    518 exceptions active at one time.
    519 Each time an exception is thrown and caught the stack unwinds and the finally
    520 clause runs. This will throw another exception (until @num_exceptions@ gets
    521 high enough) which must be allocated. The previous exceptions may not be
    522 freed because the handler/catch clause has not been run.
    523 So the EHM must keep them alive while it allocates exceptions for new throws.
    524 
    525 \begin{figure}
    526 \centering
    527 % Andrew: Figure out what these do and give them better names.
    528 \newsavebox{\myboxA}
    529 \newsavebox{\myboxB}
    530 \begin{lrbox}{\myboxA}
    531 \begin{lstlisting}[language=CFA,{moredelim=**[is][\color{red}]{@}{@}}]
    532 unsigned num_exceptions = 0;
    533 void throws() {
    534     try {
    535         try {
    536             ++num_exceptions;
    537             throw (Example){table};
    538         } finally {
    539             if (num_exceptions < 3) {
    540                 throws();
    541             }
    542         }
    543     } catch (exception_t *) {
    544         --num_exceptions;
    545     }
    546 }
    547 int main() {
    548     throws();
    549 }
    550 \end{lstlisting}
    551 \end{lrbox}
    552 
    553 \begin{lrbox}{\myboxB}
    554 \begin{lstlisting}
    555 \end{lstlisting}
    556 \end{lrbox}
    557 
    558 {\usebox\myboxA}
    559 \hspace{25pt}
    560 {\usebox\myboxB}
    561 
    562 \caption{Multiple Exceptions}
    563 \label{f:MultipleExceptions}
    564 \end{figure}
    565 \todo*{Work on multiple exceptions code sample.}
    566 
    567 All exceptions are stored in nodes which are then linked together in lists,
    568 one list per stack, with the
     430All of these nodes are linked together in a list, one list per stack, with the
    569431list head stored in the exception context. Within each linked list, the most
    570432recently thrown exception is at the head followed by older thrown
     
    577439exception, the copy function, and the free function, so they are specific to an
    578440exception type. The size and copy function are used immediately to copy an
    579 exception into managed memory. After the exception is handled, the free
    580 function is used to clean up the exception and then the entire node is
    581 passed to free so the memory can be given back to the heap.
     441exception into managed memory. After the exception is handled the free function
     442is used to clean up the exception and then the entire node is passed to free
     443so the memory can be given back to the heap.
    582444
    583445\subsection{Try Statements and Catch Clauses}
     
    592454calls them.
    593455Because this function is known and fixed (and not an arbitrary function that
    594 happens to contain a try statement), the LSDA can be generated ahead
     456happens to contain a try statement) this means the LSDA can be generated ahead
    595457of time.
    596458
    597459Both the LSDA and the personality function are set ahead of time using
    598 embedded assembly. This assembly code is handcrafted using C @asm@ statements
    599 and contains
     460embedded assembly. This is handcrafted using C @asm@ statements and contains
    600461enough information for the single try statement the function repersents.
    601462
     
    626487nested functions and all other functions besides @__cfaehm_try_terminate@ in
    627488\CFA use the GCC personality function and the @-fexceptions@ flag to generate
    628 the LSDA.
    629 Using this pattern, \CFA implements destructors with the cleanup attribute.
    630 
    631 \begin{figure}
    632 \begin{cfa}
    633 try {
    634         // TRY BLOCK
    635 } catch (Exception1 * name1 ; check(name1)) {
    636         // CATCH BLOCK 1
    637 } catch (Exception2 * name2) {
    638         // CATCH BLOCK 2
    639 }
    640 \end{cfa}
    641 
    642 \begin{cfa}
    643 void try(void) {
    644         // TRY BLOCK
    645 }
    646 int match(exception_t * __exception_inst) {
    647         {
    648                 Exception1 * name1;
    649                 if (name1 = (virtual Exception1 *)__exception_inst && check(name1)) {
    650                         return 1;
    651                 }
    652         }
    653         {
    654                 Exception2 * name2;
    655                 if (name2 = (virtual Exception2 *)__exception_inst) {
    656                         return 2;
    657                 }
    658         }
    659         return 0;
    660 }
    661 void catch(exception_t * __exception_inst, int __handler_index) {
    662         switch (__handler_index) {
    663         case 1:
    664         {
    665                 Exception1 * name1 = (virtual Exception1 *)__exception_inst;
    666                 // CATCH BLOCK 1
    667         }
    668         return;
    669         case 2:
    670         {
    671                 Exception2 * name2 = (virtual Exception2 *)__exception_inst;
    672                 // CATCH BLOCK 2
    673         }
    674         return;
    675         }
    676 }
    677 {
    678         __cfaehm_try_terminate(try, catch, match);
    679 }
    680 \end{cfa}
    681 
    682 \caption{Termination Transformation}
    683 \label{f:TerminationTransformation}
    684 \todo*{Improve (compress?) Termination Transformations.}
    685 \end{figure}
     489the LSDA. This allows destructors to be implemented with the cleanup attribute.
    686490
    687491\section{Resumption}
    688492% The stack-local data, the linked list of nodes.
    689493
    690 Resumption simpler to implement than termination
    691 because there is no stack unwinding.
    692 Instead of storing the data in a special area using assembly,
    693 there is just a linked list of possible handlers for each stack,
    694 with each node on the list reperenting a try statement on the stack.
    695 
    696 The head of the list is stored in the exception context.
    697 The nodes are stored in order, with the more recent try statements closer
    698 to the head of the list.
    699 Instead of traversing the stack resumption handling traverses the list.
    700 At each node the EHM checks to see if the try statement the node repersents
    701 can handle the exception. If it can, then the exception is handled and
    702 the operation finishes, otherwise the search continues to the next node.
    703 If the search reaches the end of the list without finding a try statement
    704 that can handle the exception the default handler is executed and the
    705 operation finishes.
    706 
    707 In each node is a handler function which does most of the work there.
    708 The handler function is passed the raised the exception and returns true
    709 if the exception is handled and false if it cannot be handled here.
    710 
    711 For each @catchResume@ clause the handler function will:
    712 check to see if the raised exception is a descendant type of the declared
    713 exception type, if it is and there is a conditional expression then it will
    714 run the test, if both checks pass the handling code for the clause is run
    715 and the function returns true, otherwise it moves onto the next clause.
    716 If this is the last @catchResume@ clause then instead of moving onto
    717 the next clause the function returns false as no handler could be found.
    718 
    719 \begin{figure}
    720 \begin{cfa}
    721 try {
    722         // TRY BLOCK
    723 } catchResume (Exception1 * name1 ; check(name1)) {
    724         // CATCH BLOCK 1
    725 } catchResume (Exception2 * name2) {
    726         // CATCH BLOCK 2
    727 }
    728 \end{cfa}
    729 
    730 \begin{cfa}
    731 bool handle(exception_t * __exception_inst) {
    732         {
    733                 Exception1 * name1;
    734                 if (name1 = (virtual Exception1 *)__exception_inst && check(name1)) {
    735                         // CATCH BLOCK 1
    736                         return 1;
    737                 }
    738         }
    739         {
    740                 Exception2 * name2;
    741                 if (name2 = (virtual Exception2 *)__exception_inst) {
    742                         // CATCH BLOCK 2
    743                         return 2;
    744                 }
    745         }
    746         return false;
    747 }
    748 struct __try_resume_node __resume_node
    749         __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
    750 __cfaehm_try_resume_setup( &__resume_node, handler );
    751 \end{cfa}
    752 
    753 \caption{Resumption Transformation}
    754 \label{f:ResumptionTransformation}
    755 \todo*{Improve (compress?) Resumption Transformations.}
    756 \end{figure}
     494Resumption simple to implement because there is no stack unwinding. The
     495resumption raise uses a list of nodes for its stack traversal. The head of the
     496list is stored in the exception context. The nodes in the list have a pointer
     497to the next node and a pointer to the handler function.
     498
     499A resumption raise traverses this list. At each node the handler function is
     500called, passing the exception by pointer. It returns true if the exception is
     501handled and false otherwise.
     502
     503The handler function does both the matching and handling. It computes the
     504condition of each @catchResume@ in top-to-bottom order, until it finds a
     505handler that matches. If no handler matches then the function returns
     506false. Otherwise the matching handler is run; if it completes successfully, the
     507function returns true. Rethrowing, through the @throwResume;@ statement,
     508causes the function to return true.
    757509
    758510% Recursive Resumption Stuff:
    759 Search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of
    760 the stack
     511Search skipping \see{\VPageref{p:searchskip}}, which ignores parts of the stack
    761512already examined, is accomplished by updating the front of the list as the
    762 search continues. Before the handler at a node is called, the head of the list
     513search continues. Before the handler at a node is called the head of the list
    763514is updated to the next node of the current node. After the search is complete,
    764515successful or not, the head of the list is reset.
     
    773524stack -- the first one points over all the checked handlers -- and the ordering
    774525is maintained.
    775 
    776 \begin{figure}
    777 \begin{minipage}[l][][b]{0,2\textwidth}
    778 \begin{verbatim}
    779 
    780 
    781   X <-
    782   |
    783   V
    784   X
    785   |
    786   V
    787   X
    788 \end{verbatim}
    789 Initial State
    790 \end{minipage}
    791 \begin{minipage}[l][][b]{0,2\textwidth}
    792 \begin{verbatim}
    793 
    794 
    795   X
    796   |
    797   V
    798   X <-
    799   |
    800   V
    801   X
    802 \end{verbatim}
    803 Handler Found
    804 \end{minipage}
    805 \begin{minipage}[l][][b]{0,2\textwidth}
    806 \begin{verbatim}
    807   X <-
    808  /
    809 / X
    810 | |
    811 \ V
    812   X
    813   |
    814   V
    815   X
    816 \end{verbatim}
    817 Try Block Added
    818 \end{minipage}
    819 \begin{minipage}[l][][b]{0,2\textwidth}
    820 \begin{verbatim}
    821 
    822 
    823   X <-
    824   |
    825   V
    826   X
    827   |
    828   V
    829   X
    830 \end{verbatim}
    831 Handler Done
    832 \end{minipage}
    833 \caption{Resumption Marking}
    834 \label{f:ResumptionMarking}
    835 \todo*{Convert Resumption Marking into a line figure.}
    836 \end{figure}
    837526
    838527\label{p:zero-cost}
     
    851540\section{Finally}
    852541% Uses destructors and GCC nested functions.
    853 A finally clause is placed into a GCC nested-function with a unique name,
    854 and no arguments or return values.
    855 This nested function is then set as the cleanup
     542Finally clauses is placed into a GCC nested-function with a unique name, and no
     543arguments or return values. This nested function is then set as the cleanup
    856544function of an empty object that is declared at the beginning of a block placed
    857545around the context of the associated @try@ statement.
    858546
    859 The rest is handled by GCC. The try block and all handlers are inside this
     547The rest is handled by GCC. The try block and all handlers are inside the
    860548block. At completion, control exits the block and the empty object is cleaned
    861549up, which runs the function that contains the finally code.
     
    865553
    866554Cancellation also uses libunwind to do its stack traversal and unwinding,
    867 however it uses a different primary function: @_Unwind_ForcedUnwind@. Details
    868 of its interface can be found in the Section~\vref{s:ForcedUnwind}.
     555however it uses a different primary function @_Unwind_ForcedUnwind@. Details
     556of its interface can be found in the \VRef{s:ForcedUnwind}.
    869557
    870558The first step of cancellation is to find the cancelled stack and its type:
     
    872560pointer and the current thread pointer, and every thread stores a pointer to
    873561its main coroutine and the coroutine it is currently executing.
    874 \todo*{Consider adding a description of how threads are coroutines.}
    875 
    876 If a the current thread's main and current coroutines are the same then the
    877 current stack is a thread stack. Furthermore it is easy to compare the
    878 current thread to the main thread to see if they are the same. And if this
    879 is not a thread stack then it must be a coroutine stack.
     562
     563So if the active thread's main and current coroutine are the same. If they
     564are then the current stack is a thread stack, otherwise it is a coroutine
     565stack. If it is a thread stack then an equality check with the stored main
     566thread pointer and current thread pointer is enough to tell if the current
     567thread is the main thread or not.
    880568
    881569However, if the threading library is not linked, the sequential execution is on
     
    886574Regardless of how the stack is chosen, the stop function and parameter are
    887575passed to the forced-unwind function. The general pattern of all three stop
    888 functions is the same: they continue unwinding until the end of stack and
    889 then preform their transfer.
     576functions is the same: they continue unwinding until the end of stack when they
     577do there primary work.
    890578
    891579For main stack cancellation, the transfer is just a program abort.
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    r8d66610 r5407cdc  
    6666% Tip: Photographs should be cropped and compressed so as not to be too large.
    6767
     68% To create a PDF output that is optimized for double-sided printing:
     69% 1) comment-out the \documentclass statement in the preamble below, and
     70%    un-comment the second \documentclass line.
     71% 2) change the value assigned below to the boolean variable "PrintVersion"
     72%    from "false" to "true".
     73
    6874% ======================================================================
    6975%   D O C U M E N T   P R E A M B L E
     
    8187}
    8288
    83 % Does nothing, ignores \href tags (redefined by hyperref package).
    84 \newcommand{\href}[1]{#1}
     89% Some LaTeX commands I define for my own nomenclature.
     90% If you have to, it's easier to make changes to nomenclature once here than
     91% in a million places throughout your thesis!
     92\newcommand{\package}[1]{\textbf{#1}} % package names in bold text
     93\newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font
     94\newcommand{\href}[1]{#1} % does nothing, but defines the command so the
     95% print-optimized version will ignore \href tags (redefined by hyperref pkg).
     96% Anything defined here may be redefined by packages added below...
    8597
    8698% For a nomenclature (optional; available from ctan.org)
     
    93105% Removes large sections of the document.
    94106\usepackage{comment}
    95 % Adds todo commands.
    96 \usepackage{todo}
    97 % cfa macros used in the document
    98 \usepackage{cfalab}
    99 % allow global and individual modification of spacing
    100 \usepackage{enumitem}
    101 % Improved reference tools.
    102 \usepackage[nospace]{varioref}
     107% Adds todos (Must be included after comment.)
     108\usepackage{todonotes}
    103109
    104110% Hyperlinks make it very easy to navigate an electronic document.
     
    145151
    146152% Exception to the rule of hyperref being the last add-on package
    147 \usepackage[toc,abbreviations]{glossaries-extra}
     153\usepackage[automake,toc,abbreviations]{glossaries-extra}
    148154% If glossaries-extra is not in your LaTeX distribution, get it from CTAN
    149155% (http://ctan.org/pkg/glossaries-extra), although it's supposed to be in
     
    202208\makeglossaries
    203209
    204 % listings package configuation:
    205 \lstMakeShortInline@
    206 \lstset{language=CFA,style=cfacommon,basicstyle=\linespread{0.9}\tt}
    207 \lstset{moredelim=**[is][\protect\color{red}]{@}{@}}
     210% cfa macros used in the document
     211%\usepackage{cfalab}
     212% I'm going to bring back eventually.
     213\makeatletter
     214% Combines all \CC* commands:
     215\newrobustcmd*\Cpp[1][\xspace]{\cfalab@Cpp#1}
     216\newcommand\cfalab@Cpp{C\kern-.1em\hbox{+\kern-.25em+}}
     217% Optional arguments do not work with pdf string. (Some fix-up required.)
     218\pdfstringdefDisableCommands{\def\Cpp{C++}}
     219
     220% Wrappers for inline code snippits.
     221\newrobustcmd*\codeCFA[1]{\lstinline[language=CFA]{#1}}
     222\newrobustcmd*\codeC[1]{\lstinline[language=C]{#1}}
     223\newrobustcmd*\codeCpp[1]{\lstinline[language=C++]{#1}}
     224\newrobustcmd*\codePy[1]{\lstinline[language=Python]{#1}}
     225
     226% Colour text, formatted in LaTeX style instead of TeX style.
     227\newcommand*\colour[2]{{\color{#1}#2}}
     228\makeatother
     229
     230\input{common}
     231% CFA code-style for all languages
     232\CFAStyle
     233% CFA default lnaguage
     234\lstset{language=CFA,basicstyle=\linespread{0.9}\tt}
    208235% Annotations from Peter:
    209236\newcommand{\PAB}[1]{{\color{blue}PAB: #1}}
     
    235262% Tip: Putting each sentence on a new line is a way to simplify later editing.
    236263%----------------------------------------------------------------------
    237 \input{intro}
    238264\input{existing}
    239265\input{features}
    240266\input{implement}
     267%\input{unwinding}
    241268\input{future}
    242269
     
    298325\phantomsection         % allows hyperref to link to the correct page
    299326
    300 \todos
    301 
    302327%----------------------------------------------------------------------
    303328\end{document} % end of logical document
  • doc/theses/mubeen_zulfiqar_MMath/AllocDS1.fig

    r8d66610 r5407cdc  
    88-2
    991200 2
    10 6 4200 1575 4500 1725
    11 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 1650 20 20 4275 1650 4295 1650
    12 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4350 1650 20 20 4350 1650 4370 1650
    13 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4425 1650 20 20 4425 1650 4445 1650
     106 4950 1275 5250 1425
     111 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 1350 20 20 5025 1350 5045 1350
     121 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 1350 20 20 5100 1350 5120 1350
     131 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5175 1350 20 20 5175 1350 5195 1350
    1414-6
    15 6 2850 2475 3150 2850
     156 5700 1950 6000 2100
     161 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2025 20 20 5775 2025 5795 2025
     171 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2025 20 20 5850 2025 5870 2025
     181 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5925 2025 20 20 5925 2025 5945 2025
     19-6
     206 3600 2100 3900 2475
    16212 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    1722        1 1 1.00 45.00 90.00
    18          2925 2475 2925 2700
     23         3675 2100 3675 2325
    19242 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    20          2850 2700 3150 2700 3150 2850 2850 2850 2850 2700
     25         3600 2325 3900 2325 3900 2475 3600 2475 3600 2325
    2126-6
    22 6 4350 2475 4650 2850
     276 5100 2100 5400 2475
    23282 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    2429        1 1 1.00 45.00 90.00
    25          4425 2475 4425 2700
     30         5175 2100 5175 2325
    26312 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    27          4350 2700 4650 2700 4650 2850 4350 2850 4350 2700
     32         5100 2325 5400 2325 5400 2475 5100 2475 5100 2325
    2833-6
    29 6 3600 2475 3825 3150
     346 4350 2100 4575 2775
    30352 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    3136        1 1 1.00 45.00 90.00
    32          3675 2475 3675 2700
     37         4425 2100 4425 2325
    33382 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    34          3600 2700 3825 2700 3825 2850 3600 2850 3600 2700
     39         4350 2325 4575 2325 4575 2475 4350 2475 4350 2325
    35402 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    36          3600 3000 3825 3000 3825 3150 3600 3150 3600 3000
     41         4350 2625 4575 2625 4575 2775 4350 2775 4350 2625
    37422 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    3843        1 1 1.00 45.00 90.00
    39          3675 2775 3675 3000
     44         4425 2400 4425 2625
    4045-6
    41 6 4875 3600 5175 3750
    42 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 3675 20 20 4950 3675 4970 3675
    43 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 3675 20 20 5025 3675 5045 3675
    44 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 3675 20 20 5100 3675 5120 3675
    45 -6
    46 6 4875 2325 5175 2475
    47 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 2400 20 20 4950 2400 4970 2400
    48 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 2400 20 20 5025 2400 5045 2400
    49 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 2400 20 20 5100 2400 5120 2400
    50 -6
    51 6 5625 2325 5925 2475
    52 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 2400 20 20 5700 2400 5720 2400
    53 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2400 20 20 5775 2400 5795 2400
    54 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2400 20 20 5850 2400 5870 2400
    55 -6
    56 6 5625 3600 5925 3750
    57 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 3675 20 20 5700 3675 5720 3675
    58 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3675 20 20 5775 3675 5795 3675
    59 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3675 20 20 5850 3675 5870 3675
     466 5700 3225 6000 3375
     471 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3300 20 20 5775 3300 5795 3300
     481 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3300 20 20 5850 3300 5870 3300
     491 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5925 3300 20 20 5925 3300 5945 3300
    6050-6
    61512 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    62          2400 2100 2400 2550
     52         2700 1950 3900 1950
    63532 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    64          2550 2100 2550 2550
     54         3000 1800 3000 2175
    65552 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    66          2700 2100 2700 2550
     56         3150 1800 3150 2175
    67572 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    68          2850 2100 2850 2550
     58         3300 1800 3300 2175
    69592 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    70          3000 2100 3000 2550
     60         3450 1800 3450 2175
    71612 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    72          3600 2100 3600 2550
     62         3600 1800 3600 2175
    73632 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    74          3900 2100 3900 2550
     64         3750 1800 3750 2175
    75652 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    76          4050 2100 4050 2550
     66         4200 1950 5400 1950
    77672 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    78          4200 2100 4200 2550
     68         4350 1800 4350 2175
    79692 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    80          4350 2100 4350 2550
     70         4500 1800 4500 2175
    81712 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    82          4500 2100 4500 2550
     72         4650 1800 4650 2175
    83732 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    84          3300 1500 3300 1800
     74         4800 1800 4800 2175
    85752 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    86          3600 1500 3600 1800
     76         4950 1800 4950 2175
    87772 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    88          3900 1500 3900 1800
     78         5100 1800 5100 2175
     792 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     80         5250 1800 5250 2175
     812 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     82         4050 1200 4050 1500
     832 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     84         4350 1200 4350 1500
     852 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     86         4650 1200 4650 1500
    89872 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    90          3000 1500 4800 1500 4800 1800 3000 1800 3000 1500
     88         3750 1200 5550 1200 5550 1500 3750 1500 3750 1200
    91892 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
    9290        1 1 1.00 45.00 90.00
    93          3225 1650 2625 2100
     91         3975 1350 3375 1800
    94922 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    9593        1 1 1.00 45.00 90.00
    96          3150 1650 2550 2100
     94         3900 1350 3300 1800
    97952 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    9896        1 1 1.00 45.00 90.00
    99          3450 1650 4050 2100
     97         4200 1350 4800 1800
    100982 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
    10199        1 1 1.00 45.00 90.00
    102          3375 1650 3975 2100
     100         4125 1350 4725 1800
    1031012 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    104          2100 2100 2100 2550
    105 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    106          1950 2250 3150 2250
    107 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    108          3450 2250 4650 2250
     102         2850 1800 2850 2175
    1091032 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    110          1950 2100 3150 2100 3150 2550 1950 2550 1950 2100
     104         2700 1800 3900 1800 3900 2175 2700 2175 2700 1800
    1111052 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    112          3450 2100 4650 2100 4650 2550 3450 2550 3450 2100
    113 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    114          2250 2100 2250 2550
    115 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    116          3750 2100 3750 2550
     106         4200 1800 5400 1800 5400 2175 4200 2175 4200 1800
    1171072 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    118108        1 1 1.00 45.00 90.00
    119          2025 2475 2025 2700
     109         2775 2100 2775 2325
    1201102 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    121111        1 1 1.00 45.00 90.00
    122          2025 2775 2025 3000
     112         2775 2400 2775 2625
    1231132 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    124          1950 3000 2100 3000 2100 3150 1950 3150 1950 3000
     114         2700 2625 2850 2625 2850 2775 2700 2775 2700 2625
    1251152 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    126          1950 2700 2100 2700 2100 2850 1950 2850 1950 2700
     116         2700 2325 2850 2325 2850 2475 2700 2475 2700 2325
    1271172 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    128118        1 1 1.00 45.00 90.00
    129          1950 3750 2700 3750 2700 3525
     119         2700 3375 3450 3375 3450 3150
    1301202 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    131          1950 3525 3150 3525 3150 3900 1950 3900 1950 3525
     121         2700 3150 3900 3150 3900 3525 2700 3525 2700 3150
    1321222 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    133123        1 1 1.00 45.00 90.00
    134          3450 3750 4200 3750 4200 3525
     124         4200 3375 4950 3375 4950 3150
    1351252 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    136          3450 3525 4650 3525 4650 3900 3450 3900 3450 3525
     126         4200 3150 5400 3150 5400 3525 4200 3525 4200 3150
    1371272 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    138128        1 1 1.00 45.00 90.00
    139          3150 4650 4200 4650 4200 4275
     129         3900 4350 4950 4350 4950 3900
    1401302 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    141          3150 4275 4650 4275 4650 4875 3150 4875 3150 4275
    142 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    143          1950 2400 3150 2400
    144 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    145          3450 2400 4650 2400
    146 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    147          5400 2100 5400 3900
    148 4 2 0 50 -1 0 11 0.0000 2 120 300 1875 2250 lock\001
    149 4 1 0 50 -1 0 12 0.0000 2 135 1935 3900 1425 N kernel-thread buckets\001
    150 4 1 0 50 -1 0 12 0.0000 2 195 810 4425 2025 heap$_2$\001
    151 4 1 0 50 -1 0 12 0.0000 2 195 810 2175 2025 heap$_1$\001
    152 4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2400 size\001
    153 4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2550 free\001
    154 4 1 0 50 -1 0 12 0.0000 2 180 825 2550 3450 local pool\001
    155 4 0 0 50 -1 0 12 0.0000 2 135 360 3525 3700 lock\001
    156 4 0 0 50 -1 0 12 0.0000 2 135 360 3225 4450 lock\001
    157 4 2 0 50 -1 0 12 0.0000 2 135 600 1875 3000 free list\001
    158 4 1 0 50 -1 0 12 0.0000 2 180 825 4050 3450 local pool\001
    159 4 1 0 50 -1 0 12 0.0000 2 180 1455 3900 4200 global pool (sbrk)\001
    160 4 0 0 50 -1 0 12 0.0000 2 135 360 2025 3700 lock\001
    161 4 1 0 50 -1 0 12 0.0000 2 180 720 6450 3150 free pool\001
    162 4 1 0 50 -1 0 12 0.0000 2 180 390 6450 2925 heap\001
     131         3900 3900 5400 3900 5400 4575 3900 4575 3900 3900
     1324 2 0 50 -1 0 12 0.0000 2 135 975 2625 2175 free buckets\001
     1334 2 0 50 -1 0 12 0.0000 2 135 435 2625 1950 locks\001
     1344 1 0 50 -1 0 12 0.0000 2 135 1365 4650 1125 N thread buckets\001
     1354 1 0 50 -1 0 12 0.0000 2 180 390 5175 1725 heap\001
     1364 1 0 50 -1 0 12 0.0000 2 180 390 2925 1725 heap\001
     1374 1 0 50 -1 0 12 0.0000 2 180 915 3300 3075 bump alloc\001
     1384 0 0 50 -1 0 12 0.0000 2 135 360 4275 3325 lock\001
     1394 1 0 50 -1 0 12 0.0000 2 180 915 4800 3075 bump alloc\001
     1404 0 0 50 -1 0 12 0.0000 2 135 360 3975 4075 lock\001
     1414 1 0 50 -1 0 12 0.0000 2 135 345 4725 3825 sbrk\001
     1424 0 0 50 -1 0 12 0.0000 2 135 360 2775 3325 lock\001
     1434 2 0 50 -1 0 12 0.0000 2 135 675 2625 2625 free lists\001
  • doc/theses/mubeen_zulfiqar_MMath/AllocDS2.fig

    r8d66610 r5407cdc  
    88-2
    991200 2
    10 6 2850 2100 3150 2250
    11 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 2175 20 20 2925 2175 2945 2175
    12 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 2175 20 20 3000 2175 3020 2175
    13 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 2175 20 20 3075 2175 3095 2175
     106 2850 2025 3150 2175
     111 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 2100 20 20 2925 2100 2945 2100
     121 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 2100 20 20 3000 2100 3020 2100
     131 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 2100 20 20 3075 2100 3095 2100
    1414-6
    15 6 4050 2100 4350 2250
    16 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 2175 20 20 4125 2175 4145 2175
    17 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 2175 20 20 4200 2175 4220 2175
    18 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 2175 20 20 4275 2175 4295 2175
     156 4050 2025 4350 2175
     161 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 2100 20 20 4125 2100 4145 2100
     171 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 2100 20 20 4200 2100 4220 2100
     181 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 2100 20 20 4275 2100 4295 2100
    1919-6
    20 6 4650 2100 4950 2250
    21 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 2175 20 20 4725 2175 4745 2175
    22 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 2175 20 20 4800 2175 4820 2175
    23 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 2175 20 20 4875 2175 4895 2175
     206 4650 2025 4950 2175
     211 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 2100 20 20 4725 2100 4745 2100
     221 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 2100 20 20 4800 2100 4820 2100
     231 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 2100 20 20 4875 2100 4895 2100
    2424-6
    25 6 3450 2100 3750 2250
    26 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 2175 20 20 3525 2175 3545 2175
    27 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 2175 20 20 3600 2175 3620 2175
    28 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 2175 20 20 3675 2175 3695 2175
     256 3450 2025 3750 2175
     261 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 2100 20 20 3525 2100 3545 2100
     271 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 2100 20 20 3600 2100 3620 2100
     281 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 2100 20 20 3675 2100 3695 2100
    2929-6
    30 6 3300 2175 3600 2550
     306 3300 2100 3600 2475
    31312 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    3232        1 1 1.00 45.00 90.00
    33          3375 2175 3375 2400
     33         3375 2100 3375 2325
    34342 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    35          3300 2400 3600 2400 3600 2550 3300 2550 3300 2400
     35         3300 2325 3600 2325 3600 2475 3300 2475 3300 2325
    3636-6
    37 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    38          3150 1800 3150 2250
    39 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    40          2850 1800 2850 2250
    41 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    42          4650 1800 4650 2250
    43 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    44          4950 1800 4950 2250
    45 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    46          4500 1725 4500 2250
    47 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    48          5100 1725 5100 2250
    49 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    50          3450 1800 3450 2250
    51 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    52          3750 1800 3750 2250
    53 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    54          3300 1725 3300 2250
    55 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    56          3900 1725 3900 2250
    57 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    58          5250 1800 5250 2250
    59 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    60          5400 1800 5400 2250
    61 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    62          5550 1800 5550 2250
    63 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    64          5700 1800 5700 2250
    65 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    66          5850 1800 5850 2250
    67 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    68          2700 1725 2700 2250
    69 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    70         1 1 1.00 45.00 90.00
    71          3375 1275 3375 1575
    72 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    73         1 1 1.00 45.00 90.00
    74          2700 1275 2700 1575
    75 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
    76         1 1 1.00 45.00 90.00
    77          2775 1275 2775 1575
    78 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    79         1 1 1.00 45.00 90.00
    80          5175 1275 5175 1575
    81 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    82         1 1 1.00 45.00 90.00
    83          5625 1275 5625 1575
    84 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    85         1 1 1.00 45.00 90.00
    86          3750 1275 3750 1575
    87 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
    88         1 1 1.00 45.00 90.00
    89          3825 1275 3825 1575
    90372 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    9138         2700 1950 6000 1950
    92392 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    93          2700 2100 6000 2100
     40         3150 1800 3150 2175
     412 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     42         2850 1800 2850 2175
     432 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     44         4650 1800 4650 2175
     452 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     46         4950 1800 4950 2175
     472 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     48         4500 1725 4500 2175
     492 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     50         5100 1725 5100 2175
     512 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     52         3450 1800 3450 2175
     532 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     54         3750 1800 3750 2175
     552 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     56         3300 1725 3300 2175
     572 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     58         3900 1725 3900 2175
     592 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     60         5250 1800 5250 2175
     612 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     62         5400 1800 5400 2175
     632 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     64         5550 1800 5550 2175
     652 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     66         5700 1800 5700 2175
     672 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     68         5850 1800 5850 2175
     692 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     70         2700 1725 2700 2175
    94712 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    95          2700 1800 6000 1800 6000 2250 2700 2250 2700 1800
     72         2700 1800 6000 1800 6000 2175 2700 2175 2700 1800
    96732 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    9774        1 1 1.00 45.00 90.00
    98          2775 2175 2775 2400
     75         2775 2100 2775 2325
    99762 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    10077        1 1 1.00 45.00 90.00
    101          2775 2475 2775 2700
     78         2775 2400 2775 2625
    102792 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    103          2700 2700 2850 2700 2850 2850 2700 2850 2700 2700
     80         2700 2625 2850 2625 2850 2775 2700 2775 2700 2625
    104812 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    105          2700 2400 2850 2400 2850 2550 2700 2550 2700 2400
     82         2700 2325 2850 2325 2850 2475 2700 2475 2700 2325
    106832 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    10784        1 1 1.00 45.00 90.00
    108          4575 2175 4575 2400
     85         4575 2100 4575 2325
    109862 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    110          4500 2400 5025 2400 5025 2550 4500 2550 4500 2400
     87         4500 2325 5025 2325 5025 2475 4500 2475 4500 2325
    111882 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    11289        1 1 1.00 45.00 90.00
    113          3600 3525 4650 3525 4650 3150
     90         3600 3525 4650 3525 4650 3075
    114912 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    115          3600 3150 5100 3150 5100 3750 3600 3750 3600 3150
    116 4 2 0 50 -1 0 11 0.0000 2 120 300 2625 1950 lock\001
     92         3600 3075 5100 3075 5100 3750 3600 3750 3600 3075
     934 2 0 50 -1 0 12 0.0000 2 135 975 2625 2175 free buckets\001
     944 2 0 50 -1 0 12 0.0000 2 135 435 2625 1950 locks\001
    117954 1 0 50 -1 0 10 0.0000 2 150 1155 3000 1725 N$\\times$S$_1$\001
    118964 1 0 50 -1 0 10 0.0000 2 150 1155 3600 1725 N$\\times$S$_2$\001
     974 1 0 50 -1 0 10 0.0000 2 150 1110 4800 1725 N$\\times$S$_t$\001
     984 2 0 50 -1 0 12 0.0000 2 135 675 2625 2625 free lists\001
     994 0 0 50 -1 0 12 0.0000 2 135 360 3675 3250 lock\001
     1004 1 0 50 -1 0 12 0.0000 2 135 345 4425 3000 sbrk\001
    1191014 1 0 50 -1 0 12 0.0000 2 180 390 4425 1500 heap\001
    120 4 2 0 50 -1 0 12 0.0000 2 135 1140 2550 1425 kernel threads\001
    121 4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2100 size\001
    122 4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2250 free\001
    123 4 2 0 50 -1 0 12 0.0000 2 135 600 2625 2700 free list\001
    124 4 0 0 50 -1 0 12 0.0000 2 135 360 3675 3325 lock\001
    125 4 1 0 50 -1 0 12 0.0000 2 180 1455 4350 3075 global pool (sbrk)\001
    126 4 1 0 50 -1 0 10 0.0000 2 150 1110 4800 1725 N$\\times$S$_t$\001
  • doc/theses/mubeen_zulfiqar_MMath/Makefile

    r8d66610 r5407cdc  
    1515
    1616.PHONY: all clean
    17 .PRECIOUS: %.dvi %.ps # do not delete intermediate files
    1817
    1918### Commands:
    2019LATEX = TEXINPUTS=${TEXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${BUILD}
    2120BIBTEX = BIBINPUTS=${BIBLIB} bibtex
    22 #GLOSSARY = INDEXSTYLE=${BUILD} makeglossaries-lite
     21#GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite
    2322
    2423### Rules and Recipes:
     
    2625all: ${DOC}
    2726
    28 ${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC:%.fig=%.tex} ${BIBSRC} Makefile | ${BUILD}
     27${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC:.fig=.tex} ${BIBSRC} Makefile | ${BUILD}
    2928        ${LATEX} ${BASE}
    3029        ${BIBTEX} ${BUILD}/${BASE}
  • doc/theses/mubeen_zulfiqar_MMath/allocator.tex

    r8d66610 r5407cdc  
     1
    12\chapter{Allocator}
    2 
    3 \noindent
    4 ====================
    5 
    6 Writing Points:
    7 \begin{itemize}
    8 \item
    9 Objective of @uHeapLmmm@.
    10 \item
    11 Design philosophy.
    12 \item
    13 Background and previous design of @uHeapLmmm@.
    14 \item
    15 Distributed design of @uHeapLmmm@.
    16 
    17 ----- SHOULD WE GIVE IMPLEMENTATION DETAILS HERE? -----
    18 
    19 \PAB{Maybe. There might be an Implementation chapter.}
    20 \item
    21 figure.
    22 \item
    23 Advantages of distributed design.
    24 \end{itemize}
    25 
    26 The new features added to @uHeapLmmm@ (incl. @malloc_size@ routine)
    27 \CFA alloc interface with examples.
    28 \begin{itemize}
    29 \item
    30 Why did we need it?
    31 \item
    32 The added benefits.
    33 \end{itemize}
    34 
    35 ----- SHOULD WE GIVE PERFORMANCE AND USABILITY COMPARISON OF DIFFERENT INTERFACES THAT WE TRIED? -----
    36 
    37 \PAB{Often Performance is its own chapter. I added one for now.}
    38 
    39 Performance evaluation using u-benchmark suite.
    40 
    41 \noindent
    42 ====================
    433
    444\newpage
    455\paragraph{Design 1: Decentralized}
    46 Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the @sbrk@ area.
     6Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the sbrk area.
    477Kernel threads (KT) are assigned to the N heaps.
    488When KTs $\le$ N, the heaps are uncontented.
  • doc/theses/mubeen_zulfiqar_MMath/background.tex

    r8d66610 r5407cdc  
    11\chapter{Background}
    22
    3 \noindent
    4 ====================
    5 
    6 Writing Points:
    7 \begin{itemize}
    8 \item
    9 Classification of benchmarks.
    10 \item
    11 Literature review of current benchmarks.
    12 \item
    13 Features and limitations.
    14 \item
    15 Literature review of current memory allocators.
    16 \item
    17 Breakdown of memory allocation techniques.
    18 \item
    19 Features and limitations.
    20 \end{itemize}
    21 
    22 \noindent
    23 ====================
    24 
    253\cite{Wasik08}
  • doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex

    r8d66610 r5407cdc  
    11\chapter{Benchmarks}
    2 
    3 \noindent
    4 ====================
    5 
    6 Writing Points:
    7 \begin{itemize}
    8 \item
    9 Performance matrices of memory allocation.
    10 \item
    11 Aim of micro benchmark suite.
    12 
    13 ----- SHOULD WE GIVE IMPLEMENTATION DETAILS HERE? -----
    14 
    15 \PAB{For the benchmarks, yes.}
    16 \item
    17 A complete list of benchmarks in micro benchmark suite.
    18 \item
    19 One detailed section for each benchmark in micro benchmark suite including:
    20 
    21 \begin{itemize}
    22 \item
    23 The introduction of the benchmark.
    24 \item
    25 Figure.
    26 \item
    27 Results with popular memory allocators.
    28 \end{itemize}
    29 
    30 \item
    31 Summarize performance of current memory allocators.
    32 \end{itemize}
    33 
    34 \noindent
    35 ====================
  • doc/theses/mubeen_zulfiqar_MMath/conclusion.tex

    r8d66610 r5407cdc  
    11\chapter{Conclusion}
    2 
    3 \noindent
    4 ====================
    5 
    6 Writing Points:
    7 \begin{itemize}
    8 \item
    9 Summarize u-benchmark suite.
    10 \item
    11 Summarize @uHeapLmmm@.
    12 \item
    13 Make recommendations on memory allocator design.
    14 \end{itemize}
    15 
    16 \noindent
    17 ====================
  • doc/theses/mubeen_zulfiqar_MMath/intro.tex

    r8d66610 r5407cdc  
    11\chapter{Introduction}
    2 
    3 \noindent
    4 ====================
    5 
    6 Writing Points:
    7 \begin{itemize}
    8 \item
    9 Introduce dynamic memory allocation with brief background.
    10 \item
    11 Scope of the thesis.
    12 \item
    13 Importance of memory allocation and micro-benchmark suite.
    14 \item
    15 Research problem.
    16 \item
    17 Research objectives.
    18 \item
    19 The vision behind cfa-malloc.
    20 \item
    21 An outline of the thesis.
    22 \end{itemize}
    23 
    24 \noindent
    25 ====================
  • doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex

    r8d66610 r5407cdc  
    8484\usepackage{graphicx}
    8585\usepackage{comment} % Removes large sections of the document.
     86\usepackage{todonotes} % Adds todos (Must be included after comment.)
    8687
    8788% Hyperlinks make it very easy to navigate an electronic document.
     
    106107    colorlinks=true,        % false: boxed links; true: colored links
    107108    linkcolor=blue,         % color of internal links
    108     citecolor=blue,        % color of links to bibliography
     109    citecolor=green,        % color of links to bibliography
    109110    filecolor=magenta,      % color of file links
    110     urlcolor=blue           % color of external links
     111    urlcolor=cyan           % color of external links
    111112}
    112113\ifthenelse{\boolean{PrintVersion}}{   % for improved print quality, change some hyperref options
     
    167168\CFAStyle                                               % CFA code-style for all languages
    168169\lstset{language=CFA,basicstyle=\linespread{0.9}\tt}    % CFA default language
    169 \newcommand{\PAB}[1]{{\color{red}PAB: #1}}
    170170
    171171%======================================================================
     
    194194\input{allocator}
    195195\input{benchmarks}
    196 \input{performance}
    197196\input{conclusion}
    198197
  • doc/user/Makefile

    r8d66610 r5407cdc  
    6161
    6262${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
    63                 ${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
     63                ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
    6464        # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
    6565        if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi
     
    6868        -${BibTeX} ${Build}/${basename $@}
    6969        # Some citations reference others so run again to resolve these citations
    70 #       ${LaTeX} ${basename $@}.tex
     70        ${LaTeX} ${basename $@}.tex
    7171        -${BibTeX} ${Build}/${basename $@}
    7272        # Make index from *.aux entries and input index at end of document
     
    7575        ${LaTeX} ${basename $@}.tex
    7676        # Run again to get index title into table of contents
    77 #       ${LaTeX} ${basename $@}.tex
     77        ${LaTeX} ${basename $@}.tex
    7878
    7979## Define the default recipes.
  • doc/user/user.tex

    r8d66610 r5407cdc  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sat May  8 08:51:33 2021
    14 %% Update Count     : 5062
     13%% Last Modified On : Sun Apr 25 19:03:03 2021
     14%% Update Count     : 4951
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    6565% keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
    6666% math escape $...$ (dollar symbol)
    67 \usepackage{common}                                                                             % common CFA document macros
    68 %\input{common}                                                                                 % common CFA document macros
     67\input{common}                                          % common CFA document macros
    6968\setlength{\gcolumnposn}{3in}
    7069\CFAStyle                                                                                               % use default CFA format-style
     
    586585For example, the octal ©0© or hexadecimal ©0x© prefix may end with an underscore ©0_377© or ©0x_ff©;
    587586the exponent infix ©E© may start or end with an underscore ©1.0_E10©, ©1.0E_10© or ©1.0_E_10©;
    588 the type suffixes ©U©, ©L©, \etc may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.
     587the type suffixes ©U©, ©L©, etc. may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.
    589588\end{enumerate}
    590589It is significantly easier to read and enter long constants when they are broken up into smaller groupings (many cultures use comma and/or period among digits for the same purpose).
     
    15711570\end{cquote}
    15721571
    1573 All type qualifiers, \eg ©const©, ©volatile©, \etc, are used in the normal way with the new declarations and also appear left to right, \eg:
     1572All type qualifiers, \eg ©const©, ©volatile©, etc., are used in the normal way with the new declarations and also appear left to right, \eg:
    15741573\begin{cquote}
    15751574\begin{tabular}{@{}l@{\hspace{1em}}l@{\hspace{1em}}l@{}}
     
    15911590\end{tabular}
    15921591\end{cquote}
    1593 All declaration qualifiers, \eg ©extern©, ©static©, \etc, are used in the normal way with the new declarations but can only appear at the start of a \CFA routine declaration,\footnote{\label{StorageClassSpecifier}
     1592All declaration qualifiers, \eg ©extern©, ©static©, etc., are used in the normal way with the new declarations but can only appear at the start of a \CFA routine declaration,\footnote{\label{StorageClassSpecifier}
    15941593The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.~\cite[\S~6.11.5(1)]{C11}} \eg:
    15951594\begin{cquote}
     
    31483147also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple.
    31493148
    3150 Since tuple-index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member-access expressions to restructure a tuple (\eg, rearrange components, drop components, duplicate components, \etc).
     3149Since tuple-index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member-access expressions to restructure a tuple (\eg, rearrange components, drop components, duplicate components, etc.).
    31513150\begin{cfa}
    31523151[ int, int, long, double ] x;
     
    33133312
    33143313\section{Tuples}
    3315 \label{tuples}
    33163314
    33173315In C and \CFA, lists of elements appear in several contexts, such as the parameter list for a routine call.
     
    34223420
    34233421\subsection{Tuple Coercions}
    3424 \label{tuple coercions}\label{coercions!tuple}
    34253422
    34263423There are four coercions that can be performed on tuples and tuple variables: closing, opening, flattening and structuring.
     
    34673464
    34683465\subsection{Mass Assignment}
    3469 \label{mass assignment}\label{assignment!mass}
    34703466
    34713467\CFA permits assignment to several variables at once using mass assignment~\cite{CLU}.
     
    35083504
    35093505\subsection{Multiple Assignment}
    3510 \label{multiple assignment}\label{assignment!multiple}
    35113506
    35123507\CFA also supports the assignment of several values at once, known as multiple assignment~\cite{CLU,Galletly96}.
     
    35503545
    35513546\subsection{Cascade Assignment}
    3552 \index{cascade assignment}\index{assignment!cascade}
    35533547
    35543548As in C, \CFA mass and multiple assignments can be cascaded, producing cascade assignment.
     
    35703564\section{Stream I/O Library}
    35713565\label{s:StreamIOLibrary}
    3572 \index{input}\index{output}
    3573 \index{stream library}\index{library!stream}
     3566\index{input/output stream library}
     3567\index{stream library}
    35743568
    35753569The goal of \CFA stream input/output (I/O) is to simplify the common cases\index{I/O!common case}, while fully supporting polymorphism and user defined types in a consistent way.
    35763570Stream I/O can be implicitly or explicitly formatted.
    3577 Implicit formatting means \CFA selects the output or input format for values that matches the variable's type.
     3571Implicit formatting means \CFA selects the output or input format for values that match with the type of a variable.
    35783572Explicit formatting means additional information is specified to augment how an output or input of value is interpreted.
    3579 \CFA formatting incorporates ideas from C ©printf©, \CC ©stream© manipulators, and Python implicit spacing and newline.
     3573\CFA formatting is a cross between C ©printf© and \CC ©cout© manipulators, and Python implicit spacing and newline.
    35803574Specifically:
    35813575\begin{itemize}
     
    35903584Hence, it is common programming practice to toggle manipulators on and then back to the default to prevent downstream side-effects.
    35913585Without this programming style, errors occur when moving prints, as manipulator effects incorrectly flow into the new location.
    3592 Furthermore, to guarantee no side-effects, manipulator values must be saved and restored across function calls.
    3593 \item
    3594 \CFA has more sophisticated implicit value spacing than Python, plus implicit newline at the end of a print.
     3586(To guarantee no side-effects, manipulator values must be saved and restored across function calls.)
     3587\item
     3588\CFA has more sophisticated implicit spacing between values than Python, plus implicit newline at the end of a print.
    35953589\end{itemize}
    3596 
    3597 The standard polymorphic I/Os stream are ©stdin©/©sin© (input), ©stdout©/©sout© and ©stderr©/©serr© (output) (like C++ ©cin©/©cout©/©cerr©).
    3598 Polymorphic streams ©exit© and ©abort© provide implicit program termination without and with generating a stack trace and core file.
    3599 Stream ©exit© implicitly returns ©EXIT_FAILURE© to the shell.
    3600 \begin{cfa}
    3601 ®exit®   | "x (" | x | ") negative value."; // terminate and return EXIT_FAILURE to shell
    3602 ®abort® | "x (" | x | ") negative value."; // terminate and generate stack trace and core file
    3603 \end{cfa}
    3604 Note, \CFA stream variables ©stdin©, ©stdout©, ©stderr©, ©exit©, and ©abort© overload C variables ©stdin©, ©stdout©, ©stderr©, and functions ©exit© and ©abort©, respectively.
    36053590The \CFA header file for the I/O library is \Indexc{fstream.hfa}.
    3606 
    3607 
    3608 \subsection{Basic I/O}
    36093591
    36103592For implicit formatted output, the common case is printing a series of variables separated by whitespace.
     
    36193601\begin{cfa}
    36203602
    3621 cout  <<  x  ®<< " "®  <<  y  ®<< " "®  <<  z << endl;
     3603cout << x ®<< " "® << y ®<< " "® << z << endl;
    36223604\end{cfa}
    36233605&
     
    36713653\end{tabular}
    36723654\end{cquote}
    3673 Input and output use a uniform operator, ©|©, rather than \CC's ©>>© and ©<<© input/output operators.
     3655Input and output use a uniform operator, ©|©, rather than separate operators, as in ©>>© and ©<<© for \CC.
    36743656There is a weak similarity between the \CFA logical-or operator and the \Index{Shell pipe-operator} for moving data, where data flows in the correct direction for input but the opposite direction for output.
    36753657
     
    37163698\end{cquote}
    37173699
    3718 \VRef[Figure]{f:CFACommand-LineProcessing} shows idiomatic \CFA command-line processing and copying an input file to an output file.
    3719 Note, a stream variable may be copied because it is a reference to an underlying stream data-structures.
    3720 All I/O errors are handles as exceptions, but end-of-file is not an exception as C programmers are use to explicitly checking for it.
    3721 
    3722 \begin{figure}
    3723 \begin{cfa}
    3724 #include ®<fstream.hfa>®
    3725 
    3726 int main( int argc, char * argv[] ) {
    3727         ®ifstream® in  = stdin;                                 $\C{// copy default files}$
    3728         ®ofstream® out = stdout;
    3729 
    3730         try {
    3731                 choose ( argc ) {
    3732                   case 2, 3:
    3733                         ®open®( in, argv[1] );                  $\C{// open input file first as output creates file}$
    3734                         if ( argc == 3 ) ®open®( out, argv[2] ); $\C{// do not create output unless input opens}$
    3735                   case 1: ;                                                     $\C{// use default files}$
    3736                   default:
    3737                         ®exit® | "Usage" | argv[0] | "[ input-file (default stdin) "
    3738                                    "[ output-file (default stdout) ] ]";
    3739                 } // choose
    3740         } catch( ®Open_Failure® * ex; ex->istream == &in ) {
    3741                 ®exit® | "Unable to open input file" | argv[1];
    3742         } catch( ®Open_Failure® * ex; ex->ostream == &out ) {
    3743                 ®close®( in );                                          $\C{// optional}$
    3744                 ®exit® | "Unable to open output file" | argv[2];
    3745         } // try
    3746 
    3747         out | nlOff;                                                    $\C{// turn off auto newline}$
    3748         in | nlOn;                                                              $\C{// turn on reading newline}$
    3749         char ch;
    3750         for () {                                                                $\C{// read/write characters}$
    3751                 in | ch;
    3752           if ( eof( in ) ) break;                               $\C{// eof ?}$
    3753                 out | ch;
    3754         } // for
    3755 } // main
    3756 \end{cfa}
    3757 \caption{\CFA Command-Line Processing}
    3758 \label{f:CFACommand-LineProcessing}
    3759 \end{figure}
    3760 
    3761 \VRef[Figure]{f:StreamFunctions} shows the stream operations.
    3762 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    3763 \item
    3764 \Indexc{fail} tests the stream error-indicator, returning nonzero if it is set.
    3765 \item
    3766 \Indexc{clear} resets the stream error-indicator.
    3767 \item
    3768 \Indexc{flush} (©ofstream© only) causes any unwritten data for a stream to be written to the file.
    3769 \item
    3770 \Indexc{eof} (©ifstream© only) tests the end-of-file indicator for the stream pointed to by stream.
    3771 Returns true if the end-of-file indicator is set, otherwise false.
    3772 \item
    3773 \Indexc{open} binds the file with ©name© to a stream accessed with ©mode© (see ©fopen©).
    3774 \item
    3775 \Indexc{close} flushes the stream and closes the file.
    3776 \item
    3777 \Indexc{write} (©ofstream© only) write ©size© bytes to the stream.
    3778 The bytes are written lazily to file when internal buffers fill.
    3779 Eager buffer writes are done with ©flush©
    3780 \item
    3781 \Indexc{read} (©ifstream© only) read ©size© bytes to the stream.
    3782 \item
    3783 \Indexc{ungetc} (©ifstream© only) pushes the character back to the input stream.
    3784 Pushed-back characters returned by subsequent reads in the reverse order of pushing.
    3785 \end{itemize}
    3786 The constructor functions:
    3787 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    3788 \item
    3789 create an unbound stream, which is subsequently bound to a file with ©open©.
    3790 \item
    3791 create a bound stream to the associated file with given ©mode©.
    3792 \end{itemize}
    3793 The destructor closes the stream.
    3794 
    3795 \begin{figure}
    3796 \begin{cfa}
    3797 // *********************************** ofstream ***********************************
    3798 
    3799 bool fail( ofstream & );$\indexc{fail}\index{ofstream@©ofstream©!©fail©}$
    3800 void clear( ofstream & );$\indexc{clear}\index{ofstream@©ofstream©!©clear©}$
    3801 int flush( ofstream & );$\indexc{flush}\index{ofstream@©ofstream©!©flush©}$
    3802 void open( ofstream &, const char name[], const char mode[] = "w" );$\indexc{open}\index{ofstream@©ofstream©!©open©}$
    3803 void close( ofstream & );$\indexc{close}\index{ofstream@©ofstream©!©close©}$
    3804 ofstream & write( ofstream &, const char data[], size_t size );$\indexc{write}\index{ofstream@©ofstream©!©write©}$
    3805 
    3806 void ?{}( ofstream & );$\index{ofstream@©ofstream©!©?{}©}$
    3807 void ?{}( ofstream &, const char name[], const char mode[] = "w" );
    3808 void ^?{}( ofstream & );$\index{ofstream@©ofstream©!©^?{}©}$
    3809 
    3810 // *********************************** ifstream ***********************************
    3811 
    3812 bool fail( ifstream & is );$\indexc{fail}\index{ifstream@©ifstream©!©fail©}$
    3813 void clear( ifstream & );$\indexc{clear}\index{ifstream@©ifstream©!©clear©}$
    3814 bool eof( ifstream & is );$\indexc{eof}\index{ifstream@©ifstream©!©eof©}$
    3815 void open( ifstream & is, const char name[], const char mode[] = "r" );$\indexc{open}\index{ifstream@©ifstream©!©open©}$
    3816 void close( ifstream & is );$\indexc{close}\index{ifstream@©ifstream©!©close©}$
    3817 ifstream & read( ifstream & is, char data[], size_t size );$\indexc{read}\index{ifstream@©ifstream©!©read©}$
    3818 ifstream & ungetc( ifstream & is, char c );$\indexc{unget}\index{ifstream@©ifstream©!©unget©}$
    3819 
    3820 void ?{}( ifstream & is );$\index{ifstream@©ifstream©!©?{}©}$
    3821 void ?{}( ifstream & is, const char name[], const char mode[] = "r" );
    3822 void ^?{}( ifstream & is );$\index{ifstream@©ifstream©!©^?{}©}$
    3823 \end{cfa}
    3824 \caption{Stream Functions}
    3825 \label{f:StreamFunctions}
    3826 \end{figure}
    38273700
    38283701
     
    39733846
    39743847\item
    3975 \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} toggle printing the separator with respect to the next printed item, and then return to the global separator setting.
     3848\Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} toggle printing the separator with respect to the next printed item, and then return to the global seperator setting.
    39763849\begin{cfa}[belowskip=0pt]
    39773850sout | 1 | sepOff | 2 | 3; $\C{// turn off implicit separator for the next item}$
     
    41574030sout | wd( 4, "ab" ) | wd( 3, "ab" ) | wd( 2, "ab" );
    41584031\end{cfa}
    4159 \begin{cfa}[showspaces=true,aboveskip=0pt]
     4032\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    41604033®  ®34 ® ®34 34
    41614034®  ®4.000000 ® ®4.000000 4.000000
     
    45054378\end{cfa}
    45064379
    4507 
    4508 \section{String Stream}
    4509 
    4510 All the stream formatting capabilities are available to format text to/from a C string rather than to a stream file.
    4511 \VRef[Figure]{f:StringStreamProcessing} shows writing (output) and reading (input) from a C string.
    4512 \begin{figure}
    4513 \begin{cfa}
    4514 #include <fstream.hfa>
    4515 #include <strstream.hfa>
    4516 
    4517 int main() {
    4518         enum { size = 256 };
    4519         char buf[size]; $\C{// output buffer}$
    4520         ®ostrstream osstr = { buf, size };® $\C{// bind output buffer/size}$
    4521         int i = 3, j = 5, k = 7;
    4522         double x = 12345678.9, y = 98765.4321e-11;
    4523 
    4524         osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); $\C{// same lines of output}$
    4525         write( osstr );
    4526         printf( "%s", buf );
    4527         sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));
    4528 
    4529         char buf2[] = "12 14 15 3.5 7e4"; $\C{// input buffer}$
    4530         ®istrstream isstr = { buf2 };®
    4531         isstr | i | j | k | x | y;
    4532         sout | i | j | k | x | y;
    4533 }
    4534 \end{cfa}
    4535 \caption{String Stream Processing}
    4536 \label{f:StringStreamProcessing}
    4537 \end{figure}
    4538 
    4539 \VRef[Figure]{f:StringStreamFunctions} shows the string stream operations.
    4540 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    4541 \item
    4542 \Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default).
    4543 \end{itemize}
    4544 The constructor functions:
    4545 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    4546 \item
    4547 create a bound stream to a write buffer (©ostrstream©) of ©size© or a read buffer (©istrstream©) containing a C string terminated with ©'\0'©.
    4548 \end{itemize}
    4549 
    4550 \begin{figure}
    4551 \begin{cfa}
    4552 // *********************************** ostrstream ***********************************
    4553 
    4554 ostrstream & write( ostrstream & os, FILE * stream = stdout );
    4555 
    4556 void ?{}( ostrstream &, char buf[], size_t size );
    4557 
    4558 // *********************************** istrstream ***********************************
    4559 
    4560 void ?{}( istrstream & is, char buf[] );
    4561 \end{cfa}
    4562 \caption{String Stream Functions}
    4563 \label{f:StringStreamFunctions}
    4564 \end{figure}
     4380\Textbf{WARNING:} ©printf©\index{printf@©printf©}, ©scanf©\index{scanf@©scanf©} and their derivatives are unsafe when used with user-level threading, as in \CFA.
     4381These stream routines use kernel-thread locking (©futex©\index{futex@©futex©}), which block kernel threads, to prevent interleaving of I/O.
     4382However, the following simple example illustrates how a deadlock can occur (other complex scenarios are possible).
     4383Assume a single kernel thread and two user-level threads calling ©printf©.
     4384One user-level thread acquires the I/O lock and is time-sliced while performing ©printf©.
     4385The other user-level thread then starts execution, calls ©printf©, and blocks the only kernel thread because it cannot acquire the I/O lock.
     4386It does not help if the kernel lock is multiple acquisition, \ie, the lock owner can acquire it multiple times, because it then results in two user threads in the ©printf© critical section, corrupting the stream.
    45654387
    45664388
     
    56605482\item
    56615483Package: a container to organize modules for distribution; It has attributes like name, author,
    5662 version, dependences, \etc.
    5663 \item
    5664 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, \etc.
     5484version, dependences, etc.
     5485\item
     5486Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, etc.
    56655487\end{itemize}
    56665488
     
    57995621
    58005622A package is defined by putting a project description file, Do.prj, with one or more modules into a directory.
    5801 This project description file contains the package's meta data, including package name, author, version, dependences, \etc.
     5623This project description file contains the package's meta data, including package name, author, version, dependences, etc.
    58025624It should be in the root of the package directory.
    58035625
     
    58565678Module: a container to organize a set of related types and methods; It has a module name, and several interfaces visible from outside
    58575679\item
    5858 Package: a container to organize modules for distribution; It has attributes like name, author, version, dependences, \etc.
    5859 \item
    5860 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, \etc.
     5680Package: a container to organize modules for distribution; It has attributes like name, author, version, dependences, etc.
     5681\item
     5682Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, etc.
    58615683\end{itemize}
    58625684
     
    82898111\begin{cquote}
    82908112\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    8291 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}   \\
     8113\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}}   \\
    82928114\hline
    82938115\begin{cfa}
    8294 #include <gmp.hfa>$\indexc{gmp}$
     8116#include <gmp>$\indexc{gmp}$
    82958117int main( void ) {
    82968118        sout | "Factorial Numbers";
  • libcfa/src/common.hfa

    r8d66610 r5407cdc  
    1010// Created On       : Wed Jul 11 17:54:36 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  5 14:02:04 2021
    13 // Update Count     : 18
     12// Last Modified On : Sat Aug 15 08:51:29 2020
     13// Update Count     : 14
    1414//
    1515
     
    6767
    6868static inline {
    69         char min( char v1, char v2 ) { return v1 < v2 ? v1 : v2; } // optimization
    70         int min( int v1, int v2 ) { return v1 < v2 ? v1 : v2; }
    71         unsigned int min( unsigned int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; }
    72         long int min( long int v1, long int v2 ) { return v1 < v2 ? v1 : v2; }
    73         unsigned long int min( unsigned long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; }
    74         long long int min( long long int v1, long long int v2 ) { return v1 < v2 ? v1 : v2; }
    75         unsigned long long int min( unsigned long long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; }
     69        char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization
     70        intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
     71        uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    7672        forall( T | { int ?<?( T, T ); } )
    77         T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; }
     73        T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
    7874
    79         char max( char v1, char v2 ) { return v1 > v2 ? v1 : v2; } // optimization
    80         int max( int v1, int v2 ) { return v1 > v2 ? v1 : v2; }
    81         unsigned int max( unsigned int v1, unsigned int v2 ) { return v1 > v2 ? v1 : v2; }
    82         long int max( long int v1, long int v2 ) { return v1 > v2 ? v1 : v2; }
    83         unsigned long int max( unsigned long int v1, unsigned long int v2 ) { return v1 > v2 ? v1 : v2; }
    84         long long int max( long long int v1, long long int v2 ) { return v1 > v2 ? v1 : v2; }
    85         unsigned long long int max( unsigned long long int v1, unsigned long long int v2 ) { return v1 > v2 ? v1 : v2; }
     75        char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization
     76        intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
     77        uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    8678        forall( T | { int ?>?( T, T ); } )
    87         T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; }
     79        T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
    8880
    8981        forall( T | { T min( T, T ); T max( T, T ); } )
  • libcfa/src/concurrency/alarm.cfa

    r8d66610 r5407cdc  
    3838
    3939void __kernel_set_timer( Duration alarm ) {
    40         alarm = max(alarm, 1`us);
    41         itimerval otv @= { 0 };
    42         getitimer( ITIMER_REAL, &otv );
    43         Duration od = { otv.it_value };
    44         if(od == 0 || od > alarm) {
    45                 setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p );
    46         }
     40        verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm`ns);
     41        setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p );
    4742}
    4843
     
    5146//=============================================================================================
    5247
    53 void ?{}( alarm_node_t & this, $thread * thrd, Duration alarm, Duration period) with( this ) {
    54         this.initial = alarm;
    55         this.period  = period;
     48void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period) with( this ) {
    5649        this.thrd = thrd;
    57         this.timeval = __kernel_get_time() + alarm;
     50        this.alarm = alarm;
     51        this.period = period;
    5852        set = false;
    5953        type = User;
    6054}
    6155
    62 void ?{}( alarm_node_t & this, processor * proc, Duration alarm, Duration period ) with( this ) {
    63         this.initial = alarm;
    64         this.period  = period;
     56void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ) with( this ) {
    6557        this.proc = proc;
    66         this.timeval = __kernel_get_time() + alarm;
     58        this.alarm = alarm;
     59        this.period = period;
    6760        set = false;
    6861        type = Kernel;
    6962}
    70 void ?{}( alarm_node_t & this, Alarm_Callback callback, Duration alarm, Duration period ) with( this ) {
     63void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ) with( this ) {
     64        this.alarm = alarm;
     65        this.period = period;
    7166        this.callback = callback;
    72         this.initial = alarm;
    73         this.period  = period;
    74         this.timeval = __kernel_get_time() + alarm;
    7567        set = false;
    7668        type = Callback;
     
    8577void insert( alarm_list_t * this, alarm_node_t * n ) {
    8678        alarm_node_t * it = & (*this)`first;
    87         while( it && (n->timeval > it->timeval) ) {
     79        while( it && (n->alarm > it->alarm) ) {
    8880                it = & (*it)`next;
    8981        }
     
    113105        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    114106        {
    115                 /* paranoid */ verify( validate( alarms ) );
     107                verify( validate( alarms ) );
     108                bool first = ! & alarms`first;
    116109
    117                 Time curr = __kernel_get_time();
    118                 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu -> %lu).\n", this, curr.tn, this->timeval.tn );
     110                __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn );
    119111                insert( &alarms, this );
    120                 __kernel_set_timer( this->timeval - curr);
    121                 this->set = true;
     112                if( first ) {
     113                        __kernel_set_timer( alarms`first.alarm - __kernel_get_time() );
     114                }
    122115        }
    123116        unlock( event_kernel->lock );
     117        this->set = true;
    124118        enable_interrupts();
    125119}
     
    130124        {
    131125                verify( validate( event_kernel->alarms ) );
    132                 if (this->set) remove( *this );
    133                 this->set = false;
     126                remove( *this );
    134127        }
    135128        unlock( event_kernel->lock );
    136129        enable_interrupts();
     130        this->set = false;
    137131}
    138132
     
    142136
    143137void sleep( Duration duration ) {
    144         alarm_node_t node = { active_thread(), duration, 0`s };
     138        alarm_node_t node = { active_thread(), __kernel_get_time() + duration, 0`s };
    145139
    146140        register_self( &node );
  • libcfa/src/concurrency/alarm.hfa

    r8d66610 r5407cdc  
    4646
    4747struct alarm_node_t {
    48         Duration initial;       // time when alarm goes off
    49         Duration period;        // if > 0 => period of alarm
     48        Time alarm;                             // time when alarm goes off
     49        Duration period;                        // if > 0 => period of alarm
    5050
    51         inline dlink(alarm_node_t);
     51        DLISTED_MGD_IMPL_IN(alarm_node_t)
    5252
    5353        union {
    54                 $thread * thrd;                 // thrd who created event
    55                 processor * proc;                       // proc who created event
    56                 Alarm_Callback callback;        // callback to handle event
     54                $thread * thrd;                                 // thrd who created event
     55                processor * proc;                               // proc who created event
     56                Alarm_Callback callback;                // callback to handle event
    5757        };
    5858
    59         Time timeval;           // actual time at which the alarm goes off
    60         enum alarm_type type;   // true if this is not a user defined alarm
    61         bool set                :1;     // whether or not the alarm has be registered
     59        bool set                :1;             // whether or not the alarm has be registered
     60        enum alarm_type type;           // true if this is not a user defined alarm
    6261};
    63 P9_EMBEDDED( alarm_node_t, dlink(alarm_node_t) )
     62DLISTED_MGD_IMPL_OUT(alarm_node_t)
    6463
    65 void ?{}( alarm_node_t & this, $thread * thrd, Duration alarm, Duration period );
    66 void ?{}( alarm_node_t & this, processor * proc, Duration alarm, Duration period );
    67 void ?{}( alarm_node_t & this, Alarm_Callback callback, Duration alarm, Duration period );
     64void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period );
     65void ?{}( alarm_node_t & this, processor   * proc, Time alarm, Duration period );
     66void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period );
    6867void ^?{}( alarm_node_t & this );
    6968
    70 typedef dlist(alarm_node_t) alarm_list_t;
     69typedef dlist(alarm_node_t, alarm_node_t) alarm_list_t;
    7170
    7271void insert( alarm_list_t * this, alarm_node_t * n );
  • libcfa/src/concurrency/clib/cfathread.cfa

    r8d66610 r5407cdc  
    2727      extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
    2828}
    29 
    30 extern Time __kernel_get_time();
    3129
    3230//================================================================================
     
    267265        int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))) {
    268266                Time t = { *abstime };
    269                 timespec curr;
    270                 clock_gettime( CLOCK_REALTIME, &curr );
    271                 Time c = { curr };
    272                 if( wait( (*cond)->impl, (*mut)->impl, t - c ) ) {
     267                if( wait( (*cond)->impl, (*mut)->impl, t ) ) {
    273268                        return 0;
    274269                }
  • libcfa/src/concurrency/clib/cfathread.h

    r8d66610 r5407cdc  
    8080
    8181        typedef struct cfathread_cond_attr {
    82                 // WARNING: adding support for pthread_condattr_setclock would require keeping track of the clock
    83                 // and reading it in cond_timedwait
    8482        } cfathread_condattr_t;
    8583        typedef struct cfathread_condition * cfathread_cond_t;
  • libcfa/src/concurrency/invoke.h

    r8d66610 r5407cdc  
    146146        struct __thread_desc_link {
    147147                struct $thread * next;
     148                struct $thread * prev;
    148149                volatile unsigned long long ts;
     150                unsigned preferred;
    149151        };
    150152
     
    153155                // context that is switch during a __cfactx_switch
    154156                struct __stack_context_t context;
    155 
    156                 // Link lists fields
    157                 // instrusive link field for threads
    158                 struct __thread_desc_link link;
    159157
    160158                // current execution status for coroutine
     
    172170                struct cluster * curr_cluster;
    173171
    174                 // preferred ready-queue
    175                 unsigned preferred;
     172                // Link lists fields
     173                // instrusive link field for threads
     174                struct __thread_desc_link link;
    176175
    177176                // coroutine body used to store context
  • libcfa/src/concurrency/io.cfa

    r8d66610 r5407cdc  
    138138                /* paranoid */ verify( proc->io.ctx );
    139139
    140                 __attribute__((unused)) cluster * cltr = proc->cltr;
    141140                $io_context & ctx = *proc->io.ctx;
    142 
    143                 // for(i; 2) {
    144                 //      unsigned idx = proc->rdq.id + i;
    145                 //      cltr->ready_queue.lanes.tscs[idx].tv = -1ull;
    146                 // }
    147141
    148142                __ioarbiter_flush( ctx );
     
    157151                                // Update statistics
    158152                                __STATS__( false, io.calls.errors.busy ++; )
    159                                 // for(i; 2) {
    160                                 //      unsigned idx = proc->rdq.id + i;
    161                                 //      cltr->ready_queue.lanes.tscs[idx].tv = rdtscl();
    162                                 // }
    163153                                return;
    164154                        default:
     
    182172
    183173                ctx.proc->io.pending = false;
    184 
    185                 ready_schedule_lock();
    186                 __cfa_io_drain( proc );
    187                 ready_schedule_unlock();
    188                 // for(i; 2) {
    189                 //      unsigned idx = proc->rdq.id + i;
    190                 //      cltr->ready_queue.lanes.tscs[idx].tv = rdtscl();
    191                 // }
    192174        }
    193175
  • libcfa/src/concurrency/kernel.cfa

    r8d66610 r5407cdc  
    163163        #if !defined(__CFA_NO_STATISTICS__)
    164164                if( this->print_halts ) {
    165                         __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->unique_id, this->name, (void*)this);
     165                        __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->id, this->name, (void*)this);
    166166                }
    167167        #endif
     
    170170                // Setup preemption data
    171171                preemption_scope scope = { this };
     172
     173                __STATS( unsigned long long last_tally = rdtscl(); )
    172174
    173175                // if we need to run some special setup, now is the time to do it.
     
    182184                MAIN_LOOP:
    183185                for() {
    184                         #define OLD_MAIN 1
    185                         #if OLD_MAIN
    186186                        // Check if there is pending io
    187187                        __maybe_io_drain( this );
     
    223223                                #if !defined(__CFA_NO_STATISTICS__)
    224224                                        if(this->print_halts) {
    225                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
     225                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
    226226                                        }
    227227                                #endif
     
    236236                                #if !defined(__CFA_NO_STATISTICS__)
    237237                                        if(this->print_halts) {
    238                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
     238                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
    239239                                        }
    240240                                #endif
     
    258258                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    259259
     260                        #if !defined(__CFA_NO_STATISTICS__)
     261                                unsigned long long curr = rdtscl();
     262                                if(curr > (last_tally + 500000000)) {
     263                                        __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats);
     264                                        last_tally = curr;
     265                                }
     266                        #endif
     267
    260268                        if(this->io.pending && !this->io.dirty) {
    261269                                __cfa_io_flush( this );
    262270                        }
    263271
    264                         #else
    265                                 #warning new kernel loop
    266                         SEARCH: {
    267                                 /* paranoid */ verify( ! __preemption_enabled() );
    268 
    269                                 // First, lock the scheduler since we are searching for a thread
    270                                 ready_schedule_lock();
    271 
    272                                 // Try to get the next thread
    273                                 readyThread = pop_fast( this->cltr );
    274                                 if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    275 
    276                                 // If we can't find a thread, might as well flush any outstanding I/O
    277                                 if(this->io.pending) { __cfa_io_flush( this ); }
    278 
    279                                 // Spin a little on I/O, just in case
    280                                         for(5) {
    281                                         __maybe_io_drain( this );
    282                                         readyThread = pop_fast( this->cltr );
    283                                         if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    284                                 }
    285 
    286                                 // no luck, try stealing a few times
    287                                         for(5) {
    288                                         if( __maybe_io_drain( this ) ) {
    289                                                 readyThread = pop_fast( this->cltr );
    290                                         } else {
    291                                                 readyThread = pop_slow( this->cltr );
    292                                         }
    293                                         if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    294                                 }
    295 
    296                                 // still no luck, search for a thread
    297                                 readyThread = pop_search( this->cltr );
    298                                 if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    299 
    300                                 // Don't block if we are done
    301                                 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    302 
    303                                 __STATS( __tls_stats()->ready.sleep.halts++; )
    304 
    305                                 // Push self to idle stack
    306                                 ready_schedule_unlock();
    307                                 mark_idle(this->cltr->procs, * this);
    308                                 ready_schedule_lock();
    309 
    310                                 // Confirm the ready-queue is empty
    311                                 __maybe_io_drain( this );
    312                                 readyThread = pop_search( this->cltr );
    313                                 ready_schedule_unlock();
    314 
    315                                 if( readyThread ) {
    316                                         // A thread was found, cancel the halt
    317                                         mark_awake(this->cltr->procs, * this);
    318 
    319                                         __STATS( __tls_stats()->ready.sleep.cancels++; )
    320 
    321                                         // continue the main loop
    322                                         break SEARCH;
    323                                 }
    324 
    325                                         __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
    326                                 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    327 
    328                                 // __disable_interrupts_hard();
    329                                 eventfd_t val;
    330                                 eventfd_read( this->idle, &val );
    331                                 // __enable_interrupts_hard();
    332 
    333                                         __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
    334 
    335                                 // We were woken up, remove self from idle
    336                                 mark_awake(this->cltr->procs, * this);
    337 
    338                                 // DON'T just proceed, start looking again
    339                                 continue MAIN_LOOP;
    340                         }
    341 
    342                 RUN_THREAD:
    343                         /* paranoid */ verify( ! __preemption_enabled() );
    344                         /* paranoid */ verify( readyThread );
    345 
    346                         // Reset io dirty bit
    347                         this->io.dirty = false;
    348 
    349                         // We found a thread run it
    350                         __run_thread(this, readyThread);
    351 
    352                         // Are we done?
    353                         if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    354 
    355                         if(this->io.pending && !this->io.dirty) {
    356                                 __cfa_io_flush( this );
    357                         }
    358 
    359                         ready_schedule_lock();
    360                         __maybe_io_drain( this );
    361                         ready_schedule_unlock();
    362                         #endif
     272                //      SEARCH: {
     273                //              /* paranoid */ verify( ! __preemption_enabled() );
     274                //              /* paranoid */ verify( kernelTLS().this_proc_id );
     275
     276                //              // First, lock the scheduler since we are searching for a thread
     277
     278                //              // Try to get the next thread
     279                //              ready_schedule_lock();
     280                //              readyThread = pop_fast( this->cltr );
     281                //              ready_schedule_unlock();
     282                //              if(readyThread) {  break SEARCH; }
     283
     284                //              // If we can't find a thread, might as well flush any outstanding I/O
     285                //              if(this->io.pending) { __cfa_io_flush( this ); }
     286
     287                //              // Spin a little on I/O, just in case
     288                //              for(25) {
     289                //                      __maybe_io_drain( this );
     290                //                      ready_schedule_lock();
     291                //                      readyThread = pop_fast( this->cltr );
     292                //                      ready_schedule_unlock();
     293                //                      if(readyThread) {  break SEARCH; }
     294                //              }
     295
     296                //              // no luck, try stealing a few times
     297                //              for(25) {
     298                //                      if( __maybe_io_drain( this ) ) {
     299                //                              ready_schedule_lock();
     300                //                              readyThread = pop_fast( this->cltr );
     301                //                      } else {
     302                //                              ready_schedule_lock();
     303                //                              readyThread = pop_slow( this->cltr );
     304                //                      }
     305                //                      ready_schedule_unlock();
     306                //                      if(readyThread) {  break SEARCH; }
     307                //              }
     308
     309                //              // still no luck, search for a thread
     310                //              ready_schedule_lock();
     311                //              readyThread = pop_search( this->cltr );
     312                //              ready_schedule_unlock();
     313                //              if(readyThread) { break SEARCH; }
     314
     315                //              // Don't block if we are done
     316                //              if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     317
     318                //              __STATS( __tls_stats()->ready.sleep.halts++; )
     319
     320                //              // Push self to idle stack
     321                //              mark_idle(this->cltr->procs, * this);
     322
     323                //              // Confirm the ready-queue is empty
     324                //              __maybe_io_drain( this );
     325                //              ready_schedule_lock();
     326                //              readyThread = pop_search( this->cltr );
     327                //              ready_schedule_unlock();
     328
     329                //              if( readyThread ) {
     330                //                      // A thread was found, cancel the halt
     331                //                      mark_awake(this->cltr->procs, * this);
     332
     333                //                      __STATS( __tls_stats()->ready.sleep.cancels++; )
     334
     335                //                      // continue the main loop
     336                //                      break SEARCH;
     337                //              }
     338
     339                //              __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); )
     340                //              __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
     341
     342                //              // __disable_interrupts_hard();
     343                //              eventfd_t val;
     344                //              eventfd_read( this->idle, &val );
     345                //              // __enable_interrupts_hard();
     346
     347                //              __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); )
     348
     349                //              // We were woken up, remove self from idle
     350                //              mark_awake(this->cltr->procs, * this);
     351
     352                //              // DON'T just proceed, start looking again
     353                //              continue MAIN_LOOP;
     354                //      }
     355
     356                // RUN_THREAD:
     357                //      /* paranoid */ verify( kernelTLS().this_proc_id );
     358                //      /* paranoid */ verify( ! __preemption_enabled() );
     359                //      /* paranoid */ verify( readyThread );
     360
     361                //      // Reset io dirty bit
     362                //      this->io.dirty = false;
     363
     364                //      // We found a thread run it
     365                //      __run_thread(this, readyThread);
     366
     367                //      // Are we done?
     368                //      if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     369
     370                //      #if !defined(__CFA_NO_STATISTICS__)
     371                //              unsigned long long curr = rdtscl();
     372                //              if(curr > (last_tally + 500000000)) {
     373                //                      __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats);
     374                //                      last_tally = curr;
     375                //              }
     376                //      #endif
     377
     378                //      if(this->io.pending && !this->io.dirty) {
     379                //              __cfa_io_flush( this );
     380                //      }
     381
     382                //      // Check if there is pending io
     383                //      __maybe_io_drain( this );
    363384                }
    364385
     
    369390
    370391        post( this->terminated );
     392
    371393
    372394        if(this == mainProcessor) {
     
    531553static void __schedule_thread( $thread * thrd ) {
    532554        /* paranoid */ verify( ! __preemption_enabled() );
     555        /* paranoid */ verify( kernelTLS().this_proc_id );
    533556        /* paranoid */ verify( ready_schedule_islocked());
    534557        /* paranoid */ verify( thrd );
     
    544567        /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    545568
    546         const bool local = thrd->state != Start;
     569
    547570        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    548571
     
    552575
    553576        // push the thread to the cluster ready-queue
    554         push( cl, thrd, local );
     577        push( cl, thrd );
    555578
    556579        // variable thrd is no longer safe to use
     
    588611static inline $thread * __next_thread(cluster * this) with( *this ) {
    589612        /* paranoid */ verify( ! __preemption_enabled() );
     613        /* paranoid */ verify( kernelTLS().this_proc_id );
    590614
    591615        ready_schedule_lock();
     
    593617        ready_schedule_unlock();
    594618
     619        /* paranoid */ verify( kernelTLS().this_proc_id );
    595620        /* paranoid */ verify( ! __preemption_enabled() );
    596621        return thrd;
     
    600625static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    601626        /* paranoid */ verify( ! __preemption_enabled() );
     627        /* paranoid */ verify( kernelTLS().this_proc_id );
    602628
    603629        ready_schedule_lock();
     
    612638        ready_schedule_unlock();
    613639
     640        /* paranoid */ verify( kernelTLS().this_proc_id );
    614641        /* paranoid */ verify( ! __preemption_enabled() );
    615642        return thrd;
     
    868895                unsigned tail = *ctx->cq.tail;
    869896                if(head == tail) return false;
    870                 #if OLD_MAIN
    871897                ready_schedule_lock();
    872898                ret = __cfa_io_drain( proc );
    873899                ready_schedule_unlock();
    874                 #else
    875                         ret = __cfa_io_drain( proc );
    876         #endif
    877900        #endif
    878901        return ret;
     
    903926        }
    904927
    905         static void crawl_list( cluster * cltr, dlist(processor) & list, unsigned count ) {
    906                 /* paranoid */ verify( cltr->stats );
    907 
    908                 processor * it = &list`first;
    909                 for(unsigned i = 0; i < count; i++) {
    910                         /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    911                         /* paranoid */ verify( it->local_data->this_stats );
    912                         __tally_stats( cltr->stats, it->local_data->this_stats );
    913                         it = &(*it)`next;
    914                 }
    915         }
    916 
    917         void crawl_cluster_stats( cluster & this ) {
    918                 // Stop the world, otherwise stats could get really messed-up
    919                 // this doesn't solve all problems but does solve many
    920                 // so it's probably good enough
    921                 uint_fast32_t last_size = ready_mutate_lock();
    922 
    923                         crawl_list(&this, this.procs.actives, this.procs.total - this.procs.idle);
    924                         crawl_list(&this, this.procs.idles  , this.procs.idle );
    925 
    926                 // Unlock the RWlock
    927                 ready_mutate_unlock( last_size );
    928         }
    929 
    930 
    931928        void print_stats_now( cluster & this, int flags ) {
    932                 crawl_cluster_stats( this );
    933929                __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    934930        }
  • libcfa/src/concurrency/kernel.hfa

    r8d66610 r5407cdc  
    4949
    5050// Processor id, required for scheduling threads
    51 
     51struct __processor_id_t {
     52        unsigned id:24;
     53
     54        #if !defined(__CFA_NO_STATISTICS__)
     55                struct __stats_t * stats;
     56        #endif
     57};
    5258
    5359coroutine processorCtx_t {
     
    5763// Wrapper around kernel threads
    5864struct __attribute__((aligned(128))) processor {
     65        // Main state
     66        inline __processor_id_t;
     67
    5968        // Cluster from which to get threads
    6069        struct cluster * cltr;
     
    8190        pthread_t kernel_thread;
    8291
    83         // Unique id for the processor (not per cluster)
    84         unsigned unique_id;
    85 
    8692        struct {
    8793                $io_context * ctx;
     
    107113
    108114        // Link lists fields
    109         inline dlink(processor);
     115        DLISTED_MGD_IMPL_IN(processor)
    110116
    111117        // special init fields
     
    117123        } init;
    118124
    119         struct KernelThreadData * local_data;
    120 
    121125        #if !defined(__CFA_NO_STATISTICS__)
    122126                int print_stats;
     
    129133#endif
    130134};
    131 P9_EMBEDDED( processor, dlink(processor) )
    132135
    133136void  ?{}(processor & this, const char name[], struct cluster & cltr);
     
    137140static inline void  ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; }
    138141static inline void  ?{}(processor & this, const char name[])     { this{name, *mainCluster}; }
     142
     143DLISTED_MGD_IMPL_OUT(processor)
    139144
    140145//-----------------------------------------------------------------------------
     
    147152
    148153// Aligned timestamps which are used by the relaxed ready queue
    149 struct __attribute__((aligned(128))) __timestamp_t {
    150         volatile unsigned long long tv;
    151 };
    152 
    153 static inline void  ?{}(__timestamp_t & this) { this.tv = 0; }
    154 static inline void ^?{}(__timestamp_t & this) {}
     154struct __attribute__((aligned(128))) __timestamp_t;
     155void  ?{}(__timestamp_t & this);
     156void ^?{}(__timestamp_t & this);
    155157
    156158//TODO adjust cache size to ARCHITECTURE
     
    175177void  ?{}(__ready_queue_t & this);
    176178void ^?{}(__ready_queue_t & this);
    177 #if !defined(__CFA_NO_STATISTICS__)
    178         unsigned cnt(const __ready_queue_t & this, unsigned idx);
    179 #endif
    180179
    181180// Idle Sleep
     
    191190
    192191        // List of idle processors
    193         dlist(processor) idles;
     192        dlist(processor, processor) idles;
    194193
    195194        // List of active processors
    196         dlist(processor) actives;
     195        dlist(processor, processor) actives;
    197196};
    198197
  • libcfa/src/concurrency/kernel/fwd.hfa

    r8d66610 r5407cdc  
    3838                        struct $thread          * volatile this_thread;
    3939                        struct processor        * volatile this_processor;
    40                         volatile bool sched_lock;
     40                        struct __processor_id_t * volatile this_proc_id;
     41                        struct __stats_t        * volatile this_stats;
    4142
    4243                        struct {
     
    5556                                uint64_t bck_seed;
    5657                        } ready_rng;
    57 
    58                         struct __stats_t        * volatile this_stats;
    59 
    60 
    61                         #ifdef __CFA_WITH_VERIFY__
    62                                 // Debug, check if the rwlock is owned for reading
    63                                 bool in_sched_lock;
    64                                 unsigned sched_id;
    65                         #endif
    6658                } __cfaabi_tls __attribute__ ((tls_model ( "initial-exec" )));
    6759
  • libcfa/src/concurrency/kernel/startup.cfa

    r8d66610 r5407cdc  
    7777static void doregister( struct cluster & cltr );
    7878static void unregister( struct cluster & cltr );
    79 static void register_tls( processor * this );
    80 static void unregister_tls( processor * this );
    8179static void ?{}( $coroutine & this, current_stack_info_t * info);
    8280static void ?{}( $thread & this, current_stack_info_t * info);
     
    125123        NULL,                                                                                           // cannot use 0p
    126124        NULL,
    127         false,
     125        NULL,
     126        NULL,
    128127        { 1, false, false },
    129         0,
    130         { 0, 0 },
    131         NULL,
    132         #ifdef __CFA_WITH_VERIFY__
    133                 false,
    134                 0,
    135         #endif
    136128};
    137129
     
    218210        (*mainProcessor){};
    219211
    220         register_tls( mainProcessor );
    221 
    222212        //initialize the global state variables
    223213        __cfaabi_tls.this_processor = mainProcessor;
     214        __cfaabi_tls.this_proc_id   = (__processor_id_t*)mainProcessor;
    224215        __cfaabi_tls.this_thread    = mainThread;
    225216
     
    228219                __init_stats( __cfaabi_tls.this_stats );
    229220        #endif
    230         mainProcessor->local_data = &__cfaabi_tls;
    231221
    232222        // Enable preemption
     
    283273        #endif
    284274
    285         mainProcessor->local_data = 0p;
    286 
    287         unregister_tls( mainProcessor );
    288 
    289275        // Destroy the main processor and its context in reverse order of construction
    290276        // These were manually constructed so we need manually destroy them
     
    330316        processor * proc = (processor *) arg;
    331317        __cfaabi_tls.this_processor = proc;
     318        __cfaabi_tls.this_proc_id   = (__processor_id_t*)proc;
    332319        __cfaabi_tls.this_thread    = 0p;
    333320        __cfaabi_tls.preemption_state.[enabled, disable_count] = [false, 1];
    334         proc->local_data = &__cfaabi_tls;
    335 
    336         register_tls( proc );
    337 
    338321        // SKULLDUGGERY: We want to create a context for the processor coroutine
    339322        // which is needed for the 2-step context switch. However, there is no reason
     
    372355                #endif
    373356        #endif
    374 
    375         proc->local_data = 0p;
    376 
    377         unregister_tls( proc );
    378357
    379358        return 0p;
     
    467446        self_mon_p = &self_mon;
    468447        link.next = 0p;
    469         link.ts   = 0;
    470         preferred = -1u;
     448        link.prev = 0p;
     449        link.preferred = -1u;
    471450        last_proc = 0p;
    472451        #if defined( __CFA_WITH_VERIFY__ )
     
    496475        this.rdq.id  = -1u;
    497476        this.rdq.target = -1u;
    498         this.rdq.cutoff = 0ull;
     477        this.rdq.cutoff = -1ull;
    499478        do_terminate = false;
    500479        preemption_alarm = 0p;
     
    506485
    507486        this.init.thrd = initT;
    508 
    509         this.local_data = 0p;
    510487
    511488        this.idle = eventfd(0, 0);
     
    519496        #endif
    520497
     498        // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue
     499        uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this);
     500                this.cltr->procs.total += 1u;
     501                insert_last(this.cltr->procs.actives, this);
     502
     503                // Adjust the ready queue size
     504                ready_queue_grow( cltr );
     505
     506        // Unlock the RWlock
     507        ready_mutate_unlock( last_size );
     508
    521509        __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
    522510}
     
    524512// Not a ctor, it just preps the destruction but should not destroy members
    525513static void deinit(processor & this) {
     514        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     515        uint_fast32_t last_size = ready_mutate_lock();
     516                this.cltr->procs.total -= 1u;
     517                remove(this);
     518
     519                // Adjust the ready queue size
     520                ready_queue_shrink( this.cltr );
     521
     522        // Unlock the RWlock and unregister: we don't need the read_lock any more
     523        ready_mutate_unregister((__processor_id_t*)&this, last_size );
     524
    526525        close(this.idle);
    527526}
     
    657656        cltr->nthreads -= 1;
    658657        unlock(cltr->thread_list_lock);
    659 }
    660 
    661 static void register_tls( processor * this ) {
    662         // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue
    663         uint_fast32_t last_size;
    664         [this->unique_id, last_size] = ready_mutate_register();
    665 
    666                 this->cltr->procs.total += 1u;
    667                 insert_last(this->cltr->procs.actives, *this);
    668 
    669                 // Adjust the ready queue size
    670                 ready_queue_grow( this->cltr );
    671 
    672         // Unlock the RWlock
    673         ready_mutate_unlock( last_size );
    674 }
    675 
    676 
    677 static void unregister_tls( processor * this ) {
    678         // Lock the RWlock so no-one pushes/pops while we are changing the queue
    679         uint_fast32_t last_size = ready_mutate_lock();
    680                 this->cltr->procs.total -= 1u;
    681                 remove(*this);
    682 
    683                 // clear the cluster so nothing gets pushed to local queues
    684                 cluster * cltr = this->cltr;
    685                 this->cltr = 0p;
    686 
    687                 // Adjust the ready queue size
    688                 ready_queue_shrink( cltr );
    689 
    690         // Unlock the RWlock and unregister: we don't need the read_lock any more
    691         ready_mutate_unregister( this->unique_id, last_size );
    692658}
    693659
  • libcfa/src/concurrency/kernel_private.hfa

    r8d66610 r5407cdc  
    2525// Scheduler
    2626
     27struct __attribute__((aligned(128))) __scheduler_lock_id_t;
    2728
    2829extern "C" {
     
    7980// Lock-Free registering/unregistering of threads
    8081// Register a processor to a given cluster and get its unique id in return
    81 unsigned register_proc_id( void );
     82void register_proc_id( struct __processor_id_t * );
    8283
    8384// Unregister a processor from a given cluster using its id, getting back the original pointer
    84 void unregister_proc_id( unsigned );
     85void unregister_proc_id( struct __processor_id_t * proc );
    8586
    8687//=======================================================================
     
    111112}
    112113
    113 
    114 
    115 
     114// Cells use by the reader writer lock
     115// while not generic it only relies on a opaque pointer
     116struct __attribute__((aligned(128))) __scheduler_lock_id_t {
     117        // Spin lock used as the underlying lock
     118        volatile bool lock;
     119
     120        // Handle pointing to the proc owning this cell
     121        // Used for allocating cells and debugging
     122        __processor_id_t * volatile handle;
     123
     124        #ifdef __CFA_WITH_VERIFY__
     125                // Debug, check if this is owned for reading
     126                bool owned;
     127        #endif
     128};
     129
     130static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    116131
    117132//-----------------------------------------------------------------------
     
    132147
    133148        // writer lock
    134         volatile bool write_lock;
     149        volatile bool lock;
    135150
    136151        // data pointer
    137         volatile bool * volatile * data;
     152        __scheduler_lock_id_t * data;
    138153};
    139154
     
    148163static inline void ready_schedule_lock(void) with(*__scheduler_lock) {
    149164        /* paranoid */ verify( ! __preemption_enabled() );
    150         /* paranoid */ verify( ! kernelTLS().in_sched_lock );
    151         /* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock );
    152         /* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id );
     165        /* paranoid */ verify( kernelTLS().this_proc_id );
     166
     167        unsigned iproc = kernelTLS().this_proc_id->id;
     168        /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id);
     169        /*paranoid*/ verify(iproc < ready);
    153170
    154171        // Step 1 : make sure no writer are in the middle of the critical section
    155         while(__atomic_load_n(&write_lock, (int)__ATOMIC_RELAXED))
     172        while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED))
    156173                Pause();
    157174
     
    162179
    163180        // Step 2 : acquire our local lock
    164         __atomic_acquire( &kernelTLS().sched_lock );
    165         /*paranoid*/ verify(kernelTLS().sched_lock);
     181        __atomic_acquire( &data[iproc].lock );
     182        /*paranoid*/ verify(data[iproc].lock);
    166183
    167184        #ifdef __CFA_WITH_VERIFY__
    168185                // Debug, check if this is owned for reading
    169                 kernelTLS().in_sched_lock = true;
     186                data[iproc].owned = true;
    170187        #endif
    171188}
     
    173190static inline void ready_schedule_unlock(void) with(*__scheduler_lock) {
    174191        /* paranoid */ verify( ! __preemption_enabled() );
    175         /* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock );
    176         /* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id );
    177         /* paranoid */ verify( kernelTLS().sched_lock );
    178         /* paranoid */ verify( kernelTLS().in_sched_lock );
     192        /* paranoid */ verify( kernelTLS().this_proc_id );
     193
     194        unsigned iproc = kernelTLS().this_proc_id->id;
     195        /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id);
     196        /*paranoid*/ verify(iproc < ready);
     197        /*paranoid*/ verify(data[iproc].lock);
     198        /*paranoid*/ verify(data[iproc].owned);
    179199        #ifdef __CFA_WITH_VERIFY__
    180200                // Debug, check if this is owned for reading
    181                 kernelTLS().in_sched_lock = false;
     201                data[iproc].owned = false;
    182202        #endif
    183         __atomic_unlock(&kernelTLS().sched_lock);
     203        __atomic_unlock(&data[iproc].lock);
    184204}
    185205
     
    187207        static inline bool ready_schedule_islocked(void) {
    188208                /* paranoid */ verify( ! __preemption_enabled() );
    189                 /* paranoid */ verify( (!kernelTLS().in_sched_lock) || kernelTLS().sched_lock );
    190                 return kernelTLS().sched_lock;
     209                /*paranoid*/ verify( kernelTLS().this_proc_id );
     210                __processor_id_t * proc = kernelTLS().this_proc_id;
     211                return __scheduler_lock->data[proc->id].owned;
    191212        }
    192213
    193214        static inline bool ready_mutate_islocked() {
    194                 return __scheduler_lock->write_lock;
     215                return __scheduler_lock->lock;
    195216        }
    196217#endif
     
    207228// Register a processor to a given cluster and get its unique id in return
    208229// For convenience, also acquires the lock
    209 static inline [unsigned, uint_fast32_t] ready_mutate_register() {
    210         unsigned id = register_proc_id();
    211         uint_fast32_t last = ready_mutate_lock();
    212         return [id, last];
     230static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {
     231        register_proc_id( proc );
     232        return ready_mutate_lock();
    213233}
    214234
    215235// Unregister a processor from a given cluster using its id, getting back the original pointer
    216236// assumes the lock is acquired
    217 static inline void ready_mutate_unregister( unsigned id, uint_fast32_t last_s ) {
     237static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {
    218238        ready_mutate_unlock( last_s );
    219         unregister_proc_id( id );
     239        unregister_proc_id( proc );
    220240}
    221241
     
    261281// push thread onto a ready queue for a cluster
    262282// returns true if the list was previously empty, false otherwise
    263 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd, bool local);
     283__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
    264284
    265285//-----------------------------------------------------------------------
  • libcfa/src/concurrency/locks.cfa

    r8d66610 r5407cdc  
    188188                alarm_node_t alarm_node;
    189189                condition_variable(L) * cond;
    190                 info_thread(L) * info_thd;
     190                info_thread(L) * i;
    191191        };
    192192
    193         void ?{}( alarm_node_wrap(L) & this, Duration alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) {
     193        void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) {
    194194                this.alarm_node{ callback, alarm, period };
    195195                this.cond = c;
    196                 this.info_thd = i;
     196                this.i = i;
    197197        }
    198198
     
    206206                //      may still be called after a thread has been removed from the queue but
    207207                //      before the alarm is unregistered
    208                 if ( listed(info_thd) ) {       // is thread on queue
    209                         info_thd->signalled = false;
     208                if ( listed(i) ) {      // is thread on queue
     209                        i->signalled = false;
    210210                        // remove this thread O(1)
    211                         remove( cond->blocked_threads, *info_thd );
     211                        remove( cond->blocked_threads, *i );
    212212                        cond->count--;
    213                         if( info_thd->lock ) {
     213                        if( i->lock ) {
    214214                                // call lock's on_notify if a lock was passed
    215                                 on_notify(*info_thd->lock, info_thd->t);
     215                                on_notify(*i->lock, i->t);
    216216                        } else {
    217217                                // otherwise wake thread
    218                                 unpark( info_thd->t );
     218                                unpark( i->t );
    219219                        }
    220220                }
     
    313313
    314314        // helper for wait()'s' with a timeout
    315         void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
     315        void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) {
    316316                lock( lock __cfaabi_dbg_ctx2 );
    317317                size_t recursion_count = queue_and_get_recursion(this, &info);
    318                 alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
     318                alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast, &this, &info };
    319319                register_self( &node_wrap.alarm_node );
    320320                unlock( lock );
     
    332332        #define WAIT_TIME( u, l, t ) \
    333333                info_thread( L ) i = { active_thread(), u, l }; \
    334                 queue_info_thread_timeout(this, i, t, alarm_node_wrap_cast ); \
     334                queue_info_thread_timeout(this, i, t ); \
    335335                return i.signalled;
    336336
     
    340340        void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { WAIT( info, &l ) }
    341341
    342         bool wait( condition_variable(L) & this, Duration duration                        ) with(this) { WAIT_TIME( 0   , 0p , duration ) }
    343         bool wait( condition_variable(L) & this, uintptr_t info, Duration duration        ) with(this) { WAIT_TIME( info, 0p , duration ) }
    344         bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , duration ) }
    345         bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , duration ) }
     342        bool wait( condition_variable(L) & this, Duration duration                        ) with(this) { WAIT_TIME( 0   , 0p , __kernel_get_time() + duration ) }
     343        bool wait( condition_variable(L) & this, uintptr_t info, Duration duration        ) with(this) { WAIT_TIME( info, 0p , __kernel_get_time() + duration ) }
     344        bool wait( condition_variable(L) & this, Time time                                ) with(this) { WAIT_TIME( 0   , 0p , time ) }
     345        bool wait( condition_variable(L) & this, uintptr_t info, Time time                ) with(this) { WAIT_TIME( info, 0p , time ) }
     346        bool wait( condition_variable(L) & this, L & l, Duration duration                 ) with(this) { WAIT_TIME( 0   , &l , __kernel_get_time() + duration ) }
     347        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , __kernel_get_time() + duration ) }
     348        bool wait( condition_variable(L) & this, L & l, Time time                         ) with(this) { WAIT_TIME( 0   , &l , time ) }
     349        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time         ) with(this) { WAIT_TIME( info, &l , time ) }
    346350}
    347351
  • libcfa/src/concurrency/locks.hfa

    r8d66610 r5407cdc  
    290290        bool wait( condition_variable(L) & this, Duration duration );
    291291        bool wait( condition_variable(L) & this, uintptr_t info, Duration duration );
     292        bool wait( condition_variable(L) & this, Time time );
     293        bool wait( condition_variable(L) & this, uintptr_t info, Time time );
    292294
    293295        void wait( condition_variable(L) & this, L & l );
     
    295297        bool wait( condition_variable(L) & this, L & l, Duration duration );
    296298        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
    297 }
     299        bool wait( condition_variable(L) & this, L & l, Time time );
     300        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
     301}
  • libcfa/src/concurrency/preemption.cfa

    r8d66610 r5407cdc  
    1818
    1919#include "preemption.hfa"
    20 
    2120#include <assert.h>
    2221
     
    2726#include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2827
    29 #include "bits/debug.hfa"
    3028#include "bits/signal.hfa"
    3129#include "kernel_private.hfa"
     
    107105static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) {
    108106        if( ! & (*alarms)`first ) return 0p;                                            // If no alarms return null
    109         if( (*alarms)`first.timeval >= currtime ) return 0p;    // If alarms head not expired return null
     107        if( (*alarms)`first.alarm >= currtime ) return 0p;      // If alarms head not expired return null
    110108        return pop(alarms);                                                                     // Otherwise just pop head
    111109}
     
    143141                if( period > 0 ) {
    144142                        __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns );
    145                         node->timeval = currtime + period;  // Alarm is periodic, add currtime to it (used cached current time)
     143                        node->alarm = currtime + period;    // Alarm is periodic, add currtime to it (used cached current time)
    146144                        insert( alarms, node );             // Reinsert the node for the next time it triggers
    147145                }
     
    150148        // If there are still alarms pending, reset the timer
    151149        if( & (*alarms)`first ) {
    152                 Duration delta = (*alarms)`first.timeval - currtime;
    153                 __kernel_set_timer( delta );
     150                Duration delta = (*alarms)`first.alarm - currtime;
     151                Duration capped = max(delta, 50`us);
     152                __kernel_set_timer( capped );
    154153        }
    155154}
     
    161160        // Alarms need to be enabled
    162161        if ( duration > 0 && ! alarm->set ) {
    163                 alarm->initial = duration;
    164                 alarm->period  = duration;
     162                alarm->alarm = __kernel_get_time() + duration;
     163                alarm->period = duration;
    165164                register_self( alarm );
    166165        }
     
    168167        else if ( duration == 0 && alarm->set ) {
    169168                unregister_self( alarm );
    170                 alarm->initial = 0;
    171                 alarm->period  = 0;
     169                alarm->alarm = 0;
     170                alarm->period = 0;
    172171        }
    173172        // If alarm is different from previous, change it
    174173        else if ( duration > 0 && alarm->period != duration ) {
    175174                unregister_self( alarm );
    176                 alarm->initial = duration;
    177                 alarm->period  = duration;
     175                alarm->alarm = __kernel_get_time() + duration;
     176                alarm->period = duration;
    178177                register_self( alarm );
    179178        }
     
    600599
    601600        // Notify the alarm thread of the shutdown
    602         sigval val;
    603         val.sival_int = 0;
     601        sigval val = { 1 };
    604602        pthread_sigqueue( alarm_thread, SIGALRM, val );
    605603
     
    621619// Used by thread to control when they want to receive preemption signals
    622620void ?{}( preemption_scope & this, processor * proc ) {
    623         (this.alarm){ proc, 0`s, 0`s };
     621        (this.alarm){ proc, (Time){ 0 }, 0`s };
    624622        this.proc = proc;
    625623        this.proc->preemption_alarm = &this.alarm;
     
    689687// Waits on SIGALRM and send SIGUSR1 to whom ever needs it
    690688static void * alarm_loop( __attribute__((unused)) void * args ) {
    691         unsigned id = register_proc_id();
     689        __processor_id_t id;
     690        register_proc_id(&id);
     691        __cfaabi_tls.this_proc_id = &id;
     692
    692693
    693694        // Block sigalrms to control when they arrive
     
    706707                siginfo_t info;
    707708                int sig = sigwaitinfo( &mask, &info );
    708 
    709                 __cfadbg_print_buffer_decl ( preemption, " KERNEL: sigwaitinfo returned %d, c: %d, v: %d\n", sig, info.si_code, info.si_value.sival_int );
    710                 __cfadbg_print_buffer_local( preemption, " KERNEL: SI_QUEUE %d, SI_TIMER %d, SI_KERNEL %d\n", SI_QUEUE, SI_TIMER, SI_KERNEL );
    711709
    712710                if( sig < 0 ) {
     
    716714                                case EAGAIN :
    717715                                case EINTR :
    718                                         {__cfadbg_print_buffer_local( preemption, " KERNEL: Spurious wakeup %d.\n", err );}
     716                                        {__cfaabi_dbg_print_buffer_decl( " KERNEL: Spurious wakeup %d.\n", err );}
    719717                                        continue;
    720718                                case EINVAL :
     
    728726                assertf(sig == SIGALRM, "Kernel Internal Error, sigwait: Unexpected signal %d (%d : %d)\n", sig, info.si_code, info.si_value.sival_int);
    729727
     728                // __cfaabi_dbg_print_safe( "Kernel : Caught alarm from %d with %d\n", info.si_code, info.si_value.sival_int );
    730729                // Switch on the code (a.k.a. the sender) to
    731730                switch( info.si_code )
    732731                {
    733                 // Signal was not sent by the kernel but by an other thread
    734                 case SI_QUEUE:
    735                         // other threads may signal the alarm thread to shut it down
    736                         // or to manual cause the preemption tick
    737                         // use info.si_value and handle the case here
    738                         switch( info.si_value.sival_int ) {
    739                         case 0:
    740                                 goto EXIT;
    741                         default:
    742                                 abort( "SI_QUEUE with val %d", info.si_value.sival_int);
    743                         }
    744                         // fallthrough
    745732                // Timers can apparently be marked as sent for the kernel
    746733                // In either case, tick preemption
     
    752739                        unlock( event_kernel->lock );
    753740                        break;
     741                // Signal was not sent by the kernel but by an other thread
     742                case SI_QUEUE:
     743                        // For now, other thread only signal the alarm thread to shut it down
     744                        // If this needs to change use info.si_value and handle the case here
     745                        goto EXIT;
    754746                }
    755747        }
     
    757749EXIT:
    758750        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    759         unregister_proc_id(id);
     751        register_proc_id(&id);
    760752
    761753        return 0p;
  • libcfa/src/concurrency/ready_queue.cfa

    r8d66610 r5407cdc  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
     19// #define USE_MPSC
    1920
    2021#define USE_RELAXED_FIFO
     
    9293        this.alloc = 0;
    9394        this.ready = 0;
     95        this.lock  = false;
    9496        this.data  = alloc(this.max);
    95         this.write_lock  = false;
    96 
     97
     98        /*paranoid*/ verify( 0 == (((uintptr_t)(this.data    )) % 64) );
     99        /*paranoid*/ verify( 0 == (((uintptr_t)(this.data + 1)) % 64) );
    97100        /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.alloc), &this.alloc));
    98101        /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.ready), &this.ready));
     
    103106}
    104107
     108void ?{}( __scheduler_lock_id_t & this, __processor_id_t * proc ) {
     109        this.handle = proc;
     110        this.lock   = false;
     111        #ifdef __CFA_WITH_VERIFY__
     112                this.owned  = false;
     113        #endif
     114}
    105115
    106116//=======================================================================
    107117// Lock-Free registering/unregistering of threads
    108 unsigned register_proc_id( void ) with(*__scheduler_lock) {
     118void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    109119        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
    110         bool * handle = (bool *)&kernelTLS().sched_lock;
    111120
    112121        // Step - 1 : check if there is already space in the data
     
    115124        // Check among all the ready
    116125        for(uint_fast32_t i = 0; i < s; i++) {
    117                 bool * volatile * cell = (bool * volatile *)&data[i]; // Cforall is bugged and the double volatiles causes problems
    118                 /* paranoid */ verify( handle != *cell );
    119 
    120                 bool * null = 0p; // Re-write every loop since compare thrashes it
    121                 if( __atomic_load_n(cell, (int)__ATOMIC_RELAXED) == null
    122                         && __atomic_compare_exchange_n( cell, &null, handle, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    123                         /* paranoid */ verify(i < ready);
    124                         /* paranoid */ verify( (kernelTLS().sched_id = i, true) );
    125                         return i;
     126                __processor_id_t * null = 0p; // Re-write every loop since compare thrashes it
     127                if( __atomic_load_n(&data[i].handle, (int)__ATOMIC_RELAXED) == null
     128                        && __atomic_compare_exchange_n( &data[i].handle, &null, proc, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     129                        /*paranoid*/ verify(i < ready);
     130                        /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
     131                        /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
     132                        proc->id = i;
    126133                }
    127134        }
     
    134141
    135142        // Step - 3 : Mark space as used and then publish it.
    136         data[n] = handle;
     143        __scheduler_lock_id_t * storage = (__scheduler_lock_id_t *)&data[n];
     144        (*storage){ proc };
    137145        while() {
    138146                unsigned copy = n;
     
    146154
    147155        // Return new spot.
    148         /* paranoid */ verify(n < ready);
    149         /* paranoid */ verify( (kernelTLS().sched_id = n, true) );
    150         return n;
    151 }
    152 
    153 void unregister_proc_id( unsigned id ) with(*__scheduler_lock) {
    154         /* paranoid */ verify(id < ready);
    155         /* paranoid */ verify(id == kernelTLS().sched_id);
    156         /* paranoid */ verify(data[id] == &kernelTLS().sched_lock);
    157 
    158         bool * volatile * cell = (bool * volatile *)&data[id]; // Cforall is bugged and the double volatiles causes problems
    159 
    160         __atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
     156        /*paranoid*/ verify(n < ready);
     157        /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
     158        /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
     159        proc->id = n;
     160}
     161
     162void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     163        unsigned id = proc->id;
     164        /*paranoid*/ verify(id < ready);
     165        /*paranoid*/ verify(proc == __atomic_load_n(&data[id].handle, __ATOMIC_RELAXED));
     166        __atomic_store_n(&data[id].handle, 0p, __ATOMIC_RELEASE);
    161167
    162168        __cfadbg_print_safe(ready_queue, "Kernel : Unregister proc %p\n", proc);
     
    168174uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
    169175        /* paranoid */ verify( ! __preemption_enabled() );
    170         /* paranoid */ verify( ! kernelTLS().sched_lock );
    171176
    172177        // Step 1 : lock global lock
    173178        // It is needed to avoid processors that register mid Critical-Section
    174179        //   to simply lock their own lock and enter.
    175         __atomic_acquire( &write_lock );
     180        __atomic_acquire( &lock );
    176181
    177182        // Step 2 : lock per-proc lock
     
    181186        uint_fast32_t s = ready;
    182187        for(uint_fast32_t i = 0; i < s; i++) {
    183                 volatile bool * llock = data[i];
    184                 if(llock) __atomic_acquire( llock );
     188                __atomic_acquire( &data[i].lock );
    185189        }
    186190
     
    199203        // Alternative solution : return s in write_lock and pass it to write_unlock
    200204        for(uint_fast32_t i = 0; i < last_s; i++) {
    201                 volatile bool * llock = data[i];
    202                 if(llock) __atomic_store_n(llock, (bool)false, __ATOMIC_RELEASE);
     205                verify(data[i].lock);
     206                __atomic_store_n(&data[i].lock, (bool)false, __ATOMIC_RELEASE);
    203207        }
    204208
    205209        // Step 2 : release global lock
    206         /*paranoid*/ assert(true == write_lock);
    207         __atomic_store_n(&write_lock, (bool)false, __ATOMIC_RELEASE);
     210        /*paranoid*/ assert(true == lock);
     211        __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
    208212
    209213        /* paranoid */ verify( ! __preemption_enabled() );
     
    249253        }
    250254
    251         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd, bool push_local) with (cltr->ready_queue) {
     255        __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    252256                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    253257
    254                 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     258                const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    255259                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
     260
     261                // write timestamp
     262                thrd->link.ts = rdtscl();
    256263
    257264                bool local;
     
    273280                        #endif
    274281
     282                #if defined(USE_MPSC)
     283                        // mpsc always succeeds
     284                } while( false );
     285                #else
    275286                        // If we can't lock it retry
    276287                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     288                #endif
    277289
    278290                // Actually push it
    279291                push(lanes.data[i], thrd);
    280292
    281                 // Unlock and return
    282                 __atomic_unlock( &lanes.data[i].lock );
     293                #if !defined(USE_MPSC)
     294                        // Unlock and return
     295                        __atomic_unlock( &lanes.data[i].lock );
     296                #endif
    283297
    284298                // Mark the current index in the tls rng instance as having an item
     
    336350#endif
    337351#if defined(USE_WORK_STEALING)
    338         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd, bool push_local) with (cltr->ready_queue) {
     352        __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    339353                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    340354
    341                 // #define USE_PREFERRED
    342                 #if !defined(USE_PREFERRED)
    343                 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     355                const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    344356                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    345                 #else
    346                         unsigned preferred = thrd->preferred;
    347                         const bool external = push_local || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr;
    348                         /* paranoid */ verifyf(external || preferred < lanes.count, "Invalid preferred queue %u for %u lanes", preferred, lanes.count );
    349 
    350                         unsigned r = preferred % READYQ_SHARD_FACTOR;
    351                         const unsigned start = preferred - r;
    352                 #endif
     357
     358                // write timestamp
     359                thrd->link.ts = rdtscl();
    353360
    354361                // Try to pick a lane and lock it
     
    364371                        }
    365372                        else {
    366                                 #if !defined(USE_PREFERRED)
    367                                         processor * proc = kernelTLS().this_processor;
    368                                         unsigned r = proc->rdq.its++;
    369                                         i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
    370                                 #else
    371                                         i = start + (r++ % READYQ_SHARD_FACTOR);
    372                                 #endif
     373                                processor * proc = kernelTLS().this_processor;
     374                                unsigned r = proc->rdq.its++;
     375                                i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
    373376                        }
     377
     378
     379                #if defined(USE_MPSC)
     380                        // mpsc always succeeds
     381                } while( false );
     382                #else
    374383                        // If we can't lock it retry
    375384                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     385                #endif
    376386
    377387                // Actually push it
    378388                push(lanes.data[i], thrd);
    379389
    380                 // Unlock and return
    381                 __atomic_unlock( &lanes.data[i].lock );
     390                #if !defined(USE_MPSC)
     391                        // Unlock and return
     392                        __atomic_unlock( &lanes.data[i].lock );
     393                #endif
    382394
    383395                #if !defined(__CFA_NO_STATISTICS__)
     
    398410
    399411                if(proc->rdq.target == -1u) {
    400                         unsigned long long min = ts(lanes.data[proc->rdq.id]);
    401                         for(int i = 0; i < READYQ_SHARD_FACTOR; i++) {
    402                                 unsigned long long tsc = ts(lanes.data[proc->rdq.id + i]);
    403                                 if(tsc < min) min = tsc;
    404                         }
    405                         proc->rdq.cutoff = min;
    406412                        proc->rdq.target = __tls_rand() % lanes.count;
     413                        unsigned it1  = proc->rdq.itr;
     414                        unsigned it2  = proc->rdq.itr + 1;
     415                        unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
     416                        unsigned idx2 = proc->rdq.id + (it2 % READYQ_SHARD_FACTOR);
     417                        unsigned long long tsc1 = ts(lanes.data[idx1]);
     418                        unsigned long long tsc2 = ts(lanes.data[idx2]);
     419                        proc->rdq.cutoff = min(tsc1, tsc2);
     420                        if(proc->rdq.cutoff == 0) proc->rdq.cutoff = -1ull;
    407421                }
    408422                else {
    409423                        unsigned target = proc->rdq.target;
    410424                        proc->rdq.target = -1u;
    411                         const unsigned long long bias = 0; //2_500_000_000;
    412                         const unsigned long long cutoff = proc->rdq.cutoff > bias ? proc->rdq.cutoff - bias : proc->rdq.cutoff;
    413                         if(lanes.tscs[target].tv < cutoff && ts(lanes.data[target]) < cutoff) {
     425                        if(lanes.tscs[target].tv < proc->rdq.cutoff) {
    414426                                $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
    415427                                if(t) return t;
     
    418430
    419431                for(READYQ_SHARD_FACTOR) {
    420                         unsigned i = proc->rdq.id + (proc->rdq.itr++ % READYQ_SHARD_FACTOR);
     432                        unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR);
    421433                        if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
    422434                }
     
    450462        // If list looks empty retry
    451463        if( is_empty(lane) ) {
     464                __STATS( stats.espec++; )
    452465                return 0p;
    453466        }
     
    455468        // If we can't get the lock retry
    456469        if( !__atomic_try_acquire(&lane.lock) ) {
     470                __STATS( stats.elock++; )
    457471                return 0p;
    458472        }
     
    461475        if( is_empty(lane) ) {
    462476                __atomic_unlock(&lane.lock);
     477                __STATS( stats.eempty++; )
    463478                return 0p;
    464479        }
     
    466481        // Actually pop the list
    467482        struct $thread * thrd;
    468         unsigned long long tsv;
    469         [thrd, tsv] = pop(lane);
     483        thrd = pop(lane);
    470484
    471485        /* paranoid */ verify(thrd);
    472         /* paranoid */ verify(tsv);
    473486        /* paranoid */ verify(lane.lock);
    474487
     
    480493
    481494        #if defined(USE_WORK_STEALING)
    482                 lanes.tscs[w].tv = tsv;
     495                lanes.tscs[w].tv = thrd->link.ts;
    483496        #endif
    484 
    485         thrd->preferred = w;
    486497
    487498        // return the popped thread
     
    511522// Check that all the intrusive queues in the data structure are still consistent
    512523static void check( __ready_queue_t & q ) with (q) {
    513         #if defined(__CFA_WITH_VERIFY__)
     524        #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
    514525                {
    515526                        for( idx ; lanes.count ) {
     
    517528                                assert(!lanes.data[idx].lock);
    518529
    519                                         if(is_empty(sl)) {
    520                                                 assert( sl.anchor.next == 0p );
    521                                                 assert( sl.anchor.ts   == 0  );
    522                                                 assert( mock_head(sl)  == sl.prev );
    523                                         } else {
    524                                                 assert( sl.anchor.next != 0p );
    525                                                 assert( sl.anchor.ts   != 0  );
    526                                                 assert( mock_head(sl)  != sl.prev );
    527                                         }
     530                                assert(head(sl)->link.prev == 0p );
     531                                assert(head(sl)->link.next->link.prev == head(sl) );
     532                                assert(tail(sl)->link.next == 0p );
     533                                assert(tail(sl)->link.prev->link.next == tail(sl) );
     534
     535                                if(is_empty(sl)) {
     536                                        assert(tail(sl)->link.prev == head(sl));
     537                                        assert(head(sl)->link.next == tail(sl));
     538                                } else {
     539                                        assert(tail(sl)->link.prev != head(sl));
     540                                        assert(head(sl)->link.next != tail(sl));
     541                                }
    528542                        }
    529543                }
     
    546560// fixes the list so that the pointers back to anchors aren't left dangling
    547561static inline void fix(__intrusive_lane_t & ll) {
    548                         if(is_empty(ll)) {
    549                                 verify(ll.anchor.next == 0p);
    550                                 ll.prev = mock_head(ll);
    551                         }
    552 }
    553 
    554 static void assign_list(unsigned & value, dlist(processor) & list, unsigned count) {
     562        #if !defined(USE_MPSC)
     563                // if the list is not empty then follow he pointer and fix its reverse
     564                if(!is_empty(ll)) {
     565                        head(ll)->link.next->link.prev = head(ll);
     566                        tail(ll)->link.prev->link.next = tail(ll);
     567                }
     568                // Otherwise just reset the list
     569                else {
     570                        verify(tail(ll)->link.next == 0p);
     571                        tail(ll)->link.prev = head(ll);
     572                        head(ll)->link.next = tail(ll);
     573                        verify(head(ll)->link.prev == 0p);
     574                }
     575        #endif
     576}
     577
     578static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) {
    555579        processor * it = &list`first;
    556580        for(unsigned i = 0; i < count; i++) {
     
    573597                lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
    574598                for(i; lanes.count) {
    575                         unsigned long long tsc = ts(lanes.data[i]);
    576                         lanes.tscs[i].tv = tsc != 0 ? tsc : rdtscl();
     599                        lanes.tscs[i].tv = ts(lanes.data[i]);
    577600                }
    578601        #endif
     
    663686                        while(!is_empty(lanes.data[idx])) {
    664687                                struct $thread * thrd;
    665                                 unsigned long long _;
    666                                 [thrd, _] = pop(lanes.data[idx]);
    667 
    668                                 push(cltr, thrd, true);
     688                                thrd = pop(lanes.data[idx]);
     689
     690                                push(cltr, thrd);
    669691
    670692                                // for printing count the number of displaced threads
     
    703725        /* paranoid */ verify( ready_mutate_islocked() );
    704726}
    705 
    706 #if !defined(__CFA_NO_STATISTICS__)
    707         unsigned cnt(const __ready_queue_t & this, unsigned idx) {
    708                 /* paranoid */ verify(this.lanes.count > idx);
    709                 return this.lanes.data[idx].cnt;
    710         }
    711 #endif
  • libcfa/src/concurrency/ready_subqueue.hfa

    r8d66610 r5407cdc  
    77// Intrusives lanes which are used by the relaxed ready queue
    88struct __attribute__((aligned(128))) __intrusive_lane_t {
    9         struct $thread * prev;
     9
     10        #if defined(USE_MPSC)
     11                mpsc_queue($thread) queue;
     12                __attribute__((aligned(128)))
     13        #else
     14                // anchor for the head and the tail of the queue
     15                __attribute__((aligned(128))) struct __sentinel_t {
     16                        // Link lists fields
     17                        // instrusive link field for threads
     18                        // must be exactly as in $thread
     19                        __thread_desc_link link;
     20                } before, after;
     21        #endif
    1022
    1123        // spin lock protecting the queue
    1224        volatile bool lock;
    1325
    14         __thread_desc_link anchor;
    15 
    16         #if !defined(__CFA_NO_STATISTICS__)
    17                 unsigned cnt;
     26        // Optional statistic counters
     27        #if !defined(__CFA_NO_SCHED_STATS__)
     28                struct __attribute__((aligned(64))) {
     29                        // difference between number of push and pops
     30                        ssize_t diff;
     31
     32                        // total number of pushes and pops
     33                        size_t  push;
     34                        size_t  pop ;
     35                } stat;
    1836        #endif
    1937};
    2038
     39void  ?{}(__intrusive_lane_t & this);
     40void ^?{}(__intrusive_lane_t & this);
     41
    2142// Get the head pointer (one before the first element) from the anchor
    22 static inline $thread * mock_head(const __intrusive_lane_t & this) {
    23         $thread * rhead = ($thread *)(
    24                 (uintptr_t)( &this.anchor ) - __builtin_offsetof( $thread, link )
    25         );
    26         return rhead;
     43static inline $thread * head(const __intrusive_lane_t & this) {
     44        #if defined(USE_MPSC)
     45                return this.queue.head;
     46        #else
     47                $thread * rhead = ($thread *)(
     48                        (uintptr_t)( &this.before ) - offsetof( $thread, link )
     49                );
     50                /* paranoid */ verify(rhead);
     51                return rhead;
     52        #endif
     53}
     54
     55// Get the tail pointer (one after the last element) from the anchor
     56static inline $thread * tail(const __intrusive_lane_t & this) {
     57        #if defined(USE_MPSC)
     58                return this.queue.tail;
     59        #else
     60                $thread * rtail = ($thread *)(
     61                        (uintptr_t)( &this.after ) - offsetof( $thread, link )
     62                );
     63                /* paranoid */ verify(rtail);
     64                return rtail;
     65        #endif
    2766}
    2867
     
    3069void ?{}( __intrusive_lane_t & this ) {
    3170        this.lock = false;
    32         this.prev = mock_head(this);
    33         this.anchor.next = 0p;
    34         this.anchor.ts   = 0;
    35         #if !defined(__CFA_NO_STATISTICS__)
    36                 this.cnt  = 0;
    37         #endif
    38 
    39         // We add a boat-load of assertions here because the anchor code is very fragile
    40         /* paranoid */ _Static_assert( offsetof( $thread, link ) == offsetof(__intrusive_lane_t, anchor) );
    41         /* paranoid */ verify( offsetof( $thread, link ) == offsetof(__intrusive_lane_t, anchor) );
    42         /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.anchor) );
    43         /* paranoid */ verify( &mock_head(this)->link.next == &this.anchor.next );
    44         /* paranoid */ verify( &mock_head(this)->link.ts   == &this.anchor.ts   );
    45         /* paranoid */ verify( mock_head(this)->link.next == 0p );
    46         /* paranoid */ verify( mock_head(this)->link.ts   == 0  );
    47         /* paranoid */ verify( mock_head(this) == this.prev );
    48         /* paranoid */ verify( __alignof__(__intrusive_lane_t) == 128 );
    49         /* paranoid */ verify( __alignof__(this) == 128 );
    50         /* paranoid */ verifyf( ((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128) );
     71
     72        #if !defined(USE_MPSC)
     73                this.before.link.prev = 0p;
     74                this.before.link.next = tail(this);
     75                this.before.link.ts   = 0;
     76
     77                this.after .link.prev = head(this);
     78                this.after .link.next = 0p;
     79                this.after .link.ts   = 0;
     80
     81                #if !defined(__CFA_NO_SCHED_STATS__)
     82                        this.stat.diff = 0;
     83                        this.stat.push = 0;
     84                        this.stat.pop  = 0;
     85                #endif
     86
     87                // We add a boat-load of assertions here because the anchor code is very fragile
     88                /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before));
     89                /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after ));
     90                /* paranoid */ verify(head(this)->link.prev == 0p );
     91                /* paranoid */ verify(head(this)->link.next == tail(this) );
     92                /* paranoid */ verify(tail(this)->link.next == 0p );
     93                /* paranoid */ verify(tail(this)->link.prev == head(this) );
     94                /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev );
     95                /* paranoid */ verify(&head(this)->link.next == &this.before.link.next );
     96                /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev );
     97                /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next );
     98                /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128);
     99                /* paranoid */ verify(__alignof__(this) == 128);
     100                /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128));
     101        #endif
    51102}
    52103
    53104// Dtor is trivial
    54105void ^?{}( __intrusive_lane_t & this ) {
    55         // Make sure the list is empty
    56         /* paranoid */ verify( this.anchor.next == 0p );
    57         /* paranoid */ verify( this.anchor.ts   == 0  );
    58         /* paranoid */ verify( mock_head(this)  == this.prev );
     106        #if !defined(USE_MPSC)
     107                // Make sure the list is empty
     108                /* paranoid */ verify(head(this)->link.prev == 0p );
     109                /* paranoid */ verify(head(this)->link.next == tail(this) );
     110                /* paranoid */ verify(tail(this)->link.next == 0p );
     111                /* paranoid */ verify(tail(this)->link.prev == head(this) );
     112        #endif
    59113}
    60114
    61115// Push a thread onto this lane
    62116// returns true of lane was empty before push, false otherwise
    63 static inline void push( __intrusive_lane_t & this, $thread * node ) {
    64         /* paranoid */ verify( this.lock );
    65         /* paranoid */ verify( node->link.next == 0p );
    66         /* paranoid */ verify( node->link.ts   == 0  );
    67         /* paranoid */ verify( this.prev->link.next == 0p );
    68         /* paranoid */ verify( this.prev->link.ts   == 0  );
    69         if( this.anchor.next == 0p ) {
    70                 /* paranoid */ verify( this.anchor.next == 0p );
    71                 /* paranoid */ verify( this.anchor.ts   == 0  );
    72                 /* paranoid */ verify( this.prev == mock_head( this ) );
    73         } else {
    74                 /* paranoid */ verify( this.anchor.next != 0p );
    75                 /* paranoid */ verify( this.anchor.ts   != 0  );
    76                 /* paranoid */ verify( this.prev != mock_head( this ) );
    77         }
    78 
    79         // Get the relevant nodes locally
    80         this.prev->link.next = node;
    81         this.prev->link.ts   = rdtscl();
    82         this.prev = node;
    83         #if !defined(__CFA_NO_STATISTICS__)
    84                 this.cnt++;
     117bool push(__intrusive_lane_t & this, $thread * node) {
     118        #if defined(USE_MPSC)
     119                inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
     120                        return this->link.next;
     121                }
     122                push(this.queue, node);
     123        #else
     124                #if defined(__CFA_WITH_VERIFY__)
     125                        /* paranoid */ verify(this.lock);
     126                        /* paranoid */ verify(node->link.ts != 0);
     127                        /* paranoid */ verify(node->link.next == 0p);
     128                        /* paranoid */ verify(node->link.prev == 0p);
     129                        /* paranoid */ verify(tail(this)->link.next == 0p);
     130                        /* paranoid */ verify(head(this)->link.prev == 0p);
     131
     132                        if(this.before.link.ts == 0l) {
     133                                /* paranoid */ verify(tail(this)->link.prev == head(this));
     134                                /* paranoid */ verify(head(this)->link.next == tail(this));
     135                        } else {
     136                                /* paranoid */ verify(tail(this)->link.prev != head(this));
     137                                /* paranoid */ verify(head(this)->link.next != tail(this));
     138                        }
     139                #endif
     140
     141                // Get the relevant nodes locally
     142                $thread * tail = tail(this);
     143                $thread * prev = tail->link.prev;
     144
     145                // Do the push
     146                node->link.next = tail;
     147                node->link.prev = prev;
     148                prev->link.next = node;
     149                tail->link.prev = node;
     150
     151                // Update stats
     152                #if !defined(__CFA_NO_SCHED_STATS__)
     153                        this.stat.diff++;
     154                        this.stat.push++;
     155                #endif
     156
     157                verify(node->link.next == tail(this));
     158
     159                // Check if the queue used to be empty
     160                if(this.before.link.ts == 0l) {
     161                        this.before.link.ts = node->link.ts;
     162                        /* paranoid */ verify(node->link.prev == head(this));
     163                        return true;
     164                }
     165                return false;
    85166        #endif
    86167}
     
    89170// returns popped
    90171// returns true of lane was empty before push, false otherwise
    91 static inline [* $thread, unsigned long long] pop( __intrusive_lane_t & this ) {
    92         /* paranoid */ verify( this.lock );
    93         /* paranoid */ verify( this.anchor.next != 0p );
    94         /* paranoid */ verify( this.anchor.ts   != 0  );
    95 
    96         // Get the relevant nodes locally
    97         unsigned long long ts = this.anchor.ts;
    98         $thread * node = this.anchor.next;
    99         this.anchor.next = node->link.next;
    100         this.anchor.ts   = node->link.ts;
    101         bool is_empty = this.anchor.ts == 0;
    102         node->link.next = 0p;
    103         node->link.ts   = 0;
    104         #if !defined(__CFA_NO_STATISTICS__)
    105                 this.cnt--;
    106         #endif
    107 
    108         // Update head time stamp
    109         if(is_empty) this.prev = mock_head( this );
    110 
    111         /* paranoid */ verify( node->link.next == 0p );
    112         /* paranoid */ verify( node->link.ts   == 0  );
    113         return [node, ts];
     172$thread * pop(__intrusive_lane_t & this) {
     173        /* paranoid */ verify(this.lock);
     174        #if defined(USE_MPSC)
     175                inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
     176                        return this->link.next;
     177                }
     178                return pop(this.queue);
     179        #else
     180                /* paranoid */ verify(this.before.link.ts != 0ul);
     181
     182                // Get anchors locally
     183                $thread * head = head(this);
     184                $thread * tail = tail(this);
     185
     186                // Get the relevant nodes locally
     187                $thread * node = head->link.next;
     188                $thread * next = node->link.next;
     189
     190                /* paranoid */ verify(node != tail);
     191                /* paranoid */ verify(node);
     192
     193                // Do the pop
     194                head->link.next = next;
     195                next->link.prev = head;
     196                node->link.next = 0p;
     197                node->link.prev = 0p;
     198
     199                // Update head time stamp
     200                this.before.link.ts = next->link.ts;
     201
     202                // Update stats
     203                #ifndef __CFA_NO_SCHED_STATS__
     204                        this.stat.diff--;
     205                        this.stat.pop ++;
     206                #endif
     207
     208                // Check if we emptied list and return accordingly
     209                /* paranoid */ verify(tail(this)->link.next == 0p);
     210                /* paranoid */ verify(head(this)->link.prev == 0p);
     211                if(next == tail) {
     212                        /* paranoid */ verify(this.before.link.ts == 0);
     213                        /* paranoid */ verify(tail(this)->link.prev == head(this));
     214                        /* paranoid */ verify(head(this)->link.next == tail(this));
     215                        return node;
     216                }
     217                else {
     218                        /* paranoid */ verify(next->link.ts != 0);
     219                        /* paranoid */ verify(tail(this)->link.prev != head(this));
     220                        /* paranoid */ verify(head(this)->link.next != tail(this));
     221                        /* paranoid */ verify(this.before.link.ts != 0);
     222                        return node;
     223                }
     224        #endif
    114225}
    115226
    116227// Check whether or not list is empty
    117228static inline bool is_empty(__intrusive_lane_t & this) {
    118         return this.anchor.ts == 0;
     229        #if defined(USE_MPSC)
     230                return this.queue.head == 0p;
     231        #else
     232                // Cannot verify here since it may not be locked
     233                return this.before.link.ts == 0;
     234        #endif
    119235}
    120236
    121237// Return the timestamp
    122238static inline unsigned long long ts(__intrusive_lane_t & this) {
    123         // Cannot verify here since it may not be locked
    124         return this.anchor.ts;
    125 }
     239        #if defined(USE_MPSC)
     240                $thread * tl = this.queue.head;
     241                if(!tl) return -1ull;
     242                return tl->link.ts;
     243        #else
     244                // Cannot verify here since it may not be locked
     245                return this.before.link.ts;
     246        #endif
     247}
     248
     249// Aligned timestamps which are used by the relaxed ready queue
     250struct __attribute__((aligned(128))) __timestamp_t {
     251        volatile unsigned long long tv;
     252};
     253
     254void  ?{}(__timestamp_t & this) { this.tv = 0; }
     255void ^?{}(__timestamp_t & this) {}
  • libcfa/src/concurrency/stats.cfa

    r8d66610 r5407cdc  
    1919                stats->ready.pop.local .attempt = 0;
    2020                stats->ready.pop.local .success = 0;
     21                stats->ready.pop.local .elock   = 0;
     22                stats->ready.pop.local .eempty  = 0;
     23                stats->ready.pop.local .espec   = 0;
    2124                stats->ready.pop.help  .attempt = 0;
    2225                stats->ready.pop.help  .success = 0;
     26                stats->ready.pop.help  .elock   = 0;
     27                stats->ready.pop.help  .eempty  = 0;
     28                stats->ready.pop.help  .espec   = 0;
    2329                stats->ready.pop.steal .attempt = 0;
    2430                stats->ready.pop.steal .success = 0;
     31                stats->ready.pop.steal .elock   = 0;
     32                stats->ready.pop.steal .eempty  = 0;
     33                stats->ready.pop.steal .espec   = 0;
    2534                stats->ready.pop.search.attempt = 0;
    2635                stats->ready.pop.search.success = 0;
     36                stats->ready.pop.search.elock   = 0;
     37                stats->ready.pop.search.eempty  = 0;
     38                stats->ready.pop.search.espec   = 0;
    2739                stats->ready.threads.migration = 0;
    2840                stats->ready.threads.extunpark = 0;
    2941                stats->ready.threads.threads   = 0;
    30                 stats->ready.threads.cthreads  = 0;
    3142                stats->ready.sleep.halts   = 0;
    3243                stats->ready.sleep.cancels = 0;
     
    4859                        stats->io.calls.completed   = 0;
    4960                        stats->io.calls.errors.busy = 0;
     61                        stats->io.poller.sleeps     = 0;
    5062                #endif
    5163
     
    5668        }
    5769
    58         static inline void tally_one( volatile uint64_t * agg, volatile uint64_t * val) {
    59                 uint64_t add = __atomic_exchange_n(val, 0_l64u, __ATOMIC_RELAXED);
    60                 __atomic_fetch_add(agg, add, __ATOMIC_RELAXED);
    61         }
    62 
    63         static inline void tally_one( volatile int64_t * agg, volatile int64_t * val) {
    64                 int64_t add = __atomic_exchange_n(val, 0_l64, __ATOMIC_RELAXED);
    65                 __atomic_fetch_add(agg, add, __ATOMIC_RELAXED);
    66         }
    67 
    6870        void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) {
    69                 tally_one( &cltr->ready.push.local.attempt, &proc->ready.push.local.attempt );
    70                 tally_one( &cltr->ready.push.local.success, &proc->ready.push.local.success );
    71                 tally_one( &cltr->ready.push.share.attempt, &proc->ready.push.share.attempt );
    72                 tally_one( &cltr->ready.push.share.success, &proc->ready.push.share.success );
    73                 tally_one( &cltr->ready.push.extrn.attempt, &proc->ready.push.extrn.attempt );
    74                 tally_one( &cltr->ready.push.extrn.success, &proc->ready.push.extrn.success );
    75                 tally_one( &cltr->ready.pop.local .attempt, &proc->ready.pop.local .attempt );
    76                 tally_one( &cltr->ready.pop.local .success, &proc->ready.pop.local .success );
    77                 tally_one( &cltr->ready.pop.help  .attempt, &proc->ready.pop.help  .attempt );
    78                 tally_one( &cltr->ready.pop.help  .success, &proc->ready.pop.help  .success );
    79                 tally_one( &cltr->ready.pop.steal .attempt, &proc->ready.pop.steal .attempt );
    80                 tally_one( &cltr->ready.pop.steal .success, &proc->ready.pop.steal .success );
    81                 tally_one( &cltr->ready.pop.search.attempt, &proc->ready.pop.search.attempt );
    82                 tally_one( &cltr->ready.pop.search.success, &proc->ready.pop.search.success );
    83                 tally_one( &cltr->ready.threads.migration , &proc->ready.threads.migration  );
    84                 tally_one( &cltr->ready.threads.extunpark , &proc->ready.threads.extunpark  );
    85                 tally_one( &cltr->ready.threads.threads   , &proc->ready.threads.threads    );
    86                 tally_one( &cltr->ready.threads.cthreads  , &proc->ready.threads.cthreads   );
    87                 tally_one( &cltr->ready.sleep.halts       , &proc->ready.sleep.halts        );
    88                 tally_one( &cltr->ready.sleep.cancels     , &proc->ready.sleep.cancels      );
    89                 tally_one( &cltr->ready.sleep.wakes       , &proc->ready.sleep.wakes        );
    90                 tally_one( &cltr->ready.sleep.exits       , &proc->ready.sleep.exits        );
     71                __atomic_fetch_add( &cltr->ready.push.local.attempt, proc->ready.push.local.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.local.attempt = 0;
     72                __atomic_fetch_add( &cltr->ready.push.local.success, proc->ready.push.local.success, __ATOMIC_SEQ_CST ); proc->ready.push.local.success = 0;
     73                __atomic_fetch_add( &cltr->ready.push.share.attempt, proc->ready.push.share.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.share.attempt = 0;
     74                __atomic_fetch_add( &cltr->ready.push.share.success, proc->ready.push.share.success, __ATOMIC_SEQ_CST ); proc->ready.push.share.success = 0;
     75                __atomic_fetch_add( &cltr->ready.push.extrn.attempt, proc->ready.push.extrn.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.attempt = 0;
     76                __atomic_fetch_add( &cltr->ready.push.extrn.success, proc->ready.push.extrn.success, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.success = 0;
     77                __atomic_fetch_add( &cltr->ready.pop.local .attempt, proc->ready.pop.local .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.local .attempt = 0;
     78                __atomic_fetch_add( &cltr->ready.pop.local .success, proc->ready.pop.local .success, __ATOMIC_SEQ_CST ); proc->ready.pop.local .success = 0;
     79                __atomic_fetch_add( &cltr->ready.pop.local .elock  , proc->ready.pop.local .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.local .elock   = 0;
     80                __atomic_fetch_add( &cltr->ready.pop.local .eempty , proc->ready.pop.local .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.local .eempty  = 0;
     81                __atomic_fetch_add( &cltr->ready.pop.local .espec  , proc->ready.pop.local .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.local .espec   = 0;
     82                __atomic_fetch_add( &cltr->ready.pop.help  .attempt, proc->ready.pop.help  .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.help  .attempt = 0;
     83                __atomic_fetch_add( &cltr->ready.pop.help  .success, proc->ready.pop.help  .success, __ATOMIC_SEQ_CST ); proc->ready.pop.help  .success = 0;
     84                __atomic_fetch_add( &cltr->ready.pop.help  .elock  , proc->ready.pop.help  .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .elock   = 0;
     85                __atomic_fetch_add( &cltr->ready.pop.help  .eempty , proc->ready.pop.help  .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .eempty  = 0;
     86                __atomic_fetch_add( &cltr->ready.pop.help  .espec  , proc->ready.pop.help  .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .espec   = 0;
     87                __atomic_fetch_add( &cltr->ready.pop.steal .attempt, proc->ready.pop.steal .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .attempt = 0;
     88                __atomic_fetch_add( &cltr->ready.pop.steal .success, proc->ready.pop.steal .success, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .success = 0;
     89                __atomic_fetch_add( &cltr->ready.pop.steal .elock  , proc->ready.pop.steal .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .elock   = 0;
     90                __atomic_fetch_add( &cltr->ready.pop.steal .eempty , proc->ready.pop.steal .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .eempty  = 0;
     91                __atomic_fetch_add( &cltr->ready.pop.steal .espec  , proc->ready.pop.steal .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .espec   = 0;
     92                __atomic_fetch_add( &cltr->ready.pop.search.attempt, proc->ready.pop.search.attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.search.attempt = 0;
     93                __atomic_fetch_add( &cltr->ready.pop.search.success, proc->ready.pop.search.success, __ATOMIC_SEQ_CST ); proc->ready.pop.search.success = 0;
     94                __atomic_fetch_add( &cltr->ready.pop.search.elock  , proc->ready.pop.search.elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.search.elock   = 0;
     95                __atomic_fetch_add( &cltr->ready.pop.search.eempty , proc->ready.pop.search.eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.search.eempty  = 0;
     96                __atomic_fetch_add( &cltr->ready.pop.search.espec  , proc->ready.pop.search.espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.search.espec   = 0;
     97                __atomic_fetch_add( &cltr->ready.threads.migration , proc->ready.threads.migration , __ATOMIC_SEQ_CST ); proc->ready.threads.migration  = 0;
     98                __atomic_fetch_add( &cltr->ready.threads.extunpark , proc->ready.threads.extunpark , __ATOMIC_SEQ_CST ); proc->ready.threads.extunpark  = 0;
     99                __atomic_fetch_add( &cltr->ready.threads.threads   , proc->ready.threads.threads   , __ATOMIC_SEQ_CST ); proc->ready.threads.threads    = 0;
     100                __atomic_fetch_add( &cltr->ready.sleep.halts       , proc->ready.sleep.halts       , __ATOMIC_SEQ_CST ); proc->ready.sleep.halts        = 0;
     101                __atomic_fetch_add( &cltr->ready.sleep.cancels     , proc->ready.sleep.cancels     , __ATOMIC_SEQ_CST ); proc->ready.sleep.cancels      = 0;
     102                __atomic_fetch_add( &cltr->ready.sleep.wakes       , proc->ready.sleep.wakes       , __ATOMIC_SEQ_CST ); proc->ready.sleep.wakes        = 0;
     103                __atomic_fetch_add( &cltr->ready.sleep.exits       , proc->ready.sleep.exits       , __ATOMIC_SEQ_CST ); proc->ready.sleep.exits        = 0;
    91104
    92105                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    93                         tally_one( &cltr->io.alloc.fast       , &proc->io.alloc.fast        );
    94                         tally_one( &cltr->io.alloc.slow       , &proc->io.alloc.slow        );
    95                         tally_one( &cltr->io.alloc.fail       , &proc->io.alloc.fail        );
    96                         tally_one( &cltr->io.alloc.revoke     , &proc->io.alloc.revoke      );
    97                         tally_one( &cltr->io.alloc.block      , &proc->io.alloc.block       );
    98                         tally_one( &cltr->io.submit.fast      , &proc->io.submit.fast       );
    99                         tally_one( &cltr->io.submit.slow      , &proc->io.submit.slow       );
    100                         tally_one( &cltr->io.flush.external   , &proc->io.flush.external    );
    101                         tally_one( &cltr->io.calls.flush      , &proc->io.calls.flush       );
    102                         tally_one( &cltr->io.calls.submitted  , &proc->io.calls.submitted   );
    103                         tally_one( &cltr->io.calls.drain      , &proc->io.calls.drain       );
    104                         tally_one( &cltr->io.calls.completed  , &proc->io.calls.completed   );
    105                         tally_one( &cltr->io.calls.errors.busy, &proc->io.calls.errors.busy );
     106                        __atomic_fetch_add( &cltr->io.alloc.fast       , proc->io.alloc.fast       , __ATOMIC_SEQ_CST ); proc->io.alloc.fast        = 0;
     107                        __atomic_fetch_add( &cltr->io.alloc.slow       , proc->io.alloc.slow       , __ATOMIC_SEQ_CST ); proc->io.alloc.slow        = 0;
     108                        __atomic_fetch_add( &cltr->io.alloc.fail       , proc->io.alloc.fail       , __ATOMIC_SEQ_CST ); proc->io.alloc.fail        = 0;
     109                        __atomic_fetch_add( &cltr->io.alloc.revoke     , proc->io.alloc.revoke     , __ATOMIC_SEQ_CST ); proc->io.alloc.revoke      = 0;
     110                        __atomic_fetch_add( &cltr->io.alloc.block      , proc->io.alloc.block      , __ATOMIC_SEQ_CST ); proc->io.alloc.block       = 0;
     111                        __atomic_fetch_add( &cltr->io.submit.fast      , proc->io.submit.fast      , __ATOMIC_SEQ_CST ); proc->io.submit.fast       = 0;
     112                        __atomic_fetch_add( &cltr->io.submit.slow      , proc->io.submit.slow      , __ATOMIC_SEQ_CST ); proc->io.submit.slow       = 0;
     113                        __atomic_fetch_add( &cltr->io.flush.external   , proc->io.flush.external   , __ATOMIC_SEQ_CST ); proc->io.flush.external    = 0;
     114                        __atomic_fetch_add( &cltr->io.calls.flush      , proc->io.calls.flush      , __ATOMIC_SEQ_CST ); proc->io.calls.flush       = 0;
     115                        __atomic_fetch_add( &cltr->io.calls.submitted  , proc->io.calls.submitted  , __ATOMIC_SEQ_CST ); proc->io.calls.submitted   = 0;
     116                        __atomic_fetch_add( &cltr->io.calls.drain      , proc->io.calls.drain      , __ATOMIC_SEQ_CST ); proc->io.calls.drain       = 0;
     117                        __atomic_fetch_add( &cltr->io.calls.completed  , proc->io.calls.completed  , __ATOMIC_SEQ_CST ); proc->io.calls.completed   = 0;
     118                        __atomic_fetch_add( &cltr->io.calls.errors.busy, proc->io.calls.errors.busy, __ATOMIC_SEQ_CST ); proc->io.calls.errors.busy = 0;
     119                        __atomic_fetch_add( &cltr->io.poller.sleeps    , proc->io.poller.sleeps    , __ATOMIC_SEQ_CST ); proc->io.poller.sleeps     = 0;
    106120                #endif
    107121        }
     
    116130                if( flags & CFA_STATS_READY_Q ) {
    117131
    118                         sstr | "----- " | type | " \"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";
     132                        sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";
    119133
    120134                        uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success;
    121135                        uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success;
    122                         sstr | "- totals   : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext,"
    123                              | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk," | ready.threads.threads | " t," | ready.threads.cthreads | " cthr)";
     136                        sstr | "- totals   : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk)";
    124137
    125138                        double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS;
     
    134147                        double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR;
    135148                        sstr | "- local    : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%'
    136                              | " (" | eng3(ready.pop.local .attempt) | " try)";
     149                             | " (" | eng3(ready.pop.local .attempt) | " try," | eng3(ready.pop.local .espec) | " spc," | eng3(ready.pop.local .elock) | " lck," | eng3(ready.pop.local .eempty) | " ept)";
    137150                        double rHlp_pc = (100.0 * (double)ready.pop.help  .success) / totalR;
    138151                        sstr | "- help     : " | eng3(ready.pop.help  .success) | "-"| ws(3, 3, rHlp_pc) | '%'
    139                              | " (" | eng3(ready.pop.help  .attempt) | " try)";
     152                             | " (" | eng3(ready.pop.help  .attempt) | " try," | eng3(ready.pop.help  .espec) | " spc," | eng3(ready.pop.help  .elock) | " lck," | eng3(ready.pop.help  .eempty) | " ept)";
    140153                        double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR;
    141154                        sstr | "- steal    : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%'
    142                              | " (" | eng3(ready.pop.steal .attempt) | " try)";
     155                             | " (" | eng3(ready.pop.steal .attempt) | " try," | eng3(ready.pop.steal .espec) | " spc," | eng3(ready.pop.steal .elock) | " lck," | eng3(ready.pop.steal .eempty) | " ept)";
    143156                        double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR;
    144157                        sstr | "- search   : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%'
    145                              | " (" | eng3(ready.pop.search.attempt) | " try)";
     158                             | " (" | eng3(ready.pop.search.attempt) | " try," | eng3(ready.pop.search.espec) | " spc," | eng3(ready.pop.search.elock) | " lck," | eng3(ready.pop.search.eempty) | " ept)";
    146159
    147160                        sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit";
     
    151164                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    152165                        if( flags & CFA_STATS_IO ) {
    153                                 sstr | "----- " | type | " \"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";
     166                                sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";
    154167
    155168                                uint64_t total_allocs = io.alloc.fast + io.alloc.slow;
     169                                double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs;
     170                                sstr | "- total allocations : " | eng3(io.alloc.fast) | "fast," | eng3(io.alloc.slow) | "slow (" | ws(3, 3, avgfasta) | "%)";
     171                                sstr | "-     failures      : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk";
    156172
    157173                                uint64_t total_submits = io.submit.fast + io.submit.slow;
    158                                 sstr | "- totals : allc" | eng3(io.alloc .fast) | nonl;
    159                                 if(io.alloc.slow) {
    160                                         double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs;
    161                                         sstr | "fast," | eng3(io.alloc .slow) | "slow (" | ws(3, 3, avgfasta) | "%)" | nonl;
    162                                 }
    163                                 sstr | " - subm" | eng3(io.submit.fast) | nonl;
    164                                 if(io.alloc.slow) {
    165                                         double avgfasts = (100.0 * (double)io.submit.fast) / total_submits;
    166                                         sstr | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)" | nonl;
    167                                 }
    168                                 sstr | nl;
    169 
    170                                 if(io.alloc.fail || io.alloc.revoke || io.alloc.block)
    171                                         sstr | "-     failures      : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk";
    172                                 if(io.flush.external)
    173                                         sstr | "- flush external    : " | eng3(io.flush.external);
     174                                double avgfasts = (100.0 * (double)io.submit.fast) / total_submits;
     175                                sstr | "- total submits     : " | eng3(io.submit.fast) | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)";
     176                                sstr | "- flush external    : " | eng3(io.flush.external);
     177
     178                                sstr | "- io_uring_enter    : " | eng3(io.calls.flush) | " (" | eng3(io.calls.drain) | ", " | eng3(io.calls.errors.busy) | " EBUSY)";
    174179
    175180                                double avgsubs = ((double)io.calls.submitted) / io.calls.flush;
    176181                                double avgcomp = ((double)io.calls.completed) / io.calls.drain;
    177                                 sstr | "- syscll : "
    178                                      |   " sub " | eng3(io.calls.flush) | "/" | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"
    179                                      | " - cmp " | eng3(io.calls.drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"
    180                                      | " - " | eng3(io.calls.errors.busy) | " EBUSY";
     182                                sstr | "-     submits       : " | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)";
     183                                sstr | "-     completes     : " | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)";
     184
     185                                sstr | "- poller sleeping   : " | eng3(io.poller.sleeps);
    181186                                sstr | nl;
    182187                        }
  • libcfa/src/concurrency/stats.hfa

    r8d66610 r5407cdc  
    22
    33// #define CFA_STATS_ARRAY 10000
    4 // #define __CFA_NO_STATISTICS__
    54
    65#include <stdint.h>
     
    2322                // number of successes at poping
    2423                volatile uint64_t success;
     24
     25                // number of attempts failed due to the lock being held
     26                volatile uint64_t elock;
     27
     28                // number of attempts failed due to the queue being empty (lock held)
     29                volatile uint64_t eempty;
     30
     31                // number of attempts failed due to the queue looking empty (lock not held)
     32                volatile uint64_t espec;
    2533        };
    2634
     
    6371                        volatile uint64_t migration;
    6472                        volatile uint64_t extunpark;
    65                         volatile  int64_t threads;  // number of threads in the system, includes only local change
    66                         volatile  int64_t cthreads; // number of threads in the system, includes only local change
     73                        volatile  int64_t threads; // number of threads in the system, includes only local change
    6774                } threads;
    6875                struct {
  • libcfa/src/concurrency/thread.cfa

    r8d66610 r5407cdc  
    3838        curr_cluster = &cl;
    3939        link.next = 0p;
    40         link.ts   = 0;
    41         preferred = -1u;
     40        link.prev = 0p;
     41        link.preferred = -1u;
    4242        last_proc = 0p;
    4343        #if defined( __CFA_WITH_VERIFY__ )
  • libcfa/src/containers/array.hfa

    r8d66610 r5407cdc  
    55
    66// the inverse of Z(-)
    7 #define z(N) sizeof(N)
     7#define z(Zn) sizeof(Zn)
     8
     9// if you're expecting a Z(n), say so, by asking for a ztype, instead of dtype or otype
     10#define ztype(Zn) Zn & | sized(Zn)
    811
    912forall( T & ) struct tag {};
     
    1619//
    1720
    18 forall( [N], S & | sized(S), Timmed &, Tbase & ) {
     21forall( ztype(Zn), ztype(S), Timmed &, Tbase & ) {
    1922    struct arpk {
    20         S strides[z(N)];
     23        S strides[z(Zn)];
    2124    };
    2225
    23     // About the choice of integral types offered as subscript overloads:
    24     // Intent is to cover these use cases:
    25     //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
    26     //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
    27     //    for( i; 5 ) { total += a[i]; }                      // i : int
    28     // It gets complicated by:
    29     // -  CFA does overloading on concrete types, like int and unsigned int, not on typedefed
    30     //    types like size_t.  So trying to overload on ptrdiff_t vs int works in 64-bit mode
    31     //    but not in 32-bit mode.
    32     // -  Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it
    33     //    should give them type size_t.
    34     //   
    35     //                          gcc -m32         cfa -m32 given bug         gcc -m64
    36     // ptrdiff_t                int              int                        long int
    37     // size_t                   unsigned int     unsigned int               unsigned long int
    38     // typeof( sizeof(42) )     unsigned int     unsigned long int          unsigned long int
    39     // int                      int              int                        int
    40 
    41     static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) {
     26    Timmed & ?[?]( arpk(Zn, S, Timmed, Tbase) & a, ptrdiff_t i ) {
    4227        return (Timmed &) a.strides[i];
    4328    }
    4429
    45     static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned int i ) {
    46         return (Timmed &) a.strides[i];
    47     }
    48 
    49     static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, long int i ) {
    50         return (Timmed &) a.strides[i];
    51     }
    52 
    53     static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) {
    54         return (Timmed &) a.strides[i];
    55     }
    56 
    57     static inline size_t ?`len( arpk(N, S, Timmed, Tbase) & a ) {
    58         return z(N);
     30    size_t ?`len( arpk(Zn, S, Timmed, Tbase) & a ) {
     31        return z(Zn);
    5932    }
    6033
    6134    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
    62     static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {
    63         void ?{}( S (&inner)[z(N)] ) {}
     35    void ?{}( arpk(Zn, S, Timmed, Tbase) & this ) {
     36        void ?{}( S (&inner)[z(Zn)] ) {}
    6437        ?{}(this.strides);
    6538    }
    66     static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
    67         void ^?{}( S (&inner)[z(N)] ) {}
     39    void ^?{}( arpk(Zn, S, Timmed, Tbase) & this ) {
     40        void ^?{}( S (&inner)[z(Zn)] ) {}
    6841        ^?{}(this.strides);
    6942    }
     
    7548
    7649forall( Te )
    77 static inline Te mkar_( tag(Te) ) {}
     50Te mkar_( tag(Te) ) {}
    7851
    79 forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
    80 static inline arpk(N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}
     52forall( ztype(Zn), ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
     53arpk(Zn, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(Zn), ZTags ) {}
    8154
    8255// based on https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
     
    10780// Core -[[-,-,-]] operator
    10881
    109 #ifdef TRY_BROKEN_DESIRED_MD_SUBSCRIPT
     82// Desired form.  One definition with recursion on IxBC (worked until Jan 2021, see trac #__TODO__)
     83// forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } )
     84// TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
     85//     return this[ab][bc];
     86// }
    11087
    111 // Desired form.  One definition with recursion on IxBC (worked until Jan 2021, see trac #__TODO__)
    112 
    113 forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } )
    114 static inline TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
     88// Workaround form.  Listing all possibilities up to 4 dims.
     89forall( TA &, TB &, IxAB | { TB & ?[?]( TA &, IxAB ); }
     90            , TC &, IxBC | { TC & ?[?]( TB &, IxBC ); } )
     91TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
    11592    return this[ab][bc];
    11693}
    117 
    118 #else
    119 
    120 // Workaround form.  Listing all possibilities up to 4 dims.
    121 
    122 forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } )
    123 static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) {
    124     return this[ab][bc];
     94forall( TA &, TB &, IxAB | { TB & ?[?]( TA &, IxAB ); }
     95            , TC &, IxBC | { TC & ?[?]( TB &, IxBC ); }
     96            , TD &, IxCD | { TD & ?[?]( TC &, IxCD ); } )
     97TD & ?[?]( TA & this, IxAB ab, IxBC bc, IxCD cd ) {
     98    return this[ab][bc][cd];
     99}
     100forall( TA &, TB &, IxAB | { TB & ?[?]( TA &, IxAB ); }
     101            , TC &, IxBC | { TC & ?[?]( TB &, IxBC ); }
     102            , TD &, IxCD | { TD & ?[?]( TC &, IxCD ); }
     103            , TE &, IxDE | { TE & ?[?]( TD &, IxDE ); } )
     104TE & ?[?]( TA & this, IxAB ab, IxBC bc, IxCD cd, IxDE de ) {
     105    return this[ab][bc][cd][de];
    125106}
    126107
    127 forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } )
    128 static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) {
    129     return this[[ab0,ab1]][bc];
     108// Adapters for "indexed by ptrdiff_t" implies "indexed by [this other integral type]"
     109// Work around restriction that assertions underlying -[[-,-,-]] must match excatly
     110forall( C &, E & | { E & ?[?]( C &, ptrdiff_t ); } ) {
     111
     112    // Targeted to support:  for( i; z(N) ) ... a[[ ..., i, ... ]]
     113    E & ?[?]( C & this, size_t i ) {
     114        return this[ (ptrdiff_t) i ];
     115    }
     116
     117    // Targeted to support:  for( i; 5 ) ... a[[ ..., i, ... ]]
     118    E & ?[?]( C & this, int i ) {
     119        return this[ (ptrdiff_t) i ];
     120    }
    130121}
    131 
    132 forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxAB_2, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1, IxAB_2 ); TC & ?[?]( TB &, IxBC ); } )
    133 static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) {
    134     return this[[ab0,ab1,ab2]][bc];
    135 }
    136 
    137 #endif
    138122
    139123//
     
    142126
    143127// Base
    144 forall( [Nq], Sq & | sized(Sq), Tbase & )
    145 static inline tag(arpk(Nq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(Tbase) ) {}
     128forall( ztype(Zq), ztype(Sq), Tbase & )
     129tag(arpk(Zq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(Tbase) ) {}
    146130
    147131// Rec
    148 forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } )
    149 static inline tag(arpk(N, S, recr, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(arpk(N, S, recq, Tbase)) ) {}
     132forall( ztype(Zq), ztype(Sq), ztype(Z), ztype(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(recq) ); } )
     133tag(arpk(Z, S, recr, Tbase)) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(arpk(Z, S, recq, Tbase)) ) {}
    150134
    151135// Wrapper
    152136struct all_t {} all;
    153 forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } )
    154 static inline result & ?[?]( arpk(N, S, Te, Tbase) & this, all_t ) {
     137forall( ztype(Z), ztype(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(Z), tag(S), tag(Te) ); } )
     138result & ?[?]( arpk(Z, S, Te, Tbase) & this, all_t ) {
    155139    return (result&) this;
    156140}
  • libcfa/src/containers/list.hfa

    r8d66610 r5407cdc  
    1818#include <assert.h>
    1919
    20 forall( Decorator &, T & )
    21 struct tytagref {
    22     inline T &;
     20#define __DLISTED_MGD_COMMON(ELEM, NODE, LINKS_FLD) \
     21static inline ELEM& $tempcv_n2e(NODE &node) { \
     22        return node; \
     23} \
     24\
     25static inline NODE& $tempcv_e2n(ELEM &node) { \
     26        return ( NODE & ) node; \
     27} \
     28\
     29static inline ELEM & ?`prev(NODE &node) { \
     30    $dlinks(ELEM) & ls = node.LINKS_FLD; \
     31        $mgd_link(ELEM) * l = &ls.prev; \
     32        ELEM * e = l->elem; \
     33        return *e; \
     34} \
     35\
     36static inline ELEM & ?`next(NODE &node) { \
     37    $dlinks(ELEM) & ls = node.LINKS_FLD; \
     38        $mgd_link(ELEM) * l = &ls.next; \
     39        ELEM * e = l->elem; \
     40        return *e; \
     41} \
     42\
     43static inline $mgd_link(ELEM) & $prev_link(NODE &node) { \
     44    $dlinks(ELEM) & ls = node.LINKS_FLD; \
     45        $mgd_link(ELEM) * l = &ls.prev; \
     46        return *l; \
     47} \
     48\
     49static inline $mgd_link(ELEM) & $next_link(NODE &node) { \
     50    $dlinks(ELEM) & ls = node.LINKS_FLD; \
     51        $mgd_link(ELEM) * l = &ls.next; \
     52        return *l; \
     53}
     54
     55#define __DLISTED_MGD_JUSTEXPL(STRUCT, IN_THELIST, STRUCT_IN_THELIST) \
     56struct STRUCT_IN_THELIST { \
     57        inline STRUCT; \
     58}; \
     59\
     60void ?{}(STRUCT_IN_THELIST &) = void; \
     61\
     62static inline STRUCT_IN_THELIST& ?`IN_THELIST(STRUCT &this) { \
     63        return (STRUCT_IN_THELIST&)this; \
     64}
     65
     66#define __DLISTED_MGD_JUSTIMPL(STRUCT)
     67
     68forall( tE & ) {
     69        struct $mgd_link {
     70                tE *elem;
     71                void *terminator;
     72                _Bool is_terminator;
     73                // will collapse to single pointer with tag bit
     74        };
     75        static inline void ?{}( $mgd_link(tE) &this, tE* elem ) {
     76                (this.elem){ elem };
     77                (this.terminator){ 0p };
     78                (this.is_terminator){ 0 };
     79        }
     80        static inline void ?{}( $mgd_link(tE) &this, void * terminator ) {
     81                (this.elem){ 0p };
     82                (this.terminator){ terminator };
     83                (this.is_terminator){ 1 };
     84        }
     85        static inline void ?=?( $mgd_link(tE) &this, tE* elem ) {
     86                this.elem = elem ;
     87                this.terminator = 0p;
     88                this.is_terminator = 0;
     89        }
     90        static inline void ?=?( $mgd_link(tE) &this, void * terminator ) {
     91                this.elem = 0p;
     92                this.terminator = terminator;
     93                this.is_terminator = 1;
     94        }
     95        struct $dlinks {
     96                // containing item is not listed
     97                // iff
     98                // links have (elem == 0p && terminator == 0p)
     99                $mgd_link(tE) next;
     100                $mgd_link(tE) prev;
     101        };
     102        static inline void ?{}( $dlinks(tE) &this ) {
     103                (this.next){ (tE *)0p };
     104                (this.prev){ (tE *)0p };
     105        }
     106}
     107
     108#define DLISTED_MGD_EXPL_IN(STRUCT, LIST_SUF) \
     109  $dlinks(STRUCT) $links_ ## LIST_SUF;
     110
     111#define DLISTED_MGD_EXPL_OUT(STRUCT, LIST_SUF) \
     112  __DLISTED_MGD_JUSTEXPL(STRUCT, in_##LIST_SUF, STRUCT ## _in_ ## LIST_SUF) \
     113  __DLISTED_MGD_COMMON(STRUCT, STRUCT##_in_##LIST_SUF,  $links_ ## LIST_SUF)
     114
     115#define DLISTED_MGD_IMPL_IN(STRUCT) \
     116  $dlinks(STRUCT) $links;
     117
     118#define DLISTED_MGD_IMPL_OUT(STRUCT) \
     119  __DLISTED_MGD_JUSTIMPL(STRUCT) \
     120  __DLISTED_MGD_COMMON(STRUCT, STRUCT, $links)
     121
     122trait $dlistable(Tnode &, Telem &) {
     123        $mgd_link(Telem) & $prev_link(Tnode &);
     124        $mgd_link(Telem) & $next_link(Tnode &);
     125        Telem& $tempcv_n2e(Tnode &);
     126        Tnode& $tempcv_e2n(Telem &);
     127
     128        Telem& ?`next(Tnode &);
     129        Telem& ?`prev(Tnode &);
    23130};
    24131
    25 trait embedded( tOuter &, tMid &, tInner & ) {
    26     tytagref( tMid, tInner ) ?`inner( tOuter & );
    27 };
    28 
    29 // embedded is reflexive, with no info (void) as the type tag
    30 forall (T &)
    31 static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; }
    32 
    33 // use this on every case of plan-9 inheritance, to make embedded a closure of plan-9 inheritance
    34 #define P9_EMBEDDED( derived, immedBase ) \
    35 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \
    36     static inline tytagref(immedBase, Tbase) ?`inner( derived & this ) { \
    37         immedBase & ib = this; \
    38         Tbase & b = ib`inner; \
    39         tytagref(immedBase, Tbase) result = { b }; \
    40         return result; \
    41     }
    42 
    43 #define EMBEDDED_VIA( OUTER, MID, INNER ) \
    44    (struct { tytagref(MID, INNER) ( * ?`inner ) ( OUTER & ); }){ ?`inner }
    45 
    46 #define DLINK_VIA( TE, TLINK ) \
    47    EMBEDDED_VIA( TE, TLINK, dlink(TE) )
    48 
    49 
    50 // The origin is the position encountered at the start of iteration,
    51 // signifying, "need to advance to the first element," and at the end
    52 // of iteration, signifying, "no more elements."  Normal comsumption of
    53 // an iterator runs ?`moveNext as the first step, and uses the return
    54 // of ?`moveNext as a guard, before dereferencing the iterator.  So
    55 // normal consumption of an iterator does not dereference an iterator
    56 // in origin position.  The value of a pointer (underlying a refence)
    57 // that is exposed publicly as an iteraor, and also a pointer stored
    58 // internally in a link field, is tagged, to indicate "is the origin"
    59 // (internally, is the list-head sentinel node), or untagged, to indicate
    60 // "is a regular node."  Intent is to help a user who dereferences an
    61 // iterator in origin position (which would be an API-use error on their
    62 // part), by failing fast.
    63 
    64 #if defined( __x86_64 )
    65     // Preferred case: tag in the most-significant bit.  Dereference
    66     // has been shown to segfault consistently.  Maintenance should
    67     // list more architectures as "ok" here, to let them use the
    68     // preferred case, when valid.
    69     #define ORIGIN_TAG_BITNO ( 8 * sizeof( size_t ) - 1 )
    70 #else
    71     // Fallback case: tag in the least-significant bit.  Dereference
    72     // will often give an alignment error, but may not, e.g. if
    73     // accessing a char-typed member.  32-bit x86 uses the most-
    74     // significant bit for real room on the heap.
    75     #define ORIGIN_TAG_BITNO 0
    76 #endif
    77 #define ORIGIN_TAG_MASK (((size_t)1) << ORIGIN_TAG_BITNO)
    78 
    79 #define ORIGIN_TAG_SET(p)   ((p) |  ORIGIN_TAG_MASK)
    80 #define ORIGIN_TAG_CLEAR(p) ((p) & ~ORIGIN_TAG_MASK)
    81 #define ORIGIN_TAG_QUERY(p) ((p) &  ORIGIN_TAG_MASK)
    82 
    83 
    84 forall( tE & ) {
    85 
    86     struct dlink{
    87         tE *next;
    88         tE *prev;
    89     };
    90 
    91     static inline void ?{}( dlink(tE) & this ) {
    92         this.next = 0p;
    93         this.prev = 0p;
    94     }
    95 
    96     forall( tLinks & = dlink(tE) )
    97     struct dlist {
    98         inline dlink(tE);
    99     };
    100 
    101     forall( tLinks & | embedded( tE, tLinks, dlink(tE) ) ) {
    102         static inline tE * $get_list_origin_addr( dlist(tE, tLinks) & lst ) {
    103             dlink(tE) & link_from_null = ( * (tE *) 0p )`inner;
    104             ptrdiff_t link_offset = (ptrdiff_t) & link_from_null;
    105             size_t origin_addr = ((size_t) & lst) - link_offset;
    106             size_t preResult = ORIGIN_TAG_SET( origin_addr );
    107             return (tE *)preResult;
    108         }
    109 
    110         static inline void ?{}( dlist(tE, tLinks) & this ) {
    111             tE * listOrigin = $get_list_origin_addr( this );
    112             ( ( dlink(tE) & ) this ){ listOrigin, listOrigin } ;
    113         }
    114     }
    115 
    116 }
    117 
    118 
    119 forall( tE &, tLinks & | embedded( tE, tLinks, dlink(tE) ) ) {
    120 
    121         static inline void insert_after(tE & list_pos, tE &to_insert) {
     132forall (Tnode &, Telem & | $dlistable(Tnode, Telem)) {
     133
     134        // implemented as a sentinel item in an underlying cicrular list
     135        // theList.$links.next is first
     136        // theList.$links.prev is last
     137        // note this allocation preserves prev-next composition as an identity
     138        struct dlist {
     139                $dlinks(Telem) $links;
     140        };
     141
     142        // an empty dlist
     143        // links refer to self, making a tight circle
     144        static inline void ?{}( dlist(Tnode, Telem) & this ) {
     145                $mgd_link(Telem) selfRef = (void *) &this;
     146                ( this.$links ) { selfRef, selfRef };
     147        }
     148
     149        static inline Telem & ?`first( dlist(Tnode, Telem) &l ) {
     150                return * l.$links.next.elem;
     151        }
     152
     153        static inline Telem & ?`last( dlist(Tnode, Telem) &l ) {
     154                return * l.$links.prev.elem;
     155        }
     156
     157        #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))
     158        static bool $validate_fwd( dlist(Tnode, Telem) & this ) {
     159                Tnode * it = & $tempcv_e2n( this`first );
     160                if (!it) return (& this`last == 0p);
     161
     162                while( $next_link(*it).elem ) {
     163                        it = & $tempcv_e2n( * $next_link(*it).elem );
     164                }
     165
     166                return ( it == & $tempcv_e2n( this`last ) ) &&
     167                           ( $next_link(*it).is_terminator ) &&
     168                           ( ((dlist(Tnode, Telem)*)$next_link(*it).terminator) == &this );
     169        }
     170        static bool $validate_rev( dlist(Tnode, Telem) & this ) {
     171                Tnode * it = & $tempcv_e2n( this`last );
     172                if (!it) return (& this`first == 0p);
     173
     174                while( $prev_link(*it).elem ) {
     175                        it = & $tempcv_e2n( * $prev_link(*it).elem );
     176                }
     177
     178                return ( it == & $tempcv_e2n( this`first ) ) &&
     179                           ( $prev_link(*it).is_terminator ) &&
     180                           ( ((dlist(Tnode, Telem)*)$prev_link(*it).terminator) == &this );
     181        }
     182        static bool validate( dlist(Tnode, Telem) & this ) {
     183                return $validate_fwd(this) && $validate_rev(this);
     184        }
     185        #endif
     186
     187        static inline void insert_after(Tnode &list_pos, Telem &to_insert) {
    122188                verify (&list_pos != 0p);
    123189                verify (&to_insert != 0p);
    124         dlink(tE) & linkToInsert = to_insert`inner;
    125                 verify(linkToInsert.prev == 0p);
    126                 verify(linkToInsert.next == 0p);
    127         tE & list_pos_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & list_pos );
    128         dlink(tE) & list_pos_links = list_pos_elem`inner;
    129         asm( "" : : : "memory" );
    130         tE & after_raw = * list_pos_links.next;
    131         tE & after_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & after_raw );
    132                 linkToInsert.prev = & list_pos;
    133                 linkToInsert.next = & after_raw;
    134         dlink(tE) & afterLinks = after_elem`inner;
    135         afterLinks.prev = &to_insert;
    136                 list_pos_links.next = &to_insert;
    137         asm( "" : : : "memory" );
    138         }
    139 
    140         static inline void insert_before(tE & list_pos, tE &to_insert) {
     190                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
     191                verify($prev_link(singleton_to_insert).elem == 0p);
     192                verify($next_link(singleton_to_insert).elem == 0p);
     193                $prev_link(singleton_to_insert) = & $tempcv_n2e(list_pos);
     194                $next_link(singleton_to_insert) = $next_link(list_pos);
     195                if ($next_link(list_pos).is_terminator) {
     196                        dlist(Tnode, Telem) *list = ( dlist(Tnode, Telem) * ) $next_link(list_pos).terminator;
     197                        $dlinks(Telem) *list_links = & list->$links;
     198                        $mgd_link(Telem) *list_last = & list_links->prev;
     199                        *list_last = &to_insert;
     200                } else {
     201                        Telem *list_pos_next = $next_link(list_pos).elem;
     202                        if (list_pos_next) {
     203                                Tnode & lpn_inlist = $tempcv_e2n(*list_pos_next);
     204                                $prev_link(lpn_inlist) = &to_insert;
     205                        }
     206                }
     207                $next_link(list_pos) = &to_insert;
     208        }
     209
     210        static inline void insert_before(Tnode &list_pos, Telem &to_insert) {
    141211                verify (&list_pos != 0p);
    142212                verify (&to_insert != 0p);
    143         dlink(tE) & linkToInsert = to_insert`inner;
    144                 verify(linkToInsert.next == 0p);
    145                 verify(linkToInsert.prev == 0p);
    146         tE & list_pos_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & list_pos );
    147         dlink(tE) & list_pos_links = list_pos_elem`inner;
    148         asm( "" : : : "memory" );
    149         tE & before_raw = * (list_pos_links).prev;
    150         tE & before_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & before_raw );
    151                 linkToInsert.next = & list_pos;
    152                 linkToInsert.prev = & before_raw;
    153         dlink(tE) & beforeLinks = before_elem`inner;
    154         beforeLinks.next = &to_insert;
    155                 (list_pos_links).prev = &to_insert;
    156         asm( "" : : : "memory" );
    157         }
    158 
    159         static inline tE & remove(tE & list_pos) {
    160                 verify (&list_pos != 0p);
    161         verify( ! ORIGIN_TAG_QUERY((size_t) & list_pos) );
    162         dlink(tE) & list_pos_links = list_pos`inner;
    163         tE & before_raw = * list_pos_links.prev;
    164         tE & before_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & before_raw );
    165         dlink(tE) & before_links = before_elem`inner;
    166         tE & after_raw = * list_pos_links.next;
    167         tE & after_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & after_raw );
    168         dlink(tE) & after_links = after_elem`inner;
    169         before_links.next = &after_raw;
    170         after_links.prev = &before_raw;
    171         asm( "" : : : "memory" );
    172                 list_pos_links.prev = 0p;
    173                 list_pos_links.next = 0p;
    174         asm( "" : : : "memory" );
    175         return list_pos;
    176         }
    177 
    178     static inline tE & ?`first( dlist(tE, tLinks) &lst ) {
    179         tE * firstPtr = lst.next;
    180         if (ORIGIN_TAG_QUERY((size_t)firstPtr)) firstPtr = 0p;
    181         return *firstPtr;
    182     }
    183     static inline tE & ?`last ( dlist(tE, tLinks) &lst ) {
    184         tE * lastPtr = lst.prev;
    185         if (ORIGIN_TAG_QUERY((size_t)lastPtr)) lastPtr = 0p;
    186         return *lastPtr;
    187     }
    188 
    189     static inline bool ?`isEmpty( dlist(tE, tLinks) & lst ) {
    190         tE * firstPtr = lst.next;
    191         if (ORIGIN_TAG_QUERY((size_t)firstPtr)) firstPtr = 0p;
    192         return firstPtr == 0p;
    193     }
    194 
    195     static inline bool ?`isListed( tE & e ) {
    196                 verify (&e != 0p);
    197         dlink(tE) & e_links = e`inner;
    198                 return (e_links.prev != 0p) || (e_links.next != 0p);
    199     }
    200 
    201     static inline tE & ?`elems( dlist(tE, tLinks) & lst ) {
    202         tE * origin = $get_list_origin_addr( lst );
    203         return *origin;
    204     }
    205 
    206     static inline bool ?`moveNext( tE && refx ) {
    207         tE && ref_inner = refx;
    208         tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner );
    209         &ref_inner = oldReferent`inner.next;
    210         return &ref_inner != 0p  &&
    211             ! ORIGIN_TAG_QUERY( (size_t) & ref_inner );
    212     }
    213 
    214     static inline bool ?`movePrev( tE && refx ) {
    215         tE && ref_inner = refx;
    216         tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner );
    217         &ref_inner = oldReferent`inner.prev;
    218         return &ref_inner != 0p  &&
    219             ! ORIGIN_TAG_QUERY( (size_t) & ref_inner );
    220     }
    221 
    222     static inline bool ?`hasNext( tE & e ) {
    223         return e`moveNext;
    224     }
    225 
    226     static inline bool ?`hasPrev( tE & e ) {
    227         return e`movePrev;
    228     }
    229 
    230     static inline tE & ?`next( tE & e ) {
    231         if( e`moveNext ) return e;
    232         return * 0p;
    233     }
    234 
    235     static inline tE & ?`prev( tE & e ) {
    236         if( e`movePrev ) return e;
    237         return * 0p;
    238     }
    239 
    240     static inline void insert_first( dlist(tE, tLinks) &lst, tE & e ) {
    241         insert_after(lst`elems, e);
    242     }
    243 
    244     static inline void insert_last( dlist(tE, tLinks) &lst, tE & e ) {
    245         insert_before(lst`elems, e);
    246     }
    247 
    248     static inline tE & try_pop_front( dlist(tE, tLinks) &lst ) {
    249         tE & first_inlist = lst`first;
    250         tE & first_item = first_inlist;
    251         if (&first_item) remove(first_inlist);
    252         return first_item;
    253     }
    254 
    255     static inline tE & try_pop_back( dlist(tE, tLinks) &lst ) {
    256         tE & last_inlist = lst`last;
    257         tE & last_item = last_inlist;
    258         if (&last_item) remove(last_inlist);
    259         return last_item;
    260     }
    261 
    262 
    263   #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))
    264         static bool $validate_fwd( dlist(tE, tLinks) & this ) {
    265         if ( ! & this`first ) return ( (& this`last) == 0p);
    266 
    267         tE & lagElem = *0p;
    268 
    269         while ( tE & it = this`elems; it`moveNext ) {
    270             if (& lagElem == 0p &&  &it != & this`first ) return false;
    271             & lagElem = & it;
    272         }
    273 
    274         if (& lagElem != & this`last) return false;
    275 
    276         // TODO: verify that it is back at this`elems;
    277         return true;
    278         }
    279         static bool $validate_rev( dlist(tE, tLinks) & this ) {
    280         if ( ! & this`last ) return ( (& this`first) == 0p);
    281 
    282         tE & lagElem = *0p;
    283 
    284         while ( tE & it = this`elems; it`movePrev ) {
    285             if (& lagElem == 0p &&  &it != & this`last ) return false;
    286             & lagElem = & it;
    287         }
    288 
    289         if (& lagElem != & this`first) return false;
    290 
    291         // TODO: verify that it is back at this`elems;
    292         return true;
    293         }
    294         static bool validate( dlist(tE, tLinks) & this ) {
    295                 return $validate_fwd(this) && $validate_rev(this);
    296         }
    297   #endif
     213                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
     214                verify($prev_link(singleton_to_insert).elem == 0p);
     215                verify($next_link(singleton_to_insert).elem == 0p);
     216                $next_link(singleton_to_insert) = & $tempcv_n2e(list_pos);
     217                $prev_link(singleton_to_insert) = $prev_link(list_pos);
     218                if ($prev_link(list_pos).is_terminator) {
     219                        dlist(Tnode, Telem) *list = ( dlist(Tnode, Telem) * ) $prev_link(list_pos).terminator;
     220                        $dlinks(Telem) *list_links = & list->$links;
     221                        $mgd_link(Telem) *list_first = & list_links->next;
     222                        *list_first = &to_insert;
     223                } else {
     224                        Telem *list_pos_prev = $prev_link(list_pos).elem;
     225                        if (list_pos_prev) {
     226                                Tnode & lpp_inlist = $tempcv_e2n(*list_pos_prev);
     227                                $next_link(lpp_inlist) = &to_insert;
     228                        }
     229                }
     230                $prev_link(list_pos) = &to_insert;
     231        }
     232
     233    static inline void insert_first(dlist(Tnode, Telem) &list, Telem &to_insert) {
     234                verify (&list != 0p);
     235                verify (&to_insert != 0p);
     236                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
     237                verify($prev_link(singleton_to_insert).elem == 0p);
     238                verify($next_link(singleton_to_insert).elem == 0p);
     239
     240                $prev_link(singleton_to_insert) = (void*) &list;
     241                $next_link(singleton_to_insert) = list.$links.next;
     242
     243                $dlinks(Telem) *listLinks = & list.$links;
     244                if (listLinks->next.is_terminator) {
     245                        $mgd_link(Telem) * listPrevReference = & listLinks->prev;
     246                        *listPrevReference = &to_insert;
     247                } else {
     248                        Tnode & next_inlist = $tempcv_e2n(*list.$links.next.elem);
     249                        $prev_link(next_inlist) = &to_insert;
     250                }
     251                $mgd_link(Telem) * listNextReference = & listLinks->next;
     252                *listNextReference = &to_insert;
     253        }
     254
     255    static inline void insert_last(dlist(Tnode, Telem) &list, Telem &to_insert) {
     256                verify (&list != 0p);
     257                verify (&to_insert != 0p);
     258                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
     259                verify($next_link(singleton_to_insert).elem == 0p);
     260                verify($prev_link(singleton_to_insert).elem == 0p);
     261
     262                $next_link(singleton_to_insert) = (void*) &list;
     263                $prev_link(singleton_to_insert) = list.$links.prev;
     264
     265                $dlinks(Telem) *listLinks = & list.$links;
     266                if (listLinks->prev.is_terminator) {
     267                        $mgd_link(Telem) * listNextReference = & listLinks->next;
     268                        *listNextReference = &to_insert;
     269                } else {
     270                        Tnode & prev_inlist = $tempcv_e2n(*list.$links.prev.elem);
     271                        $next_link(prev_inlist) = &to_insert;
     272                }
     273                $mgd_link(Telem) * listPrevReference = & listLinks->prev;
     274                *listPrevReference = &to_insert;
     275        }
     276
     277    static inline void remove(Tnode &list_pos) {
     278                verify( &list_pos != 0p );
     279
     280                $mgd_link(Telem) &incoming_from_prev = *0p;
     281                $mgd_link(Telem) &incoming_from_next = *0p;
     282
     283                if ( $prev_link(list_pos).is_terminator ) {
     284                        dlist(Tnode, Telem) * tgt_before = ( dlist(Tnode, Telem) * ) $prev_link(list_pos).terminator;
     285                        $dlinks(Telem) * links_before = & tgt_before->$links;
     286                        &incoming_from_prev = & links_before->next;
     287                } else if ($prev_link(list_pos).elem) {
     288                        Telem * tgt_before = $prev_link(list_pos).elem;
     289                        Tnode & list_pos_before = $tempcv_e2n(*tgt_before);
     290                        &incoming_from_prev = & $next_link(list_pos_before);
     291                }
     292
     293                if ( $next_link(list_pos).is_terminator ) {
     294                        dlist(Tnode, Telem) * tgt_after = ( dlist(Tnode, Telem) * ) $next_link(list_pos).terminator;
     295                        $dlinks(Telem) * links_after = & tgt_after->$links;
     296                        &incoming_from_next = & links_after->prev;
     297                } else if ($next_link(list_pos).elem) {
     298                        Telem * tgt_after  = $next_link(list_pos).elem;
     299                        Tnode & list_pos_after  = $tempcv_e2n(*tgt_after );
     300                        &incoming_from_next = & $prev_link(list_pos_after );
     301                }
     302
     303                if (& incoming_from_prev) {
     304                        incoming_from_prev = $next_link(list_pos);
     305                }
     306                if (& incoming_from_next) {
     307                        incoming_from_next = $prev_link(list_pos);
     308                }
     309
     310                $next_link(list_pos) = (Telem*) 0p;
     311                $prev_link(list_pos) = (Telem*) 0p;
     312        }
     313
     314        static inline bool ?`is_empty(dlist(Tnode, Telem) &list) {
     315                verify( &list != 0p );
     316                $dlinks(Telem) *listLinks = & list.$links;
     317                if (listLinks->next.is_terminator) {
     318                        verify(listLinks->prev.is_terminator);
     319                        verify(listLinks->next.terminator);
     320                        verify(listLinks->prev.terminator);
     321                        return true;
     322                } else {
     323                        verify(!listLinks->prev.is_terminator);
     324                        verify(listLinks->next.elem);
     325                        verify(listLinks->prev.elem);
     326                        return false;
     327                }
     328        }
     329
     330        static inline Telem & pop_first(dlist(Tnode, Telem) &list) {
     331                verify( &list != 0p );
     332                verify( !list`is_empty );
     333                $dlinks(Telem) *listLinks = & list.$links;
     334                Telem & first = *listLinks->next.elem;
     335                Tnode & list_pos_first  = $tempcv_e2n( first );
     336                remove(list_pos_first);
     337                return first;
     338        }
     339
     340        static inline Telem & pop_last(dlist(Tnode, Telem) &list) {
     341                verify( &list != 0p );
     342                verify( !list`is_empty );
     343                $dlinks(Telem) *listLinks = & list.$links;
     344                Telem & last = *listLinks->prev.elem;
     345                Tnode & list_pos_last  = $tempcv_e2n( last );
     346                remove(list_pos_last);
     347                return last;
     348        }
    298349
    299350}
  • libcfa/src/exception.c

    r8d66610 r5407cdc  
    4848
    4949// Base Exception type id:
    50 struct __cfavir_type_info __cfatid_exception_t = {
     50struct __cfa__parent_vtable __cfatid_exception_t = {
    5151        NULL,
    5252};
  • libcfa/src/exception.h

    r8d66610 r5407cdc  
    2929struct __cfaehm_base_exception_t;
    3030typedef struct __cfaehm_base_exception_t exception_t;
    31 struct __cfavir_type_info;
     31struct __cfa__parent_vtable;
    3232struct __cfaehm_base_exception_t_vtable {
    33         const struct __cfavir_type_info * __cfavir_typeid;
     33        const struct __cfa__parent_vtable * __cfavir_typeid;
    3434        size_t size;
    3535        void (*copy)(struct __cfaehm_base_exception_t *this,
     
    4141        struct __cfaehm_base_exception_t_vtable const * virtual_table;
    4242};
    43 extern struct __cfavir_type_info __cfatid_exception_t;
     43extern struct __cfa__parent_vtable __cfatid_exception_t;
    4444
    4545
  • libcfa/src/exception.hfa

    r8d66610 r5407cdc  
    157157#define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \
    158158        forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \
    159                 __cfavir_type_info const * parent; \
     159                __cfa__parent_vtable const * parent; \
    160160        }
    161161
    162162// Generate a new type-id value.
    163163#define _EHM_TYPE_ID_VALUE(exception_name, arguments) \
    164         __attribute__((cfa_linkonce)) \
     164        __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \
    165165        _EHM_TYPE_ID_TYPE(exception_name) arguments const \
    166166                        _EHM_TYPE_ID_NAME(exception_name) = { \
  • libcfa/src/executor.cfa

    r8d66610 r5407cdc  
    77#include <containers/list.hfa>
    88
    9 forall( T &, TLink& = dlink(T) | embedded(T, TLink, dlink(T)) ) {
     9forall( T & | $dlistable(T, T) ) {
    1010        monitor Buffer {                                                                        // unbounded buffer
    11                 dlist( T, TLink ) queue;                                                // unbounded list of work requests
     11                dlist( T, T ) queue;                                                    // unbounded list of work requests
    1212                condition delay;
    1313        }; // Buffer
    1414
    15         void insert( Buffer(T, TLink) & mutex buf, T * elem ) with(buf) {
    16                 dlist( T, TLink ) * qptr = &queue;                              // workaround https://cforall.uwaterloo.ca/trac/ticket/166
     15        void insert( Buffer(T) & mutex buf, T * elem ) with(buf) {
     16                dlist( T, T ) * qptr = &queue;                                  // workaround https://cforall.uwaterloo.ca/trac/ticket/166
    1717                insert_last( *qptr, *elem );                                    // insert element into buffer
    1818                signal( delay );                                                                // restart
    1919        } // insert
    2020
    21         T * remove( Buffer(T, TLink) & mutex buf ) with(buf) {
    22                 dlist( T, TLink ) * qptr = &queue;                              // workaround https://cforall.uwaterloo.ca/trac/ticket/166
    23                 // if ( (*qptr)`isEmpty ) wait( delay );                // no request to process ? => wait
    24           if ( (*qptr)`isEmpty ) return 0p;                                     // no request to process ? => wait
    25                 return &try_pop_front( *qptr );
     21        T * remove( Buffer(T) & mutex buf ) with(buf) {
     22                dlist( T, T ) * qptr = &queue;                                  // workaround https://cforall.uwaterloo.ca/trac/ticket/166
     23                // if ( (*qptr)`is_empty ) wait( delay );                       // no request to process ? => wait
     24          if ( (*qptr)`is_empty ) return 0p;                            // no request to process ? => wait
     25                return &pop_first( *qptr );
    2626        } // remove
    2727} // forall
     
    2929struct WRequest {                                                                               // client request, no return
    3030        void (* action)( void );
    31         inline dlink(WRequest);
     31        DLISTED_MGD_IMPL_IN(WRequest)
    3232}; // WRequest
    33 P9_EMBEDDED(WRequest, dlink(WRequest))
     33DLISTED_MGD_IMPL_OUT(WRequest)
    3434
    3535void ?{}( WRequest & req ) with(req) { action = 0; }
  • libcfa/src/fstream.cfa

    r8d66610 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 28 20:37:53 2021
    13 // Update Count     : 445
     12// Last Modified On : Tue Apr 27 22:08:57 2021
     13// Update Count     : 442
    1414//
    1515
     
    114114} // fail
    115115
    116 void clear( ofstream & os ) {
    117         clearerr( (FILE *)(os.file$) );
    118 } // clear
    119 
    120116int flush( ofstream & os ) {
    121117        return fflush( (FILE *)(os.file$) );
     
    211207} // nl
    212208
    213 
    214209// *********************************** ifstream ***********************************
    215210
     
    245240} // fail
    246241
    247 void clear( ifstream & is ) {
    248         clearerr( (FILE *)(is.file$) );
    249 } // clear
    250 
    251242void ends( ifstream & is ) {
    252243        if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
    253244} // ends
    254245
    255 bool eof( ifstream & is ) {
     246int eof( ifstream & is ) {
    256247        return feof( (FILE *)(is.file$) );
    257248} // eof
     
    282273} // close
    283274
    284 ifstream & read( ifstream & is, char data[], size_t size ) {
     275ifstream & read( ifstream & is, char * data, size_t size ) {
    285276        if ( fail( is ) ) {
    286277                abort | IO_MSG "attempt read I/O on failed stream";
  • libcfa/src/fstream.hfa

    r8d66610 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 28 20:37:57 2021
    13 // Update Count     : 230
     12// Last Modified On : Tue Apr 27 22:00:30 2021
     13// Update Count     : 226
    1414//
    1515
     
    7070
    7171bool fail( ofstream & );
    72 void clear( ofstream & );
    7372int flush( ofstream & );
    7473void open( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w"
     
    120119
    121120bool fail( ifstream & is );
    122 void clear( ifstream & );
    123 bool eof( ifstream & is );
     121int eof( ifstream & is );
    124122void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"
    125123void open( ifstream & is, const char name[] );
    126124void close( ifstream & is );
    127 ifstream & read( ifstream & is, char data[], size_t size );
     125ifstream & read( ifstream & is, char * data, size_t size );
    128126ifstream & ungetc( ifstream & is, char c );
    129127
  • libcfa/src/heap.cfa

    r8d66610 r5407cdc  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  5 13:11:28 2021
    13 // Update Count     : 1035
     12// Last Modified On : Tue Apr 20 21:20:48 2021
     13// Update Count     : 1033
    1414//
    1515
     
    2828#include "bits/locks.hfa"                                                               // __spinlock_t
    2929#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    30 #include "math.hfa"                                                                             // min
     30#include "math.hfa"                                                                             // ceiling
    3131#include "bitmanip.hfa"                                                                 // is_pow2, ceiling2
    3232
  • libcfa/src/iostream.cfa

    r8d66610 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 15 09:39:21 2021
    13 // Update Count     : 1342
     12// Last Modified On : Tue Apr 27 18:01:03 2021
     13// Update Count     : 1330
    1414//
    1515
     
    659659                        int exp10, len2; \
    660660                        eng( f.val, f.pc, exp10 );                                      /* changes arguments */ \
    661                         /* printf( "%g %d %d %d %s\n", f.val, f.wd, f.pc, exp10, format ); */ \
    662661                        if ( ! f.flags.left && f.wd > 1 ) { \
    663                                 /* Exponent size: 'e', optional minus sign, number of digits: log10(0) => undefined */ \
    664                                 f.wd -= 1 + (exp10 < 0 ? 1 : 0) + lrint( floor( exp10 == 0 ? 0 : log10( abs( exp10 ) ) ) ) + 1; \
     662                                /* Exponent size (number of digits, 'e', optional minus sign) */ \
     663                                f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \
    665664                                if ( f.wd < 1 ) f.wd = 1; \
    666665                        } /* if */ \
     
    709708                if ( ! f.flags.pc ) {                                                   /* no precision */ \
    710709                        fmtstr[sizeof(DFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    711                         /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star] ); */ \
     710                        /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
    712711                        PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
    713712                } else {                                                                                /* precision */ \
  • libcfa/src/iostream.hfa

    r8d66610 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 28 20:37:56 2021
    13 // Update Count     : 401
     12// Last Modified On : Tue Apr 27 17:59:21 2021
     13// Update Count     : 398
    1414//
    1515
     
    5252       
    5353trait ostream( ostype & | basic_ostream( ostype ) ) {
     54        int flush( ostype & );
    5455        bool fail( ostype & );                                                          // operation failed?
    55         void clear( ostype & );
    56         int flush( ostype & );
    5756        void open( ostype &, const char name[], const char mode[] );
    5857        void close( ostype & );
     
    303302        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    304303        istype & ungetc( istype &, char );
    305         bool eof( istype & );
     304        int eof( istype & );
    306305}; // basic_istream
    307306
    308307trait istream( istype & | basic_istream( istype ) ) {
    309308        bool fail( istype & );
    310         void clear( istype & );
    311309        void open( istype & is, const char name[] );
    312310        void close( istype & is );
    313         istype & read( istype &, char [], size_t );
     311        istype & read( istype &, char *, size_t );
    314312        void acquire( istype & );                                                       // concurrent access
    315313}; // istream
  • libcfa/src/virtual.c

    r8d66610 r5407cdc  
    1010// Created On       : Tus Jul 11 15:10:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon May 17 11:01:00 2021
    13 // Update Count     : 2
     12// Last Modified On : Wed Jul 26 14:24:00 2017
     13// Update Count     : 1
    1414//
    1515
     
    1717#include "assert.h"
    1818
    19 int __cfavir_is_parent(
    20                 __cfavir_type_id parent,
    21                 __cfavir_type_id child ) {
     19int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
     20        struct __cfa__parent_vtable const * child ) {
    2221        assert( child );
    2322        do {
     
    2928}
    3029
    31 void * __cfavir_virtual_cast(
    32                 __cfavir_type_id parent,
    33                 __cfavir_type_id const * child ) {
     30void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
     31        struct __cfa__parent_vtable const * const * child ) {
    3432        assert( child );
    35         return (__cfavir_is_parent(parent, *child)) ? (void *)child : (void *)0;
     33        return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0;
    3634}
  • libcfa/src/virtual.h

    r8d66610 r5407cdc  
    1010// Created On       : Tus Jul 11 15:08:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon May 17 11:03:00 2021
    13 // Update Count     : 2
     12// Last Modified On : Wed Jul 26 14:18:00 2017
     13// Update Count     : 1
    1414//
    1515
     
    2020#endif
    2121
    22 // Information on a type for the virtual system.
    23 // There should be exactly one instance per type and there should be a
    24 // pointer to it at the head of every virtual table.
    25 struct __cfavir_type_info {
    26         // Type id of parent type, null if this is a root type.
    27     struct __cfavir_type_info const * const parent;
     22// All strict/explicate vtables should have this head, showing their parent.
     23struct __cfa__parent_vtable {
     24    struct __cfa__parent_vtable const * const parent;
    2825};
    2926
    30 // A pointer to type information acts as the type id.
    31 typedef struct __cfavir_type_info const * __cfavir_type_id;
    32 
    33 // Takes in two non-null type ids.
    34 int __cfavir_is_parent(
    35                 __cfavir_type_id parent, __cfavir_type_id child );
     27// Takes in two non-null pointers to type_objects.
     28int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
     29                struct __cfa__parent_vtable const * child );
    3630
    3731// If parent is a parent of child then return child, otherwise return NULL.
    3832// Input pointers are none-null, child's first level should be an object with
    3933// a vtable
    40 void * __cfavir_virtual_cast(
    41                 __cfavir_type_id parent, __cfavir_type_id const * child );
     34void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
     35                struct __cfa__parent_vtable const * const * child );
    4236
    4337#ifdef __cforall
  • src/CodeGen/module.mk

    r8d66610 r5407cdc  
    2525        CodeGen/GenType.cc \
    2626        CodeGen/GenType.h \
    27         CodeGen/LinkOnce.cc \
    28         CodeGen/LinkOnce.h \
    2927        CodeGen/OperatorTable.cc \
    3028        CodeGen/OperatorTable.h \
  • src/Concurrency/Keywords.cc

    r8d66610 r5407cdc  
    432432                                new ObjectDecl(
    433433                                        Virtual::concurrentDefaultVTableName(),
    434                                         noStorageClasses,
     434                                        Type::Const,
    435435                                        LinkageSpec::Cforall,
    436436                                        /* bitfieldWidth */ nullptr,
     
    504504                        new ObjectDecl(
    505505                                Virtual::concurrentDefaultVTableName(),
    506                                 Type::StorageClasses( Type::Extern ),
     506                                Type::Const,
    507507                                LinkageSpec::Cforall,
    508508                                /* bitfieldWidth */ nullptr,
  • src/GenPoly/Box.cc

    r8d66610 r5407cdc  
    15251525                                        stmtsToAddBefore.push_back( new DeclStmt( newBuf ) );
    15261526
    1527                                         // if the object has a cleanup attribute, the cleanup should be on the buffer, not the pointer
    1528                                         auto matchAndMove = [newBuf](Attribute * attr){
    1529                                                 if(attr->name == "cleanup") {
    1530                                                         newBuf->attributes.push_back(attr);
    1531                                                         return true;
    1532                                                 }
    1533                                                 return false;
    1534                                         };
    1535 
    1536                                         objectDecl->attributes.remove_if(matchAndMove);
    1537 
    15381527                                        delete objectDecl->get_init();
    15391528                                        objectDecl->set_init( new SingleInit( new VariableExpr( newBuf ) ) );
  • src/InitTweak/InitTweak.cc

    r8d66610 r5407cdc  
    12161216
    12171217        void addDataSectonAttribute( ObjectDecl * objDecl ) {
    1218                 objDecl->attributes.push_back(new Attribute("section", {
    1219                         new ConstantExpr( Constant::from_string(".data#") ),
    1220                 }));
     1218                Type *strLitT = new PointerType( Type::Qualifiers( ),
     1219                        new BasicType( Type::Qualifiers( ), BasicType::Char ) );
     1220                std::list< Expression * > attr_params;
     1221                attr_params.push_back(
     1222                        new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) );
     1223                objDecl->attributes.push_back(new Attribute("section", attr_params));
    12211224        }
    12221225
    12231226        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
    1224                 objDecl->attributes.push_back(new ast::Attribute("section", {
    1225                         ast::ConstantExpr::from_string(objDecl->location, ".data#"),
    1226                 }));
     1227                auto strLitT = new ast::PointerType(new ast::BasicType(ast::BasicType::Char));
     1228                objDecl->attributes.push_back(new ast::Attribute("section", {new ast::ConstantExpr(objDecl->location, strLitT, "\".data#\"", std::nullopt)}));
    12271229        }
    12281230
  • src/Parser/DeclarationNode.cc

    r8d66610 r5407cdc  
    10761076        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
    10771077                // otype is internally converted to dtype + otype parameters
    1078                 static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::Dtype };
     1078                static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::ALtype };
    10791079                static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
    10801080                assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
    1081                 TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype || variable.tyClass == TypeDecl::ALtype, variable.initializer ? variable.initializer->buildType() : nullptr );
     1081                TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype, variable.initializer ? variable.initializer->buildType() : nullptr );
    10821082                buildList( variable.assertions, ret->get_assertions() );
    10831083                return ret;
  • src/Virtual/ExpandCasts.cc

    r8d66610 r5407cdc  
    105105        void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
    106106                if ( (! vcast_decl) &&
    107                      functionDecl->get_name() == "__cfavir_virtual_cast" ) {
     107                     functionDecl->get_name() == "__cfa__virtual_cast" ) {
    108108                        vcast_decl = functionDecl;
    109109                }
     
    113113                if ( pvt_decl || ! structDecl->has_body() ) {
    114114                        return;
    115                 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {
     115                } else if ( structDecl->get_name() == "__cfa__parent_vtable" ) {
    116116                        pvt_decl = structDecl;
    117117                }
  • src/Virtual/Tables.cc

    r8d66610 r5407cdc  
    172172}
    173173
     174Attribute * linkonce( const std::string & subsection ) {
     175        const std::string section = ".gnu.linkonce." + subsection;
     176        return new Attribute( "section", {
     177                new ConstantExpr( Constant::from_string( section ) ),
     178        } );
     179}
     180
    174181ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    175182        assert( typeIdType );
     
    186193                        new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    187194                        ) } ),
    188                 { new Attribute( "cfa_linkonce", {} ) },
     195                { linkonce( typeid_name ) },
    189196                noFuncSpecifiers
    190197        );
  • src/main.cc

    r8d66610 r5407cdc  
    3737#include "CodeGen/FixNames.h"               // for fixNames
    3838#include "CodeGen/Generate.h"               // for generate
    39 #include "CodeGen/LinkOnce.h"               // for translateLinkOnce
    4039#include "CodeTools/DeclStats.h"            // for printDeclStats
    4140#include "CodeTools/ResolvProtoDump.h"      // for dumpAsResolvProto
     
    406405                PASS( "Box", GenPoly::box( translationUnit ) );
    407406
    408                 PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) );
    409 
    410                 // Code has been lowered to C, now we can start generation.
    411 
    412407                if ( bcodegenp ) {
    413408                        dump( translationUnit );
  • tests/Makefile.am

    r8d66610 r5407cdc  
    6767.PHONY: list .validate
    6868.INTERMEDIATE: .validate .validate.cfa
    69 EXTRA_PROGRAMS = avl_test linkonce .dummy_hack # build but do not install
     69EXTRA_PROGRAMS = avl_test .dummy_hack # build but do not install
    7070EXTRA_DIST = test.py \
    7171        pybin/__init__.py \
     
    9494
    9595avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    96 linkonce_SOURCES = link-once/main.cfa link-once/partner.cfa
    9796# automake doesn't know we still need C/CPP rules so pretend like we have a C program
    9897nodist__dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
  • tests/array-container/array-basic.cfa

    r8d66610 r5407cdc  
    55//
    66
    7 forall( [Nx], [Ny], [Nz] )
     7forall( ztype(Nx), ztype(Ny), ztype(Nz) )
    88void typesTest( tag(Nx), tag(Ny), tag(Nz) ) {
    99
     
    5959}
    6060
    61 forall( [Nw], [Nx], [Ny], [Nz] )
     61forall( ztype(Nw), ztype(Nx), ztype(Ny), ztype(Nz) )
    6262void fillHelloData( array( float, Nw, Nx, Ny, Nz ) & wxyz ) {
    6363    for (w; z(Nw))
     
    6868}
    6969
    70 forall( [Zn]
     70forall( ztype(Zn)
    7171      , S & | sized(S)
    7272      )
     
    8686}
    8787
    88 forall( [Nw], [Nx], [Ny], [Nz] )
     88forall( ztype(Nw), ztype(Nx), ztype(Ny), ztype(Nz) )
    8989void runtimeTest( tag(Nw), tag(Nx), tag(Ny), tag(Nz) ) {
    9090
     
    105105    printf("result Ws [][][][] lo = %f\n", result);
    106106
    107     result = total1d_low( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
    108     printf("result Ws [,,,]    lo = %f\n", result);
     107    // fixme: -[[-,-,-,-]] not working
     108    // result = total1d_low( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
     109    // printf("result Ws [,,,]    lo = %f\n", result);
    109110
    110111    result = total1d_hi( wxyz[all][slice_ix][slice_ix][slice_ix] );
    111112    printf("result Ws [][][][] hi = %f\n", result);
    112113
    113     result = total1d_hi( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
    114     printf("result Ws [,,,]    hi = %f\n", result);
     114    // fixme: -[[-,-,-,-]] not working
     115    // result = total1d_hi( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
     116    // printf("result Ws [,,,]    hi = %f\n", result);
    115117
    116118    // summing across X, with w=y=z=1
     
    124126    printf("result Xs [][][][] lo = %f\n", result);
    125127
    126     result = total1d_low( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
    127     printf("result Xs [,,,]    lo = %f\n", result);
     128    // fixme: -[[-,-,-,-]] not working
     129    // result = total1d_low( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
     130    // printf("result Xs [,,,]    lo = %f\n", result);
    128131
    129132    result = total1d_hi( wxyz[slice_ix][all][slice_ix][slice_ix] );   
    130133    printf("result Xs [][][][] hi = %f\n", result);
    131134
    132     result = total1d_hi( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
    133     printf("result Xs [,,,]    hi = %f\n", result);
     135    // fixme: -[[-,-,-,-]] not working
     136    // result = total1d_hi( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
     137    // printf("result Xs [,,,]    hi = %f\n", result);
    134138
    135139}
  • tests/concurrent/clib_tls.c

    r8d66610 r5407cdc  
    33#include <clib/cfathread.h>
    44#include <bits/defs.hfa>
    5 #include <time_t.hfa>
    65
    76extern "C" {
    87void _exit(int status);
    98}
    10 
    11 Duration default_preemption(){
    12         return 0;
    13 }
    14 
    159
    1610thread_local int checkval = 0xBAADF00D;
  • tests/exceptions/virtual-cast.cfa

    r8d66610 r5407cdc  
    1616// Hand defined alpha virtual type:
    1717struct __cfatid_struct_alpha {
    18         __cfavir_type_info parent;
     18        __cfa__parent_vtable const * parent;
    1919};
    2020
    21 __attribute__(( cfa_linkonce ))
     21__attribute__(( section(".gnu.linkonce.__cfatid_alpha") ))
    2222struct __cfatid_struct_alpha __cfatid_alpha = {
    23         (__cfavir_type_info *)0,
     23        (__cfa__parent_vtable *)0,
    2424};
    2525
  • tests/exceptions/virtual-poly.cfa

    r8d66610 r5407cdc  
    1010
    1111struct __cfatid_struct_mono_base {
    12     __cfavir_type_info const * parent;
     12    __cfa__parent_vtable const * parent;
    1313};
    1414
    15 __attribute__(( cfa_linkonce ))
     15__attribute__(( section(".gnu.linkonce.__cfatid_mono_base") ))
    1616struct __cfatid_struct_mono_base __cfatid_mono_base = {
    17     (__cfavir_type_info *)0,
     17    (__cfa__parent_vtable *)0,
    1818};
    1919
     
    5858forall(U)
    5959struct __cfatid_struct_poly_base {
    60     __cfavir_type_info const * parent;
     60    __cfa__parent_vtable const * parent;
    6161};
    6262
     
    8787
    8888__cfatid_struct_poly_base(int) __cfatid_poly_base @= {
    89         (__cfavir_type_info *)0,
     89        (__cfa__parent_vtable *)0,
    9090};
    9191__cfatid_struct_poly_child(int) __cfatid_poly_child = {
  • tests/list/.expect/dlist-insert-remove.txt

    r8d66610 r5407cdc  
     1~~~~~~~~~~~~~~~~~ Headless List Tests - insert_after ~~~~~~~~~~~~~~~~
     2
     3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     4Test 1-i:  Modifying Freds on MINE
     5~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     6==== fred by MINE before
     73.14
     8-
     93.14
     10-
     110.5
     12-
     130.5
     14-
     15==== fred by YOURS before
     163.14
     17-
     183.14
     19-
     200.5
     21-
     220.5
     23-
     24==== fred by MINE after
     253.14
     260.5
     27-
     283.14
     29-
     300.5
     31-
     320.5
     333.14
     34-
     35==== fred by YOURS after
     363.14
     37-
     383.14
     39-
     400.5
     41-
     420.5
     43-
     44~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     45Test 2-i.  Modifying Freds on YOURS
     46~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     47==== fred by MINE before
     483.14
     49-
     503.14
     51-
     520.5
     53-
     540.5
     55-
     56==== fred by YOURS before
     573.14
     58-
     593.14
     60-
     610.5
     62-
     630.5
     64-
     65==== fred by MINE after
     663.14
     67-
     683.14
     69-
     700.5
     71-
     720.5
     73-
     74==== fred by YOURS after
     753.14
     760.5
     77-
     783.14
     79-
     800.5
     81-
     820.5
     833.14
     84-
     85~~~~~~~~~~~~~~~~~~~~~~~~~~~
     86Test 3-i.  Modifying Maries
     87~~~~~~~~~~~~~~~~~~~~~~~~~~~
     88==== mary before
     893.14
     90-
     913.14
     92-
     930.5
     94-
     950.5
     96-
     97==== mary after
     983.14
     990.5
     100-
     1013.14
     102-
     1030.5
     104-
     1050.5
     1063.14
     107-
     108
     109~~~~~~~~~~~~~~~~ Headless List Tests - insert_before ~~~~~~~~~~~~~~~~
     110
     111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     112Test 1-ii:  Modifying Freds on MINE
     113~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     114==== fred by MINE before
     1153.14
     116-
     1173.14
     118-
     1190.5
     120-
     1210.5
     122-
     123==== fred by YOURS before
     1243.14
     125-
     1263.14
     127-
     1280.5
     129-
     1300.5
     131-
     132==== fred by MINE after
     1333.14
     1340.5
     135-
     1363.14
     137-
     1380.5
     139-
     1400.5
     1413.14
     142-
     143==== fred by YOURS after
     1443.14
     145-
     1463.14
     147-
     1480.5
     149-
     1500.5
     151-
     152~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     153Test 2-ii.  Modifying Freds on YOURS
     154~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     155==== fred by MINE before
     1563.14
     157-
     1583.14
     159-
     1600.5
     161-
     1620.5
     163-
     164==== fred by YOURS before
     1653.14
     166-
     1673.14
     168-
     1690.5
     170-
     1710.5
     172-
     173==== fred by MINE after
     1743.14
     175-
     1763.14
     177-
     1780.5
     179-
     1800.5
     181-
     182==== fred by YOURS after
     1833.14
     1840.5
     185-
     1863.14
     187-
     1880.5
     189-
     1900.5
     1913.14
     192-
     193~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     194Test 3-ii.  Modifying Maries
     195~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     196==== mary before
     1973.14
     198-
     1993.14
     200-
     2010.5
     202-
     2030.5
     204-
     205==== mary after
     2063.14
     2070.5
     208-
     2093.14
     210-
     2110.5
     212-
     2130.5
     2143.14
     215-
    1216
    2217~~~~~~~~~~~~~~~~~ Headed List Tests - insert_first ~~~~~~~~~~~~~~~~~~
     
    342557-
    343558
     559~~~~~~~~~~ Element removal tests on Headless List: mid ~~~~~~~~~~
     560
     561~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     562Test 10-i.  Modifying Freds on MINE
     563~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     564==== fred by MINE before
     5651.7
     5662.7
     5673.7
     568-
     5691.7
     570-
     5713.7
     572-
     5733.7
     5742.7
     5751.7
     576-
     577==== fred by YOURS before
     5781.7
     5792.7
     5803.7
     581-
     5821.7
     583-
     5843.7
     585-
     5863.7
     5872.7
     5881.7
     589-
     590==== fred by MINE after
     5911.7
     5923.7
     593-
     5941.7
     595-
     5963.7
     597-
     5983.7
     5991.7
     600-
     601==== fred by YOURS after
     6021.7
     6032.7
     6043.7
     605-
     6061.7
     607-
     6083.7
     609-
     6103.7
     6112.7
     6121.7
     613-
     614==== fred by MINE after
     6152.7
     616-
     6172.7
     618-
     619-
     620-
     621~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     622Test 11-i.  Modifying Freds on YOURS
     623~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     624==== fred by MINE before
     6251.7
     6262.7
     6273.7
     628-
     6291.7
     630-
     6313.7
     632-
     6333.7
     6342.7
     6351.7
     636-
     637==== fred by YOURS before
     6381.7
     6392.7
     6403.7
     641-
     6421.7
     643-
     6443.7
     645-
     6463.7
     6472.7
     6481.7
     649-
     650==== fred by MINE after
     6511.7
     6522.7
     6533.7
     654-
     6551.7
     656-
     6573.7
     658-
     6593.7
     6602.7
     6611.7
     662-
     663==== fred by YOURS after
     6641.7
     6653.7
     666-
     6671.7
     668-
     6693.7
     670-
     6713.7
     6721.7
     673-
     674==== fred by YOURS after
     6752.7
     676-
     6772.7
     678-
     679-
     680-
     681~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     682Test 12-i.  Modifying Maries
     683~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     684==== mary before
     6851.7
     6862.7
     6873.7
     688-
     6891.7
     690-
     6913.7
     692-
     6933.7
     6942.7
     6951.7
     696-
     697==== mary after
     6981.7
     6993.7
     700-
     7011.7
     702-
     7033.7
     704-
     7053.7
     7061.7
     707-
     708==== mary after
     7092.7
     710-
     7112.7
     712-
     713-
     714-
     715
     716~~~~~~~~~~ Element removal tests on Headless List: at first ~~~~~~~~~~
     717
     718~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     719Test 10-ii.  Modifying Freds on MINE
     720~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     721==== fred by MINE before
     7221.7
     7232.7
     7243.7
     725-
     7261.7
     727-
     7283.7
     729-
     7303.7
     7312.7
     7321.7
     733-
     734==== fred by YOURS before
     7351.7
     7362.7
     7373.7
     738-
     7391.7
     740-
     7413.7
     742-
     7433.7
     7442.7
     7451.7
     746-
     747==== fred by MINE after
     7482.7
     7493.7
     750-
     7512.7
     752-
     7533.7
     754-
     7553.7
     7562.7
     757-
     758==== fred by YOURS after
     7591.7
     7602.7
     7613.7
     762-
     7631.7
     764-
     7653.7
     766-
     7673.7
     7682.7
     7691.7
     770-
     771==== fred by MINE after
     7721.7
     773-
     7741.7
     775-
     776-
     777-
     778~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     779Test 11-ii.  Modifying Freds on YOURS
     780~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     781==== fred by MINE before
     7821.7
     7832.7
     7843.7
     785-
     7861.7
     787-
     7883.7
     789-
     7903.7
     7912.7
     7921.7
     793-
     794==== fred by YOURS before
     7951.7
     7962.7
     7973.7
     798-
     7991.7
     800-
     8013.7
     802-
     8033.7
     8042.7
     8051.7
     806-
     807==== fred by MINE after
     8081.7
     8092.7
     8103.7
     811-
     8121.7
     813-
     8143.7
     815-
     8163.7
     8172.7
     8181.7
     819-
     820==== fred by YOURS after
     8212.7
     8223.7
     823-
     8242.7
     825-
     8263.7
     827-
     8283.7
     8292.7
     830-
     831==== fred by YOURS after
     8321.7
     833-
     8341.7
     835-
     836-
     837-
     838~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     839Test 12-ii.  Modifying Maries
     840~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     841==== mary before
     8421.7
     8432.7
     8443.7
     845-
     8461.7
     847-
     8483.7
     849-
     8503.7
     8512.7
     8521.7
     853-
     854==== mary after
     8552.7
     8563.7
     857-
     8582.7
     859-
     8603.7
     861-
     8623.7
     8632.7
     864-
     865==== mary after
     8661.7
     867-
     8681.7
     869-
     870-
     871-
     872
     873~~~~~~~~~~ Element removal tests on Headless List: at last ~~~~~~~~~~
     874
     875~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     876Test 10-iii.  Modifying Freds on MINE
     877~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     878==== fred by MINE before
     8791.7
     8802.7
     8813.7
     882-
     8831.7
     884-
     8853.7
     886-
     8873.7
     8882.7
     8891.7
     890-
     891==== fred by YOURS before
     8921.7
     8932.7
     8943.7
     895-
     8961.7
     897-
     8983.7
     899-
     9003.7
     9012.7
     9021.7
     903-
     904==== fred by MINE after
     9051.7
     9062.7
     907-
     9081.7
     909-
     9102.7
     911-
     9122.7
     9131.7
     914-
     915==== fred by YOURS after
     9161.7
     9172.7
     9183.7
     919-
     9201.7
     921-
     9223.7
     923-
     9243.7
     9252.7
     9261.7
     927-
     928==== fred by MINE after
     9293.7
     930-
     9313.7
     932-
     933-
     934-
     935~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     936Test 11-iii.  Modifying Freds on YOURS
     937~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     938==== fred by MINE before
     9391.7
     9402.7
     9413.7
     942-
     9431.7
     944-
     9453.7
     946-
     9473.7
     9482.7
     9491.7
     950-
     951==== fred by YOURS before
     9521.7
     9532.7
     9543.7
     955-
     9561.7
     957-
     9583.7
     959-
     9603.7
     9612.7
     9621.7
     963-
     964==== fred by MINE after
     9651.7
     9662.7
     9673.7
     968-
     9691.7
     970-
     9713.7
     972-
     9733.7
     9742.7
     9751.7
     976-
     977==== fred by YOURS after
     9781.7
     9792.7
     980-
     9811.7
     982-
     9832.7
     984-
     9852.7
     9861.7
     987-
     988==== fred by YOURS after
     9893.7
     990-
     9913.7
     992-
     993-
     994-
     995~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     996Test 12-iii.  Modifying Maries
     997~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     998==== mary before
     9991.7
     10002.7
     10013.7
     1002-
     10031.7
     1004-
     10053.7
     1006-
     10073.7
     10082.7
     10091.7
     1010-
     1011==== mary after
     10121.7
     10132.7
     1014-
     10151.7
     1016-
     10172.7
     1018-
     10192.7
     10201.7
     1021-
     1022==== mary after
     10233.7
     1024-
     10253.7
     1026-
     1027-
     1028-
     1029
    3441030~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~
    3451031
     
    10921778-
    10931779-
    1094 
    1095 ~~~~~~~~~~~~~~~~~~~ Ease-of-access cases ~~~~~~~~~~~~~~~~~~
    1096 
    1097 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1098 Test 18-i.  Modifying Freds on MINE
    1099 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1100 Not implmented
    1101 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1102 Test 18-ii.  Modifying Freds on YOURS
    1103 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1104 Not implmented
    1105 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1106 Test 18-iii.  Modifying Maries
    1107 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1108 accessor_cases done
    1109 try_pop cases done
    1110 origin_mutation cases done
    1111 isListed cases done
  • tests/list/dlist-insert-remove.cfa

    r8d66610 r5407cdc  
    1919struct fred {
    2020        float adatum;
    21         inline struct mine { inline dlink(fred); };
    22         inline struct yours { inline dlink(fred); };
     21        DLISTED_MGD_EXPL_IN(fred, mine)
     22        DLISTED_MGD_EXPL_IN(fred, yours)
    2323};
    24 P9_EMBEDDED(fred, fred.mine)
    25 P9_EMBEDDED(fred, fred.yours)
    26 P9_EMBEDDED(fred.mine, dlink(fred))
    27 P9_EMBEDDED(fred.yours, dlink(fred))
    28 
     24
     25DLISTED_MGD_EXPL_OUT(fred, mine)
     26DLISTED_MGD_EXPL_OUT(fred, yours)
    2927
    3028void ?{}(fred &this, float adatum) {
     
    3533struct mary {
    3634        float anotherdatum;
    37         inline dlink(mary);
     35        DLISTED_MGD_IMPL_IN(mary)
    3836};
    3937
    40 P9_EMBEDDED(mary, dlink(mary))
     38DLISTED_MGD_IMPL_OUT(mary)
    4139
    4240void ?{}(mary &this, float anotherdatum) {
     
    5553////////////////////////////////////////////////////////////
    5654
    57 void printMyFredsFwd(fred & f) {
    58     with( DLINK_VIA( fred, fred.mine ) )
    59         do {
     55void printMyFredsFwd(fred &f) {
     56        while (&f != 0p) {
    6057                sout | f.adatum;
    61         } while (f`moveNext);
    62 }
    63 
    64 void printMyFredsRev(fred & f) {
    65     with( DLINK_VIA( fred, fred.mine ) )
    66         do {
     58                &f = &f`in_mine`next;
     59        }
     60}
     61
     62void printMyFredsRev(fred &f) {
     63        while (&f != 0p) {
    6764                sout | f.adatum;
    68         } while (f`movePrev);
    69 }
    70 
     65                &f = &f`in_mine`prev;
     66        }
     67}
    7168
    7269void printMyFreddies(fred &f1, fred &f2, int isBefore) {
     
    7673                sout | "==== fred by MINE after ";
    7774        }
    78         if (&f1) {
    79                 printMyFredsFwd(f1);    sout | '-';
    80                 printMyFredsRev(f1);    sout | '-';
    81         } else {
    82                 sout | '-'; sout | '-';
     75        printMyFredsFwd(f1);    sout | '-';
     76        printMyFredsRev(f1);    sout | '-';
     77        printMyFredsFwd(f2);    sout | '-';
     78        printMyFredsRev(f2);    sout | '-';
     79}
     80
     81void printYourFredsFwd(fred &f) {
     82        while (&f != 0p) {
     83                sout | f.adatum;
     84                &f = &f`in_yours`next;
    8385        }
    84         if (&f2) {
    85                 printMyFredsFwd(f2);    sout | '-';
    86                 printMyFredsRev(f2);    sout | '-';
    87         } else {
    88                 sout | '-'; sout | '-';
     86}
     87
     88void printYourFredsRev(fred &f) {
     89        while (&f != 0p) {
     90                sout | f.adatum;
     91                &f = &f`in_yours`prev;
    8992        }
    90 }
    91 
    92 void printYourFredsFwd(fred & f) {
    93     with( DLINK_VIA( fred, fred.yours ) )
    94         do {
    95                 sout | f.adatum;
    96         } while (f`moveNext);
    97 }
    98 
    99 void printYourFredsRev(fred & f) {
    100     with( DLINK_VIA( fred, fred.yours ) )
    101         do {
    102                 sout | f.adatum;
    103         } while (f`movePrev);
    10493}
    10594
     
    11099                sout | "==== fred by YOURS after ";
    111100        }
    112         if (&f1) {
    113                 printYourFredsFwd(f1);  sout | '-';
    114                 printYourFredsRev(f1);  sout | '-';
    115         } else {
    116                 sout | '-'; sout | '-';
     101        printYourFredsFwd(f1);  sout | '-';
     102        printYourFredsRev(f1);  sout | '-';
     103        printYourFredsFwd(f2);  sout | '-';
     104        printYourFredsRev(f2);  sout | '-';
     105}
     106
     107void printMariesFwd(mary &m) {
     108        while (&m != 0p) {
     109                sout | m.anotherdatum;
     110                &m = &m`next;
    117111        }
    118         if (&f2) {
    119                 printYourFredsFwd(f2);  sout | '-';
    120                 printYourFredsRev(f2);  sout | '-';
    121         } else {
    122                 sout | '-'; sout | '-';
     112}
     113
     114void printMariesRev(mary &m) {
     115        while (&m != 0p) {
     116                sout | m.anotherdatum;
     117                &m = &m`prev;
    123118        }
    124 }
    125 
    126 void printMariesFwd(mary &m) {
    127         do {
    128                 sout | m.anotherdatum;
    129         } while (m`moveNext);
    130 }
    131 
    132 void printMariesRev(mary &m) {
    133         do {
    134                 sout | m.anotherdatum;
    135         } while (m`movePrev);
    136119}
    137120
     
    142125                sout | "==== mary after ";
    143126        }
    144         if (&m1) {
    145                 printMariesFwd(m1);     sout | '-';
    146                 printMariesRev(m1);     sout | '-';
    147         } else {
    148                 sout | '-'; sout | '-';
    149         }
    150         if (&m2) {
    151                 printMariesFwd(m2);     sout | '-';
    152                 printMariesRev(m2);     sout | '-';
    153         } else {
    154                 sout | '-'; sout | '-';
    155         }
     127        printMariesFwd(m1);     sout | '-';
     128        printMariesRev(m1);     sout | '-';
     129        printMariesFwd(m2);     sout | '-';
     130        printMariesRev(m2);     sout | '-';
    156131}
    157132
     
    178153//  - from list position #2 moving backward (d)
    179154// The expected-output comments are in form a;b;c;d where a::=num,num,num
    180 #if 0
     155
    181156void test__insertafter_singleton_on_singleton__fred_mine () {
    182157        fred f1 = {3.14};
     
    186161        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    187162
    188         diref(fred, fred.mine) f1_mine = f1`from;
    189         insert_after(f1_mine, f2);
     163        insert_after(f1`in_mine, f2);
    190164
    191165        printMyFreddies(f1, f2, 0);     // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
     
    200174        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    201175
    202         diref(fred, fred.yours) f1_yours = f1`from;
    203         insert_after(f1_yours, f2);
     176        insert_after(f1`in_yours, f2);
    204177
    205178        printMyFreddies(f1, f2, 0);     // 3.14; 3.14; 0.5; 0.5 (unmodified)
     
    235208        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    236209
    237         diref(fred, fred.mine) f2_mine = f2`from;
    238         insert_before(f2_mine, f1);
     210        insert_before(f2`in_mine, f1);
    239211
    240212        printMyFreddies(f1, f2, 0);     // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
     
    249221        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    250222
    251         diref(fred, fred.yours) f2_yours = f2`from;
    252         insert_before(f2_yours, f1);
     223        insert_before(f2`in_yours, f1);
    253224
    254225        printMyFreddies(f1, f2, 0);     // 3.14; 3.14; 0.5; 0.5 (unmodified)
     
    266237        printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    267238}
    268 #endif
     239
    269240////////////////////////////////////////////////////////////
    270241//
     
    279250// All three tests exercise the case of creating an empty container and
    280251// adding two items to it.
     252
    281253void test__insertfirst_two_on_empty__fred_mine() {
    282254
     
    284256        fred f2 = {0.5};
    285257
    286         dlist(fred, fred.mine) lf;
     258        dlist(fred_in_mine, fred) lf;
    287259
    288260        verify(validate(lf));
     
    305277        fred f2 = {0.5};
    306278
    307         dlist(fred, fred.yours) lf;
     279        dlist(fred_in_yours, fred) lf;
    308280
    309281        verify(validate(lf));
     
    320292        printYourFreddies(f1, f2, 0);   // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    321293}
     294
    322295void test__insertfirst_two_on_empty__mary() {
    323296
     
    325298        mary m2 = {0.5};
    326299
    327         dlist(mary) lm;
     300        dlist(mary, mary) lm;
    328301
    329302        verify(validate(lm));
     
    352325        fred f2 = {0.5};
    353326
    354         dlist(fred, fred.mine) lf;
     327        dlist(fred_in_mine, fred) lf;
    355328
    356329        verify(validate(lf));
     
    373346        fred f2 = {0.5};
    374347
    375         dlist(fred, fred.yours) lf;
     348        dlist(fred_in_yours, fred) lf;
    376349
    377350        verify(validate(lf));
     
    394367        mary m2 = {0.5};
    395368
    396         dlist(mary) lm;
     369        dlist(mary, mary) lm;
    397370
    398371        verify(validate(lm));
     
    421394        fred f2 = {0.5};
    422395
    423         dlist(fred, fred.mine) lf;
    424 
    425         assert( & lf`first == 0p );
    426         assert( & lf`last == 0p );
     396        dlist(fred_in_mine, fred) lf;
     397
     398        assert(& lf`first == 0p);
     399        assert(& lf`last == 0p);
    427400
    428401        insert_first(lf, f1);
    429402
    430         assert( & lf`first == & f1 );
    431         assert( & lf`last  == & f1 );
     403        assert(& lf`first == & f1);
     404        assert(& lf`last == & f1);
    432405
    433406        verify(validate(lf));
    434407
    435         with ( DLINK_VIA(fred, fred.mine) ) insert_after(f1, f2);
     408        insert_after(f1`in_mine, f2);
    436409
    437410        verify(validate(lf));
     
    440413        printYourFreddies(f1, f2, 0);   // 3.14; 3.14; 0.5; 0.5 (unmodified)
    441414
    442         assert( & lf`first == & f1 );
    443         assert( & lf`last  == & f2 );
     415        assert(& lf`first == & f1);
     416        assert(& lf`last == & f2);
    444417}
    445418
     
    449422        fred f2 = {0.5};
    450423
    451         dlist(fred, fred.yours) lf;
    452 
    453         assert( & lf`first == 0p );
    454         assert( & lf`last == 0p );
     424        dlist(fred_in_yours, fred) lf;
     425
     426        assert(& lf`first == 0p);
     427        assert(& lf`last == 0p);
    455428
    456429        insert_first(lf, f1);
    457430
    458         assert( & lf`first == & f1 );
    459         assert( & lf`last  == & f1 );
     431        assert(& lf`first == & f1);
     432        assert(& lf`last == & f1);
    460433
    461434        verify(validate(lf));
    462435
    463     with ( DLINK_VIA(fred, fred.yours) ) insert_after(f1, f2);
     436        insert_after(f1`in_yours, f2);
    464437
    465438        verify(validate(lf));
     
    468441        printYourFreddies(f1, f2, 0);   // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    469442
    470         assert( & lf`first == & f1 );
    471         assert( & lf`last  == & f2 );
     443        assert(& lf`first == & f1);
     444        assert(& lf`last == & f2);
    472445}
    473446
     
    477450        mary m2 = {0.5};
    478451
    479         dlist(mary) lm;
    480 
    481         assert( & lm`first == 0p );
    482         assert( & lm`last == 0p );
     452        dlist(mary, mary) lm;
     453
     454        assert(& lm`first == 0p);
     455        assert(& lm`last == 0p);
    483456
    484457        insert_first(lm, m1);
    485458
    486         assert( & lm`first == & m1 );
    487         assert( & lm`last  == & m1 );
     459        assert(& lm`first == & m1);
     460        assert(& lm`last == & m1);
    488461
    489462        verify(validate(lm));
     
    495468        printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    496469
    497         assert( & lm`first == & m1 );
    498         assert( & lm`last  == & m2 );
     470        assert(& lm`first == & m1);
     471        assert(& lm`last == & m2);
    499472}
    500473
     
    514487        fred f2 = {0.5};
    515488
    516         dlist(fred, fred.mine) lf;
    517 
    518         assert( & lf`first == 0p );
    519         assert( & lf`last == 0p );
     489        dlist(fred_in_mine, fred) lf;
     490
     491        assert(& lf`first == 0p);
     492        assert(& lf`last == 0p);
    520493
    521494        insert_last(lf, f2);
    522495
    523         assert( & lf`first == & f2 );
    524         assert( & lf`last  == & f2 );
     496        assert(& lf`first == & f2);
     497        assert(& lf`last == & f2);
    525498
    526499        verify(validate(lf));
    527500
    528         with ( DLINK_VIA(fred, fred.mine) ) insert_before(f2, f1);
     501        insert_before(f2`in_mine, f1);
    529502
    530503        verify(validate(lf));
     
    533506        printYourFreddies(f1, f2, 0);   // 3.14; 3.14; 0.5; 0.5 (unmodified)
    534507
    535         assert( & lf`first == & f1 );
    536         assert( & lf`last  == & f2 );
     508        assert(& lf`first == & f1);
     509        assert(& lf`last == & f2);
    537510}
    538511
     
    542515        fred f2 = {0.5};
    543516
    544         dlist(fred, fred.yours) lf;
    545 
    546         assert( & lf`first == 0p );
    547         assert( & lf`last == 0p );
     517        dlist(fred_in_yours, fred) lf;
     518
     519        assert(& lf`first == 0p);
     520        assert(& lf`last == 0p);
    548521
    549522        insert_last(lf, f2);
    550523
    551         assert( & lf`first == & f2 );
    552         assert( & lf`last  == & f2 );
     524        assert(& lf`first == & f2);
     525        assert(& lf`last == & f2);
    553526
    554527        verify(validate(lf));
    555528
    556         with ( DLINK_VIA(fred, fred.yours) )insert_before(f2, f1);
     529        insert_before(f2`in_yours, f1);
    557530
    558531        verify(validate(lf));
     
    561534        printYourFreddies(f1, f2, 0);   // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    562535
    563         assert( & lf`first == & f1 );
    564         assert( & lf`last  == & f2 );
     536        assert(& lf`first == & f1);
     537        assert(& lf`last == & f2);
    565538}
    566539
     
    570543        mary m2 = {0.5};
    571544
    572         dlist(mary) lm;
    573 
    574         assert( & lm`first == 0p );
    575         assert( & lm`last == 0p );
     545        dlist(mary, mary) lm;
     546
     547        assert(& lm`first == 0p);
     548        assert(& lm`last == 0p);
    576549
    577550        insert_last(lm, m2);
    578551
    579         assert( & lm`first == & m2 );
    580         assert( & lm`last  == & m2 );
     552        assert(& lm`first == & m2);
     553        assert(& lm`last == & m2);
    581554
    582555        verify(validate(lm));
     
    588561        printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    589562
    590         assert( & lm`first == & m1 );
    591         assert( & lm`last  == & m2 );
    592 }
    593 #if 0
     563        assert(& lm`first == & m1);
     564        assert(& lm`last == & m2);
     565}
    594566
    595567////////////////////////////////////////////////////////////
     
    874846//
    875847////////////////////////////////////////////////////////////
    876 #endif
     848
    877849void test__remove_at_head__fred_mine() {
    878850
     
    881853        fred f3 = {3.7};
    882854
    883         dlist(fred, fred.mine) flm;
     855        dlist(fred_in_mine, fred) flm;
    884856        insert_last(flm, f1);
    885857        insert_last(flm, f2);
    886858        insert_last(flm, f3);
    887859
    888         dlist(fred, fred.yours) fly;
     860        dlist(fred_in_yours, fred) fly;
    889861        insert_last(fly, f1);
    890862        insert_last(fly, f2);
     
    897869        verify(validate(flm));
    898870
    899         with( DLINK_VIA(fred, fred.mine) ) remove(f1);
     871        remove(f1`in_mine);
    900872
    901873        verify(validate(fly));
     
    909881
    910882        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    911         // assert(f1.$links_mine.next.is_terminator == false);
    912         // assert(f1.$links_mine.prev.is_terminator == false);
    913 }
    914 
     883        assert(f1.$links_mine.next.is_terminator == false);
     884        assert(f1.$links_mine.prev.is_terminator == false);
     885}
    915886
    916887void test__remove_at_head__fred_yours() {
     
    920891        fred f3 = {3.7};
    921892
    922         dlist(fred, fred.mine) flm;
     893        dlist(fred_in_mine, fred) flm;
    923894        insert_last(flm, f1);
    924895        insert_last(flm, f2);
    925896        insert_last(flm, f3);
    926897
    927         dlist(fred, fred.yours) fly;
     898        dlist(fred_in_yours, fred) fly;
    928899        insert_last(fly, f1);
    929900        insert_last(fly, f2);
     
    936907        verify(validate(flm));
    937908
    938         with( DLINK_VIA(fred, fred.yours) ) remove(f1);
     909        remove(f1`in_yours);
    939910
    940911        verify(validate(fly));
     
    948919
    949920        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    950         // assert(f1.$links_yours.next.is_terminator == false);
    951         // assert(f1.$links_yours.prev.is_terminator == false);
     921        assert(f1.$links_yours.next.is_terminator == false);
     922        assert(f1.$links_yours.prev.is_terminator == false);
    952923}
    953924
     
    958929        mary m3 = {3.7};
    959930
    960         dlist(mary) ml;
     931        dlist(mary, mary) ml;
    961932        insert_last(ml, m1);
    962933        insert_last(ml, m2);
     
    977948
    978949        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    979         // assert(m1.$links.next.is_terminator == false);
    980         // assert(m1.$links.prev.is_terminator == false);
     950        assert(m1.$links.next.is_terminator == false);
     951        assert(m1.$links.prev.is_terminator == false);
    981952}
    982953
     
    997968        fred f3 = {3.7};
    998969
    999         dlist(fred, fred.mine) flm;
     970        dlist(fred_in_mine, fred) flm;
    1000971        insert_last(flm, f1);
    1001972        insert_last(flm, f2);
    1002973        insert_last(flm, f3);
    1003974
    1004         dlist(fred, fred.yours) fly;
     975        dlist(fred_in_yours, fred) fly;
    1005976        insert_last(fly, f1);
    1006977        insert_last(fly, f2);
     
    1013984        verify(validate(flm));
    1014985
    1015         with( DLINK_VIA(fred, fred.mine) ) remove(f3);
     986        remove(f3`in_mine);
    1016987
    1017988        verify(validate(fly));
     
    1025996
    1026997        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1027         // assert(f3.$links_mine.next.is_terminator == false);
    1028         // assert(f3.$links_mine.prev.is_terminator == false);
     998        assert(f3.$links_mine.next.is_terminator == false);
     999        assert(f3.$links_mine.prev.is_terminator == false);
    10291000}
    10301001
     
    10351006        fred f3 = {3.7};
    10361007
    1037         dlist(fred, fred.mine) flm;
     1008        dlist(fred_in_mine, fred) flm;
    10381009        insert_last(flm, f1);
    10391010        insert_last(flm, f2);
    10401011        insert_last(flm, f3);
    10411012
    1042         dlist(fred, fred.yours) fly;
     1013        dlist(fred_in_yours, fred) fly;
    10431014        insert_last(fly, f1);
    10441015        insert_last(fly, f2);
     
    10511022        verify(validate(flm));
    10521023
    1053         with( DLINK_VIA(fred, fred.yours) ) remove(f3);
     1024        remove(f3`in_yours);
    10541025
    10551026        verify(validate(fly));
     
    10631034
    10641035        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1065         // assert(f3.$links_yours.next.is_terminator == false);
    1066         // assert(f3.$links_yours.prev.is_terminator == false);
     1036        assert(f3.$links_yours.next.is_terminator == false);
     1037        assert(f3.$links_yours.prev.is_terminator == false);
    10671038}
    10681039
     
    10731044        mary m3 = {3.7};
    10741045
    1075         dlist(mary) ml;
     1046        dlist(mary, mary) ml;
    10761047        insert_last(ml, m1);
    10771048        insert_last(ml, m2);
     
    10921063
    10931064        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1094         // assert(m3.$links.next.is_terminator == false);
    1095         // assert(m3.$links.prev.is_terminator == false);
     1065        assert(m3.$links.next.is_terminator == false);
     1066        assert(m3.$links.prev.is_terminator == false);
    10961067}
    10971068
     
    11101081        fred f = {0.7};
    11111082
    1112         dlist(fred, fred.mine) flm;
     1083        dlist(fred_in_mine, fred) flm;
    11131084        insert_last(flm, f);
    11141085
    1115         dlist(fred, fred.yours) fly;
     1086        dlist(fred_in_yours, fred) fly;
    11161087        insert_last(fly, f);
    11171088
     
    11221093        verify(validate(flm));
    11231094
    1124         with( DLINK_VIA(fred, fred.mine) ) remove(f);
    1125 
    1126         verify(validate(fly));
    1127         verify(validate(flm));
    1128 
    1129         assert( & flm`first == 0p );
    1130         assert( & flm`last == 0p );
     1095        remove(f`in_mine);
     1096
     1097        verify(validate(fly));
     1098        verify(validate(flm));
     1099
     1100        assert(& flm`first == 0p);
     1101        assert(& flm`last  == 0p);
    11311102
    11321103        printYourFreddies(fly`first, fly`last, 0);   // 0.7; 0.7; 0.7; 0.7 (unmodified)
     
    11361107
    11371108        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1138         // assert(f.$links_mine.next.is_terminator == false);
    1139         // assert(f.$links_mine.prev.is_terminator == false);
     1109        assert(f.$links_mine.next.is_terminator == false);
     1110        assert(f.$links_mine.prev.is_terminator == false);
    11401111
    11411112        insert_last(flm, f);
     
    11491120        fred f = {0.7};
    11501121
    1151         dlist(fred, fred.mine) flm;
     1122        dlist(fred_in_mine, fred) flm;
    11521123        insert_last(flm, f);
    11531124
    1154         dlist(fred, fred.yours) fly;
     1125        dlist(fred_in_yours, fred) fly;
    11551126        insert_last(fly, f);
    11561127
     
    11611132        verify(validate(flm));
    11621133
    1163         with( DLINK_VIA(fred, fred.yours) ) remove(f);
    1164 
    1165         verify(validate(fly));
    1166         verify(validate(flm));
    1167 
    1168         assert( & fly`first == 0p );
    1169         assert( & fly`last == 0p );
     1134        remove(f`in_yours);
     1135
     1136        verify(validate(fly));
     1137        verify(validate(flm));
     1138
     1139        assert(& fly`first == 0p);
     1140        assert(& fly`last  == 0p);
    11701141
    11711142        printYourFreddies(flm`first, flm`last, 0);   // 0.7; 0.7; 0.7; 0.7 (unmodified)
     
    11751146
    11761147        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1177         // assert(f.$links_yours.next.is_terminator == false);
    1178         // assert(f.$links_yours.prev.is_terminator == false);
     1148        assert(f.$links_yours.next.is_terminator == false);
     1149        assert(f.$links_yours.prev.is_terminator == false);
    11791150
    11801151        insert_last(fly, f);
     
    11881159        mary m = {0.7};
    11891160
    1190         dlist(mary) ml;
     1161        dlist(mary, mary) ml;
    11911162        insert_last(ml, m);
    11921163
     
    11991170        verify(validate(ml));
    12001171
    1201         assert( & ml`first == 0p );
    1202         assert( & ml`last == 0p );
     1172        assert(& ml`first == 0p);
     1173        assert(& ml`last  == 0p);
    12031174
    12041175        // observe f is solo in mine (now unlisted); in yours, it was just traversed
     
    12061177
    12071178        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1208         // assert(m.$links.next.is_terminator == false);
    1209         // assert(m.$links.prev.is_terminator == false);
     1179        assert(m.$links.next.is_terminator == false);
     1180        assert(m.$links.prev.is_terminator == false);
    12101181
    12111182        insert_last(ml, m);
     
    12321203        fred f3 = {3.7};
    12331204
    1234         dlist(fred, fred.mine) flm;
     1205        dlist(fred_in_mine, fred) flm;
    12351206        insert_last(flm, f1);
    12361207        insert_last(flm, f2);
    12371208        insert_last(flm, f3);
    12381209
    1239         dlist(fred, fred.yours) fly;
     1210        dlist(fred_in_yours, fred) fly;
    12401211        insert_last(fly, f1);
    12411212        insert_last(fly, f2);
     
    12481219        verify(validate(flm));
    12491220
    1250         fred & popped = try_pop_front(flm);
     1221        fred & popped = pop_first(flm);
    12511222
    12521223        verify(validate(fly));
     
    12681239        fred f3 = {3.7};
    12691240
    1270         dlist(fred, fred.mine) flm;
     1241        dlist(fred_in_mine, fred) flm;
    12711242        insert_last(flm, f1);
    12721243        insert_last(flm, f2);
    12731244        insert_last(flm, f3);
    12741245
    1275         dlist(fred, fred.yours) fly;
     1246        dlist(fred_in_yours, fred) fly;
    12761247        insert_last(fly, f1);
    12771248        insert_last(fly, f2);
     
    12841255        verify(validate(flm));
    12851256
    1286         fred & popped = try_pop_front(fly);
     1257        fred & popped = pop_first(fly);
    12871258
    12881259        verify(validate(fly));
     
    13041275        mary m3 = {3.7};
    13051276
    1306         dlist(mary) ml;
     1277        dlist(mary, mary) ml;
    13071278        insert_last(ml, m1);
    13081279        insert_last(ml, m2);
     
    13131284        verify(validate(ml));
    13141285
    1315         mary & popped = try_pop_front(ml);
     1286        mary & popped = pop_first(ml);
    13161287
    13171288        verify(validate(ml));
     
    13311302        fred f3 = {3.7};
    13321303
    1333         dlist(fred, fred.mine) flm;
     1304        dlist(fred_in_mine, fred) flm;
    13341305        insert_last(flm, f1);
    13351306        insert_last(flm, f2);
    13361307        insert_last(flm, f3);
    13371308
    1338         dlist(fred, fred.yours) fly;
     1309        dlist(fred_in_yours, fred) fly;
    13391310        insert_last(fly, f1);
    13401311        insert_last(fly, f2);
     
    13471318        verify(validate(flm));
    13481319
    1349         fred & popped = try_pop_back(flm);
     1320        fred & popped = pop_last(flm);
    13501321
    13511322        verify(validate(fly));
     
    13671338        fred f3 = {3.7};
    13681339
    1369         dlist(fred, fred.mine) flm;
     1340        dlist(fred_in_mine, fred) flm;
    13701341        insert_last(flm, f1);
    13711342        insert_last(flm, f2);
    13721343        insert_last(flm, f3);
    13731344
    1374         dlist(fred, fred.yours) fly;
     1345        dlist(fred_in_yours, fred) fly;
    13751346        insert_last(fly, f1);
    13761347        insert_last(fly, f2);
     
    13831354        verify(validate(flm));
    13841355
    1385         fred & popped = try_pop_back(fly);
     1356        fred & popped = pop_last(fly);
    13861357
    13871358        verify(validate(fly));
     
    14031374        mary m3 = {3.7};
    14041375
    1405         dlist(mary) ml;
     1376        dlist(mary, mary) ml;
    14061377        insert_last(ml, m1);
    14071378        insert_last(ml, m2);
     
    14121383        verify(validate(ml));
    14131384
    1414         mary & popped = try_pop_back(ml);
     1385        mary & popped = pop_last(ml);
    14151386
    14161387        verify(validate(ml));
     
    14261397////////////////////////////////////////////////////////////
    14271398//
    1428 // Section 4g
    1429 //
    1430 // Test cases of `isEmpty, `hasPrev, `hasNext,
    1431 // try_pop_front, try_pop_back, modifications via `elems
    1432 //
    1433 // Example of call-side user code
    1434 //
    1435 ////////////////////////////////////////////////////////////
    1436 
    1437 void test__accessor_cases__mary() {
    1438 
    1439         mary m1 = {1.7};
    1440         mary m2 = {2.7};
    1441         mary m3 = {3.7};
    1442 
    1443         dlist(mary) ml;                 assert( ml`isEmpty);
    1444 
    1445         insert_last(ml, m1);    assert(!ml`isEmpty);
    1446         insert_last(ml, m2);    assert(!ml`isEmpty);
    1447         insert_last(ml, m3);    assert(!ml`isEmpty);
    1448 
    1449         mary & m1prev = m1`prev;
    1450         mary & m1next = m1`next;
    1451         mary & m2prev = m2`prev;
    1452         mary & m2next = m2`next;
    1453         mary & m3prev = m3`prev;
    1454         mary & m3next = m3`next;
    1455 
    1456         assert (&m1prev == 0p);
    1457         assert (&m1next == &m2);
    1458         assert (&m2prev == &m1);
    1459         assert (&m2next == &m3);
    1460         assert (&m3prev == &m2);
    1461         assert (&m3next == 0p);
    1462 
    1463         assert(!m1`hasPrev);
    1464         assert( m1`hasNext);
    1465         assert( m2`hasPrev);
    1466         assert( m2`hasNext);
    1467         assert( m3`hasPrev);
    1468         assert(!m3`hasNext);
    1469 
    1470         printf("accessor_cases done\n");
    1471 }
    1472 
    1473 void test__try_pop__mary() {
    1474 
    1475         mary m1 = {1.7};
    1476         mary m2 = {2.7};
    1477         mary m3 = {3.7};
    1478 
    1479         dlist(mary) ml;
    1480 
    1481         mary &m1r = *0p;
    1482         mary &m2r = *0p;
    1483         mary &m3r = *0p;
    1484         mary &mxr = *0p;
    1485 
    1486         // queue, back to front
    1487 
    1488         assert( ml`isEmpty);
    1489 
    1490         insert_last(ml, m1);
    1491         insert_last(ml, m2);
    1492         insert_last(ml, m3);
    1493 
    1494         &m1r = & try_pop_front(ml);     assert(!ml`isEmpty);
    1495         &m2r = & try_pop_front(ml);     assert(!ml`isEmpty);
    1496         &m3r = & try_pop_front(ml);     assert( ml`isEmpty);
    1497         &mxr = & try_pop_front(ml);     assert( ml`isEmpty);
    1498 
    1499         assert( &m1r == &m1 );
    1500         assert( &m2r == &m2 );
    1501         assert( &m3r == &m3 );
    1502         assert( &mxr == 0p  );
    1503 
    1504         &m1r = 0p;
    1505         &m2r = 0p;
    1506         &m3r = 0p;
    1507 
    1508         // queue, front to back
    1509 
    1510         assert( ml`isEmpty);
    1511 
    1512         insert_first(ml, m1);
    1513         insert_first(ml, m2);
    1514         insert_first(ml, m3);
    1515 
    1516         &m1r = & try_pop_back(ml);      assert(!ml`isEmpty);
    1517         &m2r = & try_pop_back(ml);      assert(!ml`isEmpty);
    1518         &m3r = & try_pop_back(ml);      assert( ml`isEmpty);
    1519         &mxr = & try_pop_back(ml);      assert( ml`isEmpty);
    1520 
    1521         assert( &m1r == &m1 );
    1522         assert( &m2r == &m2 );
    1523         assert( &m3r == &m3 );
    1524         assert( &mxr == 0p  );
    1525 
    1526         &m1r = 0p;
    1527         &m2r = 0p;
    1528         &m3r = 0p;
    1529 
    1530         // stack at front
    1531 
    1532         assert( ml`isEmpty);
    1533 
    1534         insert_first(ml, m1);
    1535         insert_first(ml, m2);
    1536         insert_first(ml, m3);
    1537 
    1538         &m3r = & try_pop_front(ml);     assert(!ml`isEmpty);
    1539         &m2r = & try_pop_front(ml);     assert(!ml`isEmpty);
    1540         &m1r = & try_pop_front(ml);     assert( ml`isEmpty);
    1541         &mxr = & try_pop_front(ml);     assert( ml`isEmpty);
    1542 
    1543         assert( &m1r == &m1 );
    1544         assert( &m2r == &m2 );
    1545         assert( &m3r == &m3 );
    1546         assert( &mxr == 0p  );
    1547 
    1548         &m1r = 0p;
    1549         &m2r = 0p;
    1550         &m3r = 0p;
    1551 
    1552         // stack at back
    1553 
    1554         assert( ml`isEmpty);
    1555 
    1556         insert_last(ml, m1);
    1557         insert_last(ml, m2);
    1558         insert_last(ml, m3);
    1559 
    1560         &m3r = & try_pop_back(ml);      assert(!ml`isEmpty);
    1561         &m2r = & try_pop_back(ml);      assert(!ml`isEmpty);
    1562         &m1r = & try_pop_back(ml);      assert( ml`isEmpty);
    1563         &mxr = & try_pop_back(ml);      assert( ml`isEmpty);
    1564 
    1565         assert( &m1r == &m1 );
    1566         assert( &m2r == &m2 );
    1567         assert( &m3r == &m3 );
    1568         assert( &mxr == 0p  );
    1569 
    1570         &m1r = 0p;
    1571         &m2r = 0p;
    1572         &m3r = 0p;
    1573 
    1574         printf("try_pop cases done\n");
    1575 }
    1576 
    1577 void test__origin_mutation__mary() {
    1578 
    1579         mary m1 = {1.7};
    1580 
    1581         dlist(mary) ml;
    1582         mary & mlorigin = ml`elems;
    1583 
    1584         // insert before the origin
    1585 
    1586         insert_before( ml`elems, m1 );
    1587         assert( ! ml`isEmpty );
    1588 
    1589         mary & mlfirst = ml`first;
    1590         mary & mllast = ml`last;
    1591 
    1592         assert( &m1 == & mlfirst );
    1593         assert( &m1 == & mllast );
    1594 
    1595         // moveNext after last goes back to origin, &vv
    1596 
    1597         bool canMoveNext = mllast`moveNext;
    1598         bool canMovePrev = mlfirst`movePrev;
    1599 
    1600         assert( ! canMoveNext );
    1601         assert( ! canMovePrev );
    1602 
    1603         assert( &mlorigin == & mlfirst );
    1604         assert( &mlorigin == & mllast );
    1605 
    1606         printf("origin_mutation cases done\n");
    1607 }
    1608 
    1609 void test__isListed_cases__mary() {
    1610 
    1611         mary m1 = {1.7};        assert(! m1`isListed);
    1612         mary m2 = {2.7};        assert(! m2`isListed);
    1613         mary m3 = {3.7};        assert(! m3`isListed);
    1614 
    1615         dlist(mary) ml;
    1616 
    1617         insert_last(ml, m1);    assert(  m1`isListed);  assert(! m2`isListed);
    1618         insert_last(ml, m2);    assert(  m2`isListed);  assert(! m3`isListed);
    1619         insert_last(ml, m3);    assert(  m3`isListed);
    1620 
    1621         remove( m1 );           assert(! m1`isListed);  assert(  m2`isListed);
    1622         remove( m2 );           assert(! m2`isListed);  assert(  m3`isListed);
    1623         remove( m3 );           assert(! m3`isListed);
    1624 
    1625         printf("isListed cases done\n");
    1626 }
    1627 
    1628 ////////////////////////////////////////////////////////////
    1629 //
    16301399// Section 5
    16311400//
     
    16351404
    16361405int main() {
    1637 #if 0
     1406
    16381407        sout | "~~~~~~~~~~~~~~~~~ Headless List Tests - insert_after ~~~~~~~~~~~~~~~~";
    16391408        sout | "";
     
    16721441        sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    16731442        test__insertbefore_singleton_on_singleton__mary();
    1674 #endif
     1443
    16751444        sout | "";
    16761445        sout | "~~~~~~~~~~~~~~~~~ Headed List Tests - insert_first ~~~~~~~~~~~~~~~~~~";
     
    17481517        sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    17491518        test__insertbefore_before_first__mary();
    1750 #if 0
    17511519
    17521520        sout | "";
     
    18061574        sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    18071575        test__remove_at_last__mary();
    1808 #endif
     1576
    18091577        sout | "";
    18101578        sout | "~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~";
     
    19021670        test__pop_last__maries();
    19031671
    1904         sout | "";
    1905         sout | "~~~~~~~~~~~~~~~~~~~ Ease-of-access cases ~~~~~~~~~~~~~~~~~~";
    1906         sout | "";
    1907 
    1908         sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    1909         sout | "Test 18-i.  Modifying Freds on MINE";
    1910         sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    1911         sout | "Not implmented";
    1912 
    1913         sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    1914         sout | "Test 18-ii.  Modifying Freds on YOURS";
    1915         sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    1916         sout | "Not implmented";
    1917 
    1918         sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    1919         sout | "Test 18-iii.  Modifying Maries";
    1920         sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    1921 
    1922         test__accessor_cases__mary();
    1923         test__try_pop__mary();
    1924         test__origin_mutation__mary();
    1925         test__isListed_cases__mary();
    1926 
    19271672        return 0;
    19281673}
  • tests/strstream.cfa

    r8d66610 r5407cdc  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo
    3 //
    4 // strstream.cfa --
    5 //
    6 // Author           : Peter A. Buhr
    7 // Created On       : Wed Apr 28 21:47:35 2021
    8 // Last Modified By : Peter A. Buhr
    9 // Last Modified On : Wed Apr 28 21:50:02 2021
    10 // Update Count     : 3
    11 //
    12 
    131#include <fstream.hfa>
    142#include <strstream.hfa>
    153
    164int main() {
    17         enum { size = 256 };
    18         char buf[size];                                                                         // output buffer
    19         ostrstream osstr = { buf, size };                                       // bind output buffer/size
    20         int i = 3, j = 5, k = 7;
    21         double x = 12345678.9, y = 98765.4321e-11;
     5    enum { size = 256 };
     6    char buf[size];
     7    ostrstream osstr = { buf, size };
     8    int i = 3, j = 5, k = 7;
     9    double x = 12345678.9, y = 98765.4321e-11;
    2210
    23         osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); // same lines of output
    24         write( osstr );
    25         printf( "%s", buf );
    26         sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));
     11    osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));
     12    write( osstr );
     13    printf( "%s", buf );
     14    sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));
    2715
    28         // char buf2[] = "12 14 15 3.5 7e4";                                    // input buffer
    29         // istrstream isstr = { buf2 };
    30         // isstr | i | j | k | x | y;
    31         // sout | i | j | k | x | y;
     16    // char buf2[] = "12 14 15 3.5 7e4";
     17    // istrstream isstr = { buf2 };
     18    // isstr | i | j | k | x | y;
     19    // sout | i | j | k | x | y;
    3220}
    33 
    34 // Local Variables: //
    35 // tab-width: 4 //
    36 // compile-command: "cfa strstream.cfa" //
    37 // End: //
  • tests/unified_locking/timeout_lock.cfa

    r8d66610 r5407cdc  
    3333
    3434        for ( unsigned int i = 0; i < NoOfTimes + 3; i += 1 ) {
    35             if ( wait( c_m, m, 1000000`ns ) ) {
     35            if ( wait( c_m, m, 1`s ) ) {
    3636                        // printf("Thread: %p signalled\n", active_thread()); // removed since can't expect non deterministic output
    3737            } else {
     
    5151        // Test calls which occur increasingly close to timeout value.
    5252
    53         sleep( 100000`ns );
     53        sleep( 100000000`ns );
    5454        notify_one(c_m);
    5555        block();
    5656
    57         sleep( 500000`ns );
     57        sleep( 500000000`ns );
    5858        notify_one(c_m);
    5959        block();
    6060
    61         sleep( 900000`ns );
     61        sleep( 900000000`ns );
    6262        notify_one(c_m);
    6363        block();
    6464
    6565        for ( unsigned int i = 0; i < NoOfTimes; i += 1 ) {
    66             sleep( 999700`ns );
     66            sleep( 999700000`ns );
    6767                notify_one(c_m);
    6868            block();
     
    7575        wait( c_m, 1`ns );                                                                                                              // bool wait( condition_variable(L) & this, Duration duration );       
    7676        wait( c_m, 10, 1`ns );                                                                                                  // bool wait( condition_variable(L) & this, uintptr_t info, Duration duration );
     77        wait( c_m, __kernel_get_time() + 1`ns );                                                                // bool wait( condition_variable(L) & this, Time time );
     78        wait( c_m, 10, __kernel_get_time() + 1`ns );                                                    // bool wait( condition_variable(L) & this, uintptr_t info, Time time );
    7779        lock(m); wait( c_m, m, 1`ns ); unlock(m);                                                               // bool wait( condition_variable(L) & this, L & l, Duration duration );
    7880        lock(m); wait( c_m, m, 10, 1`ns ); unlock(m);                                                   // bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
     81        lock(m); wait( c_m, m, __kernel_get_time() + 1`ns ); unlock(m);                 // bool wait( condition_variable(L) & this, L & l, Time time );
     82        lock(m); wait( c_m, m, 10, __kernel_get_time() + 1`ns ); unlock(m);             // bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
    7983        printf("Done Test 1\n");
    8084
Note: See TracChangeset for help on using the changeset viewer.