Changeset 8d66610


Ignore:
Timestamp:
May 21, 2021, 4:48:10 PM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
f1bce515
Parents:
5407cdc (diff), 7404cdc (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
21 added
69 edited
3 moved

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.tex

    r5407cdc r8d66610  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun Feb 14 15:52:46 2021
    14 %% Update Count     : 524
     13%% Last Modified On : Sat May  8 08:48:37 2021
     14%% Update Count     : 540
    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}{\protect\CCIcon\xspace}                        % C++ symbolic name
     44\newcommand{\CC}[1][]{\protect\CCIcon{#1}\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}}
    104105
    105106% index macros
     
    152153% Latin abbreviation
    153154\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
    154160\@ifundefined{eg}{
    155161\newcommand{\EG}{\abbrevFont{e}.\abbrevFont{g}.}
    156 \newcommand*{\eg}{%
    157         \@ifnextchar{,}{\EG}%
    158                 {\@ifnextchar{:}{\EG}%
    159                         {\EG,\xspace}}%
    160 }}{}%
     162\newcommand{\eg}{\EG\CheckCommaColon}
     163}{}%
    161164\@ifundefined{ie}{
    162165\newcommand{\IE}{\abbrevFont{i}.\abbrevFont{e}.}
    163 \newcommand*{\ie}{%
    164         \@ifnextchar{,}{\IE}%
    165                 {\@ifnextchar{:}{\IE}%
    166                         {\IE,\xspace}}%
    167 }}{}%
     166\newcommand{\ie}{\IE\CheckCommaColon}
     167}{}%
    168168\@ifundefined{etc}{
    169169\newcommand{\ETC}{\abbrevFont{etc}}
    170 \newcommand*{\etc}{%
    171         \@ifnextchar{.}{\ETC}%
    172         {\ETC.\xspace}%
    173 }}{}%
     170\newcommand{\etc}{\ETC\CheckPeriod}
     171}{}%
    174172\@ifundefined{etal}{
    175173\newcommand{\ETAL}{\abbrevFont{et}~\abbrevFont{al}}
    176 \newcommand*{\etal}{%
    177         \@ifnextchar{.}{\protect\ETAL}%
    178                 {\protect\ETAL.\xspace}%
    179 }}{}%
     174\newcommand{\etal}{\ETAL\CheckPeriod}
     175}{}%
    180176\@ifundefined{viz}{
    181177\newcommand{\VIZ}{\abbrevFont{viz}}
    182 \newcommand*{\viz}{%
    183         \@ifnextchar{.}{\VIZ}%
    184                 {\VIZ.\xspace}%
    185 }}{}%
     178\newcommand{\viz}{\VIZ\CheckPeriod}
     179}{}%
    186180\makeatother
    187181
     
    284278showlines=true,                                                 % show blank lines at end of code
    285279aboveskip=4pt,                                                  % spacing above/below code block
    286 belowskip=0pt,
     280belowskip=2pt,
    287281numberstyle=\footnotesize\sf,                   % numbering style
    288282% replace/adjust listing characters that look bad in sanserif
     
    297291\lstset{
    298292language=CFA,
    299 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    300 %moredelim=**[is][\color{red}]{®}{®},   % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
     293%moredelim=**[is][\color{red}]{@}{@},   % red highlighting @...@
     294moredelim=**[is][\color{red}]{®}{®},    % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
    301295%moredelim=**[is][\color{blue}]{ß}{ß},  % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
    302296%moredelim=**[is][\color{OliveGreen}]{¢}{¢}, % green highlighting ¢...¢ (cent symbol) emacs: C-q M-"
  • doc/theses/andrew_beach_MMath/Makefile

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

    r5407cdc r8d66610  
    11% Package for CFA Research Lab.
     2% (Now more a personal collection and testing grounds for common.sty.)
    23%
    3 % Made by combining and updating various macro files people had made.
     4% This is a collection of commands everyone working on CFA related documents
     5% should find useful. So mostly programming language related tools.
    46%
    57% Internal commands are prefixed with "\cfalab@".
     
    1012
    1113% Other packages required.
     14%
     15% Access to new basic LaTeX tools and other low level commands.
    1216\RequirePackage{etoolbox}
     17% Code formatting tools and environments.
    1318\RequirePackage{listings}
     19% Automatically adds spaces.
    1420\RequirePackage{xspace}
    1521
    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.
     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
     27% 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}
    2032
    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 
    27 % Cforall with the forall symbol.
    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+}}
    31 
    32 % This is executed very early in the \begin{document} code.
     33% This is executed very early in the \begin{document} code, before the
     34% document's contents but after packages are loaded.
    3335\AtEndPreamble{
    3436  \@ifpackageloaded{hyperref}{
     
    3638    \pdfstringdefDisableCommands{
    3739      \def\CFA{CFA}
    38       \def\CPP{C++}
     40      \def\Cpp{C++}
     41      \def\lstinline{}
     42      \def\code#1#2{#2}
    3943    }
    4044  }{}
    4145}
     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}}}
    4270
    4371% The CFA listings language. Based off of ANCI C and including GCC extensions.
     
    6189\lstset{defaultdialect={[UW]CFA}}
    6290
    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,
     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,
    68126}
    69127
    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}
     128% common.tex Compatablity ===================================================
     129% Below this line is for compatability with the old common.tex file.
    76130
    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}}}
     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}
    86150
    87151\endinput
  • doc/theses/andrew_beach_MMath/existing.tex

    r5407cdc r8d66610  
    1616to be defined~\cite{Moss18}.
    1717\begin{cfa}
    18 char i; int i; double i;                        $\C[3.75in]{// variable overload}$
    19 int f(); double f();                            $\C{// return overload}$
    20 void g( int ); void g( double );        $\C{// parameter overload}\CRT$
     18char i; int i; double i;
     19int f(); double f();
     20void g( int ); void g( double );
    2121\end{cfa}
    2222This feature requires name mangling so the assembly symbols are unique for
     
    2626mangling is:
    2727\begin{cfa}
    28 // name mangling
     28// name mangling on by default
    2929int i; // _X1ii_1
    30 @extern "C"@ {  // no name mangling
     30extern "C" {  // disables name mangling
    3131        int j; // j
    32         @extern "Cforall"@ {  // name mangling
     32        extern "Cforall" {  // enables name mangling
    3333                int k; // _X1ki_1
    3434        }
    35         // no name mangling
    36 }
    37 // name mangling
     35        // revert to no name mangling
     36}
     37// revert to 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, infixed
    67 multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it
    68 easy to tell the difference between prefix operations (such as @++?@) and
    69 post-fix operations (@?++@).
     66token with @?@, which indicates the position of the arguments. For example,
     67infixed multiplication is @?*?@ while prefix dereference is @*?@.
     68This syntax make it easy to tell the difference between prefix operations
     69(such as @++?@) and post-fix operations (@?++@).
    7070
    7171The special name for a constructor is @?{}@, which comes from the
    72 initialization syntax in C. The special name for a destructor is @^{}@, where
    73 the @^@ has no special meaning.
     72initialization syntax in C. That initialation syntax is also the operator
     73form. \CFA will generate a constructor call each time a variable is declared,
     74passing the initialization arguments to the constructort.
     75\begin{cfa}
     76struct Example { ... };
     77void ?{}(Example & this) { ... }
     78{
     79        Example a;
     80        Example b = {};
     81}
     82void ?{}(Example & this, char first, int num) { ... }
     83{
     84        Example c = {'a', 2};
     85}
     86\end{cfa}
     87Both @a@ and @b@ will be initalized with the first constructor (there is no
     88general way to skip initialation) while @c@ will be initalized with the
     89second.
     90
    7491% I don't like the \^{} symbol but $^\wedge$ isn't better.
    75 \begin{cfa}
    76 struct T { ... };
    77 void ?@{}@(@T &@ this, ...) { ... }  // constructor
    78 void ?@^{}@(@T &@ this, ...) { ... } // destructor
     92Similarly destructors use the special name @^?{}@ (the @^@ has no special
     93meaning). They can be called explicatly as well but normally they are
     94implicitly called on a variable when it goes out of scope.
     95\begin{cfa}
     96void ^?{}(Example & this) { ... }
    7997{
    80         T s = @{@ ... @}@;  // same constructor/initialization braces
    81 } // destructor call automatically generated
    82 \end{cfa}
    83 The first parameter is a reference parameter to the type for the
    84 constructor/destructor. Destructors may have multiple parameters.  The compiler
    85 implicitly matches an overloaded constructor @void ^?{}(T &, ...);@ to an
    86 object declaration with associated initialization, and generates a construction
    87 call after the object is allocated. When an object goes out of scope, the
    88 matching overloaded destructor @void ^?{}(T &);@ is called.  Without explicit
    89 definition, \CFA creates a default and copy constructor, destructor and
    90 assignment (like \Cpp). It is possible to define constructors/destructors for
    91 basic and existing types (unlike \Cpp).
     98    Example d;
     99} // <- implicit destructor call
     100\end{cfa}
     101No operator name is restricted in what function signatures they may be bound
     102to although most of the forms cannot be called in operator form. Some
     103``near-misses" will generate warnings.
     104
     105Whenever a type is defined, \CFA will create a default zero-argument
     106constructor, a copy constructor, a series of argument-per-field constructors
     107and a destructor. All user constructors are defined after this.
     108Because operators are never part of the type definition they may be added
     109at any time, including on built-in types.
    92110
    93111\section{Polymorphism}
     
    105123works on any type @T@:
    106124\begin{cfa}
    107 @forall( T )@ @T@ identity( @T@ val ) { return val; }
    108 int forty_two = identity( 42 ); // T bound to int, forty_two == 42
    109 \end{cfa}
     125forall( T ) T identity( T val ) { return val; }
     126int forty_two = identity( 42 );
     127char capital_a = identity( 'A' );
     128\end{cfa}
     129Each 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@
     131in the second).
    110132
    111133To allow a polymorphic function to be separately compiled, the type @T@ must be
     
    115137types used in a function, \eg:
    116138\begin{cfa}
    117 forall( T @| { void do_once(T); }@) // assertion
     139forall( T | { void do_once(T); })
    118140void do_twice(T value) {
    119141        do_once(value);
    120142        do_once(value);
    121143}
    122 void do_once(@int@ i) { ... }  // provide assertion
    123 @int@ i;
    124 do_twice(i); // implicitly pass assertion do_once to do_twice
    125 \end{cfa}
    126 Any object with a type fulfilling the assertion may be passed as an argument to
    127 a @do_twice@ call.
     144\end{cfa}
    128145
    129146A polymorphic function can be used in the same way as a normal function.  The
     
    132149all the variables replaced with the concrete types from the arguments) is
    133150defined at a call site.
     151\begin{cfa}
     152void do_once(int i) { ... }
     153int i;
     154do_twice(i);
     155\end{cfa}
     156Any object with a type fulfilling the assertion may be passed as an argument to
     157a @do_twice@ call.
    134158
    135159Note, a function named @do_once@ is not required in the scope of @do_twice@ to
     
    138162call.
    139163\begin{cfa}
    140 void do_once(double y) { ... } // global
     164void do_once(double y) { ... }
    141165int quadruple(int x) {
    142         void do_once(int y) { y = y * 2; } // local
    143         do_twice(x); // using local "do_once"
     166        void do_once(int y) { y = y * 2; }
     167        do_twice(x);
    144168        return x;
    145169}
     
    150174function. The matched assertion function is then passed as a function pointer
    151175to @do_twice@ and called within it.
     176The global definition of @do_once@ is ignored.
    152177
    153178To avoid typing long lists of assertions, constraints can be collect into
     
    161186and the @forall@ list in the previous example is replaced with the trait.
    162187\begin{cfa}
    163 forall(dtype T | @done_once(T)@)
     188forall(dtype T | done_once(T))
    164189\end{cfa}
    165190In general, a trait can contain an arbitrary number of assertions, both
     
    172197declarations instead of parameters, returns, and local variable declarations.
    173198\begin{cfa}
    174 forall(dtype @T@)
     199forall(dtype T)
    175200struct node {
    176         node(@T@) * next;  // generic linked node
    177         @T@ * data;
    178 }
    179 node(@int@) inode;
    180 \end{cfa}
    181 The generic type @node(T)@ is an example of a polymorphic-type usage.  Like \Cpp
    182 template usage, a polymorphic-type usage must specify a type parameter.
     201        node(T) * next;  // generic linked node
     202        T * data;
     203}
     204node(int) inode;
     205\end{cfa}
     206The generic type @node(T)@ is an example of a polymorphic type usage.  Like \Cpp
     207template usage, a polymorphic type usage must specify a type parameter.
    183208
    184209There are many other polymorphism features in \CFA but these are the ones used
     
    219244Each coroutine has a @main@ function, which takes a reference to a coroutine
    220245object and returns @void@.
    221 \begin{cfa}[numbers=left]
    222 void 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;
     246\begin{cfa}
     247void main(CountUp & this) {
     248    for (unsigned int next = 0 ; true ; ++next) {
     249                next = up;
     250                suspend;$\label{suspend}$
    228251        }
    229252}
     
    254277@mutex@.
    255278\begin{cfa}
    256 void example(MonitorA & @mutex@ argA, MonitorB & @mutex@ argB);
     279void example(MonitorA & mutex argA, MonitorB & mutex argB);
    257280\end{cfa}
    258281When the function is called, it implicitly acquires the monitor lock for all of
  • doc/theses/andrew_beach_MMath/features.tex

    r5407cdc r8d66610  
    2020\subparagraph{Raise}
    2121The raise is the starting point for exception handling. It marks the beginning
    22 of exception handling by \newterm{raising} an excepion, which passes it to
     22of exception handling by 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 \codePy{raise} statement from Python. In real systems a raise may preform
    27 some other work (such as memory management) but for the purposes of this
    28 overview that can be ignored.
     26the \code{Python}{raise} statement from Python. In real systems a raise may
     27preform some other work (such as memory management) but for the
     28purposes of this overview 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 \codeC{exception}) acts as a catch-all, leaf types catch single types
     95(here \code{C}{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 using different tools to create the hierarchy.
     103language; so different tools are used 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. But \CFA uses a hierarchial system of exceptions and this feature
    126 is 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.
     125any EHM.
     126However the \CFA uses a hierarchy built with the virtual system as the basis
     127for exceptions and exception matching.
     128
     129The virtual system would have ideally been part of \CFA before the work
     130on exception handling began, but unfortunately it was not.
     131Because of this only the features and framework needed for the EHM were
     132designed and implemented. Other features were considered to ensure that
     133the structure could accomidate other desirable features but they were not
     134implemented.
     135The rest of this section will only discuss the finalized portion of the
     136virtual system.
    130137
    131138The virtual system supports multiple ``trees" of types. Each tree is
     
    143150It is important to note that these are virtual members, not virtual methods
    144151of object-orientated programming, and can be of any type.
    145 However, since \CFA has function pointers and they are allowed, virtual
    146 members can be used to mimic virtual methods.
     152\CFA still supports virtual methods as a special case of virtual members.
     153Function pointers that take a pointer to the virtual type will be modified
     154with each level of inheritance so that refers to the new type.
     155This means an object can always be passed to a function in its virtual table
     156as if it were a method.
    147157
    148158Each virtual type has a unique id.
     
    175185While much of the virtual infrastructure is created, it is currently only used
    176186internally for exception handling. The only user-level feature is the virtual
    177 cast, which is the same as the \Cpp \lstinline[language=C++]|dynamic_cast|.
     187cast, which is the same as the \Cpp \code{C++}{dynamic_cast}.
    178188\label{p:VirtualCast}
    179189\begin{cfa}
     
    197207\begin{cfa}
    198208trait is_exception(exceptT &, virtualT &) {
    199         virtualT const & get_exception_vtable(exceptT *);
     209        // Numerous imaginary assertions.
    200210};
    201211\end{cfa}
    202212The trait is defined over two types, the exception type and the virtual table
    203 type. This should be one-to-one: each exception type has only one virtual
    204 table type and vice versa. The only assertion in the trait is
    205 @get_exception_vtable@, which takes a pointer of the exception type and
    206 returns 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.
    210 The function @get_exception_vtable@ is actually a constant function.
    211 Regardless of the value passed in (including the null pointer) it should
    212 return a reference to the virtual table instance for that type.
    213 The reason it is a function instead of a constant is that it make type
    214 annotations easier to write as you can use the exception type instead of the
    215 virtual 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.
     213type. Each exception type should have but a single virtual table type.
     214Now there are no actual assertions in this trait because the trait system
     215actually can't express them (adding such assertions would be part of
     216completing the virtual system). The imaginary assertions would probably come
     217from a trait defined by the virtual system, and state that the exception type
     218is a virtual type, is a decendent of @exception_t@ (the base exception type)
     219and note its virtual table type.
    218220
    219221% I did have a note about how it is the programmer's responsibility to make
     
    235237Both traits ensure a pair of types are an exception type and its virtual table
    236238and defines one of the two default handlers. The default handlers are used
    237 as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}.
     239as fallbacks and are discussed in detail in \vref{s:ExceptionHandling}.
    238240
    239241However, all three of these traits can be tricky to use directly.
     
    351353for particular exception type.
    352354The global default termination handler performs a cancellation
    353 \see{\VRef{s:Cancellation}} on the current stack with the copied exception.
     355(see \vref{s:Cancellation}) on the current stack with the copied exception.
    354356
    355357\subsection{Resumption}
     
    426428
    427429\subsubsection{Resumption Marking}
     430\label{s:ResumptionMarking}
    428431A key difference between resumption and termination is that resumption does
    429432not unwind the stack. A side effect that is that when a handler is matched
     
    472475The symmetry between resumption termination is why this pattern was picked.
    473476Other patterns, such as marking just the handlers that caught, also work but
    474 lack the symmetry means there are less rules to remember.
     477lack the symmetry means there are more rules to remember.
    475478
    476479\section{Conditional Catch}
     
    557560\end{cfa}
    558561If there are further handlers after this handler only the first version will
    559 check them. If multiple handlers on a single try block could handle the same
    560 exception the translations get more complex but they are equivilantly
     562check them. If multiple handlers on a single try block that could handle the
     563same exception the translations get more complex but they are equivilantly
    561564powerful.
    562565
     
    633636and the current stack is
    634637unwound. After that it depends one which stack is being cancelled.
    635 \begin{description}
    636 \item[Main Stack:]
     638
     639\paragraph{Main Stack}
    637640The main stack is the one used by the program main at the start of execution,
    638641and is the only stack in a sequential program.
     
    645648to, so it would have be explicitly managed.
    646649
    647 \item[Thread Stack:]
     650\paragraph{Thread Stack}
    648651A thread stack is created for a \CFA @thread@ object or object that satisfies
    649652the @is_thread@ trait.
     
    671674Also you can always add an explicit join if that is the desired behaviour.
    672675
    673 \item[Coroutine Stack:]
     676\paragraph{Coroutine Stack}
    674677A coroutine stack is created for a @coroutine@ object or object that
    675678satisfies the @is_coroutine@ trait.
     
    685688(in terms of coroutine state) called resume on this coroutine, so the message
    686689is passed to the latter.
    687 \end{description}
  • doc/theses/andrew_beach_MMath/future.tex

    r5407cdc r8d66610  
    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

    r5407cdc r8d66610  
    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{\VPageref{p:VirtualCast}}, substantial structure is required to
    12 support it, and provide features for exception handling and the standard
    13 library.
     11cast (see the virtual cast feature \vpageref{p:VirtualCast}),
     12substantial structure is required to support it,
     13and provide features for exception handling and the standard library.
    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. This is always the first field so that
    18 if it is cast to a supertype the field's location is still known.
    19 
    20 This field is set as part of all new generated constructors.
    21 \todo{They only come as part exceptions and don't work.}
    22 After the object is created the field is constant.
    23 
    24 However 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
    26 type's virtual members.
     16Virtual types only have one change to their structure: the addition of a
     17pointer to the virtual table, which is called the \emph{virtual-table pointer}.
     18Internally, the field is called @virtual_table@.
     19The field is fixed after construction. It is always the first field in the
     20structure so that its location is always known.
     21\todo{Talk about constructors for virtual types (after they are working).}
     22
     23This is what binds an instance of a virtual type to a virtual table. This
     24pointer can be used as an identity check. It can also be used to access the
     25virtual table and the virtual members there.
     26
     27\subsection{Type Id}
     28Every virtual type has a unique id.
     29Type ids can be compared for equality (the types reperented are the same)
     30or used to access the type's type information.
     31The type information currently is only the parent's type id or, if the
     32type has no parent, zero.
     33
     34The id's are implemented as pointers to the type's type information instance.
     35Derefencing the pointer gets the type information.
     36By going back-and-forth between the type id and
     37the type info one can find every ancestor of a virtual type.
     38It also pushes the issue of creating a unique value (for
     39the type id) to the problem of creating a unique instance (for type
     40information) which the linker can solve.
     41
     42Advanced linker support is required because there is no place that appears
     43only once to attach the type information to. There should be one structure
     44definition but it is included in multiple translation units. Each virtual
     45table definition should be unique but there are an arbitrary number of thoses.
     46So the special section prefix \texttt{.gnu.linkonce} is used.
     47With a unique suffix (making the entire section name unique) the linker will
     48remove multiple definition making sure only one version exists after linking.
     49Then it is just a matter of making sure there is a unique name for each type.
     50
     51This is done in three phases.
     52The first phase is to generate a new structure definition to store the type
     53information. The layout is the same in each case, just the parent's type id,
     54but the types are changed.
     55The structure's name is change, it is based off the virtual type's name, and
     56the type of the parent's type id.
     57If the virtual type is polymorphic then the type information structure is
     58polymorphic as well, with the same polymorphic arguments.
     59
     60The second phase is to generate an instance of the type information with a
     61almost unique name, generated by mangling the virtual type name.
     62
     63The third phase is implicit with \CFA's overloading scheme. \CFA mangles
     64names with type information so that all of the symbols exported to the linker
     65are unique even if in \CFA code they are the same. Having two declarations
     66with the same name and same type is forbidden because it is impossible for
     67overload resolution to pick between them. This is why a unique type is
     68generated for each virtual type.
     69Polymorphic information is included in this mangling so polymorphic
     70types will have seperate instances for each set of polymorphic arguments.
     71
     72\begin{cfa}
     73struct TYPE_ID_TYPE {
     74        PARENT_ID_TYPE const * parent;
     75};
     76
     77__attribute__((cfa_linkonce))
     78TYPE_ID_TYPE const TYPE_ID_NAME = {
     79        &PARENT_ID_NAME,
     80};
     81\end{cfa}
     82
     83\subsubsection{cfa\_linkonce Attribute}
     84Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}.
     85This attribute can be put on an object or function definition
     86(any global declaration with a name and a type).
     87This allows you to define that object or function multiple times.
     88All definitions should have the link-once attribute on them and all should
     89be identical.
     90
     91The simplist way to use it is to put a definition in a header where the
     92forward declaration would usually go.
     93This is how it is used for type-id instances. There was is no unique location
     94associated with a type except for the type definition which is in a header.
     95This allows the unique type-id object to be generated there.
     96
     97Internally @cfa_linkonce@ removes all @section@ attributes
     98from the declaration (as well as itself) and replaces them with
     99@section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the
     100mangled name of the object.
     101The prefix \texttt{.gnu.linkonce} in section names is recognized by the
     102linker. If two of these sections with the same name, including everything
     103that comes after the special prefix, then only one will be used and the other
     104will be discarded.
    27105
    28106\subsection{Virtual Table}
    29 Every time a virtual type is defined the new virtual table type must also be
    30 defined.
    31 
    32 The unique instance is important because the address of the virtual table
    33 instance is used as the identifier for the virtual type. So a pointer to the
    34 virtual 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
    36 system instead.}
    37 
    38 The first step in putting it all together is to create the virtual table type.
    39 The virtual table type is just a structure and can be described in terms of
    40 its fields. The first field is always the parent type ID (or a pointer to
    41 the parent virtual table) or 0 (the null pointer).
    42 Next are other fields on the parent virtual table are repeated.
    43 Finally are the fields used to store any new virtual members of the new
    44 The virtual type
    45 
    46 The virtual system is accessed through a private constant field inserted at the
    47 beginning of every virtual type, called the virtual-table pointer. This field
    48 points at a type's virtual table and is assigned during the object's
    49 construction. The address of a virtual table acts as the unique identifier for
    50 the virtual type, and the first field of a virtual table is a pointer to the
    51 parent virtual-table or @0p@. The remaining fields are duplicated from the
    52 parent tables in this type's inheritance chain, followed by any fields this type
    53 introduces. Parent fields are duplicated so they can be changed (all virtual
    54 members are overridable), so that references to the dispatched type
    55 are replaced with the current virtual type.
    56 % These are always taken by pointer or reference.
    57 
    58 % Simple ascii diragram:
    59 \begin{verbatim}
    60 parent_pointer  \
    61 parent_field0   |
    62 ...             | Same layout as parent.
    63 parent_fieldN   /
     107Each virtual type has a virtual table type that stores its type id and
     108virtual members.
     109Each virtual type instance is bound to a table instance that is filled with
     110the values of virtual members.
     111Both the layout of the fields and their value are decided by the rules given
     112below.
     113
     114The layout always comes in three parts.
     115The first section is just the type id at the head of the table. It is always
     116there to ensure that
     117The second section are all the virtual members of the parent, in the same
     118order as they appear in the parent's virtual table. Note that the type may
     119change slightly as references to the ``this" will change. This is limited to
     120inside pointers/references and via function pointers so that the size (and
     121hence the offsets) are the same.
     122The third section is similar to the second except that it is the new virtual
     123members introduced at this level in the hierarchy.
     124
     125\begin{figure}
     126\begin{cfa}
     127type_id
     128parent_field0
     129...
     130parent_fieldN
    64131child_field0
    65132...
    66133child_fieldN
    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 
    75 A virtual table is created when the virtual type is created. The name of the
    76 type is created by mangling the name of the base type. The name of the instance
    77 is also generated by name mangling. The fields are initialized automatically.
    78 The parent field is initialized by getting the type of the parent field and
    79 using that to calculate the mangled name of the parent's virtual table type.
    80 There are two special fields that are included like normal fields but have
    81 special initialization rules: the @size@ field is the type's size and is
    82 initialized with a @sizeof@ expression, the @align@ field is the type's
    83 alignment and uses an @alignof@ expression. The remaining fields are resolved
    84 to a name matching the field's name and type using the normal visibility and
    85 overload resolution rules of the type system.
    86 
    87 These operations are split up into several groups depending on where they take
    88 place which varies for monomorphic and polymorphic types. The first devision is
    89 between the declarations and the definitions. Declarations, such as a function
    90 signature or a aggregate's name, must always be visible but may be repeated in
    91 the form of forward declarations in headers. Definitions, such as function
    92 bodies and a aggregate's layout, can be separately compiled but must occur
    93 exactly once in a source file.
    94 
    95 \begin{sloppypar}
    96 The declarations include the virtual type definition and forward declarations
    97 of the virtual table instance, constructor, message function and
    98 @get_exception_vtable@. The definition includes the storage and initialization
    99 of the virtual table instance and the bodies of the three functions.
    100 \end{sloppypar}
    101 
    102 Monomorphic instances put all of these two groups in one place each.
    103 Polymorphic instances also split out the core declarations and definitions from
    104 the per-instance information. The virtual table type and most of the functions
    105 are polymorphic so they are all part of the core. The virtual table instance
    106 and the @get_exception_vtable@ function.
    107 
    108 \begin{sloppypar}
     134\end{cfa}
     135\caption{Virtual Table Layout}
     136\label{f:VirtualTableLayout}
     137\todo*{Improve the Virtual Table Layout diagram.}
     138\end{figure}
     139
     140The first and second sections together mean that every virtual table has a
     141prefix that has the same layout and types as its parent virtual table.
     142This, combined with the fixed offset to the virtual table pointer, means that
     143for any virtual type it doesn't matter if we have it or any of its
     144descendants, it is still always safe to access the virtual table through
     145the virtual table pointer.
     146From there it is safe to check the type id to identify the exact type of the
     147underlying object, access any of the virtual members and pass the object to
     148any of the method-like virtual members.
     149
     150When a virtual table is declared the user decides where to declare it and its
     151name. The initialization of the virtual table is entirely automatic based on
     152the context of the declaration.
     153
     154The type id is always fixed, each virtual table type will always have one
     155exactly one possible type id.
     156The virtual members are usually filled in by resolution. The best match for
     157a given name and type at the declaration site is filled in.
     158There are two exceptions to that rule: the @size@ field is the type's size
     159and is set to the result of a @sizeof@ expression, the @align@ field is the
     160type's alignment and similarly uses an @alignof@ expression.
     161
     162\subsubsection{Concurrency Integration}
    109163Coroutines and threads need instances of @CoroutineCancelled@ and
    110164@ThreadCancelled@ respectively to use all of their functionality. When a new
     
    112166the instance is created as well. The definition of the virtual table is created
    113167at the definition of the main function.
    114 \end{sloppypar}
     168
     169\begin{figure}
     170\begin{cfa}
     171coroutine Example {
     172        // fields
     173}
     174\end{cfa}
     175
     176\begin{cfa}
     177__attribute__((cfa_linkonce))
     178struct __cfatid_struct_CoroutineCancelled(Example)
     179                __cfatid_CoroutineCancelled = {
     180        &EXCEPTION_TYPE_ID,
     181};
     182extern CoroutineCancelled_vtable _default_vtable_object_declaration;
     183extern CoroutineCancelled_vtable & _default_vtable;
     184\end{cfa}
     185
     186\begin{cfa}
     187void main(Example & this) {
     188        // body
     189}
     190\end{cfa}
     191
     192\begin{cfa}
     193CoroutineCancelled_vtable _default_vtable_object_declaration = {
     194        __cfatid_CoroutineCancelled,
     195        // Virtual member initialization.
     196};
     197
     198CoroutineCancelled_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.}
    115205
    116206\subsection{Virtual Cast}
     
    119209% The C-cast is just to make sure the generated code is correct so the rest of
    120210% the section is about that function.
    121 The function is
     211The function is implemented in the standard library and has the following
     212signature:
    122213\begin{cfa}
    123214void * __cfa__virtual_cast(
    124         struct __cfa__parent_vtable const * parent,
    125         struct __cfa__parent_vtable const * const * child );
    126 \end{cfa}
    127 and it is implemented in the standard library. The structure reperents the
    128 head 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@
    130 points at the object of the (possibe) child type.
    131 
    132 In terms of the virtual cast expression, @parent@ comes from looking up the
    133 type being cast to and @child@ is the result of the expression being cast.
    134 Because the complier outputs C code, some type C type casts are also used.
    135 The last bit of glue is an map that saves every virtual type the compiler
    136 sees. This is used to check the type used in a virtual cast is a virtual
    137 type and to get its virtual table.
    138 (It also checks for conflicting definitions.)
    139 
    140 Inside 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
    142 requires one more level of derefence to pass through the object) then @child@
    143 is returned, otherwise the null pointer is returned.
    144 
    145 The check itself is preformed is a simple linear search. If the child
    146 virtual table or any of its ancestors (which are retreved through the first
    147 field of every virtual table) are the same as the parent virtual table then
    148 the cast succeeds.
     215        struct __cfavir_type_td parent,
     216        struct __cfavir_type_id const * child );
     217\end{cfa}
     218The type id of target type of the virtual cast is passed in as @parent@ and
     219the cast target is passed in as @child@.
     220
     221For C generation both arguments and the result are wrapped with type casts.
     222There is also an internal store inside the compiler to make sure that the
     223target type is a virtual type.
     224% It also checks for conflicting definitions.
     225
     226The virtual cast either returns the original pointer as a new type or null.
     227So the function just does the parent check and returns the approprate value.
     228The parent check is a simple linear search of child's ancestors using the
     229type information.
    149230
    150231\section{Exceptions}
     
    161242
    162243Stack unwinding is the process of removing stack frames (activations) from the
    163 stack. On function entry and return, unwinding is handled directly by the code
    164 embedded in the function. Usually, the stack-frame size is known statically
    165 based on parameter and local variable declarations. For dynamically-sized
    166 local variables, a runtime computation is necessary to know the frame
    167 size. Finally, a function's frame-size may change during execution as local
    168 variables (static or dynamic sized) go in and out of scope.
     244stack. On function entry and return, unwinding is handled directly by the
     245call/return code embedded in the function.
     246In many cases the position of the instruction pointer (relative to parameter
     247and local declarations) is enough to know the current size of the stack
     248frame.
     249
     250Usually, the stack-frame size is known statically based on parameter and
     251local variable declarations. Even with dynamic stack-size the information
     252to determain how much of the stack has to be removed is still contained
     253within the function.
    169254Allocating/deallocating stack space is usually an $O(1)$ operation achieved by
    170255bumping the hardware stack-pointer up or down as needed.
    171 
    172 Unwinding across multiple stack frames is more complex because individual stack
    173 management code associated with each frame is bypassed. That is, the location
    174 of a function's frame-management code is largely unknown and dispersed
    175 throughout the function, hence the current frame size managed by that code is
    176 also unknown. Hence, code unwinding across frames does not have direct
    177 knowledge about what is on the stack, and hence, how much of the stack needs to
    178 be 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.
     256Constructing/destructing values on the stack takes longer put in terms of
     257figuring out what needs to be done is of similar complexity.
     258
     259Unwinding across multiple stack frames is more complex because that
     260information is no longer contained within the current function.
     261With seperate compilation a function has no way of knowing what its callers
     262are so it can't know how large those frames are.
     263Without altering the main code path it is also hard to pass that work off
     264to the caller.
    187265
    188266The traditional unwinding mechanism for C is implemented by saving a snap-shot
     
    191269reseting to a snap-shot of an arbitrary but existing function frame on the
    192270stack. It is up to the programmer to ensure the snap-shot is valid when it is
    193 reset, making this unwinding approach fragile with potential errors that are
    194 difficult to debug because the stack becomes corrupted.
    195 
    196 However, many languages define cleanup actions that must be taken when objects
    197 are deallocated from the stack or blocks end, such as running a variable's
    198 destructor or a @try@ statement's @finally@ clause. Handling these mechanisms
    199 requires walking the stack and checking each stack frame for these potential
    200 actions.
    201 
    202 For exceptions, it must be possible to walk the stack frames in search of @try@
    203 statements to match and execute a handler. For termination exceptions, it must
    204 also be possible to unwind all stack frames from the throw to the matching
    205 catch, and each of these frames must be checked for cleanup actions. Stack
    206 walking is where most of the complexity and expense of exception handling
    207 appears.
     271reset and that all required clean-up from the unwound stacks is preformed.
     272This approach is fragile and forces a work onto the surounding code.
     273
     274With respect to that work forced onto the surounding code,
     275many languages define clean-up actions that must be taken when certain
     276sections of the stack are removed. Such as when the storage for a variable
     277is removed from the stack or when a try statement with a finally clause is
     278(conceptually) popped from the stack.
     279None of these should be handled by the user, that would contradict the
     280intention of these features, so they need to be handled automatically.
     281
     282To safely remove sections of the stack the language must be able to find and
     283run these clean-up actions even when removing multiple functions unknown at
     284the beginning of the unwinding.
    208285
    209286One of the most popular tools for stack management is libunwind, a low-level
     
    215292\subsection{libunwind Usage}
    216293Libunwind, accessed through @unwind.h@ on most platforms, is a C library that
    217 provides \CC-style stack-unwinding. Its operation is divided into two phases:
     294provides \Cpp-style stack-unwinding. Its operation is divided into two phases:
    218295search and cleanup. The dynamic target search -- phase 1 -- is used to scan the
    219296stack and decide where unwinding should stop (but no unwinding occurs). The
     
    226303LSDA can contain any information but conventionally it is a table with entries
    227304representing regions of the function and what has to be done there during
    228 unwinding. These regions are bracketed by the instruction pointer. If the
     305unwinding. These regions are bracketed by instruction addresses. If the
    229306instruction pointer is within a region's start/end, then execution is currently
    230307executing in that region. Regions are used to mark out the scopes of objects
     
    238315
    239316The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and
    240 attaches its personality function. However, this
     317attaches a personality function to each function.
     318In plain C (which \CFA currently compiles down to) this
    241319flag only handles the cleanup attribute:
    242 \todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive
    243 and that's all I know.}
    244320\begin{cfa}
    245321void clean_up( int * var ) { ... }
    246322int avar __attribute__(( cleanup(clean_up) ));
    247323\end{cfa}
    248 which is used on a variable and specifies a function, in this case @clean_up@,
    249 run when the variable goes out of scope.
    250 The function is passed a pointer to the object being removed from the stack
    251 so it can be used to mimic destructors.
    252 However, this feature cannot be used to mimic @try@ statements as it cannot
    253 control the unwinding.
     324The attribue is used on a variable and specifies a function,
     325in this case @clean_up@, run when the variable goes out of scope.
     326This is enough to mimic destructors, but not try statements which can effect
     327the unwinding.
     328
     329To get full unwinding support all of this has to be done directly with
     330assembly and assembler directives. Partiularly the cfi directives
     331\texttt{.cfi\_lsda} and \texttt{.cfi\_personality}.
    254332
    255333\subsection{Personality Functions}
     
    268346\end{lstlisting}
    269347The @action@ argument is a bitmask of possible actions:
    270 \begin{enumerate}
     348\begin{enumerate}[topsep=5pt]
    271349\item
    272350@_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function
     
    291369@_UA_FORCE_UNWIND@ specifies a forced unwind call. Forced unwind only performs
    292370the cleanup phase and uses a different means to decide when to stop
    293 \see{\VRef{s:ForcedUnwind}}.
     371(see \vref{s:ForcedUnwind}).
    294372\end{enumerate}
    295373
    296374The @exception_class@ argument is a copy of the
    297 \lstinline[language=C]|exception|'s @exception_class@ field.
    298 
    299 The \lstinline[language=C]|exception| argument is a pointer to the user
    300 provided storage object. It has two public fields, the exception class, which
    301 is actually just a number, identifying the exception handling mechanism that
    302 created it, and the cleanup function. The cleanup function is called if
    303 required by the exception.
     375\code{C}{exception}'s @exception_class@ field.
     376This a number that identifies the exception handling mechanism that created
     377the
     378
     379The \code{C}{exception} argument is a pointer to the user
     380provided storage object. It has two public fields: the @exception_class@,
     381which is described above, and the @exception_cleanup@ function.
     382The clean-up function is used by the EHM to clean-up the exception if it
     383should need to be freed at an unusual time, it takes an argument that says
     384why it had to be cleaned up.
    304385
    305386The @context@ argument is a pointer to an opaque type passed to helper
     
    309390that can be passed several places in libunwind. It includes a number of
    310391messages for special cases (some of which should never be used by the
    311 personality function) and error codes but unless otherwise noted the
     392personality function) and error codes. However, unless otherwise noted, the
    312393personality function should always return @_URC_CONTINUE_UNWIND@.
    313394
     
    324405@_URC_END_OF_STACK@.
    325406
    326 Second, when a handler is matched, raise exception continues onto the cleanup
    327 phase.
     407Second, when a handler is matched, raise exception moves to the clean-up
     408phase and walks the stack a second time.
    328409Once again, it calls the personality functions of each stack frame from newest
    329410to oldest. This pass stops at the stack frame containing the matching handler.
     
    338419Forced Unwind is the other central function in libunwind.
    339420\begin{cfa}
    340 _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *,
     421_Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Exception *,
    341422        _Unwind_Stop_Fn, void *);
    342423\end{cfa}
     
    380461Each stack must have its own exception context. In a sequential \CFA program,
    381462there is only one stack with a single global exception-context. However, when
    382 the library @libcfathread@ is linked, there are multiple stacks where each
     463the library @libcfathread@ is linked, there are multiple stacks and each
    383464needs its own exception context.
    384465
    385 General access to the exception context is provided by function
     466The exception context should be retrieved by calling the function
    386467@this_exception_context@. For sequential execution, this function is defined as
    387468a weak symbol in the \CFA system-library, @libcfa@. When a \CFA program is
     
    390471
    391472The sequential @this_exception_context@ returns a hard-coded pointer to the
    392 global execption context.
     473global exception context.
    393474The concurrent version adds the exception context to the data stored at the
    394 base of each stack. When @this_exception_context@ is called it retrieves the
     475base of each stack. When @this_exception_context@ is called, it retrieves the
    395476active stack and returns the address of the context saved there.
    396477
     
    399480% catches. Talk about GCC nested functions.
    400481
    401 Termination exceptions use libunwind heavily because it matches the intended
    402 use from \CC exceptions closely. The main complication for \CFA is that the
     482\CFA termination exceptions use libunwind heavily because they match \Cpp
     483\Cpp exceptions closely. The main complication for \CFA is that the
    403484compiler generates C code, making it very difficult to generate the assembly to
    404485form the LSDA for try blocks or destructors.
     
    411492per-exception storage.
    412493
    413 [Quick ASCII diagram to get started.]
     494\begin{figure}
    414495\begin{verbatim}
    415496Fixed Header  | _Unwind_Exception   <- pointer target
     
    420501              V ...
    421502\end{verbatim}
    422 
    423 Exceptions are stored in variable-sized blocks.
    424 The first component is a fixed sized data structure that contains the
     503\caption{Exception Layout}
     504\label{f:ExceptionLayout}
     505\end{figure}
     506\todo*{Convert the exception layout to an actual diagram.}
     507
     508Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}).
     509The first component is a fixed-sized data structure that contains the
    425510information for libunwind and the exception system. The second component is an
    426511area of memory big enough to store the exception. Macros with pointer arthritic
     
    428513@_Unwind_Exception@ to the entire node.
    429514
    430 All of these nodes are linked together in a list, one list per stack, with the
     515Multipe exceptions can exist at the same time because exceptions can be
     516raised inside handlers, destructors and finally blocks.
     517Figure~\vref{f:MultipleExceptions} shows a program that has multiple
     518exceptions active at one time.
     519Each time an exception is thrown and caught the stack unwinds and the finally
     520clause runs. This will throw another exception (until @num_exceptions@ gets
     521high enough) which must be allocated. The previous exceptions may not be
     522freed because the handler/catch clause has not been run.
     523So 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}]{@}{@}}]
     532unsigned num_exceptions = 0;
     533void 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}
     547int 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
     567All exceptions are stored in nodes which are then linked together in lists,
     568one list per stack, with the
    431569list head stored in the exception context. Within each linked list, the most
    432570recently thrown exception is at the head followed by older thrown
     
    439577exception, the copy function, and the free function, so they are specific to an
    440578exception type. The size and copy function are used immediately to copy an
    441 exception into managed memory. After the exception is handled the free function
    442 is used to clean up the exception and then the entire node is passed to free
    443 so the memory can be given back to the heap.
     579exception into managed memory. After the exception is handled, the free
     580function is used to clean up the exception and then the entire node is
     581passed to free so the memory can be given back to the heap.
    444582
    445583\subsection{Try Statements and Catch Clauses}
     
    454592calls them.
    455593Because this function is known and fixed (and not an arbitrary function that
    456 happens to contain a try statement) this means the LSDA can be generated ahead
     594happens to contain a try statement), the LSDA can be generated ahead
    457595of time.
    458596
    459597Both the LSDA and the personality function are set ahead of time using
    460 embedded assembly. This is handcrafted using C @asm@ statements and contains
     598embedded assembly. This assembly code is handcrafted using C @asm@ statements
     599and contains
    461600enough information for the single try statement the function repersents.
    462601
     
    487626nested functions and all other functions besides @__cfaehm_try_terminate@ in
    488627\CFA use the GCC personality function and the @-fexceptions@ flag to generate
    489 the LSDA. This allows destructors to be implemented with the cleanup attribute.
     628the LSDA.
     629Using this pattern, \CFA implements destructors with the cleanup attribute.
     630
     631\begin{figure}
     632\begin{cfa}
     633try {
     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}
     643void try(void) {
     644        // TRY BLOCK
     645}
     646int 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}
     661void 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}
    490686
    491687\section{Resumption}
    492688% The stack-local data, the linked list of nodes.
    493689
    494 Resumption simple to implement because there is no stack unwinding. The
    495 resumption raise uses a list of nodes for its stack traversal. The head of the
    496 list is stored in the exception context. The nodes in the list have a pointer
    497 to the next node and a pointer to the handler function.
    498 
    499 A resumption raise traverses this list. At each node the handler function is
    500 called, passing the exception by pointer. It returns true if the exception is
    501 handled and false otherwise.
    502 
    503 The handler function does both the matching and handling. It computes the
    504 condition of each @catchResume@ in top-to-bottom order, until it finds a
    505 handler that matches. If no handler matches then the function returns
    506 false. Otherwise the matching handler is run; if it completes successfully, the
    507 function returns true. Rethrowing, through the @throwResume;@ statement,
    508 causes the function to return true.
     690Resumption simpler to implement than termination
     691because there is no stack unwinding.
     692Instead of storing the data in a special area using assembly,
     693there is just a linked list of possible handlers for each stack,
     694with each node on the list reperenting a try statement on the stack.
     695
     696The head of the list is stored in the exception context.
     697The nodes are stored in order, with the more recent try statements closer
     698to the head of the list.
     699Instead of traversing the stack resumption handling traverses the list.
     700At each node the EHM checks to see if the try statement the node repersents
     701can handle the exception. If it can, then the exception is handled and
     702the operation finishes, otherwise the search continues to the next node.
     703If the search reaches the end of the list without finding a try statement
     704that can handle the exception the default handler is executed and the
     705operation finishes.
     706
     707In each node is a handler function which does most of the work there.
     708The handler function is passed the raised the exception and returns true
     709if the exception is handled and false if it cannot be handled here.
     710
     711For each @catchResume@ clause the handler function will:
     712check to see if the raised exception is a descendant type of the declared
     713exception type, if it is and there is a conditional expression then it will
     714run the test, if both checks pass the handling code for the clause is run
     715and the function returns true, otherwise it moves onto the next clause.
     716If this is the last @catchResume@ clause then instead of moving onto
     717the next clause the function returns false as no handler could be found.
     718
     719\begin{figure}
     720\begin{cfa}
     721try {
     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}
     731bool 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}
     748struct __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}
    509757
    510758% Recursive Resumption Stuff:
    511 Search skipping \see{\VPageref{p:searchskip}}, which ignores parts of the stack
     759Search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of
     760the stack
    512761already examined, is accomplished by updating the front of the list as the
    513 search continues. Before the handler at a node is called the head of the list
     762search continues. Before the handler at a node is called, the head of the list
    514763is updated to the next node of the current node. After the search is complete,
    515764successful or not, the head of the list is reset.
     
    524773stack -- the first one points over all the checked handlers -- and the ordering
    525774is 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}
     789Initial 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}
     803Handler 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}
     817Try 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}
     831Handler Done
     832\end{minipage}
     833\caption{Resumption Marking}
     834\label{f:ResumptionMarking}
     835\todo*{Convert Resumption Marking into a line figure.}
     836\end{figure}
    526837
    527838\label{p:zero-cost}
     
    540851\section{Finally}
    541852% Uses destructors and GCC nested functions.
    542 Finally clauses is placed into a GCC nested-function with a unique name, and no
    543 arguments or return values. This nested function is then set as the cleanup
     853A finally clause is placed into a GCC nested-function with a unique name,
     854and no arguments or return values.
     855This nested function is then set as the cleanup
    544856function of an empty object that is declared at the beginning of a block placed
    545857around the context of the associated @try@ statement.
    546858
    547 The rest is handled by GCC. The try block and all handlers are inside the
     859The rest is handled by GCC. The try block and all handlers are inside this
    548860block. At completion, control exits the block and the empty object is cleaned
    549861up, which runs the function that contains the finally code.
     
    553865
    554866Cancellation also uses libunwind to do its stack traversal and unwinding,
    555 however it uses a different primary function @_Unwind_ForcedUnwind@. Details
    556 of its interface can be found in the \VRef{s:ForcedUnwind}.
     867however it uses a different primary function: @_Unwind_ForcedUnwind@. Details
     868of its interface can be found in the Section~\vref{s:ForcedUnwind}.
    557869
    558870The first step of cancellation is to find the cancelled stack and its type:
     
    560872pointer and the current thread pointer, and every thread stores a pointer to
    561873its main coroutine and the coroutine it is currently executing.
    562 
    563 So if the active thread's main and current coroutine are the same. If they
    564 are then the current stack is a thread stack, otherwise it is a coroutine
    565 stack. If it is a thread stack then an equality check with the stored main
    566 thread pointer and current thread pointer is enough to tell if the current
    567 thread is the main thread or not.
     874\todo*{Consider adding a description of how threads are coroutines.}
     875
     876If a the current thread's main and current coroutines are the same then the
     877current stack is a thread stack. Furthermore it is easy to compare the
     878current thread to the main thread to see if they are the same. And if this
     879is not a thread stack then it must be a coroutine stack.
    568880
    569881However, if the threading library is not linked, the sequential execution is on
     
    574886Regardless of how the stack is chosen, the stop function and parameter are
    575887passed to the forced-unwind function. The general pattern of all three stop
    576 functions is the same: they continue unwinding until the end of stack when they
    577 do there primary work.
     888functions is the same: they continue unwinding until the end of stack and
     889then preform their transfer.
    578890
    579891For main stack cancellation, the transfer is just a program abort.
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    r5407cdc r8d66610  
    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 
    7468% ======================================================================
    7569%   D O C U M E N T   P R E A M B L E
     
    8781}
    8882
    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...
     83% Does nothing, ignores \href tags (redefined by hyperref package).
     84\newcommand{\href}[1]{#1}
    9785
    9886% For a nomenclature (optional; available from ctan.org)
     
    10593% Removes large sections of the document.
    10694\usepackage{comment}
    107 % Adds todos (Must be included after comment.)
    108 \usepackage{todonotes}
     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}
    109103
    110104% Hyperlinks make it very easy to navigate an electronic document.
     
    151145
    152146% Exception to the rule of hyperref being the last add-on package
    153 \usepackage[automake,toc,abbreviations]{glossaries-extra}
     147\usepackage[toc,abbreviations]{glossaries-extra}
    154148% If glossaries-extra is not in your LaTeX distribution, get it from CTAN
    155149% (http://ctan.org/pkg/glossaries-extra), although it's supposed to be in
     
    208202\makeglossaries
    209203
    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}
     204% listings package configuation:
     205\lstMakeShortInline@
     206\lstset{language=CFA,style=cfacommon,basicstyle=\linespread{0.9}\tt}
     207\lstset{moredelim=**[is][\protect\color{red}]{@}{@}}
    235208% Annotations from Peter:
    236209\newcommand{\PAB}[1]{{\color{blue}PAB: #1}}
     
    262235% Tip: Putting each sentence on a new line is a way to simplify later editing.
    263236%----------------------------------------------------------------------
     237\input{intro}
    264238\input{existing}
    265239\input{features}
    266240\input{implement}
    267 %\input{unwinding}
    268241\input{future}
    269242
     
    325298\phantomsection         % allows hyperref to link to the correct page
    326299
     300\todos
     301
    327302%----------------------------------------------------------------------
    328303\end{document} % end of logical document
  • doc/theses/mubeen_zulfiqar_MMath/AllocDS1.fig

    r5407cdc r8d66610  
    88-2
    991200 2
    10 6 4950 1275 5250 1425
    11 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 1350 20 20 5025 1350 5045 1350
    12 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 1350 20 20 5100 1350 5120 1350
    13 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5175 1350 20 20 5175 1350 5195 1350
     106 4200 1575 4500 1725
     111 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 1650 20 20 4275 1650 4295 1650
     121 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4350 1650 20 20 4350 1650 4370 1650
     131 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4425 1650 20 20 4425 1650 4445 1650
    1414-6
    15 6 5700 1950 6000 2100
    16 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2025 20 20 5775 2025 5795 2025
    17 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2025 20 20 5850 2025 5870 2025
    18 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5925 2025 20 20 5925 2025 5945 2025
    19 -6
    20 6 3600 2100 3900 2475
     156 2850 2475 3150 2850
    21162 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    2217        1 1 1.00 45.00 90.00
    23          3675 2100 3675 2325
     18         2925 2475 2925 2700
    24192 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    25          3600 2325 3900 2325 3900 2475 3600 2475 3600 2325
     20         2850 2700 3150 2700 3150 2850 2850 2850 2850 2700
    2621-6
    27 6 5100 2100 5400 2475
     226 4350 2475 4650 2850
    28232 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    2924        1 1 1.00 45.00 90.00
    30          5175 2100 5175 2325
     25         4425 2475 4425 2700
    31262 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    32          5100 2325 5400 2325 5400 2475 5100 2475 5100 2325
     27         4350 2700 4650 2700 4650 2850 4350 2850 4350 2700
    3328-6
    34 6 4350 2100 4575 2775
     296 3600 2475 3825 3150
    35302 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    3631        1 1 1.00 45.00 90.00
    37          4425 2100 4425 2325
     32         3675 2475 3675 2700
    38332 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    39          4350 2325 4575 2325 4575 2475 4350 2475 4350 2325
     34         3600 2700 3825 2700 3825 2850 3600 2850 3600 2700
    40352 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    41          4350 2625 4575 2625 4575 2775 4350 2775 4350 2625
     36         3600 3000 3825 3000 3825 3150 3600 3150 3600 3000
    42372 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    4338        1 1 1.00 45.00 90.00
    44          4425 2400 4425 2625
     39         3675 2775 3675 3000
    4540-6
    46 6 5700 3225 6000 3375
    47 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3300 20 20 5775 3300 5795 3300
    48 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3300 20 20 5850 3300 5870 3300
    49 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5925 3300 20 20 5925 3300 5945 3300
     416 4875 3600 5175 3750
     421 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 3675 20 20 4950 3675 4970 3675
     431 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 3675 20 20 5025 3675 5045 3675
     441 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 3675 20 20 5100 3675 5120 3675
     45-6
     466 4875 2325 5175 2475
     471 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 2400 20 20 4950 2400 4970 2400
     481 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 2400 20 20 5025 2400 5045 2400
     491 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 2400 20 20 5100 2400 5120 2400
     50-6
     516 5625 2325 5925 2475
     521 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 2400 20 20 5700 2400 5720 2400
     531 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2400 20 20 5775 2400 5795 2400
     541 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2400 20 20 5850 2400 5870 2400
     55-6
     566 5625 3600 5925 3750
     571 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 3675 20 20 5700 3675 5720 3675
     581 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3675 20 20 5775 3675 5795 3675
     591 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3675 20 20 5850 3675 5870 3675
    5060-6
    51612 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    52          2700 1950 3900 1950
     62         2400 2100 2400 2550
    53632 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    54          3000 1800 3000 2175
     64         2550 2100 2550 2550
    55652 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    56          3150 1800 3150 2175
     66         2700 2100 2700 2550
    57672 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    58          3300 1800 3300 2175
     68         2850 2100 2850 2550
    59692 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    60          3450 1800 3450 2175
     70         3000 2100 3000 2550
    61712 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    62          3600 1800 3600 2175
     72         3600 2100 3600 2550
    63732 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    64          3750 1800 3750 2175
     74         3900 2100 3900 2550
    65752 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    66          4200 1950 5400 1950
     76         4050 2100 4050 2550
    67772 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    68          4350 1800 4350 2175
     78         4200 2100 4200 2550
    69792 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    70          4500 1800 4500 2175
     80         4350 2100 4350 2550
    71812 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    72          4650 1800 4650 2175
     82         4500 2100 4500 2550
    73832 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    74          4800 1800 4800 2175
     84         3300 1500 3300 1800
    75852 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    76          4950 1800 4950 2175
     86         3600 1500 3600 1800
    77872 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    78          5100 1800 5100 2175
    79 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    80          5250 1800 5250 2175
    81 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    82          4050 1200 4050 1500
    83 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    84          4350 1200 4350 1500
    85 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    86          4650 1200 4650 1500
     88         3900 1500 3900 1800
    87892 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    88          3750 1200 5550 1200 5550 1500 3750 1500 3750 1200
     90         3000 1500 4800 1500 4800 1800 3000 1800 3000 1500
    89912 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
    9092        1 1 1.00 45.00 90.00
    91          3975 1350 3375 1800
     93         3225 1650 2625 2100
    92942 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    9395        1 1 1.00 45.00 90.00
    94          3900 1350 3300 1800
     96         3150 1650 2550 2100
    95972 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    9698        1 1 1.00 45.00 90.00
    97          4200 1350 4800 1800
     99         3450 1650 4050 2100
    981002 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
    99101        1 1 1.00 45.00 90.00
    100          4125 1350 4725 1800
     102         3375 1650 3975 2100
    1011032 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    102          2850 1800 2850 2175
     104         2100 2100 2100 2550
     1052 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     106         1950 2250 3150 2250
     1072 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     108         3450 2250 4650 2250
    1031092 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    104          2700 1800 3900 1800 3900 2175 2700 2175 2700 1800
     110         1950 2100 3150 2100 3150 2550 1950 2550 1950 2100
    1051112 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    106          4200 1800 5400 1800 5400 2175 4200 2175 4200 1800
     112         3450 2100 4650 2100 4650 2550 3450 2550 3450 2100
     1132 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     114         2250 2100 2250 2550
     1152 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     116         3750 2100 3750 2550
    1071172 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    108118        1 1 1.00 45.00 90.00
    109          2775 2100 2775 2325
     119         2025 2475 2025 2700
    1101202 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    111121        1 1 1.00 45.00 90.00
    112          2775 2400 2775 2625
     122         2025 2775 2025 3000
    1131232 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    114          2700 2625 2850 2625 2850 2775 2700 2775 2700 2625
     124         1950 3000 2100 3000 2100 3150 1950 3150 1950 3000
    1151252 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    116          2700 2325 2850 2325 2850 2475 2700 2475 2700 2325
     126         1950 2700 2100 2700 2100 2850 1950 2850 1950 2700
    1171272 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    118128        1 1 1.00 45.00 90.00
    119          2700 3375 3450 3375 3450 3150
     129         1950 3750 2700 3750 2700 3525
    1201302 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    121          2700 3150 3900 3150 3900 3525 2700 3525 2700 3150
     131         1950 3525 3150 3525 3150 3900 1950 3900 1950 3525
    1221322 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    123133        1 1 1.00 45.00 90.00
    124          4200 3375 4950 3375 4950 3150
     134         3450 3750 4200 3750 4200 3525
    1251352 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    126          4200 3150 5400 3150 5400 3525 4200 3525 4200 3150
     136         3450 3525 4650 3525 4650 3900 3450 3900 3450 3525
    1271372 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    128138        1 1 1.00 45.00 90.00
    129          3900 4350 4950 4350 4950 3900
     139         3150 4650 4200 4650 4200 4275
    1301402 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    131          3900 3900 5400 3900 5400 4575 3900 4575 3900 3900
    132 4 2 0 50 -1 0 12 0.0000 2 135 975 2625 2175 free buckets\001
    133 4 2 0 50 -1 0 12 0.0000 2 135 435 2625 1950 locks\001
    134 4 1 0 50 -1 0 12 0.0000 2 135 1365 4650 1125 N thread buckets\001
    135 4 1 0 50 -1 0 12 0.0000 2 180 390 5175 1725 heap\001
    136 4 1 0 50 -1 0 12 0.0000 2 180 390 2925 1725 heap\001
    137 4 1 0 50 -1 0 12 0.0000 2 180 915 3300 3075 bump alloc\001
    138 4 0 0 50 -1 0 12 0.0000 2 135 360 4275 3325 lock\001
    139 4 1 0 50 -1 0 12 0.0000 2 180 915 4800 3075 bump alloc\001
    140 4 0 0 50 -1 0 12 0.0000 2 135 360 3975 4075 lock\001
    141 4 1 0 50 -1 0 12 0.0000 2 135 345 4725 3825 sbrk\001
    142 4 0 0 50 -1 0 12 0.0000 2 135 360 2775 3325 lock\001
    143 4 2 0 50 -1 0 12 0.0000 2 135 675 2625 2625 free lists\001
     141         3150 4275 4650 4275 4650 4875 3150 4875 3150 4275
     1422 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     143         1950 2400 3150 2400
     1442 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     145         3450 2400 4650 2400
     1462 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     147         5400 2100 5400 3900
     1484 2 0 50 -1 0 11 0.0000 2 120 300 1875 2250 lock\001
     1494 1 0 50 -1 0 12 0.0000 2 135 1935 3900 1425 N kernel-thread buckets\001
     1504 1 0 50 -1 0 12 0.0000 2 195 810 4425 2025 heap$_2$\001
     1514 1 0 50 -1 0 12 0.0000 2 195 810 2175 2025 heap$_1$\001
     1524 2 0 50 -1 0 11 0.0000 2 120 270 1875 2400 size\001
     1534 2 0 50 -1 0 11 0.0000 2 120 270 1875 2550 free\001
     1544 1 0 50 -1 0 12 0.0000 2 180 825 2550 3450 local pool\001
     1554 0 0 50 -1 0 12 0.0000 2 135 360 3525 3700 lock\001
     1564 0 0 50 -1 0 12 0.0000 2 135 360 3225 4450 lock\001
     1574 2 0 50 -1 0 12 0.0000 2 135 600 1875 3000 free list\001
     1584 1 0 50 -1 0 12 0.0000 2 180 825 4050 3450 local pool\001
     1594 1 0 50 -1 0 12 0.0000 2 180 1455 3900 4200 global pool (sbrk)\001
     1604 0 0 50 -1 0 12 0.0000 2 135 360 2025 3700 lock\001
     1614 1 0 50 -1 0 12 0.0000 2 180 720 6450 3150 free pool\001
     1624 1 0 50 -1 0 12 0.0000 2 180 390 6450 2925 heap\001
  • doc/theses/mubeen_zulfiqar_MMath/AllocDS2.fig

    r5407cdc r8d66610  
    88-2
    991200 2
    10 6 2850 2025 3150 2175
    11 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 2100 20 20 2925 2100 2945 2100
    12 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 2100 20 20 3000 2100 3020 2100
    13 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 2100 20 20 3075 2100 3095 2100
     106 2850 2100 3150 2250
     111 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 2175 20 20 2925 2175 2945 2175
     121 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 2175 20 20 3000 2175 3020 2175
     131 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 2175 20 20 3075 2175 3095 2175
    1414-6
    15 6 4050 2025 4350 2175
    16 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 2100 20 20 4125 2100 4145 2100
    17 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 2100 20 20 4200 2100 4220 2100
    18 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 2100 20 20 4275 2100 4295 2100
     156 4050 2100 4350 2250
     161 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 2175 20 20 4125 2175 4145 2175
     171 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 2175 20 20 4200 2175 4220 2175
     181 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 2175 20 20 4275 2175 4295 2175
    1919-6
    20 6 4650 2025 4950 2175
    21 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 2100 20 20 4725 2100 4745 2100
    22 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 2100 20 20 4800 2100 4820 2100
    23 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 2100 20 20 4875 2100 4895 2100
     206 4650 2100 4950 2250
     211 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 2175 20 20 4725 2175 4745 2175
     221 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 2175 20 20 4800 2175 4820 2175
     231 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 2175 20 20 4875 2175 4895 2175
    2424-6
    25 6 3450 2025 3750 2175
    26 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 2100 20 20 3525 2100 3545 2100
    27 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 2100 20 20 3600 2100 3620 2100
    28 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 2100 20 20 3675 2100 3695 2100
     256 3450 2100 3750 2250
     261 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 2175 20 20 3525 2175 3545 2175
     271 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 2175 20 20 3600 2175 3620 2175
     281 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 2175 20 20 3675 2175 3695 2175
    2929-6
    30 6 3300 2100 3600 2475
     306 3300 2175 3600 2550
    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 2100 3375 2325
     33         3375 2175 3375 2400
    34342 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    35          3300 2325 3600 2325 3600 2475 3300 2475 3300 2325
     35         3300 2400 3600 2400 3600 2550 3300 2550 3300 2400
    3636-6
     372 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     38         3150 1800 3150 2250
     392 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     40         2850 1800 2850 2250
     412 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     42         4650 1800 4650 2250
     432 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     44         4950 1800 4950 2250
     452 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     46         4500 1725 4500 2250
     472 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     48         5100 1725 5100 2250
     492 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     50         3450 1800 3450 2250
     512 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     52         3750 1800 3750 2250
     532 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     54         3300 1725 3300 2250
     552 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     56         3900 1725 3900 2250
     572 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     58         5250 1800 5250 2250
     592 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     60         5400 1800 5400 2250
     612 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     62         5550 1800 5550 2250
     632 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     64         5700 1800 5700 2250
     652 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     66         5850 1800 5850 2250
     672 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
     68         2700 1725 2700 2250
     692 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
     722 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
     752 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
     782 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
     812 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
     842 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
     872 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
    37902 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    3891         2700 1950 6000 1950
    39922 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    40          3150 1800 3150 2175
    41 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    42          2850 1800 2850 2175
    43 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    44          4650 1800 4650 2175
    45 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    46          4950 1800 4950 2175
    47 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    48          4500 1725 4500 2175
    49 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    50          5100 1725 5100 2175
    51 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    52          3450 1800 3450 2175
    53 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    54          3750 1800 3750 2175
    55 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    56          3300 1725 3300 2175
    57 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    58          3900 1725 3900 2175
    59 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    60          5250 1800 5250 2175
    61 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    62          5400 1800 5400 2175
    63 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    64          5550 1800 5550 2175
    65 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    66          5700 1800 5700 2175
    67 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    68          5850 1800 5850 2175
    69 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
    70          2700 1725 2700 2175
     93         2700 2100 6000 2100
    71942 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    72          2700 1800 6000 1800 6000 2175 2700 2175 2700 1800
     95         2700 1800 6000 1800 6000 2250 2700 2250 2700 1800
    73962 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    7497        1 1 1.00 45.00 90.00
    75          2775 2100 2775 2325
     98         2775 2175 2775 2400
    76992 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    77100        1 1 1.00 45.00 90.00
    78          2775 2400 2775 2625
     101         2775 2475 2775 2700
    791022 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    80          2700 2625 2850 2625 2850 2775 2700 2775 2700 2625
     103         2700 2700 2850 2700 2850 2850 2700 2850 2700 2700
    811042 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    82          2700 2325 2850 2325 2850 2475 2700 2475 2700 2325
     105         2700 2400 2850 2400 2850 2550 2700 2550 2700 2400
    831062 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
    84107        1 1 1.00 45.00 90.00
    85          4575 2100 4575 2325
     108         4575 2175 4575 2400
    861092 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    87          4500 2325 5025 2325 5025 2475 4500 2475 4500 2325
     110         4500 2400 5025 2400 5025 2550 4500 2550 4500 2400
    881112 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
    89112        1 1 1.00 45.00 90.00
    90          3600 3525 4650 3525 4650 3075
     113         3600 3525 4650 3525 4650 3150
    911142 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    92          3600 3075 5100 3075 5100 3750 3600 3750 3600 3075
    93 4 2 0 50 -1 0 12 0.0000 2 135 975 2625 2175 free buckets\001
    94 4 2 0 50 -1 0 12 0.0000 2 135 435 2625 1950 locks\001
     115         3600 3150 5100 3150 5100 3750 3600 3750 3600 3150
     1164 2 0 50 -1 0 11 0.0000 2 120 300 2625 1950 lock\001
    951174 1 0 50 -1 0 10 0.0000 2 150 1155 3000 1725 N$\\times$S$_1$\001
    961184 1 0 50 -1 0 10 0.0000 2 150 1155 3600 1725 N$\\times$S$_2$\001
     1194 1 0 50 -1 0 12 0.0000 2 180 390 4425 1500 heap\001
     1204 2 0 50 -1 0 12 0.0000 2 135 1140 2550 1425 kernel threads\001
     1214 2 0 50 -1 0 11 0.0000 2 120 270 2625 2100 size\001
     1224 2 0 50 -1 0 11 0.0000 2 120 270 2625 2250 free\001
     1234 2 0 50 -1 0 12 0.0000 2 135 600 2625 2700 free list\001
     1244 0 0 50 -1 0 12 0.0000 2 135 360 3675 3325 lock\001
     1254 1 0 50 -1 0 12 0.0000 2 180 1455 4350 3075 global pool (sbrk)\001
    971264 1 0 50 -1 0 10 0.0000 2 150 1110 4800 1725 N$\\times$S$_t$\001
    98 4 2 0 50 -1 0 12 0.0000 2 135 675 2625 2625 free lists\001
    99 4 0 0 50 -1 0 12 0.0000 2 135 360 3675 3250 lock\001
    100 4 1 0 50 -1 0 12 0.0000 2 135 345 4425 3000 sbrk\001
    101 4 1 0 50 -1 0 12 0.0000 2 180 390 4425 1500 heap\001
  • doc/theses/mubeen_zulfiqar_MMath/Makefile

    r5407cdc r8d66610  
    1515
    1616.PHONY: all clean
     17.PRECIOUS: %.dvi %.ps # do not delete intermediate files
    1718
    1819### Commands:
    1920LATEX = TEXINPUTS=${TEXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${BUILD}
    2021BIBTEX = BIBINPUTS=${BIBLIB} bibtex
    21 #GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite
     22#GLOSSARY = INDEXSTYLE=${BUILD} makeglossaries-lite
    2223
    2324### Rules and Recipes:
     
    2526all: ${DOC}
    2627
    27 ${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC:.fig=.tex} ${BIBSRC} Makefile | ${BUILD}
     28${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC:%.fig=%.tex} ${BIBSRC} Makefile | ${BUILD}
    2829        ${LATEX} ${BASE}
    2930        ${BIBTEX} ${BUILD}/${BASE}
  • doc/theses/mubeen_zulfiqar_MMath/allocator.tex

    r5407cdc r8d66610  
     1\chapter{Allocator}
    12
    2 \chapter{Allocator}
     3\noindent
     4====================
     5
     6Writing Points:
     7\begin{itemize}
     8\item
     9Objective of @uHeapLmmm@.
     10\item
     11Design philosophy.
     12\item
     13Background and previous design of @uHeapLmmm@.
     14\item
     15Distributed design of @uHeapLmmm@.
     16
     17----- SHOULD WE GIVE IMPLEMENTATION DETAILS HERE? -----
     18
     19\PAB{Maybe. There might be an Implementation chapter.}
     20\item
     21figure.
     22\item
     23Advantages of distributed design.
     24\end{itemize}
     25
     26The new features added to @uHeapLmmm@ (incl. @malloc_size@ routine)
     27\CFA alloc interface with examples.
     28\begin{itemize}
     29\item
     30Why did we need it?
     31\item
     32The 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
     39Performance evaluation using u-benchmark suite.
     40
     41\noindent
     42====================
    343
    444\newpage
    545\paragraph{Design 1: Decentralized}
    6 Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the sbrk area.
     46Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the @sbrk@ area.
    747Kernel threads (KT) are assigned to the N heaps.
    848When KTs $\le$ N, the heaps are uncontented.
  • doc/theses/mubeen_zulfiqar_MMath/background.tex

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

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

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

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

    r5407cdc r8d66610  
    8484\usepackage{graphicx}
    8585\usepackage{comment} % Removes large sections of the document.
    86 \usepackage{todonotes} % Adds todos (Must be included after comment.)
    8786
    8887% Hyperlinks make it very easy to navigate an electronic document.
     
    107106    colorlinks=true,        % false: boxed links; true: colored links
    108107    linkcolor=blue,         % color of internal links
    109     citecolor=green,        % color of links to bibliography
     108    citecolor=blue,        % color of links to bibliography
    110109    filecolor=magenta,      % color of file links
    111     urlcolor=cyan           % color of external links
     110    urlcolor=blue           % color of external links
    112111}
    113112\ifthenelse{\boolean{PrintVersion}}{   % for improved print quality, change some hyperref options
     
    168167\CFAStyle                                               % CFA code-style for all languages
    169168\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}
    196197\input{conclusion}
    197198
  • doc/user/Makefile

    r5407cdc r8d66610  
    6161
    6262${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
    63                 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
     63                ${Macros}/common.sty ${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

    r5407cdc r8d66610  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun Apr 25 19:03:03 2021
    14 %% Update Count     : 4951
     13%% Last Modified On : Sat May  8 08:51:33 2021
     14%% Update Count     : 5062
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    6565% keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^
    6666% math escape $...$ (dollar symbol)
    67 \input{common}                                          % common CFA document macros
     67\usepackage{common}                                                                             % common CFA document macros
     68%\input{common}                                                                                 % common CFA document macros
    6869\setlength{\gcolumnposn}{3in}
    6970\CFAStyle                                                                                               % use default CFA format-style
     
    585586For example, the octal ©0© or hexadecimal ©0x© prefix may end with an underscore ©0_377© or ©0x_ff©;
    586587the exponent infix ©E© may start or end with an underscore ©1.0_E10©, ©1.0E_10© or ©1.0_E_10©;
    587 the type suffixes ©U©, ©L©, etc. may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.
     588the type suffixes ©U©, ©L©, \etc may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.
    588589\end{enumerate}
    589590It 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).
     
    15701571\end{cquote}
    15711572
    1572 All type qualifiers, \eg ©const©, ©volatile©, etc., are used in the normal way with the new declarations and also appear left to right, \eg:
     1573All type qualifiers, \eg ©const©, ©volatile©, \etc, are used in the normal way with the new declarations and also appear left to right, \eg:
    15731574\begin{cquote}
    15741575\begin{tabular}{@{}l@{\hspace{1em}}l@{\hspace{1em}}l@{}}
     
    15901591\end{tabular}
    15911592\end{cquote}
    1592 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}
     1593All 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}
    15931594The 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:
    15941595\begin{cquote}
     
    31473148also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple.
    31483149
    3149 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.).
     3150Since 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).
    31503151\begin{cfa}
    31513152[ int, int, long, double ] x;
     
    33123313
    33133314\section{Tuples}
     3315\label{tuples}
    33143316
    33153317In C and \CFA, lists of elements appear in several contexts, such as the parameter list for a routine call.
     
    34203422
    34213423\subsection{Tuple Coercions}
     3424\label{tuple coercions}\label{coercions!tuple}
    34223425
    34233426There are four coercions that can be performed on tuples and tuple variables: closing, opening, flattening and structuring.
     
    34643467
    34653468\subsection{Mass Assignment}
     3469\label{mass assignment}\label{assignment!mass}
    34663470
    34673471\CFA permits assignment to several variables at once using mass assignment~\cite{CLU}.
     
    35043508
    35053509\subsection{Multiple Assignment}
     3510\label{multiple assignment}\label{assignment!multiple}
    35063511
    35073512\CFA also supports the assignment of several values at once, known as multiple assignment~\cite{CLU,Galletly96}.
     
    35453550
    35463551\subsection{Cascade Assignment}
     3552\index{cascade assignment}\index{assignment!cascade}
    35473553
    35483554As in C, \CFA mass and multiple assignments can be cascaded, producing cascade assignment.
     
    35643570\section{Stream I/O Library}
    35653571\label{s:StreamIOLibrary}
    3566 \index{input/output stream library}
    3567 \index{stream library}
     3572\index{input}\index{output}
     3573\index{stream library}\index{library!stream}
    35683574
    35693575The 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.
    35703576Stream I/O can be implicitly or explicitly formatted.
    3571 Implicit formatting means \CFA selects the output or input format for values that match with the type of a variable.
     3577Implicit formatting means \CFA selects the output or input format for values that matches the variable's type.
    35723578Explicit formatting means additional information is specified to augment how an output or input of value is interpreted.
    3573 \CFA formatting is a cross between C ©printf© and \CC ©cout© manipulators, and Python implicit spacing and newline.
     3579\CFA formatting incorporates ideas from C ©printf©, \CC ©stream© manipulators, and Python implicit spacing and newline.
    35743580Specifically:
    35753581\begin{itemize}
     
    35843590Hence, it is common programming practice to toggle manipulators on and then back to the default to prevent downstream side-effects.
    35853591Without this programming style, errors occur when moving prints, as manipulator effects incorrectly flow into the new location.
    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.
     3592Furthermore, 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.
    35893595\end{itemize}
     3596
     3597The standard polymorphic I/Os stream are ©stdin©/©sin© (input), ©stdout©/©sout© and ©stderr©/©serr© (output) (like C++ ©cin©/©cout©/©cerr©).
     3598Polymorphic streams ©exit© and ©abort© provide implicit program termination without and with generating a stack trace and core file.
     3599Stream ©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}
     3604Note, \CFA stream variables ©stdin©, ©stdout©, ©stderr©, ©exit©, and ©abort© overload C variables ©stdin©, ©stdout©, ©stderr©, and functions ©exit© and ©abort©, respectively.
    35903605The \CFA header file for the I/O library is \Indexc{fstream.hfa}.
     3606
     3607
     3608\subsection{Basic I/O}
    35913609
    35923610For implicit formatted output, the common case is printing a series of variables separated by whitespace.
     
    36013619\begin{cfa}
    36023620
    3603 cout << x ®<< " "® << y ®<< " "® << z << endl;
     3621cout  <<  x  ®<< " "®  <<  y  ®<< " "®  <<  z << endl;
    36043622\end{cfa}
    36053623&
     
    36533671\end{tabular}
    36543672\end{cquote}
    3655 Input and output use a uniform operator, ©|©, rather than separate operators, as in ©>>© and ©<<© for \CC.
     3673Input and output use a uniform operator, ©|©, rather than \CC's ©>>© and ©<<© input/output operators.
    36563674There 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.
    36573675
     
    36983716\end{cquote}
    36993717
     3718\VRef[Figure]{f:CFACommand-LineProcessing} shows idiomatic \CFA command-line processing and copying an input file to an output file.
     3719Note, a stream variable may be copied because it is a reference to an underlying stream data-structures.
     3720All 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
     3726int 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.
     3771Returns 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.
     3778The bytes are written lazily to file when internal buffers fill.
     3779Eager 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.
     3784Pushed-back characters returned by subsequent reads in the reverse order of pushing.
     3785\end{itemize}
     3786The constructor functions:
     3787\begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
     3788\item
     3789create an unbound stream, which is subsequently bound to a file with ©open©.
     3790\item
     3791create a bound stream to the associated file with given ©mode©.
     3792\end{itemize}
     3793The destructor closes the stream.
     3794
     3795\begin{figure}
     3796\begin{cfa}
     3797// *********************************** ofstream ***********************************
     3798
     3799bool fail( ofstream & );$\indexc{fail}\index{ofstream@©ofstream©!©fail©}$
     3800void clear( ofstream & );$\indexc{clear}\index{ofstream@©ofstream©!©clear©}$
     3801int flush( ofstream & );$\indexc{flush}\index{ofstream@©ofstream©!©flush©}$
     3802void open( ofstream &, const char name[], const char mode[] = "w" );$\indexc{open}\index{ofstream@©ofstream©!©open©}$
     3803void close( ofstream & );$\indexc{close}\index{ofstream@©ofstream©!©close©}$
     3804ofstream & write( ofstream &, const char data[], size_t size );$\indexc{write}\index{ofstream@©ofstream©!©write©}$
     3805
     3806void ?{}( ofstream & );$\index{ofstream@©ofstream©!©?{}©}$
     3807void ?{}( ofstream &, const char name[], const char mode[] = "w" );
     3808void ^?{}( ofstream & );$\index{ofstream@©ofstream©!©^?{}©}$
     3809
     3810// *********************************** ifstream ***********************************
     3811
     3812bool fail( ifstream & is );$\indexc{fail}\index{ifstream@©ifstream©!©fail©}$
     3813void clear( ifstream & );$\indexc{clear}\index{ifstream@©ifstream©!©clear©}$
     3814bool eof( ifstream & is );$\indexc{eof}\index{ifstream@©ifstream©!©eof©}$
     3815void open( ifstream & is, const char name[], const char mode[] = "r" );$\indexc{open}\index{ifstream@©ifstream©!©open©}$
     3816void close( ifstream & is );$\indexc{close}\index{ifstream@©ifstream©!©close©}$
     3817ifstream & read( ifstream & is, char data[], size_t size );$\indexc{read}\index{ifstream@©ifstream©!©read©}$
     3818ifstream & ungetc( ifstream & is, char c );$\indexc{unget}\index{ifstream@©ifstream©!©unget©}$
     3819
     3820void ?{}( ifstream & is );$\index{ifstream@©ifstream©!©?{}©}$
     3821void ?{}( ifstream & is, const char name[], const char mode[] = "r" );
     3822void ^?{}( ifstream & is );$\index{ifstream@©ifstream©!©^?{}©}$
     3823\end{cfa}
     3824\caption{Stream Functions}
     3825\label{f:StreamFunctions}
     3826\end{figure}
    37003827
    37013828
     
    38463973
    38473974\item
    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.
     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.
    38493976\begin{cfa}[belowskip=0pt]
    38503977sout | 1 | sepOff | 2 | 3; $\C{// turn off implicit separator for the next item}$
     
    40304157sout | wd( 4, "ab" ) | wd( 3, "ab" ) | wd( 2, "ab" );
    40314158\end{cfa}
    4032 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
     4159\begin{cfa}[showspaces=true,aboveskip=0pt]
    40334160®  ®34 ® ®34 34
    40344161®  ®4.000000 ® ®4.000000 4.000000
     
    43784505\end{cfa}
    43794506
    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.
    4381 These stream routines use kernel-thread locking (©futex©\index{futex@©futex©}), which block kernel threads, to prevent interleaving of I/O.
    4382 However, the following simple example illustrates how a deadlock can occur (other complex scenarios are possible).
    4383 Assume a single kernel thread and two user-level threads calling ©printf©.
    4384 One user-level thread acquires the I/O lock and is time-sliced while performing ©printf©.
    4385 The other user-level thread then starts execution, calls ©printf©, and blocks the only kernel thread because it cannot acquire the I/O lock.
    4386 It 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.
     4507
     4508\section{String Stream}
     4509
     4510All 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
     4517int 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}
     4544The constructor functions:
     4545\begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
     4546\item
     4547create 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
     4554ostrstream & write( ostrstream & os, FILE * stream = stdout );
     4555
     4556void ?{}( ostrstream &, char buf[], size_t size );
     4557
     4558// *********************************** istrstream ***********************************
     4559
     4560void ?{}( istrstream & is, char buf[] );
     4561\end{cfa}
     4562\caption{String Stream Functions}
     4563\label{f:StringStreamFunctions}
     4564\end{figure}
    43874565
    43884566
     
    54825660\item
    54835661Package: a container to organize modules for distribution; It has attributes like name, author,
    5484 version, dependences, etc.
    5485 \item
    5486 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, etc.
     5662version, dependences, \etc.
     5663\item
     5664Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, \etc.
    54875665\end{itemize}
    54885666
     
    56215799
    56225800A package is defined by putting a project description file, Do.prj, with one or more modules into a directory.
    5623 This project description file contains the package's meta data, including package name, author, version, dependences, etc.
     5801This project description file contains the package's meta data, including package name, author, version, dependences, \etc.
    56245802It should be in the root of the package directory.
    56255803
     
    56785856Module: a container to organize a set of related types and methods; It has a module name, and several interfaces visible from outside
    56795857\item
    5680 Package: a container to organize modules for distribution; It has attributes like name, author, version, dependences, etc.
    5681 \item
    5682 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, etc.
     5858Package: a container to organize modules for distribution; It has attributes like name, author, version, dependences, \etc.
     5859\item
     5860Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, \etc.
    56835861\end{itemize}
    56845862
     
    81118289\begin{cquote}
    81128290\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    8113 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}}   \\
     8291\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}   \\
    81148292\hline
    81158293\begin{cfa}
    8116 #include <gmp>$\indexc{gmp}$
     8294#include <gmp.hfa>$\indexc{gmp}$
    81178295int main( void ) {
    81188296        sout | "Factorial Numbers";
  • libcfa/src/common.hfa

    r5407cdc r8d66610  
    1010// Created On       : Wed Jul 11 17:54:36 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 08:51:29 2020
    13 // Update Count     : 14
     12// Last Modified On : Wed May  5 14:02:04 2021
     13// Update Count     : 18
    1414//
    1515
     
    6767
    6868static inline {
    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
     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; }
    7276        forall( T | { int ?<?( T, T ); } )
    73         T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
     77        T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; }
    7478
    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
     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; }
    7886        forall( T | { int ?>?( T, T ); } )
    79         T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
     87        T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; }
    8088
    8189        forall( T | { T min( T, T ); T max( T, T ); } )
  • libcfa/src/concurrency/alarm.cfa

    r5407cdc r8d66610  
    3838
    3939void __kernel_set_timer( Duration alarm ) {
    40         verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm`ns);
    41         setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p );
     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        }
    4247}
    4348
     
    4651//=============================================================================================
    4752
    48 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period) with( this ) {
     53void ?{}( alarm_node_t & this, $thread * thrd, Duration alarm, Duration period) with( this ) {
     54        this.initial = alarm;
     55        this.period  = period;
    4956        this.thrd = thrd;
    50         this.alarm = alarm;
    51         this.period = period;
     57        this.timeval = __kernel_get_time() + alarm;
    5258        set = false;
    5359        type = User;
    5460}
    5561
    56 void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ) with( this ) {
     62void ?{}( alarm_node_t & this, processor * proc, Duration alarm, Duration period ) with( this ) {
     63        this.initial = alarm;
     64        this.period  = period;
    5765        this.proc = proc;
    58         this.alarm = alarm;
    59         this.period = period;
     66        this.timeval = __kernel_get_time() + alarm;
    6067        set = false;
    6168        type = Kernel;
    6269}
    63 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ) with( this ) {
    64         this.alarm = alarm;
    65         this.period = period;
     70void ?{}( alarm_node_t & this, Alarm_Callback callback, Duration alarm, Duration period ) with( this ) {
    6671        this.callback = callback;
     72        this.initial = alarm;
     73        this.period  = period;
     74        this.timeval = __kernel_get_time() + alarm;
    6775        set = false;
    6876        type = Callback;
     
    7785void insert( alarm_list_t * this, alarm_node_t * n ) {
    7886        alarm_node_t * it = & (*this)`first;
    79         while( it && (n->alarm > it->alarm) ) {
     87        while( it && (n->timeval > it->timeval) ) {
    8088                it = & (*it)`next;
    8189        }
     
    105113        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    106114        {
    107                 verify( validate( alarms ) );
    108                 bool first = ! & alarms`first;
     115                /* paranoid */ verify( validate( alarms ) );
    109116
    110                 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn );
     117                Time curr = __kernel_get_time();
     118                __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu -> %lu).\n", this, curr.tn, this->timeval.tn );
    111119                insert( &alarms, this );
    112                 if( first ) {
    113                         __kernel_set_timer( alarms`first.alarm - __kernel_get_time() );
    114                 }
     120                __kernel_set_timer( this->timeval - curr);
     121                this->set = true;
    115122        }
    116123        unlock( event_kernel->lock );
    117         this->set = true;
    118124        enable_interrupts();
    119125}
     
    124130        {
    125131                verify( validate( event_kernel->alarms ) );
    126                 remove( *this );
     132                if (this->set) remove( *this );
     133                this->set = false;
    127134        }
    128135        unlock( event_kernel->lock );
    129136        enable_interrupts();
    130         this->set = false;
    131137}
    132138
     
    136142
    137143void sleep( Duration duration ) {
    138         alarm_node_t node = { active_thread(), __kernel_get_time() + duration, 0`s };
     144        alarm_node_t node = { active_thread(), duration, 0`s };
    139145
    140146        register_self( &node );
  • libcfa/src/concurrency/alarm.hfa

    r5407cdc r8d66610  
    4646
    4747struct alarm_node_t {
    48         Time alarm;                             // time when alarm goes off
    49         Duration period;                        // if > 0 => period of alarm
     48        Duration initial;       // time when alarm goes off
     49        Duration period;        // if > 0 => period of alarm
    5050
    51         DLISTED_MGD_IMPL_IN(alarm_node_t)
     51        inline dlink(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         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
     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
    6162};
    62 DLISTED_MGD_IMPL_OUT(alarm_node_t)
     63P9_EMBEDDED( alarm_node_t, dlink(alarm_node_t) )
    6364
    64 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period );
    65 void ?{}( alarm_node_t & this, processor   * proc, Time alarm, Duration period );
    66 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period );
     65void ?{}( alarm_node_t & this, $thread * thrd, Duration alarm, Duration period );
     66void ?{}( alarm_node_t & this, processor * proc, Duration alarm, Duration period );
     67void ?{}( alarm_node_t & this, Alarm_Callback callback, Duration alarm, Duration period );
    6768void ^?{}( alarm_node_t & this );
    6869
    69 typedef dlist(alarm_node_t, alarm_node_t) alarm_list_t;
     70typedef dlist(alarm_node_t) alarm_list_t;
    7071
    7172void insert( alarm_list_t * this, alarm_node_t * n );
  • libcfa/src/concurrency/clib/cfathread.cfa

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

    r5407cdc r8d66610  
    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
    8284        } cfathread_condattr_t;
    8385        typedef struct cfathread_condition * cfathread_cond_t;
  • libcfa/src/concurrency/invoke.h

    r5407cdc r8d66610  
    146146        struct __thread_desc_link {
    147147                struct $thread * next;
    148                 struct $thread * prev;
    149148                volatile unsigned long long ts;
    150                 unsigned preferred;
    151149        };
    152150
     
    155153                // context that is switch during a __cfactx_switch
    156154                struct __stack_context_t context;
     155
     156                // Link lists fields
     157                // instrusive link field for threads
     158                struct __thread_desc_link link;
    157159
    158160                // current execution status for coroutine
     
    170172                struct cluster * curr_cluster;
    171173
    172                 // Link lists fields
    173                 // instrusive link field for threads
    174                 struct __thread_desc_link link;
     174                // preferred ready-queue
     175                unsigned preferred;
    175176
    176177                // coroutine body used to store context
  • libcfa/src/concurrency/io.cfa

    r5407cdc r8d66610  
    138138                /* paranoid */ verify( proc->io.ctx );
    139139
     140                __attribute__((unused)) cluster * cltr = proc->cltr;
    140141                $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                // }
    141147
    142148                __ioarbiter_flush( ctx );
     
    151157                                // Update statistics
    152158                                __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                                // }
    153163                                return;
    154164                        default:
     
    172182
    173183                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                // }
    174192        }
    175193
  • libcfa/src/concurrency/kernel.cfa

    r5407cdc r8d66610  
    163163        #if !defined(__CFA_NO_STATISTICS__)
    164164                if( this->print_halts ) {
    165                         __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->id, this->name, (void*)this);
     165                        __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->unique_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(); )
    174172
    175173                // if we need to run some special setup, now is the time to do it.
     
    184182                MAIN_LOOP:
    185183                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->id, rdtscl());
     225                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_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->id, rdtscl());
     238                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_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 
    268260                        if(this->io.pending && !this->io.dirty) {
    269261                                __cfa_io_flush( this );
    270262                        }
    271263
    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 );
     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
    384363                }
    385364
     
    390369
    391370        post( this->terminated );
    392 
    393371
    394372        if(this == mainProcessor) {
     
    553531static void __schedule_thread( $thread * thrd ) {
    554532        /* paranoid */ verify( ! __preemption_enabled() );
    555         /* paranoid */ verify( kernelTLS().this_proc_id );
    556533        /* paranoid */ verify( ready_schedule_islocked());
    557534        /* paranoid */ verify( thrd );
     
    567544        /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
    568545
    569 
     546        const bool local = thrd->state != Start;
    570547        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    571548
     
    575552
    576553        // push the thread to the cluster ready-queue
    577         push( cl, thrd );
     554        push( cl, thrd, local );
    578555
    579556        // variable thrd is no longer safe to use
     
    611588static inline $thread * __next_thread(cluster * this) with( *this ) {
    612589        /* paranoid */ verify( ! __preemption_enabled() );
    613         /* paranoid */ verify( kernelTLS().this_proc_id );
    614590
    615591        ready_schedule_lock();
     
    617593        ready_schedule_unlock();
    618594
    619         /* paranoid */ verify( kernelTLS().this_proc_id );
    620595        /* paranoid */ verify( ! __preemption_enabled() );
    621596        return thrd;
     
    625600static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    626601        /* paranoid */ verify( ! __preemption_enabled() );
    627         /* paranoid */ verify( kernelTLS().this_proc_id );
    628602
    629603        ready_schedule_lock();
     
    638612        ready_schedule_unlock();
    639613
    640         /* paranoid */ verify( kernelTLS().this_proc_id );
    641614        /* paranoid */ verify( ! __preemption_enabled() );
    642615        return thrd;
     
    895868                unsigned tail = *ctx->cq.tail;
    896869                if(head == tail) return false;
     870                #if OLD_MAIN
    897871                ready_schedule_lock();
    898872                ret = __cfa_io_drain( proc );
    899873                ready_schedule_unlock();
     874                #else
     875                        ret = __cfa_io_drain( proc );
     876        #endif
    900877        #endif
    901878        return ret;
     
    926903        }
    927904
     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
    928931        void print_stats_now( cluster & this, int flags ) {
     932                crawl_cluster_stats( this );
    929933                __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    930934        }
  • libcfa/src/concurrency/kernel.hfa

    r5407cdc r8d66610  
    4949
    5050// Processor id, required for scheduling threads
    51 struct __processor_id_t {
    52         unsigned id:24;
    53 
    54         #if !defined(__CFA_NO_STATISTICS__)
    55                 struct __stats_t * stats;
    56         #endif
    57 };
     51
    5852
    5953coroutine processorCtx_t {
     
    6357// Wrapper around kernel threads
    6458struct __attribute__((aligned(128))) processor {
    65         // Main state
    66         inline __processor_id_t;
    67 
    6859        // Cluster from which to get threads
    6960        struct cluster * cltr;
     
    9081        pthread_t kernel_thread;
    9182
     83        // Unique id for the processor (not per cluster)
     84        unsigned unique_id;
     85
    9286        struct {
    9387                $io_context * ctx;
     
    113107
    114108        // Link lists fields
    115         DLISTED_MGD_IMPL_IN(processor)
     109        inline dlink(processor);
    116110
    117111        // special init fields
     
    123117        } init;
    124118
     119        struct KernelThreadData * local_data;
     120
    125121        #if !defined(__CFA_NO_STATISTICS__)
    126122                int print_stats;
     
    133129#endif
    134130};
     131P9_EMBEDDED( processor, dlink(processor) )
    135132
    136133void  ?{}(processor & this, const char name[], struct cluster & cltr);
     
    140137static inline void  ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; }
    141138static inline void  ?{}(processor & this, const char name[])     { this{name, *mainCluster}; }
    142 
    143 DLISTED_MGD_IMPL_OUT(processor)
    144139
    145140//-----------------------------------------------------------------------------
     
    152147
    153148// Aligned timestamps which are used by the relaxed ready queue
    154 struct __attribute__((aligned(128))) __timestamp_t;
    155 void  ?{}(__timestamp_t & this);
    156 void ^?{}(__timestamp_t & this);
     149struct __attribute__((aligned(128))) __timestamp_t {
     150        volatile unsigned long long tv;
     151};
     152
     153static inline void  ?{}(__timestamp_t & this) { this.tv = 0; }
     154static inline void ^?{}(__timestamp_t & this) {}
    157155
    158156//TODO adjust cache size to ARCHITECTURE
     
    177175void  ?{}(__ready_queue_t & this);
    178176void ^?{}(__ready_queue_t & this);
     177#if !defined(__CFA_NO_STATISTICS__)
     178        unsigned cnt(const __ready_queue_t & this, unsigned idx);
     179#endif
    179180
    180181// Idle Sleep
     
    190191
    191192        // List of idle processors
    192         dlist(processor, processor) idles;
     193        dlist(processor) idles;
    193194
    194195        // List of active processors
    195         dlist(processor, processor) actives;
     196        dlist(processor) actives;
    196197};
    197198
  • libcfa/src/concurrency/kernel/fwd.hfa

    r5407cdc r8d66610  
    3838                        struct $thread          * volatile this_thread;
    3939                        struct processor        * volatile this_processor;
    40                         struct __processor_id_t * volatile this_proc_id;
    41                         struct __stats_t        * volatile this_stats;
     40                        volatile bool sched_lock;
    4241
    4342                        struct {
     
    5655                                uint64_t bck_seed;
    5756                        } 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
    5866                } __cfaabi_tls __attribute__ ((tls_model ( "initial-exec" )));
    5967
  • libcfa/src/concurrency/kernel/startup.cfa

    r5407cdc r8d66610  
    7777static void doregister( struct cluster & cltr );
    7878static void unregister( struct cluster & cltr );
     79static void register_tls( processor * this );
     80static void unregister_tls( processor * this );
    7981static void ?{}( $coroutine & this, current_stack_info_t * info);
    8082static void ?{}( $thread & this, current_stack_info_t * info);
     
    123125        NULL,                                                                                           // cannot use 0p
    124126        NULL,
     127        false,
     128        { 1, false, false },
     129        0,
     130        { 0, 0 },
    125131        NULL,
    126         NULL,
    127         { 1, false, false },
     132        #ifdef __CFA_WITH_VERIFY__
     133                false,
     134                0,
     135        #endif
    128136};
    129137
     
    210218        (*mainProcessor){};
    211219
     220        register_tls( mainProcessor );
     221
    212222        //initialize the global state variables
    213223        __cfaabi_tls.this_processor = mainProcessor;
    214         __cfaabi_tls.this_proc_id   = (__processor_id_t*)mainProcessor;
    215224        __cfaabi_tls.this_thread    = mainThread;
    216225
     
    219228                __init_stats( __cfaabi_tls.this_stats );
    220229        #endif
     230        mainProcessor->local_data = &__cfaabi_tls;
    221231
    222232        // Enable preemption
     
    273283        #endif
    274284
     285        mainProcessor->local_data = 0p;
     286
     287        unregister_tls( mainProcessor );
     288
    275289        // Destroy the main processor and its context in reverse order of construction
    276290        // These were manually constructed so we need manually destroy them
     
    316330        processor * proc = (processor *) arg;
    317331        __cfaabi_tls.this_processor = proc;
    318         __cfaabi_tls.this_proc_id   = (__processor_id_t*)proc;
    319332        __cfaabi_tls.this_thread    = 0p;
    320333        __cfaabi_tls.preemption_state.[enabled, disable_count] = [false, 1];
     334        proc->local_data = &__cfaabi_tls;
     335
     336        register_tls( proc );
     337
    321338        // SKULLDUGGERY: We want to create a context for the processor coroutine
    322339        // which is needed for the 2-step context switch. However, there is no reason
     
    355372                #endif
    356373        #endif
     374
     375        proc->local_data = 0p;
     376
     377        unregister_tls( proc );
    357378
    358379        return 0p;
     
    446467        self_mon_p = &self_mon;
    447468        link.next = 0p;
    448         link.prev = 0p;
    449         link.preferred = -1u;
     469        link.ts   = 0;
     470        preferred = -1u;
    450471        last_proc = 0p;
    451472        #if defined( __CFA_WITH_VERIFY__ )
     
    475496        this.rdq.id  = -1u;
    476497        this.rdq.target = -1u;
    477         this.rdq.cutoff = -1ull;
     498        this.rdq.cutoff = 0ull;
    478499        do_terminate = false;
    479500        preemption_alarm = 0p;
     
    485506
    486507        this.init.thrd = initT;
     508
     509        this.local_data = 0p;
    487510
    488511        this.idle = eventfd(0, 0);
     
    496519        #endif
    497520
    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 
    509521        __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
    510522}
     
    512524// Not a ctor, it just preps the destruction but should not destroy members
    513525static 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 
    525526        close(this.idle);
    526527}
     
    656657        cltr->nthreads -= 1;
    657658        unlock(cltr->thread_list_lock);
     659}
     660
     661static 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
     677static 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 );
    658692}
    659693
  • libcfa/src/concurrency/kernel_private.hfa

    r5407cdc r8d66610  
    2525// Scheduler
    2626
    27 struct __attribute__((aligned(128))) __scheduler_lock_id_t;
    2827
    2928extern "C" {
     
    8079// Lock-Free registering/unregistering of threads
    8180// Register a processor to a given cluster and get its unique id in return
    82 void register_proc_id( struct __processor_id_t * );
     81unsigned register_proc_id( void );
    8382
    8483// Unregister a processor from a given cluster using its id, getting back the original pointer
    85 void unregister_proc_id( struct __processor_id_t * proc );
     84void unregister_proc_id( unsigned );
    8685
    8786//=======================================================================
     
    112111}
    113112
    114 // Cells use by the reader writer lock
    115 // while not generic it only relies on a opaque pointer
    116 struct __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 
    130 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
     113
     114
     115
    131116
    132117//-----------------------------------------------------------------------
     
    147132
    148133        // writer lock
    149         volatile bool lock;
     134        volatile bool write_lock;
    150135
    151136        // data pointer
    152         __scheduler_lock_id_t * data;
     137        volatile bool * volatile * data;
    153138};
    154139
     
    163148static inline void ready_schedule_lock(void) with(*__scheduler_lock) {
    164149        /* paranoid */ verify( ! __preemption_enabled() );
    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);
     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 );
    170153
    171154        // Step 1 : make sure no writer are in the middle of the critical section
    172         while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED))
     155        while(__atomic_load_n(&write_lock, (int)__ATOMIC_RELAXED))
    173156                Pause();
    174157
     
    179162
    180163        // Step 2 : acquire our local lock
    181         __atomic_acquire( &data[iproc].lock );
    182         /*paranoid*/ verify(data[iproc].lock);
     164        __atomic_acquire( &kernelTLS().sched_lock );
     165        /*paranoid*/ verify(kernelTLS().sched_lock);
    183166
    184167        #ifdef __CFA_WITH_VERIFY__
    185168                // Debug, check if this is owned for reading
    186                 data[iproc].owned = true;
     169                kernelTLS().in_sched_lock = true;
    187170        #endif
    188171}
     
    190173static inline void ready_schedule_unlock(void) with(*__scheduler_lock) {
    191174        /* paranoid */ verify( ! __preemption_enabled() );
    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);
     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 );
    199179        #ifdef __CFA_WITH_VERIFY__
    200180                // Debug, check if this is owned for reading
    201                 data[iproc].owned = false;
     181                kernelTLS().in_sched_lock = false;
    202182        #endif
    203         __atomic_unlock(&data[iproc].lock);
     183        __atomic_unlock(&kernelTLS().sched_lock);
    204184}
    205185
     
    207187        static inline bool ready_schedule_islocked(void) {
    208188                /* paranoid */ verify( ! __preemption_enabled() );
    209                 /*paranoid*/ verify( kernelTLS().this_proc_id );
    210                 __processor_id_t * proc = kernelTLS().this_proc_id;
    211                 return __scheduler_lock->data[proc->id].owned;
     189                /* paranoid */ verify( (!kernelTLS().in_sched_lock) || kernelTLS().sched_lock );
     190                return kernelTLS().sched_lock;
    212191        }
    213192
    214193        static inline bool ready_mutate_islocked() {
    215                 return __scheduler_lock->lock;
     194                return __scheduler_lock->write_lock;
    216195        }
    217196#endif
     
    228207// Register a processor to a given cluster and get its unique id in return
    229208// For convenience, also acquires the lock
    230 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {
    231         register_proc_id( proc );
    232         return ready_mutate_lock();
     209static 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];
    233213}
    234214
    235215// Unregister a processor from a given cluster using its id, getting back the original pointer
    236216// assumes the lock is acquired
    237 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {
     217static inline void ready_mutate_unregister( unsigned id, uint_fast32_t last_s ) {
    238218        ready_mutate_unlock( last_s );
    239         unregister_proc_id( proc );
     219        unregister_proc_id( id );
    240220}
    241221
     
    281261// push thread onto a ready queue for a cluster
    282262// returns true if the list was previously empty, false otherwise
    283 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
     263__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd, bool local);
    284264
    285265//-----------------------------------------------------------------------
  • libcfa/src/concurrency/locks.cfa

    r5407cdc r8d66610  
    188188                alarm_node_t alarm_node;
    189189                condition_variable(L) * cond;
    190                 info_thread(L) * i;
     190                info_thread(L) * info_thd;
    191191        };
    192192
    193         void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) {
     193        void ?{}( alarm_node_wrap(L) & this, Duration 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.i = i;
     196                this.info_thd = 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(i) ) {      // is thread on queue
    209                         i->signalled = false;
     208                if ( listed(info_thd) ) {       // is thread on queue
     209                        info_thd->signalled = false;
    210210                        // remove this thread O(1)
    211                         remove( cond->blocked_threads, *i );
     211                        remove( cond->blocked_threads, *info_thd );
    212212                        cond->count--;
    213                         if( i->lock ) {
     213                        if( info_thd->lock ) {
    214214                                // call lock's on_notify if a lock was passed
    215                                 on_notify(*i->lock, i->t);
     215                                on_notify(*info_thd->lock, info_thd->t);
    216216                        } else {
    217217                                // otherwise wake thread
    218                                 unpark( i->t );
     218                                unpark( info_thd->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, Time t ) with(this) {
     315        void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) 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, alarm_node_wrap_cast, &this, &info };
     318                alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &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 ); \
     334                queue_info_thread_timeout(this, i, t, alarm_node_wrap_cast ); \
    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 , __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 ) }
     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 ) }
    350346}
    351347
  • libcfa/src/concurrency/locks.hfa

    r5407cdc r8d66610  
    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 );
    294292
    295293        void wait( condition_variable(L) & this, L & l );
     
    297295        bool wait( condition_variable(L) & this, L & l, Duration duration );
    298296        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration );
    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 }
     297}
  • libcfa/src/concurrency/preemption.cfa

    r5407cdc r8d66610  
    1818
    1919#include "preemption.hfa"
     20
    2021#include <assert.h>
    2122
     
    2627#include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2728
     29#include "bits/debug.hfa"
    2830#include "bits/signal.hfa"
    2931#include "kernel_private.hfa"
     
    105107static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) {
    106108        if( ! & (*alarms)`first ) return 0p;                                            // If no alarms return null
    107         if( (*alarms)`first.alarm >= currtime ) return 0p;      // If alarms head not expired return null
     109        if( (*alarms)`first.timeval >= currtime ) return 0p;    // If alarms head not expired return null
    108110        return pop(alarms);                                                                     // Otherwise just pop head
    109111}
     
    141143                if( period > 0 ) {
    142144                        __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns );
    143                         node->alarm = currtime + period;    // Alarm is periodic, add currtime to it (used cached current time)
     145                        node->timeval = currtime + period;  // Alarm is periodic, add currtime to it (used cached current time)
    144146                        insert( alarms, node );             // Reinsert the node for the next time it triggers
    145147                }
     
    148150        // If there are still alarms pending, reset the timer
    149151        if( & (*alarms)`first ) {
    150                 Duration delta = (*alarms)`first.alarm - currtime;
    151                 Duration capped = max(delta, 50`us);
    152                 __kernel_set_timer( capped );
     152                Duration delta = (*alarms)`first.timeval - currtime;
     153                __kernel_set_timer( delta );
    153154        }
    154155}
     
    160161        // Alarms need to be enabled
    161162        if ( duration > 0 && ! alarm->set ) {
    162                 alarm->alarm = __kernel_get_time() + duration;
    163                 alarm->period = duration;
     163                alarm->initial = duration;
     164                alarm->period  = duration;
    164165                register_self( alarm );
    165166        }
     
    167168        else if ( duration == 0 && alarm->set ) {
    168169                unregister_self( alarm );
    169                 alarm->alarm = 0;
    170                 alarm->period = 0;
     170                alarm->initial = 0;
     171                alarm->period  = 0;
    171172        }
    172173        // If alarm is different from previous, change it
    173174        else if ( duration > 0 && alarm->period != duration ) {
    174175                unregister_self( alarm );
    175                 alarm->alarm = __kernel_get_time() + duration;
    176                 alarm->period = duration;
     176                alarm->initial = duration;
     177                alarm->period  = duration;
    177178                register_self( alarm );
    178179        }
     
    599600
    600601        // Notify the alarm thread of the shutdown
    601         sigval val = { 1 };
     602        sigval val;
     603        val.sival_int = 0;
    602604        pthread_sigqueue( alarm_thread, SIGALRM, val );
    603605
     
    619621// Used by thread to control when they want to receive preemption signals
    620622void ?{}( preemption_scope & this, processor * proc ) {
    621         (this.alarm){ proc, (Time){ 0 }, 0`s };
     623        (this.alarm){ proc, 0`s, 0`s };
    622624        this.proc = proc;
    623625        this.proc->preemption_alarm = &this.alarm;
     
    687689// Waits on SIGALRM and send SIGUSR1 to whom ever needs it
    688690static void * alarm_loop( __attribute__((unused)) void * args ) {
    689         __processor_id_t id;
    690         register_proc_id(&id);
    691         __cfaabi_tls.this_proc_id = &id;
    692 
     691        unsigned id = register_proc_id();
    693692
    694693        // Block sigalrms to control when they arrive
     
    707706                siginfo_t info;
    708707                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 );
    709711
    710712                if( sig < 0 ) {
     
    714716                                case EAGAIN :
    715717                                case EINTR :
    716                                         {__cfaabi_dbg_print_buffer_decl( " KERNEL: Spurious wakeup %d.\n", err );}
     718                                        {__cfadbg_print_buffer_local( preemption, " KERNEL: Spurious wakeup %d.\n", err );}
    717719                                        continue;
    718720                                case EINVAL :
     
    726728                assertf(sig == SIGALRM, "Kernel Internal Error, sigwait: Unexpected signal %d (%d : %d)\n", sig, info.si_code, info.si_value.sival_int);
    727729
    728                 // __cfaabi_dbg_print_safe( "Kernel : Caught alarm from %d with %d\n", info.si_code, info.si_value.sival_int );
    729730                // Switch on the code (a.k.a. the sender) to
    730731                switch( info.si_code )
    731732                {
     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
    732745                // Timers can apparently be marked as sent for the kernel
    733746                // In either case, tick preemption
     
    739752                        unlock( event_kernel->lock );
    740753                        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;
    746754                }
    747755        }
     
    749757EXIT:
    750758        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    751         register_proc_id(&id);
     759        unregister_proc_id(id);
    752760
    753761        return 0p;
  • libcfa/src/concurrency/ready_queue.cfa

    r5407cdc r8d66610  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
    19 // #define USE_MPSC
    2019
    2120#define USE_RELAXED_FIFO
     
    9392        this.alloc = 0;
    9493        this.ready = 0;
    95         this.lock  = false;
    9694        this.data  = alloc(this.max);
    97 
    98         /*paranoid*/ verify( 0 == (((uintptr_t)(this.data    )) % 64) );
    99         /*paranoid*/ verify( 0 == (((uintptr_t)(this.data + 1)) % 64) );
     95        this.write_lock  = false;
     96
    10097        /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.alloc), &this.alloc));
    10198        /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.ready), &this.ready));
     
    106103}
    107104
    108 void ?{}( __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 }
    115105
    116106//=======================================================================
    117107// Lock-Free registering/unregistering of threads
    118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     108unsigned register_proc_id( void ) with(*__scheduler_lock) {
    119109        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
     110        bool * handle = (bool *)&kernelTLS().sched_lock;
    120111
    121112        // Step - 1 : check if there is already space in the data
     
    124115        // Check among all the ready
    125116        for(uint_fast32_t i = 0; i < s; 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;
     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;
    133126                }
    134127        }
     
    141134
    142135        // Step - 3 : Mark space as used and then publish it.
    143         __scheduler_lock_id_t * storage = (__scheduler_lock_id_t *)&data[n];
    144         (*storage){ proc };
     136        data[n] = handle;
    145137        while() {
    146138                unsigned copy = n;
     
    154146
    155147        // Return new spot.
    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 
    162 void 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);
     148        /* paranoid */ verify(n < ready);
     149        /* paranoid */ verify( (kernelTLS().sched_id = n, true) );
     150        return n;
     151}
     152
     153void 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);
    167161
    168162        __cfadbg_print_safe(ready_queue, "Kernel : Unregister proc %p\n", proc);
     
    174168uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
    175169        /* paranoid */ verify( ! __preemption_enabled() );
     170        /* paranoid */ verify( ! kernelTLS().sched_lock );
    176171
    177172        // Step 1 : lock global lock
    178173        // It is needed to avoid processors that register mid Critical-Section
    179174        //   to simply lock their own lock and enter.
    180         __atomic_acquire( &lock );
     175        __atomic_acquire( &write_lock );
    181176
    182177        // Step 2 : lock per-proc lock
     
    186181        uint_fast32_t s = ready;
    187182        for(uint_fast32_t i = 0; i < s; i++) {
    188                 __atomic_acquire( &data[i].lock );
     183                volatile bool * llock = data[i];
     184                if(llock) __atomic_acquire( llock );
    189185        }
    190186
     
    203199        // Alternative solution : return s in write_lock and pass it to write_unlock
    204200        for(uint_fast32_t i = 0; i < last_s; i++) {
    205                 verify(data[i].lock);
    206                 __atomic_store_n(&data[i].lock, (bool)false, __ATOMIC_RELEASE);
     201                volatile bool * llock = data[i];
     202                if(llock) __atomic_store_n(llock, (bool)false, __ATOMIC_RELEASE);
    207203        }
    208204
    209205        // Step 2 : release global lock
    210         /*paranoid*/ assert(true == lock);
    211         __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
     206        /*paranoid*/ assert(true == write_lock);
     207        __atomic_store_n(&write_lock, (bool)false, __ATOMIC_RELEASE);
    212208
    213209        /* paranoid */ verify( ! __preemption_enabled() );
     
    253249        }
    254250
    255         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     251        __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd, bool push_local) with (cltr->ready_queue) {
    256252                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    257253
    258                 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     254                const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    259255                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    260 
    261                 // write timestamp
    262                 thrd->link.ts = rdtscl();
    263256
    264257                bool local;
     
    280273                        #endif
    281274
    282                 #if defined(USE_MPSC)
    283                         // mpsc always succeeds
    284                 } while( false );
    285                 #else
    286275                        // If we can't lock it retry
    287276                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    288                 #endif
    289277
    290278                // Actually push it
    291279                push(lanes.data[i], thrd);
    292280
    293                 #if !defined(USE_MPSC)
    294                         // Unlock and return
    295                         __atomic_unlock( &lanes.data[i].lock );
    296                 #endif
     281                // Unlock and return
     282                __atomic_unlock( &lanes.data[i].lock );
    297283
    298284                // Mark the current index in the tls rng instance as having an item
     
    350336#endif
    351337#if defined(USE_WORK_STEALING)
    352         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     338        __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd, bool push_local) with (cltr->ready_queue) {
    353339                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    354340
    355                 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     341                // #define USE_PREFERRED
     342                #if !defined(USE_PREFERRED)
     343                const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    356344                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    357 
    358                 // write timestamp
    359                 thrd->link.ts = rdtscl();
     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
    360353
    361354                // Try to pick a lane and lock it
     
    371364                        }
    372365                        else {
    373                                 processor * proc = kernelTLS().this_processor;
    374                                 unsigned r = proc->rdq.its++;
    375                                 i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
     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
    376373                        }
    377 
    378 
    379                 #if defined(USE_MPSC)
    380                         // mpsc always succeeds
    381                 } while( false );
    382                 #else
    383374                        // If we can't lock it retry
    384375                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    385                 #endif
    386376
    387377                // Actually push it
    388378                push(lanes.data[i], thrd);
    389379
    390                 #if !defined(USE_MPSC)
    391                         // Unlock and return
    392                         __atomic_unlock( &lanes.data[i].lock );
    393                 #endif
     380                // Unlock and return
     381                __atomic_unlock( &lanes.data[i].lock );
    394382
    395383                #if !defined(__CFA_NO_STATISTICS__)
     
    410398
    411399                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;
    412406                        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;
    421407                }
    422408                else {
    423409                        unsigned target = proc->rdq.target;
    424410                        proc->rdq.target = -1u;
    425                         if(lanes.tscs[target].tv < proc->rdq.cutoff) {
     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) {
    426414                                $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
    427415                                if(t) return t;
     
    430418
    431419                for(READYQ_SHARD_FACTOR) {
    432                         unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR);
     420                        unsigned i = proc->rdq.id + (proc->rdq.itr++ % READYQ_SHARD_FACTOR);
    433421                        if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
    434422                }
     
    462450        // If list looks empty retry
    463451        if( is_empty(lane) ) {
    464                 __STATS( stats.espec++; )
    465452                return 0p;
    466453        }
     
    468455        // If we can't get the lock retry
    469456        if( !__atomic_try_acquire(&lane.lock) ) {
    470                 __STATS( stats.elock++; )
    471457                return 0p;
    472458        }
     
    475461        if( is_empty(lane) ) {
    476462                __atomic_unlock(&lane.lock);
    477                 __STATS( stats.eempty++; )
    478463                return 0p;
    479464        }
     
    481466        // Actually pop the list
    482467        struct $thread * thrd;
    483         thrd = pop(lane);
     468        unsigned long long tsv;
     469        [thrd, tsv] = pop(lane);
    484470
    485471        /* paranoid */ verify(thrd);
     472        /* paranoid */ verify(tsv);
    486473        /* paranoid */ verify(lane.lock);
    487474
     
    493480
    494481        #if defined(USE_WORK_STEALING)
    495                 lanes.tscs[w].tv = thrd->link.ts;
     482                lanes.tscs[w].tv = tsv;
    496483        #endif
     484
     485        thrd->preferred = w;
    497486
    498487        // return the popped thread
     
    522511// Check that all the intrusive queues in the data structure are still consistent
    523512static void check( __ready_queue_t & q ) with (q) {
    524         #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
     513        #if defined(__CFA_WITH_VERIFY__)
    525514                {
    526515                        for( idx ; lanes.count ) {
     
    528517                                assert(!lanes.data[idx].lock);
    529518
    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                                 }
     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                                        }
    542528                        }
    543529                }
     
    560546// fixes the list so that the pointers back to anchors aren't left dangling
    561547static inline void fix(__intrusive_lane_t & ll) {
    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 
    578 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) {
     548                        if(is_empty(ll)) {
     549                                verify(ll.anchor.next == 0p);
     550                                ll.prev = mock_head(ll);
     551                        }
     552}
     553
     554static void assign_list(unsigned & value, dlist(processor) & list, unsigned count) {
    579555        processor * it = &list`first;
    580556        for(unsigned i = 0; i < count; i++) {
     
    597573                lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
    598574                for(i; lanes.count) {
    599                         lanes.tscs[i].tv = ts(lanes.data[i]);
     575                        unsigned long long tsc = ts(lanes.data[i]);
     576                        lanes.tscs[i].tv = tsc != 0 ? tsc : rdtscl();
    600577                }
    601578        #endif
     
    686663                        while(!is_empty(lanes.data[idx])) {
    687664                                struct $thread * thrd;
    688                                 thrd = pop(lanes.data[idx]);
    689 
    690                                 push(cltr, thrd);
     665                                unsigned long long _;
     666                                [thrd, _] = pop(lanes.data[idx]);
     667
     668                                push(cltr, thrd, true);
    691669
    692670                                // for printing count the number of displaced threads
     
    725703        /* paranoid */ verify( ready_mutate_islocked() );
    726704}
     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

    r5407cdc r8d66610  
    77// Intrusives lanes which are used by the relaxed ready queue
    88struct __attribute__((aligned(128))) __intrusive_lane_t {
    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
     9        struct $thread * prev;
    2210
    2311        // spin lock protecting the queue
    2412        volatile bool lock;
    2513
    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;
     14        __thread_desc_link anchor;
    3115
    32                         // total number of pushes and pops
    33                         size_t  push;
    34                         size_t  pop ;
    35                 } stat;
     16        #if !defined(__CFA_NO_STATISTICS__)
     17                unsigned cnt;
    3618        #endif
    3719};
    3820
    39 void  ?{}(__intrusive_lane_t & this);
    40 void ^?{}(__intrusive_lane_t & this);
    41 
    4221// Get the head pointer (one before the first element) from the anchor
    43 static 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
    56 static 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
     22static 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;
    6627}
    6728
     
    6930void ?{}( __intrusive_lane_t & this ) {
    7031        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
    7138
    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
     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) );
    10251}
    10352
    10453// Dtor is trivial
    10554void ^?{}( __intrusive_lane_t & this ) {
    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
     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 );
    11359}
    11460
    11561// Push a thread onto this lane
    11662// returns true of lane was empty before push, false otherwise
    117 bool 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);
     63static 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        }
    13178
    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;
     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++;
    16685        #endif
    16786}
     
    17089// returns popped
    17190// returns true of lane was empty before push, false otherwise
    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);
     91static 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  );
    18195
    182                 // Get anchors locally
    183                 $thread * head = head(this);
    184                 $thread * tail = tail(this);
     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
    185107
    186                 // Get the relevant nodes locally
    187                 $thread * node = head->link.next;
    188                 $thread * next = node->link.next;
     108        // Update head time stamp
     109        if(is_empty) this.prev = mock_head( this );
    189110
    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
     111        /* paranoid */ verify( node->link.next == 0p );
     112        /* paranoid */ verify( node->link.ts   == 0  );
     113        return [node, ts];
    225114}
    226115
    227116// Check whether or not list is empty
    228117static inline bool is_empty(__intrusive_lane_t & this) {
    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
     118        return this.anchor.ts == 0;
    235119}
    236120
    237121// Return the timestamp
    238122static inline unsigned long long ts(__intrusive_lane_t & this) {
    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
     123        // Cannot verify here since it may not be locked
     124        return this.anchor.ts;
    247125}
    248 
    249 // Aligned timestamps which are used by the relaxed ready queue
    250 struct __attribute__((aligned(128))) __timestamp_t {
    251         volatile unsigned long long tv;
    252 };
    253 
    254 void  ?{}(__timestamp_t & this) { this.tv = 0; }
    255 void ^?{}(__timestamp_t & this) {}
  • libcfa/src/concurrency/stats.cfa

    r5407cdc r8d66610  
    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;
    2421                stats->ready.pop.help  .attempt = 0;
    2522                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;
    2923                stats->ready.pop.steal .attempt = 0;
    3024                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;
    3425                stats->ready.pop.search.attempt = 0;
    3526                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;
    3927                stats->ready.threads.migration = 0;
    4028                stats->ready.threads.extunpark = 0;
    4129                stats->ready.threads.threads   = 0;
     30                stats->ready.threads.cthreads  = 0;
    4231                stats->ready.sleep.halts   = 0;
    4332                stats->ready.sleep.cancels = 0;
     
    5948                        stats->io.calls.completed   = 0;
    6049                        stats->io.calls.errors.busy = 0;
    61                         stats->io.poller.sleeps     = 0;
    6250                #endif
    6351
     
    6856        }
    6957
     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
    7068        void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) {
    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;
     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        );
    10491
    10592                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    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;
     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 );
    120106                #endif
    121107        }
     
    130116                if( flags & CFA_STATS_READY_Q ) {
    131117
    132                         sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";
     118                        sstr | "----- " | type | " \"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";
    133119
    134120                        uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success;
    135121                        uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success;
    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)";
     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)";
    137124
    138125                        double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS;
     
    147134                        double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR;
    148135                        sstr | "- local    : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%'
    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)";
     136                             | " (" | eng3(ready.pop.local .attempt) | " try)";
    150137                        double rHlp_pc = (100.0 * (double)ready.pop.help  .success) / totalR;
    151138                        sstr | "- help     : " | eng3(ready.pop.help  .success) | "-"| ws(3, 3, rHlp_pc) | '%'
    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)";
     139                             | " (" | eng3(ready.pop.help  .attempt) | " try)";
    153140                        double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR;
    154141                        sstr | "- steal    : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%'
    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)";
     142                             | " (" | eng3(ready.pop.steal .attempt) | " try)";
    156143                        double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR;
    157144                        sstr | "- search   : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%'
    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)";
     145                             | " (" | eng3(ready.pop.search.attempt) | " try)";
    159146
    160147                        sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit";
     
    164151                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    165152                        if( flags & CFA_STATS_IO ) {
    166                                 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";
     153                                sstr | "----- " | type | " \"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";
    167154
    168155                                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";
    172156
    173157                                uint64_t total_submits = io.submit.fast + io.submit.slow;
    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)";
     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);
    179174
    180175                                double avgsubs = ((double)io.calls.submitted) / io.calls.flush;
    181176                                double avgcomp = ((double)io.calls.completed) / io.calls.drain;
    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);
     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";
    186181                                sstr | nl;
    187182                        }
  • libcfa/src/concurrency/stats.hfa

    r5407cdc r8d66610  
    22
    33// #define CFA_STATS_ARRAY 10000
     4// #define __CFA_NO_STATISTICS__
    45
    56#include <stdint.h>
     
    2223                // number of successes at poping
    2324                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;
    3325        };
    3426
     
    7163                        volatile uint64_t migration;
    7264                        volatile uint64_t extunpark;
    73                         volatile  int64_t threads; // number of threads in the system, includes only local change
     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
    7467                } threads;
    7568                struct {
  • libcfa/src/concurrency/thread.cfa

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

    r5407cdc r8d66610  
    55
    66// the inverse of Z(-)
    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)
     7#define z(N) sizeof(N)
    118
    129forall( T & ) struct tag {};
     
    1916//
    2017
    21 forall( ztype(Zn), ztype(S), Timmed &, Tbase & ) {
     18forall( [N], S & | sized(S), Timmed &, Tbase & ) {
    2219    struct arpk {
    23         S strides[z(Zn)];
     20        S strides[z(N)];
    2421    };
    2522
    26     Timmed & ?[?]( arpk(Zn, S, Timmed, Tbase) & a, ptrdiff_t i ) {
     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 ) {
    2742        return (Timmed &) a.strides[i];
    2843    }
    2944
    30     size_t ?`len( arpk(Zn, S, Timmed, Tbase) & a ) {
    31         return z(Zn);
     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);
    3259    }
    3360
    3461    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
    35     void ?{}( arpk(Zn, S, Timmed, Tbase) & this ) {
    36         void ?{}( S (&inner)[z(Zn)] ) {}
     62    static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {
     63        void ?{}( S (&inner)[z(N)] ) {}
    3764        ?{}(this.strides);
    3865    }
    39     void ^?{}( arpk(Zn, S, Timmed, Tbase) & this ) {
    40         void ^?{}( S (&inner)[z(Zn)] ) {}
     66    static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
     67        void ^?{}( S (&inner)[z(N)] ) {}
    4168        ^?{}(this.strides);
    4269    }
     
    4875
    4976forall( Te )
    50 Te mkar_( tag(Te) ) {}
     77static inline Te mkar_( tag(Te) ) {}
    5178
    52 forall( ztype(Zn), ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
    53 arpk(Zn, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(Zn), ZTags ) {}
     79forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
     80static inline arpk(N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}
    5481
    5582// based on https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
     
    80107// Core -[[-,-,-]] operator
    81108
     109#ifdef TRY_BROKEN_DESIRED_MD_SUBSCRIPT
     110
    82111// 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 // }
     112
     113forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } )
     114static inline TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
     115    return this[ab][bc];
     116}
     117
     118#else
    87119
    88120// Workaround form.  Listing all possibilities up to 4 dims.
    89 forall( TA &, TB &, IxAB | { TB & ?[?]( TA &, IxAB ); }
    90             , TC &, IxBC | { TC & ?[?]( TB &, IxBC ); } )
    91 TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
     121
     122forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } )
     123static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) {
    92124    return this[ab][bc];
    93125}
    94 forall( TA &, TB &, IxAB | { TB & ?[?]( TA &, IxAB ); }
    95             , TC &, IxBC | { TC & ?[?]( TB &, IxBC ); }
    96             , TD &, IxCD | { TD & ?[?]( TC &, IxCD ); } )
    97 TD & ?[?]( TA & this, IxAB ab, IxBC bc, IxCD cd ) {
    98     return this[ab][bc][cd];
    99 }
    100 forall( TA &, TB &, IxAB | { TB & ?[?]( TA &, IxAB ); }
    101             , TC &, IxBC | { TC & ?[?]( TB &, IxBC ); }
    102             , TD &, IxCD | { TD & ?[?]( TC &, IxCD ); }
    103             , TE &, IxDE | { TE & ?[?]( TD &, IxDE ); } )
    104 TE & ?[?]( TA & this, IxAB ab, IxBC bc, IxCD cd, IxDE de ) {
    105     return this[ab][bc][cd][de];
     126
     127forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } )
     128static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) {
     129    return this[[ab0,ab1]][bc];
    106130}
    107131
    108 // Adapters for "indexed by ptrdiff_t" implies "indexed by [this other integral type]"
    109 // Work around restriction that assertions underlying -[[-,-,-]] must match excatly
    110 forall( C &, E & | { E & ?[?]( C &, ptrdiff_t ); } ) {
     132forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxAB_2, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1, IxAB_2 ); TC & ?[?]( TB &, IxBC ); } )
     133static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) {
     134    return this[[ab0,ab1,ab2]][bc];
     135}
    111136
    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     }
    121 }
     137#endif
    122138
    123139//
     
    126142
    127143// Base
    128 forall( ztype(Zq), ztype(Sq), Tbase & )
    129 tag(arpk(Zq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(Tbase) ) {}
     144forall( [Nq], Sq & | sized(Sq), Tbase & )
     145static inline tag(arpk(Nq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(Tbase) ) {}
    130146
    131147// Rec
    132 forall( ztype(Zq), ztype(Sq), ztype(Z), ztype(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(recq) ); } )
    133 tag(arpk(Z, S, recr, Tbase)) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(arpk(Z, S, recq, Tbase)) ) {}
     148forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } )
     149static inline tag(arpk(N, S, recr, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(arpk(N, S, recq, Tbase)) ) {}
    134150
    135151// Wrapper
    136152struct all_t {} all;
    137 forall( ztype(Z), ztype(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(Z), tag(S), tag(Te) ); } )
    138 result & ?[?]( arpk(Z, S, Te, Tbase) & this, all_t ) {
     153forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } )
     154static inline result & ?[?]( arpk(N, S, Te, Tbase) & this, all_t ) {
    139155    return (result&) this;
    140156}
  • libcfa/src/containers/list.hfa

    r5407cdc r8d66610  
    1818#include <assert.h>
    1919
    20 #define __DLISTED_MGD_COMMON(ELEM, NODE, LINKS_FLD) \
    21 static inline ELEM& $tempcv_n2e(NODE &node) { \
    22         return node; \
    23 } \
    24 \
    25 static inline NODE& $tempcv_e2n(ELEM &node) { \
    26         return ( NODE & ) node; \
    27 } \
    28 \
    29 static 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 \
    36 static 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 \
    43 static 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 \
    49 static 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; \
     20forall( Decorator &, T & )
     21struct tytagref {
     22    inline T &;
     23};
     24
     25trait embedded( tOuter &, tMid &, tInner & ) {
     26    tytagref( tMid, tInner ) ?`inner( tOuter & );
     27};
     28
     29// embedded is reflexive, with no info (void) as the type tag
     30forall (T &)
     31static 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 ) \
     35forall( 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
     84forall( 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
    53116}
    54117
    55 #define __DLISTED_MGD_JUSTEXPL(STRUCT, IN_THELIST, STRUCT_IN_THELIST) \
    56 struct STRUCT_IN_THELIST { \
    57         inline STRUCT; \
    58 }; \
    59 \
    60 void ?{}(STRUCT_IN_THELIST &) = void; \
    61 \
    62 static inline STRUCT_IN_THELIST& ?`IN_THELIST(STRUCT &this) { \
    63         return (STRUCT_IN_THELIST&)this; \
    64 }
    65 
    66 #define __DLISTED_MGD_JUSTIMPL(STRUCT)
    67 
    68 forall( 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 
    122 trait $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 &);
    130 };
    131 
    132 forall (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) {
     118
     119forall( tE &, tLinks & | embedded( tE, tLinks, dlink(tE) ) ) {
     120
     121        static inline void insert_after(tE & list_pos, tE &to_insert) {
    188122                verify (&list_pos != 0p);
    189123                verify (&to_insert != 0p);
    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) {
     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) {
    211141                verify (&list_pos != 0p);
    212142                verify (&to_insert != 0p);
    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         }
     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
    349298
    350299}
  • libcfa/src/exception.c

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

    r5407cdc r8d66610  
    2929struct __cfaehm_base_exception_t;
    3030typedef struct __cfaehm_base_exception_t exception_t;
    31 struct __cfa__parent_vtable;
     31struct __cfavir_type_info;
    3232struct __cfaehm_base_exception_t_vtable {
    33         const struct __cfa__parent_vtable * __cfavir_typeid;
     33        const struct __cfavir_type_info * __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 __cfa__parent_vtable __cfatid_exception_t;
     43extern struct __cfavir_type_info __cfatid_exception_t;
    4444
    4545
  • libcfa/src/exception.hfa

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

    r5407cdc r8d66610  
    77#include <containers/list.hfa>
    88
    9 forall( T & | $dlistable(T, T) ) {
     9forall( T &, TLink& = dlink(T) | embedded(T, TLink, dlink(T)) ) {
    1010        monitor Buffer {                                                                        // unbounded buffer
    11                 dlist( T, T ) queue;                                                    // unbounded list of work requests
     11                dlist( T, TLink ) queue;                                                // unbounded list of work requests
    1212                condition delay;
    1313        }; // Buffer
    1414
    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
     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
    1717                insert_last( *qptr, *elem );                                    // insert element into buffer
    1818                signal( delay );                                                                // restart
    1919        } // insert
    2020
    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 );
     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 );
    2626        } // remove
    2727} // forall
     
    2929struct WRequest {                                                                               // client request, no return
    3030        void (* action)( void );
    31         DLISTED_MGD_IMPL_IN(WRequest)
     31        inline dlink(WRequest);
    3232}; // WRequest
    33 DLISTED_MGD_IMPL_OUT(WRequest)
     33P9_EMBEDDED(WRequest, dlink(WRequest))
    3434
    3535void ?{}( WRequest & req ) with(req) { action = 0; }
  • libcfa/src/fstream.cfa

    r5407cdc r8d66610  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 22:08:57 2021
    13 // Update Count     : 442
     12// Last Modified On : Wed Apr 28 20:37:53 2021
     13// Update Count     : 445
    1414//
    1515
     
    114114} // fail
    115115
     116void clear( ofstream & os ) {
     117        clearerr( (FILE *)(os.file$) );
     118} // clear
     119
    116120int flush( ofstream & os ) {
    117121        return fflush( (FILE *)(os.file$) );
     
    207211} // nl
    208212
     213
    209214// *********************************** ifstream ***********************************
    210215
     
    240245} // fail
    241246
     247void clear( ifstream & is ) {
     248        clearerr( (FILE *)(is.file$) );
     249} // clear
     250
    242251void ends( ifstream & is ) {
    243252        if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
    244253} // ends
    245254
    246 int eof( ifstream & is ) {
     255bool eof( ifstream & is ) {
    247256        return feof( (FILE *)(is.file$) );
    248257} // eof
     
    273282} // close
    274283
    275 ifstream & read( ifstream & is, char * data, size_t size ) {
     284ifstream & read( ifstream & is, char data[], size_t size ) {
    276285        if ( fail( is ) ) {
    277286                abort | IO_MSG "attempt read I/O on failed stream";
  • libcfa/src/fstream.hfa

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

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

    r5407cdc r8d66610  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 18:01:03 2021
    13 // Update Count     : 1330
     12// Last Modified On : Sat May 15 09:39:21 2021
     13// Update Count     : 1342
    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 ); */ \
    661662                        if ( ! f.flags.left && f.wd > 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); \
     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; \
    664665                                if ( f.wd < 1 ) f.wd = 1; \
    665666                        } /* if */ \
     
    708709                if ( ! f.flags.pc ) {                                                   /* no precision */ \
    709710                        fmtstr[sizeof(DFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    710                         /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
     711                        /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star] ); */ \
    711712                        PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
    712713                } else {                                                                                /* precision */ \
  • libcfa/src/iostream.hfa

    r5407cdc r8d66610  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 17:59:21 2021
    13 // Update Count     : 398
     12// Last Modified On : Wed Apr 28 20:37:56 2021
     13// Update Count     : 401
    1414//
    1515
     
    5252       
    5353trait ostream( ostype & | basic_ostream( ostype ) ) {
     54        bool fail( ostype & );                                                          // operation failed?
     55        void clear( ostype & );
    5456        int flush( ostype & );
    55         bool fail( ostype & );                                                          // operation failed?
    5657        void open( ostype &, const char name[], const char mode[] );
    5758        void close( ostype & );
     
    302303        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    303304        istype & ungetc( istype &, char );
    304         int eof( istype & );
     305        bool eof( istype & );
    305306}; // basic_istream
    306307
    307308trait istream( istype & | basic_istream( istype ) ) {
    308309        bool fail( istype & );
     310        void clear( istype & );
    309311        void open( istype & is, const char name[] );
    310312        void close( istype & is );
    311         istype & read( istype &, char *, size_t );
     313        istype & read( istype &, char [], size_t );
    312314        void acquire( istype & );                                                       // concurrent access
    313315}; // istream
  • libcfa/src/virtual.c

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

    r5407cdc r8d66610  
    1010// Created On       : Tus Jul 11 15:08:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul 26 14:18:00 2017
    13 // Update Count     : 1
     12// Last Modified On : Mon May 17 11:03:00 2021
     13// Update Count     : 2
    1414//
    1515
     
    2020#endif
    2121
    22 // All strict/explicate vtables should have this head, showing their parent.
    23 struct __cfa__parent_vtable {
    24     struct __cfa__parent_vtable const * const parent;
     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.
     25struct __cfavir_type_info {
     26        // Type id of parent type, null if this is a root type.
     27    struct __cfavir_type_info const * const parent;
    2528};
    2629
    27 // Takes in two non-null pointers to type_objects.
    28 int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
    29                 struct __cfa__parent_vtable const * child );
     30// A pointer to type information acts as the type id.
     31typedef struct __cfavir_type_info const * __cfavir_type_id;
     32
     33// Takes in two non-null type ids.
     34int __cfavir_is_parent(
     35                __cfavir_type_id parent, __cfavir_type_id child );
    3036
    3137// If parent is a parent of child then return child, otherwise return NULL.
    3238// Input pointers are none-null, child's first level should be an object with
    3339// a vtable
    34 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
    35                 struct __cfa__parent_vtable const * const * child );
     40void * __cfavir_virtual_cast(
     41                __cfavir_type_id parent, __cfavir_type_id const * child );
    3642
    3743#ifdef __cforall
  • src/CodeGen/module.mk

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

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

    r5407cdc r8d66610  
    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
    15271538                                        delete objectDecl->get_init();
    15281539                                        objectDecl->set_init( new SingleInit( new VariableExpr( newBuf ) ) );
  • src/InitTweak/InitTweak.cc

    r5407cdc r8d66610  
    12161216
    12171217        void addDataSectonAttribute( ObjectDecl * objDecl ) {
    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));
     1218                objDecl->attributes.push_back(new Attribute("section", {
     1219                        new ConstantExpr( Constant::from_string(".data#") ),
     1220                }));
    12241221        }
    12251222
    12261223        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
    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)}));
     1224                objDecl->attributes.push_back(new ast::Attribute("section", {
     1225                        ast::ConstantExpr::from_string(objDecl->location, ".data#"),
     1226                }));
    12291227        }
    12301228
  • src/Parser/DeclarationNode.cc

    r5407cdc r8d66610  
    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::ALtype };
     1078                static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::Dtype };
    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.initializer ? variable.initializer->buildType() : nullptr );
     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 );
    10821082                buildList( variable.assertions, ret->get_assertions() );
    10831083                return ret;
  • src/Virtual/ExpandCasts.cc

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

    r5407cdc r8d66610  
    172172}
    173173
    174 Attribute * 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 
    181174ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    182175        assert( typeIdType );
     
    193186                        new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    194187                        ) } ),
    195                 { linkonce( typeid_name ) },
     188                { new Attribute( "cfa_linkonce", {} ) },
    196189                noFuncSpecifiers
    197190        );
  • src/main.cc

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

    r5407cdc r8d66610  
    6767.PHONY: list .validate
    6868.INTERMEDIATE: .validate .validate.cfa
    69 EXTRA_PROGRAMS = avl_test .dummy_hack # build but do not install
     69EXTRA_PROGRAMS = avl_test linkonce .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
     96linkonce_SOURCES = link-once/main.cfa link-once/partner.cfa
    9697# automake doesn't know we still need C/CPP rules so pretend like we have a C program
    9798nodist__dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
  • tests/array-container/.expect/array-basic.txt

    r5407cdc r8d66610  
    11expect Ws             = 7.060606
    22result Ws [][][][] lo = 7.060606
     3result Ws [,,,]    lo = 7.060606
    34result Ws [][][][] hi = 7.060606
     5result Ws [,,,]    hi = 7.060606
    46expect Xs             = 8.150808
    57result Xs [][][][] lo = 8.150808
     8result Xs [,,,]    lo = 8.150808
    69result Xs [][][][] hi = 8.150808
     10result Xs [,,,]    hi = 8.150808
  • tests/array-container/array-basic.cfa

    r5407cdc r8d66610  
    55//
    66
    7 forall( ztype(Nx), ztype(Ny), ztype(Nz) )
     7forall( [Nx], [Ny], [Nz] )
    88void typesTest( tag(Nx), tag(Ny), tag(Nz) ) {
    99
     
    5959}
    6060
    61 forall( ztype(Nw), ztype(Nx), ztype(Ny), ztype(Nz) )
     61forall( [Nw], [Nx], [Ny], [Nz] )
    6262void fillHelloData( array( float, Nw, Nx, Ny, Nz ) & wxyz ) {
    6363    for (w; z(Nw))
     
    6868}
    6969
    70 forall( ztype(Zn)
     70forall( [Zn]
    7171      , S & | sized(S)
    7272      )
     
    8686}
    8787
    88 forall( ztype(Nw), ztype(Nx), ztype(Ny), ztype(Nz) )
     88forall( [Nw], [Nx], [Ny], [Nz] )
    8989void runtimeTest( tag(Nw), tag(Nx), tag(Ny), tag(Nz) ) {
    9090
     
    105105    printf("result Ws [][][][] lo = %f\n", result);
    106106
    107     // fixme: -[[-,-,-,-]] not working
    108     // result = total1d_low( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
    109     // printf("result Ws [,,,]    lo = %f\n", result);
     107    result = total1d_low( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
     108    printf("result Ws [,,,]    lo = %f\n", result);
    110109
    111110    result = total1d_hi( wxyz[all][slice_ix][slice_ix][slice_ix] );
    112111    printf("result Ws [][][][] hi = %f\n", result);
    113112
    114     // fixme: -[[-,-,-,-]] not working
    115     // result = total1d_hi( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
    116     // printf("result Ws [,,,]    hi = %f\n", result);
     113    result = total1d_hi( wxyz[[all, slice_ix, slice_ix, slice_ix]] );
     114    printf("result Ws [,,,]    hi = %f\n", result);
    117115
    118116    // summing across X, with w=y=z=1
     
    126124    printf("result Xs [][][][] lo = %f\n", result);
    127125
    128     // fixme: -[[-,-,-,-]] not working
    129     // result = total1d_low( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
    130     // printf("result Xs [,,,]    lo = %f\n", result);
     126    result = total1d_low( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
     127    printf("result Xs [,,,]    lo = %f\n", result);
    131128
    132129    result = total1d_hi( wxyz[slice_ix][all][slice_ix][slice_ix] );   
    133130    printf("result Xs [][][][] hi = %f\n", result);
    134131
    135     // fixme: -[[-,-,-,-]] not working
    136     // result = total1d_hi( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
    137     // printf("result Xs [,,,]    hi = %f\n", result);
     132    result = total1d_hi( wxyz[[slice_ix, all, slice_ix, slice_ix]] );
     133    printf("result Xs [,,,]    hi = %f\n", result);
    138134
    139135}
  • tests/concurrent/clib_tls.c

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

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

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

    r5407cdc r8d66610  
    1 ~~~~~~~~~~~~~~~~~ Headless List Tests - insert_after ~~~~~~~~~~~~~~~~
    2 
    3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    4 Test 1-i:  Modifying Freds on MINE
    5 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    6 ==== fred by MINE before
    7 3.14
    8 -
    9 3.14
    10 -
    11 0.5
    12 -
    13 0.5
    14 -
    15 ==== fred by YOURS before
    16 3.14
    17 -
    18 3.14
    19 -
    20 0.5
    21 -
    22 0.5
    23 -
    24 ==== fred by MINE after
    25 3.14
    26 0.5
    27 -
    28 3.14
    29 -
    30 0.5
    31 -
    32 0.5
    33 3.14
    34 -
    35 ==== fred by YOURS after
    36 3.14
    37 -
    38 3.14
    39 -
    40 0.5
    41 -
    42 0.5
    43 -
    44 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    45 Test 2-i.  Modifying Freds on YOURS
    46 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    47 ==== fred by MINE before
    48 3.14
    49 -
    50 3.14
    51 -
    52 0.5
    53 -
    54 0.5
    55 -
    56 ==== fred by YOURS before
    57 3.14
    58 -
    59 3.14
    60 -
    61 0.5
    62 -
    63 0.5
    64 -
    65 ==== fred by MINE after
    66 3.14
    67 -
    68 3.14
    69 -
    70 0.5
    71 -
    72 0.5
    73 -
    74 ==== fred by YOURS after
    75 3.14
    76 0.5
    77 -
    78 3.14
    79 -
    80 0.5
    81 -
    82 0.5
    83 3.14
    84 -
    85 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    86 Test 3-i.  Modifying Maries
    87 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    88 ==== mary before
    89 3.14
    90 -
    91 3.14
    92 -
    93 0.5
    94 -
    95 0.5
    96 -
    97 ==== mary after
    98 3.14
    99 0.5
    100 -
    101 3.14
    102 -
    103 0.5
    104 -
    105 0.5
    106 3.14
    107 -
    108 
    109 ~~~~~~~~~~~~~~~~ Headless List Tests - insert_before ~~~~~~~~~~~~~~~~
    110 
    111 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    112 Test 1-ii:  Modifying Freds on MINE
    113 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    114 ==== fred by MINE before
    115 3.14
    116 -
    117 3.14
    118 -
    119 0.5
    120 -
    121 0.5
    122 -
    123 ==== fred by YOURS before
    124 3.14
    125 -
    126 3.14
    127 -
    128 0.5
    129 -
    130 0.5
    131 -
    132 ==== fred by MINE after
    133 3.14
    134 0.5
    135 -
    136 3.14
    137 -
    138 0.5
    139 -
    140 0.5
    141 3.14
    142 -
    143 ==== fred by YOURS after
    144 3.14
    145 -
    146 3.14
    147 -
    148 0.5
    149 -
    150 0.5
    151 -
    152 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    153 Test 2-ii.  Modifying Freds on YOURS
    154 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    155 ==== fred by MINE before
    156 3.14
    157 -
    158 3.14
    159 -
    160 0.5
    161 -
    162 0.5
    163 -
    164 ==== fred by YOURS before
    165 3.14
    166 -
    167 3.14
    168 -
    169 0.5
    170 -
    171 0.5
    172 -
    173 ==== fred by MINE after
    174 3.14
    175 -
    176 3.14
    177 -
    178 0.5
    179 -
    180 0.5
    181 -
    182 ==== fred by YOURS after
    183 3.14
    184 0.5
    185 -
    186 3.14
    187 -
    188 0.5
    189 -
    190 0.5
    191 3.14
    192 -
    193 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    194 Test 3-ii.  Modifying Maries
    195 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    196 ==== mary before
    197 3.14
    198 -
    199 3.14
    200 -
    201 0.5
    202 -
    203 0.5
    204 -
    205 ==== mary after
    206 3.14
    207 0.5
    208 -
    209 3.14
    210 -
    211 0.5
    212 -
    213 0.5
    214 3.14
    215 -
    2161
    2172~~~~~~~~~~~~~~~~~ Headed List Tests - insert_first ~~~~~~~~~~~~~~~~~~
     
    557342-
    558343
    559 ~~~~~~~~~~ Element removal tests on Headless List: mid ~~~~~~~~~~
    560 
    561 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    562 Test 10-i.  Modifying Freds on MINE
    563 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    564 ==== fred by MINE before
    565 1.7
    566 2.7
    567 3.7
    568 -
    569 1.7
    570 -
    571 3.7
    572 -
    573 3.7
    574 2.7
    575 1.7
    576 -
    577 ==== fred by YOURS before
    578 1.7
    579 2.7
    580 3.7
    581 -
    582 1.7
    583 -
    584 3.7
    585 -
    586 3.7
    587 2.7
    588 1.7
    589 -
    590 ==== fred by MINE after
    591 1.7
    592 3.7
    593 -
    594 1.7
    595 -
    596 3.7
    597 -
    598 3.7
    599 1.7
    600 -
    601 ==== fred by YOURS after
    602 1.7
    603 2.7
    604 3.7
    605 -
    606 1.7
    607 -
    608 3.7
    609 -
    610 3.7
    611 2.7
    612 1.7
    613 -
    614 ==== fred by MINE after
    615 2.7
    616 -
    617 2.7
    618 -
    619 -
    620 -
    621 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    622 Test 11-i.  Modifying Freds on YOURS
    623 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    624 ==== fred by MINE before
    625 1.7
    626 2.7
    627 3.7
    628 -
    629 1.7
    630 -
    631 3.7
    632 -
    633 3.7
    634 2.7
    635 1.7
    636 -
    637 ==== fred by YOURS before
    638 1.7
    639 2.7
    640 3.7
    641 -
    642 1.7
    643 -
    644 3.7
    645 -
    646 3.7
    647 2.7
    648 1.7
    649 -
    650 ==== fred by MINE after
    651 1.7
    652 2.7
    653 3.7
    654 -
    655 1.7
    656 -
    657 3.7
    658 -
    659 3.7
    660 2.7
    661 1.7
    662 -
    663 ==== fred by YOURS after
    664 1.7
    665 3.7
    666 -
    667 1.7
    668 -
    669 3.7
    670 -
    671 3.7
    672 1.7
    673 -
    674 ==== fred by YOURS after
    675 2.7
    676 -
    677 2.7
    678 -
    679 -
    680 -
    681 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    682 Test 12-i.  Modifying Maries
    683 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     344~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~
     345
     346~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     347Test 13-i.  Modifying Freds on MINE
     348~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     349==== fred by MINE before
     3501.7
     3512.7
     3523.7
     353-
     3541.7
     355-
     3563.7
     357-
     3583.7
     3592.7
     3601.7
     361-
     362==== fred by YOURS before
     3631.7
     3642.7
     3653.7
     366-
     3671.7
     368-
     3693.7
     370-
     3713.7
     3722.7
     3731.7
     374-
     375==== fred by MINE after
     3762.7
     3773.7
     378-
     3792.7
     380-
     3813.7
     382-
     3833.7
     3842.7
     385-
     386==== fred by YOURS after
     3871.7
     3882.7
     3893.7
     390-
     3911.7
     392-
     3933.7
     394-
     3953.7
     3962.7
     3971.7
     398-
     399==== fred by MINE after
     4001.7
     401-
     4021.7
     403-
     404-
     405-
     406~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     407Test 14-i.  Modifying Freds on YOURS
     408~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     409==== fred by MINE before
     4101.7
     4112.7
     4123.7
     413-
     4141.7
     415-
     4163.7
     417-
     4183.7
     4192.7
     4201.7
     421-
     422==== fred by YOURS before
     4231.7
     4242.7
     4253.7
     426-
     4271.7
     428-
     4293.7
     430-
     4313.7
     4322.7
     4331.7
     434-
     435==== fred by MINE after
     4361.7
     4372.7
     4383.7
     439-
     4401.7
     441-
     4423.7
     443-
     4443.7
     4452.7
     4461.7
     447-
     448==== fred by YOURS after
     4492.7
     4503.7
     451-
     4522.7
     453-
     4543.7
     455-
     4563.7
     4572.7
     458-
     459==== fred by YOURS after
     4601.7
     461-
     4621.7
     463-
     464-
     465-
     466~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     467Test 15-i.  Modifying Maries
     468~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    684469==== mary before
    6854701.7
     
    696481-
    697482==== mary after
    698 1.7
    699 3.7
    700 -
    701 1.7
    702 -
    703 3.7
    704 -
    705 3.7
    706 1.7
    707 -
    708 ==== mary after
    709 2.7
    710 -
    711 2.7
    712 -
    713 -
    714 -
    715 
    716 ~~~~~~~~~~ Element removal tests on Headless List: at first ~~~~~~~~~~
    717 
    718 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    719 Test 10-ii.  Modifying Freds on MINE
    720 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    721 ==== fred by MINE before
    722 1.7
    723 2.7
    724 3.7
    725 -
    726 1.7
    727 -
    728 3.7
    729 -
    730 3.7
    731 2.7
    732 1.7
    733 -
    734 ==== fred by YOURS before
    735 1.7
    736 2.7
    737 3.7
    738 -
    739 1.7
    740 -
    741 3.7
    742 -
    743 3.7
    744 2.7
    745 1.7
    746 -
    747 ==== fred by MINE after
    748 2.7
    749 3.7
    750 -
    751 2.7
    752 -
    753 3.7
    754 -
    755 3.7
    756 2.7
    757 -
    758 ==== fred by YOURS after
    759 1.7
    760 2.7
    761 3.7
    762 -
    763 1.7
    764 -
    765 3.7
    766 -
    767 3.7
    768 2.7
    769 1.7
    770 -
    771 ==== fred by MINE after
    772 1.7
    773 -
    774 1.7
    775 -
    776 -
    777 -
    778 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    779 Test 11-ii.  Modifying Freds on YOURS
    780 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    781 ==== fred by MINE before
    782 1.7
    783 2.7
    784 3.7
    785 -
    786 1.7
    787 -
    788 3.7
    789 -
    790 3.7
    791 2.7
    792 1.7
    793 -
    794 ==== fred by YOURS before
    795 1.7
    796 2.7
    797 3.7
    798 -
    799 1.7
    800 -
    801 3.7
    802 -
    803 3.7
    804 2.7
    805 1.7
    806 -
    807 ==== fred by MINE after
    808 1.7
    809 2.7
    810 3.7
    811 -
    812 1.7
    813 -
    814 3.7
    815 -
    816 3.7
    817 2.7
    818 1.7
    819 -
    820 ==== fred by YOURS after
    821 2.7
    822 3.7
    823 -
    824 2.7
    825 -
    826 3.7
    827 -
    828 3.7
    829 2.7
    830 -
    831 ==== fred by YOURS after
    832 1.7
    833 -
    834 1.7
    835 -
    836 -
    837 -
    838 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    839 Test 12-ii.  Modifying Maries
    840 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     4832.7
     4843.7
     485-
     4862.7
     487-
     4883.7
     489-
     4903.7
     4912.7
     492-
     493==== mary after
     4941.7
     495-
     4961.7
     497-
     498-
     499-
     500
     501~~~~~~~~~~ Element removal tests on Headed List: at last ~~~~~~~~~~
     502
     503~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     504Test 13-ii.  Modifying Freds on MINE
     505~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     506==== fred by MINE before
     5071.7
     5082.7
     5093.7
     510-
     5111.7
     512-
     5133.7
     514-
     5153.7
     5162.7
     5171.7
     518-
     519==== fred by YOURS before
     5201.7
     5212.7
     5223.7
     523-
     5241.7
     525-
     5263.7
     527-
     5283.7
     5292.7
     5301.7
     531-
     532==== fred by MINE after
     5331.7
     5342.7
     535-
     5361.7
     537-
     5382.7
     539-
     5402.7
     5411.7
     542-
     543==== fred by YOURS after
     5441.7
     5452.7
     5463.7
     547-
     5481.7
     549-
     5503.7
     551-
     5523.7
     5532.7
     5541.7
     555-
     556==== fred by MINE after
     5573.7
     558-
     5593.7
     560-
     561-
     562-
     563~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     564Test 14-ii.  Modifying Freds on YOURS
     565~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     566==== fred by MINE before
     5671.7
     5682.7
     5693.7
     570-
     5711.7
     572-
     5733.7
     574-
     5753.7
     5762.7
     5771.7
     578-
     579==== fred by YOURS before
     5801.7
     5812.7
     5823.7
     583-
     5841.7
     585-
     5863.7
     587-
     5883.7
     5892.7
     5901.7
     591-
     592==== fred by MINE after
     5931.7
     5942.7
     5953.7
     596-
     5971.7
     598-
     5993.7
     600-
     6013.7
     6022.7
     6031.7
     604-
     605==== fred by YOURS after
     6061.7
     6072.7
     608-
     6091.7
     610-
     6112.7
     612-
     6132.7
     6141.7
     615-
     616==== fred by YOURS after
     6173.7
     618-
     6193.7
     620-
     621-
     622-
     623~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     624Test 15-ii.  Modifying Maries
     625~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    841626==== mary before
    8426271.7
     
    853638-
    854639==== mary after
    855 2.7
    856 3.7
    857 -
    858 2.7
    859 -
    860 3.7
    861 -
    862 3.7
    863 2.7
    864 -
    865 ==== mary after
    866 1.7
    867 -
    868 1.7
    869 -
    870 -
    871 -
    872 
    873 ~~~~~~~~~~ Element removal tests on Headless List: at last ~~~~~~~~~~
    874 
    875 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    876 Test 10-iii.  Modifying Freds on MINE
    877 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    878 ==== fred by MINE before
    879 1.7
    880 2.7
    881 3.7
    882 -
    883 1.7
    884 -
    885 3.7
    886 -
    887 3.7
    888 2.7
    889 1.7
    890 -
    891 ==== fred by YOURS before
    892 1.7
    893 2.7
    894 3.7
    895 -
    896 1.7
    897 -
    898 3.7
    899 -
    900 3.7
    901 2.7
    902 1.7
    903 -
    904 ==== fred by MINE after
    905 1.7
    906 2.7
    907 -
    908 1.7
    909 -
    910 2.7
    911 -
    912 2.7
    913 1.7
    914 -
    915 ==== fred by YOURS after
    916 1.7
    917 2.7
    918 3.7
    919 -
    920 1.7
    921 -
    922 3.7
    923 -
    924 3.7
    925 2.7
    926 1.7
    927 -
    928 ==== fred by MINE after
    929 3.7
    930 -
    931 3.7
    932 -
    933 -
    934 -
    935 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    936 Test 11-iii.  Modifying Freds on YOURS
    937 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    938 ==== fred by MINE before
    939 1.7
    940 2.7
    941 3.7
    942 -
    943 1.7
    944 -
    945 3.7
    946 -
    947 3.7
    948 2.7
    949 1.7
    950 -
    951 ==== fred by YOURS before
    952 1.7
    953 2.7
    954 3.7
    955 -
    956 1.7
    957 -
    958 3.7
    959 -
    960 3.7
    961 2.7
    962 1.7
    963 -
    964 ==== fred by MINE after
    965 1.7
    966 2.7
    967 3.7
    968 -
    969 1.7
    970 -
    971 3.7
    972 -
    973 3.7
    974 2.7
    975 1.7
    976 -
    977 ==== fred by YOURS after
    978 1.7
    979 2.7
    980 -
    981 1.7
    982 -
    983 2.7
    984 -
    985 2.7
    986 1.7
    987 -
    988 ==== fred by YOURS after
    989 3.7
    990 -
    991 3.7
    992 -
    993 -
    994 -
    995 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    996 Test 12-iii.  Modifying Maries
    997 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     6401.7
     6412.7
     642-
     6431.7
     644-
     6452.7
     646-
     6472.7
     6481.7
     649-
     650==== mary after
     6513.7
     652-
     6533.7
     654-
     655-
     656-
     657
     658~~~~~~~~~~ Element removal tests on Headed List: of sole ~~~~~~~~~~
     659
     660~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     661Test 13-iii.  Modifying Freds on MINE
     662~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     663==== fred by MINE before
     6640.7
     665-
     6660.7
     667-
     6680.7
     669-
     6700.7
     671-
     672==== fred by YOURS before
     6730.7
     674-
     6750.7
     676-
     6770.7
     678-
     6790.7
     680-
     681==== fred by YOURS after
     6820.7
     683-
     6840.7
     685-
     6860.7
     687-
     6880.7
     689-
     690==== fred by MINE after
     6910.7
     692-
     6930.7
     694-
     695-
     696-
     697==== fred by MINE after
     6980.7
     699-
     7000.7
     701-
     7020.7
     703-
     7040.7
     705-
     706~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     707Test 14-iii.  Modifying Freds on YOURS
     708~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     709==== fred by MINE before
     7100.7
     711-
     7120.7
     713-
     7140.7
     715-
     7160.7
     717-
     718==== fred by YOURS before
     7190.7
     720-
     7210.7
     722-
     7230.7
     724-
     7250.7
     726-
     727==== fred by YOURS after
     7280.7
     729-
     7300.7
     731-
     7320.7
     733-
     7340.7
     735-
     736==== fred by YOURS after
     7370.7
     738-
     7390.7
     740-
     741-
     742-
     743==== fred by YOURS after
     7440.7
     745-
     7460.7
     747-
     7480.7
     749-
     7500.7
     751-
     752~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     753Test 15-iii.  Modifying Maries
     754~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    998755==== mary before
    999 1.7
    1000 2.7
    1001 3.7
    1002 -
    1003 1.7
    1004 -
    1005 3.7
    1006 -
    1007 3.7
    1008 2.7
    1009 1.7
    1010 -
    1011 ==== mary after
    1012 1.7
    1013 2.7
    1014 -
    1015 1.7
    1016 -
    1017 2.7
    1018 -
    1019 2.7
    1020 1.7
    1021 -
    1022 ==== mary after
    1023 3.7
    1024 -
    1025 3.7
    1026 -
    1027 -
    1028 -
    1029 
    1030 ~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~
    1031 
    1032 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1033 Test 13-i.  Modifying Freds on MINE
    1034 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1035 ==== fred by MINE before
    1036 1.7
    1037 2.7
    1038 3.7
    1039 -
    1040 1.7
    1041 -
    1042 3.7
    1043 -
    1044 3.7
    1045 2.7
    1046 1.7
    1047 -
    1048 ==== fred by YOURS before
    1049 1.7
    1050 2.7
    1051 3.7
    1052 -
    1053 1.7
    1054 -
    1055 3.7
    1056 -
    1057 3.7
    1058 2.7
    1059 1.7
    1060 -
    1061 ==== fred by MINE after
    1062 2.7
    1063 3.7
    1064 -
    1065 2.7
    1066 -
    1067 3.7
    1068 -
    1069 3.7
    1070 2.7
    1071 -
    1072 ==== fred by YOURS after
    1073 1.7
    1074 2.7
    1075 3.7
    1076 -
    1077 1.7
    1078 -
    1079 3.7
    1080 -
    1081 3.7
    1082 2.7
    1083 1.7
    1084 -
    1085 ==== fred by MINE after
    1086 1.7
    1087 -
    1088 1.7
    1089 -
    1090 -
    1091 -
    1092 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1093 Test 14-i.  Modifying Freds on YOURS
    1094 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1095 ==== fred by MINE before
    1096 1.7
    1097 2.7
    1098 3.7
    1099 -
    1100 1.7
    1101 -
    1102 3.7
    1103 -
    1104 3.7
    1105 2.7
    1106 1.7
    1107 -
    1108 ==== fred by YOURS before
    1109 1.7
    1110 2.7
    1111 3.7
    1112 -
    1113 1.7
    1114 -
    1115 3.7
    1116 -
    1117 3.7
    1118 2.7
    1119 1.7
    1120 -
    1121 ==== fred by MINE after
    1122 1.7
    1123 2.7
    1124 3.7
    1125 -
    1126 1.7
    1127 -
    1128 3.7
    1129 -
    1130 3.7
    1131 2.7
    1132 1.7
    1133 -
    1134 ==== fred by YOURS after
    1135 2.7
    1136 3.7
    1137 -
    1138 2.7
    1139 -
    1140 3.7
    1141 -
    1142 3.7
    1143 2.7
    1144 -
    1145 ==== fred by YOURS after
    1146 1.7
    1147 -
    1148 1.7
    1149 -
    1150 -
    1151 -
    1152 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1153 Test 15-i.  Modifying Maries
     7560.7
     757-
     7580.7
     759-
     7600.7
     761-
     7620.7
     763-
     764==== mary after
     7650.7
     766-
     7670.7
     768-
     769-
     770-
     771==== mary after
     7720.7
     773-
     7740.7
     775-
     7760.7
     777-
     7780.7
     779-
     780
     781~~~~~~~~~~ End removal tests on Headed List: First ~~~~~~~~~~
     782
     783~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     784Test 16-i.  Modifying Freds on MINE
     785~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     786==== fred by MINE before
     7871.7
     7882.7
     7893.7
     790-
     7911.7
     792-
     7933.7
     794-
     7953.7
     7962.7
     7971.7
     798-
     799==== fred by YOURS before
     8001.7
     8012.7
     8023.7
     803-
     8041.7
     805-
     8063.7
     807-
     8083.7
     8092.7
     8101.7
     811-
     812==== fred by MINE after
     8132.7
     8143.7
     815-
     8162.7
     817-
     8183.7
     819-
     8203.7
     8212.7
     822-
     823==== fred by YOURS after
     8241.7
     8252.7
     8263.7
     827-
     8281.7
     829-
     8303.7
     831-
     8323.7
     8332.7
     8341.7
     835-
     836==== fred by MINE after
     8371.7
     838-
     8391.7
     840-
     841-
     842-
     843~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     844Test 16-ii.  Modifying Freds on YOURS
     845~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     846==== fred by MINE before
     8471.7
     8482.7
     8493.7
     850-
     8511.7
     852-
     8533.7
     854-
     8553.7
     8562.7
     8571.7
     858-
     859==== fred by YOURS before
     8601.7
     8612.7
     8623.7
     863-
     8641.7
     865-
     8663.7
     867-
     8683.7
     8692.7
     8701.7
     871-
     872==== fred by MINE after
     8731.7
     8742.7
     8753.7
     876-
     8771.7
     878-
     8793.7
     880-
     8813.7
     8822.7
     8831.7
     884-
     885==== fred by YOURS after
     8862.7
     8873.7
     888-
     8892.7
     890-
     8913.7
     892-
     8933.7
     8942.7
     895-
     896==== fred by YOURS after
     8971.7
     898-
     8991.7
     900-
     901-
     902-
     903~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     904Test 16-iii.  Modifying Maries
    1154905~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1155906==== mary before
     
    1185936-
    1186937
    1187 ~~~~~~~~~~ Element removal tests on Headed List: at last ~~~~~~~~~~
    1188 
    1189 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1190 Test 13-ii.  Modifying Freds on MINE
    1191 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1192 ==== fred by MINE before
    1193 1.7
    1194 2.7
    1195 3.7
    1196 -
    1197 1.7
    1198 -
    1199 3.7
    1200 -
    1201 3.7
    1202 2.7
    1203 1.7
    1204 -
    1205 ==== fred by YOURS before
    1206 1.7
    1207 2.7
    1208 3.7
    1209 -
    1210 1.7
    1211 -
    1212 3.7
    1213 -
    1214 3.7
    1215 2.7
    1216 1.7
    1217 -
    1218 ==== fred by MINE after
    1219 1.7
    1220 2.7
    1221 -
    1222 1.7
    1223 -
    1224 2.7
    1225 -
    1226 2.7
    1227 1.7
    1228 -
    1229 ==== fred by YOURS after
    1230 1.7
    1231 2.7
    1232 3.7
    1233 -
    1234 1.7
    1235 -
    1236 3.7
    1237 -
    1238 3.7
    1239 2.7
    1240 1.7
    1241 -
    1242 ==== fred by MINE after
    1243 3.7
    1244 -
    1245 3.7
    1246 -
    1247 -
    1248 -
    1249 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1250 Test 14-ii.  Modifying Freds on YOURS
    1251 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1252 ==== fred by MINE before
    1253 1.7
    1254 2.7
    1255 3.7
    1256 -
    1257 1.7
    1258 -
    1259 3.7
    1260 -
    1261 3.7
    1262 2.7
    1263 1.7
    1264 -
    1265 ==== fred by YOURS before
    1266 1.7
    1267 2.7
    1268 3.7
    1269 -
    1270 1.7
    1271 -
    1272 3.7
    1273 -
    1274 3.7
    1275 2.7
    1276 1.7
    1277 -
    1278 ==== fred by MINE after
    1279 1.7
    1280 2.7
    1281 3.7
    1282 -
    1283 1.7
    1284 -
    1285 3.7
    1286 -
    1287 3.7
    1288 2.7
    1289 1.7
    1290 -
    1291 ==== fred by YOURS after
    1292 1.7
    1293 2.7
    1294 -
    1295 1.7
    1296 -
    1297 2.7
    1298 -
    1299 2.7
    1300 1.7
    1301 -
    1302 ==== fred by YOURS after
    1303 3.7
    1304 -
    1305 3.7
    1306 -
    1307 -
    1308 -
    1309 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1310 Test 15-ii.  Modifying Maries
     938~~~~~~~~~~ End removal tests on Headed List: Last ~~~~~~~~~~
     939
     940~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     941Test 17-i.  Modifying Freds on MINE
     942~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     943==== fred by MINE before
     9441.7
     9452.7
     9463.7
     947-
     9481.7
     949-
     9503.7
     951-
     9523.7
     9532.7
     9541.7
     955-
     956==== fred by YOURS before
     9571.7
     9582.7
     9593.7
     960-
     9611.7
     962-
     9633.7
     964-
     9653.7
     9662.7
     9671.7
     968-
     969==== fred by MINE after
     9701.7
     9712.7
     972-
     9731.7
     974-
     9752.7
     976-
     9772.7
     9781.7
     979-
     980==== fred by YOURS after
     9811.7
     9822.7
     9833.7
     984-
     9851.7
     986-
     9873.7
     988-
     9893.7
     9902.7
     9911.7
     992-
     993==== fred by MINE after
     9943.7
     995-
     9963.7
     997-
     998-
     999-
     1000~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1001Test 17-ii.  Modifying Freds on YOURS
     1002~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1003==== fred by MINE before
     10041.7
     10052.7
     10063.7
     1007-
     10081.7
     1009-
     10103.7
     1011-
     10123.7
     10132.7
     10141.7
     1015-
     1016==== fred by YOURS before
     10171.7
     10182.7
     10193.7
     1020-
     10211.7
     1022-
     10233.7
     1024-
     10253.7
     10262.7
     10271.7
     1028-
     1029==== fred by MINE after
     10301.7
     10312.7
     10323.7
     1033-
     10341.7
     1035-
     10363.7
     1037-
     10383.7
     10392.7
     10401.7
     1041-
     1042==== fred by YOURS after
     10431.7
     10442.7
     1045-
     10461.7
     1047-
     10482.7
     1049-
     10502.7
     10511.7
     1052-
     1053==== fred by YOURS after
     10543.7
     1055-
     10563.7
     1057-
     1058-
     1059-
     1060~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1061Test 17-iii.  Modifying Maries
    13111062~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    13121063==== mary before
     
    13421093-
    13431094
    1344 ~~~~~~~~~~ Element removal tests on Headed List: of sole ~~~~~~~~~~
    1345 
    1346 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1347 Test 13-iii.  Modifying Freds on MINE
    1348 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1349 ==== fred by MINE before
    1350 0.7
    1351 -
    1352 0.7
    1353 -
    1354 0.7
    1355 -
    1356 0.7
    1357 -
    1358 ==== fred by YOURS before
    1359 0.7
    1360 -
    1361 0.7
    1362 -
    1363 0.7
    1364 -
    1365 0.7
    1366 -
    1367 ==== fred by YOURS after
    1368 0.7
    1369 -
    1370 0.7
    1371 -
    1372 0.7
    1373 -
    1374 0.7
    1375 -
    1376 ==== fred by MINE after
    1377 0.7
    1378 -
    1379 0.7
    1380 -
    1381 -
    1382 -
    1383 ==== fred by MINE after
    1384 0.7
    1385 -
    1386 0.7
    1387 -
    1388 0.7
    1389 -
    1390 0.7
    1391 -
    1392 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1393 Test 14-iii.  Modifying Freds on YOURS
    1394 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1395 ==== fred by MINE before
    1396 0.7
    1397 -
    1398 0.7
    1399 -
    1400 0.7
    1401 -
    1402 0.7
    1403 -
    1404 ==== fred by YOURS before
    1405 0.7
    1406 -
    1407 0.7
    1408 -
    1409 0.7
    1410 -
    1411 0.7
    1412 -
    1413 ==== fred by YOURS after
    1414 0.7
    1415 -
    1416 0.7
    1417 -
    1418 0.7
    1419 -
    1420 0.7
    1421 -
    1422 ==== fred by YOURS after
    1423 0.7
    1424 -
    1425 0.7
    1426 -
    1427 -
    1428 -
    1429 ==== fred by YOURS after
    1430 0.7
    1431 -
    1432 0.7
    1433 -
    1434 0.7
    1435 -
    1436 0.7
    1437 -
    1438 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1439 Test 15-iii.  Modifying Maries
    1440 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1441 ==== mary before
    1442 0.7
    1443 -
    1444 0.7
    1445 -
    1446 0.7
    1447 -
    1448 0.7
    1449 -
    1450 ==== mary after
    1451 0.7
    1452 -
    1453 0.7
    1454 -
    1455 -
    1456 -
    1457 ==== mary after
    1458 0.7
    1459 -
    1460 0.7
    1461 -
    1462 0.7
    1463 -
    1464 0.7
    1465 -
    1466 
    1467 ~~~~~~~~~~ End removal tests on Headed List: First ~~~~~~~~~~
    1468 
    1469 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1470 Test 16-i.  Modifying Freds on MINE
    1471 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1472 ==== fred by MINE before
    1473 1.7
    1474 2.7
    1475 3.7
    1476 -
    1477 1.7
    1478 -
    1479 3.7
    1480 -
    1481 3.7
    1482 2.7
    1483 1.7
    1484 -
    1485 ==== fred by YOURS before
    1486 1.7
    1487 2.7
    1488 3.7
    1489 -
    1490 1.7
    1491 -
    1492 3.7
    1493 -
    1494 3.7
    1495 2.7
    1496 1.7
    1497 -
    1498 ==== fred by MINE after
    1499 2.7
    1500 3.7
    1501 -
    1502 2.7
    1503 -
    1504 3.7
    1505 -
    1506 3.7
    1507 2.7
    1508 -
    1509 ==== fred by YOURS after
    1510 1.7
    1511 2.7
    1512 3.7
    1513 -
    1514 1.7
    1515 -
    1516 3.7
    1517 -
    1518 3.7
    1519 2.7
    1520 1.7
    1521 -
    1522 ==== fred by MINE after
    1523 1.7
    1524 -
    1525 1.7
    1526 -
    1527 -
    1528 -
    1529 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1530 Test 16-ii.  Modifying Freds on YOURS
    1531 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1532 ==== fred by MINE before
    1533 1.7
    1534 2.7
    1535 3.7
    1536 -
    1537 1.7
    1538 -
    1539 3.7
    1540 -
    1541 3.7
    1542 2.7
    1543 1.7
    1544 -
    1545 ==== fred by YOURS before
    1546 1.7
    1547 2.7
    1548 3.7
    1549 -
    1550 1.7
    1551 -
    1552 3.7
    1553 -
    1554 3.7
    1555 2.7
    1556 1.7
    1557 -
    1558 ==== fred by MINE after
    1559 1.7
    1560 2.7
    1561 3.7
    1562 -
    1563 1.7
    1564 -
    1565 3.7
    1566 -
    1567 3.7
    1568 2.7
    1569 1.7
    1570 -
    1571 ==== fred by YOURS after
    1572 2.7
    1573 3.7
    1574 -
    1575 2.7
    1576 -
    1577 3.7
    1578 -
    1579 3.7
    1580 2.7
    1581 -
    1582 ==== fred by YOURS after
    1583 1.7
    1584 -
    1585 1.7
    1586 -
    1587 -
    1588 -
    1589 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1590 Test 16-iii.  Modifying Maries
    1591 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1592 ==== mary before
    1593 1.7
    1594 2.7
    1595 3.7
    1596 -
    1597 1.7
    1598 -
    1599 3.7
    1600 -
    1601 3.7
    1602 2.7
    1603 1.7
    1604 -
    1605 ==== mary after
    1606 2.7
    1607 3.7
    1608 -
    1609 2.7
    1610 -
    1611 3.7
    1612 -
    1613 3.7
    1614 2.7
    1615 -
    1616 ==== mary after
    1617 1.7
    1618 -
    1619 1.7
    1620 -
    1621 -
    1622 -
    1623 
    1624 ~~~~~~~~~~ End removal tests on Headed List: Last ~~~~~~~~~~
    1625 
    1626 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1627 Test 17-i.  Modifying Freds on MINE
    1628 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1629 ==== fred by MINE before
    1630 1.7
    1631 2.7
    1632 3.7
    1633 -
    1634 1.7
    1635 -
    1636 3.7
    1637 -
    1638 3.7
    1639 2.7
    1640 1.7
    1641 -
    1642 ==== fred by YOURS before
    1643 1.7
    1644 2.7
    1645 3.7
    1646 -
    1647 1.7
    1648 -
    1649 3.7
    1650 -
    1651 3.7
    1652 2.7
    1653 1.7
    1654 -
    1655 ==== fred by MINE after
    1656 1.7
    1657 2.7
    1658 -
    1659 1.7
    1660 -
    1661 2.7
    1662 -
    1663 2.7
    1664 1.7
    1665 -
    1666 ==== fred by YOURS after
    1667 1.7
    1668 2.7
    1669 3.7
    1670 -
    1671 1.7
    1672 -
    1673 3.7
    1674 -
    1675 3.7
    1676 2.7
    1677 1.7
    1678 -
    1679 ==== fred by MINE after
    1680 3.7
    1681 -
    1682 3.7
    1683 -
    1684 -
    1685 -
    1686 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1687 Test 17-ii.  Modifying Freds on YOURS
    1688 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1689 ==== fred by MINE before
    1690 1.7
    1691 2.7
    1692 3.7
    1693 -
    1694 1.7
    1695 -
    1696 3.7
    1697 -
    1698 3.7
    1699 2.7
    1700 1.7
    1701 -
    1702 ==== fred by YOURS before
    1703 1.7
    1704 2.7
    1705 3.7
    1706 -
    1707 1.7
    1708 -
    1709 3.7
    1710 -
    1711 3.7
    1712 2.7
    1713 1.7
    1714 -
    1715 ==== fred by MINE after
    1716 1.7
    1717 2.7
    1718 3.7
    1719 -
    1720 1.7
    1721 -
    1722 3.7
    1723 -
    1724 3.7
    1725 2.7
    1726 1.7
    1727 -
    1728 ==== fred by YOURS after
    1729 1.7
    1730 2.7
    1731 -
    1732 1.7
    1733 -
    1734 2.7
    1735 -
    1736 2.7
    1737 1.7
    1738 -
    1739 ==== fred by YOURS after
    1740 3.7
    1741 -
    1742 3.7
    1743 -
    1744 -
    1745 -
    1746 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1747 Test 17-iii.  Modifying Maries
    1748 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1749 ==== mary before
    1750 1.7
    1751 2.7
    1752 3.7
    1753 -
    1754 1.7
    1755 -
    1756 3.7
    1757 -
    1758 3.7
    1759 2.7
    1760 1.7
    1761 -
    1762 ==== mary after
    1763 1.7
    1764 2.7
    1765 -
    1766 1.7
    1767 -
    1768 2.7
    1769 -
    1770 2.7
    1771 1.7
    1772 -
    1773 ==== mary after
    1774 3.7
    1775 -
    1776 3.7
    1777 -
    1778 -
    1779 -
     1095~~~~~~~~~~~~~~~~~~~ Ease-of-access cases ~~~~~~~~~~~~~~~~~~
     1096
     1097~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1098Test 18-i.  Modifying Freds on MINE
     1099~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1100Not implmented
     1101~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1102Test 18-ii.  Modifying Freds on YOURS
     1103~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1104Not implmented
     1105~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1106Test 18-iii.  Modifying Maries
     1107~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     1108accessor_cases done
     1109try_pop cases done
     1110origin_mutation cases done
     1111isListed cases done
  • tests/list/dlist-insert-remove.cfa

    r5407cdc r8d66610  
    1919struct fred {
    2020        float adatum;
    21         DLISTED_MGD_EXPL_IN(fred, mine)
    22         DLISTED_MGD_EXPL_IN(fred, yours)
     21        inline struct mine { inline dlink(fred); };
     22        inline struct yours { inline dlink(fred); };
    2323};
    24 
    25 DLISTED_MGD_EXPL_OUT(fred, mine)
    26 DLISTED_MGD_EXPL_OUT(fred, yours)
     24P9_EMBEDDED(fred, fred.mine)
     25P9_EMBEDDED(fred, fred.yours)
     26P9_EMBEDDED(fred.mine, dlink(fred))
     27P9_EMBEDDED(fred.yours, dlink(fred))
     28
    2729
    2830void ?{}(fred &this, float adatum) {
     
    3335struct mary {
    3436        float anotherdatum;
    35         DLISTED_MGD_IMPL_IN(mary)
     37        inline dlink(mary);
    3638};
    3739
    38 DLISTED_MGD_IMPL_OUT(mary)
     40P9_EMBEDDED(mary, dlink(mary))
    3941
    4042void ?{}(mary &this, float anotherdatum) {
     
    5355////////////////////////////////////////////////////////////
    5456
    55 void printMyFredsFwd(fred &f) {
    56         while (&f != 0p) {
     57void printMyFredsFwd(fred & f) {
     58    with( DLINK_VIA( fred, fred.mine ) )
     59        do {
    5760                sout | f.adatum;
    58                 &f = &f`in_mine`next;
    59         }
    60 }
    61 
    62 void printMyFredsRev(fred &f) {
    63         while (&f != 0p) {
     61        } while (f`moveNext);
     62}
     63
     64void printMyFredsRev(fred & f) {
     65    with( DLINK_VIA( fred, fred.mine ) )
     66        do {
    6467                sout | f.adatum;
    65                 &f = &f`in_mine`prev;
    66         }
    67 }
     68        } while (f`movePrev);
     69}
     70
    6871
    6972void printMyFreddies(fred &f1, fred &f2, int isBefore) {
     
    7376                sout | "==== fred by MINE after ";
    7477        }
    75         printMyFredsFwd(f1);    sout | '-';
    76         printMyFredsRev(f1);    sout | '-';
    77         printMyFredsFwd(f2);    sout | '-';
    78         printMyFredsRev(f2);    sout | '-';
    79 }
    80 
    81 void printYourFredsFwd(fred &f) {
    82         while (&f != 0p) {
     78        if (&f1) {
     79                printMyFredsFwd(f1);    sout | '-';
     80                printMyFredsRev(f1);    sout | '-';
     81        } else {
     82                sout | '-'; sout | '-';
     83        }
     84        if (&f2) {
     85                printMyFredsFwd(f2);    sout | '-';
     86                printMyFredsRev(f2);    sout | '-';
     87        } else {
     88                sout | '-'; sout | '-';
     89        }
     90}
     91
     92void printYourFredsFwd(fred & f) {
     93    with( DLINK_VIA( fred, fred.yours ) )
     94        do {
    8395                sout | f.adatum;
    84                 &f = &f`in_yours`next;
    85         }
    86 }
    87 
    88 void printYourFredsRev(fred &f) {
    89         while (&f != 0p) {
     96        } while (f`moveNext);
     97}
     98
     99void printYourFredsRev(fred & f) {
     100    with( DLINK_VIA( fred, fred.yours ) )
     101        do {
    90102                sout | f.adatum;
    91                 &f = &f`in_yours`prev;
    92         }
     103        } while (f`movePrev);
    93104}
    94105
     
    99110                sout | "==== fred by YOURS after ";
    100111        }
    101         printYourFredsFwd(f1);  sout | '-';
    102         printYourFredsRev(f1);  sout | '-';
    103         printYourFredsFwd(f2);  sout | '-';
    104         printYourFredsRev(f2);  sout | '-';
     112        if (&f1) {
     113                printYourFredsFwd(f1);  sout | '-';
     114                printYourFredsRev(f1);  sout | '-';
     115        } else {
     116                sout | '-'; sout | '-';
     117        }
     118        if (&f2) {
     119                printYourFredsFwd(f2);  sout | '-';
     120                printYourFredsRev(f2);  sout | '-';
     121        } else {
     122                sout | '-'; sout | '-';
     123        }
    105124}
    106125
    107126void printMariesFwd(mary &m) {
    108         while (&m != 0p) {
     127        do {
    109128                sout | m.anotherdatum;
    110                 &m = &m`next;
    111         }
     129        } while (m`moveNext);
    112130}
    113131
    114132void printMariesRev(mary &m) {
    115         while (&m != 0p) {
     133        do {
    116134                sout | m.anotherdatum;
    117                 &m = &m`prev;
    118         }
     135        } while (m`movePrev);
    119136}
    120137
     
    125142                sout | "==== mary after ";
    126143        }
    127         printMariesFwd(m1);     sout | '-';
    128         printMariesRev(m1);     sout | '-';
    129         printMariesFwd(m2);     sout | '-';
    130         printMariesRev(m2);     sout | '-';
     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        }
    131156}
    132157
     
    153178//  - from list position #2 moving backward (d)
    154179// The expected-output comments are in form a;b;c;d where a::=num,num,num
    155 
     180#if 0
    156181void test__insertafter_singleton_on_singleton__fred_mine () {
    157182        fred f1 = {3.14};
     
    161186        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    162187
    163         insert_after(f1`in_mine, f2);
     188        diref(fred, fred.mine) f1_mine = f1`from;
     189        insert_after(f1_mine, f2);
    164190
    165191        printMyFreddies(f1, f2, 0);     // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
     
    174200        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    175201
    176         insert_after(f1`in_yours, f2);
     202        diref(fred, fred.yours) f1_yours = f1`from;
     203        insert_after(f1_yours, f2);
    177204
    178205        printMyFreddies(f1, f2, 0);     // 3.14; 3.14; 0.5; 0.5 (unmodified)
     
    208235        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    209236
    210         insert_before(f2`in_mine, f1);
     237        diref(fred, fred.mine) f2_mine = f2`from;
     238        insert_before(f2_mine, f1);
    211239
    212240        printMyFreddies(f1, f2, 0);     // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
     
    221249        printYourFreddies(f1, f2, 1);   // 3.14; 3.14; 0.5; 0.5
    222250
    223         insert_before(f2`in_yours, f1);
     251        diref(fred, fred.yours) f2_yours = f2`from;
     252        insert_before(f2_yours, f1);
    224253
    225254        printMyFreddies(f1, f2, 0);     // 3.14; 3.14; 0.5; 0.5 (unmodified)
     
    237266        printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    238267}
    239 
     268#endif
    240269////////////////////////////////////////////////////////////
    241270//
     
    250279// All three tests exercise the case of creating an empty container and
    251280// adding two items to it.
    252 
    253281void test__insertfirst_two_on_empty__fred_mine() {
    254282
     
    256284        fred f2 = {0.5};
    257285
    258         dlist(fred_in_mine, fred) lf;
     286        dlist(fred, fred.mine) lf;
    259287
    260288        verify(validate(lf));
     
    277305        fred f2 = {0.5};
    278306
    279         dlist(fred_in_yours, fred) lf;
     307        dlist(fred, fred.yours) lf;
    280308
    281309        verify(validate(lf));
     
    292320        printYourFreddies(f1, f2, 0);   // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    293321}
    294 
    295322void test__insertfirst_two_on_empty__mary() {
    296323
     
    298325        mary m2 = {0.5};
    299326
    300         dlist(mary, mary) lm;
     327        dlist(mary) lm;
    301328
    302329        verify(validate(lm));
     
    325352        fred f2 = {0.5};
    326353
    327         dlist(fred_in_mine, fred) lf;
     354        dlist(fred, fred.mine) lf;
    328355
    329356        verify(validate(lf));
     
    346373        fred f2 = {0.5};
    347374
    348         dlist(fred_in_yours, fred) lf;
     375        dlist(fred, fred.yours) lf;
    349376
    350377        verify(validate(lf));
     
    367394        mary m2 = {0.5};
    368395
    369         dlist(mary, mary) lm;
     396        dlist(mary) lm;
    370397
    371398        verify(validate(lm));
     
    394421        fred f2 = {0.5};
    395422
    396         dlist(fred_in_mine, fred) lf;
    397 
    398         assert(& lf`first == 0p);
    399         assert(& lf`last == 0p);
     423        dlist(fred, fred.mine) lf;
     424
     425        assert( & lf`first == 0p );
     426        assert( & lf`last == 0p );
    400427
    401428        insert_first(lf, f1);
    402429
    403         assert(& lf`first == & f1);
    404         assert(& lf`last == & f1);
     430        assert( & lf`first == & f1 );
     431        assert( & lf`last  == & f1 );
    405432
    406433        verify(validate(lf));
    407434
    408         insert_after(f1`in_mine, f2);
     435        with ( DLINK_VIA(fred, fred.mine) ) insert_after(f1, f2);
    409436
    410437        verify(validate(lf));
     
    413440        printYourFreddies(f1, f2, 0);   // 3.14; 3.14; 0.5; 0.5 (unmodified)
    414441
    415         assert(& lf`first == & f1);
    416         assert(& lf`last == & f2);
     442        assert( & lf`first == & f1 );
     443        assert( & lf`last  == & f2 );
    417444}
    418445
     
    422449        fred f2 = {0.5};
    423450
    424         dlist(fred_in_yours, fred) lf;
    425 
    426         assert(& lf`first == 0p);
    427         assert(& lf`last == 0p);
     451        dlist(fred, fred.yours) lf;
     452
     453        assert( & lf`first == 0p );
     454        assert( & lf`last == 0p );
    428455
    429456        insert_first(lf, f1);
    430457
    431         assert(& lf`first == & f1);
    432         assert(& lf`last == & f1);
     458        assert( & lf`first == & f1 );
     459        assert( & lf`last  == & f1 );
    433460
    434461        verify(validate(lf));
    435462
    436         insert_after(f1`in_yours, f2);
     463    with ( DLINK_VIA(fred, fred.yours) ) insert_after(f1, f2);
    437464
    438465        verify(validate(lf));
     
    441468        printYourFreddies(f1, f2, 0);   // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    442469
    443         assert(& lf`first == & f1);
    444         assert(& lf`last == & f2);
     470        assert( & lf`first == & f1 );
     471        assert( & lf`last  == & f2 );
    445472}
    446473
     
    450477        mary m2 = {0.5};
    451478
    452         dlist(mary, mary) lm;
    453 
    454         assert(& lm`first == 0p);
    455         assert(& lm`last == 0p);
     479        dlist(mary) lm;
     480
     481        assert( & lm`first == 0p );
     482        assert( & lm`last == 0p );
    456483
    457484        insert_first(lm, m1);
    458485
    459         assert(& lm`first == & m1);
    460         assert(& lm`last == & m1);
     486        assert( & lm`first == & m1 );
     487        assert( & lm`last  == & m1 );
    461488
    462489        verify(validate(lm));
     
    468495        printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    469496
    470         assert(& lm`first == & m1);
    471         assert(& lm`last == & m2);
     497        assert( & lm`first == & m1 );
     498        assert( & lm`last  == & m2 );
    472499}
    473500
     
    487514        fred f2 = {0.5};
    488515
    489         dlist(fred_in_mine, fred) lf;
    490 
    491         assert(& lf`first == 0p);
    492         assert(& lf`last == 0p);
     516        dlist(fred, fred.mine) lf;
     517
     518        assert( & lf`first == 0p );
     519        assert( & lf`last == 0p );
    493520
    494521        insert_last(lf, f2);
    495522
    496         assert(& lf`first == & f2);
    497         assert(& lf`last == & f2);
     523        assert( & lf`first == & f2 );
     524        assert( & lf`last  == & f2 );
    498525
    499526        verify(validate(lf));
    500527
    501         insert_before(f2`in_mine, f1);
     528        with ( DLINK_VIA(fred, fred.mine) ) insert_before(f2, f1);
    502529
    503530        verify(validate(lf));
     
    506533        printYourFreddies(f1, f2, 0);   // 3.14; 3.14; 0.5; 0.5 (unmodified)
    507534
    508         assert(& lf`first == & f1);
    509         assert(& lf`last == & f2);
     535        assert( & lf`first == & f1 );
     536        assert( & lf`last  == & f2 );
    510537}
    511538
     
    515542        fred f2 = {0.5};
    516543
    517         dlist(fred_in_yours, fred) lf;
    518 
    519         assert(& lf`first == 0p);
    520         assert(& lf`last == 0p);
     544        dlist(fred, fred.yours) lf;
     545
     546        assert( & lf`first == 0p );
     547        assert( & lf`last == 0p );
    521548
    522549        insert_last(lf, f2);
    523550
    524         assert(& lf`first == & f2);
    525         assert(& lf`last == & f2);
     551        assert( & lf`first == & f2 );
     552        assert( & lf`last  == & f2 );
    526553
    527554        verify(validate(lf));
    528555
    529         insert_before(f2`in_yours, f1);
     556        with ( DLINK_VIA(fred, fred.yours) )insert_before(f2, f1);
    530557
    531558        verify(validate(lf));
     
    534561        printYourFreddies(f1, f2, 0);   // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    535562
    536         assert(& lf`first == & f1);
    537         assert(& lf`last == & f2);
     563        assert( & lf`first == & f1 );
     564        assert( & lf`last  == & f2 );
    538565}
    539566
     
    543570        mary m2 = {0.5};
    544571
    545         dlist(mary, mary) lm;
    546 
    547         assert(& lm`first == 0p);
    548         assert(& lm`last == 0p);
     572        dlist(mary) lm;
     573
     574        assert( & lm`first == 0p );
     575        assert( & lm`last == 0p );
    549576
    550577        insert_last(lm, m2);
    551578
    552         assert(& lm`first == & m2);
    553         assert(& lm`last == & m2);
     579        assert( & lm`first == & m2 );
     580        assert( & lm`last  == & m2 );
    554581
    555582        verify(validate(lm));
     
    561588        printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified)
    562589
    563         assert(& lm`first == & m1);
    564         assert(& lm`last == & m2);
    565 }
     590        assert( & lm`first == & m1 );
     591        assert( & lm`last  == & m2 );
     592}
     593#if 0
    566594
    567595////////////////////////////////////////////////////////////
     
    846874//
    847875////////////////////////////////////////////////////////////
    848 
     876#endif
    849877void test__remove_at_head__fred_mine() {
    850878
     
    853881        fred f3 = {3.7};
    854882
    855         dlist(fred_in_mine, fred) flm;
     883        dlist(fred, fred.mine) flm;
    856884        insert_last(flm, f1);
    857885        insert_last(flm, f2);
    858886        insert_last(flm, f3);
    859887
    860         dlist(fred_in_yours, fred) fly;
     888        dlist(fred, fred.yours) fly;
    861889        insert_last(fly, f1);
    862890        insert_last(fly, f2);
     
    869897        verify(validate(flm));
    870898
    871         remove(f1`in_mine);
     899        with( DLINK_VIA(fred, fred.mine) ) remove(f1);
    872900
    873901        verify(validate(fly));
     
    881909
    882910        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    883         assert(f1.$links_mine.next.is_terminator == false);
    884         assert(f1.$links_mine.prev.is_terminator == false);
    885 }
     911        // assert(f1.$links_mine.next.is_terminator == false);
     912        // assert(f1.$links_mine.prev.is_terminator == false);
     913}
     914
    886915
    887916void test__remove_at_head__fred_yours() {
     
    891920        fred f3 = {3.7};
    892921
    893         dlist(fred_in_mine, fred) flm;
     922        dlist(fred, fred.mine) flm;
    894923        insert_last(flm, f1);
    895924        insert_last(flm, f2);
    896925        insert_last(flm, f3);
    897926
    898         dlist(fred_in_yours, fred) fly;
     927        dlist(fred, fred.yours) fly;
    899928        insert_last(fly, f1);
    900929        insert_last(fly, f2);
     
    907936        verify(validate(flm));
    908937
    909         remove(f1`in_yours);
     938        with( DLINK_VIA(fred, fred.yours) ) remove(f1);
    910939
    911940        verify(validate(fly));
     
    919948
    920949        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    921         assert(f1.$links_yours.next.is_terminator == false);
    922         assert(f1.$links_yours.prev.is_terminator == false);
     950        // assert(f1.$links_yours.next.is_terminator == false);
     951        // assert(f1.$links_yours.prev.is_terminator == false);
    923952}
    924953
     
    929958        mary m3 = {3.7};
    930959
    931         dlist(mary, mary) ml;
     960        dlist(mary) ml;
    932961        insert_last(ml, m1);
    933962        insert_last(ml, m2);
     
    948977
    949978        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    950         assert(m1.$links.next.is_terminator == false);
    951         assert(m1.$links.prev.is_terminator == false);
     979        // assert(m1.$links.next.is_terminator == false);
     980        // assert(m1.$links.prev.is_terminator == false);
    952981}
    953982
     
    968997        fred f3 = {3.7};
    969998
    970         dlist(fred_in_mine, fred) flm;
     999        dlist(fred, fred.mine) flm;
    9711000        insert_last(flm, f1);
    9721001        insert_last(flm, f2);
    9731002        insert_last(flm, f3);
    9741003
    975         dlist(fred_in_yours, fred) fly;
     1004        dlist(fred, fred.yours) fly;
    9761005        insert_last(fly, f1);
    9771006        insert_last(fly, f2);
     
    9841013        verify(validate(flm));
    9851014
    986         remove(f3`in_mine);
     1015        with( DLINK_VIA(fred, fred.mine) ) remove(f3);
    9871016
    9881017        verify(validate(fly));
     
    9961025
    9971026        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    998         assert(f3.$links_mine.next.is_terminator == false);
    999         assert(f3.$links_mine.prev.is_terminator == false);
     1027        // assert(f3.$links_mine.next.is_terminator == false);
     1028        // assert(f3.$links_mine.prev.is_terminator == false);
    10001029}
    10011030
     
    10061035        fred f3 = {3.7};
    10071036
    1008         dlist(fred_in_mine, fred) flm;
     1037        dlist(fred, fred.mine) flm;
    10091038        insert_last(flm, f1);
    10101039        insert_last(flm, f2);
    10111040        insert_last(flm, f3);
    10121041
    1013         dlist(fred_in_yours, fred) fly;
     1042        dlist(fred, fred.yours) fly;
    10141043        insert_last(fly, f1);
    10151044        insert_last(fly, f2);
     
    10221051        verify(validate(flm));
    10231052
    1024         remove(f3`in_yours);
     1053        with( DLINK_VIA(fred, fred.yours) ) remove(f3);
    10251054
    10261055        verify(validate(fly));
     
    10341063
    10351064        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1036         assert(f3.$links_yours.next.is_terminator == false);
    1037         assert(f3.$links_yours.prev.is_terminator == false);
     1065        // assert(f3.$links_yours.next.is_terminator == false);
     1066        // assert(f3.$links_yours.prev.is_terminator == false);
    10381067}
    10391068
     
    10441073        mary m3 = {3.7};
    10451074
    1046         dlist(mary, mary) ml;
     1075        dlist(mary) ml;
    10471076        insert_last(ml, m1);
    10481077        insert_last(ml, m2);
     
    10631092
    10641093        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1065         assert(m3.$links.next.is_terminator == false);
    1066         assert(m3.$links.prev.is_terminator == false);
     1094        // assert(m3.$links.next.is_terminator == false);
     1095        // assert(m3.$links.prev.is_terminator == false);
    10671096}
    10681097
     
    10811110        fred f = {0.7};
    10821111
    1083         dlist(fred_in_mine, fred) flm;
     1112        dlist(fred, fred.mine) flm;
    10841113        insert_last(flm, f);
    10851114
    1086         dlist(fred_in_yours, fred) fly;
     1115        dlist(fred, fred.yours) fly;
    10871116        insert_last(fly, f);
    10881117
     
    10931122        verify(validate(flm));
    10941123
    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);
     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 );
    11021131
    11031132        printYourFreddies(fly`first, fly`last, 0);   // 0.7; 0.7; 0.7; 0.7 (unmodified)
     
    11071136
    11081137        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1109         assert(f.$links_mine.next.is_terminator == false);
    1110         assert(f.$links_mine.prev.is_terminator == false);
     1138        // assert(f.$links_mine.next.is_terminator == false);
     1139        // assert(f.$links_mine.prev.is_terminator == false);
    11111140
    11121141        insert_last(flm, f);
     
    11201149        fred f = {0.7};
    11211150
    1122         dlist(fred_in_mine, fred) flm;
     1151        dlist(fred, fred.mine) flm;
    11231152        insert_last(flm, f);
    11241153
    1125         dlist(fred_in_yours, fred) fly;
     1154        dlist(fred, fred.yours) fly;
    11261155        insert_last(fly, f);
    11271156
     
    11321161        verify(validate(flm));
    11331162
    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);
     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 );
    11411170
    11421171        printYourFreddies(flm`first, flm`last, 0);   // 0.7; 0.7; 0.7; 0.7 (unmodified)
     
    11461175
    11471176        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1148         assert(f.$links_yours.next.is_terminator == false);
    1149         assert(f.$links_yours.prev.is_terminator == false);
     1177        // assert(f.$links_yours.next.is_terminator == false);
     1178        // assert(f.$links_yours.prev.is_terminator == false);
    11501179
    11511180        insert_last(fly, f);
     
    11591188        mary m = {0.7};
    11601189
    1161         dlist(mary, mary) ml;
     1190        dlist(mary) ml;
    11621191        insert_last(ml, m);
    11631192
     
    11701199        verify(validate(ml));
    11711200
    1172         assert(& ml`first == 0p);
    1173         assert(& ml`last  == 0p);
     1201        assert( & ml`first == 0p );
     1202        assert( & ml`last == 0p );
    11741203
    11751204        // observe f is solo in mine (now unlisted); in yours, it was just traversed
     
    11771206
    11781207        // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics
    1179         assert(m.$links.next.is_terminator == false);
    1180         assert(m.$links.prev.is_terminator == false);
     1208        // assert(m.$links.next.is_terminator == false);
     1209        // assert(m.$links.prev.is_terminator == false);
    11811210
    11821211        insert_last(ml, m);
     
    12031232        fred f3 = {3.7};
    12041233
    1205         dlist(fred_in_mine, fred) flm;
     1234        dlist(fred, fred.mine) flm;
    12061235        insert_last(flm, f1);
    12071236        insert_last(flm, f2);
    12081237        insert_last(flm, f3);
    12091238
    1210         dlist(fred_in_yours, fred) fly;
     1239        dlist(fred, fred.yours) fly;
    12111240        insert_last(fly, f1);
    12121241        insert_last(fly, f2);
     
    12191248        verify(validate(flm));
    12201249
    1221         fred & popped = pop_first(flm);
     1250        fred & popped = try_pop_front(flm);
    12221251
    12231252        verify(validate(fly));
     
    12391268        fred f3 = {3.7};
    12401269
    1241         dlist(fred_in_mine, fred) flm;
     1270        dlist(fred, fred.mine) flm;
    12421271        insert_last(flm, f1);
    12431272        insert_last(flm, f2);
    12441273        insert_last(flm, f3);
    12451274
    1246         dlist(fred_in_yours, fred) fly;
     1275        dlist(fred, fred.yours) fly;
    12471276        insert_last(fly, f1);
    12481277        insert_last(fly, f2);
     
    12551284        verify(validate(flm));
    12561285
    1257         fred & popped = pop_first(fly);
     1286        fred & popped = try_pop_front(fly);
    12581287
    12591288        verify(validate(fly));
     
    12751304        mary m3 = {3.7};
    12761305
    1277         dlist(mary, mary) ml;
     1306        dlist(mary) ml;
    12781307        insert_last(ml, m1);
    12791308        insert_last(ml, m2);
     
    12841313        verify(validate(ml));
    12851314
    1286         mary & popped = pop_first(ml);
     1315        mary & popped = try_pop_front(ml);
    12871316
    12881317        verify(validate(ml));
     
    13021331        fred f3 = {3.7};
    13031332
    1304         dlist(fred_in_mine, fred) flm;
     1333        dlist(fred, fred.mine) flm;
    13051334        insert_last(flm, f1);
    13061335        insert_last(flm, f2);
    13071336        insert_last(flm, f3);
    13081337
    1309         dlist(fred_in_yours, fred) fly;
     1338        dlist(fred, fred.yours) fly;
    13101339        insert_last(fly, f1);
    13111340        insert_last(fly, f2);
     
    13181347        verify(validate(flm));
    13191348
    1320         fred & popped = pop_last(flm);
     1349        fred & popped = try_pop_back(flm);
    13211350
    13221351        verify(validate(fly));
     
    13381367        fred f3 = {3.7};
    13391368
    1340         dlist(fred_in_mine, fred) flm;
     1369        dlist(fred, fred.mine) flm;
    13411370        insert_last(flm, f1);
    13421371        insert_last(flm, f2);
    13431372        insert_last(flm, f3);
    13441373
    1345         dlist(fred_in_yours, fred) fly;
     1374        dlist(fred, fred.yours) fly;
    13461375        insert_last(fly, f1);
    13471376        insert_last(fly, f2);
     
    13541383        verify(validate(flm));
    13551384
    1356         fred & popped = pop_last(fly);
     1385        fred & popped = try_pop_back(fly);
    13571386
    13581387        verify(validate(fly));
     
    13741403        mary m3 = {3.7};
    13751404
    1376         dlist(mary, mary) ml;
     1405        dlist(mary) ml;
    13771406        insert_last(ml, m1);
    13781407        insert_last(ml, m2);
     
    13831412        verify(validate(ml));
    13841413
    1385         mary & popped = pop_last(ml);
     1414        mary & popped = try_pop_back(ml);
    13861415
    13871416        verify(validate(ml));
     
    13971426////////////////////////////////////////////////////////////
    13981427//
     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
     1437void 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
     1473void 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
     1577void 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
     1609void 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//
    13991630// Section 5
    14001631//
     
    14041635
    14051636int main() {
    1406 
     1637#if 0
    14071638        sout | "~~~~~~~~~~~~~~~~~ Headless List Tests - insert_after ~~~~~~~~~~~~~~~~";
    14081639        sout | "";
     
    14411672        sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    14421673        test__insertbefore_singleton_on_singleton__mary();
    1443 
     1674#endif
    14441675        sout | "";
    14451676        sout | "~~~~~~~~~~~~~~~~~ Headed List Tests - insert_first ~~~~~~~~~~~~~~~~~~";
     
    15171748        sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    15181749        test__insertbefore_before_first__mary();
     1750#if 0
    15191751
    15201752        sout | "";
     
    15741806        sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    15751807        test__remove_at_last__mary();
    1576 
     1808#endif
    15771809        sout | "";
    15781810        sout | "~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~";
     
    16701902        test__pop_last__maries();
    16711903
     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
    16721927        return 0;
    16731928}
  • tests/strstream.cfa

    r5407cdc r8d66610  
     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
    113#include <fstream.hfa>
    214#include <strstream.hfa>
    315
    416int main() {
    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;
     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;
    1022
    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));
     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));
    1527
    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;
     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;
    2032}
     33
     34// Local Variables: //
     35// tab-width: 4 //
     36// compile-command: "cfa strstream.cfa" //
     37// End: //
  • tests/unified_locking/timeout_lock.cfa

    r5407cdc r8d66610  
    3333
    3434        for ( unsigned int i = 0; i < NoOfTimes + 3; i += 1 ) {
    35             if ( wait( c_m, m, 1`s ) ) {
     35            if ( wait( c_m, m, 1000000`ns ) ) {
    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( 100000000`ns );
     53        sleep( 100000`ns );
    5454        notify_one(c_m);
    5555        block();
    5656
    57         sleep( 500000000`ns );
     57        sleep( 500000`ns );
    5858        notify_one(c_m);
    5959        block();
    6060
    61         sleep( 900000000`ns );
     61        sleep( 900000`ns );
    6262        notify_one(c_m);
    6363        block();
    6464
    6565        for ( unsigned int i = 0; i < NoOfTimes; i += 1 ) {
    66             sleep( 999700000`ns );
     66            sleep( 999700`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 );
    7977        lock(m); wait( c_m, m, 1`ns ); unlock(m);                                                               // bool wait( condition_variable(L) & this, L & l, Duration duration );
    8078        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 );
    8379        printf("Done Test 1\n");
    8480
Note: See TracChangeset for help on using the changeset viewer.