Changes in / [8d66610:5407cdc]
- Files:
-
- 3 added
- 24 deleted
- 69 edited
-
doc/LaTeXmacros/common.sty (deleted)
-
doc/LaTeXmacros/common.tex (modified) (6 diffs)
-
doc/theses/andrew_beach_MMath/Makefile (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/cfalab.sty (modified) (4 diffs)
-
doc/theses/andrew_beach_MMath/existing.tex (modified) (13 diffs)
-
doc/theses/andrew_beach_MMath/features.tex (modified) (16 diffs)
-
doc/theses/andrew_beach_MMath/future.tex (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/implement.tex (modified) (27 diffs)
-
doc/theses/andrew_beach_MMath/intro.tex (deleted)
-
doc/theses/andrew_beach_MMath/uw-ethesis.tex (modified) (7 diffs)
-
doc/theses/mubeen_zulfiqar_MMath/AllocDS1.fig (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/AllocDS2.fig (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/Makefile (modified) (2 diffs)
-
doc/theses/mubeen_zulfiqar_MMath/allocator.tex (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/background.tex (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/conclusion.tex (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/intro.tex (modified) (1 diff)
-
doc/theses/mubeen_zulfiqar_MMath/performance.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex (modified) (4 diffs)
-
doc/user/Makefile (modified) (3 diffs)
-
doc/user/user.tex (modified) (23 diffs)
-
libcfa/src/common.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/alarm.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/alarm.hfa (modified) (1 diff)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/clib/cfathread.h (modified) (1 diff)
-
libcfa/src/concurrency/invoke.h (modified) (3 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (16 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (10 diffs)
-
libcfa/src/concurrency/kernel/fwd.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (13 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (10 diffs)
-
libcfa/src/concurrency/locks.cfa (modified) (5 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/preemption.cfa (modified) (15 diffs)
-
libcfa/src/concurrency/ready_queue.cfa (modified) (26 diffs)
-
libcfa/src/concurrency/ready_subqueue.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/stats.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/stats.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (1 diff)
-
libcfa/src/containers/array.hfa (modified) (5 diffs)
-
libcfa/src/containers/list.hfa (modified) (1 diff)
-
libcfa/src/exception.c (modified) (1 diff)
-
libcfa/src/exception.h (modified) (2 diffs)
-
libcfa/src/exception.hfa (modified) (1 diff)
-
libcfa/src/executor.baseline.txt (deleted)
-
libcfa/src/executor.cfa (modified) (2 diffs)
-
libcfa/src/fstream.cfa (modified) (5 diffs)
-
libcfa/src/fstream.hfa (modified) (3 diffs)
-
libcfa/src/heap.cfa (modified) (2 diffs)
-
libcfa/src/iostream.cfa (modified) (3 diffs)
-
libcfa/src/iostream.hfa (modified) (3 diffs)
-
libcfa/src/virtual.c (modified) (3 diffs)
-
libcfa/src/virtual.h (modified) (2 diffs)
-
src/CodeGen/LinkOnce.cc (deleted)
-
src/CodeGen/LinkOnce.h (deleted)
-
src/CodeGen/module.mk (modified) (1 diff)
-
src/Concurrency/Keywords.cc (modified) (2 diffs)
-
src/GenPoly/Box.cc (modified) (1 diff)
-
src/InitTweak/InitTweak.cc (modified) (1 diff)
-
src/Parser/DeclarationNode.cc (modified) (1 diff)
-
src/Virtual/ExpandCasts.cc (modified) (2 diffs)
-
src/Virtual/Tables.cc (modified) (2 diffs)
-
src/main.cc (modified) (2 diffs)
-
tests/.expect/linkonce.txt (deleted)
-
tests/Makefile.am (modified) (2 diffs)
-
tests/array-container/.expect/array-basic.txt (deleted)
-
tests/array-container/.expect/array-basic.x64.txt (added)
-
tests/array-container/.expect/array-md-sbscr-cases.x64.txt (deleted)
-
tests/array-container/array-basic.cfa (modified) (6 diffs)
-
tests/array-container/array-md-sbscr-cases.cfa (deleted)
-
tests/concurrent/.expect/sleep.txt (deleted)
-
tests/concurrent/clib_tls.c (modified) (1 diff)
-
tests/concurrent/sleep.cfa (deleted)
-
tests/exceptions/virtual-cast.cfa (modified) (1 diff)
-
tests/exceptions/virtual-poly.cfa (modified) (3 diffs)
-
tests/io/.expect/manipulatorsOutput4.txt (deleted)
-
tests/io/.expect/manipulatorsOutput4.x64.txt (added)
-
tests/link-once/main.cfa (deleted)
-
tests/link-once/partner.cfa (deleted)
-
tests/list/.expect/dlist-insert-remove.txt (modified) (3 diffs)
-
tests/list/dlist-insert-remove.cfa (modified) (76 diffs)
-
tests/raii/.expect/boxed-types.txt (deleted)
-
tests/raii/boxed-types.cfa (deleted)
-
tests/strstream.cfa (modified) (1 diff)
-
tests/unified_locking/.expect/timeout_lock.txt (deleted)
-
tests/unified_locking/timeout_lock.cfa (modified) (3 diffs)
-
tests/unified_locking/timeout_lock.txt (added)
-
tests/zombies/linked-list-perf/experiment.cpp (deleted)
-
tests/zombies/linked-list-perf/experiment.koad (deleted)
-
tests/zombies/linked-list-perf/mike-old.hfa (deleted)
-
tests/zombies/linked-list-perf/mike-proto-list.hfa (deleted)
-
tests/zombies/linked-list-perf/thierry-subqueue-old-rip.hfa (deleted)
-
tools/perf/process_stat_array.py (deleted)
Legend:
- Unmodified
- Added
- Removed
-
doc/LaTeXmacros/common.tex
r8d66610 r5407cdc 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : S at May 8 08:48:37202114 %% Update Count : 5 4013 %% Last Modified On : Sun Feb 14 15:52:46 2021 14 %% Update Count : 524 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 38 38 \usepackage{xspace} 39 39 \newcommand{\CFAIcon}{\textsf{C}\raisebox{\depth}{\rotatebox{180}{\textsf{A}}}} % Cforall icon 40 \newcommand{\CFA}{\protect\CFAIcon\xspace} % CFA symbolic name41 \newcommand{\CFL}{\textrm{Cforall}\xspace} % Cforall non-icon name42 \newcommand{\Celeven}{\textrm{C11}\xspace} % C11 symbolic name40 \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 43 43 \newcommand{\CCIcon}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}} % C++ icon 44 \newcommand{\CC} [1][]{\protect\CCIcon{#1}\xspace}% C++ symbolic name44 \newcommand{\CC}{\protect\CCIcon\xspace} % C++ symbolic name 45 45 % numbers disallowed in latex variables names => use number names 46 \newcommand{\CCeleven}{\protect\CCIcon{11}\xspace} % C++11 symbolic name47 \newcommand{\CCfourteen}{\protect\CCIcon{14}\xspace} % C++14 symbolic name48 \newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace} % C++17 symbolic name49 \newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace} % C++20 symbolic name46 \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 50 50 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name 51 51 … … 102 102 \renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}{-2.5ex \@plus -1ex \@minus -.2ex}{1.0ex \@plus .2ex}{\normalfont\normalsize\bfseries}} 103 103 \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}}105 104 106 105 % index macros … … 153 152 % Latin abbreviation 154 153 \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 160 154 \@ifundefined{eg}{ 161 155 \newcommand{\EG}{\abbrevFont{e}.\abbrevFont{g}.} 162 \newcommand{\eg}{\EG\CheckCommaColon} 163 }{}% 156 \newcommand*{\eg}{% 157 \@ifnextchar{,}{\EG}% 158 {\@ifnextchar{:}{\EG}% 159 {\EG,\xspace}}% 160 }}{}% 164 161 \@ifundefined{ie}{ 165 162 \newcommand{\IE}{\abbrevFont{i}.\abbrevFont{e}.} 166 \newcommand{\ie}{\IE\CheckCommaColon} 167 }{}% 163 \newcommand*{\ie}{% 164 \@ifnextchar{,}{\IE}% 165 {\@ifnextchar{:}{\IE}% 166 {\IE,\xspace}}% 167 }}{}% 168 168 \@ifundefined{etc}{ 169 169 \newcommand{\ETC}{\abbrevFont{etc}} 170 \newcommand{\etc}{\ETC\CheckPeriod} 171 }{}% 170 \newcommand*{\etc}{% 171 \@ifnextchar{.}{\ETC}% 172 {\ETC.\xspace}% 173 }}{}% 172 174 \@ifundefined{etal}{ 173 175 \newcommand{\ETAL}{\abbrevFont{et}~\abbrevFont{al}} 174 \newcommand{\etal}{\ETAL\CheckPeriod} 175 }{}% 176 \newcommand*{\etal}{% 177 \@ifnextchar{.}{\protect\ETAL}% 178 {\protect\ETAL.\xspace}% 179 }}{}% 176 180 \@ifundefined{viz}{ 177 181 \newcommand{\VIZ}{\abbrevFont{viz}} 178 \newcommand{\viz}{\VIZ\CheckPeriod} 179 }{}% 182 \newcommand*{\viz}{% 183 \@ifnextchar{.}{\VIZ}% 184 {\VIZ.\xspace}% 185 }}{}% 180 186 \makeatother 181 187 … … 278 284 showlines=true, % show blank lines at end of code 279 285 aboveskip=4pt, % spacing above/below code block 280 belowskip= 2pt,286 belowskip=0pt, 281 287 numberstyle=\footnotesize\sf, % numbering style 282 288 % replace/adjust listing characters that look bad in sanserif … … 291 297 \lstset{ 292 298 language=CFA, 293 %moredelim=**[is][\color{red}]{@}{@}, % red highlighting @...@294 moredelim=**[is][\color{red}]{®}{®}, % red highlighting ®...® (registered trademark symbol) emacs: C-q M-.299 moredelim=**[is][\color{red}]{@}{@}, % red highlighting @...@ 300 %moredelim=**[is][\color{red}]{®}{®}, % red highlighting ®...® (registered trademark symbol) emacs: C-q M-. 295 301 %moredelim=**[is][\color{blue}]{ß}{ß}, % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_ 296 302 %moredelim=**[is][\color{OliveGreen}]{¢}{¢}, % green highlighting ¢...¢ (cent symbol) emacs: C-q M-" -
doc/theses/andrew_beach_MMath/Makefile
r8d66610 r5407cdc 34 34 ${LATEX} ${BASE} 35 35 ${BIBTEX} ${BUILD}/${BASE} 36 ${LATEX} ${BASE} 36 37 ${GLOSSARY} ${BUILD}/${BASE} 37 38 ${LATEX} ${BASE} -
doc/theses/andrew_beach_MMath/cfalab.sty
r8d66610 r5407cdc 1 1 % Package for CFA Research Lab. 2 % (Now more a personal collection and testing grounds for common.sty.)3 2 % 4 % This is a collection of commands everyone working on CFA related documents 5 % should find useful. So mostly programming language related tools. 3 % Made by combining and updating various macro files people had made. 6 4 % 7 5 % Internal commands are prefixed with "\cfalab@". … … 12 10 13 11 % Other packages required. 14 %15 % Access to new basic LaTeX tools and other low level commands.16 12 \RequirePackage{etoolbox} 17 % Code formatting tools and environments.18 13 \RequirePackage{listings} 19 % Automatically adds spaces.20 14 \RequirePackage{xspace} 21 15 22 % Tip for commands that end with \xspace: if the default is not correct then 23 % follow the command with {} to disable \xspace, use '{} ' to force add a 24 % space and '{}<whatever-follows>' to force remove one. 25 % 26 % \CFA 16 % Symbols: All symbols are zero argument robust commands with special rules 17 % about the space following the c.s. token. Normally the space might be 18 % re-added according to the rules of the xspace package. They may be followed 19 % by a star (which the command will consume) to disable this behaviour. 20 21 % \newsymbolcmd{<command>}{<replacement text>} 22 % Defines <command> to be a symbol that has the given <replacement text>. 23 \newrobustcmd*\newsymbolcmd[2]{\newrobustcmd{#1}{\cfalab@symbol{#2}}} 24 \def\cfalab@symbol#1{\@ifnextchar*{#1\cfalab@eatstar}{#1\xspace}} 25 \def\cfalab@eatstar*{} 26 27 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} 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+}} 32 31 33 % This is executed very early in the \begin{document} code, before the 34 % document's contents but after packages are loaded. 32 % This is executed very early in the \begin{document} code. 35 33 \AtEndPreamble{ 36 34 \@ifpackageloaded{hyperref}{ … … 38 36 \pdfstringdefDisableCommands{ 39 37 \def\CFA{CFA} 40 \def\Cpp{C++} 41 \def\lstinline{} 42 \def\code#1#2{#2} 38 \def\CPP{C++} 43 39 } 44 40 }{} 45 41 } 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 up64 % after loading them.65 \let\cfalab@textunderscore@old=\textunderscore66 \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}}}70 42 71 43 % The CFA listings language. Based off of ANCI C and including GCC extensions. … … 89 61 \lstset{defaultdialect={[UW]CFA}} 90 62 91 % Create an internal paragraph indent amount. This is used internally to 92 % mimic the standard indent even when it has been overriden in the document. 93 \newlength\cfalab@parindent 94 \deflength\cfalab@parindent{\parindent} 95 96 % The cfacommon style has many useful defaults for CFA and other types of 97 % code. Use the listings option "style=cfacommon" to load them. 98 \lstdefinestyle{cfacommon}{ 99 columns=fullflexible, 100 basicstyle=\linespread{0.9}\sf, 101 stringstyle=\tt, 102 tabsize=5, 103 % Indent code to paragraph indentation. 104 xleftmargin=\cfalab@parindent, 105 % Allow ASCII characters in the range 128-255. 106 extendedchars=true, 107 % This allows you to use "math mode" to insert LaTeX into the code. 108 % Use \( and \) if you need to insert math mode inside that code. 109 escapechar=\$, 110 % Disable LaTeX math escape in CFA code $...$ 111 mathescape=false, 112 keepspaces=true, 113 % Do not show spaces with cup. 114 showstringspaces=false, 115 % Show blank lines at end of code. 116 showlines=true, 117 % Spacing above/below code block. 118 aboveskip=4pt,belowskip=0pt, 119 numberstyle=\footnotesize\sf, 120 % Replace/adjust listing characters that look bad in sanserif. 121 literate={-}{\makebox[1ex][c]{\raisebox{0.7ex}{\rule{0.75ex}{0.1ex}}}}1 122 {^}{\raisebox{0.6ex}{$\scriptscriptstyle\land\,$}}1 123 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1 124 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 125 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex\textgreater}2, 63 % The cfalab style defines some common settings useful in different languages. 64 \lstdefinestyle{cfalab}{% 65 columns=fullflexible, 66 basicstyle=\linespread{0.9}\tt, 67 stringstyle=\tt, 126 68 } 127 69 128 % common.tex Compatablity =================================================== 129 % Below this line is for compatability with the old common.tex file. 70 % \code*[<escape character>]{<code>} 71 % Use the listings package to format a snipit of <code>. 72 % The <escape character> must be a character that does not appear in 73 % <code> and defaults to a backtick. 74 \newcommand*\codeC[2][\`]{\lstinline[language=C]#1#2#1} 75 \newcommand*\codeCFA[2][\`]{\lstinline[language=CFA]#1#2#1} 130 76 131 % Backwards compatable way to activate the cfacommon style. 132 \newcommand{\CFAStyle}{\lstset{style=cfacommon}} 133 134 % A couple of abbreviations are provided. Just ones someone liked. 135 % 136 % Abbreviation formatting commands (renew to customize): 137 \newcommand{\abbrevFont}{\textit} 138 % 139 % Abbreviations that, if not followed by a comma or colon, add a comma. 140 \newrobustcmd*\cfalab@abbrev@comma{% 141 \@ifnextchar{,}{}{\@ifnextchar{:}{}{,\xspace}}} 142 \providerobustcmd*\eg{\abbrevFont{e}.\abbrevFont{g}.\cfalab@abbrev@comma} 143 \providerobustcmd*\ie{\abbrevFont{i}.\abbrevFont{e}.\cfalab@abbrev@comma} 144 % 145 % Abbreviations that, if not followed by a period, add a period. 146 \newrobustcmd*\cfalab@abbrev@period{\@ifnextchar{.}{}{.\xspace}} 147 \providerobustcmd*\etc{\abbrevFont{etc}\cfalab@abbrev@period} 148 \providerobustcmd*\etal{\abbrevFont{et}~\abbrevFont{al}\cfalab@abbrev@period} 149 \providerobustcmd*\viz{\abbrevFont{viz}\cfalab@abbrev@period} 77 % \settextunderscore{(new|old)} 78 % Redefines the underscore either as a new repersentation or the old one. 79 % Not that some other packages (ex. hyperref) can override this. Set it 80 % up after loading them. 81 \let\cfalab@textunderscore@old=\textunderscore 82 \newcommand\cfalab@textunderscore@new{% 83 \leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}} 84 \newcommand\settextunderscore[1]{% 85 \renewcommand\textunderscore{\csuse{cfalab@textunderscore@#1}}} 150 86 151 87 \endinput -
doc/theses/andrew_beach_MMath/existing.tex
r8d66610 r5407cdc 16 16 to be defined~\cite{Moss18}. 17 17 \begin{cfa} 18 char i; int i; double i; 19 int f(); double f(); 20 void g( int ); void g( double ); 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$ 21 21 \end{cfa} 22 22 This feature requires name mangling so the assembly symbols are unique for … … 26 26 mangling is: 27 27 \begin{cfa} 28 // name mangling on by default28 // name mangling 29 29 int i; // _X1ii_1 30 extern "C" { // disablesname mangling30 @extern "C"@ { // no name mangling 31 31 int j; // j 32 extern "Cforall" { // enablesname mangling32 @extern "Cforall"@ { // name mangling 33 33 int k; // _X1ki_1 34 34 } 35 // revert tono name mangling36 } 37 // revert toname mangling35 // no name mangling 36 } 37 // name mangling 38 38 \end{cfa} 39 39 Both forms of @extern@ affect all the declarations within their nested lexical … … 50 50 \begin{cfa} 51 51 int i, j; 52 int & ri = i, &&rri = ri;52 int @&@ ri = i, @&&@ rri = ri; 53 53 rri = 3; // auto-dereference assign to i 54 &ri = &j; // rebindable54 @&@ri = @&@j; // rebindable 55 55 ri = 5; // assign to j 56 56 \end{cfa} … … 64 64 65 65 In general, operator names in \CFA are constructed by bracketing an operator 66 token with @?@, which indicates the position of the arguments. For example, 67 infixed multiplication is @?*?@ while prefix dereference is @*?@. 68 This syntax make it easy to tell the difference between prefix operations 69 (such as @++?@) andpost-fix operations (@?++@).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 (@?++@). 70 70 71 71 The special name for a constructor is @?{}@, which comes from the 72 initialization syntax in C. That initialation syntax is also the operator 73 form. \CFA will generate a constructor call each time a variable is declared, 74 passing the initialization arguments to the constructort. 75 \begin{cfa} 76 struct Example { ... }; 77 void ?{}(Example & this) { ... } 72 initialization syntax in C. The special name for a destructor is @^{}@, where 73 the @^@ has no special meaning. 74 % 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 78 79 { 79 Example a; 80 Example b = {}; 81 } 82 void ?{}(Example & this, char first, int num) { ... } 83 { 84 Example c = {'a', 2}; 85 } 86 \end{cfa} 87 Both @a@ and @b@ will be initalized with the first constructor (there is no 88 general way to skip initialation) while @c@ will be initalized with the 89 second. 90 91 % I don't like the \^{} symbol but $^\wedge$ isn't better. 92 Similarly destructors use the special name @^?{}@ (the @^@ has no special 93 meaning). They can be called explicatly as well but normally they are 94 implicitly called on a variable when it goes out of scope. 95 \begin{cfa} 96 void ^?{}(Example & this) { ... } 97 { 98 Example d; 99 } // <- implicit destructor call 100 \end{cfa} 101 No operator name is restricted in what function signatures they may be bound 102 to although most of the forms cannot be called in operator form. Some 103 ``near-misses" will generate warnings. 104 105 Whenever a type is defined, \CFA will create a default zero-argument 106 constructor, a copy constructor, a series of argument-per-field constructors 107 and a destructor. All user constructors are defined after this. 108 Because operators are never part of the type definition they may be added 109 at any time, including on built-in types. 80 T s = @{@ ... @}@; // same constructor/initialization braces 81 } // destructor call automatically generated 82 \end{cfa} 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). 110 92 111 93 \section{Polymorphism} … … 123 105 works on any type @T@: 124 106 \begin{cfa} 125 forall( T ) T identity( T val ) { return val; } 126 int forty_two = identity( 42 ); 127 char capital_a = identity( 'A' ); 128 \end{cfa} 129 Each use of a polymorphic declaration will resolve its polymorphic parameters 130 (in this case, just @T@) to concrete types (@int@ in the first use and @char@ 131 in the second). 107 @forall( T )@ @T@ identity( @T@ val ) { return val; } 108 int forty_two = identity( 42 ); // T bound to int, forty_two == 42 109 \end{cfa} 132 110 133 111 To allow a polymorphic function to be separately compiled, the type @T@ must be … … 137 115 types used in a function, \eg: 138 116 \begin{cfa} 139 forall( T | { void do_once(T); })117 forall( T @| { void do_once(T); }@) // assertion 140 118 void do_twice(T value) { 141 119 do_once(value); 142 120 do_once(value); 143 121 } 144 \end{cfa} 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. 145 128 146 129 A polymorphic function can be used in the same way as a normal function. The … … 149 132 all the variables replaced with the concrete types from the arguments) is 150 133 defined at a call site. 151 \begin{cfa}152 void do_once(int i) { ... }153 int i;154 do_twice(i);155 \end{cfa}156 Any object with a type fulfilling the assertion may be passed as an argument to157 a @do_twice@ call.158 134 159 135 Note, a function named @do_once@ is not required in the scope of @do_twice@ to … … 162 138 call. 163 139 \begin{cfa} 164 void do_once(double y) { ... } 140 void do_once(double y) { ... } // global 165 141 int quadruple(int x) { 166 void do_once(int y) { y = y * 2; } 167 do_twice(x); 142 void do_once(int y) { y = y * 2; } // local 143 do_twice(x); // using local "do_once" 168 144 return x; 169 145 } … … 174 150 function. The matched assertion function is then passed as a function pointer 175 151 to @do_twice@ and called within it. 176 The global definition of @do_once@ is ignored.177 152 178 153 To avoid typing long lists of assertions, constraints can be collect into … … 186 161 and the @forall@ list in the previous example is replaced with the trait. 187 162 \begin{cfa} 188 forall(dtype T | done_once(T))163 forall(dtype T | @done_once(T)@) 189 164 \end{cfa} 190 165 In general, a trait can contain an arbitrary number of assertions, both … … 197 172 declarations instead of parameters, returns, and local variable declarations. 198 173 \begin{cfa} 199 forall(dtype T)174 forall(dtype @T@) 200 175 struct node { 201 node( T) * next; // generic linked node202 T* data;203 } 204 node( int) inode;205 \end{cfa} 206 The generic type @node(T)@ is an example of a polymorphic type usage. Like \Cpp207 template usage, a polymorphic type usage must specify a type parameter.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. 208 183 209 184 There are many other polymorphism features in \CFA but these are the ones used … … 244 219 Each coroutine has a @main@ function, which takes a reference to a coroutine 245 220 object and returns @void@. 246 \begin{cfa} 247 void main(CountUp & this) { 248 for (unsigned int next = 0 ; true ; ++next) { 249 next = up; 250 suspend;$\label{suspend}$ 221 \begin{cfa}[numbers=left] 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; 251 228 } 252 229 } … … 277 254 @mutex@. 278 255 \begin{cfa} 279 void example(MonitorA & mutex argA, MonitorB & mutexargB);256 void example(MonitorA & @mutex@ argA, MonitorB & @mutex@ argB); 280 257 \end{cfa} 281 258 When the function is called, it implicitly acquires the monitor lock for all of -
doc/theses/andrew_beach_MMath/features.tex
r8d66610 r5407cdc 20 20 \subparagraph{Raise} 21 21 The raise is the starting point for exception handling. It marks the beginning 22 of exception handling by raisingan excepion, which passes it to22 of exception handling by \newterm{raising} an excepion, which passes it to 23 23 the EHM. 24 24 25 25 Some well known examples include the @throw@ statements of \Cpp and Java and 26 the \code {Python}{raise} statement from Python. In real systems a raise may27 preform some other work (such as memory management) but for the 28 purposes of thisoverview that can be ignored.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. 29 29 30 30 \subparagraph{Handle} … … 93 93 A handler labelled with any given exception can handle exceptions of that 94 94 type or any child type of that exception. The root of the exception hierarchy 95 (here \code {C}{exception}) acts as a catch-all, leaf types catch single types95 (here \codeC{exception}) acts as a catch-all, leaf types catch single types 96 96 and the exceptions in the middle can be used to catch different groups of 97 97 related exceptions. … … 101 101 between different sub-hierarchies. 102 102 This design is used in \CFA even though it is not a object-orientated 103 language ; so different tools are usedto create the hierarchy.103 language using different tools to create the hierarchy. 104 104 105 105 % Could I cite the rational for the Python IO exception rework? … … 123 123 \section{Virtuals} 124 124 Virtual types and casts are not part of \CFA's EHM nor are they required for 125 any EHM. 126 However the \CFA uses a hierarchy built with the virtual system as the basis 127 for exceptions and exception matching. 128 129 The virtual system would have ideally been part of \CFA before the work 130 on exception handling began, but unfortunately it was not. 131 Because of this only the features and framework needed for the EHM were 132 designed and implemented. Other features were considered to ensure that 133 the structure could accomidate other desirable features but they were not 134 implemented. 135 The rest of this section will only discuss the finalized portion of the 136 virtual system. 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. 137 130 138 131 The virtual system supports multiple ``trees" of types. Each tree is … … 150 143 It is important to note that these are virtual members, not virtual methods 151 144 of object-orientated programming, and can be of any type. 152 \CFA still supports virtual methods as a special case of virtual members. 153 Function pointers that take a pointer to the virtual type will be modified 154 with each level of inheritance so that refers to the new type. 155 This means an object can always be passed to a function in its virtual table 156 as if it were a method. 145 However, since \CFA has function pointers and they are allowed, virtual 146 members can be used to mimic virtual methods. 157 147 158 148 Each virtual type has a unique id. … … 185 175 While much of the virtual infrastructure is created, it is currently only used 186 176 internally for exception handling. The only user-level feature is the virtual 187 cast, which is the same as the \Cpp \ code{C++}{dynamic_cast}.177 cast, which is the same as the \Cpp \lstinline[language=C++]|dynamic_cast|. 188 178 \label{p:VirtualCast} 189 179 \begin{cfa} … … 207 197 \begin{cfa} 208 198 trait is_exception(exceptT &, virtualT &) { 209 // Numerous imaginary assertions.199 virtualT const & get_exception_vtable(exceptT *); 210 200 }; 211 201 \end{cfa} 212 202 The trait is defined over two types, the exception type and the virtual table 213 type. Each exception type should have but a single virtual table type. 214 Now there are no actual assertions in this trait because the trait system 215 actually can't express them (adding such assertions would be part of 216 completing the virtual system). The imaginary assertions would probably come 217 from a trait defined by the virtual system, and state that the exception type 218 is a virtual type, is a decendent of @exception_t@ (the base exception type) 219 and note its virtual table type. 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. 220 218 221 219 % I did have a note about how it is the programmer's responsibility to make … … 237 235 Both traits ensure a pair of types are an exception type and its virtual table 238 236 and defines one of the two default handlers. The default handlers are used 239 as fallbacks and are discussed in detail in \ vref{s:ExceptionHandling}.237 as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}. 240 238 241 239 However, all three of these traits can be tricky to use directly. … … 353 351 for particular exception type. 354 352 The global default termination handler performs a cancellation 355 (see \vref{s:Cancellation})on the current stack with the copied exception.353 \see{\VRef{s:Cancellation}} on the current stack with the copied exception. 356 354 357 355 \subsection{Resumption} … … 428 426 429 427 \subsubsection{Resumption Marking} 430 \label{s:ResumptionMarking}431 428 A key difference between resumption and termination is that resumption does 432 429 not unwind the stack. A side effect that is that when a handler is matched … … 475 472 The symmetry between resumption termination is why this pattern was picked. 476 473 Other patterns, such as marking just the handlers that caught, also work but 477 lack the symmetry means there are morerules to remember.474 lack the symmetry means there are less rules to remember. 478 475 479 476 \section{Conditional Catch} … … 560 557 \end{cfa} 561 558 If there are further handlers after this handler only the first version will 562 check them. If multiple handlers on a single try block that could handle the563 sameexception the translations get more complex but they are equivilantly559 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 564 561 powerful. 565 562 … … 636 633 and the current stack is 637 634 unwound. After that it depends one which stack is being cancelled. 638 639 \ paragraph{Main Stack}635 \begin{description} 636 \item[Main Stack:] 640 637 The main stack is the one used by the program main at the start of execution, 641 638 and is the only stack in a sequential program. … … 648 645 to, so it would have be explicitly managed. 649 646 650 \ paragraph{Thread Stack}647 \item[Thread Stack:] 651 648 A thread stack is created for a \CFA @thread@ object or object that satisfies 652 649 the @is_thread@ trait. … … 674 671 Also you can always add an explicit join if that is the desired behaviour. 675 672 676 \ paragraph{Coroutine Stack}673 \item[Coroutine Stack:] 677 674 A coroutine stack is created for a @coroutine@ object or object that 678 675 satisfies the @is_coroutine@ trait. … … 688 685 (in terms of coroutine state) called resume on this coroutine, so the message 689 686 is passed to the latter. 687 \end{description} -
doc/theses/andrew_beach_MMath/future.tex
r8d66610 r5407cdc 110 110 \section{Zero-Cost Try} 111 111 \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 compiler112 code rather than assembler code \see{\VPageref{p:zero-cost}}. When the compiler 113 113 does create its own assembly (or LLVM byte-code), then zero-cost try-statements 114 114 are possible. The downside of zero-cost try-statements is the LSDA complexity, -
doc/theses/andrew_beach_MMath/implement.tex
r8d66610 r5407cdc 9 9 % Virtual table rules. Virtual tables, the pointer to them and the cast. 10 10 While the \CFA virtual system currently has only one public feature, virtual 11 cast (see the virtual cast feature \vpageref{p:VirtualCast}),12 su bstantial structure is required to support it,13 and provide features for exception handling and the standardlibrary.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. 14 14 15 15 \subsection{Virtual Type} 16 Virtual types only have one change to their structure: the addition of a 17 pointer to the virtual table, which is called the \emph{virtual-table pointer}. 18 Internally, the field is called @virtual_table@. 19 The field is fixed after construction. It is always the first field in the 20 structure so that its location is always known. 21 \todo{Talk about constructors for virtual types (after they are working).} 22 23 This is what binds an instance of a virtual type to a virtual table. This 24 pointer can be used as an identity check. It can also be used to access the 25 virtual table and the virtual members there. 26 27 \subsection{Type Id} 28 Every virtual type has a unique id. 29 Type ids can be compared for equality (the types reperented are the same) 30 or used to access the type's type information. 31 The type information currently is only the parent's type id or, if the 32 type has no parent, zero. 33 34 The id's are implemented as pointers to the type's type information instance. 35 Derefencing the pointer gets the type information. 36 By going back-and-forth between the type id and 37 the type info one can find every ancestor of a virtual type. 38 It also pushes the issue of creating a unique value (for 39 the type id) to the problem of creating a unique instance (for type 40 information) which the linker can solve. 41 42 Advanced linker support is required because there is no place that appears 43 only once to attach the type information to. There should be one structure 44 definition but it is included in multiple translation units. Each virtual 45 table definition should be unique but there are an arbitrary number of thoses. 46 So the special section prefix \texttt{.gnu.linkonce} is used. 47 With a unique suffix (making the entire section name unique) the linker will 48 remove multiple definition making sure only one version exists after linking. 49 Then it is just a matter of making sure there is a unique name for each type. 50 51 This is done in three phases. 52 The first phase is to generate a new structure definition to store the type 53 information. The layout is the same in each case, just the parent's type id, 54 but the types are changed. 55 The structure's name is change, it is based off the virtual type's name, and 56 the type of the parent's type id. 57 If the virtual type is polymorphic then the type information structure is 58 polymorphic as well, with the same polymorphic arguments. 59 60 The second phase is to generate an instance of the type information with a 61 almost unique name, generated by mangling the virtual type name. 62 63 The third phase is implicit with \CFA's overloading scheme. \CFA mangles 64 names with type information so that all of the symbols exported to the linker 65 are unique even if in \CFA code they are the same. Having two declarations 66 with the same name and same type is forbidden because it is impossible for 67 overload resolution to pick between them. This is why a unique type is 68 generated for each virtual type. 69 Polymorphic information is included in this mangling so polymorphic 70 types will have seperate instances for each set of polymorphic arguments. 71 72 \begin{cfa} 73 struct TYPE_ID_TYPE { 74 PARENT_ID_TYPE const * parent; 75 }; 76 77 __attribute__((cfa_linkonce)) 78 TYPE_ID_TYPE const TYPE_ID_NAME = { 79 &PARENT_ID_NAME, 80 }; 81 \end{cfa} 82 83 \subsubsection{cfa\_linkonce Attribute} 84 Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}. 85 This attribute can be put on an object or function definition 86 (any global declaration with a name and a type). 87 This allows you to define that object or function multiple times. 88 All definitions should have the link-once attribute on them and all should 89 be identical. 90 91 The simplist way to use it is to put a definition in a header where the 92 forward declaration would usually go. 93 This is how it is used for type-id instances. There was is no unique location 94 associated with a type except for the type definition which is in a header. 95 This allows the unique type-id object to be generated there. 96 97 Internally @cfa_linkonce@ removes all @section@ attributes 98 from the declaration (as well as itself) and replaces them with 99 @section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the 100 mangled name of the object. 101 The prefix \texttt{.gnu.linkonce} in section names is recognized by the 102 linker. If two of these sections with the same name, including everything 103 that comes after the special prefix, then only one will be used and the other 104 will be discarded. 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. 105 27 106 28 \subsection{Virtual Table} 107 Each virtual type has a virtual table type that stores its type id and 108 virtual members. 109 Each virtual type instance is bound to a table instance that is filled with 110 the values of virtual members. 111 Both the layout of the fields and their value are decided by the rules given 112 below. 113 114 The layout always comes in three parts. 115 The first section is just the type id at the head of the table. It is always 116 there to ensure that 117 The second section are all the virtual members of the parent, in the same 118 order as they appear in the parent's virtual table. Note that the type may 119 change slightly as references to the ``this" will change. This is limited to 120 inside pointers/references and via function pointers so that the size (and 121 hence the offsets) are the same. 122 The third section is similar to the second except that it is the new virtual 123 members introduced at this level in the hierarchy. 124 125 \begin{figure} 126 \begin{cfa} 127 type_id 128 parent_field0 129 ... 130 parent_fieldN 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 / 131 64 child_field0 132 65 ... 133 66 child_fieldN 134 \end{cfa} 135 \caption{Virtual Table Layout} 136 \label{f:VirtualTableLayout} 137 \todo*{Improve the Virtual Table Layout diagram.} 138 \end{figure} 139 140 The first and second sections together mean that every virtual table has a 141 prefix that has the same layout and types as its parent virtual table. 142 This, combined with the fixed offset to the virtual table pointer, means that 143 for any virtual type it doesn't matter if we have it or any of its 144 descendants, it is still always safe to access the virtual table through 145 the virtual table pointer. 146 From there it is safe to check the type id to identify the exact type of the 147 underlying object, access any of the virtual members and pass the object to 148 any of the method-like virtual members. 149 150 When a virtual table is declared the user decides where to declare it and its 151 name. The initialization of the virtual table is entirely automatic based on 152 the context of the declaration. 153 154 The type id is always fixed, each virtual table type will always have one 155 exactly one possible type id. 156 The virtual members are usually filled in by resolution. The best match for 157 a given name and type at the declaration site is filled in. 158 There are two exceptions to that rule: the @size@ field is the type's size 159 and is set to the result of a @sizeof@ expression, the @align@ field is the 160 type's alignment and similarly uses an @alignof@ expression. 161 162 \subsubsection{Concurrency Integration} 67 \end{verbatim} 68 \todo{Refine the diagram} 69 70 % For each virtual type, a virtual table is constructed. This is both a new type 71 % and an instance of that type. Other instances of the type could be created 72 % but the system doesn't use them. So this section will go over the creation of 73 % the type and the instance. 74 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} 163 109 Coroutines and threads need instances of @CoroutineCancelled@ and 164 110 @ThreadCancelled@ respectively to use all of their functionality. When a new … … 166 112 the instance is created as well. The definition of the virtual table is created 167 113 at the definition of the main function. 168 169 \begin{figure} 170 \begin{cfa} 171 coroutine Example { 172 // fields 173 } 174 \end{cfa} 175 176 \begin{cfa} 177 __attribute__((cfa_linkonce)) 178 struct __cfatid_struct_CoroutineCancelled(Example) 179 __cfatid_CoroutineCancelled = { 180 &EXCEPTION_TYPE_ID, 181 }; 182 extern CoroutineCancelled_vtable _default_vtable_object_declaration; 183 extern CoroutineCancelled_vtable & _default_vtable; 184 \end{cfa} 185 186 \begin{cfa} 187 void main(Example & this) { 188 // body 189 } 190 \end{cfa} 191 192 \begin{cfa} 193 CoroutineCancelled_vtable _default_vtable_object_declaration = { 194 __cfatid_CoroutineCancelled, 195 // Virtual member initialization. 196 }; 197 198 CoroutineCancelled_vtable & _default_vtable = 199 &_default_vtable_object_declaration; 200 \end{cfa} 201 \caption{Concurrency Transformations} 202 \label{f:ConcurrencyTransformations} 203 \end{figure} 204 \todo{Improve Concurrency Transformations figure.} 114 \end{sloppypar} 205 115 206 116 \subsection{Virtual Cast} … … 209 119 % The C-cast is just to make sure the generated code is correct so the rest of 210 120 % the section is about that function. 211 The function is implemented in the standard library and has the following 212 signature: 121 The function is 213 122 \begin{cfa} 214 123 void * __cfa__virtual_cast( 215 struct __cfa vir_type_tdparent,216 struct __cfa vir_type_idconst * child );124 struct __cfa__parent_vtable const * parent, 125 struct __cfa__parent_vtable const * const * child ); 217 126 \end{cfa} 218 The type id of target type of the virtual cast is passed in as @parent@ and 219 the cast target is passed in as @child@. 220 221 For C generation both arguments and the result are wrapped with type casts. 222 There is also an internal store inside the compiler to make sure that the 223 target type is a virtual type. 224 % It also checks for conflicting definitions. 225 226 The virtual cast either returns the original pointer as a new type or null. 227 So the function just does the parent check and returns the approprate value. 228 The parent check is a simple linear search of child's ancestors using the 229 type information. 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. 230 149 231 150 \section{Exceptions} … … 242 161 243 162 Stack unwinding is the process of removing stack frames (activations) from the 244 stack. On function entry and return, unwinding is handled directly by the 245 call/return code embedded in the function. 246 In many cases the position of the instruction pointer (relative to parameter 247 and local declarations) is enough to know the current size of the stack 248 frame. 249 250 Usually, the stack-frame size is known statically based on parameter and 251 local variable declarations. Even with dynamic stack-size the information 252 to determain how much of the stack has to be removed is still contained 253 within the function. 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. 254 169 Allocating/deallocating stack space is usually an $O(1)$ operation achieved by 255 170 bumping the hardware stack-pointer up or down as needed. 256 Constructing/destructing values on the stack takes longer put in terms of 257 figuring out what needs to be done is of similar complexity. 258 259 Unwinding across multiple stack frames is more complex because that 260 information is no longer contained within the current function. 261 With seperate compilation a function has no way of knowing what its callers 262 are so it can't know how large those frames are. 263 Without altering the main code path it is also hard to pass that work off 264 to the caller. 171 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. 265 187 266 188 The traditional unwinding mechanism for C is implemented by saving a snap-shot … … 269 191 reseting to a snap-shot of an arbitrary but existing function frame on the 270 192 stack. It is up to the programmer to ensure the snap-shot is valid when it is 271 reset and that all required clean-up from the unwound stacks is preformed. 272 This approach is fragile and forces a work onto the surounding code. 273 274 With respect to that work forced onto the surounding code, 275 many languages define clean-up actions that must be taken when certain 276 sections of the stack are removed. Such as when the storage for a variable 277 is removed from the stack or when a try statement with a finally clause is 278 (conceptually) popped from the stack. 279 None of these should be handled by the user, that would contradict the 280 intention of these features, so they need to be handled automatically. 281 282 To safely remove sections of the stack the language must be able to find and 283 run these clean-up actions even when removing multiple functions unknown at 284 the beginning of the unwinding. 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. 285 208 286 209 One of the most popular tools for stack management is libunwind, a low-level … … 292 215 \subsection{libunwind Usage} 293 216 Libunwind, accessed through @unwind.h@ on most platforms, is a C library that 294 provides \C pp-style stack-unwinding. Its operation is divided into two phases:217 provides \CC-style stack-unwinding. Its operation is divided into two phases: 295 218 search and cleanup. The dynamic target search -- phase 1 -- is used to scan the 296 219 stack and decide where unwinding should stop (but no unwinding occurs). The … … 303 226 LSDA can contain any information but conventionally it is a table with entries 304 227 representing regions of the function and what has to be done there during 305 unwinding. These regions are bracketed by instruction addresses. If the228 unwinding. These regions are bracketed by the instruction pointer. If the 306 229 instruction pointer is within a region's start/end, then execution is currently 307 230 executing in that region. Regions are used to mark out the scopes of objects … … 315 238 316 239 The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and 317 attaches a personality function to each function. 318 In plain C (which \CFA currently compiles down to) this 240 attaches its personality function. However, this 319 241 flag 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.} 320 244 \begin{cfa} 321 245 void clean_up( int * var ) { ... } 322 246 int avar __attribute__(( cleanup(clean_up) )); 323 247 \end{cfa} 324 The attribue is used on a variable and specifies a function, 325 in this case @clean_up@, run when the variable goes out of scope. 326 This is enough to mimic destructors, but not try statements which can effect 327 the unwinding. 328 329 To get full unwinding support all of this has to be done directly with 330 assembly and assembler directives. Partiularly the cfi directives 331 \texttt{.cfi\_lsda} and \texttt{.cfi\_personality}. 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. 332 254 333 255 \subsection{Personality Functions} … … 346 268 \end{lstlisting} 347 269 The @action@ argument is a bitmask of possible actions: 348 \begin{enumerate} [topsep=5pt]270 \begin{enumerate} 349 271 \item 350 272 @_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function … … 369 291 @_UA_FORCE_UNWIND@ specifies a forced unwind call. Forced unwind only performs 370 292 the cleanup phase and uses a different means to decide when to stop 371 (see \vref{s:ForcedUnwind}).293 \see{\VRef{s:ForcedUnwind}}. 372 294 \end{enumerate} 373 295 374 296 The @exception_class@ argument is a copy of the 375 \code{C}{exception}'s @exception_class@ field. 376 This a number that identifies the exception handling mechanism that created 377 the 378 379 The \code{C}{exception} argument is a pointer to the user 380 provided storage object. It has two public fields: the @exception_class@, 381 which is described above, and the @exception_cleanup@ function. 382 The clean-up function is used by the EHM to clean-up the exception if it 383 should need to be freed at an unusual time, it takes an argument that says 384 why it had to be cleaned up. 297 \lstinline[language=C]|exception|'s @exception_class@ field. 298 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. 385 304 386 305 The @context@ argument is a pointer to an opaque type passed to helper … … 390 309 that can be passed several places in libunwind. It includes a number of 391 310 messages for special cases (some of which should never be used by the 392 personality function) and error codes . However, unless otherwise noted,the311 personality function) and error codes but unless otherwise noted the 393 312 personality function should always return @_URC_CONTINUE_UNWIND@. 394 313 … … 405 324 @_URC_END_OF_STACK@. 406 325 407 Second, when a handler is matched, raise exception moves to the clean-up408 phase and walks the stack a second time.326 Second, when a handler is matched, raise exception continues onto the cleanup 327 phase. 409 328 Once again, it calls the personality functions of each stack frame from newest 410 329 to oldest. This pass stops at the stack frame containing the matching handler. … … 419 338 Forced Unwind is the other central function in libunwind. 420 339 \begin{cfa} 421 _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *,340 _Unwind_Reason_Code _Unwind_ForcedUnwind( _Unwind_Exception *, 422 341 _Unwind_Stop_Fn, void *); 423 342 \end{cfa} … … 461 380 Each stack must have its own exception context. In a sequential \CFA program, 462 381 there is only one stack with a single global exception-context. However, when 463 the library @libcfathread@ is linked, there are multiple stacks andeach382 the library @libcfathread@ is linked, there are multiple stacks where each 464 383 needs its own exception context. 465 384 466 The exception context should be retrieved by calling thefunction385 General access to the exception context is provided by function 467 386 @this_exception_context@. For sequential execution, this function is defined as 468 387 a weak symbol in the \CFA system-library, @libcfa@. When a \CFA program is … … 471 390 472 391 The sequential @this_exception_context@ returns a hard-coded pointer to the 473 global ex ception context.392 global execption context. 474 393 The concurrent version adds the exception context to the data stored at the 475 base of each stack. When @this_exception_context@ is called ,it retrieves the394 base of each stack. When @this_exception_context@ is called it retrieves the 476 395 active stack and returns the address of the context saved there. 477 396 … … 480 399 % catches. Talk about GCC nested functions. 481 400 482 \CFA termination exceptions use libunwind heavily because they match \Cpp 483 \Cppexceptions closely. The main complication for \CFA is that the401 Termination exceptions use libunwind heavily because it matches the intended 402 use from \CC exceptions closely. The main complication for \CFA is that the 484 403 compiler generates C code, making it very difficult to generate the assembly to 485 404 form the LSDA for try blocks or destructors. … … 492 411 per-exception storage. 493 412 494 \begin{figure} 413 [Quick ASCII diagram to get started.] 495 414 \begin{verbatim} 496 415 Fixed Header | _Unwind_Exception <- pointer target … … 501 420 V ... 502 421 \end{verbatim} 503 \caption{Exception Layout} 504 \label{f:ExceptionLayout} 505 \end{figure} 506 \todo*{Convert the exception layout to an actual diagram.} 507 508 Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}). 509 The first component is a fixed-sized data structure that contains the 422 423 Exceptions are stored in variable-sized blocks. 424 The first component is a fixed sized data structure that contains the 510 425 information for libunwind and the exception system. The second component is an 511 426 area of memory big enough to store the exception. Macros with pointer arthritic … … 513 428 @_Unwind_Exception@ to the entire node. 514 429 515 Multipe exceptions can exist at the same time because exceptions can be 516 raised inside handlers, destructors and finally blocks. 517 Figure~\vref{f:MultipleExceptions} shows a program that has multiple 518 exceptions active at one time. 519 Each time an exception is thrown and caught the stack unwinds and the finally 520 clause runs. This will throw another exception (until @num_exceptions@ gets 521 high enough) which must be allocated. The previous exceptions may not be 522 freed because the handler/catch clause has not been run. 523 So the EHM must keep them alive while it allocates exceptions for new throws. 524 525 \begin{figure} 526 \centering 527 % Andrew: Figure out what these do and give them better names. 528 \newsavebox{\myboxA} 529 \newsavebox{\myboxB} 530 \begin{lrbox}{\myboxA} 531 \begin{lstlisting}[language=CFA,{moredelim=**[is][\color{red}]{@}{@}}] 532 unsigned num_exceptions = 0; 533 void throws() { 534 try { 535 try { 536 ++num_exceptions; 537 throw (Example){table}; 538 } finally { 539 if (num_exceptions < 3) { 540 throws(); 541 } 542 } 543 } catch (exception_t *) { 544 --num_exceptions; 545 } 546 } 547 int main() { 548 throws(); 549 } 550 \end{lstlisting} 551 \end{lrbox} 552 553 \begin{lrbox}{\myboxB} 554 \begin{lstlisting} 555 \end{lstlisting} 556 \end{lrbox} 557 558 {\usebox\myboxA} 559 \hspace{25pt} 560 {\usebox\myboxB} 561 562 \caption{Multiple Exceptions} 563 \label{f:MultipleExceptions} 564 \end{figure} 565 \todo*{Work on multiple exceptions code sample.} 566 567 All exceptions are stored in nodes which are then linked together in lists, 568 one list per stack, with the 430 All of these nodes are linked together in a list, one list per stack, with the 569 431 list head stored in the exception context. Within each linked list, the most 570 432 recently thrown exception is at the head followed by older thrown … … 577 439 exception, the copy function, and the free function, so they are specific to an 578 440 exception type. The size and copy function are used immediately to copy an 579 exception into managed memory. After the exception is handled , the free580 function is used to clean up the exception and then the entire node is 581 passed to freeso the memory can be given back to the heap.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. 582 444 583 445 \subsection{Try Statements and Catch Clauses} … … 592 454 calls them. 593 455 Because this function is known and fixed (and not an arbitrary function that 594 happens to contain a try statement) ,the LSDA can be generated ahead456 happens to contain a try statement) this means the LSDA can be generated ahead 595 457 of time. 596 458 597 459 Both the LSDA and the personality function are set ahead of time using 598 embedded assembly. This assembly code is handcrafted using C @asm@ statements 599 and contains 460 embedded assembly. This is handcrafted using C @asm@ statements and contains 600 461 enough information for the single try statement the function repersents. 601 462 … … 626 487 nested functions and all other functions besides @__cfaehm_try_terminate@ in 627 488 \CFA use the GCC personality function and the @-fexceptions@ flag to generate 628 the LSDA. 629 Using this pattern, \CFA implements destructors with the cleanup attribute. 630 631 \begin{figure} 632 \begin{cfa} 633 try { 634 // TRY BLOCK 635 } catch (Exception1 * name1 ; check(name1)) { 636 // CATCH BLOCK 1 637 } catch (Exception2 * name2) { 638 // CATCH BLOCK 2 639 } 640 \end{cfa} 641 642 \begin{cfa} 643 void try(void) { 644 // TRY BLOCK 645 } 646 int match(exception_t * __exception_inst) { 647 { 648 Exception1 * name1; 649 if (name1 = (virtual Exception1 *)__exception_inst && check(name1)) { 650 return 1; 651 } 652 } 653 { 654 Exception2 * name2; 655 if (name2 = (virtual Exception2 *)__exception_inst) { 656 return 2; 657 } 658 } 659 return 0; 660 } 661 void catch(exception_t * __exception_inst, int __handler_index) { 662 switch (__handler_index) { 663 case 1: 664 { 665 Exception1 * name1 = (virtual Exception1 *)__exception_inst; 666 // CATCH BLOCK 1 667 } 668 return; 669 case 2: 670 { 671 Exception2 * name2 = (virtual Exception2 *)__exception_inst; 672 // CATCH BLOCK 2 673 } 674 return; 675 } 676 } 677 { 678 __cfaehm_try_terminate(try, catch, match); 679 } 680 \end{cfa} 681 682 \caption{Termination Transformation} 683 \label{f:TerminationTransformation} 684 \todo*{Improve (compress?) Termination Transformations.} 685 \end{figure} 489 the LSDA. This allows destructors to be implemented with the cleanup attribute. 686 490 687 491 \section{Resumption} 688 492 % The stack-local data, the linked list of nodes. 689 493 690 Resumption simpler to implement than termination 691 because there is no stack unwinding. 692 Instead of storing the data in a special area using assembly, 693 there is just a linked list of possible handlers for each stack, 694 with each node on the list reperenting a try statement on the stack. 695 696 The head of the list is stored in the exception context. 697 The nodes are stored in order, with the more recent try statements closer 698 to the head of the list. 699 Instead of traversing the stack resumption handling traverses the list. 700 At each node the EHM checks to see if the try statement the node repersents 701 can handle the exception. If it can, then the exception is handled and 702 the operation finishes, otherwise the search continues to the next node. 703 If the search reaches the end of the list without finding a try statement 704 that can handle the exception the default handler is executed and the 705 operation finishes. 706 707 In each node is a handler function which does most of the work there. 708 The handler function is passed the raised the exception and returns true 709 if the exception is handled and false if it cannot be handled here. 710 711 For each @catchResume@ clause the handler function will: 712 check to see if the raised exception is a descendant type of the declared 713 exception type, if it is and there is a conditional expression then it will 714 run the test, if both checks pass the handling code for the clause is run 715 and the function returns true, otherwise it moves onto the next clause. 716 If this is the last @catchResume@ clause then instead of moving onto 717 the next clause the function returns false as no handler could be found. 718 719 \begin{figure} 720 \begin{cfa} 721 try { 722 // TRY BLOCK 723 } catchResume (Exception1 * name1 ; check(name1)) { 724 // CATCH BLOCK 1 725 } catchResume (Exception2 * name2) { 726 // CATCH BLOCK 2 727 } 728 \end{cfa} 729 730 \begin{cfa} 731 bool handle(exception_t * __exception_inst) { 732 { 733 Exception1 * name1; 734 if (name1 = (virtual Exception1 *)__exception_inst && check(name1)) { 735 // CATCH BLOCK 1 736 return 1; 737 } 738 } 739 { 740 Exception2 * name2; 741 if (name2 = (virtual Exception2 *)__exception_inst) { 742 // CATCH BLOCK 2 743 return 2; 744 } 745 } 746 return false; 747 } 748 struct __try_resume_node __resume_node 749 __attribute__((cleanup( __cfaehm_try_resume_cleanup ))); 750 __cfaehm_try_resume_setup( &__resume_node, handler ); 751 \end{cfa} 752 753 \caption{Resumption Transformation} 754 \label{f:ResumptionTransformation} 755 \todo*{Improve (compress?) Resumption Transformations.} 756 \end{figure} 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. 757 509 758 510 % Recursive Resumption Stuff: 759 Search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of 760 the stack 511 Search skipping \see{\VPageref{p:searchskip}}, which ignores parts of the stack 761 512 already examined, is accomplished by updating the front of the list as the 762 search continues. Before the handler at a node is called ,the head of the list513 search continues. Before the handler at a node is called the head of the list 763 514 is updated to the next node of the current node. After the search is complete, 764 515 successful or not, the head of the list is reset. … … 773 524 stack -- the first one points over all the checked handlers -- and the ordering 774 525 is maintained. 775 776 \begin{figure}777 \begin{minipage}[l][][b]{0,2\textwidth}778 \begin{verbatim}779 780 781 X <-782 |783 V784 X785 |786 V787 X788 \end{verbatim}789 Initial State790 \end{minipage}791 \begin{minipage}[l][][b]{0,2\textwidth}792 \begin{verbatim}793 794 795 X796 |797 V798 X <-799 |800 V801 X802 \end{verbatim}803 Handler Found804 \end{minipage}805 \begin{minipage}[l][][b]{0,2\textwidth}806 \begin{verbatim}807 X <-808 /809 / X810 | |811 \ V812 X813 |814 V815 X816 \end{verbatim}817 Try Block Added818 \end{minipage}819 \begin{minipage}[l][][b]{0,2\textwidth}820 \begin{verbatim}821 822 823 X <-824 |825 V826 X827 |828 V829 X830 \end{verbatim}831 Handler Done832 \end{minipage}833 \caption{Resumption Marking}834 \label{f:ResumptionMarking}835 \todo*{Convert Resumption Marking into a line figure.}836 \end{figure}837 526 838 527 \label{p:zero-cost} … … 851 540 \section{Finally} 852 541 % Uses destructors and GCC nested functions. 853 A finally clause is placed into a GCC nested-function with a unique name, 854 and no arguments or return values. 855 This nested function is then set as the cleanup 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 856 544 function of an empty object that is declared at the beginning of a block placed 857 545 around the context of the associated @try@ statement. 858 546 859 The rest is handled by GCC. The try block and all handlers are inside th is547 The rest is handled by GCC. The try block and all handlers are inside the 860 548 block. At completion, control exits the block and the empty object is cleaned 861 549 up, which runs the function that contains the finally code. … … 865 553 866 554 Cancellation also uses libunwind to do its stack traversal and unwinding, 867 however it uses a different primary function :@_Unwind_ForcedUnwind@. Details868 of its interface can be found in the Section~\vref{s:ForcedUnwind}.555 however it uses a different primary function @_Unwind_ForcedUnwind@. Details 556 of its interface can be found in the \VRef{s:ForcedUnwind}. 869 557 870 558 The first step of cancellation is to find the cancelled stack and its type: … … 872 560 pointer and the current thread pointer, and every thread stores a pointer to 873 561 its main coroutine and the coroutine it is currently executing. 874 \todo*{Consider adding a description of how threads are coroutines.} 875 876 If a the current thread's main and current coroutines are the same then the877 current stack is a thread stack. Furthermore it is easy to compare the 878 current thread to the main thread to see if they are the same. And if this 879 is not a thread stack then it must be a coroutine stack.562 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. 880 568 881 569 However, if the threading library is not linked, the sequential execution is on … … 886 574 Regardless of how the stack is chosen, the stop function and parameter are 887 575 passed to the forced-unwind function. The general pattern of all three stop 888 functions is the same: they continue unwinding until the end of stack and889 then preform their transfer.576 functions is the same: they continue unwinding until the end of stack when they 577 do there primary work. 890 578 891 579 For main stack cancellation, the transfer is just a program abort. -
doc/theses/andrew_beach_MMath/uw-ethesis.tex
r8d66610 r5407cdc 66 66 % Tip: Photographs should be cropped and compressed so as not to be too large. 67 67 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 68 74 % ====================================================================== 69 75 % D O C U M E N T P R E A M B L E … … 81 87 } 82 88 83 % Does nothing, ignores \href tags (redefined by hyperref package). 84 \newcommand{\href}[1]{#1} 89 % Some LaTeX commands I define for my own nomenclature. 90 % If you have to, it's easier to make changes to nomenclature once here than 91 % in a million places throughout your thesis! 92 \newcommand{\package}[1]{\textbf{#1}} % package names in bold text 93 \newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font 94 \newcommand{\href}[1]{#1} % does nothing, but defines the command so the 95 % print-optimized version will ignore \href tags (redefined by hyperref pkg). 96 % Anything defined here may be redefined by packages added below... 85 97 86 98 % For a nomenclature (optional; available from ctan.org) … … 93 105 % Removes large sections of the document. 94 106 \usepackage{comment} 95 % Adds todo commands. 96 \usepackage{todo} 97 % cfa macros used in the document 98 \usepackage{cfalab} 99 % allow global and individual modification of spacing 100 \usepackage{enumitem} 101 % Improved reference tools. 102 \usepackage[nospace]{varioref} 107 % Adds todos (Must be included after comment.) 108 \usepackage{todonotes} 103 109 104 110 % Hyperlinks make it very easy to navigate an electronic document. … … 145 151 146 152 % Exception to the rule of hyperref being the last add-on package 147 \usepackage[ toc,abbreviations]{glossaries-extra}153 \usepackage[automake,toc,abbreviations]{glossaries-extra} 148 154 % If glossaries-extra is not in your LaTeX distribution, get it from CTAN 149 155 % (http://ctan.org/pkg/glossaries-extra), although it's supposed to be in … … 202 208 \makeglossaries 203 209 204 % listings package configuation: 205 \lstMakeShortInline@ 206 \lstset{language=CFA,style=cfacommon,basicstyle=\linespread{0.9}\tt} 207 \lstset{moredelim=**[is][\protect\color{red}]{@}{@}} 210 % cfa macros used in the document 211 %\usepackage{cfalab} 212 % I'm going to bring back eventually. 213 \makeatletter 214 % Combines all \CC* commands: 215 \newrobustcmd*\Cpp[1][\xspace]{\cfalab@Cpp#1} 216 \newcommand\cfalab@Cpp{C\kern-.1em\hbox{+\kern-.25em+}} 217 % Optional arguments do not work with pdf string. (Some fix-up required.) 218 \pdfstringdefDisableCommands{\def\Cpp{C++}} 219 220 % Wrappers for inline code snippits. 221 \newrobustcmd*\codeCFA[1]{\lstinline[language=CFA]{#1}} 222 \newrobustcmd*\codeC[1]{\lstinline[language=C]{#1}} 223 \newrobustcmd*\codeCpp[1]{\lstinline[language=C++]{#1}} 224 \newrobustcmd*\codePy[1]{\lstinline[language=Python]{#1}} 225 226 % Colour text, formatted in LaTeX style instead of TeX style. 227 \newcommand*\colour[2]{{\color{#1}#2}} 228 \makeatother 229 230 \input{common} 231 % CFA code-style for all languages 232 \CFAStyle 233 % CFA default lnaguage 234 \lstset{language=CFA,basicstyle=\linespread{0.9}\tt} 208 235 % Annotations from Peter: 209 236 \newcommand{\PAB}[1]{{\color{blue}PAB: #1}} … … 235 262 % Tip: Putting each sentence on a new line is a way to simplify later editing. 236 263 %---------------------------------------------------------------------- 237 \input{intro}238 264 \input{existing} 239 265 \input{features} 240 266 \input{implement} 267 %\input{unwinding} 241 268 \input{future} 242 269 … … 298 325 \phantomsection % allows hyperref to link to the correct page 299 326 300 \todos301 302 327 %---------------------------------------------------------------------- 303 328 \end{document} % end of logical document -
doc/theses/mubeen_zulfiqar_MMath/AllocDS1.fig
r8d66610 r5407cdc 8 8 -2 9 9 1200 2 10 6 4 200 1575 4500 172511 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 1650 20 20 4275 1650 4295 165012 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4350 1650 20 20 4350 1650 4370 165013 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4425 1650 20 20 4425 1650 4445 165010 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 14 14 -6 15 6 2850 2475 3150 2850 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 16 21 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 17 22 1 1 1.00 45.00 90.00 18 2925 2475 2925 270023 3675 2100 3675 2325 19 24 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 20 2850 2700 3150 2700 3150 2850 2850 2850 2850 270025 3600 2325 3900 2325 3900 2475 3600 2475 3600 2325 21 26 -6 22 6 4350 2475 4650 285027 6 5100 2100 5400 2475 23 28 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 24 29 1 1 1.00 45.00 90.00 25 4425 2475 4425 270030 5175 2100 5175 2325 26 31 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 27 4350 2700 4650 2700 4650 2850 4350 2850 4350 270032 5100 2325 5400 2325 5400 2475 5100 2475 5100 2325 28 33 -6 29 6 3600 2475 3825 315034 6 4350 2100 4575 2775 30 35 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 31 36 1 1 1.00 45.00 90.00 32 3675 2475 3675 270037 4425 2100 4425 2325 33 38 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 34 3600 2700 3825 2700 3825 2850 3600 2850 3600 270039 4350 2325 4575 2325 4575 2475 4350 2475 4350 2325 35 40 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 36 3600 3000 3825 3000 3825 3150 3600 3150 3600 300041 4350 2625 4575 2625 4575 2775 4350 2775 4350 2625 37 42 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 38 43 1 1 1.00 45.00 90.00 39 3675 2775 3675 300044 4425 2400 4425 2625 40 45 -6 41 6 4875 3600 5175 3750 42 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 3675 20 20 4950 3675 4970 3675 43 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 3675 20 20 5025 3675 5045 3675 44 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 3675 20 20 5100 3675 5120 3675 45 -6 46 6 4875 2325 5175 2475 47 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 2400 20 20 4950 2400 4970 2400 48 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 2400 20 20 5025 2400 5045 2400 49 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 2400 20 20 5100 2400 5120 2400 50 -6 51 6 5625 2325 5925 2475 52 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 2400 20 20 5700 2400 5720 2400 53 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2400 20 20 5775 2400 5795 2400 54 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2400 20 20 5850 2400 5870 2400 55 -6 56 6 5625 3600 5925 3750 57 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 3675 20 20 5700 3675 5720 3675 58 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3675 20 20 5775 3675 5795 3675 59 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3675 20 20 5850 3675 5870 3675 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 60 50 -6 61 51 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 62 2 400 2100 2400 255052 2700 1950 3900 1950 63 53 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 64 2550 2100 2550 255054 3000 1800 3000 2175 65 55 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 66 2700 2100 2700 255056 3150 1800 3150 2175 67 57 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 68 2850 2100 2850 255058 3300 1800 3300 2175 69 59 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 70 3 000 2100 3000 255060 3450 1800 3450 2175 71 61 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 72 3600 2100 3600 255062 3600 1800 3600 2175 73 63 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 74 3 900 2100 3900 255064 3750 1800 3750 2175 75 65 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 76 4 050 2100 4050 255066 4200 1950 5400 1950 77 67 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 78 4 200 2100 4200 255068 4350 1800 4350 2175 79 69 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 80 4 350 2100 4350 255070 4500 1800 4500 2175 81 71 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 82 4 500 2100 4500 255072 4650 1800 4650 2175 83 73 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 84 3300 1500 3300 180074 4800 1800 4800 2175 85 75 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 86 3600 1500 3600 180076 4950 1800 4950 2175 87 77 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 88 3900 1500 3900 1800 78 5100 1800 5100 2175 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 89 87 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 90 3 000 1500 4800 1500 4800 1800 3000 1800 3000 150088 3750 1200 5550 1200 5550 1500 3750 1500 3750 1200 91 89 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2 92 90 1 1 1.00 45.00 90.00 93 3 225 1650 2625 210091 3975 1350 3375 1800 94 92 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 95 93 1 1 1.00 45.00 90.00 96 3 150 1650 2550 210094 3900 1350 3300 1800 97 95 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 98 96 1 1 1.00 45.00 90.00 99 3450 1650 4050 210097 4200 1350 4800 1800 100 98 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2 101 99 1 1 1.00 45.00 90.00 102 3375 1650 3975 2100100 4125 1350 4725 1800 103 101 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 104 2100 2100 2100 2550 105 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 106 1950 2250 3150 2250 107 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 108 3450 2250 4650 2250 102 2850 1800 2850 2175 109 103 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 110 1950 2100 3150 2100 3150 2550 1950 2550 1950 2100104 2700 1800 3900 1800 3900 2175 2700 2175 2700 1800 111 105 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 112 3450 2100 4650 2100 4650 2550 3450 2550 3450 2100 113 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 114 2250 2100 2250 2550 115 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 116 3750 2100 3750 2550 106 4200 1800 5400 1800 5400 2175 4200 2175 4200 1800 117 107 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 118 108 1 1 1.00 45.00 90.00 119 2 025 2475 2025 2700109 2775 2100 2775 2325 120 110 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 121 111 1 1 1.00 45.00 90.00 122 2 025 2775 2025 3000112 2775 2400 2775 2625 123 113 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 124 1950 3000 2100 3000 2100 3150 1950 3150 1950 3000114 2700 2625 2850 2625 2850 2775 2700 2775 2700 2625 125 115 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 126 1950 2700 2100 2700 2100 2850 1950 2850 1950 2700116 2700 2325 2850 2325 2850 2475 2700 2475 2700 2325 127 117 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3 128 118 1 1 1.00 45.00 90.00 129 1950 3750 2700 3750 2700 3525119 2700 3375 3450 3375 3450 3150 130 120 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 131 1950 3525 3150 3525 3150 3900 1950 3900 1950 3525121 2700 3150 3900 3150 3900 3525 2700 3525 2700 3150 132 122 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3 133 123 1 1 1.00 45.00 90.00 134 3450 3750 4200 3750 4200 3525124 4200 3375 4950 3375 4950 3150 135 125 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 136 3450 3525 4650 3525 4650 3900 3450 3900 3450 3525126 4200 3150 5400 3150 5400 3525 4200 3525 4200 3150 137 127 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3 138 128 1 1 1.00 45.00 90.00 139 3 150 4650 4200 4650 4200 4275129 3900 4350 4950 4350 4950 3900 140 130 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 141 3150 4275 4650 4275 4650 4875 3150 4875 3150 4275 142 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 143 1950 2400 3150 2400 144 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 145 3450 2400 4650 2400 146 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 147 5400 2100 5400 3900 148 4 2 0 50 -1 0 11 0.0000 2 120 300 1875 2250 lock\001 149 4 1 0 50 -1 0 12 0.0000 2 135 1935 3900 1425 N kernel-thread buckets\001 150 4 1 0 50 -1 0 12 0.0000 2 195 810 4425 2025 heap$_2$\001 151 4 1 0 50 -1 0 12 0.0000 2 195 810 2175 2025 heap$_1$\001 152 4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2400 size\001 153 4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2550 free\001 154 4 1 0 50 -1 0 12 0.0000 2 180 825 2550 3450 local pool\001 155 4 0 0 50 -1 0 12 0.0000 2 135 360 3525 3700 lock\001 156 4 0 0 50 -1 0 12 0.0000 2 135 360 3225 4450 lock\001 157 4 2 0 50 -1 0 12 0.0000 2 135 600 1875 3000 free list\001 158 4 1 0 50 -1 0 12 0.0000 2 180 825 4050 3450 local pool\001 159 4 1 0 50 -1 0 12 0.0000 2 180 1455 3900 4200 global pool (sbrk)\001 160 4 0 0 50 -1 0 12 0.0000 2 135 360 2025 3700 lock\001 161 4 1 0 50 -1 0 12 0.0000 2 180 720 6450 3150 free pool\001 162 4 1 0 50 -1 0 12 0.0000 2 180 390 6450 2925 heap\001 131 3900 3900 5400 3900 5400 4575 3900 4575 3900 3900 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 -
doc/theses/mubeen_zulfiqar_MMath/AllocDS2.fig
r8d66610 r5407cdc 8 8 -2 9 9 1200 2 10 6 2850 2 100 3150 225011 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 21 75 20 20 2925 2175 2945 217512 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 21 75 20 20 3000 2175 3020 217513 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 21 75 20 20 3075 2175 3095 217510 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 14 14 -6 15 6 4050 2 100 4350 225016 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 21 75 20 20 4125 2175 4145 217517 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 21 75 20 20 4200 2175 4220 217518 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 21 75 20 20 4275 2175 4295 217515 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 19 19 -6 20 6 4650 2 100 4950 225021 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 21 75 20 20 4725 2175 4745 217522 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 21 75 20 20 4800 2175 4820 217523 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 21 75 20 20 4875 2175 4895 217520 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 24 24 -6 25 6 3450 2 100 3750 225026 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 21 75 20 20 3525 2175 3545 217527 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 21 75 20 20 3600 2175 3620 217528 1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 21 75 20 20 3675 2175 3695 217525 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 29 29 -6 30 6 3300 21 75 3600 255030 6 3300 2100 3600 2475 31 31 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 32 32 1 1 1.00 45.00 90.00 33 3375 21 75 3375 240033 3375 2100 3375 2325 34 34 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 35 3300 2 400 3600 2400 3600 2550 3300 2550 3300 240035 3300 2325 3600 2325 3600 2475 3300 2475 3300 2325 36 36 -6 37 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 238 3150 1800 3150 225039 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 240 2850 1800 2850 225041 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 242 4650 1800 4650 225043 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 244 4950 1800 4950 225045 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 246 4500 1725 4500 225047 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 248 5100 1725 5100 225049 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 250 3450 1800 3450 225051 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 252 3750 1800 3750 225053 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 254 3300 1725 3300 225055 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 256 3900 1725 3900 225057 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 258 5250 1800 5250 225059 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 260 5400 1800 5400 225061 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 262 5550 1800 5550 225063 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 264 5700 1800 5700 225065 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 266 5850 1800 5850 225067 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 268 2700 1725 2700 225069 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 270 1 1 1.00 45.00 90.0071 3375 1275 3375 157572 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 273 1 1 1.00 45.00 90.0074 2700 1275 2700 157575 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 276 1 1 1.00 45.00 90.0077 2775 1275 2775 157578 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 279 1 1 1.00 45.00 90.0080 5175 1275 5175 157581 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 282 1 1 1.00 45.00 90.0083 5625 1275 5625 157584 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 285 1 1 1.00 45.00 90.0086 3750 1275 3750 157587 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 288 1 1 1.00 45.00 90.0089 3825 1275 3825 157590 37 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 91 38 2700 1950 6000 1950 92 39 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 93 2700 2100 6000 2100 40 3150 1800 3150 2175 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 94 71 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 95 2700 1800 6000 1800 6000 2 250 2700 22502700 180072 2700 1800 6000 1800 6000 2175 2700 2175 2700 1800 96 73 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 97 74 1 1 1.00 45.00 90.00 98 2775 21 75 2775 240075 2775 2100 2775 2325 99 76 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 100 77 1 1 1.00 45.00 90.00 101 2775 24 75 2775 270078 2775 2400 2775 2625 102 79 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 103 2700 2 700 2850 2700 2850 2850 2700 2850 2700 270080 2700 2625 2850 2625 2850 2775 2700 2775 2700 2625 104 81 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 105 2700 2 400 2850 2400 2850 2550 2700 2550 2700 240082 2700 2325 2850 2325 2850 2475 2700 2475 2700 2325 106 83 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 107 84 1 1 1.00 45.00 90.00 108 4575 21 75 4575 240085 4575 2100 4575 2325 109 86 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 110 4500 2 400 5025 2400 5025 2550 4500 2550 4500 240087 4500 2325 5025 2325 5025 2475 4500 2475 4500 2325 111 88 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3 112 89 1 1 1.00 45.00 90.00 113 3600 3525 4650 3525 4650 3 15090 3600 3525 4650 3525 4650 3075 114 91 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 115 3600 3150 5100 3150 5100 3750 3600 3750 3600 3150 116 4 2 0 50 -1 0 11 0.0000 2 120 300 2625 1950 lock\001 92 3600 3075 5100 3075 5100 3750 3600 3750 3600 3075 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 117 95 4 1 0 50 -1 0 10 0.0000 2 150 1155 3000 1725 N$\\times$S$_1$\001 118 96 4 1 0 50 -1 0 10 0.0000 2 150 1155 3600 1725 N$\\times$S$_2$\001 97 4 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 119 101 4 1 0 50 -1 0 12 0.0000 2 180 390 4425 1500 heap\001 120 4 2 0 50 -1 0 12 0.0000 2 135 1140 2550 1425 kernel threads\001121 4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2100 size\001122 4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2250 free\001123 4 2 0 50 -1 0 12 0.0000 2 135 600 2625 2700 free list\001124 4 0 0 50 -1 0 12 0.0000 2 135 360 3675 3325 lock\001125 4 1 0 50 -1 0 12 0.0000 2 180 1455 4350 3075 global pool (sbrk)\001126 4 1 0 50 -1 0 10 0.0000 2 150 1110 4800 1725 N$\\times$S$_t$\001 -
doc/theses/mubeen_zulfiqar_MMath/Makefile
r8d66610 r5407cdc 15 15 16 16 .PHONY: all clean 17 .PRECIOUS: %.dvi %.ps # do not delete intermediate files18 17 19 18 ### Commands: 20 19 LATEX = TEXINPUTS=${TEXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${BUILD} 21 20 BIBTEX = BIBINPUTS=${BIBLIB} bibtex 22 #GLOSSARY =INDEXSTYLE=${BUILD} makeglossaries-lite21 #GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite 23 22 24 23 ### Rules and Recipes: … … 26 25 all: ${DOC} 27 26 28 ${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC: %.fig=%.tex} ${BIBSRC} Makefile | ${BUILD}27 ${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC:.fig=.tex} ${BIBSRC} Makefile | ${BUILD} 29 28 ${LATEX} ${BASE} 30 29 ${BIBTEX} ${BUILD}/${BASE} -
doc/theses/mubeen_zulfiqar_MMath/allocator.tex
r8d66610 r5407cdc 1 1 2 \chapter{Allocator} 2 3 \noindent4 ====================5 6 Writing Points:7 \begin{itemize}8 \item9 Objective of @uHeapLmmm@.10 \item11 Design philosophy.12 \item13 Background and previous design of @uHeapLmmm@.14 \item15 Distributed design of @uHeapLmmm@.16 17 ----- SHOULD WE GIVE IMPLEMENTATION DETAILS HERE? -----18 19 \PAB{Maybe. There might be an Implementation chapter.}20 \item21 figure.22 \item23 Advantages of distributed design.24 \end{itemize}25 26 The new features added to @uHeapLmmm@ (incl. @malloc_size@ routine)27 \CFA alloc interface with examples.28 \begin{itemize}29 \item30 Why did we need it?31 \item32 The added benefits.33 \end{itemize}34 35 ----- SHOULD WE GIVE PERFORMANCE AND USABILITY COMPARISON OF DIFFERENT INTERFACES THAT WE TRIED? -----36 37 \PAB{Often Performance is its own chapter. I added one for now.}38 39 Performance evaluation using u-benchmark suite.40 41 \noindent42 ====================43 3 44 4 \newpage 45 5 \paragraph{Design 1: Decentralized} 46 Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the @sbrk@area.6 Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the sbrk area. 47 7 Kernel threads (KT) are assigned to the N heaps. 48 8 When KTs $\le$ N, the heaps are uncontented. -
doc/theses/mubeen_zulfiqar_MMath/background.tex
r8d66610 r5407cdc 1 1 \chapter{Background} 2 2 3 \noindent4 ====================5 6 Writing Points:7 \begin{itemize}8 \item9 Classification of benchmarks.10 \item11 Literature review of current benchmarks.12 \item13 Features and limitations.14 \item15 Literature review of current memory allocators.16 \item17 Breakdown of memory allocation techniques.18 \item19 Features and limitations.20 \end{itemize}21 22 \noindent23 ====================24 25 3 \cite{Wasik08} -
doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex
r8d66610 r5407cdc 1 1 \chapter{Benchmarks} 2 3 \noindent4 ====================5 6 Writing Points:7 \begin{itemize}8 \item9 Performance matrices of memory allocation.10 \item11 Aim of micro benchmark suite.12 13 ----- SHOULD WE GIVE IMPLEMENTATION DETAILS HERE? -----14 15 \PAB{For the benchmarks, yes.}16 \item17 A complete list of benchmarks in micro benchmark suite.18 \item19 One detailed section for each benchmark in micro benchmark suite including:20 21 \begin{itemize}22 \item23 The introduction of the benchmark.24 \item25 Figure.26 \item27 Results with popular memory allocators.28 \end{itemize}29 30 \item31 Summarize performance of current memory allocators.32 \end{itemize}33 34 \noindent35 ==================== -
doc/theses/mubeen_zulfiqar_MMath/conclusion.tex
r8d66610 r5407cdc 1 1 \chapter{Conclusion} 2 3 \noindent4 ====================5 6 Writing Points:7 \begin{itemize}8 \item9 Summarize u-benchmark suite.10 \item11 Summarize @uHeapLmmm@.12 \item13 Make recommendations on memory allocator design.14 \end{itemize}15 16 \noindent17 ==================== -
doc/theses/mubeen_zulfiqar_MMath/intro.tex
r8d66610 r5407cdc 1 1 \chapter{Introduction} 2 3 \noindent4 ====================5 6 Writing Points:7 \begin{itemize}8 \item9 Introduce dynamic memory allocation with brief background.10 \item11 Scope of the thesis.12 \item13 Importance of memory allocation and micro-benchmark suite.14 \item15 Research problem.16 \item17 Research objectives.18 \item19 The vision behind cfa-malloc.20 \item21 An outline of the thesis.22 \end{itemize}23 24 \noindent25 ==================== -
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex
r8d66610 r5407cdc 84 84 \usepackage{graphicx} 85 85 \usepackage{comment} % Removes large sections of the document. 86 \usepackage{todonotes} % Adds todos (Must be included after comment.) 86 87 87 88 % Hyperlinks make it very easy to navigate an electronic document. … … 106 107 colorlinks=true, % false: boxed links; true: colored links 107 108 linkcolor=blue, % color of internal links 108 citecolor= blue, % color of links to bibliography109 citecolor=green, % color of links to bibliography 109 110 filecolor=magenta, % color of file links 110 urlcolor= blue% color of external links111 urlcolor=cyan % color of external links 111 112 } 112 113 \ifthenelse{\boolean{PrintVersion}}{ % for improved print quality, change some hyperref options … … 167 168 \CFAStyle % CFA code-style for all languages 168 169 \lstset{language=CFA,basicstyle=\linespread{0.9}\tt} % CFA default language 169 \newcommand{\PAB}[1]{{\color{red}PAB: #1}}170 170 171 171 %====================================================================== … … 194 194 \input{allocator} 195 195 \input{benchmarks} 196 \input{performance}197 196 \input{conclusion} 198 197 -
doc/user/Makefile
r8d66610 r5407cdc 61 61 62 62 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \ 63 ${Macros}/common. sty${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}63 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build} 64 64 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 65 65 if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi … … 68 68 -${BibTeX} ${Build}/${basename $@} 69 69 # Some citations reference others so run again to resolve these citations 70 #${LaTeX} ${basename $@}.tex70 ${LaTeX} ${basename $@}.tex 71 71 -${BibTeX} ${Build}/${basename $@} 72 72 # Make index from *.aux entries and input index at end of document … … 75 75 ${LaTeX} ${basename $@}.tex 76 76 # Run again to get index title into table of contents 77 #${LaTeX} ${basename $@}.tex77 ${LaTeX} ${basename $@}.tex 78 78 79 79 ## Define the default recipes. -
doc/user/user.tex
r8d66610 r5407cdc 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : S at May 8 08:51:33 202114 %% Update Count : 506213 %% Last Modified On : Sun Apr 25 19:03:03 2021 14 %% Update Count : 4951 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 65 65 % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^ 66 66 % math escape $...$ (dollar symbol) 67 \usepackage{common} % common CFA document macros 68 %\input{common} % common CFA document macros 67 \input{common} % common CFA document macros 69 68 \setlength{\gcolumnposn}{3in} 70 69 \CFAStyle % use default CFA format-style … … 586 585 For example, the octal ©0© or hexadecimal ©0x© prefix may end with an underscore ©0_377© or ©0x_ff©; 587 586 the exponent infix ©E© may start or end with an underscore ©1.0_E10©, ©1.0E_10© or ©1.0_E_10©; 588 the type suffixes ©U©, ©L©, \etcmay start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.587 the type suffixes ©U©, ©L©, etc. may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©. 589 588 \end{enumerate} 590 589 It 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). … … 1571 1570 \end{cquote} 1572 1571 1573 All type qualifiers, \eg ©const©, ©volatile©, \etc, are used in the normal way with the new declarations and also appear left to right, \eg: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: 1574 1573 \begin{cquote} 1575 1574 \begin{tabular}{@{}l@{\hspace{1em}}l@{\hspace{1em}}l@{}} … … 1591 1590 \end{tabular} 1592 1591 \end{cquote} 1593 All declaration qualifiers, \eg ©extern©, ©static©, \etc, are used in the normal way with the new declarations but can only appear at the start of a \CFA routine declaration,\footnote{\label{StorageClassSpecifier}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} 1594 1593 The 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: 1595 1594 \begin{cquote} … … 3148 3147 also, it is unnecessary to specify all the fields of a struct in a multiple record-field tuple. 3149 3148 3150 Since tuple-index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member-access expressions to restructure a tuple (\eg, rearrange components, drop components, duplicate components, \etc).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.). 3151 3150 \begin{cfa} 3152 3151 [ int, int, long, double ] x; … … 3313 3312 3314 3313 \section{Tuples} 3315 \label{tuples}3316 3314 3317 3315 In C and \CFA, lists of elements appear in several contexts, such as the parameter list for a routine call. … … 3422 3420 3423 3421 \subsection{Tuple Coercions} 3424 \label{tuple coercions}\label{coercions!tuple}3425 3422 3426 3423 There are four coercions that can be performed on tuples and tuple variables: closing, opening, flattening and structuring. … … 3467 3464 3468 3465 \subsection{Mass Assignment} 3469 \label{mass assignment}\label{assignment!mass}3470 3466 3471 3467 \CFA permits assignment to several variables at once using mass assignment~\cite{CLU}. … … 3508 3504 3509 3505 \subsection{Multiple Assignment} 3510 \label{multiple assignment}\label{assignment!multiple}3511 3506 3512 3507 \CFA also supports the assignment of several values at once, known as multiple assignment~\cite{CLU,Galletly96}. … … 3550 3545 3551 3546 \subsection{Cascade Assignment} 3552 \index{cascade assignment}\index{assignment!cascade}3553 3547 3554 3548 As in C, \CFA mass and multiple assignments can be cascaded, producing cascade assignment. … … 3570 3564 \section{Stream I/O Library} 3571 3565 \label{s:StreamIOLibrary} 3572 \index{input }\index{output}3573 \index{stream library} \index{library!stream}3566 \index{input/output stream library} 3567 \index{stream library} 3574 3568 3575 3569 The 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. 3576 3570 Stream I/O can be implicitly or explicitly formatted. 3577 Implicit formatting means \CFA selects the output or input format for values that match es the variable's type.3571 Implicit formatting means \CFA selects the output or input format for values that match with the type of a variable. 3578 3572 Explicit formatting means additional information is specified to augment how an output or input of value is interpreted. 3579 \CFA formatting i ncorporates ideas from C ©printf©, \CC ©stream© manipulators, and Python implicit spacing and newline.3573 \CFA formatting is a cross between C ©printf© and \CC ©cout© manipulators, and Python implicit spacing and newline. 3580 3574 Specifically: 3581 3575 \begin{itemize} … … 3590 3584 Hence, it is common programming practice to toggle manipulators on and then back to the default to prevent downstream side-effects. 3591 3585 Without this programming style, errors occur when moving prints, as manipulator effects incorrectly flow into the new location. 3592 Furthermore, to guarantee no side-effects, manipulator values must be saved and restored across function calls. 3593 \item 3594 \CFA has more sophisticated implicit value spacingthan Python, plus implicit newline at the end of a print.3586 (To guarantee no side-effects, manipulator values must be saved and restored across function calls.) 3587 \item 3588 \CFA has more sophisticated implicit spacing between values than Python, plus implicit newline at the end of a print. 3595 3589 \end{itemize} 3596 3597 The standard polymorphic I/Os stream are ©stdin©/©sin© (input), ©stdout©/©sout© and ©stderr©/©serr© (output) (like C++ ©cin©/©cout©/©cerr©).3598 Polymorphic streams ©exit© and ©abort© provide implicit program termination without and with generating a stack trace and core file.3599 Stream ©exit© implicitly returns ©EXIT_FAILURE© to the shell.3600 \begin{cfa}3601 ®exit® | "x (" | x | ") negative value."; // terminate and return EXIT_FAILURE to shell3602 ®abort® | "x (" | x | ") negative value."; // terminate and generate stack trace and core file3603 \end{cfa}3604 Note, \CFA stream variables ©stdin©, ©stdout©, ©stderr©, ©exit©, and ©abort© overload C variables ©stdin©, ©stdout©, ©stderr©, and functions ©exit© and ©abort©, respectively.3605 3590 The \CFA header file for the I/O library is \Indexc{fstream.hfa}. 3606 3607 3608 \subsection{Basic I/O}3609 3591 3610 3592 For implicit formatted output, the common case is printing a series of variables separated by whitespace. … … 3619 3601 \begin{cfa} 3620 3602 3621 cout << x ®<< " "® << y ®<< " "® << z<< endl;3603 cout << x ®<< " "® << y ®<< " "® << z << endl; 3622 3604 \end{cfa} 3623 3605 & … … 3671 3653 \end{tabular} 3672 3654 \end{cquote} 3673 Input and output use a uniform operator, ©|©, rather than \CC's ©>>© and ©<<© input/output operators.3655 Input and output use a uniform operator, ©|©, rather than separate operators, as in ©>>© and ©<<© for \CC. 3674 3656 There 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. 3675 3657 … … 3716 3698 \end{cquote} 3717 3699 3718 \VRef[Figure]{f:CFACommand-LineProcessing} shows idiomatic \CFA command-line processing and copying an input file to an output file.3719 Note, a stream variable may be copied because it is a reference to an underlying stream data-structures.3720 All I/O errors are handles as exceptions, but end-of-file is not an exception as C programmers are use to explicitly checking for it.3721 3722 \begin{figure}3723 \begin{cfa}3724 #include ®<fstream.hfa>®3725 3726 int main( int argc, char * argv[] ) {3727 ®ifstream® in = stdin; $\C{// copy default files}$3728 ®ofstream® out = stdout;3729 3730 try {3731 choose ( argc ) {3732 case 2, 3:3733 ®open®( in, argv[1] ); $\C{// open input file first as output creates file}$3734 if ( argc == 3 ) ®open®( out, argv[2] ); $\C{// do not create output unless input opens}$3735 case 1: ; $\C{// use default files}$3736 default:3737 ®exit® | "Usage" | argv[0] | "[ input-file (default stdin) "3738 "[ output-file (default stdout) ] ]";3739 } // choose3740 } 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 } // try3746 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 } // for3755 } // main3756 \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 \item3764 \Indexc{fail} tests the stream error-indicator, returning nonzero if it is set.3765 \item3766 \Indexc{clear} resets the stream error-indicator.3767 \item3768 \Indexc{flush} (©ofstream© only) causes any unwritten data for a stream to be written to the file.3769 \item3770 \Indexc{eof} (©ifstream© only) tests the end-of-file indicator for the stream pointed to by stream.3771 Returns true if the end-of-file indicator is set, otherwise false.3772 \item3773 \Indexc{open} binds the file with ©name© to a stream accessed with ©mode© (see ©fopen©).3774 \item3775 \Indexc{close} flushes the stream and closes the file.3776 \item3777 \Indexc{write} (©ofstream© only) write ©size© bytes to the stream.3778 The bytes are written lazily to file when internal buffers fill.3779 Eager buffer writes are done with ©flush©3780 \item3781 \Indexc{read} (©ifstream© only) read ©size© bytes to the stream.3782 \item3783 \Indexc{ungetc} (©ifstream© only) pushes the character back to the input stream.3784 Pushed-back characters returned by subsequent reads in the reverse order of pushing.3785 \end{itemize}3786 The constructor functions:3787 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]3788 \item3789 create an unbound stream, which is subsequently bound to a file with ©open©.3790 \item3791 create a bound stream to the associated file with given ©mode©.3792 \end{itemize}3793 The destructor closes the stream.3794 3795 \begin{figure}3796 \begin{cfa}3797 // *********************************** ofstream ***********************************3798 3799 bool fail( ofstream & );$\indexc{fail}\index{ofstream@©ofstream©!©fail©}$3800 void clear( ofstream & );$\indexc{clear}\index{ofstream@©ofstream©!©clear©}$3801 int flush( ofstream & );$\indexc{flush}\index{ofstream@©ofstream©!©flush©}$3802 void open( ofstream &, const char name[], const char mode[] = "w" );$\indexc{open}\index{ofstream@©ofstream©!©open©}$3803 void close( ofstream & );$\indexc{close}\index{ofstream@©ofstream©!©close©}$3804 ofstream & write( ofstream &, const char data[], size_t size );$\indexc{write}\index{ofstream@©ofstream©!©write©}$3805 3806 void ?{}( ofstream & );$\index{ofstream@©ofstream©!©?{}©}$3807 void ?{}( ofstream &, const char name[], const char mode[] = "w" );3808 void ^?{}( ofstream & );$\index{ofstream@©ofstream©!©^?{}©}$3809 3810 // *********************************** ifstream ***********************************3811 3812 bool fail( ifstream & is );$\indexc{fail}\index{ifstream@©ifstream©!©fail©}$3813 void clear( ifstream & );$\indexc{clear}\index{ifstream@©ifstream©!©clear©}$3814 bool eof( ifstream & is );$\indexc{eof}\index{ifstream@©ifstream©!©eof©}$3815 void open( ifstream & is, const char name[], const char mode[] = "r" );$\indexc{open}\index{ifstream@©ifstream©!©open©}$3816 void close( ifstream & is );$\indexc{close}\index{ifstream@©ifstream©!©close©}$3817 ifstream & read( ifstream & is, char data[], size_t size );$\indexc{read}\index{ifstream@©ifstream©!©read©}$3818 ifstream & ungetc( ifstream & is, char c );$\indexc{unget}\index{ifstream@©ifstream©!©unget©}$3819 3820 void ?{}( ifstream & is );$\index{ifstream@©ifstream©!©?{}©}$3821 void ?{}( ifstream & is, const char name[], const char mode[] = "r" );3822 void ^?{}( ifstream & is );$\index{ifstream@©ifstream©!©^?{}©}$3823 \end{cfa}3824 \caption{Stream Functions}3825 \label{f:StreamFunctions}3826 \end{figure}3827 3700 3828 3701 … … 3973 3846 3974 3847 \item 3975 \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} toggle printing the separator with respect to the next printed item, and then return to the global sep arator setting.3848 \Indexc{sepOn}\index{manipulator!sepOn@©sepOn©} and \Indexc{sepOff}\index{manipulator!sepOff@©sepOff©} toggle printing the separator with respect to the next printed item, and then return to the global seperator setting. 3976 3849 \begin{cfa}[belowskip=0pt] 3977 3850 sout | 1 | sepOff | 2 | 3; $\C{// turn off implicit separator for the next item}$ … … 4157 4030 sout | wd( 4, "ab" ) | wd( 3, "ab" ) | wd( 2, "ab" ); 4158 4031 \end{cfa} 4159 \begin{cfa}[showspaces=true,aboveskip=0pt ]4032 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4160 4033 ® ®34 ® ®34 34 4161 4034 ® ®4.000000 ® ®4.000000 4.000000 … … 4505 4378 \end{cfa} 4506 4379 4507 4508 \section{String Stream} 4509 4510 All the stream formatting capabilities are available to format text to/from a C string rather than to a stream file. 4511 \VRef[Figure]{f:StringStreamProcessing} shows writing (output) and reading (input) from a C string. 4512 \begin{figure} 4513 \begin{cfa} 4514 #include <fstream.hfa> 4515 #include <strstream.hfa> 4516 4517 int main() { 4518 enum { size = 256 }; 4519 char buf[size]; $\C{// output buffer}$ 4520 ®ostrstream osstr = { buf, size };® $\C{// bind output buffer/size}$ 4521 int i = 3, j = 5, k = 7; 4522 double x = 12345678.9, y = 98765.4321e-11; 4523 4524 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); $\C{// same lines of output}$ 4525 write( osstr ); 4526 printf( "%s", buf ); 4527 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); 4528 4529 char buf2[] = "12 14 15 3.5 7e4"; $\C{// input buffer}$ 4530 ®istrstream isstr = { buf2 };® 4531 isstr | i | j | k | x | y; 4532 sout | i | j | k | x | y; 4533 } 4534 \end{cfa} 4535 \caption{String Stream Processing} 4536 \label{f:StringStreamProcessing} 4537 \end{figure} 4538 4539 \VRef[Figure]{f:StringStreamFunctions} shows the string stream operations. 4540 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt] 4541 \item 4542 \Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default). 4543 \end{itemize} 4544 The constructor functions: 4545 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt] 4546 \item 4547 create a bound stream to a write buffer (©ostrstream©) of ©size© or a read buffer (©istrstream©) containing a C string terminated with ©'\0'©. 4548 \end{itemize} 4549 4550 \begin{figure} 4551 \begin{cfa} 4552 // *********************************** ostrstream *********************************** 4553 4554 ostrstream & write( ostrstream & os, FILE * stream = stdout ); 4555 4556 void ?{}( ostrstream &, char buf[], size_t size ); 4557 4558 // *********************************** istrstream *********************************** 4559 4560 void ?{}( istrstream & is, char buf[] ); 4561 \end{cfa} 4562 \caption{String Stream Functions} 4563 \label{f:StringStreamFunctions} 4564 \end{figure} 4380 \Textbf{WARNING:} ©printf©\index{printf@©printf©}, ©scanf©\index{scanf@©scanf©} and their derivatives are unsafe when used with user-level threading, as in \CFA. 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. 4565 4387 4566 4388 … … 5660 5482 \item 5661 5483 Package: a container to organize modules for distribution; It has attributes like name, author, 5662 version, dependences, \etc.5663 \item 5664 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, \etc.5484 version, dependences, etc. 5485 \item 5486 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, etc. 5665 5487 \end{itemize} 5666 5488 … … 5799 5621 5800 5622 A package is defined by putting a project description file, Do.prj, with one or more modules into a directory. 5801 This project description file contains the package's meta data, including package name, author, version, dependences, \etc.5623 This project description file contains the package's meta data, including package name, author, version, dependences, etc. 5802 5624 It should be in the root of the package directory. 5803 5625 … … 5856 5678 Module: a container to organize a set of related types and methods; It has a module name, and several interfaces visible from outside 5857 5679 \item 5858 Package: a container to organize modules for distribution; It has attributes like name, author, version, dependences, \etc.5859 \item 5860 Project: a working set for a \CFA project; It has attributes like name, author, version, dependences, \etc.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. 5861 5683 \end{itemize} 5862 5684 … … 8289 8111 \begin{cquote} 8290 8112 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}} 8291 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c @{}}{\textbf{C}} \\8113 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}} \\ 8292 8114 \hline 8293 8115 \begin{cfa} 8294 #include <gmp .hfa>$\indexc{gmp}$8116 #include <gmp>$\indexc{gmp}$ 8295 8117 int main( void ) { 8296 8118 sout | "Factorial Numbers"; -
libcfa/src/common.hfa
r8d66610 r5407cdc 10 10 // Created On : Wed Jul 11 17:54:36 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 5 14:02:04 202113 // Update Count : 1 812 // Last Modified On : Sat Aug 15 08:51:29 2020 13 // Update Count : 14 14 14 // 15 15 … … 67 67 68 68 static inline { 69 char min( char v1, char v2 ) { return v1 < v2 ? v1 : v2; } // optimization 70 int min( int v1, int v2 ) { return v1 < v2 ? v1 : v2; } 71 unsigned int min( unsigned int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; } 72 long int min( long int v1, long int v2 ) { return v1 < v2 ? v1 : v2; } 73 unsigned long int min( unsigned long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; } 74 long long int min( long long int v1, long long int v2 ) { return v1 < v2 ? v1 : v2; } 75 unsigned long long int min( unsigned long long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; } 69 char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization 70 intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization 71 uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization 76 72 forall( T | { int ?<?( T, T ); } ) 77 T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; }73 T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; } 78 74 79 char max( char v1, char v2 ) { return v1 > v2 ? v1 : v2; } // optimization 80 int max( int v1, int v2 ) { return v1 > v2 ? v1 : v2; } 81 unsigned int max( unsigned int v1, unsigned int v2 ) { return v1 > v2 ? v1 : v2; } 82 long int max( long int v1, long int v2 ) { return v1 > v2 ? v1 : v2; } 83 unsigned long int max( unsigned long int v1, unsigned long int v2 ) { return v1 > v2 ? v1 : v2; } 84 long long int max( long long int v1, long long int v2 ) { return v1 > v2 ? v1 : v2; } 85 unsigned long long int max( unsigned long long int v1, unsigned long long int v2 ) { return v1 > v2 ? v1 : v2; } 75 char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization 76 intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization 77 uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization 86 78 forall( T | { int ?>?( T, T ); } ) 87 T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; }79 T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; } 88 80 89 81 forall( T | { T min( T, T ); T max( T, T ); } ) -
libcfa/src/concurrency/alarm.cfa
r8d66610 r5407cdc 38 38 39 39 void __kernel_set_timer( Duration alarm ) { 40 alarm = max(alarm, 1`us); 41 itimerval otv @= { 0 }; 42 getitimer( ITIMER_REAL, &otv ); 43 Duration od = { otv.it_value }; 44 if(od == 0 || od > alarm) { 45 setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p ); 46 } 40 verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm`ns); 41 setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p ); 47 42 } 48 43 … … 51 46 //============================================================================================= 52 47 53 void ?{}( alarm_node_t & this, $thread * thrd, Duration alarm, Duration period) with( this ) { 54 this.initial = alarm; 55 this.period = period; 48 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period) with( this ) { 56 49 this.thrd = thrd; 57 this.timeval = __kernel_get_time() + alarm; 50 this.alarm = alarm; 51 this.period = period; 58 52 set = false; 59 53 type = User; 60 54 } 61 55 62 void ?{}( alarm_node_t & this, processor * proc, Duration alarm, Duration period ) with( this ) { 63 this.initial = alarm; 64 this.period = period; 56 void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ) with( this ) { 65 57 this.proc = proc; 66 this.timeval = __kernel_get_time() + alarm; 58 this.alarm = alarm; 59 this.period = period; 67 60 set = false; 68 61 type = Kernel; 69 62 } 70 void ?{}( alarm_node_t & this, Alarm_Callback callback, Duration alarm, Duration period ) with( this ) { 63 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ) with( this ) { 64 this.alarm = alarm; 65 this.period = period; 71 66 this.callback = callback; 72 this.initial = alarm;73 this.period = period;74 this.timeval = __kernel_get_time() + alarm;75 67 set = false; 76 68 type = Callback; … … 85 77 void insert( alarm_list_t * this, alarm_node_t * n ) { 86 78 alarm_node_t * it = & (*this)`first; 87 while( it && (n-> timeval > it->timeval) ) {79 while( it && (n->alarm > it->alarm) ) { 88 80 it = & (*it)`next; 89 81 } … … 113 105 lock( event_kernel->lock __cfaabi_dbg_ctx2 ); 114 106 { 115 /* paranoid */ verify( validate( alarms ) ); 107 verify( validate( alarms ) ); 108 bool first = ! & alarms`first; 116 109 117 Time curr = __kernel_get_time(); 118 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu -> %lu).\n", this, curr.tn, this->timeval.tn ); 110 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn ); 119 111 insert( &alarms, this ); 120 __kernel_set_timer( this->timeval - curr); 121 this->set = true; 112 if( first ) { 113 __kernel_set_timer( alarms`first.alarm - __kernel_get_time() ); 114 } 122 115 } 123 116 unlock( event_kernel->lock ); 117 this->set = true; 124 118 enable_interrupts(); 125 119 } … … 130 124 { 131 125 verify( validate( event_kernel->alarms ) ); 132 if (this->set) remove( *this ); 133 this->set = false; 126 remove( *this ); 134 127 } 135 128 unlock( event_kernel->lock ); 136 129 enable_interrupts(); 130 this->set = false; 137 131 } 138 132 … … 142 136 143 137 void sleep( Duration duration ) { 144 alarm_node_t node = { active_thread(), duration, 0`s };138 alarm_node_t node = { active_thread(), __kernel_get_time() + duration, 0`s }; 145 139 146 140 register_self( &node ); -
libcfa/src/concurrency/alarm.hfa
r8d66610 r5407cdc 46 46 47 47 struct alarm_node_t { 48 Duration initial;// time when alarm goes off49 Duration period; // if > 0 => period of alarm48 Time alarm; // time when alarm goes off 49 Duration period; // if > 0 => period of alarm 50 50 51 inline dlink(alarm_node_t);51 DLISTED_MGD_IMPL_IN(alarm_node_t) 52 52 53 53 union { 54 $thread * thrd; // thrd who created event55 processor * proc; // proc who created event56 Alarm_Callback callback; // callback to handle event54 $thread * thrd; // thrd who created event 55 processor * proc; // proc who created event 56 Alarm_Callback callback; // callback to handle event 57 57 }; 58 58 59 Time timeval; // actual time at which the alarm goes off 60 enum alarm_type type; // true if this is not a user defined alarm 61 bool set :1; // whether or not the alarm has be registered 59 bool set :1; // whether or not the alarm has be registered 60 enum alarm_type type; // true if this is not a user defined alarm 62 61 }; 63 P9_EMBEDDED( alarm_node_t, dlink(alarm_node_t))62 DLISTED_MGD_IMPL_OUT(alarm_node_t) 64 63 65 void ?{}( alarm_node_t & this, $thread * thrd, Durationalarm, Duration period );66 void ?{}( alarm_node_t & this, processor * proc, Durationalarm, Duration period );67 void ?{}( alarm_node_t & this, Alarm_Callback callback, Durationalarm, Duration period );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 ); 68 67 void ^?{}( alarm_node_t & this ); 69 68 70 typedef dlist(alarm_node_t ) alarm_list_t;69 typedef dlist(alarm_node_t, alarm_node_t) alarm_list_t; 71 70 72 71 void insert( alarm_list_t * this, alarm_node_t * n ); -
libcfa/src/concurrency/clib/cfathread.cfa
r8d66610 r5407cdc 27 27 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 28 28 } 29 30 extern Time __kernel_get_time();31 29 32 30 //================================================================================ … … 267 265 int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))) { 268 266 Time t = { *abstime }; 269 timespec curr; 270 clock_gettime( CLOCK_REALTIME, &curr ); 271 Time c = { curr }; 272 if( wait( (*cond)->impl, (*mut)->impl, t - c ) ) { 267 if( wait( (*cond)->impl, (*mut)->impl, t ) ) { 273 268 return 0; 274 269 } -
libcfa/src/concurrency/clib/cfathread.h
r8d66610 r5407cdc 80 80 81 81 typedef struct cfathread_cond_attr { 82 // WARNING: adding support for pthread_condattr_setclock would require keeping track of the clock83 // and reading it in cond_timedwait84 82 } cfathread_condattr_t; 85 83 typedef struct cfathread_condition * cfathread_cond_t; -
libcfa/src/concurrency/invoke.h
r8d66610 r5407cdc 146 146 struct __thread_desc_link { 147 147 struct $thread * next; 148 struct $thread * prev; 148 149 volatile unsigned long long ts; 150 unsigned preferred; 149 151 }; 150 152 … … 153 155 // context that is switch during a __cfactx_switch 154 156 struct __stack_context_t context; 155 156 // Link lists fields157 // instrusive link field for threads158 struct __thread_desc_link link;159 157 160 158 // current execution status for coroutine … … 172 170 struct cluster * curr_cluster; 173 171 174 // preferred ready-queue 175 unsigned preferred; 172 // Link lists fields 173 // instrusive link field for threads 174 struct __thread_desc_link link; 176 175 177 176 // coroutine body used to store context -
libcfa/src/concurrency/io.cfa
r8d66610 r5407cdc 138 138 /* paranoid */ verify( proc->io.ctx ); 139 139 140 __attribute__((unused)) cluster * cltr = proc->cltr;141 140 $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 // }147 141 148 142 __ioarbiter_flush( ctx ); … … 157 151 // Update statistics 158 152 __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 // }163 153 return; 164 154 default: … … 182 172 183 173 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 // }192 174 } 193 175 -
libcfa/src/concurrency/kernel.cfa
r8d66610 r5407cdc 163 163 #if !defined(__CFA_NO_STATISTICS__) 164 164 if( this->print_halts ) { 165 __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this-> unique_id, this->name, (void*)this);165 __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->id, this->name, (void*)this); 166 166 } 167 167 #endif … … 170 170 // Setup preemption data 171 171 preemption_scope scope = { this }; 172 173 __STATS( unsigned long long last_tally = rdtscl(); ) 172 174 173 175 // if we need to run some special setup, now is the time to do it. … … 182 184 MAIN_LOOP: 183 185 for() { 184 #define OLD_MAIN 1185 #if OLD_MAIN186 186 // Check if there is pending io 187 187 __maybe_io_drain( this ); … … 223 223 #if !defined(__CFA_NO_STATISTICS__) 224 224 if(this->print_halts) { 225 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this-> unique_id, rdtscl());225 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); 226 226 } 227 227 #endif … … 236 236 #if !defined(__CFA_NO_STATISTICS__) 237 237 if(this->print_halts) { 238 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this-> unique_id, rdtscl());238 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); 239 239 } 240 240 #endif … … 258 258 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 259 259 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 260 268 if(this->io.pending && !this->io.dirty) { 261 269 __cfa_io_flush( this ); 262 270 } 263 271 264 #else 265 #warning new kernel loop 266 SEARCH: { 267 /* paranoid */ verify( ! __preemption_enabled() ); 268 269 // First, lock the scheduler since we are searching for a thread 270 ready_schedule_lock(); 271 272 // Try to get the next thread 273 readyThread = pop_fast( this->cltr ); 274 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 275 276 // If we can't find a thread, might as well flush any outstanding I/O 277 if(this->io.pending) { __cfa_io_flush( this ); } 278 279 // Spin a little on I/O, just in case 280 for(5) { 281 __maybe_io_drain( this ); 282 readyThread = pop_fast( this->cltr ); 283 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 284 } 285 286 // no luck, try stealing a few times 287 for(5) { 288 if( __maybe_io_drain( this ) ) { 289 readyThread = pop_fast( this->cltr ); 290 } else { 291 readyThread = pop_slow( this->cltr ); 292 } 293 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 294 } 295 296 // still no luck, search for a thread 297 readyThread = pop_search( this->cltr ); 298 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 299 300 // Don't block if we are done 301 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 302 303 __STATS( __tls_stats()->ready.sleep.halts++; ) 304 305 // Push self to idle stack 306 ready_schedule_unlock(); 307 mark_idle(this->cltr->procs, * this); 308 ready_schedule_lock(); 309 310 // Confirm the ready-queue is empty 311 __maybe_io_drain( this ); 312 readyThread = pop_search( this->cltr ); 313 ready_schedule_unlock(); 314 315 if( readyThread ) { 316 // A thread was found, cancel the halt 317 mark_awake(this->cltr->procs, * this); 318 319 __STATS( __tls_stats()->ready.sleep.cancels++; ) 320 321 // continue the main loop 322 break SEARCH; 323 } 324 325 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 326 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 327 328 // __disable_interrupts_hard(); 329 eventfd_t val; 330 eventfd_read( this->idle, &val ); 331 // __enable_interrupts_hard(); 332 333 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) 334 335 // We were woken up, remove self from idle 336 mark_awake(this->cltr->procs, * this); 337 338 // DON'T just proceed, start looking again 339 continue MAIN_LOOP; 340 } 341 342 RUN_THREAD: 343 /* paranoid */ verify( ! __preemption_enabled() ); 344 /* paranoid */ verify( readyThread ); 345 346 // Reset io dirty bit 347 this->io.dirty = false; 348 349 // We found a thread run it 350 __run_thread(this, readyThread); 351 352 // Are we done? 353 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 354 355 if(this->io.pending && !this->io.dirty) { 356 __cfa_io_flush( this ); 357 } 358 359 ready_schedule_lock(); 360 __maybe_io_drain( this ); 361 ready_schedule_unlock(); 362 #endif 272 // SEARCH: { 273 // /* paranoid */ verify( ! __preemption_enabled() ); 274 // /* paranoid */ verify( kernelTLS().this_proc_id ); 275 276 // // First, lock the scheduler since we are searching for a thread 277 278 // // Try to get the next thread 279 // ready_schedule_lock(); 280 // readyThread = pop_fast( this->cltr ); 281 // ready_schedule_unlock(); 282 // if(readyThread) { break SEARCH; } 283 284 // // If we can't find a thread, might as well flush any outstanding I/O 285 // if(this->io.pending) { __cfa_io_flush( this ); } 286 287 // // Spin a little on I/O, just in case 288 // for(25) { 289 // __maybe_io_drain( this ); 290 // ready_schedule_lock(); 291 // readyThread = pop_fast( this->cltr ); 292 // ready_schedule_unlock(); 293 // if(readyThread) { break SEARCH; } 294 // } 295 296 // // no luck, try stealing a few times 297 // for(25) { 298 // if( __maybe_io_drain( this ) ) { 299 // ready_schedule_lock(); 300 // readyThread = pop_fast( this->cltr ); 301 // } else { 302 // ready_schedule_lock(); 303 // readyThread = pop_slow( this->cltr ); 304 // } 305 // ready_schedule_unlock(); 306 // if(readyThread) { break SEARCH; } 307 // } 308 309 // // still no luck, search for a thread 310 // ready_schedule_lock(); 311 // readyThread = pop_search( this->cltr ); 312 // ready_schedule_unlock(); 313 // if(readyThread) { break SEARCH; } 314 315 // // Don't block if we are done 316 // if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 317 318 // __STATS( __tls_stats()->ready.sleep.halts++; ) 319 320 // // Push self to idle stack 321 // mark_idle(this->cltr->procs, * this); 322 323 // // Confirm the ready-queue is empty 324 // __maybe_io_drain( this ); 325 // ready_schedule_lock(); 326 // readyThread = pop_search( this->cltr ); 327 // ready_schedule_unlock(); 328 329 // if( readyThread ) { 330 // // A thread was found, cancel the halt 331 // mark_awake(this->cltr->procs, * this); 332 333 // __STATS( __tls_stats()->ready.sleep.cancels++; ) 334 335 // // continue the main loop 336 // break SEARCH; 337 // } 338 339 // __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); ) 340 // __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 341 342 // // __disable_interrupts_hard(); 343 // eventfd_t val; 344 // eventfd_read( this->idle, &val ); 345 // // __enable_interrupts_hard(); 346 347 // __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); ) 348 349 // // We were woken up, remove self from idle 350 // mark_awake(this->cltr->procs, * this); 351 352 // // DON'T just proceed, start looking again 353 // continue MAIN_LOOP; 354 // } 355 356 // RUN_THREAD: 357 // /* paranoid */ verify( kernelTLS().this_proc_id ); 358 // /* paranoid */ verify( ! __preemption_enabled() ); 359 // /* paranoid */ verify( readyThread ); 360 361 // // Reset io dirty bit 362 // this->io.dirty = false; 363 364 // // We found a thread run it 365 // __run_thread(this, readyThread); 366 367 // // Are we done? 368 // if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 369 370 // #if !defined(__CFA_NO_STATISTICS__) 371 // unsigned long long curr = rdtscl(); 372 // if(curr > (last_tally + 500000000)) { 373 // __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats); 374 // last_tally = curr; 375 // } 376 // #endif 377 378 // if(this->io.pending && !this->io.dirty) { 379 // __cfa_io_flush( this ); 380 // } 381 382 // // Check if there is pending io 383 // __maybe_io_drain( this ); 363 384 } 364 385 … … 369 390 370 391 post( this->terminated ); 392 371 393 372 394 if(this == mainProcessor) { … … 531 553 static void __schedule_thread( $thread * thrd ) { 532 554 /* paranoid */ verify( ! __preemption_enabled() ); 555 /* paranoid */ verify( kernelTLS().this_proc_id ); 533 556 /* paranoid */ verify( ready_schedule_islocked()); 534 557 /* paranoid */ verify( thrd ); … … 544 567 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary ); 545 568 546 const bool local = thrd->state != Start; 569 547 570 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 548 571 … … 552 575 553 576 // push the thread to the cluster ready-queue 554 push( cl, thrd , local);577 push( cl, thrd ); 555 578 556 579 // variable thrd is no longer safe to use … … 588 611 static inline $thread * __next_thread(cluster * this) with( *this ) { 589 612 /* paranoid */ verify( ! __preemption_enabled() ); 613 /* paranoid */ verify( kernelTLS().this_proc_id ); 590 614 591 615 ready_schedule_lock(); … … 593 617 ready_schedule_unlock(); 594 618 619 /* paranoid */ verify( kernelTLS().this_proc_id ); 595 620 /* paranoid */ verify( ! __preemption_enabled() ); 596 621 return thrd; … … 600 625 static inline $thread * __next_thread_slow(cluster * this) with( *this ) { 601 626 /* paranoid */ verify( ! __preemption_enabled() ); 627 /* paranoid */ verify( kernelTLS().this_proc_id ); 602 628 603 629 ready_schedule_lock(); … … 612 638 ready_schedule_unlock(); 613 639 640 /* paranoid */ verify( kernelTLS().this_proc_id ); 614 641 /* paranoid */ verify( ! __preemption_enabled() ); 615 642 return thrd; … … 868 895 unsigned tail = *ctx->cq.tail; 869 896 if(head == tail) return false; 870 #if OLD_MAIN871 897 ready_schedule_lock(); 872 898 ret = __cfa_io_drain( proc ); 873 899 ready_schedule_unlock(); 874 #else875 ret = __cfa_io_drain( proc );876 #endif877 900 #endif 878 901 return ret; … … 903 926 } 904 927 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-up919 // this doesn't solve all problems but does solve many920 // so it's probably good enough921 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 RWlock927 ready_mutate_unlock( last_size );928 }929 930 931 928 void print_stats_now( cluster & this, int flags ) { 932 crawl_cluster_stats( this );933 929 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 934 930 } -
libcfa/src/concurrency/kernel.hfa
r8d66610 r5407cdc 49 49 50 50 // Processor id, required for scheduling threads 51 51 struct __processor_id_t { 52 unsigned id:24; 53 54 #if !defined(__CFA_NO_STATISTICS__) 55 struct __stats_t * stats; 56 #endif 57 }; 52 58 53 59 coroutine processorCtx_t { … … 57 63 // Wrapper around kernel threads 58 64 struct __attribute__((aligned(128))) processor { 65 // Main state 66 inline __processor_id_t; 67 59 68 // Cluster from which to get threads 60 69 struct cluster * cltr; … … 81 90 pthread_t kernel_thread; 82 91 83 // Unique id for the processor (not per cluster)84 unsigned unique_id;85 86 92 struct { 87 93 $io_context * ctx; … … 107 113 108 114 // Link lists fields 109 inline dlink(processor);115 DLISTED_MGD_IMPL_IN(processor) 110 116 111 117 // special init fields … … 117 123 } init; 118 124 119 struct KernelThreadData * local_data;120 121 125 #if !defined(__CFA_NO_STATISTICS__) 122 126 int print_stats; … … 129 133 #endif 130 134 }; 131 P9_EMBEDDED( processor, dlink(processor) )132 135 133 136 void ?{}(processor & this, const char name[], struct cluster & cltr); … … 137 140 static inline void ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; } 138 141 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster}; } 142 143 DLISTED_MGD_IMPL_OUT(processor) 139 144 140 145 //----------------------------------------------------------------------------- … … 147 152 148 153 // Aligned timestamps which are used by the relaxed ready queue 149 struct __attribute__((aligned(128))) __timestamp_t { 150 volatile unsigned long long tv; 151 }; 152 153 static inline void ?{}(__timestamp_t & this) { this.tv = 0; } 154 static inline void ^?{}(__timestamp_t & this) {} 154 struct __attribute__((aligned(128))) __timestamp_t; 155 void ?{}(__timestamp_t & this); 156 void ^?{}(__timestamp_t & this); 155 157 156 158 //TODO adjust cache size to ARCHITECTURE … … 175 177 void ?{}(__ready_queue_t & this); 176 178 void ^?{}(__ready_queue_t & this); 177 #if !defined(__CFA_NO_STATISTICS__)178 unsigned cnt(const __ready_queue_t & this, unsigned idx);179 #endif180 179 181 180 // Idle Sleep … … 191 190 192 191 // List of idle processors 193 dlist(processor ) idles;192 dlist(processor, processor) idles; 194 193 195 194 // List of active processors 196 dlist(processor ) actives;195 dlist(processor, processor) actives; 197 196 }; 198 197 -
libcfa/src/concurrency/kernel/fwd.hfa
r8d66610 r5407cdc 38 38 struct $thread * volatile this_thread; 39 39 struct processor * volatile this_processor; 40 volatile bool sched_lock; 40 struct __processor_id_t * volatile this_proc_id; 41 struct __stats_t * volatile this_stats; 41 42 42 43 struct { … … 55 56 uint64_t bck_seed; 56 57 } 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 reading63 bool in_sched_lock;64 unsigned sched_id;65 #endif66 58 } __cfaabi_tls __attribute__ ((tls_model ( "initial-exec" ))); 67 59 -
libcfa/src/concurrency/kernel/startup.cfa
r8d66610 r5407cdc 77 77 static void doregister( struct cluster & cltr ); 78 78 static void unregister( struct cluster & cltr ); 79 static void register_tls( processor * this );80 static void unregister_tls( processor * this );81 79 static void ?{}( $coroutine & this, current_stack_info_t * info); 82 80 static void ?{}( $thread & this, current_stack_info_t * info); … … 125 123 NULL, // cannot use 0p 126 124 NULL, 127 false, 125 NULL, 126 NULL, 128 127 { 1, false, false }, 129 0,130 { 0, 0 },131 NULL,132 #ifdef __CFA_WITH_VERIFY__133 false,134 0,135 #endif136 128 }; 137 129 … … 218 210 (*mainProcessor){}; 219 211 220 register_tls( mainProcessor );221 222 212 //initialize the global state variables 223 213 __cfaabi_tls.this_processor = mainProcessor; 214 __cfaabi_tls.this_proc_id = (__processor_id_t*)mainProcessor; 224 215 __cfaabi_tls.this_thread = mainThread; 225 216 … … 228 219 __init_stats( __cfaabi_tls.this_stats ); 229 220 #endif 230 mainProcessor->local_data = &__cfaabi_tls;231 221 232 222 // Enable preemption … … 283 273 #endif 284 274 285 mainProcessor->local_data = 0p;286 287 unregister_tls( mainProcessor );288 289 275 // Destroy the main processor and its context in reverse order of construction 290 276 // These were manually constructed so we need manually destroy them … … 330 316 processor * proc = (processor *) arg; 331 317 __cfaabi_tls.this_processor = proc; 318 __cfaabi_tls.this_proc_id = (__processor_id_t*)proc; 332 319 __cfaabi_tls.this_thread = 0p; 333 320 __cfaabi_tls.preemption_state.[enabled, disable_count] = [false, 1]; 334 proc->local_data = &__cfaabi_tls;335 336 register_tls( proc );337 338 321 // SKULLDUGGERY: We want to create a context for the processor coroutine 339 322 // which is needed for the 2-step context switch. However, there is no reason … … 372 355 #endif 373 356 #endif 374 375 proc->local_data = 0p;376 377 unregister_tls( proc );378 357 379 358 return 0p; … … 467 446 self_mon_p = &self_mon; 468 447 link.next = 0p; 469 link. ts = 0;470 preferred = -1u;448 link.prev = 0p; 449 link.preferred = -1u; 471 450 last_proc = 0p; 472 451 #if defined( __CFA_WITH_VERIFY__ ) … … 496 475 this.rdq.id = -1u; 497 476 this.rdq.target = -1u; 498 this.rdq.cutoff = 0ull;477 this.rdq.cutoff = -1ull; 499 478 do_terminate = false; 500 479 preemption_alarm = 0p; … … 506 485 507 486 this.init.thrd = initT; 508 509 this.local_data = 0p;510 487 511 488 this.idle = eventfd(0, 0); … … 519 496 #endif 520 497 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 521 509 __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this); 522 510 } … … 524 512 // Not a ctor, it just preps the destruction but should not destroy members 525 513 static 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 526 525 close(this.idle); 527 526 } … … 657 656 cltr->nthreads -= 1; 658 657 unlock(cltr->thread_list_lock); 659 }660 661 static void register_tls( processor * this ) {662 // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue663 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 size670 ready_queue_grow( this->cltr );671 672 // Unlock the RWlock673 ready_mutate_unlock( last_size );674 }675 676 677 static void unregister_tls( processor * this ) {678 // Lock the RWlock so no-one pushes/pops while we are changing the queue679 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 queues684 cluster * cltr = this->cltr;685 this->cltr = 0p;686 687 // Adjust the ready queue size688 ready_queue_shrink( cltr );689 690 // Unlock the RWlock and unregister: we don't need the read_lock any more691 ready_mutate_unregister( this->unique_id, last_size );692 658 } 693 659 -
libcfa/src/concurrency/kernel_private.hfa
r8d66610 r5407cdc 25 25 // Scheduler 26 26 27 struct __attribute__((aligned(128))) __scheduler_lock_id_t; 27 28 28 29 extern "C" { … … 79 80 // Lock-Free registering/unregistering of threads 80 81 // Register a processor to a given cluster and get its unique id in return 81 unsigned register_proc_id( void);82 void register_proc_id( struct __processor_id_t * ); 82 83 83 84 // Unregister a processor from a given cluster using its id, getting back the original pointer 84 void unregister_proc_id( unsigned);85 void unregister_proc_id( struct __processor_id_t * proc ); 85 86 86 87 //======================================================================= … … 111 112 } 112 113 113 114 115 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)); 116 131 117 132 //----------------------------------------------------------------------- … … 132 147 133 148 // writer lock 134 volatile bool write_lock;149 volatile bool lock; 135 150 136 151 // data pointer 137 volatile bool * volatile* data;152 __scheduler_lock_id_t * data; 138 153 }; 139 154 … … 148 163 static inline void ready_schedule_lock(void) with(*__scheduler_lock) { 149 164 /* paranoid */ verify( ! __preemption_enabled() ); 150 /* paranoid */ verify( ! kernelTLS().in_sched_lock ); 151 /* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock ); 152 /* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id ); 165 /* paranoid */ verify( kernelTLS().this_proc_id ); 166 167 unsigned iproc = kernelTLS().this_proc_id->id; 168 /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id); 169 /*paranoid*/ verify(iproc < ready); 153 170 154 171 // Step 1 : make sure no writer are in the middle of the critical section 155 while(__atomic_load_n(& write_lock, (int)__ATOMIC_RELAXED))172 while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED)) 156 173 Pause(); 157 174 … … 162 179 163 180 // Step 2 : acquire our local lock 164 __atomic_acquire( & kernelTLS().sched_lock );165 /*paranoid*/ verify( kernelTLS().sched_lock);181 __atomic_acquire( &data[iproc].lock ); 182 /*paranoid*/ verify(data[iproc].lock); 166 183 167 184 #ifdef __CFA_WITH_VERIFY__ 168 185 // Debug, check if this is owned for reading 169 kernelTLS().in_sched_lock= true;186 data[iproc].owned = true; 170 187 #endif 171 188 } … … 173 190 static inline void ready_schedule_unlock(void) with(*__scheduler_lock) { 174 191 /* paranoid */ verify( ! __preemption_enabled() ); 175 /* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock ); 176 /* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id ); 177 /* paranoid */ verify( kernelTLS().sched_lock ); 178 /* paranoid */ verify( kernelTLS().in_sched_lock ); 192 /* paranoid */ verify( kernelTLS().this_proc_id ); 193 194 unsigned iproc = kernelTLS().this_proc_id->id; 195 /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id); 196 /*paranoid*/ verify(iproc < ready); 197 /*paranoid*/ verify(data[iproc].lock); 198 /*paranoid*/ verify(data[iproc].owned); 179 199 #ifdef __CFA_WITH_VERIFY__ 180 200 // Debug, check if this is owned for reading 181 kernelTLS().in_sched_lock= false;201 data[iproc].owned = false; 182 202 #endif 183 __atomic_unlock(& kernelTLS().sched_lock);203 __atomic_unlock(&data[iproc].lock); 184 204 } 185 205 … … 187 207 static inline bool ready_schedule_islocked(void) { 188 208 /* paranoid */ verify( ! __preemption_enabled() ); 189 /* paranoid */ verify( (!kernelTLS().in_sched_lock) || kernelTLS().sched_lock ); 190 return kernelTLS().sched_lock; 209 /*paranoid*/ verify( kernelTLS().this_proc_id ); 210 __processor_id_t * proc = kernelTLS().this_proc_id; 211 return __scheduler_lock->data[proc->id].owned; 191 212 } 192 213 193 214 static inline bool ready_mutate_islocked() { 194 return __scheduler_lock-> write_lock;215 return __scheduler_lock->lock; 195 216 } 196 217 #endif … … 207 228 // Register a processor to a given cluster and get its unique id in return 208 229 // For convenience, also acquires the lock 209 static inline [unsigned, uint_fast32_t] ready_mutate_register() { 210 unsigned id = register_proc_id(); 211 uint_fast32_t last = ready_mutate_lock(); 212 return [id, last]; 230 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) { 231 register_proc_id( proc ); 232 return ready_mutate_lock(); 213 233 } 214 234 215 235 // Unregister a processor from a given cluster using its id, getting back the original pointer 216 236 // assumes the lock is acquired 217 static inline void ready_mutate_unregister( unsigned id, uint_fast32_t last_s ) {237 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) { 218 238 ready_mutate_unlock( last_s ); 219 unregister_proc_id( id);239 unregister_proc_id( proc ); 220 240 } 221 241 … … 261 281 // push thread onto a ready queue for a cluster 262 282 // returns true if the list was previously empty, false otherwise 263 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd , bool local);283 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd); 264 284 265 285 //----------------------------------------------------------------------- -
libcfa/src/concurrency/locks.cfa
r8d66610 r5407cdc 188 188 alarm_node_t alarm_node; 189 189 condition_variable(L) * cond; 190 info_thread(L) * i nfo_thd;190 info_thread(L) * i; 191 191 }; 192 192 193 void ?{}( alarm_node_wrap(L) & this, Durationalarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) {193 void ?{}( alarm_node_wrap(L) & this, Time alarm, Duration period, Alarm_Callback callback, condition_variable(L) * c, info_thread(L) * i ) { 194 194 this.alarm_node{ callback, alarm, period }; 195 195 this.cond = c; 196 this.i nfo_thd= i;196 this.i = i; 197 197 } 198 198 … … 206 206 // may still be called after a thread has been removed from the queue but 207 207 // before the alarm is unregistered 208 if ( listed(i nfo_thd) ) { // is thread on queue209 i nfo_thd->signalled = false;208 if ( listed(i) ) { // is thread on queue 209 i->signalled = false; 210 210 // remove this thread O(1) 211 remove( cond->blocked_threads, *i nfo_thd);211 remove( cond->blocked_threads, *i ); 212 212 cond->count--; 213 if( i nfo_thd->lock ) {213 if( i->lock ) { 214 214 // call lock's on_notify if a lock was passed 215 on_notify(*i nfo_thd->lock, info_thd->t);215 on_notify(*i->lock, i->t); 216 216 } else { 217 217 // otherwise wake thread 218 unpark( i nfo_thd->t );218 unpark( i->t ); 219 219 } 220 220 } … … 313 313 314 314 // helper for wait()'s' with a timeout 315 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback) with(this) {315 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Time t ) with(this) { 316 316 lock( lock __cfaabi_dbg_ctx2 ); 317 317 size_t recursion_count = queue_and_get_recursion(this, &info); 318 alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };318 alarm_node_wrap(L) node_wrap = { t, 0`s, alarm_node_wrap_cast, &this, &info }; 319 319 register_self( &node_wrap.alarm_node ); 320 320 unlock( lock ); … … 332 332 #define WAIT_TIME( u, l, t ) \ 333 333 info_thread( L ) i = { active_thread(), u, l }; \ 334 queue_info_thread_timeout(this, i, t , alarm_node_wrap_cast); \334 queue_info_thread_timeout(this, i, t ); \ 335 335 return i.signalled; 336 336 … … 340 340 void wait( condition_variable(L) & this, L & l, uintptr_t info ) with(this) { WAIT( info, &l ) } 341 341 342 bool wait( condition_variable(L) & this, Duration duration ) with(this) { WAIT_TIME( 0 , 0p , duration ) } 343 bool wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, 0p , duration ) } 344 bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { WAIT_TIME( 0 , &l , duration ) } 345 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , duration ) } 342 bool wait( condition_variable(L) & this, Duration duration ) with(this) { WAIT_TIME( 0 , 0p , __kernel_get_time() + duration ) } 343 bool wait( condition_variable(L) & this, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, 0p , __kernel_get_time() + duration ) } 344 bool wait( condition_variable(L) & this, Time time ) with(this) { WAIT_TIME( 0 , 0p , time ) } 345 bool wait( condition_variable(L) & this, uintptr_t info, Time time ) with(this) { WAIT_TIME( info, 0p , time ) } 346 bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { WAIT_TIME( 0 , &l , __kernel_get_time() + duration ) } 347 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , __kernel_get_time() + duration ) } 348 bool wait( condition_variable(L) & this, L & l, Time time ) with(this) { WAIT_TIME( 0 , &l , time ) } 349 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ) with(this) { WAIT_TIME( info, &l , time ) } 346 350 } 347 351 -
libcfa/src/concurrency/locks.hfa
r8d66610 r5407cdc 290 290 bool wait( condition_variable(L) & this, Duration duration ); 291 291 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 ); 292 294 293 295 void wait( condition_variable(L) & this, L & l ); … … 295 297 bool wait( condition_variable(L) & this, L & l, Duration duration ); 296 298 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ); 297 } 299 bool wait( condition_variable(L) & this, L & l, Time time ); 300 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ); 301 } -
libcfa/src/concurrency/preemption.cfa
r8d66610 r5407cdc 18 18 19 19 #include "preemption.hfa" 20 21 20 #include <assert.h> 22 21 … … 27 26 #include <limits.h> // PTHREAD_STACK_MIN 28 27 29 #include "bits/debug.hfa"30 28 #include "bits/signal.hfa" 31 29 #include "kernel_private.hfa" … … 107 105 static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) { 108 106 if( ! & (*alarms)`first ) return 0p; // If no alarms return null 109 if( (*alarms)`first. timeval>= currtime ) return 0p; // If alarms head not expired return null107 if( (*alarms)`first.alarm >= currtime ) return 0p; // If alarms head not expired return null 110 108 return pop(alarms); // Otherwise just pop head 111 109 } … … 143 141 if( period > 0 ) { 144 142 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns ); 145 node-> timeval = currtime + period;// Alarm is periodic, add currtime to it (used cached current time)143 node->alarm = currtime + period; // Alarm is periodic, add currtime to it (used cached current time) 146 144 insert( alarms, node ); // Reinsert the node for the next time it triggers 147 145 } … … 150 148 // If there are still alarms pending, reset the timer 151 149 if( & (*alarms)`first ) { 152 Duration delta = (*alarms)`first.timeval - currtime; 153 __kernel_set_timer( delta ); 150 Duration delta = (*alarms)`first.alarm - currtime; 151 Duration capped = max(delta, 50`us); 152 __kernel_set_timer( capped ); 154 153 } 155 154 } … … 161 160 // Alarms need to be enabled 162 161 if ( duration > 0 && ! alarm->set ) { 163 alarm-> initial =duration;164 alarm->period = duration;162 alarm->alarm = __kernel_get_time() + duration; 163 alarm->period = duration; 165 164 register_self( alarm ); 166 165 } … … 168 167 else if ( duration == 0 && alarm->set ) { 169 168 unregister_self( alarm ); 170 alarm-> initial= 0;171 alarm->period = 0;169 alarm->alarm = 0; 170 alarm->period = 0; 172 171 } 173 172 // If alarm is different from previous, change it 174 173 else if ( duration > 0 && alarm->period != duration ) { 175 174 unregister_self( alarm ); 176 alarm-> initial =duration;177 alarm->period = duration;175 alarm->alarm = __kernel_get_time() + duration; 176 alarm->period = duration; 178 177 register_self( alarm ); 179 178 } … … 600 599 601 600 // Notify the alarm thread of the shutdown 602 sigval val; 603 val.sival_int = 0; 601 sigval val = { 1 }; 604 602 pthread_sigqueue( alarm_thread, SIGALRM, val ); 605 603 … … 621 619 // Used by thread to control when they want to receive preemption signals 622 620 void ?{}( preemption_scope & this, processor * proc ) { 623 (this.alarm){ proc, 0`s, 0`s };621 (this.alarm){ proc, (Time){ 0 }, 0`s }; 624 622 this.proc = proc; 625 623 this.proc->preemption_alarm = &this.alarm; … … 689 687 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 690 688 static void * alarm_loop( __attribute__((unused)) void * args ) { 691 unsigned id = register_proc_id(); 689 __processor_id_t id; 690 register_proc_id(&id); 691 __cfaabi_tls.this_proc_id = &id; 692 692 693 693 694 // Block sigalrms to control when they arrive … … 706 707 siginfo_t info; 707 708 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 );711 709 712 710 if( sig < 0 ) { … … 716 714 case EAGAIN : 717 715 case EINTR : 718 {__cfa dbg_print_buffer_local( preemption," KERNEL: Spurious wakeup %d.\n", err );}716 {__cfaabi_dbg_print_buffer_decl( " KERNEL: Spurious wakeup %d.\n", err );} 719 717 continue; 720 718 case EINVAL : … … 728 726 assertf(sig == SIGALRM, "Kernel Internal Error, sigwait: Unexpected signal %d (%d : %d)\n", sig, info.si_code, info.si_value.sival_int); 729 727 728 // __cfaabi_dbg_print_safe( "Kernel : Caught alarm from %d with %d\n", info.si_code, info.si_value.sival_int ); 730 729 // Switch on the code (a.k.a. the sender) to 731 730 switch( info.si_code ) 732 731 { 733 // Signal was not sent by the kernel but by an other thread734 case SI_QUEUE:735 // other threads may signal the alarm thread to shut it down736 // or to manual cause the preemption tick737 // use info.si_value and handle the case here738 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 // fallthrough745 732 // Timers can apparently be marked as sent for the kernel 746 733 // In either case, tick preemption … … 752 739 unlock( event_kernel->lock ); 753 740 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; 754 746 } 755 747 } … … 757 749 EXIT: 758 750 __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" ); 759 unregister_proc_id(id);751 register_proc_id(&id); 760 752 761 753 return 0p; -
libcfa/src/concurrency/ready_queue.cfa
r8d66610 r5407cdc 17 17 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ 18 18 19 // #define USE_MPSC 19 20 20 21 #define USE_RELAXED_FIFO … … 92 93 this.alloc = 0; 93 94 this.ready = 0; 95 this.lock = false; 94 96 this.data = alloc(this.max); 95 this.write_lock = false; 96 97 98 /*paranoid*/ verify( 0 == (((uintptr_t)(this.data )) % 64) ); 99 /*paranoid*/ verify( 0 == (((uintptr_t)(this.data + 1)) % 64) ); 97 100 /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.alloc), &this.alloc)); 98 101 /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.ready), &this.ready)); … … 103 106 } 104 107 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 } 105 115 106 116 //======================================================================= 107 117 // Lock-Free registering/unregistering of threads 108 unsigned register_proc_id( void) with(*__scheduler_lock) {118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) { 109 119 __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc); 110 bool * handle = (bool *)&kernelTLS().sched_lock;111 120 112 121 // Step - 1 : check if there is already space in the data … … 115 124 // Check among all the ready 116 125 for(uint_fast32_t i = 0; i < s; i++) { 117 bool * volatile * cell = (bool * volatile *)&data[i]; // Cforall is bugged and the double volatiles causes problems 118 /* paranoid */ verify( handle != *cell ); 119 120 bool * null = 0p; // Re-write every loop since compare thrashes it 121 if( __atomic_load_n(cell, (int)__ATOMIC_RELAXED) == null 122 && __atomic_compare_exchange_n( cell, &null, handle, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 123 /* paranoid */ verify(i < ready); 124 /* paranoid */ verify( (kernelTLS().sched_id = i, true) ); 125 return i; 126 __processor_id_t * null = 0p; // Re-write every loop since compare thrashes it 127 if( __atomic_load_n(&data[i].handle, (int)__ATOMIC_RELAXED) == null 128 && __atomic_compare_exchange_n( &data[i].handle, &null, proc, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 129 /*paranoid*/ verify(i < ready); 130 /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size)); 131 /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0); 132 proc->id = i; 126 133 } 127 134 } … … 134 141 135 142 // Step - 3 : Mark space as used and then publish it. 136 data[n] = handle; 143 __scheduler_lock_id_t * storage = (__scheduler_lock_id_t *)&data[n]; 144 (*storage){ proc }; 137 145 while() { 138 146 unsigned copy = n; … … 146 154 147 155 // Return new spot. 148 /* paranoid */ verify(n < ready); 149 /* paranoid */ verify( (kernelTLS().sched_id = n, true) ); 150 return n; 151 } 152 153 void unregister_proc_id( unsigned id ) with(*__scheduler_lock) { 154 /* paranoid */ verify(id < ready); 155 /* paranoid */ verify(id == kernelTLS().sched_id); 156 /* paranoid */ verify(data[id] == &kernelTLS().sched_lock); 157 158 bool * volatile * cell = (bool * volatile *)&data[id]; // Cforall is bugged and the double volatiles causes problems 159 160 __atomic_store_n(cell, 0p, __ATOMIC_RELEASE); 156 /*paranoid*/ verify(n < ready); 157 /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size)); 158 /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0); 159 proc->id = n; 160 } 161 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); 161 167 162 168 __cfadbg_print_safe(ready_queue, "Kernel : Unregister proc %p\n", proc); … … 168 174 uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) { 169 175 /* paranoid */ verify( ! __preemption_enabled() ); 170 /* paranoid */ verify( ! kernelTLS().sched_lock );171 176 172 177 // Step 1 : lock global lock 173 178 // It is needed to avoid processors that register mid Critical-Section 174 179 // to simply lock their own lock and enter. 175 __atomic_acquire( & write_lock );180 __atomic_acquire( &lock ); 176 181 177 182 // Step 2 : lock per-proc lock … … 181 186 uint_fast32_t s = ready; 182 187 for(uint_fast32_t i = 0; i < s; i++) { 183 volatile bool * llock = data[i]; 184 if(llock) __atomic_acquire( llock ); 188 __atomic_acquire( &data[i].lock ); 185 189 } 186 190 … … 199 203 // Alternative solution : return s in write_lock and pass it to write_unlock 200 204 for(uint_fast32_t i = 0; i < last_s; i++) { 201 v olatile bool * llock = data[i];202 if(llock) __atomic_store_n(llock, (bool)false, __ATOMIC_RELEASE);205 verify(data[i].lock); 206 __atomic_store_n(&data[i].lock, (bool)false, __ATOMIC_RELEASE); 203 207 } 204 208 205 209 // Step 2 : release global lock 206 /*paranoid*/ assert(true == write_lock);207 __atomic_store_n(& write_lock, (bool)false, __ATOMIC_RELEASE);210 /*paranoid*/ assert(true == lock); 211 __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE); 208 212 209 213 /* paranoid */ verify( ! __preemption_enabled() ); … … 249 253 } 250 254 251 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd , bool push_local) with (cltr->ready_queue) {255 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 252 256 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 253 257 254 const bool external = !push_local ||(!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);258 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 255 259 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 260 261 // write timestamp 262 thrd->link.ts = rdtscl(); 256 263 257 264 bool local; … … 273 280 #endif 274 281 282 #if defined(USE_MPSC) 283 // mpsc always succeeds 284 } while( false ); 285 #else 275 286 // If we can't lock it retry 276 287 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 288 #endif 277 289 278 290 // Actually push it 279 291 push(lanes.data[i], thrd); 280 292 281 // Unlock and return 282 __atomic_unlock( &lanes.data[i].lock ); 293 #if !defined(USE_MPSC) 294 // Unlock and return 295 __atomic_unlock( &lanes.data[i].lock ); 296 #endif 283 297 284 298 // Mark the current index in the tls rng instance as having an item … … 336 350 #endif 337 351 #if defined(USE_WORK_STEALING) 338 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd , bool push_local) with (cltr->ready_queue) {352 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 339 353 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 340 354 341 // #define USE_PREFERRED 342 #if !defined(USE_PREFERRED) 343 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 355 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 344 356 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 345 #else 346 unsigned preferred = thrd->preferred; 347 const bool external = push_local || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr; 348 /* paranoid */ verifyf(external || preferred < lanes.count, "Invalid preferred queue %u for %u lanes", preferred, lanes.count ); 349 350 unsigned r = preferred % READYQ_SHARD_FACTOR; 351 const unsigned start = preferred - r; 352 #endif 357 358 // write timestamp 359 thrd->link.ts = rdtscl(); 353 360 354 361 // Try to pick a lane and lock it … … 364 371 } 365 372 else { 366 #if !defined(USE_PREFERRED) 367 processor * proc = kernelTLS().this_processor; 368 unsigned r = proc->rdq.its++; 369 i = proc->rdq.id + (r % READYQ_SHARD_FACTOR); 370 #else 371 i = start + (r++ % READYQ_SHARD_FACTOR); 372 #endif 373 processor * proc = kernelTLS().this_processor; 374 unsigned r = proc->rdq.its++; 375 i = proc->rdq.id + (r % READYQ_SHARD_FACTOR); 373 376 } 377 378 379 #if defined(USE_MPSC) 380 // mpsc always succeeds 381 } while( false ); 382 #else 374 383 // If we can't lock it retry 375 384 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 385 #endif 376 386 377 387 // Actually push it 378 388 push(lanes.data[i], thrd); 379 389 380 // Unlock and return 381 __atomic_unlock( &lanes.data[i].lock ); 390 #if !defined(USE_MPSC) 391 // Unlock and return 392 __atomic_unlock( &lanes.data[i].lock ); 393 #endif 382 394 383 395 #if !defined(__CFA_NO_STATISTICS__) … … 398 410 399 411 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;406 412 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; 407 421 } 408 422 else { 409 423 unsigned target = proc->rdq.target; 410 424 proc->rdq.target = -1u; 411 const unsigned long long bias = 0; //2_500_000_000; 412 const unsigned long long cutoff = proc->rdq.cutoff > bias ? proc->rdq.cutoff - bias : proc->rdq.cutoff; 413 if(lanes.tscs[target].tv < cutoff && ts(lanes.data[target]) < cutoff) { 425 if(lanes.tscs[target].tv < proc->rdq.cutoff) { 414 426 $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help)); 415 427 if(t) return t; … … 418 430 419 431 for(READYQ_SHARD_FACTOR) { 420 unsigned i = proc->rdq.id + ( proc->rdq.itr++% READYQ_SHARD_FACTOR);432 unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR); 421 433 if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t; 422 434 } … … 450 462 // If list looks empty retry 451 463 if( is_empty(lane) ) { 464 __STATS( stats.espec++; ) 452 465 return 0p; 453 466 } … … 455 468 // If we can't get the lock retry 456 469 if( !__atomic_try_acquire(&lane.lock) ) { 470 __STATS( stats.elock++; ) 457 471 return 0p; 458 472 } … … 461 475 if( is_empty(lane) ) { 462 476 __atomic_unlock(&lane.lock); 477 __STATS( stats.eempty++; ) 463 478 return 0p; 464 479 } … … 466 481 // Actually pop the list 467 482 struct $thread * thrd; 468 unsigned long long tsv; 469 [thrd, tsv] = pop(lane); 483 thrd = pop(lane); 470 484 471 485 /* paranoid */ verify(thrd); 472 /* paranoid */ verify(tsv);473 486 /* paranoid */ verify(lane.lock); 474 487 … … 480 493 481 494 #if defined(USE_WORK_STEALING) 482 lanes.tscs[w].tv = t sv;495 lanes.tscs[w].tv = thrd->link.ts; 483 496 #endif 484 485 thrd->preferred = w;486 497 487 498 // return the popped thread … … 511 522 // Check that all the intrusive queues in the data structure are still consistent 512 523 static void check( __ready_queue_t & q ) with (q) { 513 #if defined(__CFA_WITH_VERIFY__) 524 #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC) 514 525 { 515 526 for( idx ; lanes.count ) { … … 517 528 assert(!lanes.data[idx].lock); 518 529 519 if(is_empty(sl)) { 520 assert( sl.anchor.next == 0p ); 521 assert( sl.anchor.ts == 0 ); 522 assert( mock_head(sl) == sl.prev ); 523 } else { 524 assert( sl.anchor.next != 0p ); 525 assert( sl.anchor.ts != 0 ); 526 assert( mock_head(sl) != sl.prev ); 527 } 530 assert(head(sl)->link.prev == 0p ); 531 assert(head(sl)->link.next->link.prev == head(sl) ); 532 assert(tail(sl)->link.next == 0p ); 533 assert(tail(sl)->link.prev->link.next == tail(sl) ); 534 535 if(is_empty(sl)) { 536 assert(tail(sl)->link.prev == head(sl)); 537 assert(head(sl)->link.next == tail(sl)); 538 } else { 539 assert(tail(sl)->link.prev != head(sl)); 540 assert(head(sl)->link.next != tail(sl)); 541 } 528 542 } 529 543 } … … 546 560 // fixes the list so that the pointers back to anchors aren't left dangling 547 561 static inline void fix(__intrusive_lane_t & ll) { 548 if(is_empty(ll)) { 549 verify(ll.anchor.next == 0p); 550 ll.prev = mock_head(ll); 551 } 552 } 553 554 static void assign_list(unsigned & value, dlist(processor) & list, unsigned count) { 562 #if !defined(USE_MPSC) 563 // if the list is not empty then follow he pointer and fix its reverse 564 if(!is_empty(ll)) { 565 head(ll)->link.next->link.prev = head(ll); 566 tail(ll)->link.prev->link.next = tail(ll); 567 } 568 // Otherwise just reset the list 569 else { 570 verify(tail(ll)->link.next == 0p); 571 tail(ll)->link.prev = head(ll); 572 head(ll)->link.next = tail(ll); 573 verify(head(ll)->link.prev == 0p); 574 } 575 #endif 576 } 577 578 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) { 555 579 processor * it = &list`first; 556 580 for(unsigned i = 0; i < count; i++) { … … 573 597 lanes.tscs = alloc(lanes.count, lanes.tscs`realloc); 574 598 for(i; lanes.count) { 575 unsigned long long tsc = ts(lanes.data[i]); 576 lanes.tscs[i].tv = tsc != 0 ? tsc : rdtscl(); 599 lanes.tscs[i].tv = ts(lanes.data[i]); 577 600 } 578 601 #endif … … 663 686 while(!is_empty(lanes.data[idx])) { 664 687 struct $thread * thrd; 665 unsigned long long _; 666 [thrd, _] = pop(lanes.data[idx]); 667 668 push(cltr, thrd, true); 688 thrd = pop(lanes.data[idx]); 689 690 push(cltr, thrd); 669 691 670 692 // for printing count the number of displaced threads … … 703 725 /* paranoid */ verify( ready_mutate_islocked() ); 704 726 } 705 706 #if !defined(__CFA_NO_STATISTICS__)707 unsigned cnt(const __ready_queue_t & this, unsigned idx) {708 /* paranoid */ verify(this.lanes.count > idx);709 return this.lanes.data[idx].cnt;710 }711 #endif -
libcfa/src/concurrency/ready_subqueue.hfa
r8d66610 r5407cdc 7 7 // Intrusives lanes which are used by the relaxed ready queue 8 8 struct __attribute__((aligned(128))) __intrusive_lane_t { 9 struct $thread * prev; 9 10 #if defined(USE_MPSC) 11 mpsc_queue($thread) queue; 12 __attribute__((aligned(128))) 13 #else 14 // anchor for the head and the tail of the queue 15 __attribute__((aligned(128))) struct __sentinel_t { 16 // Link lists fields 17 // instrusive link field for threads 18 // must be exactly as in $thread 19 __thread_desc_link link; 20 } before, after; 21 #endif 10 22 11 23 // spin lock protecting the queue 12 24 volatile bool lock; 13 25 14 __thread_desc_link anchor; 15 16 #if !defined(__CFA_NO_STATISTICS__) 17 unsigned cnt; 26 // Optional statistic counters 27 #if !defined(__CFA_NO_SCHED_STATS__) 28 struct __attribute__((aligned(64))) { 29 // difference between number of push and pops 30 ssize_t diff; 31 32 // total number of pushes and pops 33 size_t push; 34 size_t pop ; 35 } stat; 18 36 #endif 19 37 }; 20 38 39 void ?{}(__intrusive_lane_t & this); 40 void ^?{}(__intrusive_lane_t & this); 41 21 42 // Get the head pointer (one before the first element) from the anchor 22 static inline $thread * mock_head(const __intrusive_lane_t & this) { 23 $thread * rhead = ($thread *)( 24 (uintptr_t)( &this.anchor ) - __builtin_offsetof( $thread, link ) 25 ); 26 return rhead; 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 27 66 } 28 67 … … 30 69 void ?{}( __intrusive_lane_t & this ) { 31 70 this.lock = false; 32 this.prev = mock_head(this); 33 this.anchor.next = 0p; 34 this.anchor.ts = 0; 35 #if !defined(__CFA_NO_STATISTICS__) 36 this.cnt = 0; 37 #endif 38 39 // We add a boat-load of assertions here because the anchor code is very fragile 40 /* paranoid */ _Static_assert( offsetof( $thread, link ) == offsetof(__intrusive_lane_t, anchor) ); 41 /* paranoid */ verify( offsetof( $thread, link ) == offsetof(__intrusive_lane_t, anchor) ); 42 /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.anchor) ); 43 /* paranoid */ verify( &mock_head(this)->link.next == &this.anchor.next ); 44 /* paranoid */ verify( &mock_head(this)->link.ts == &this.anchor.ts ); 45 /* paranoid */ verify( mock_head(this)->link.next == 0p ); 46 /* paranoid */ verify( mock_head(this)->link.ts == 0 ); 47 /* paranoid */ verify( mock_head(this) == this.prev ); 48 /* paranoid */ verify( __alignof__(__intrusive_lane_t) == 128 ); 49 /* paranoid */ verify( __alignof__(this) == 128 ); 50 /* paranoid */ verifyf( ((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128) ); 71 72 #if !defined(USE_MPSC) 73 this.before.link.prev = 0p; 74 this.before.link.next = tail(this); 75 this.before.link.ts = 0; 76 77 this.after .link.prev = head(this); 78 this.after .link.next = 0p; 79 this.after .link.ts = 0; 80 81 #if !defined(__CFA_NO_SCHED_STATS__) 82 this.stat.diff = 0; 83 this.stat.push = 0; 84 this.stat.pop = 0; 85 #endif 86 87 // We add a boat-load of assertions here because the anchor code is very fragile 88 /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before)); 89 /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after )); 90 /* paranoid */ verify(head(this)->link.prev == 0p ); 91 /* paranoid */ verify(head(this)->link.next == tail(this) ); 92 /* paranoid */ verify(tail(this)->link.next == 0p ); 93 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 94 /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev ); 95 /* paranoid */ verify(&head(this)->link.next == &this.before.link.next ); 96 /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev ); 97 /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next ); 98 /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128); 99 /* paranoid */ verify(__alignof__(this) == 128); 100 /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128)); 101 #endif 51 102 } 52 103 53 104 // Dtor is trivial 54 105 void ^?{}( __intrusive_lane_t & this ) { 55 // Make sure the list is empty 56 /* paranoid */ verify( this.anchor.next == 0p ); 57 /* paranoid */ verify( this.anchor.ts == 0 ); 58 /* paranoid */ verify( mock_head(this) == this.prev ); 106 #if !defined(USE_MPSC) 107 // Make sure the list is empty 108 /* paranoid */ verify(head(this)->link.prev == 0p ); 109 /* paranoid */ verify(head(this)->link.next == tail(this) ); 110 /* paranoid */ verify(tail(this)->link.next == 0p ); 111 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 112 #endif 59 113 } 60 114 61 115 // Push a thread onto this lane 62 116 // returns true of lane was empty before push, false otherwise 63 static inline void push( __intrusive_lane_t & this, $thread * node ) { 64 /* paranoid */ verify( this.lock ); 65 /* paranoid */ verify( node->link.next == 0p ); 66 /* paranoid */ verify( node->link.ts == 0 ); 67 /* paranoid */ verify( this.prev->link.next == 0p ); 68 /* paranoid */ verify( this.prev->link.ts == 0 ); 69 if( this.anchor.next == 0p ) { 70 /* paranoid */ verify( this.anchor.next == 0p ); 71 /* paranoid */ verify( this.anchor.ts == 0 ); 72 /* paranoid */ verify( this.prev == mock_head( this ) ); 73 } else { 74 /* paranoid */ verify( this.anchor.next != 0p ); 75 /* paranoid */ verify( this.anchor.ts != 0 ); 76 /* paranoid */ verify( this.prev != mock_head( this ) ); 77 } 78 79 // Get the relevant nodes locally 80 this.prev->link.next = node; 81 this.prev->link.ts = rdtscl(); 82 this.prev = node; 83 #if !defined(__CFA_NO_STATISTICS__) 84 this.cnt++; 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); 131 132 if(this.before.link.ts == 0l) { 133 /* paranoid */ verify(tail(this)->link.prev == head(this)); 134 /* paranoid */ verify(head(this)->link.next == tail(this)); 135 } else { 136 /* paranoid */ verify(tail(this)->link.prev != head(this)); 137 /* paranoid */ verify(head(this)->link.next != tail(this)); 138 } 139 #endif 140 141 // Get the relevant nodes locally 142 $thread * tail = tail(this); 143 $thread * prev = tail->link.prev; 144 145 // Do the push 146 node->link.next = tail; 147 node->link.prev = prev; 148 prev->link.next = node; 149 tail->link.prev = node; 150 151 // Update stats 152 #if !defined(__CFA_NO_SCHED_STATS__) 153 this.stat.diff++; 154 this.stat.push++; 155 #endif 156 157 verify(node->link.next == tail(this)); 158 159 // Check if the queue used to be empty 160 if(this.before.link.ts == 0l) { 161 this.before.link.ts = node->link.ts; 162 /* paranoid */ verify(node->link.prev == head(this)); 163 return true; 164 } 165 return false; 85 166 #endif 86 167 } … … 89 170 // returns popped 90 171 // returns true of lane was empty before push, false otherwise 91 static inline [* $thread, unsigned long long] pop( __intrusive_lane_t & this ) { 92 /* paranoid */ verify( this.lock ); 93 /* paranoid */ verify( this.anchor.next != 0p ); 94 /* paranoid */ verify( this.anchor.ts != 0 ); 95 96 // Get the relevant nodes locally 97 unsigned long long ts = this.anchor.ts; 98 $thread * node = this.anchor.next; 99 this.anchor.next = node->link.next; 100 this.anchor.ts = node->link.ts; 101 bool is_empty = this.anchor.ts == 0; 102 node->link.next = 0p; 103 node->link.ts = 0; 104 #if !defined(__CFA_NO_STATISTICS__) 105 this.cnt--; 106 #endif 107 108 // Update head time stamp 109 if(is_empty) this.prev = mock_head( this ); 110 111 /* paranoid */ verify( node->link.next == 0p ); 112 /* paranoid */ verify( node->link.ts == 0 ); 113 return [node, ts]; 172 $thread * pop(__intrusive_lane_t & this) { 173 /* paranoid */ verify(this.lock); 174 #if defined(USE_MPSC) 175 inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) { 176 return this->link.next; 177 } 178 return pop(this.queue); 179 #else 180 /* paranoid */ verify(this.before.link.ts != 0ul); 181 182 // Get anchors locally 183 $thread * head = head(this); 184 $thread * tail = tail(this); 185 186 // Get the relevant nodes locally 187 $thread * node = head->link.next; 188 $thread * next = node->link.next; 189 190 /* paranoid */ verify(node != tail); 191 /* paranoid */ verify(node); 192 193 // Do the pop 194 head->link.next = next; 195 next->link.prev = head; 196 node->link.next = 0p; 197 node->link.prev = 0p; 198 199 // Update head time stamp 200 this.before.link.ts = next->link.ts; 201 202 // Update stats 203 #ifndef __CFA_NO_SCHED_STATS__ 204 this.stat.diff--; 205 this.stat.pop ++; 206 #endif 207 208 // Check if we emptied list and return accordingly 209 /* paranoid */ verify(tail(this)->link.next == 0p); 210 /* paranoid */ verify(head(this)->link.prev == 0p); 211 if(next == tail) { 212 /* paranoid */ verify(this.before.link.ts == 0); 213 /* paranoid */ verify(tail(this)->link.prev == head(this)); 214 /* paranoid */ verify(head(this)->link.next == tail(this)); 215 return node; 216 } 217 else { 218 /* paranoid */ verify(next->link.ts != 0); 219 /* paranoid */ verify(tail(this)->link.prev != head(this)); 220 /* paranoid */ verify(head(this)->link.next != tail(this)); 221 /* paranoid */ verify(this.before.link.ts != 0); 222 return node; 223 } 224 #endif 114 225 } 115 226 116 227 // Check whether or not list is empty 117 228 static inline bool is_empty(__intrusive_lane_t & this) { 118 return this.anchor.ts == 0; 229 #if defined(USE_MPSC) 230 return this.queue.head == 0p; 231 #else 232 // Cannot verify here since it may not be locked 233 return this.before.link.ts == 0; 234 #endif 119 235 } 120 236 121 237 // Return the timestamp 122 238 static inline unsigned long long ts(__intrusive_lane_t & this) { 123 // Cannot verify here since it may not be locked 124 return this.anchor.ts; 125 } 239 #if defined(USE_MPSC) 240 $thread * tl = this.queue.head; 241 if(!tl) return -1ull; 242 return tl->link.ts; 243 #else 244 // Cannot verify here since it may not be locked 245 return this.before.link.ts; 246 #endif 247 } 248 249 // Aligned timestamps which are used by the relaxed ready queue 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
r8d66610 r5407cdc 19 19 stats->ready.pop.local .attempt = 0; 20 20 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; 21 24 stats->ready.pop.help .attempt = 0; 22 25 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; 23 29 stats->ready.pop.steal .attempt = 0; 24 30 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; 25 34 stats->ready.pop.search.attempt = 0; 26 35 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; 27 39 stats->ready.threads.migration = 0; 28 40 stats->ready.threads.extunpark = 0; 29 41 stats->ready.threads.threads = 0; 30 stats->ready.threads.cthreads = 0;31 42 stats->ready.sleep.halts = 0; 32 43 stats->ready.sleep.cancels = 0; … … 48 59 stats->io.calls.completed = 0; 49 60 stats->io.calls.errors.busy = 0; 61 stats->io.poller.sleeps = 0; 50 62 #endif 51 63 … … 56 68 } 57 69 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 68 70 void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) { 69 tally_one( &cltr->ready.push.local.attempt, &proc->ready.push.local.attempt ); 70 tally_one( &cltr->ready.push.local.success, &proc->ready.push.local.success ); 71 tally_one( &cltr->ready.push.share.attempt, &proc->ready.push.share.attempt ); 72 tally_one( &cltr->ready.push.share.success, &proc->ready.push.share.success ); 73 tally_one( &cltr->ready.push.extrn.attempt, &proc->ready.push.extrn.attempt ); 74 tally_one( &cltr->ready.push.extrn.success, &proc->ready.push.extrn.success ); 75 tally_one( &cltr->ready.pop.local .attempt, &proc->ready.pop.local .attempt ); 76 tally_one( &cltr->ready.pop.local .success, &proc->ready.pop.local .success ); 77 tally_one( &cltr->ready.pop.help .attempt, &proc->ready.pop.help .attempt ); 78 tally_one( &cltr->ready.pop.help .success, &proc->ready.pop.help .success ); 79 tally_one( &cltr->ready.pop.steal .attempt, &proc->ready.pop.steal .attempt ); 80 tally_one( &cltr->ready.pop.steal .success, &proc->ready.pop.steal .success ); 81 tally_one( &cltr->ready.pop.search.attempt, &proc->ready.pop.search.attempt ); 82 tally_one( &cltr->ready.pop.search.success, &proc->ready.pop.search.success ); 83 tally_one( &cltr->ready.threads.migration , &proc->ready.threads.migration ); 84 tally_one( &cltr->ready.threads.extunpark , &proc->ready.threads.extunpark ); 85 tally_one( &cltr->ready.threads.threads , &proc->ready.threads.threads ); 86 tally_one( &cltr->ready.threads.cthreads , &proc->ready.threads.cthreads ); 87 tally_one( &cltr->ready.sleep.halts , &proc->ready.sleep.halts ); 88 tally_one( &cltr->ready.sleep.cancels , &proc->ready.sleep.cancels ); 89 tally_one( &cltr->ready.sleep.wakes , &proc->ready.sleep.wakes ); 90 tally_one( &cltr->ready.sleep.exits , &proc->ready.sleep.exits ); 71 __atomic_fetch_add( &cltr->ready.push.local.attempt, proc->ready.push.local.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.local.attempt = 0; 72 __atomic_fetch_add( &cltr->ready.push.local.success, proc->ready.push.local.success, __ATOMIC_SEQ_CST ); proc->ready.push.local.success = 0; 73 __atomic_fetch_add( &cltr->ready.push.share.attempt, proc->ready.push.share.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.share.attempt = 0; 74 __atomic_fetch_add( &cltr->ready.push.share.success, proc->ready.push.share.success, __ATOMIC_SEQ_CST ); proc->ready.push.share.success = 0; 75 __atomic_fetch_add( &cltr->ready.push.extrn.attempt, proc->ready.push.extrn.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.attempt = 0; 76 __atomic_fetch_add( &cltr->ready.push.extrn.success, proc->ready.push.extrn.success, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.success = 0; 77 __atomic_fetch_add( &cltr->ready.pop.local .attempt, proc->ready.pop.local .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.local .attempt = 0; 78 __atomic_fetch_add( &cltr->ready.pop.local .success, proc->ready.pop.local .success, __ATOMIC_SEQ_CST ); proc->ready.pop.local .success = 0; 79 __atomic_fetch_add( &cltr->ready.pop.local .elock , proc->ready.pop.local .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.local .elock = 0; 80 __atomic_fetch_add( &cltr->ready.pop.local .eempty , proc->ready.pop.local .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.local .eempty = 0; 81 __atomic_fetch_add( &cltr->ready.pop.local .espec , proc->ready.pop.local .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.local .espec = 0; 82 __atomic_fetch_add( &cltr->ready.pop.help .attempt, proc->ready.pop.help .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.help .attempt = 0; 83 __atomic_fetch_add( &cltr->ready.pop.help .success, proc->ready.pop.help .success, __ATOMIC_SEQ_CST ); proc->ready.pop.help .success = 0; 84 __atomic_fetch_add( &cltr->ready.pop.help .elock , proc->ready.pop.help .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.help .elock = 0; 85 __atomic_fetch_add( &cltr->ready.pop.help .eempty , proc->ready.pop.help .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.help .eempty = 0; 86 __atomic_fetch_add( &cltr->ready.pop.help .espec , proc->ready.pop.help .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.help .espec = 0; 87 __atomic_fetch_add( &cltr->ready.pop.steal .attempt, proc->ready.pop.steal .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .attempt = 0; 88 __atomic_fetch_add( &cltr->ready.pop.steal .success, proc->ready.pop.steal .success, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .success = 0; 89 __atomic_fetch_add( &cltr->ready.pop.steal .elock , proc->ready.pop.steal .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .elock = 0; 90 __atomic_fetch_add( &cltr->ready.pop.steal .eempty , proc->ready.pop.steal .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .eempty = 0; 91 __atomic_fetch_add( &cltr->ready.pop.steal .espec , proc->ready.pop.steal .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .espec = 0; 92 __atomic_fetch_add( &cltr->ready.pop.search.attempt, proc->ready.pop.search.attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.search.attempt = 0; 93 __atomic_fetch_add( &cltr->ready.pop.search.success, proc->ready.pop.search.success, __ATOMIC_SEQ_CST ); proc->ready.pop.search.success = 0; 94 __atomic_fetch_add( &cltr->ready.pop.search.elock , proc->ready.pop.search.elock , __ATOMIC_SEQ_CST ); proc->ready.pop.search.elock = 0; 95 __atomic_fetch_add( &cltr->ready.pop.search.eempty , proc->ready.pop.search.eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.search.eempty = 0; 96 __atomic_fetch_add( &cltr->ready.pop.search.espec , proc->ready.pop.search.espec , __ATOMIC_SEQ_CST ); proc->ready.pop.search.espec = 0; 97 __atomic_fetch_add( &cltr->ready.threads.migration , proc->ready.threads.migration , __ATOMIC_SEQ_CST ); proc->ready.threads.migration = 0; 98 __atomic_fetch_add( &cltr->ready.threads.extunpark , proc->ready.threads.extunpark , __ATOMIC_SEQ_CST ); proc->ready.threads.extunpark = 0; 99 __atomic_fetch_add( &cltr->ready.threads.threads , proc->ready.threads.threads , __ATOMIC_SEQ_CST ); proc->ready.threads.threads = 0; 100 __atomic_fetch_add( &cltr->ready.sleep.halts , proc->ready.sleep.halts , __ATOMIC_SEQ_CST ); proc->ready.sleep.halts = 0; 101 __atomic_fetch_add( &cltr->ready.sleep.cancels , proc->ready.sleep.cancels , __ATOMIC_SEQ_CST ); proc->ready.sleep.cancels = 0; 102 __atomic_fetch_add( &cltr->ready.sleep.wakes , proc->ready.sleep.wakes , __ATOMIC_SEQ_CST ); proc->ready.sleep.wakes = 0; 103 __atomic_fetch_add( &cltr->ready.sleep.exits , proc->ready.sleep.exits , __ATOMIC_SEQ_CST ); proc->ready.sleep.exits = 0; 91 104 92 105 #if defined(CFA_HAVE_LINUX_IO_URING_H) 93 tally_one( &cltr->io.alloc.fast , &proc->io.alloc.fast ); 94 tally_one( &cltr->io.alloc.slow , &proc->io.alloc.slow ); 95 tally_one( &cltr->io.alloc.fail , &proc->io.alloc.fail ); 96 tally_one( &cltr->io.alloc.revoke , &proc->io.alloc.revoke ); 97 tally_one( &cltr->io.alloc.block , &proc->io.alloc.block ); 98 tally_one( &cltr->io.submit.fast , &proc->io.submit.fast ); 99 tally_one( &cltr->io.submit.slow , &proc->io.submit.slow ); 100 tally_one( &cltr->io.flush.external , &proc->io.flush.external ); 101 tally_one( &cltr->io.calls.flush , &proc->io.calls.flush ); 102 tally_one( &cltr->io.calls.submitted , &proc->io.calls.submitted ); 103 tally_one( &cltr->io.calls.drain , &proc->io.calls.drain ); 104 tally_one( &cltr->io.calls.completed , &proc->io.calls.completed ); 105 tally_one( &cltr->io.calls.errors.busy, &proc->io.calls.errors.busy ); 106 __atomic_fetch_add( &cltr->io.alloc.fast , proc->io.alloc.fast , __ATOMIC_SEQ_CST ); proc->io.alloc.fast = 0; 107 __atomic_fetch_add( &cltr->io.alloc.slow , proc->io.alloc.slow , __ATOMIC_SEQ_CST ); proc->io.alloc.slow = 0; 108 __atomic_fetch_add( &cltr->io.alloc.fail , proc->io.alloc.fail , __ATOMIC_SEQ_CST ); proc->io.alloc.fail = 0; 109 __atomic_fetch_add( &cltr->io.alloc.revoke , proc->io.alloc.revoke , __ATOMIC_SEQ_CST ); proc->io.alloc.revoke = 0; 110 __atomic_fetch_add( &cltr->io.alloc.block , proc->io.alloc.block , __ATOMIC_SEQ_CST ); proc->io.alloc.block = 0; 111 __atomic_fetch_add( &cltr->io.submit.fast , proc->io.submit.fast , __ATOMIC_SEQ_CST ); proc->io.submit.fast = 0; 112 __atomic_fetch_add( &cltr->io.submit.slow , proc->io.submit.slow , __ATOMIC_SEQ_CST ); proc->io.submit.slow = 0; 113 __atomic_fetch_add( &cltr->io.flush.external , proc->io.flush.external , __ATOMIC_SEQ_CST ); proc->io.flush.external = 0; 114 __atomic_fetch_add( &cltr->io.calls.flush , proc->io.calls.flush , __ATOMIC_SEQ_CST ); proc->io.calls.flush = 0; 115 __atomic_fetch_add( &cltr->io.calls.submitted , proc->io.calls.submitted , __ATOMIC_SEQ_CST ); proc->io.calls.submitted = 0; 116 __atomic_fetch_add( &cltr->io.calls.drain , proc->io.calls.drain , __ATOMIC_SEQ_CST ); proc->io.calls.drain = 0; 117 __atomic_fetch_add( &cltr->io.calls.completed , proc->io.calls.completed , __ATOMIC_SEQ_CST ); proc->io.calls.completed = 0; 118 __atomic_fetch_add( &cltr->io.calls.errors.busy, proc->io.calls.errors.busy, __ATOMIC_SEQ_CST ); proc->io.calls.errors.busy = 0; 119 __atomic_fetch_add( &cltr->io.poller.sleeps , proc->io.poller.sleeps , __ATOMIC_SEQ_CST ); proc->io.poller.sleeps = 0; 106 120 #endif 107 121 } … … 116 130 if( flags & CFA_STATS_READY_Q ) { 117 131 118 sstr | "----- " | type | " \"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";132 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----"; 119 133 120 134 uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success; 121 135 uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success; 122 sstr | "- totals : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," 123 | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk," | ready.threads.threads | " t," | ready.threads.cthreads | " cthr)"; 136 sstr | "- totals : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk)"; 124 137 125 138 double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS; … … 134 147 double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR; 135 148 sstr | "- local : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%' 136 | " (" | eng3(ready.pop.local .attempt) | " try )";149 | " (" | eng3(ready.pop.local .attempt) | " try," | eng3(ready.pop.local .espec) | " spc," | eng3(ready.pop.local .elock) | " lck," | eng3(ready.pop.local .eempty) | " ept)"; 137 150 double rHlp_pc = (100.0 * (double)ready.pop.help .success) / totalR; 138 151 sstr | "- help : " | eng3(ready.pop.help .success) | "-"| ws(3, 3, rHlp_pc) | '%' 139 | " (" | eng3(ready.pop.help .attempt) | " try )";152 | " (" | eng3(ready.pop.help .attempt) | " try," | eng3(ready.pop.help .espec) | " spc," | eng3(ready.pop.help .elock) | " lck," | eng3(ready.pop.help .eempty) | " ept)"; 140 153 double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR; 141 154 sstr | "- steal : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%' 142 | " (" | eng3(ready.pop.steal .attempt) | " try )";155 | " (" | eng3(ready.pop.steal .attempt) | " try," | eng3(ready.pop.steal .espec) | " spc," | eng3(ready.pop.steal .elock) | " lck," | eng3(ready.pop.steal .eempty) | " ept)"; 143 156 double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR; 144 157 sstr | "- search : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%' 145 | " (" | eng3(ready.pop.search.attempt) | " try )";158 | " (" | eng3(ready.pop.search.attempt) | " try," | eng3(ready.pop.search.espec) | " spc," | eng3(ready.pop.search.elock) | " lck," | eng3(ready.pop.search.eempty) | " ept)"; 146 159 147 160 sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit"; … … 151 164 #if defined(CFA_HAVE_LINUX_IO_URING_H) 152 165 if( flags & CFA_STATS_IO ) { 153 sstr | "----- " | type | " \"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";166 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----"; 154 167 155 168 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"; 156 172 157 173 uint64_t total_submits = io.submit.fast + io.submit.slow; 158 sstr | "- totals : allc" | eng3(io.alloc .fast) | nonl; 159 if(io.alloc.slow) { 160 double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs; 161 sstr | "fast," | eng3(io.alloc .slow) | "slow (" | ws(3, 3, avgfasta) | "%)" | nonl; 162 } 163 sstr | " - subm" | eng3(io.submit.fast) | nonl; 164 if(io.alloc.slow) { 165 double avgfasts = (100.0 * (double)io.submit.fast) / total_submits; 166 sstr | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)" | nonl; 167 } 168 sstr | nl; 169 170 if(io.alloc.fail || io.alloc.revoke || io.alloc.block) 171 sstr | "- failures : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk"; 172 if(io.flush.external) 173 sstr | "- flush external : " | eng3(io.flush.external); 174 double avgfasts = (100.0 * (double)io.submit.fast) / total_submits; 175 sstr | "- total submits : " | eng3(io.submit.fast) | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)"; 176 sstr | "- flush external : " | eng3(io.flush.external); 177 178 sstr | "- io_uring_enter : " | eng3(io.calls.flush) | " (" | eng3(io.calls.drain) | ", " | eng3(io.calls.errors.busy) | " EBUSY)"; 174 179 175 180 double avgsubs = ((double)io.calls.submitted) / io.calls.flush; 176 181 double avgcomp = ((double)io.calls.completed) / io.calls.drain; 177 sstr | "- syscll : "178 | " sub " | eng3(io.calls.flush) | "/" | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"179 | " - cmp " | eng3(io.calls.drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)" 180 | " - " | eng3(io.calls.errors.busy) | " EBUSY";182 sstr | "- submits : " | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"; 183 sstr | "- completes : " | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"; 184 185 sstr | "- poller sleeping : " | eng3(io.poller.sleeps); 181 186 sstr | nl; 182 187 } -
libcfa/src/concurrency/stats.hfa
r8d66610 r5407cdc 2 2 3 3 // #define CFA_STATS_ARRAY 10000 4 // #define __CFA_NO_STATISTICS__5 4 6 5 #include <stdint.h> … … 23 22 // number of successes at poping 24 23 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; 25 33 }; 26 34 … … 63 71 volatile uint64_t migration; 64 72 volatile uint64_t extunpark; 65 volatile int64_t threads; // number of threads in the system, includes only local change 66 volatile int64_t cthreads; // number of threads in the system, includes only local change 73 volatile int64_t threads; // number of threads in the system, includes only local change 67 74 } threads; 68 75 struct { -
libcfa/src/concurrency/thread.cfa
r8d66610 r5407cdc 38 38 curr_cluster = &cl; 39 39 link.next = 0p; 40 link. ts = 0;41 preferred = -1u;40 link.prev = 0p; 41 link.preferred = -1u; 42 42 last_proc = 0p; 43 43 #if defined( __CFA_WITH_VERIFY__ ) -
libcfa/src/containers/array.hfa
r8d66610 r5407cdc 5 5 6 6 // the inverse of Z(-) 7 #define z(N) sizeof(N) 7 #define z(Zn) sizeof(Zn) 8 9 // if you're expecting a Z(n), say so, by asking for a ztype, instead of dtype or otype 10 #define ztype(Zn) Zn & | sized(Zn) 8 11 9 12 forall( T & ) struct tag {}; … … 16 19 // 17 20 18 forall( [N], S & | sized(S), Timmed &, Tbase & ) {21 forall( ztype(Zn), ztype(S), Timmed &, Tbase & ) { 19 22 struct arpk { 20 S strides[z( N)];23 S strides[z(Zn)]; 21 24 }; 22 25 23 // About the choice of integral types offered as subscript overloads: 24 // Intent is to cover these use cases: 25 // float foo( ptrdiff_t i ) { return a[i]; } // i : ptrdiff_t 26 // forall( [N] ) ... for( i; N ) { total += a[i]; } // i : typeof( sizeof(42) ) 27 // for( i; 5 ) { total += a[i]; } // i : int 28 // It gets complicated by: 29 // - CFA does overloading on concrete types, like int and unsigned int, not on typedefed 30 // types like size_t. So trying to overload on ptrdiff_t vs int works in 64-bit mode 31 // but not in 32-bit mode. 32 // - Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it 33 // should give them type size_t. 34 // 35 // gcc -m32 cfa -m32 given bug gcc -m64 36 // ptrdiff_t int int long int 37 // size_t unsigned int unsigned int unsigned long int 38 // typeof( sizeof(42) ) unsigned int unsigned long int unsigned long int 39 // int int int int 40 41 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) { 26 Timmed & ?[?]( arpk(Zn, S, Timmed, Tbase) & a, ptrdiff_t i ) { 42 27 return (Timmed &) a.strides[i]; 43 28 } 44 29 45 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned int i ) { 46 return (Timmed &) a.strides[i]; 47 } 48 49 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, long int i ) { 50 return (Timmed &) a.strides[i]; 51 } 52 53 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) { 54 return (Timmed &) a.strides[i]; 55 } 56 57 static inline size_t ?`len( arpk(N, S, Timmed, Tbase) & a ) { 58 return z(N); 30 size_t ?`len( arpk(Zn, S, Timmed, Tbase) & a ) { 31 return z(Zn); 59 32 } 60 33 61 34 // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa) 62 static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {63 void ?{}( S (&inner)[z( N)] ) {}35 void ?{}( arpk(Zn, S, Timmed, Tbase) & this ) { 36 void ?{}( S (&inner)[z(Zn)] ) {} 64 37 ?{}(this.strides); 65 38 } 66 static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {67 void ^?{}( S (&inner)[z( N)] ) {}39 void ^?{}( arpk(Zn, S, Timmed, Tbase) & this ) { 40 void ^?{}( S (&inner)[z(Zn)] ) {} 68 41 ^?{}(this.strides); 69 42 } … … 75 48 76 49 forall( Te ) 77 static inlineTe mkar_( tag(Te) ) {}50 Te mkar_( tag(Te) ) {} 78 51 79 forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )80 static inline arpk(N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}52 forall( ztype(Zn), ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } ) 53 arpk(Zn, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(Zn), ZTags ) {} 81 54 82 55 // based on https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros … … 107 80 // Core -[[-,-,-]] operator 108 81 109 #ifdef TRY_BROKEN_DESIRED_MD_SUBSCRIPT 82 // Desired form. One definition with recursion on IxBC (worked until Jan 2021, see trac #__TODO__) 83 // forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } ) 84 // TC & ?[?]( TA & this, IxAB ab, IxBC bc ) { 85 // return this[ab][bc]; 86 // } 110 87 111 // Desired form. One definition with recursion on IxBC (worked until Jan 2021, see trac #__TODO__)112 113 forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB );TC & ?[?]( TB &, IxBC ); } )114 static inlineTC & ?[?]( TA & this, IxAB ab, IxBC bc ) {88 // 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 ) { 115 92 return this[ab][bc]; 116 93 } 117 118 #else 119 120 // Workaround form. Listing all possibilities up to 4 dims. 121 122 forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } ) 123 static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) { 124 return this[ab][bc]; 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]; 125 106 } 126 107 127 forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } ) 128 static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) { 129 return this[[ab0,ab1]][bc]; 108 // Adapters for "indexed by ptrdiff_t" implies "indexed by [this other integral type]" 109 // Work around restriction that assertions underlying -[[-,-,-]] must match excatly 110 forall( C &, E & | { E & ?[?]( C &, ptrdiff_t ); } ) { 111 112 // Targeted to support: for( i; z(N) ) ... a[[ ..., i, ... ]] 113 E & ?[?]( C & this, size_t i ) { 114 return this[ (ptrdiff_t) i ]; 115 } 116 117 // Targeted to support: for( i; 5 ) ... a[[ ..., i, ... ]] 118 E & ?[?]( C & this, int i ) { 119 return this[ (ptrdiff_t) i ]; 120 } 130 121 } 131 132 forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxAB_2, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1, IxAB_2 ); TC & ?[?]( TB &, IxBC ); } )133 static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) {134 return this[[ab0,ab1,ab2]][bc];135 }136 137 #endif138 122 139 123 // … … 142 126 143 127 // Base 144 forall( [Nq], Sq & | sized(Sq), Tbase & )145 static inline tag(arpk(Nq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(Tbase) ) {}128 forall( ztype(Zq), ztype(Sq), Tbase & ) 129 tag(arpk(Zq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Zq), tag(Sq), tag(Tbase) ) {} 146 130 147 131 // Rec 148 forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } )149 static inline tag(arpk(N, S, recr, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(arpk(N, S, recq, Tbase)) ) {}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)) ) {} 150 134 151 135 // Wrapper 152 136 struct all_t {} all; 153 forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } )154 static inline result & ?[?]( arpk(N, S, Te, Tbase) & this, all_t ) {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 ) { 155 139 return (result&) this; 156 140 } -
libcfa/src/containers/list.hfa
r8d66610 r5407cdc 18 18 #include <assert.h> 19 19 20 forall( Decorator &, T & ) 21 struct tytagref { 22 inline T &; 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; \ 53 } 54 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 &); 23 130 }; 24 131 25 trait embedded( tOuter &, tMid &, tInner & ) { 26 tytagref( tMid, tInner ) ?`inner( tOuter & ); 27 }; 28 29 // embedded is reflexive, with no info (void) as the type tag 30 forall (T &) 31 static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; } 32 33 // use this on every case of plan-9 inheritance, to make embedded a closure of plan-9 inheritance 34 #define P9_EMBEDDED( derived, immedBase ) \ 35 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \ 36 static inline tytagref(immedBase, Tbase) ?`inner( derived & this ) { \ 37 immedBase & ib = this; \ 38 Tbase & b = ib`inner; \ 39 tytagref(immedBase, Tbase) result = { b }; \ 40 return result; \ 41 } 42 43 #define EMBEDDED_VIA( OUTER, MID, INNER ) \ 44 (struct { tytagref(MID, INNER) ( * ?`inner ) ( OUTER & ); }){ ?`inner } 45 46 #define DLINK_VIA( TE, TLINK ) \ 47 EMBEDDED_VIA( TE, TLINK, dlink(TE) ) 48 49 50 // The origin is the position encountered at the start of iteration, 51 // signifying, "need to advance to the first element," and at the end 52 // of iteration, signifying, "no more elements." Normal comsumption of 53 // an iterator runs ?`moveNext as the first step, and uses the return 54 // of ?`moveNext as a guard, before dereferencing the iterator. So 55 // normal consumption of an iterator does not dereference an iterator 56 // in origin position. The value of a pointer (underlying a refence) 57 // that is exposed publicly as an iteraor, and also a pointer stored 58 // internally in a link field, is tagged, to indicate "is the origin" 59 // (internally, is the list-head sentinel node), or untagged, to indicate 60 // "is a regular node." Intent is to help a user who dereferences an 61 // iterator in origin position (which would be an API-use error on their 62 // part), by failing fast. 63 64 #if defined( __x86_64 ) 65 // Preferred case: tag in the most-significant bit. Dereference 66 // has been shown to segfault consistently. Maintenance should 67 // list more architectures as "ok" here, to let them use the 68 // preferred case, when valid. 69 #define ORIGIN_TAG_BITNO ( 8 * sizeof( size_t ) - 1 ) 70 #else 71 // Fallback case: tag in the least-significant bit. Dereference 72 // will often give an alignment error, but may not, e.g. if 73 // accessing a char-typed member. 32-bit x86 uses the most- 74 // significant bit for real room on the heap. 75 #define ORIGIN_TAG_BITNO 0 76 #endif 77 #define ORIGIN_TAG_MASK (((size_t)1) << ORIGIN_TAG_BITNO) 78 79 #define ORIGIN_TAG_SET(p) ((p) | ORIGIN_TAG_MASK) 80 #define ORIGIN_TAG_CLEAR(p) ((p) & ~ORIGIN_TAG_MASK) 81 #define ORIGIN_TAG_QUERY(p) ((p) & ORIGIN_TAG_MASK) 82 83 84 forall( tE & ) { 85 86 struct dlink{ 87 tE *next; 88 tE *prev; 89 }; 90 91 static inline void ?{}( dlink(tE) & this ) { 92 this.next = 0p; 93 this.prev = 0p; 94 } 95 96 forall( tLinks & = dlink(tE) ) 97 struct dlist { 98 inline dlink(tE); 99 }; 100 101 forall( tLinks & | embedded( tE, tLinks, dlink(tE) ) ) { 102 static inline tE * $get_list_origin_addr( dlist(tE, tLinks) & lst ) { 103 dlink(tE) & link_from_null = ( * (tE *) 0p )`inner; 104 ptrdiff_t link_offset = (ptrdiff_t) & link_from_null; 105 size_t origin_addr = ((size_t) & lst) - link_offset; 106 size_t preResult = ORIGIN_TAG_SET( origin_addr ); 107 return (tE *)preResult; 108 } 109 110 static inline void ?{}( dlist(tE, tLinks) & this ) { 111 tE * listOrigin = $get_list_origin_addr( this ); 112 ( ( dlink(tE) & ) this ){ listOrigin, listOrigin } ; 113 } 114 } 115 116 } 117 118 119 forall( tE &, tLinks & | embedded( tE, tLinks, dlink(tE) ) ) { 120 121 static inline void insert_after(tE & list_pos, tE &to_insert) { 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) { 122 188 verify (&list_pos != 0p); 123 189 verify (&to_insert != 0p); 124 dlink(tE) & linkToInsert = to_insert`inner; 125 verify(linkToInsert.prev == 0p); 126 verify(linkToInsert.next == 0p); 127 tE & list_pos_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & list_pos ); 128 dlink(tE) & list_pos_links = list_pos_elem`inner; 129 asm( "" : : : "memory" ); 130 tE & after_raw = * list_pos_links.next; 131 tE & after_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & after_raw ); 132 linkToInsert.prev = & list_pos; 133 linkToInsert.next = & after_raw; 134 dlink(tE) & afterLinks = after_elem`inner; 135 afterLinks.prev = &to_insert; 136 list_pos_links.next = &to_insert; 137 asm( "" : : : "memory" ); 138 } 139 140 static inline void insert_before(tE & list_pos, tE &to_insert) { 190 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 191 verify($prev_link(singleton_to_insert).elem == 0p); 192 verify($next_link(singleton_to_insert).elem == 0p); 193 $prev_link(singleton_to_insert) = & $tempcv_n2e(list_pos); 194 $next_link(singleton_to_insert) = $next_link(list_pos); 195 if ($next_link(list_pos).is_terminator) { 196 dlist(Tnode, Telem) *list = ( dlist(Tnode, Telem) * ) $next_link(list_pos).terminator; 197 $dlinks(Telem) *list_links = & list->$links; 198 $mgd_link(Telem) *list_last = & list_links->prev; 199 *list_last = &to_insert; 200 } else { 201 Telem *list_pos_next = $next_link(list_pos).elem; 202 if (list_pos_next) { 203 Tnode & lpn_inlist = $tempcv_e2n(*list_pos_next); 204 $prev_link(lpn_inlist) = &to_insert; 205 } 206 } 207 $next_link(list_pos) = &to_insert; 208 } 209 210 static inline void insert_before(Tnode &list_pos, Telem &to_insert) { 141 211 verify (&list_pos != 0p); 142 212 verify (&to_insert != 0p); 143 dlink(tE) & linkToInsert = to_insert`inner; 144 verify(linkToInsert.next == 0p); 145 verify(linkToInsert.prev == 0p); 146 tE & list_pos_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & list_pos ); 147 dlink(tE) & list_pos_links = list_pos_elem`inner; 148 asm( "" : : : "memory" ); 149 tE & before_raw = * (list_pos_links).prev; 150 tE & before_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & before_raw ); 151 linkToInsert.next = & list_pos; 152 linkToInsert.prev = & before_raw; 153 dlink(tE) & beforeLinks = before_elem`inner; 154 beforeLinks.next = &to_insert; 155 (list_pos_links).prev = &to_insert; 156 asm( "" : : : "memory" ); 157 } 158 159 static inline tE & remove(tE & list_pos) { 160 verify (&list_pos != 0p); 161 verify( ! ORIGIN_TAG_QUERY((size_t) & list_pos) ); 162 dlink(tE) & list_pos_links = list_pos`inner; 163 tE & before_raw = * list_pos_links.prev; 164 tE & before_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & before_raw ); 165 dlink(tE) & before_links = before_elem`inner; 166 tE & after_raw = * list_pos_links.next; 167 tE & after_elem = * (tE *) ORIGIN_TAG_CLEAR( (size_t) & after_raw ); 168 dlink(tE) & after_links = after_elem`inner; 169 before_links.next = &after_raw; 170 after_links.prev = &before_raw; 171 asm( "" : : : "memory" ); 172 list_pos_links.prev = 0p; 173 list_pos_links.next = 0p; 174 asm( "" : : : "memory" ); 175 return list_pos; 176 } 177 178 static inline tE & ?`first( dlist(tE, tLinks) &lst ) { 179 tE * firstPtr = lst.next; 180 if (ORIGIN_TAG_QUERY((size_t)firstPtr)) firstPtr = 0p; 181 return *firstPtr; 182 } 183 static inline tE & ?`last ( dlist(tE, tLinks) &lst ) { 184 tE * lastPtr = lst.prev; 185 if (ORIGIN_TAG_QUERY((size_t)lastPtr)) lastPtr = 0p; 186 return *lastPtr; 187 } 188 189 static inline bool ?`isEmpty( dlist(tE, tLinks) & lst ) { 190 tE * firstPtr = lst.next; 191 if (ORIGIN_TAG_QUERY((size_t)firstPtr)) firstPtr = 0p; 192 return firstPtr == 0p; 193 } 194 195 static inline bool ?`isListed( tE & e ) { 196 verify (&e != 0p); 197 dlink(tE) & e_links = e`inner; 198 return (e_links.prev != 0p) || (e_links.next != 0p); 199 } 200 201 static inline tE & ?`elems( dlist(tE, tLinks) & lst ) { 202 tE * origin = $get_list_origin_addr( lst ); 203 return *origin; 204 } 205 206 static inline bool ?`moveNext( tE && refx ) { 207 tE && ref_inner = refx; 208 tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner ); 209 &ref_inner = oldReferent`inner.next; 210 return &ref_inner != 0p && 211 ! ORIGIN_TAG_QUERY( (size_t) & ref_inner ); 212 } 213 214 static inline bool ?`movePrev( tE && refx ) { 215 tE && ref_inner = refx; 216 tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner ); 217 &ref_inner = oldReferent`inner.prev; 218 return &ref_inner != 0p && 219 ! ORIGIN_TAG_QUERY( (size_t) & ref_inner ); 220 } 221 222 static inline bool ?`hasNext( tE & e ) { 223 return e`moveNext; 224 } 225 226 static inline bool ?`hasPrev( tE & e ) { 227 return e`movePrev; 228 } 229 230 static inline tE & ?`next( tE & e ) { 231 if( e`moveNext ) return e; 232 return * 0p; 233 } 234 235 static inline tE & ?`prev( tE & e ) { 236 if( e`movePrev ) return e; 237 return * 0p; 238 } 239 240 static inline void insert_first( dlist(tE, tLinks) &lst, tE & e ) { 241 insert_after(lst`elems, e); 242 } 243 244 static inline void insert_last( dlist(tE, tLinks) &lst, tE & e ) { 245 insert_before(lst`elems, e); 246 } 247 248 static inline tE & try_pop_front( dlist(tE, tLinks) &lst ) { 249 tE & first_inlist = lst`first; 250 tE & first_item = first_inlist; 251 if (&first_item) remove(first_inlist); 252 return first_item; 253 } 254 255 static inline tE & try_pop_back( dlist(tE, tLinks) &lst ) { 256 tE & last_inlist = lst`last; 257 tE & last_item = last_inlist; 258 if (&last_item) remove(last_inlist); 259 return last_item; 260 } 261 262 263 #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__)) 264 static bool $validate_fwd( dlist(tE, tLinks) & this ) { 265 if ( ! & this`first ) return ( (& this`last) == 0p); 266 267 tE & lagElem = *0p; 268 269 while ( tE & it = this`elems; it`moveNext ) { 270 if (& lagElem == 0p && &it != & this`first ) return false; 271 & lagElem = & it; 272 } 273 274 if (& lagElem != & this`last) return false; 275 276 // TODO: verify that it is back at this`elems; 277 return true; 278 } 279 static bool $validate_rev( dlist(tE, tLinks) & this ) { 280 if ( ! & this`last ) return ( (& this`first) == 0p); 281 282 tE & lagElem = *0p; 283 284 while ( tE & it = this`elems; it`movePrev ) { 285 if (& lagElem == 0p && &it != & this`last ) return false; 286 & lagElem = & it; 287 } 288 289 if (& lagElem != & this`first) return false; 290 291 // TODO: verify that it is back at this`elems; 292 return true; 293 } 294 static bool validate( dlist(tE, tLinks) & this ) { 295 return $validate_fwd(this) && $validate_rev(this); 296 } 297 #endif 213 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 214 verify($prev_link(singleton_to_insert).elem == 0p); 215 verify($next_link(singleton_to_insert).elem == 0p); 216 $next_link(singleton_to_insert) = & $tempcv_n2e(list_pos); 217 $prev_link(singleton_to_insert) = $prev_link(list_pos); 218 if ($prev_link(list_pos).is_terminator) { 219 dlist(Tnode, Telem) *list = ( dlist(Tnode, Telem) * ) $prev_link(list_pos).terminator; 220 $dlinks(Telem) *list_links = & list->$links; 221 $mgd_link(Telem) *list_first = & list_links->next; 222 *list_first = &to_insert; 223 } else { 224 Telem *list_pos_prev = $prev_link(list_pos).elem; 225 if (list_pos_prev) { 226 Tnode & lpp_inlist = $tempcv_e2n(*list_pos_prev); 227 $next_link(lpp_inlist) = &to_insert; 228 } 229 } 230 $prev_link(list_pos) = &to_insert; 231 } 232 233 static inline void insert_first(dlist(Tnode, Telem) &list, Telem &to_insert) { 234 verify (&list != 0p); 235 verify (&to_insert != 0p); 236 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 237 verify($prev_link(singleton_to_insert).elem == 0p); 238 verify($next_link(singleton_to_insert).elem == 0p); 239 240 $prev_link(singleton_to_insert) = (void*) &list; 241 $next_link(singleton_to_insert) = list.$links.next; 242 243 $dlinks(Telem) *listLinks = & list.$links; 244 if (listLinks->next.is_terminator) { 245 $mgd_link(Telem) * listPrevReference = & listLinks->prev; 246 *listPrevReference = &to_insert; 247 } else { 248 Tnode & next_inlist = $tempcv_e2n(*list.$links.next.elem); 249 $prev_link(next_inlist) = &to_insert; 250 } 251 $mgd_link(Telem) * listNextReference = & listLinks->next; 252 *listNextReference = &to_insert; 253 } 254 255 static inline void insert_last(dlist(Tnode, Telem) &list, Telem &to_insert) { 256 verify (&list != 0p); 257 verify (&to_insert != 0p); 258 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 259 verify($next_link(singleton_to_insert).elem == 0p); 260 verify($prev_link(singleton_to_insert).elem == 0p); 261 262 $next_link(singleton_to_insert) = (void*) &list; 263 $prev_link(singleton_to_insert) = list.$links.prev; 264 265 $dlinks(Telem) *listLinks = & list.$links; 266 if (listLinks->prev.is_terminator) { 267 $mgd_link(Telem) * listNextReference = & listLinks->next; 268 *listNextReference = &to_insert; 269 } else { 270 Tnode & prev_inlist = $tempcv_e2n(*list.$links.prev.elem); 271 $next_link(prev_inlist) = &to_insert; 272 } 273 $mgd_link(Telem) * listPrevReference = & listLinks->prev; 274 *listPrevReference = &to_insert; 275 } 276 277 static inline void remove(Tnode &list_pos) { 278 verify( &list_pos != 0p ); 279 280 $mgd_link(Telem) &incoming_from_prev = *0p; 281 $mgd_link(Telem) &incoming_from_next = *0p; 282 283 if ( $prev_link(list_pos).is_terminator ) { 284 dlist(Tnode, Telem) * tgt_before = ( dlist(Tnode, Telem) * ) $prev_link(list_pos).terminator; 285 $dlinks(Telem) * links_before = & tgt_before->$links; 286 &incoming_from_prev = & links_before->next; 287 } else if ($prev_link(list_pos).elem) { 288 Telem * tgt_before = $prev_link(list_pos).elem; 289 Tnode & list_pos_before = $tempcv_e2n(*tgt_before); 290 &incoming_from_prev = & $next_link(list_pos_before); 291 } 292 293 if ( $next_link(list_pos).is_terminator ) { 294 dlist(Tnode, Telem) * tgt_after = ( dlist(Tnode, Telem) * ) $next_link(list_pos).terminator; 295 $dlinks(Telem) * links_after = & tgt_after->$links; 296 &incoming_from_next = & links_after->prev; 297 } else if ($next_link(list_pos).elem) { 298 Telem * tgt_after = $next_link(list_pos).elem; 299 Tnode & list_pos_after = $tempcv_e2n(*tgt_after ); 300 &incoming_from_next = & $prev_link(list_pos_after ); 301 } 302 303 if (& incoming_from_prev) { 304 incoming_from_prev = $next_link(list_pos); 305 } 306 if (& incoming_from_next) { 307 incoming_from_next = $prev_link(list_pos); 308 } 309 310 $next_link(list_pos) = (Telem*) 0p; 311 $prev_link(list_pos) = (Telem*) 0p; 312 } 313 314 static inline bool ?`is_empty(dlist(Tnode, Telem) &list) { 315 verify( &list != 0p ); 316 $dlinks(Telem) *listLinks = & list.$links; 317 if (listLinks->next.is_terminator) { 318 verify(listLinks->prev.is_terminator); 319 verify(listLinks->next.terminator); 320 verify(listLinks->prev.terminator); 321 return true; 322 } else { 323 verify(!listLinks->prev.is_terminator); 324 verify(listLinks->next.elem); 325 verify(listLinks->prev.elem); 326 return false; 327 } 328 } 329 330 static inline Telem & pop_first(dlist(Tnode, Telem) &list) { 331 verify( &list != 0p ); 332 verify( !list`is_empty ); 333 $dlinks(Telem) *listLinks = & list.$links; 334 Telem & first = *listLinks->next.elem; 335 Tnode & list_pos_first = $tempcv_e2n( first ); 336 remove(list_pos_first); 337 return first; 338 } 339 340 static inline Telem & pop_last(dlist(Tnode, Telem) &list) { 341 verify( &list != 0p ); 342 verify( !list`is_empty ); 343 $dlinks(Telem) *listLinks = & list.$links; 344 Telem & last = *listLinks->prev.elem; 345 Tnode & list_pos_last = $tempcv_e2n( last ); 346 remove(list_pos_last); 347 return last; 348 } 298 349 299 350 } -
libcfa/src/exception.c
r8d66610 r5407cdc 48 48 49 49 // Base Exception type id: 50 struct __cfa vir_type_info__cfatid_exception_t = {50 struct __cfa__parent_vtable __cfatid_exception_t = { 51 51 NULL, 52 52 }; -
libcfa/src/exception.h
r8d66610 r5407cdc 29 29 struct __cfaehm_base_exception_t; 30 30 typedef struct __cfaehm_base_exception_t exception_t; 31 struct __cfa vir_type_info;31 struct __cfa__parent_vtable; 32 32 struct __cfaehm_base_exception_t_vtable { 33 const struct __cfa vir_type_info* __cfavir_typeid;33 const struct __cfa__parent_vtable * __cfavir_typeid; 34 34 size_t size; 35 35 void (*copy)(struct __cfaehm_base_exception_t *this, … … 41 41 struct __cfaehm_base_exception_t_vtable const * virtual_table; 42 42 }; 43 extern struct __cfa vir_type_info__cfatid_exception_t;43 extern struct __cfa__parent_vtable __cfatid_exception_t; 44 44 45 45 -
libcfa/src/exception.hfa
r8d66610 r5407cdc 157 157 #define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \ 158 158 forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \ 159 __cfa vir_type_infoconst * parent; \159 __cfa__parent_vtable const * parent; \ 160 160 } 161 161 162 162 // Generate a new type-id value. 163 163 #define _EHM_TYPE_ID_VALUE(exception_name, arguments) \ 164 __attribute__(( cfa_linkonce)) \164 __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \ 165 165 _EHM_TYPE_ID_TYPE(exception_name) arguments const \ 166 166 _EHM_TYPE_ID_NAME(exception_name) = { \ -
libcfa/src/executor.cfa
r8d66610 r5407cdc 7 7 #include <containers/list.hfa> 8 8 9 forall( T & , TLink& = dlink(T) | embedded(T, TLink, dlink(T)) ) {9 forall( T & | $dlistable(T, T) ) { 10 10 monitor Buffer { // unbounded buffer 11 dlist( T, T Link ) queue;// unbounded list of work requests11 dlist( T, T ) queue; // unbounded list of work requests 12 12 condition delay; 13 13 }; // Buffer 14 14 15 void insert( Buffer(T , TLink) & mutex buf, T * elem ) with(buf) {16 dlist( T, T Link ) * qptr = &queue;// workaround https://cforall.uwaterloo.ca/trac/ticket/16615 void insert( Buffer(T) & mutex buf, T * elem ) with(buf) { 16 dlist( T, T ) * qptr = &queue; // workaround https://cforall.uwaterloo.ca/trac/ticket/166 17 17 insert_last( *qptr, *elem ); // insert element into buffer 18 18 signal( delay ); // restart 19 19 } // insert 20 20 21 T * remove( Buffer(T , TLink) & mutex buf ) with(buf) {22 dlist( T, T Link ) * qptr = &queue;// workaround https://cforall.uwaterloo.ca/trac/ticket/16623 // if ( (*qptr)`is Empty ) wait( delay );// no request to process ? => wait24 if ( (*qptr)`is Empty ) return 0p;// no request to process ? => wait25 return & try_pop_front( *qptr );21 T * remove( Buffer(T) & mutex buf ) with(buf) { 22 dlist( T, T ) * qptr = &queue; // workaround https://cforall.uwaterloo.ca/trac/ticket/166 23 // if ( (*qptr)`is_empty ) wait( delay ); // no request to process ? => wait 24 if ( (*qptr)`is_empty ) return 0p; // no request to process ? => wait 25 return &pop_first( *qptr ); 26 26 } // remove 27 27 } // forall … … 29 29 struct WRequest { // client request, no return 30 30 void (* action)( void ); 31 inline dlink(WRequest);31 DLISTED_MGD_IMPL_IN(WRequest) 32 32 }; // WRequest 33 P9_EMBEDDED(WRequest, dlink(WRequest))33 DLISTED_MGD_IMPL_OUT(WRequest) 34 34 35 35 void ?{}( WRequest & req ) with(req) { action = 0; } -
libcfa/src/fstream.cfa
r8d66610 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 28 20:37:53202113 // Update Count : 44 512 // Last Modified On : Tue Apr 27 22:08:57 2021 13 // Update Count : 442 14 14 // 15 15 … … 114 114 } // fail 115 115 116 void clear( ofstream & os ) {117 clearerr( (FILE *)(os.file$) );118 } // clear119 120 116 int flush( ofstream & os ) { 121 117 return fflush( (FILE *)(os.file$) ); … … 211 207 } // nl 212 208 213 214 209 // *********************************** ifstream *********************************** 215 210 … … 245 240 } // fail 246 241 247 void clear( ifstream & is ) {248 clearerr( (FILE *)(is.file$) );249 } // clear250 251 242 void ends( ifstream & is ) { 252 243 if ( is.acquired$ ) { is.acquired$ = false; release( is ); } 253 244 } // ends 254 245 255 booleof( ifstream & is ) {246 int eof( ifstream & is ) { 256 247 return feof( (FILE *)(is.file$) ); 257 248 } // eof … … 282 273 } // close 283 274 284 ifstream & read( ifstream & is, char data[], size_t size ) {275 ifstream & read( ifstream & is, char * data, size_t size ) { 285 276 if ( fail( is ) ) { 286 277 abort | IO_MSG "attempt read I/O on failed stream"; -
libcfa/src/fstream.hfa
r8d66610 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 28 20:37:57202113 // Update Count : 2 3012 // Last Modified On : Tue Apr 27 22:00:30 2021 13 // Update Count : 226 14 14 // 15 15 … … 70 70 71 71 bool fail( ofstream & ); 72 void clear( ofstream & );73 72 int flush( ofstream & ); 74 73 void open( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w" … … 120 119 121 120 bool fail( ifstream & is ); 122 void clear( ifstream & ); 123 bool eof( ifstream & is ); 121 int eof( ifstream & is ); 124 122 void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r" 125 123 void open( ifstream & is, const char name[] ); 126 124 void close( ifstream & is ); 127 ifstream & read( ifstream & is, char data[], size_t size );125 ifstream & read( ifstream & is, char * data, size_t size ); 128 126 ifstream & ungetc( ifstream & is, char c ); 129 127 -
libcfa/src/heap.cfa
r8d66610 r5407cdc 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 5 13:11:28 202113 // Update Count : 103 512 // Last Modified On : Tue Apr 20 21:20:48 2021 13 // Update Count : 1033 14 14 // 15 15 … … 28 28 #include "bits/locks.hfa" // __spinlock_t 29 29 #include "startup.hfa" // STARTUP_PRIORITY_MEMORY 30 #include "math.hfa" // min30 #include "math.hfa" // ceiling 31 31 #include "bitmanip.hfa" // is_pow2, ceiling2 32 32 -
libcfa/src/iostream.cfa
r8d66610 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 15 09:39:21202113 // Update Count : 13 4212 // Last Modified On : Tue Apr 27 18:01:03 2021 13 // Update Count : 1330 14 14 // 15 15 … … 659 659 int exp10, len2; \ 660 660 eng( f.val, f.pc, exp10 ); /* changes arguments */ \ 661 /* printf( "%g %d %d %d %s\n", f.val, f.wd, f.pc, exp10, format ); */ \662 661 if ( ! f.flags.left && f.wd > 1 ) { \ 663 /* Exponent size : 'e', optional minus sign, number of digits: log10(0) => undefined*/ \664 f.wd -= 1 + (exp10 < 0 ? 1 : 0) + lrint( floor( exp10 == 0 ? 0 : log10( abs( exp10 ) ) ) ) + 1; \662 /* Exponent size (number of digits, 'e', optional minus sign) */ \ 663 f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \ 665 664 if ( f.wd < 1 ) f.wd = 1; \ 666 665 } /* if */ \ … … 709 708 if ( ! f.flags.pc ) { /* no precision */ \ 710 709 fmtstr[sizeof(DFMTNP)-2] = f.base; /* sizeof includes '\0' */ \ 711 /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star] ); */ \710 /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \ 712 711 PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \ 713 712 } else { /* precision */ \ -
libcfa/src/iostream.hfa
r8d66610 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 28 20:37:56202113 // Update Count : 40112 // Last Modified On : Tue Apr 27 17:59:21 2021 13 // Update Count : 398 14 14 // 15 15 … … 52 52 53 53 trait ostream( ostype & | basic_ostream( ostype ) ) { 54 int flush( ostype & ); 54 55 bool fail( ostype & ); // operation failed? 55 void clear( ostype & );56 int flush( ostype & );57 56 void open( ostype &, const char name[], const char mode[] ); 58 57 void close( ostype & ); … … 303 302 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 304 303 istype & ungetc( istype &, char ); 305 booleof( istype & );304 int eof( istype & ); 306 305 }; // basic_istream 307 306 308 307 trait istream( istype & | basic_istream( istype ) ) { 309 308 bool fail( istype & ); 310 void clear( istype & );311 309 void open( istype & is, const char name[] ); 312 310 void close( istype & is ); 313 istype & read( istype &, char [], size_t );311 istype & read( istype &, char *, size_t ); 314 312 void acquire( istype & ); // concurrent access 315 313 }; // istream -
libcfa/src/virtual.c
r8d66610 r5407cdc 10 10 // Created On : Tus Jul 11 15:10:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon May 17 11:01:00 202113 // Update Count : 212 // Last Modified On : Wed Jul 26 14:24:00 2017 13 // Update Count : 1 14 14 // 15 15 … … 17 17 #include "assert.h" 18 18 19 int __cfavir_is_parent( 20 __cfavir_type_id parent, 21 __cfavir_type_id child ) { 19 int __cfa__is_parent( struct __cfa__parent_vtable const * parent, 20 struct __cfa__parent_vtable const * child ) { 22 21 assert( child ); 23 22 do { … … 29 28 } 30 29 31 void * __cfavir_virtual_cast( 32 __cfavir_type_id parent, 33 __cfavir_type_id const * child ) { 30 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 31 struct __cfa__parent_vtable const * const * child ) { 34 32 assert( child ); 35 return (__cfa vir_is_parent(parent, *child)) ? (void *)child : (void *)0;33 return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0; 36 34 } -
libcfa/src/virtual.h
r8d66610 r5407cdc 10 10 // Created On : Tus Jul 11 15:08:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon May 17 11:03:00 202113 // Update Count : 212 // Last Modified On : Wed Jul 26 14:18:00 2017 13 // Update Count : 1 14 14 // 15 15 … … 20 20 #endif 21 21 22 // Information on a type for the virtual system. 23 // There should be exactly one instance per type and there should be a 24 // pointer to it at the head of every virtual table. 25 struct __cfavir_type_info { 26 // Type id of parent type, null if this is a root type. 27 struct __cfavir_type_info const * const parent; 22 // All strict/explicate vtables should have this head, showing their parent. 23 struct __cfa__parent_vtable { 24 struct __cfa__parent_vtable const * const parent; 28 25 }; 29 26 30 // A pointer to type information acts as the type id. 31 typedef struct __cfavir_type_info const * __cfavir_type_id; 32 33 // Takes in two non-null type ids. 34 int __cfavir_is_parent( 35 __cfavir_type_id parent, __cfavir_type_id child ); 27 // Takes in two non-null pointers to type_objects. 28 int __cfa__is_parent( struct __cfa__parent_vtable const * parent, 29 struct __cfa__parent_vtable const * child ); 36 30 37 31 // If parent is a parent of child then return child, otherwise return NULL. 38 32 // Input pointers are none-null, child's first level should be an object with 39 33 // a vtable 40 void * __cfa vir_virtual_cast(41 __cfavir_type_id parent, __cfavir_type_idconst * child );34 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 35 struct __cfa__parent_vtable const * const * child ); 42 36 43 37 #ifdef __cforall -
src/CodeGen/module.mk
r8d66610 r5407cdc 25 25 CodeGen/GenType.cc \ 26 26 CodeGen/GenType.h \ 27 CodeGen/LinkOnce.cc \28 CodeGen/LinkOnce.h \29 27 CodeGen/OperatorTable.cc \ 30 28 CodeGen/OperatorTable.h \ -
src/Concurrency/Keywords.cc
r8d66610 r5407cdc 432 432 new ObjectDecl( 433 433 Virtual::concurrentDefaultVTableName(), 434 noStorageClasses,434 Type::Const, 435 435 LinkageSpec::Cforall, 436 436 /* bitfieldWidth */ nullptr, … … 504 504 new ObjectDecl( 505 505 Virtual::concurrentDefaultVTableName(), 506 Type:: StorageClasses( Type::Extern ),506 Type::Const, 507 507 LinkageSpec::Cforall, 508 508 /* bitfieldWidth */ nullptr, -
src/GenPoly/Box.cc
r8d66610 r5407cdc 1525 1525 stmtsToAddBefore.push_back( new DeclStmt( newBuf ) ); 1526 1526 1527 // if the object has a cleanup attribute, the cleanup should be on the buffer, not the pointer1528 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 1538 1527 delete objectDecl->get_init(); 1539 1528 objectDecl->set_init( new SingleInit( new VariableExpr( newBuf ) ) ); -
src/InitTweak/InitTweak.cc
r8d66610 r5407cdc 1216 1216 1217 1217 void addDataSectonAttribute( ObjectDecl * objDecl ) { 1218 objDecl->attributes.push_back(new Attribute("section", { 1219 new ConstantExpr( Constant::from_string(".data#") ), 1220 })); 1218 Type *strLitT = new PointerType( Type::Qualifiers( ), 1219 new BasicType( Type::Qualifiers( ), BasicType::Char ) ); 1220 std::list< Expression * > attr_params; 1221 attr_params.push_back( 1222 new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) ); 1223 objDecl->attributes.push_back(new Attribute("section", attr_params)); 1221 1224 } 1222 1225 1223 1226 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { 1224 objDecl->attributes.push_back(new ast::Attribute("section", { 1225 ast::ConstantExpr::from_string(objDecl->location, ".data#"), 1226 })); 1227 auto strLitT = new ast::PointerType(new ast::BasicType(ast::BasicType::Char)); 1228 objDecl->attributes.push_back(new ast::Attribute("section", {new ast::ConstantExpr(objDecl->location, strLitT, "\".data#\"", std::nullopt)})); 1227 1229 } 1228 1230 -
src/Parser/DeclarationNode.cc
r8d66610 r5407cdc 1076 1076 if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) { 1077 1077 // otype is internally converted to dtype + otype parameters 1078 static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl:: Dtype };1078 static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::DStype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype, TypeDecl::ALtype }; 1079 1079 static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." ); 1080 1080 assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." ); 1081 TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype || variable.tyClass == TypeDecl::ALtype, variable.initializer ? variable.initializer->buildType() : nullptr );1081 TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype, variable.initializer ? variable.initializer->buildType() : nullptr ); 1082 1082 buildList( variable.assertions, ret->get_assertions() ); 1083 1083 return ret; -
src/Virtual/ExpandCasts.cc
r8d66610 r5407cdc 105 105 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) { 106 106 if ( (! vcast_decl) && 107 functionDecl->get_name() == "__cfa vir_virtual_cast" ) {107 functionDecl->get_name() == "__cfa__virtual_cast" ) { 108 108 vcast_decl = functionDecl; 109 109 } … … 113 113 if ( pvt_decl || ! structDecl->has_body() ) { 114 114 return; 115 } else if ( structDecl->get_name() == "__cfa vir_type_info" ) {115 } else if ( structDecl->get_name() == "__cfa__parent_vtable" ) { 116 116 pvt_decl = structDecl; 117 117 } -
src/Virtual/Tables.cc
r8d66610 r5407cdc 172 172 } 173 173 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 174 181 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) { 175 182 assert( typeIdType ); … … 186 193 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) ) 187 194 ) } ), 188 { new Attribute( "cfa_linkonce", {}) },195 { linkonce( typeid_name ) }, 189 196 noFuncSpecifiers 190 197 ); -
src/main.cc
r8d66610 r5407cdc 37 37 #include "CodeGen/FixNames.h" // for fixNames 38 38 #include "CodeGen/Generate.h" // for generate 39 #include "CodeGen/LinkOnce.h" // for translateLinkOnce40 39 #include "CodeTools/DeclStats.h" // for printDeclStats 41 40 #include "CodeTools/ResolvProtoDump.h" // for dumpAsResolvProto … … 406 405 PASS( "Box", GenPoly::box( translationUnit ) ); 407 406 408 PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) );409 410 // Code has been lowered to C, now we can start generation.411 412 407 if ( bcodegenp ) { 413 408 dump( translationUnit ); -
tests/Makefile.am
r8d66610 r5407cdc 67 67 .PHONY: list .validate 68 68 .INTERMEDIATE: .validate .validate.cfa 69 EXTRA_PROGRAMS = avl_test linkonce.dummy_hack # build but do not install69 EXTRA_PROGRAMS = avl_test .dummy_hack # build but do not install 70 70 EXTRA_DIST = test.py \ 71 71 pybin/__init__.py \ … … 94 94 95 95 avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa 96 linkonce_SOURCES = link-once/main.cfa link-once/partner.cfa97 96 # automake doesn't know we still need C/CPP rules so pretend like we have a C program 98 97 nodist__dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp -
tests/array-container/array-basic.cfa
r8d66610 r5407cdc 5 5 // 6 6 7 forall( [Nx], [Ny], [Nz])7 forall( ztype(Nx), ztype(Ny), ztype(Nz) ) 8 8 void typesTest( tag(Nx), tag(Ny), tag(Nz) ) { 9 9 … … 59 59 } 60 60 61 forall( [Nw], [Nx], [Ny], [Nz])61 forall( ztype(Nw), ztype(Nx), ztype(Ny), ztype(Nz) ) 62 62 void fillHelloData( array( float, Nw, Nx, Ny, Nz ) & wxyz ) { 63 63 for (w; z(Nw)) … … 68 68 } 69 69 70 forall( [Zn]70 forall( ztype(Zn) 71 71 , S & | sized(S) 72 72 ) … … 86 86 } 87 87 88 forall( [Nw], [Nx], [Ny], [Nz])88 forall( ztype(Nw), ztype(Nx), ztype(Ny), ztype(Nz) ) 89 89 void runtimeTest( tag(Nw), tag(Nx), tag(Ny), tag(Nz) ) { 90 90 … … 105 105 printf("result Ws [][][][] lo = %f\n", result); 106 106 107 result = total1d_low( wxyz[[all, slice_ix, slice_ix, slice_ix]] ); 108 printf("result Ws [,,,] lo = %f\n", result); 107 // fixme: -[[-,-,-,-]] not working 108 // result = total1d_low( wxyz[[all, slice_ix, slice_ix, slice_ix]] ); 109 // printf("result Ws [,,,] lo = %f\n", result); 109 110 110 111 result = total1d_hi( wxyz[all][slice_ix][slice_ix][slice_ix] ); 111 112 printf("result Ws [][][][] hi = %f\n", result); 112 113 113 result = total1d_hi( wxyz[[all, slice_ix, slice_ix, slice_ix]] ); 114 printf("result Ws [,,,] hi = %f\n", result); 114 // fixme: -[[-,-,-,-]] not working 115 // result = total1d_hi( wxyz[[all, slice_ix, slice_ix, slice_ix]] ); 116 // printf("result Ws [,,,] hi = %f\n", result); 115 117 116 118 // summing across X, with w=y=z=1 … … 124 126 printf("result Xs [][][][] lo = %f\n", result); 125 127 126 result = total1d_low( wxyz[[slice_ix, all, slice_ix, slice_ix]] ); 127 printf("result Xs [,,,] lo = %f\n", result); 128 // fixme: -[[-,-,-,-]] not working 129 // result = total1d_low( wxyz[[slice_ix, all, slice_ix, slice_ix]] ); 130 // printf("result Xs [,,,] lo = %f\n", result); 128 131 129 132 result = total1d_hi( wxyz[slice_ix][all][slice_ix][slice_ix] ); 130 133 printf("result Xs [][][][] hi = %f\n", result); 131 134 132 result = total1d_hi( wxyz[[slice_ix, all, slice_ix, slice_ix]] ); 133 printf("result Xs [,,,] hi = %f\n", result); 135 // fixme: -[[-,-,-,-]] not working 136 // result = total1d_hi( wxyz[[slice_ix, all, slice_ix, slice_ix]] ); 137 // printf("result Xs [,,,] hi = %f\n", result); 134 138 135 139 } -
tests/concurrent/clib_tls.c
r8d66610 r5407cdc 3 3 #include <clib/cfathread.h> 4 4 #include <bits/defs.hfa> 5 #include <time_t.hfa>6 5 7 6 extern "C" { 8 7 void _exit(int status); 9 8 } 10 11 Duration default_preemption(){12 return 0;13 }14 15 9 16 10 thread_local int checkval = 0xBAADF00D; -
tests/exceptions/virtual-cast.cfa
r8d66610 r5407cdc 16 16 // Hand defined alpha virtual type: 17 17 struct __cfatid_struct_alpha { 18 __cfa vir_type_infoparent;18 __cfa__parent_vtable const * parent; 19 19 }; 20 20 21 __attribute__(( cfa_linkonce))21 __attribute__(( section(".gnu.linkonce.__cfatid_alpha") )) 22 22 struct __cfatid_struct_alpha __cfatid_alpha = { 23 (__cfa vir_type_info*)0,23 (__cfa__parent_vtable *)0, 24 24 }; 25 25 -
tests/exceptions/virtual-poly.cfa
r8d66610 r5407cdc 10 10 11 11 struct __cfatid_struct_mono_base { 12 __cfa vir_type_infoconst * parent;12 __cfa__parent_vtable const * parent; 13 13 }; 14 14 15 __attribute__(( cfa_linkonce))15 __attribute__(( section(".gnu.linkonce.__cfatid_mono_base") )) 16 16 struct __cfatid_struct_mono_base __cfatid_mono_base = { 17 (__cfa vir_type_info*)0,17 (__cfa__parent_vtable *)0, 18 18 }; 19 19 … … 58 58 forall(U) 59 59 struct __cfatid_struct_poly_base { 60 __cfa vir_type_infoconst * parent;60 __cfa__parent_vtable const * parent; 61 61 }; 62 62 … … 87 87 88 88 __cfatid_struct_poly_base(int) __cfatid_poly_base @= { 89 (__cfa vir_type_info*)0,89 (__cfa__parent_vtable *)0, 90 90 }; 91 91 __cfatid_struct_poly_child(int) __cfatid_poly_child = { -
tests/list/.expect/dlist-insert-remove.txt
r8d66610 r5407cdc 1 ~~~~~~~~~~~~~~~~~ Headless List Tests - insert_after ~~~~~~~~~~~~~~~~ 2 3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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 - 1 216 2 217 ~~~~~~~~~~~~~~~~~ Headed List Tests - insert_first ~~~~~~~~~~~~~~~~~~ … … 342 557 - 343 558 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 684 ==== mary before 685 1.7 686 2.7 687 3.7 688 - 689 1.7 690 - 691 3.7 692 - 693 3.7 694 2.7 695 1.7 696 - 697 ==== 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 841 ==== mary before 842 1.7 843 2.7 844 3.7 845 - 846 1.7 847 - 848 3.7 849 - 850 3.7 851 2.7 852 1.7 853 - 854 ==== 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 998 ==== 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 344 1030 ~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~ 345 1031 … … 1092 1778 - 1093 1779 - 1094 1095 ~~~~~~~~~~~~~~~~~~~ Ease-of-access cases ~~~~~~~~~~~~~~~~~~1096 1097 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1098 Test 18-i. Modifying Freds on MINE1099 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1100 Not implmented1101 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1102 Test 18-ii. Modifying Freds on YOURS1103 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1104 Not implmented1105 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1106 Test 18-iii. Modifying Maries1107 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1108 accessor_cases done1109 try_pop cases done1110 origin_mutation cases done1111 isListed cases done -
tests/list/dlist-insert-remove.cfa
r8d66610 r5407cdc 19 19 struct fred { 20 20 float adatum; 21 inline struct mine { inline dlink(fred); };22 inline struct yours { inline dlink(fred); };21 DLISTED_MGD_EXPL_IN(fred, mine) 22 DLISTED_MGD_EXPL_IN(fred, yours) 23 23 }; 24 P9_EMBEDDED(fred, fred.mine) 25 P9_EMBEDDED(fred, fred.yours) 26 P9_EMBEDDED(fred.mine, dlink(fred)) 27 P9_EMBEDDED(fred.yours, dlink(fred)) 28 24 25 DLISTED_MGD_EXPL_OUT(fred, mine) 26 DLISTED_MGD_EXPL_OUT(fred, yours) 29 27 30 28 void ?{}(fred &this, float adatum) { … … 35 33 struct mary { 36 34 float anotherdatum; 37 inline dlink(mary);35 DLISTED_MGD_IMPL_IN(mary) 38 36 }; 39 37 40 P9_EMBEDDED(mary, dlink(mary))38 DLISTED_MGD_IMPL_OUT(mary) 41 39 42 40 void ?{}(mary &this, float anotherdatum) { … … 55 53 //////////////////////////////////////////////////////////// 56 54 57 void printMyFredsFwd(fred & f) { 58 with( DLINK_VIA( fred, fred.mine ) ) 59 do { 55 void printMyFredsFwd(fred &f) { 56 while (&f != 0p) { 60 57 sout | f.adatum; 61 } while (f`moveNext);62 }63 64 void printMyFredsRev(fred & f) { 65 with( DLINK_VIA( fred, fred.mine ) ) 66 do{58 &f = &f`in_mine`next; 59 } 60 } 61 62 void printMyFredsRev(fred &f) { 63 while (&f != 0p) { 67 64 sout | f.adatum; 68 } while (f`movePrev);69 }70 65 &f = &f`in_mine`prev; 66 } 67 } 71 68 72 69 void printMyFreddies(fred &f1, fred &f2, int isBefore) { … … 76 73 sout | "==== fred by MINE after "; 77 74 } 78 if (&f1) { 79 printMyFredsFwd(f1); sout | '-'; 80 printMyFredsRev(f1); sout | '-'; 81 } else { 82 sout | '-'; sout | '-'; 75 printMyFredsFwd(f1); sout | '-'; 76 printMyFredsRev(f1); sout | '-'; 77 printMyFredsFwd(f2); sout | '-'; 78 printMyFredsRev(f2); sout | '-'; 79 } 80 81 void printYourFredsFwd(fred &f) { 82 while (&f != 0p) { 83 sout | f.adatum; 84 &f = &f`in_yours`next; 83 85 } 84 if (&f2) { 85 printMyFredsFwd(f2); sout | '-'; 86 printMyFredsRev(f2); sout | '-'; 87 } else { 88 sout | '-'; sout | '-'; 86 } 87 88 void printYourFredsRev(fred &f) { 89 while (&f != 0p) { 90 sout | f.adatum; 91 &f = &f`in_yours`prev; 89 92 } 90 }91 92 void printYourFredsFwd(fred & f) {93 with( DLINK_VIA( fred, fred.yours ) )94 do {95 sout | f.adatum;96 } while (f`moveNext);97 }98 99 void printYourFredsRev(fred & f) {100 with( DLINK_VIA( fred, fred.yours ) )101 do {102 sout | f.adatum;103 } while (f`movePrev);104 93 } 105 94 … … 110 99 sout | "==== fred by YOURS after "; 111 100 } 112 if (&f1) { 113 printYourFredsFwd(f1); sout | '-'; 114 printYourFredsRev(f1); sout | '-'; 115 } else { 116 sout | '-'; sout | '-'; 101 printYourFredsFwd(f1); sout | '-'; 102 printYourFredsRev(f1); sout | '-'; 103 printYourFredsFwd(f2); sout | '-'; 104 printYourFredsRev(f2); sout | '-'; 105 } 106 107 void printMariesFwd(mary &m) { 108 while (&m != 0p) { 109 sout | m.anotherdatum; 110 &m = &m`next; 117 111 } 118 if (&f2) { 119 printYourFredsFwd(f2); sout | '-'; 120 printYourFredsRev(f2); sout | '-'; 121 } else { 122 sout | '-'; sout | '-'; 112 } 113 114 void printMariesRev(mary &m) { 115 while (&m != 0p) { 116 sout | m.anotherdatum; 117 &m = &m`prev; 123 118 } 124 }125 126 void printMariesFwd(mary &m) {127 do {128 sout | m.anotherdatum;129 } while (m`moveNext);130 }131 132 void printMariesRev(mary &m) {133 do {134 sout | m.anotherdatum;135 } while (m`movePrev);136 119 } 137 120 … … 142 125 sout | "==== mary after "; 143 126 } 144 if (&m1) { 145 printMariesFwd(m1); sout | '-'; 146 printMariesRev(m1); sout | '-'; 147 } else { 148 sout | '-'; sout | '-'; 149 } 150 if (&m2) { 151 printMariesFwd(m2); sout | '-'; 152 printMariesRev(m2); sout | '-'; 153 } else { 154 sout | '-'; sout | '-'; 155 } 127 printMariesFwd(m1); sout | '-'; 128 printMariesRev(m1); sout | '-'; 129 printMariesFwd(m2); sout | '-'; 130 printMariesRev(m2); sout | '-'; 156 131 } 157 132 … … 178 153 // - from list position #2 moving backward (d) 179 154 // The expected-output comments are in form a;b;c;d where a::=num,num,num 180 #if 0 155 181 156 void test__insertafter_singleton_on_singleton__fred_mine () { 182 157 fred f1 = {3.14}; … … 186 161 printYourFreddies(f1, f2, 1); // 3.14; 3.14; 0.5; 0.5 187 162 188 diref(fred, fred.mine) f1_mine = f1`from; 189 insert_after(f1_mine, f2); 163 insert_after(f1`in_mine, f2); 190 164 191 165 printMyFreddies(f1, f2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) … … 200 174 printYourFreddies(f1, f2, 1); // 3.14; 3.14; 0.5; 0.5 201 175 202 diref(fred, fred.yours) f1_yours = f1`from; 203 insert_after(f1_yours, f2); 176 insert_after(f1`in_yours, f2); 204 177 205 178 printMyFreddies(f1, f2, 0); // 3.14; 3.14; 0.5; 0.5 (unmodified) … … 235 208 printYourFreddies(f1, f2, 1); // 3.14; 3.14; 0.5; 0.5 236 209 237 diref(fred, fred.mine) f2_mine = f2`from; 238 insert_before(f2_mine, f1); 210 insert_before(f2`in_mine, f1); 239 211 240 212 printMyFreddies(f1, f2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) … … 249 221 printYourFreddies(f1, f2, 1); // 3.14; 3.14; 0.5; 0.5 250 222 251 diref(fred, fred.yours) f2_yours = f2`from; 252 insert_before(f2_yours, f1); 223 insert_before(f2`in_yours, f1); 253 224 254 225 printMyFreddies(f1, f2, 0); // 3.14; 3.14; 0.5; 0.5 (unmodified) … … 266 237 printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) 267 238 } 268 #endif 239 269 240 //////////////////////////////////////////////////////////// 270 241 // … … 279 250 // All three tests exercise the case of creating an empty container and 280 251 // adding two items to it. 252 281 253 void test__insertfirst_two_on_empty__fred_mine() { 282 254 … … 284 256 fred f2 = {0.5}; 285 257 286 dlist(fred , fred.mine) lf;258 dlist(fred_in_mine, fred) lf; 287 259 288 260 verify(validate(lf)); … … 305 277 fred f2 = {0.5}; 306 278 307 dlist(fred , fred.yours) lf;279 dlist(fred_in_yours, fred) lf; 308 280 309 281 verify(validate(lf)); … … 320 292 printYourFreddies(f1, f2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) 321 293 } 294 322 295 void test__insertfirst_two_on_empty__mary() { 323 296 … … 325 298 mary m2 = {0.5}; 326 299 327 dlist(mary ) lm;300 dlist(mary, mary) lm; 328 301 329 302 verify(validate(lm)); … … 352 325 fred f2 = {0.5}; 353 326 354 dlist(fred , fred.mine) lf;327 dlist(fred_in_mine, fred) lf; 355 328 356 329 verify(validate(lf)); … … 373 346 fred f2 = {0.5}; 374 347 375 dlist(fred , fred.yours) lf;348 dlist(fred_in_yours, fred) lf; 376 349 377 350 verify(validate(lf)); … … 394 367 mary m2 = {0.5}; 395 368 396 dlist(mary ) lm;369 dlist(mary, mary) lm; 397 370 398 371 verify(validate(lm)); … … 421 394 fred f2 = {0.5}; 422 395 423 dlist(fred , fred.mine) lf;424 425 assert( & lf`first == 0p);426 assert( & lf`last == 0p);396 dlist(fred_in_mine, fred) lf; 397 398 assert(& lf`first == 0p); 399 assert(& lf`last == 0p); 427 400 428 401 insert_first(lf, f1); 429 402 430 assert( & lf`first == & f1);431 assert( & lf`last == & f1);403 assert(& lf`first == & f1); 404 assert(& lf`last == & f1); 432 405 433 406 verify(validate(lf)); 434 407 435 with ( DLINK_VIA(fred, fred.mine) ) insert_after(f1, f2);408 insert_after(f1`in_mine, f2); 436 409 437 410 verify(validate(lf)); … … 440 413 printYourFreddies(f1, f2, 0); // 3.14; 3.14; 0.5; 0.5 (unmodified) 441 414 442 assert( & lf`first == & f1);443 assert( & lf`last == & f2);415 assert(& lf`first == & f1); 416 assert(& lf`last == & f2); 444 417 } 445 418 … … 449 422 fred f2 = {0.5}; 450 423 451 dlist(fred , fred.yours) lf;452 453 assert( & lf`first == 0p);454 assert( & lf`last == 0p);424 dlist(fred_in_yours, fred) lf; 425 426 assert(& lf`first == 0p); 427 assert(& lf`last == 0p); 455 428 456 429 insert_first(lf, f1); 457 430 458 assert( & lf`first == & f1);459 assert( & lf`last == & f1);431 assert(& lf`first == & f1); 432 assert(& lf`last == & f1); 460 433 461 434 verify(validate(lf)); 462 435 463 with ( DLINK_VIA(fred, fred.yours) ) insert_after(f1, f2);436 insert_after(f1`in_yours, f2); 464 437 465 438 verify(validate(lf)); … … 468 441 printYourFreddies(f1, f2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) 469 442 470 assert( & lf`first == & f1);471 assert( & lf`last == & f2);443 assert(& lf`first == & f1); 444 assert(& lf`last == & f2); 472 445 } 473 446 … … 477 450 mary m2 = {0.5}; 478 451 479 dlist(mary ) lm;480 481 assert( & lm`first == 0p);482 assert( & lm`last == 0p);452 dlist(mary, mary) lm; 453 454 assert(& lm`first == 0p); 455 assert(& lm`last == 0p); 483 456 484 457 insert_first(lm, m1); 485 458 486 assert( & lm`first == & m1);487 assert( & lm`last == & m1);459 assert(& lm`first == & m1); 460 assert(& lm`last == & m1); 488 461 489 462 verify(validate(lm)); … … 495 468 printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) 496 469 497 assert( & lm`first == & m1);498 assert( & lm`last == & m2);470 assert(& lm`first == & m1); 471 assert(& lm`last == & m2); 499 472 } 500 473 … … 514 487 fred f2 = {0.5}; 515 488 516 dlist(fred , fred.mine) lf;517 518 assert( & lf`first == 0p);519 assert( & lf`last == 0p);489 dlist(fred_in_mine, fred) lf; 490 491 assert(& lf`first == 0p); 492 assert(& lf`last == 0p); 520 493 521 494 insert_last(lf, f2); 522 495 523 assert( & lf`first == & f2);524 assert( & lf`last == & f2);496 assert(& lf`first == & f2); 497 assert(& lf`last == & f2); 525 498 526 499 verify(validate(lf)); 527 500 528 with ( DLINK_VIA(fred, fred.mine) ) insert_before(f2, f1);501 insert_before(f2`in_mine, f1); 529 502 530 503 verify(validate(lf)); … … 533 506 printYourFreddies(f1, f2, 0); // 3.14; 3.14; 0.5; 0.5 (unmodified) 534 507 535 assert( & lf`first == & f1);536 assert( & lf`last == & f2);508 assert(& lf`first == & f1); 509 assert(& lf`last == & f2); 537 510 } 538 511 … … 542 515 fred f2 = {0.5}; 543 516 544 dlist(fred , fred.yours) lf;545 546 assert( & lf`first == 0p);547 assert( & lf`last == 0p);517 dlist(fred_in_yours, fred) lf; 518 519 assert(& lf`first == 0p); 520 assert(& lf`last == 0p); 548 521 549 522 insert_last(lf, f2); 550 523 551 assert( & lf`first == & f2);552 assert( & lf`last == & f2);524 assert(& lf`first == & f2); 525 assert(& lf`last == & f2); 553 526 554 527 verify(validate(lf)); 555 528 556 with ( DLINK_VIA(fred, fred.yours) )insert_before(f2, f1);529 insert_before(f2`in_yours, f1); 557 530 558 531 verify(validate(lf)); … … 561 534 printYourFreddies(f1, f2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) 562 535 563 assert( & lf`first == & f1);564 assert( & lf`last == & f2);536 assert(& lf`first == & f1); 537 assert(& lf`last == & f2); 565 538 } 566 539 … … 570 543 mary m2 = {0.5}; 571 544 572 dlist(mary ) lm;573 574 assert( & lm`first == 0p);575 assert( & lm`last == 0p);545 dlist(mary, mary) lm; 546 547 assert(& lm`first == 0p); 548 assert(& lm`last == 0p); 576 549 577 550 insert_last(lm, m2); 578 551 579 assert( & lm`first == & m2);580 assert( & lm`last == & m2);552 assert(& lm`first == & m2); 553 assert(& lm`last == & m2); 581 554 582 555 verify(validate(lm)); … … 588 561 printMariatheotokos(m1, m2, 0); // 3.14, 0.5; 3.14; 0.5; 0.5, 3.14 (modified) 589 562 590 assert( & lm`first == & m1 ); 591 assert( & lm`last == & m2 ); 592 } 593 #if 0 563 assert(& lm`first == & m1); 564 assert(& lm`last == & m2); 565 } 594 566 595 567 //////////////////////////////////////////////////////////// … … 874 846 // 875 847 //////////////////////////////////////////////////////////// 876 #endif 848 877 849 void test__remove_at_head__fred_mine() { 878 850 … … 881 853 fred f3 = {3.7}; 882 854 883 dlist(fred , fred.mine) flm;855 dlist(fred_in_mine, fred) flm; 884 856 insert_last(flm, f1); 885 857 insert_last(flm, f2); 886 858 insert_last(flm, f3); 887 859 888 dlist(fred , fred.yours) fly;860 dlist(fred_in_yours, fred) fly; 889 861 insert_last(fly, f1); 890 862 insert_last(fly, f2); … … 897 869 verify(validate(flm)); 898 870 899 with( DLINK_VIA(fred, fred.mine) ) remove(f1);871 remove(f1`in_mine); 900 872 901 873 verify(validate(fly)); … … 909 881 910 882 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 911 // assert(f1.$links_mine.next.is_terminator == false); 912 // assert(f1.$links_mine.prev.is_terminator == false); 913 } 914 883 assert(f1.$links_mine.next.is_terminator == false); 884 assert(f1.$links_mine.prev.is_terminator == false); 885 } 915 886 916 887 void test__remove_at_head__fred_yours() { … … 920 891 fred f3 = {3.7}; 921 892 922 dlist(fred , fred.mine) flm;893 dlist(fred_in_mine, fred) flm; 923 894 insert_last(flm, f1); 924 895 insert_last(flm, f2); 925 896 insert_last(flm, f3); 926 897 927 dlist(fred , fred.yours) fly;898 dlist(fred_in_yours, fred) fly; 928 899 insert_last(fly, f1); 929 900 insert_last(fly, f2); … … 936 907 verify(validate(flm)); 937 908 938 with( DLINK_VIA(fred, fred.yours) ) remove(f1);909 remove(f1`in_yours); 939 910 940 911 verify(validate(fly)); … … 948 919 949 920 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 950 //assert(f1.$links_yours.next.is_terminator == false);951 //assert(f1.$links_yours.prev.is_terminator == false);921 assert(f1.$links_yours.next.is_terminator == false); 922 assert(f1.$links_yours.prev.is_terminator == false); 952 923 } 953 924 … … 958 929 mary m3 = {3.7}; 959 930 960 dlist(mary ) ml;931 dlist(mary, mary) ml; 961 932 insert_last(ml, m1); 962 933 insert_last(ml, m2); … … 977 948 978 949 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 979 //assert(m1.$links.next.is_terminator == false);980 //assert(m1.$links.prev.is_terminator == false);950 assert(m1.$links.next.is_terminator == false); 951 assert(m1.$links.prev.is_terminator == false); 981 952 } 982 953 … … 997 968 fred f3 = {3.7}; 998 969 999 dlist(fred , fred.mine) flm;970 dlist(fred_in_mine, fred) flm; 1000 971 insert_last(flm, f1); 1001 972 insert_last(flm, f2); 1002 973 insert_last(flm, f3); 1003 974 1004 dlist(fred , fred.yours) fly;975 dlist(fred_in_yours, fred) fly; 1005 976 insert_last(fly, f1); 1006 977 insert_last(fly, f2); … … 1013 984 verify(validate(flm)); 1014 985 1015 with( DLINK_VIA(fred, fred.mine) ) remove(f3);986 remove(f3`in_mine); 1016 987 1017 988 verify(validate(fly)); … … 1025 996 1026 997 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 1027 //assert(f3.$links_mine.next.is_terminator == false);1028 //assert(f3.$links_mine.prev.is_terminator == false);998 assert(f3.$links_mine.next.is_terminator == false); 999 assert(f3.$links_mine.prev.is_terminator == false); 1029 1000 } 1030 1001 … … 1035 1006 fred f3 = {3.7}; 1036 1007 1037 dlist(fred , fred.mine) flm;1008 dlist(fred_in_mine, fred) flm; 1038 1009 insert_last(flm, f1); 1039 1010 insert_last(flm, f2); 1040 1011 insert_last(flm, f3); 1041 1012 1042 dlist(fred , fred.yours) fly;1013 dlist(fred_in_yours, fred) fly; 1043 1014 insert_last(fly, f1); 1044 1015 insert_last(fly, f2); … … 1051 1022 verify(validate(flm)); 1052 1023 1053 with( DLINK_VIA(fred, fred.yours) ) remove(f3);1024 remove(f3`in_yours); 1054 1025 1055 1026 verify(validate(fly)); … … 1063 1034 1064 1035 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 1065 //assert(f3.$links_yours.next.is_terminator == false);1066 //assert(f3.$links_yours.prev.is_terminator == false);1036 assert(f3.$links_yours.next.is_terminator == false); 1037 assert(f3.$links_yours.prev.is_terminator == false); 1067 1038 } 1068 1039 … … 1073 1044 mary m3 = {3.7}; 1074 1045 1075 dlist(mary ) ml;1046 dlist(mary, mary) ml; 1076 1047 insert_last(ml, m1); 1077 1048 insert_last(ml, m2); … … 1092 1063 1093 1064 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 1094 //assert(m3.$links.next.is_terminator == false);1095 //assert(m3.$links.prev.is_terminator == false);1065 assert(m3.$links.next.is_terminator == false); 1066 assert(m3.$links.prev.is_terminator == false); 1096 1067 } 1097 1068 … … 1110 1081 fred f = {0.7}; 1111 1082 1112 dlist(fred , fred.mine) flm;1083 dlist(fred_in_mine, fred) flm; 1113 1084 insert_last(flm, f); 1114 1085 1115 dlist(fred , fred.yours) fly;1086 dlist(fred_in_yours, fred) fly; 1116 1087 insert_last(fly, f); 1117 1088 … … 1122 1093 verify(validate(flm)); 1123 1094 1124 with( DLINK_VIA(fred, fred.mine) ) remove(f);1125 1126 verify(validate(fly)); 1127 verify(validate(flm)); 1128 1129 assert( & flm`first == 0p);1130 assert( & flm`last == 0p);1095 remove(f`in_mine); 1096 1097 verify(validate(fly)); 1098 verify(validate(flm)); 1099 1100 assert(& flm`first == 0p); 1101 assert(& flm`last == 0p); 1131 1102 1132 1103 printYourFreddies(fly`first, fly`last, 0); // 0.7; 0.7; 0.7; 0.7 (unmodified) … … 1136 1107 1137 1108 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 1138 //assert(f.$links_mine.next.is_terminator == false);1139 //assert(f.$links_mine.prev.is_terminator == false);1109 assert(f.$links_mine.next.is_terminator == false); 1110 assert(f.$links_mine.prev.is_terminator == false); 1140 1111 1141 1112 insert_last(flm, f); … … 1149 1120 fred f = {0.7}; 1150 1121 1151 dlist(fred , fred.mine) flm;1122 dlist(fred_in_mine, fred) flm; 1152 1123 insert_last(flm, f); 1153 1124 1154 dlist(fred , fred.yours) fly;1125 dlist(fred_in_yours, fred) fly; 1155 1126 insert_last(fly, f); 1156 1127 … … 1161 1132 verify(validate(flm)); 1162 1133 1163 with( DLINK_VIA(fred, fred.yours) ) remove(f);1164 1165 verify(validate(fly)); 1166 verify(validate(flm)); 1167 1168 assert( & fly`first == 0p);1169 assert( & fly`last == 0p);1134 remove(f`in_yours); 1135 1136 verify(validate(fly)); 1137 verify(validate(flm)); 1138 1139 assert(& fly`first == 0p); 1140 assert(& fly`last == 0p); 1170 1141 1171 1142 printYourFreddies(flm`first, flm`last, 0); // 0.7; 0.7; 0.7; 0.7 (unmodified) … … 1175 1146 1176 1147 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 1177 //assert(f.$links_yours.next.is_terminator == false);1178 //assert(f.$links_yours.prev.is_terminator == false);1148 assert(f.$links_yours.next.is_terminator == false); 1149 assert(f.$links_yours.prev.is_terminator == false); 1179 1150 1180 1151 insert_last(fly, f); … … 1188 1159 mary m = {0.7}; 1189 1160 1190 dlist(mary ) ml;1161 dlist(mary, mary) ml; 1191 1162 insert_last(ml, m); 1192 1163 … … 1199 1170 verify(validate(ml)); 1200 1171 1201 assert( & ml`first == 0p);1202 assert( & ml`last == 0p);1172 assert(& ml`first == 0p); 1173 assert(& ml`last == 0p); 1203 1174 1204 1175 // observe f is solo in mine (now unlisted); in yours, it was just traversed … … 1206 1177 1207 1178 // TODO: decide on appropriate ovservable outcome (is_listed?) and its itended semantics 1208 //assert(m.$links.next.is_terminator == false);1209 //assert(m.$links.prev.is_terminator == false);1179 assert(m.$links.next.is_terminator == false); 1180 assert(m.$links.prev.is_terminator == false); 1210 1181 1211 1182 insert_last(ml, m); … … 1232 1203 fred f3 = {3.7}; 1233 1204 1234 dlist(fred , fred.mine) flm;1205 dlist(fred_in_mine, fred) flm; 1235 1206 insert_last(flm, f1); 1236 1207 insert_last(flm, f2); 1237 1208 insert_last(flm, f3); 1238 1209 1239 dlist(fred , fred.yours) fly;1210 dlist(fred_in_yours, fred) fly; 1240 1211 insert_last(fly, f1); 1241 1212 insert_last(fly, f2); … … 1248 1219 verify(validate(flm)); 1249 1220 1250 fred & popped = try_pop_front(flm);1221 fred & popped = pop_first(flm); 1251 1222 1252 1223 verify(validate(fly)); … … 1268 1239 fred f3 = {3.7}; 1269 1240 1270 dlist(fred , fred.mine) flm;1241 dlist(fred_in_mine, fred) flm; 1271 1242 insert_last(flm, f1); 1272 1243 insert_last(flm, f2); 1273 1244 insert_last(flm, f3); 1274 1245 1275 dlist(fred , fred.yours) fly;1246 dlist(fred_in_yours, fred) fly; 1276 1247 insert_last(fly, f1); 1277 1248 insert_last(fly, f2); … … 1284 1255 verify(validate(flm)); 1285 1256 1286 fred & popped = try_pop_front(fly);1257 fred & popped = pop_first(fly); 1287 1258 1288 1259 verify(validate(fly)); … … 1304 1275 mary m3 = {3.7}; 1305 1276 1306 dlist(mary ) ml;1277 dlist(mary, mary) ml; 1307 1278 insert_last(ml, m1); 1308 1279 insert_last(ml, m2); … … 1313 1284 verify(validate(ml)); 1314 1285 1315 mary & popped = try_pop_front(ml);1286 mary & popped = pop_first(ml); 1316 1287 1317 1288 verify(validate(ml)); … … 1331 1302 fred f3 = {3.7}; 1332 1303 1333 dlist(fred , fred.mine) flm;1304 dlist(fred_in_mine, fred) flm; 1334 1305 insert_last(flm, f1); 1335 1306 insert_last(flm, f2); 1336 1307 insert_last(flm, f3); 1337 1308 1338 dlist(fred , fred.yours) fly;1309 dlist(fred_in_yours, fred) fly; 1339 1310 insert_last(fly, f1); 1340 1311 insert_last(fly, f2); … … 1347 1318 verify(validate(flm)); 1348 1319 1349 fred & popped = try_pop_back(flm);1320 fred & popped = pop_last(flm); 1350 1321 1351 1322 verify(validate(fly)); … … 1367 1338 fred f3 = {3.7}; 1368 1339 1369 dlist(fred , fred.mine) flm;1340 dlist(fred_in_mine, fred) flm; 1370 1341 insert_last(flm, f1); 1371 1342 insert_last(flm, f2); 1372 1343 insert_last(flm, f3); 1373 1344 1374 dlist(fred , fred.yours) fly;1345 dlist(fred_in_yours, fred) fly; 1375 1346 insert_last(fly, f1); 1376 1347 insert_last(fly, f2); … … 1383 1354 verify(validate(flm)); 1384 1355 1385 fred & popped = try_pop_back(fly);1356 fred & popped = pop_last(fly); 1386 1357 1387 1358 verify(validate(fly)); … … 1403 1374 mary m3 = {3.7}; 1404 1375 1405 dlist(mary ) ml;1376 dlist(mary, mary) ml; 1406 1377 insert_last(ml, m1); 1407 1378 insert_last(ml, m2); … … 1412 1383 verify(validate(ml)); 1413 1384 1414 mary & popped = try_pop_back(ml);1385 mary & popped = pop_last(ml); 1415 1386 1416 1387 verify(validate(ml)); … … 1426 1397 //////////////////////////////////////////////////////////// 1427 1398 // 1428 // Section 4g1429 //1430 // Test cases of `isEmpty, `hasPrev, `hasNext,1431 // try_pop_front, try_pop_back, modifications via `elems1432 //1433 // Example of call-side user code1434 //1435 ////////////////////////////////////////////////////////////1436 1437 void test__accessor_cases__mary() {1438 1439 mary m1 = {1.7};1440 mary m2 = {2.7};1441 mary m3 = {3.7};1442 1443 dlist(mary) ml; assert( ml`isEmpty);1444 1445 insert_last(ml, m1); assert(!ml`isEmpty);1446 insert_last(ml, m2); assert(!ml`isEmpty);1447 insert_last(ml, m3); assert(!ml`isEmpty);1448 1449 mary & m1prev = m1`prev;1450 mary & m1next = m1`next;1451 mary & m2prev = m2`prev;1452 mary & m2next = m2`next;1453 mary & m3prev = m3`prev;1454 mary & m3next = m3`next;1455 1456 assert (&m1prev == 0p);1457 assert (&m1next == &m2);1458 assert (&m2prev == &m1);1459 assert (&m2next == &m3);1460 assert (&m3prev == &m2);1461 assert (&m3next == 0p);1462 1463 assert(!m1`hasPrev);1464 assert( m1`hasNext);1465 assert( m2`hasPrev);1466 assert( m2`hasNext);1467 assert( m3`hasPrev);1468 assert(!m3`hasNext);1469 1470 printf("accessor_cases done\n");1471 }1472 1473 void test__try_pop__mary() {1474 1475 mary m1 = {1.7};1476 mary m2 = {2.7};1477 mary m3 = {3.7};1478 1479 dlist(mary) ml;1480 1481 mary &m1r = *0p;1482 mary &m2r = *0p;1483 mary &m3r = *0p;1484 mary &mxr = *0p;1485 1486 // queue, back to front1487 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 back1509 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 front1531 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 back1553 1554 assert( ml`isEmpty);1555 1556 insert_last(ml, m1);1557 insert_last(ml, m2);1558 insert_last(ml, m3);1559 1560 &m3r = & try_pop_back(ml); assert(!ml`isEmpty);1561 &m2r = & try_pop_back(ml); assert(!ml`isEmpty);1562 &m1r = & try_pop_back(ml); assert( ml`isEmpty);1563 &mxr = & try_pop_back(ml); assert( ml`isEmpty);1564 1565 assert( &m1r == &m1 );1566 assert( &m2r == &m2 );1567 assert( &m3r == &m3 );1568 assert( &mxr == 0p );1569 1570 &m1r = 0p;1571 &m2r = 0p;1572 &m3r = 0p;1573 1574 printf("try_pop cases done\n");1575 }1576 1577 void test__origin_mutation__mary() {1578 1579 mary m1 = {1.7};1580 1581 dlist(mary) ml;1582 mary & mlorigin = ml`elems;1583 1584 // insert before the origin1585 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, &vv1596 1597 bool canMoveNext = mllast`moveNext;1598 bool canMovePrev = mlfirst`movePrev;1599 1600 assert( ! canMoveNext );1601 assert( ! canMovePrev );1602 1603 assert( &mlorigin == & mlfirst );1604 assert( &mlorigin == & mllast );1605 1606 printf("origin_mutation cases done\n");1607 }1608 1609 void test__isListed_cases__mary() {1610 1611 mary m1 = {1.7}; assert(! m1`isListed);1612 mary m2 = {2.7}; assert(! m2`isListed);1613 mary m3 = {3.7}; assert(! m3`isListed);1614 1615 dlist(mary) ml;1616 1617 insert_last(ml, m1); assert( m1`isListed); assert(! m2`isListed);1618 insert_last(ml, m2); assert( m2`isListed); assert(! m3`isListed);1619 insert_last(ml, m3); assert( m3`isListed);1620 1621 remove( m1 ); assert(! m1`isListed); assert( m2`isListed);1622 remove( m2 ); assert(! m2`isListed); assert( m3`isListed);1623 remove( m3 ); assert(! m3`isListed);1624 1625 printf("isListed cases done\n");1626 }1627 1628 ////////////////////////////////////////////////////////////1629 //1630 1399 // Section 5 1631 1400 // … … 1635 1404 1636 1405 int main() { 1637 #if 0 1406 1638 1407 sout | "~~~~~~~~~~~~~~~~~ Headless List Tests - insert_after ~~~~~~~~~~~~~~~~"; 1639 1408 sout | ""; … … 1672 1441 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; 1673 1442 test__insertbefore_singleton_on_singleton__mary(); 1674 #endif 1443 1675 1444 sout | ""; 1676 1445 sout | "~~~~~~~~~~~~~~~~~ Headed List Tests - insert_first ~~~~~~~~~~~~~~~~~~"; … … 1748 1517 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; 1749 1518 test__insertbefore_before_first__mary(); 1750 #if 01751 1519 1752 1520 sout | ""; … … 1806 1574 sout | "~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; 1807 1575 test__remove_at_last__mary(); 1808 #endif 1576 1809 1577 sout | ""; 1810 1578 sout | "~~~~~~~~~~ Element removal tests on Headed List: at first ~~~~~~~~~~"; … … 1902 1670 test__pop_last__maries(); 1903 1671 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 1927 1672 return 0; 1928 1673 } -
tests/strstream.cfa
r8d66610 r5407cdc 1 //2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo3 //4 // strstream.cfa --5 //6 // Author : Peter A. Buhr7 // Created On : Wed Apr 28 21:47:35 20218 // Last Modified By : Peter A. Buhr9 // Last Modified On : Wed Apr 28 21:50:02 202110 // Update Count : 311 //12 13 1 #include <fstream.hfa> 14 2 #include <strstream.hfa> 15 3 16 4 int main() { 17 enum { size = 256 };18 char buf[size]; // output buffer 19 ostrstream osstr = { buf, size }; // bind output buffer/size 20 int i = 3, j = 5, k = 7;21 double x = 12345678.9, y = 98765.4321e-11;5 enum { size = 256 }; 6 char buf[size]; 7 ostrstream osstr = { buf, size }; 8 int i = 3, j = 5, k = 7; 9 double x = 12345678.9, y = 98765.4321e-11; 22 10 23 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); // same lines of output 24 write( osstr );25 printf( "%s", buf );26 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));11 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); 12 write( osstr ); 13 printf( "%s", buf ); 14 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); 27 15 28 // char buf2[] = "12 14 15 3.5 7e4"; // input buffer 29 // istrstream isstr = { buf2 };30 // isstr | i | j | k | x | y;31 // sout | i | j | k | x | y;16 // char buf2[] = "12 14 15 3.5 7e4"; 17 // istrstream isstr = { buf2 }; 18 // isstr | i | j | k | x | y; 19 // sout | i | j | k | x | y; 32 20 } 33 34 // Local Variables: //35 // tab-width: 4 //36 // compile-command: "cfa strstream.cfa" //37 // End: // -
tests/unified_locking/timeout_lock.cfa
r8d66610 r5407cdc 33 33 34 34 for ( unsigned int i = 0; i < NoOfTimes + 3; i += 1 ) { 35 if ( wait( c_m, m, 1 000000`ns ) ) {35 if ( wait( c_m, m, 1`s ) ) { 36 36 // printf("Thread: %p signalled\n", active_thread()); // removed since can't expect non deterministic output 37 37 } else { … … 51 51 // Test calls which occur increasingly close to timeout value. 52 52 53 sleep( 100000 `ns );53 sleep( 100000000`ns ); 54 54 notify_one(c_m); 55 55 block(); 56 56 57 sleep( 500000 `ns );57 sleep( 500000000`ns ); 58 58 notify_one(c_m); 59 59 block(); 60 60 61 sleep( 900000 `ns );61 sleep( 900000000`ns ); 62 62 notify_one(c_m); 63 63 block(); 64 64 65 65 for ( unsigned int i = 0; i < NoOfTimes; i += 1 ) { 66 sleep( 999700 `ns );66 sleep( 999700000`ns ); 67 67 notify_one(c_m); 68 68 block(); … … 75 75 wait( c_m, 1`ns ); // bool wait( condition_variable(L) & this, Duration duration ); 76 76 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 ); 77 79 lock(m); wait( c_m, m, 1`ns ); unlock(m); // bool wait( condition_variable(L) & this, L & l, Duration duration ); 78 80 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 ); 79 83 printf("Done Test 1\n"); 80 84
Note:
See TracChangeset
for help on using the changeset viewer.