Changes in / [e2e7330:bc6f918]
- Files:
-
- 8 added
- 9 deleted
- 50 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
re2e7330 rbc6f918 9 9 config.log 10 10 stamp-h1 11 /Makefile 12 src/**/Makefile 13 tools/**/Makefile 11 Makefile 12 driver/Makefile 13 libcfa/Makefile 14 src/Makefile 14 15 /version 15 16 -
Jenkinsfile
re2e7330 rbc6f918 174 174 175 175 def notify_server(int wait) { 176 sh """curl -- data "wait=${wait}" -X POST http://plg2:8082/jenkins/notify > /dev/null || true"""176 sh """curl --silent --data "wait=${wait}" -X POST http://plg2:8082/jenkins/notify > /dev/null || true""" 177 177 return 178 178 } … … 324 324 325 325 //Then publish the results 326 sh 'curl -H \'Content-Type: application/json\'--data @bench.json http://plg2:8082/jenkins/publish > /dev/null || true'326 sh 'curl -H "Content-Type: application/json" --silent --data @bench.json http://plg2:8082/jenkins/publish > /dev/null || true' 327 327 } 328 328 } -
doc/papers/OOPSLA17/.gitignore
re2e7330 rbc6f918 1 1 # generated by latex 2 build/* 2 *.aux 3 *.bbl 4 *.blg 5 *.brf 6 *.dvi 7 *.idx 8 *.ilg 9 *.ind 10 *.log 11 *.out 3 12 *.pdf 4 13 *.ps 14 *.toc 15 *.lof 16 *.lot 17 *.synctex.gz 18 comment.cut 19 timing.tex -
doc/papers/OOPSLA17/Makefile
re2e7330 rbc6f918 1 ## Define the configuration variables.1 ## Define the appropriate configuration variables. 2 2 3 Build = build 4 Figures = figures 5 Macros = ../../LaTeXmacros 6 TeXLIB = .:${Macros}:${Build}:../../bibliography: 7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build} 3 TeXLIB = .:../LaTeXmacros:../LaTeXmacros/listings:../LaTeXmacros/enumitem:../bibliography/: 4 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 8 5 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 9 10 MAKEFLAGS = --no-print-directory --silent #11 VPATH = ${Figures} evaluation12 6 13 7 ## Define the text source files. … … 39 33 40 34 clean : 41 @rm -frv ${DOCUMENT} ${basename ${DOCUMENT}}.ps ${Build} 35 rm -f *.bbl *.aux *.dvi *.idx *.ilg *.ind *.brf *.out *.log *.toc *.blg *.pstex_t *.cf \ 36 ${FIGURES} ${PICTURES} ${PROGRAMS} ${GRAPHS} ${basename ${DOCUMENT}}.ps ${DOCUMENT} 42 37 43 38 # File Dependencies # … … 47 42 48 43 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 49 dvips $ {Build}/$< -o $@44 dvips $< -o $@ 50 45 51 ${basename ${DOCUMENT}}.dvi : Makefile ${Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex ../../bibliography/pl.bib 46 #${DOCUMENT} : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \ 47 48 ${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex ../bibliography/cfa.bib 49 # Conditionally create an empty *.idx (index) file for inclusion until makeindex is run. 50 if [ ! -r ${basename $@}.idx ] ; then touch ${basename $@}.idx ; fi 52 51 # Must have *.aux file containing citations for bibtex 53 52 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 54 -${BibTeX} ${ Build}/${basename $@}55 # Some citations reference others so run again to resolve these citations53 -${BibTeX} ${basename $@} 54 # Some citations reference others so run steps again to resolve these citations 56 55 ${LaTeX} ${basename $@}.tex 57 -${BibTeX} ${Build}/${basename $@} 58 # Run again to finish citations 56 -${BibTeX} ${basename $@} 57 # Make index from *.aux entries and input index at end of document 58 makeindex -s ../LaTeXmacros/indexstyle ${basename $@}.idx 59 59 ${LaTeX} ${basename $@}.tex 60 # Run again to get index title into table of contents 61 ${LaTeX} ${basename $@}.tex 62 63 predefined : 64 sed -f predefined.sed ${basename ${DOCUMENT}}.tex > ${basename $@}.cf 60 65 61 66 ## Define the default recipes. 62 67 63 ${Build}: 64 mkdir -p ${Build} 65 66 ${GRAPHS} : timing.gp timing.dat 67 gnuplot -e Build="'${Build}/'" evaluation/timing.gp 68 ${GRAPHS} : evaluation/timing.gp evaluation/timing.dat 69 gnuplot evaluation/timing.gp 68 70 69 71 %.tex : %.fig 70 fig2dev -L eepic $< > $ {Build}/$@72 fig2dev -L eepic $< > $@ 71 73 72 74 %.ps : %.fig 73 fig2dev -L ps $< > $ {Build}/$@75 fig2dev -L ps $< > $@ 74 76 75 77 %.pstex : %.fig 76 fig2dev -L pstex $< > $ {Build}/$@77 fig2dev -L pstex_t -p $ {Build}/$@ $< > ${Build}/$@_t78 fig2dev -L pstex $< > $@ 79 fig2dev -L pstex_t -p $@ $< > $@_t 78 80 79 81 # Local Variables: # -
doc/papers/OOPSLA17/evaluation/timing.gp
re2e7330 rbc6f918 2 2 # set output "timing.pdf" 3 3 set terminal pslatex size 6.25,2.125 color solid 4 set output Build."timing.tex"4 set output "timing.tex" 5 5 6 6 set pointsize 2.0 -
doc/papers/OOPSLA17/generic_types.tex
re2e7330 rbc6f918 1109 1109 1110 1110 \bibliographystyle{ACM-Reference-Format} 1111 \bibliography{ pl}1111 \bibliography{cfa} 1112 1112 1113 1113 -
doc/papers/concurrency/.gitignore
re2e7330 rbc6f918 1 # generated by latex 2 build/* 1 build/*.aux 2 build/*.acn 3 build/*.acr 4 build/*.alg 5 build/*.bbl 6 build/*.blg 7 build/*.brf 8 build/*.dvi 9 build/*.glg 10 build/*.glo 11 build/*.gls 12 build/*.idx 13 build/*.ind 14 build/*.ist 15 build/*.lof 16 build/*.log 17 build/*.lol 18 build/*.lot 19 build/*.out 20 build/*.ps 21 build/*.pstex 22 build/*.pstex_t 23 build/*.tex 24 build/*.toc 3 25 *.pdf 4 *.ps 26 *.png 27 figures/*.tex 28 29 examples -
doc/papers/concurrency/Paper.tex
re2e7330 rbc6f918 1 % inline code ©...© (copyright symbol) emacs: C-q M-) 2 % red highlighting ®...® (registered trademark symbol) emacs: C-q M-. 3 % blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_ 4 % green highlighting ¢...¢ (cent symbol) emacs: C-q M-" 5 % LaTex escape §...§ (section symbol) emacs: C-q M-' 6 % keyword escape ¶...¶ (pilcrow symbol) emacs: C-q M-^ 1 % requires tex packages: texlive-base texlive-latex-base tex-common texlive-humanities texlive-latex-extra texlive-fonts-recommended 2 3 % inline code �...� (copyright symbol) emacs: C-q M-) 4 % red highlighting �...� (registered trademark symbol) emacs: C-q M-. 5 % blue highlighting �...� (sharp s symbol) emacs: C-q M-_ 6 % green highlighting �...� (cent symbol) emacs: C-q M-" 7 % LaTex escape �...� (section symbol) emacs: C-q M-' 8 % keyword escape �...� (pilcrow symbol) emacs: C-q M-^ 7 9 % math escape $...$ (dollar symbol) 8 10 … … 18 20 \usepackage{epic,eepic} 19 21 \usepackage{upquote} % switch curled `'" to straight 22 \usepackage{dirtytalk} 20 23 \usepackage{calc} 21 24 \usepackage{xspace} … … 43 46 \urlstyle{rm} 44 47 48 \usepackage{tikz} 49 \def\checkmark{\tikz\fill[scale=0.4](0,.35) -- (.25,0) -- (1,.7) -- (.25,.15) -- cycle;} 50 45 51 \setlength{\topmargin}{-0.45in} % move running title into header 46 52 \setlength{\headsep}{0.25in} … … 72 78 73 79 \title{Concurrency in \CFA} 74 \author{Thierry Delisle and Peter A. Buhr, Waterloo, Ontario, Canada}80 \author{Thierry Delisle, Waterloo, Ontario, Canada, 2018} 75 81 76 82 … … 79 85 80 86 \begin{abstract} 81 \CFA is a modern, \emph{non-object-oriented} extension of the C programming language. 82 This paper serves as a definition and an implementation for the concurrency and parallelism \CFA offers. These features are created from scratch due to the lack of concurrency in ISO C. Lightweight threads are introduced into the language. In addition, monitors are introduced as a high-level tool for control-flow based synchronization and mutual-exclusion. The main contributions of this paper are two-fold: it extends the existing semantics of monitors introduce by~\cite{Hoare74} to handle monitors in groups and also details the engineering effort needed to introduce these features as core language features. Indeed, these features are added with respect to expectations of C programmers, and integrate with the \CFA type-system and other language features. 87 \CFA is a modern, non-object-oriented extension of the C programming language. This thesis serves as a definition and an implementation for the concurrency and parallelism \CFA offers. These features are created from scratch due to the lack of concurrency in ISO C. Lightweight threads are introduced into the language. In addition, monitors are introduced as a high-level tool for control-flow based synchronization and mutual-exclusion. The main contributions of this thesis are two-fold: it extends the existing semantics of monitors introduce by~\cite{Hoare74} to handle monitors in groups and also details the engineering effort needed to introduce these features as core language features. Indeed, these features are added with respect to expectations of C programmers, and integrate with the \CFA type-system and other language features. 83 88 \end{abstract} 84 89 … … 90 95 \section{Introduction} 91 96 % ====================================================================== 92 93 This paper provides a minimal concurrency \textbf{api} that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency system is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of concurrency. Indeed, for highly productive concurrent programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading. The high-level approach and its minimal \textbf{api} are tested in a dialect of C, called \CFA. Furthermore, the proposed \textbf{api} doubles as an early definition of the \CFA language and library. This paper also provides an implementation of the concurrency library for \CFA as well as all the required language features added to the source-to-source translator. 97 This thesis provides a minimal concurrency \textbf{api} that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency system is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of concurrency. Indeed, for highly productive concurrent programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading. The high-level approach and its minimal \textbf{api} are tested in a dialect of C, called \CFA. Furthermore, the proposed \textbf{api} doubles as an early definition of the \CFA language and library. This thesis also provides an implementation of the concurrency library for \CFA as well as all the required language features added to the source-to-source translator. 94 98 95 99 There are actually two problems that need to be solved in the design of concurrency for a programming language: which concurrency and which parallelism tools are available to the programmer. While these two concepts are often combined, they are in fact distinct, requiring different tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are about performance, cost and resource utilization. 96 100 97 In the context of this paper, a \textbf{thread} is a fundamental unit of execution that runs a sequence of code, generally on a program stack. Having multiple simultaneous threads gives rise to concurrency and generally requires some kind of locking mechanism to ensure proper execution. Correspondingly, \textbf{concurrency} is defined as the concepts and challenges that occur when multiple independent (sharing memory, timing dependencies, etc.) concurrent threads are introduced. Accordingly, \textbf{locking} (and by extension locks) are defined as a mechanism that prevents the progress of certain threads in order to avoid problems due to concurrency. Finally, in this paper\textbf{parallelism} is distinct from concurrency and is defined as running multiple threads simultaneously. More precisely, parallelism implies \emph{actual} simultaneous execution as opposed to concurrency which only requires \emph{apparent} simultaneous execution. As such, parallelism is only observable in the differences in performance or, more generally, differences in timing.101 In the context of this thesis, a \textbf{thread} is a fundamental unit of execution that runs a sequence of code, generally on a program stack. Having multiple simultaneous threads gives rise to concurrency and generally requires some kind of locking mechanism to ensure proper execution. Correspondingly, \textbf{concurrency} is defined as the concepts and challenges that occur when multiple independent (sharing memory, timing dependencies, etc.) concurrent threads are introduced. Accordingly, \textbf{locking} (and by extension locks) are defined as a mechanism that prevents the progress of certain threads in order to avoid problems due to concurrency. Finally, in this thesis \textbf{parallelism} is distinct from concurrency and is defined as running multiple threads simultaneously. More precisely, parallelism implies \emph{actual} simultaneous execution as opposed to concurrency which only requires \emph{apparent} simultaneous execution. As such, parallelism is only observable in the differences in performance or, more generally, differences in timing. 98 102 99 103 % ====================================================================== … … 109 113 110 114 % ====================================================================== 111 \s ubsection{References}115 \section{References} 112 116 113 117 Like \CC, \CFA introduces rebind-able references providing multiple dereferencing as an alternative to pointers. In regards to concurrency, the semantic difference between pointers and references are not particularly relevant, but since this document uses mostly references, here is a quick overview of the semantics: … … 128 132 129 133 % ====================================================================== 130 \s ubsection{Overloading}134 \section{Overloading} 131 135 132 136 Another important feature of \CFA is function overloading as in Java and \CC, where routines with the same name are selected based on the number and type of the arguments. As well, \CFA uses the return type as part of the selection criteria, as in Ada~\cite{Ada}. For routines with multiple parameters and returns, the selection is complex. … … 149 153 150 154 % ====================================================================== 151 \s ubsection{Operators}155 \section{Operators} 152 156 Overloading also extends to operators. The syntax for denoting operator-overloading is to name a routine with the symbol of the operator and question marks where the arguments of the operation appear, e.g.: 153 157 \begin{cfacode} … … 169 173 170 174 % ====================================================================== 171 \s ubsection{Constructors/Destructors}175 \section{Constructors/Destructors} 172 176 Object lifetime is often a challenge in concurrency. \CFA uses the approach of giving concurrent meaning to object lifetime as a means of synchronization and/or mutual exclusion. Since \CFA relies heavily on the lifetime of objects, constructors and destructors is a core feature required for concurrency and parallelism. \CFA uses the following syntax for constructors and destructors: 173 177 \begin{cfacode} … … 204 208 205 209 % ====================================================================== 206 \s ubsection{Parametric Polymorphism}210 \section{Parametric Polymorphism} 207 211 \label{s:ParametricPolymorphism} 208 212 Routines in \CFA can also be reused for multiple types. This capability is done using the \code{forall} clauses, which allow separately compiled routines to support generic usage over multiple types. For example, the following sum function works for any type that supports construction from 0 and addition: … … 237 241 238 242 % ====================================================================== 239 \s ubsection{with Clause/Statement}243 \section{with Clause/Statement} 240 244 Since \CFA lacks the concept of a receiver, certain functions end up needing to repeat variable names often. To remove this inconvenience, \CFA provides the \code{with} statement, which opens an aggregate scope making its fields directly accessible (like Pascal). 241 245 \begin{cfacode} … … 282 286 283 287 \section{\protect\CFA's Thread Building Blocks} 284 One of the important features that are missing in C is threading\footnote{While the C11 standard defines a ``threads.h'' header, it is minimal and defined as optional. As such, library support for threading is far from widespread. At the time of writing the paper, neither \texttt{gcc} nor \texttt{clang} support ``threads.h'' in their respective standard libraries.}. On modern architectures, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore modern programming languages must have the proper tools to allow users to write efficient concurrent programs to take advantage of parallelism. As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages. And being a system-level language means programmers expect to choose precisely which features they need and which cost they are willing to pay.288 One of the important features that are missing in C is threading\footnote{While the C11 standard defines a ``threads.h'' header, it is minimal and defined as optional. As such, library support for threading is far from widespread. At the time of writing the thesis, neither \texttt{gcc} nor \texttt{clang} support ``threads.h'' in their respective standard libraries.}. On modern architectures, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore modern programming languages must have the proper tools to allow users to write efficient concurrent programs to take advantage of parallelism. As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages. And being a system-level language means programmers expect to choose precisely which features they need and which cost they are willing to pay. 285 289 286 290 \section{Coroutines: A Stepping Stone}\label{coroutine} … … 660 664 \end{cfacode} 661 665 662 In this example, threads of type \code{foo} start execution in the \code{void main(foo &)} routine, which prints \code{"Hello World!".} While this paperencourages this approach to enforce strongly typed programming, users may prefer to use the routine-based thread semantics for the sake of simplicity. With the static semantics it is trivial to write a thread type that takes a function pointer as a parameter and executes it on its stack asynchronously.666 In this example, threads of type \code{foo} start execution in the \code{void main(foo &)} routine, which prints \code{"Hello World!".} While this thesis encourages this approach to enforce strongly typed programming, users may prefer to use the routine-based thread semantics for the sake of simplicity. With the static semantics it is trivial to write a thread type that takes a function pointer as a parameter and executes it on its stack asynchronously. 663 667 \begin{cfacode} 664 668 typedef void (*voidFunc)(int); … … 995 999 % ====================================================================== 996 1000 % ====================================================================== 997 In addition to mutual exclusion, the monitors at the core of \CFA's concurrency can also be used to achieve synchronization. With monitors, this capability is generally achieved with internal or external scheduling as in~\cite{Hoare74}. With \textbf{scheduling} loosely defined as deciding which thread acquires the critical section next, \textbf{internal scheduling} means making the decision from inside the critical section (i.e., with access to the shared state), while \textbf{external scheduling} means making the decision when entering the critical section (i.e., without access to the shared state). Since internal scheduling within a single monitor is mostly a solved problem, this paperconcentrates on extending internal scheduling to multiple monitors. Indeed, like the \textbf{bulk-acq} semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side.1001 In addition to mutual exclusion, the monitors at the core of \CFA's concurrency can also be used to achieve synchronization. With monitors, this capability is generally achieved with internal or external scheduling as in~\cite{Hoare74}. With \textbf{scheduling} loosely defined as deciding which thread acquires the critical section next, \textbf{internal scheduling} means making the decision from inside the critical section (i.e., with access to the shared state), while \textbf{external scheduling} means making the decision when entering the critical section (i.e., without access to the shared state). Since internal scheduling within a single monitor is mostly a solved problem, this thesis concentrates on extending internal scheduling to multiple monitors. Indeed, like the \textbf{bulk-acq} semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side. 998 1002 999 1003 First, here is a simple example of internal scheduling: … … 1796 1800 A \textbf{cfacluster} is a group of \textbf{kthread} executed in isolation. \textbf{uthread} are scheduled on the \textbf{kthread} of a given \textbf{cfacluster}, allowing organization between \textbf{uthread} and \textbf{kthread}. It is important that \textbf{kthread} belonging to a same \textbf{cfacluster} have homogeneous settings, otherwise migrating a \textbf{uthread} from one \textbf{kthread} to the other can cause issues. A \textbf{cfacluster} also offers a pluggable scheduler that can optimize the workload generated by the \textbf{uthread}. 1797 1801 1798 \textbf{cfacluster} have not been fully implemented in the context of this paper. Currently \CFA only supports one \textbf{cfacluster}, the initial one.1802 \textbf{cfacluster} have not been fully implemented in the context of this thesis. Currently \CFA only supports one \textbf{cfacluster}, the initial one. 1799 1803 1800 1804 \subsection{Future Work: Machine Setup}\label{machine} 1801 While this was not done in the context of this paper, another important aspect of clusters is affinity. While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heterogeneous setups. For example, a system using \textbf{numa} configurations may benefit from users being able to tie clusters and/or kernel threads to certain CPU cores. OS support for CPU affinity is now common~\cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx}, which means it is both possible and desirable for \CFA to offer an abstraction mechanism for portable CPU affinity.1805 While this was not done in the context of this thesis, another important aspect of clusters is affinity. While many common desktop and laptop PCs have homogeneous CPUs, other devices often have more heterogeneous setups. For example, a system using \textbf{numa} configurations may benefit from users being able to tie clusters and/or kernel threads to certain CPU cores. OS support for CPU affinity is now common~\cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx}, which means it is both possible and desirable for \CFA to offer an abstraction mechanism for portable CPU affinity. 1802 1806 1803 1807 \subsection{Paradigms}\label{cfaparadigms} … … 1811 1815 The main memory concern for concurrency is queues. All blocking operations are made by parking threads onto queues and all queues are designed with intrusive nodes, where each node has pre-allocated link fields for chaining, to avoid the need for memory allocation. Since several concurrency operations can use an unbound amount of memory (depending on \textbf{bulk-acq}), statically defining information in the intrusive fields of threads is insufficient.The only way to use a variable amount of memory without requiring memory allocation is to pre-allocate large buffers of memory eagerly and store the information in these buffers. Conveniently, the call stack fits that description and is easy to use, which is why it is used heavily in the implementation of internal scheduling, particularly variable-length arrays. Since stack allocation is based on scopes, the first step of the implementation is to identify the scopes that are available to store the information, and which of these can have a variable-length array. The threads and the condition both have a fixed amount of memory, while \code{mutex} routines and blocking calls allow for an unbound amount, within the stack size. 1812 1816 1813 Note that since the major contributions of this paperare extending monitor semantics to \textbf{bulk-acq} and loose object definitions, any challenges that are not resulting of these characteristics of \CFA are considered as solved problems and therefore not discussed.1817 Note that since the major contributions of this thesis are extending monitor semantics to \textbf{bulk-acq} and loose object definitions, any challenges that are not resulting of these characteristics of \CFA are considered as solved problems and therefore not discussed. 1814 1818 1815 1819 % ====================================================================== … … 2611 2615 2612 2616 \section{Conclusion} 2613 This paper has achieved a minimal concurrency \textbf{api} that is simple, efficient and usable as the basis for higher-level features. The approach presented is based on a lightweight thread-system for parallelism, which sits on top of clusters of processors. This M:N model is judged to be both more efficient and allow more flexibility for users. Furthermore, this document introduces monitors as the main concurrency tool for users. This paperalso offers a novel approach allowing multiple monitors to be accessed simultaneously without running into the Nested Monitor Problem~\cite{Lister77}. It also offers a full implementation of the concurrency runtime written entirely in \CFA, effectively the largest \CFA code base to date.2617 This thesis has achieved a minimal concurrency \textbf{api} that is simple, efficient and usable as the basis for higher-level features. The approach presented is based on a lightweight thread-system for parallelism, which sits on top of clusters of processors. This M:N model is judged to be both more efficient and allow more flexibility for users. Furthermore, this document introduces monitors as the main concurrency tool for users. This thesis also offers a novel approach allowing multiple monitors to be accessed simultaneously without running into the Nested Monitor Problem~\cite{Lister77}. It also offers a full implementation of the concurrency runtime written entirely in \CFA, effectively the largest \CFA code base to date. 2614 2618 2615 2619 … … 2621 2625 2622 2626 \subsection{Performance} \label{futur:perf} 2623 This paperpresents a first implementation of the \CFA concurrency runtime. Therefore, there is still significant work to improve performance. Many of the data structures and algorithms may change in the future to more efficient versions. For example, the number of monitors in a single \textbf{bulk-acq} is only bound by the stack size, this is probably unnecessarily generous. It may be possible that limiting the number helps increase performance. However, it is not obvious that the benefit would be significant.2627 This thesis presents a first implementation of the \CFA concurrency runtime. Therefore, there is still significant work to improve performance. Many of the data structures and algorithms may change in the future to more efficient versions. For example, the number of monitors in a single \textbf{bulk-acq} is only bound by the stack size, this is probably unnecessarily generous. It may be possible that limiting the number helps increase performance. However, it is not obvious that the benefit would be significant. 2624 2628 2625 2629 \subsection{Flexible Scheduling} \label{futur:sched} … … 2725 2729 \section{Acknowledgements} 2726 2730 2727 Thanks to Aaron Moss, Rob Schluntz and Andrew Beach for their work on the \CFA project as well as all the discussions which helped concretize the ideas in this paper. 2728 Partial funding was supplied by the Natural Sciences and Engineering Research Council of Canada and a corporate partnership with Huawei Ltd. 2731 I would like to thank my supervisor, Professor Peter Buhr, for his guidance through my degree as well as the editing of this document. 2732 2733 I would like to thank Professors Martin Karsten and Gregor Richards, for reading my thesis and providing helpful feedback. 2734 2735 Thanks to Aaron Moss, Rob Schluntz and Andrew Beach for their work on the \CFA project as well as all the discussions which have helped me concretize the ideas in this thesis. 2736 2737 Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science and the corporate partnership with Huawei Ltd. 2729 2738 2730 2739 … … 2735 2744 2736 2745 \end{document} 2737 2738 % Local Variables: %2739 % tab-width: 4 %2740 % fill-column: 120 %2741 % compile-command: "make" %2742 % End: % -
doc/papers/general/.gitignore
re2e7330 rbc6f918 1 1 # generated by latex 2 build/* 2 *.aux 3 *.bbl 4 *.blg 5 *.brf 6 *.dvi 7 *.idx 8 *.ilg 9 *.ind 10 *.log 11 *.out 3 12 *.pdf 4 13 *.ps 14 *.toc 15 *.lof 16 *.lot 17 *.synctex.gz 18 comment.cut 19 timing.tex -
doc/papers/general/Paper.tex
re2e7330 rbc6f918 1095 1095 1096 1096 \bibliographystyle{plain} 1097 \bibliography{ pl}1097 \bibliography{cfa} 1098 1098 1099 1099 -
doc/papers/general/evaluation/timing.gp
re2e7330 rbc6f918 2 2 # set output "timing.pdf" 3 3 set terminal pslatex size 6.25,2.125 color solid 4 set output Build."timing.tex"4 set output "timing.tex" 5 5 6 6 set pointsize 2.0 -
doc/proposals/tuples/tuples.tex
re2e7330 rbc6f918 322 322 \addcontentsline{toc}{section}{\refname} 323 323 \bibliographystyle{plain} 324 \bibliography{ pl}324 \bibliography{cfa} 325 325 326 326 %\addcontentsline{toc}{section}{\indexname} % add index name to table of contents -
doc/refrat/.gitignore
re2e7330 rbc6f918 1 1 # generated by latex 2 build/* 2 *.aux 3 *.bbl 4 *.blg 5 *.brf 6 *.dvi 7 *.idx 8 *.ilg 9 *.ind 10 *.log 11 *.out 3 12 *.pdf 4 13 *.ps 14 *.toc -
doc/refrat/Makefile
re2e7330 rbc6f918 1 ## Define the configuration variables.1 ## Define the appropriate configuration variables. 2 2 3 Build = build 4 Figures = figures 5 Macros = ../LaTeXmacros 6 TeXLIB = .:${Macros}:${Build}:../bibliography: 7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build} 3 TeXLIB = .:../LaTeXmacros:../LaTeXmacros/listings:../LaTeXmacros/enumitem:../bibliography/: 4 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 8 5 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 9 10 MAKEFLAGS = --no-print-directory --silent #11 VPATH = ${Figures}12 6 13 7 ## Define the text source files. … … 37 31 # Directives # 38 32 39 .PHONY : all clean # not file names40 41 33 all : ${DOCUMENT} 42 34 43 35 clean : 44 @rm -frv ${DOCUMENT} ${basename ${DOCUMENT}}.ps ${Build} 36 rm -f *.bbl *.aux *.dvi *.idx *.ilg *.ind *.brf *.out *.log *.toc *.blg *.pstex_t *.cf \ 37 ${FIGURES} ${PICTURES} ${PROGRAMS} ${GRAPHS} ${basename ${DOCUMENT}}.ps ${DOCUMENT} 45 38 46 39 # File Dependencies # … … 50 43 51 44 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 52 dvips $ {Build}/$< -o $@45 dvips $< -o $@ 53 46 54 ${basename ${DOCUMENT}}.dvi : Makefile ${ Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \55 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib47 ${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \ 48 ../LaTeXmacros/common.tex ../LaTeXmacros/lstlang.sty ../LaTeXmacros/indexstyle ../bibliography/cfa.bib 56 49 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 57 if [ ! -r ${basename $@}.ind ] ; then touch ${ Build}/${basename $@}.ind ; fi50 if [ ! -r ${basename $@}.ind ] ; then touch ${basename $@}.ind ; fi 58 51 # Must have *.aux file containing citations for bibtex 59 52 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 60 -${BibTeX} ${ Build}/${basename $@}61 # Some citations reference others so run again to resolve these citations53 -${BibTeX} ${basename $@} 54 # Some citations reference others so run steps again to resolve these citations 62 55 ${LaTeX} ${basename $@}.tex 63 -${BibTeX} ${ Build}/${basename $@}56 -${BibTeX} ${basename $@} 64 57 # Make index from *.aux entries and input index at end of document 65 makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx 66 # Run again to finish citations 58 makeindex -s ../LaTeXmacros/indexstyle ${basename $@}.idx 67 59 ${LaTeX} ${basename $@}.tex 68 60 # Run again to get index title into table of contents … … 74 66 ## Define the default recipes. 75 67 76 ${Build}:77 mkdir -p ${Build}78 79 68 %.tex : %.fig 80 fig2dev -L eepic $< > $ {Build}/$@69 fig2dev -L eepic $< > $@ 81 70 82 71 %.ps : %.fig 83 fig2dev -L ps $< > $ {Build}/$@72 fig2dev -L ps $< > $@ 84 73 85 74 %.pstex : %.fig 86 fig2dev -L pstex $< > $ {Build}/$@87 fig2dev -L pstex_t -p $ {Build}/$@ $< > ${Build}/$@_t75 fig2dev -L pstex $< > $@ 76 fig2dev -L pstex_t -p $@ $< > $@_t 88 77 89 78 # Local Variables: # -
doc/refrat/refrat.tex
re2e7330 rbc6f918 11 11 %% Created On : Wed Apr 6 14:52:25 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Wed Jan 31 17:30:23 201814 %% Update Count : 10 813 %% Last Modified On : Tue Aug 15 18:46:31 2017 14 %% Update Count : 106 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 141 141 The manual deliberately imitates the ordering of the \Celeven standard (although the section numbering differs). 142 142 Unfortunately, this means the manual contains more ``forward references'' than usual, making it harder to follow if the reader does not have a copy of the \Celeven standard. 143 For a simple introduction to \CFA, see~\cite{Cforall}. 143 For a simple introduction to \CFA, see the companion document ``An Overview of \CFA'' 144 \cite{Ditchfield96:Overview}. 144 145 145 146 \begin{rationale} … … 595 596 \begin{rationale} 596 597 Since each subsection describes the interpretations of an expression in terms of the interpretations of its subexpressions, this chapter can be taken as describing an overload resolution algorithm that uses one bottom-up pass over an expression tree. 597 Such an algorithm was first described (for Ada) by Baker~\cite{Bak er82}.598 Such an algorithm was first described (for Ada) by Baker~\cite{Bak:overload}. 598 599 It is extended here to handle polymorphic functions and arithmetic conversions. 599 600 The overload resolution rules and the predefined functions have been chosen so that, in programs that do not introduce overloaded declarations, expressions will have the same meaning in C and in \CFA. … … 3774 3775 3775 3776 \bibliographystyle{plain} 3776 \bibliography{ pl}3777 \bibliography{cfa} 3777 3778 3778 3779 -
doc/user/.gitignore
re2e7330 rbc6f918 1 1 # generated by latex 2 build/* 2 *.aux 3 *.bbl 4 *.blg 5 *.brf 6 *.dvi 7 *.idx 8 *.ilg 9 *.ind 10 *.log 11 *.out 3 12 *.pdf 4 13 *.ps 14 *.toc -
doc/user/Makefile
re2e7330 rbc6f918 1 ## Define the configuration variables.1 ## Define the appropriate configuration variables. 2 2 3 Build = build 4 Figures = figures 5 Macros = ../LaTeXmacros 6 TeXLIB = .:${Macros}:${Build}:../bibliography: 7 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build} 3 TeXLIB = .:../LaTeXmacros:../bibliography/: 4 LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error 8 5 BibTeX = BIBINPUTS=${TeXLIB} && export BIBINPUTS && bibtex 9 10 MAKEFLAGS = --no-print-directory --silent #11 VPATH = ${Figures}12 6 13 7 ## Define the text source files. … … 41 35 # Directives # 42 36 43 .PHONY : all clean # not file names44 45 37 all : ${DOCUMENT} 46 38 47 39 clean : 48 @rm -frv ${DOCUMENT} ${basename ${DOCUMENT}}.ps ${Build} 40 rm -f *.bbl *.aux *.dvi *.idx *.ilg *.ind *.brf *.out *.log *.toc *.blg *.pstex_t *.cf \ 41 ${FIGURES} ${PICTURES} ${PROGRAMS} ${GRAPHS} ${basename ${DOCUMENT}}.ps ${DOCUMENT} 49 42 50 43 # File Dependencies # … … 54 47 55 48 ${basename ${DOCUMENT}}.ps : ${basename ${DOCUMENT}}.dvi 56 dvips $ {Build}/$< -o $@49 dvips $< -o $@ 57 50 58 ${basename ${DOCUMENT}}.dvi : Makefile ${ Build} ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \59 ${Macros}/common.tex ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib51 ${basename ${DOCUMENT}}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${basename ${DOCUMENT}}.tex \ 52 ../LaTeXmacros/common.tex ../LaTeXmacros/lstlang.sty ../LaTeXmacros/indexstyle ../bibliography/cfa.bib 60 53 # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run. 61 if [ ! -r ${basename $@}.ind ] ; then touch ${ Build}/${basename $@}.ind ; fi54 if [ ! -r ${basename $@}.ind ] ; then touch ${basename $@}.ind ; fi 62 55 # Must have *.aux file containing citations for bibtex 63 56 if [ ! -r ${basename $@}.aux ] ; then ${LaTeX} ${basename $@}.tex ; fi 64 -${BibTeX} ${ Build}/${basename $@}65 # Some citations reference others so run again to resolve these citations57 -${BibTeX} ${basename $@} 58 # Some citations reference others so run steps again to resolve these citations 66 59 ${LaTeX} ${basename $@}.tex 67 -${BibTeX} ${ Build}/${basename $@}60 -${BibTeX} ${basename $@} 68 61 # Make index from *.aux entries and input index at end of document 69 makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx 70 # Run again to finish citations 62 makeindex -s ../LaTeXmacros/indexstyle ${basename $@}.idx 71 63 ${LaTeX} ${basename $@}.tex 72 64 # Run again to get index title into table of contents 73 65 ${LaTeX} ${basename $@}.tex 74 66 67 predefined : 68 sed -f predefined.sed ${basename ${DOCUMENT}}.tex > ${basename $@}.cf 69 75 70 ## Define the default recipes. 76 71 77 ${Build}:78 mkdir -p ${Build}79 80 72 %.tex : %.fig 81 fig2dev -L eepic $< > $ {Build}/$@73 fig2dev -L eepic $< > $@ 82 74 83 75 %.ps : %.fig 84 fig2dev -L ps $< > $ {Build}/$@76 fig2dev -L ps $< > $@ 85 77 86 78 %.pstex : %.fig 87 fig2dev -L pstex $< > $ {Build}/$@88 fig2dev -L pstex_t -p $ {Build}/$@ $< > ${Build}/$@_t79 fig2dev -L pstex $< > $@ 80 fig2dev -L pstex_t -p $@ $< > $@_t 89 81 90 82 # Local Variables: # -
doc/user/user.tex
re2e7330 rbc6f918 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Wed Jan 31 07:59:24 201814 %% Update Count : 314 613 %% Last Modified On : Mon Nov 27 18:09:59 2017 14 %% Update Count : 3143 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 40 40 \usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref} 41 41 \usepackage{breakurl} 42 \renewcommand{\UrlFont}{\small\sf} 42 43 43 44 \usepackage[pagewise]{lineno} … … 6660 6661 6661 6662 \bibliographystyle{plain} 6662 \bibliography{ pl}6663 \bibliography{cfa} 6663 6664 6664 6665 -
src/benchmark/Makefile.am
re2e7330 rbc6f918 59 59 @echo -e '\t"githash": "'${githash}'",' 60 60 @echo -e '\t"arch": "' ${arch} '",' 61 @echo -e '\t"compile": {'62 @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :'63 @echo -e '\t\t"dummy" : {}'64 @echo -e '\t},'65 61 @echo -e '\t"ctxswitch": {' 66 62 @echo -en '\t\t"coroutine":' -
src/benchmark/Makefile.in
re2e7330 rbc6f918 473 473 @echo -e '\t"githash": "'${githash}'",' 474 474 @echo -e '\t"arch": "' ${arch} '",' 475 @echo -e '\t"compile": {'476 @+make compile TIME_FORMAT='%e,' PRINT_FORMAT='\t\t\"%s\" :'477 @echo -e '\t\t"dummy" : {}'478 @echo -e '\t},'479 475 @echo -e '\t"ctxswitch": {' 480 476 @echo -en '\t\t"coroutine":' -
src/driver/cfa.cc
re2e7330 rbc6f918 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jan 30 15:46:15 201813 // Update Count : 16 112 // Last Modified On : Tue Oct 31 11:40:44 2017 13 // Update Count : 160 14 14 // 15 15 … … 277 277 args[nargs] = "--undefined=__cfaabi_dbg_bits_write"; 278 278 nargs += 1; 279 args[nargs] = "-Xlinker";280 nargs += 1;281 args[nargs] = "--undefined=__cfaabi_interpose_startup";282 nargs += 1;283 279 284 280 } // if … … 357 353 nargs += 1; 358 354 args[nargs] = "-D__int8_t_defined"; // prevent gcc type-size attributes 359 nargs += 1;360 args[nargs] = "-D__NO_STRING_INLINES"; // prevent gcc strcmp unrolling361 355 nargs += 1; 362 356 args[nargs] = ( *new string( string("-B") + Bprefix + "/" ) ).c_str(); -
src/libcfa/bits/containers.h
re2e7330 rbc6f918 140 140 141 141 #ifdef __cforall 142 143 142 forall(dtype T | is_node(T)) 144 static inline void ?{}( __queue(T) & this ) with( this ){145 head{ NULL };146 tail{ &head };143 static inline void ?{}( __queue(T) & this ) { 144 (this.head){ NULL }; 145 (this.tail){ &this.head }; 147 146 } 148 147 149 148 forall(dtype T | is_node(T) | sized(T)) 150 static inline void append( __queue(T) & this, T * val ) with( this ){151 verify(t ail != NULL);152 *t ail = val;153 t ail = &get_next( *val );149 static inline void append( __queue(T) & this, T * val ) { 150 verify(this.tail != NULL); 151 *this.tail = val; 152 this.tail = &get_next( *val ); 154 153 } 155 154 … … 168 167 169 168 forall(dtype T | is_node(T) | sized(T)) 170 static inline T * remove( __queue(T) & this, T ** it ) with( this ){169 static inline T * remove( __queue(T) & this, T ** it ) { 171 170 T * val = *it; 172 171 verify( val ); … … 174 173 (*it) = get_next( *val ); 175 174 176 if( t ail == &get_next( *val ) ) {177 t ail = it;175 if( this.tail == &get_next( *val ) ) { 176 this.tail = it; 178 177 } 179 178 180 179 get_next( *val ) = NULL; 181 180 182 verify( ( head == NULL) == (&head ==tail) );183 verify( *t ail == NULL );181 verify( (this.head == NULL) == (&this.head == this.tail) ); 182 verify( *this.tail == NULL ); 184 183 return val; 185 184 } 186 185 #endif 187 188 //-----------------------------------------------------------------------------189 // Tools190 //-----------------------------------------------------------------------------191 #ifdef __cforall192 193 #endif -
src/libcfa/bits/locks.h
re2e7330 rbc6f918 58 58 59 59 #ifdef __cforall 60 extern "C" {61 extern void disable_interrupts();62 extern void enable_interrupts_noPoll();63 }64 65 60 extern void yield( unsigned int ); 66 61 extern thread_local struct thread_desc * volatile this_thread; 67 extern thread_local struct processor * volatile this_processor;68 62 69 63 static inline void ?{}( __spinlock_t & this ) { … … 74 68 static inline _Bool try_lock ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) { 75 69 _Bool result = __lock_test_and_test_and_set( this.lock ); 76 if( result ) { 77 disable_interrupts(); 78 __cfaabi_dbg_debug_do( 70 __cfaabi_dbg_debug_do( 71 if( result ) { 79 72 this.prev_name = caller; 80 73 this.prev_thrd = this_thread; 81 )82 }74 } 75 ) 83 76 return result; 84 77 } … … 106 99 #endif 107 100 } 108 disable_interrupts();109 101 __cfaabi_dbg_debug_do( 110 102 this.prev_name = caller; … … 113 105 } 114 106 115 // // Lock the spinlock, yield if already acquired 116 // static inline void lock_yield( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) { 117 // for ( unsigned int i = 1;; i += 1 ) { 118 // if ( __lock_test_and_test_and_set( this.lock ) ) break; 119 // yield( i ); 120 // } 121 // disable_interrupts(); 122 // __cfaabi_dbg_debug_do( 123 // this.prev_name = caller; 124 // this.prev_thrd = this_thread; 125 // ) 126 // } 107 // Lock the spinlock, spin if already acquired 108 static inline void lock_yield( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) { 109 for ( unsigned int i = 1;; i += 1 ) { 110 if ( __lock_test_and_test_and_set( this.lock ) ) break; 111 yield( i ); 112 } 113 __cfaabi_dbg_debug_do( 114 this.prev_name = caller; 115 this.prev_thrd = this_thread; 116 ) 117 } 127 118 128 119 static inline void unlock( __spinlock_t & this ) { 129 enable_interrupts_noPoll();130 120 __lock_release( this.lock ); 131 121 } -
src/libcfa/concurrency/coroutine.c
re2e7330 rbc6f918 118 118 } //ctxSwitchDirect 119 119 120 void create_stack( coStack_t* this, unsigned int storageSize ) with( *this ){120 void create_stack( coStack_t* this, unsigned int storageSize ) { 121 121 //TEMP HACK do this on proper kernel startup 122 122 if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE ); … … 124 124 size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment 125 125 126 if ( (intptr_t) storage == 0 ) {127 userStack = false;128 size = libCeiling( storageSize, 16 );126 if ( (intptr_t)this->storage == 0 ) { 127 this->userStack = false; 128 this->size = libCeiling( storageSize, 16 ); 129 129 // use malloc/memalign because "new" raises an exception for out-of-memory 130 130 131 131 // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment 132 __cfaabi_dbg_debug_do( storage = memalign( pageSize, cxtSize +size + pageSize ) );133 __cfaabi_dbg_no_debug_do( storage = malloc( cxtSize +size + 8 ) );132 __cfaabi_dbg_debug_do( this->storage = memalign( pageSize, cxtSize + this->size + pageSize ) ); 133 __cfaabi_dbg_no_debug_do( this->storage = malloc( cxtSize + this->size + 8 ) ); 134 134 135 135 __cfaabi_dbg_debug_do( 136 if ( mprotect( storage, pageSize, PROT_NONE ) == -1 ) {136 if ( mprotect( this->storage, pageSize, PROT_NONE ) == -1 ) { 137 137 abortf( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) ); 138 138 } // if 139 139 ); 140 140 141 if ( (intptr_t) storage == 0 ) {142 abortf( "Attempt to allocate %d bytes of storage for coroutine or task execution-state but insufficient memory available.", size );141 if ( (intptr_t)this->storage == 0 ) { 142 abortf( "Attempt to allocate %d bytes of storage for coroutine or task execution-state but insufficient memory available.", this->size ); 143 143 } // if 144 144 145 __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize );146 __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment145 __cfaabi_dbg_debug_do( this->limit = (char *)this->storage + pageSize ); 146 __cfaabi_dbg_no_debug_do( this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ) ); // minimum alignment 147 147 148 148 } else { 149 assertf( ((size_t) storage & (libAlign() - 1)) != 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.",storage, (int)libAlign() );150 userStack = true;151 size = storageSize - cxtSize;149 assertf( ((size_t)this->storage & (libAlign() - 1)) != 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", this->storage, (int)libAlign() ); 150 this->userStack = true; 151 this->size = storageSize - cxtSize; 152 152 153 if ( size % 16 != 0u )size -= 8;153 if ( this->size % 16 != 0u ) this->size -= 8; 154 154 155 limit = (char *)libCeiling( (unsigned long)storage, 16 ); // minimum alignment155 this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ); // minimum alignment 156 156 } // if 157 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.",size, MinStackSize );157 assertf( this->size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", this->size, MinStackSize ); 158 158 159 base = (char *)limit +size;160 context =base;161 t op = (char *)context + cxtSize;159 this->base = (char *)this->limit + this->size; 160 this->context = this->base; 161 this->top = (char *)this->context + cxtSize; 162 162 } 163 163 -
src/libcfa/concurrency/invoke.h
re2e7330 rbc6f918 134 134 // instrusive link field for threads 135 135 struct thread_desc * next; 136 137 __cfaabi_dbg_debug_do(138 // instrusive link field for debugging139 struct thread_desc * dbg_next;140 struct thread_desc * dbg_prev;141 )142 136 }; 143 137 -
src/libcfa/concurrency/kernel.c
re2e7330 rbc6f918 87 87 } 88 88 89 void ?{}( coStack_t & this, current_stack_info_t * info) with( this ){90 size= info->size;91 storage= info->storage;92 limit= info->limit;93 base= info->base;94 context= info->context;95 t op= info->top;96 userStack = true;97 } 98 99 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ){100 stack{ info };101 name = "Main Thread";102 errno_ = 0;103 state = Start;104 starter = NULL;105 } 106 107 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ){108 self_cor{ info };89 void ?{}( coStack_t & this, current_stack_info_t * info) { 90 this.size = info->size; 91 this.storage = info->storage; 92 this.limit = info->limit; 93 this.base = info->base; 94 this.context = info->context; 95 this.top = info->top; 96 this.userStack = true; 97 } 98 99 void ?{}( coroutine_desc & this, current_stack_info_t * info) { 100 (this.stack){ info }; 101 this.name = "Main Thread"; 102 this.errno_ = 0; 103 this.state = Start; 104 this.starter = NULL; 105 } 106 107 void ?{}( thread_desc & this, current_stack_info_t * info) { 108 (this.self_cor){ info }; 109 109 } 110 110 … … 133 133 void ?{}(processor & this, cluster * cltr) { 134 134 this.cltr = cltr; 135 this.terminated{ 0 };135 (this.terminated){ 0 }; 136 136 this.do_terminate = false; 137 137 this.preemption_alarm = NULL; … … 143 143 void ?{}(processor & this, cluster * cltr, processorCtx_t & runner) { 144 144 this.cltr = cltr; 145 this.terminated{ 0 };145 (this.terminated){ 0 }; 146 146 this.do_terminate = false; 147 147 this.preemption_alarm = NULL; … … 154 154 } 155 155 156 void ^?{}(processor & this) with( this ){157 if( ! do_terminate ) {156 void ^?{}(processor & this) { 157 if( ! this.do_terminate ) { 158 158 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 159 do_terminate = true;160 P( t erminated );161 pthread_join( kernel_thread, NULL );162 } 163 } 164 165 void ?{}(cluster & this) with( this ){166 ready_queue{};167 ready_queue_lock{};168 169 preemption = default_preemption();159 this.do_terminate = true; 160 P( this.terminated ); 161 pthread_join( this.kernel_thread, NULL ); 162 } 163 } 164 165 void ?{}(cluster & this) { 166 (this.ready_queue){}; 167 ( this.ready_queue_lock ){}; 168 169 this.preemption = default_preemption(); 170 170 } 171 171 … … 240 240 // Once a thread has finished running, some of 241 241 // its final actions must be executed from the kernel 242 void finishRunning(processor * this) with( this->finish ) { 243 if( action_code == Release ) { 244 verify( disable_preempt_count > 1 ); 245 unlock( *lock ); 246 } 247 else if( action_code == Schedule ) { 248 ScheduleThread( thrd ); 249 } 250 else if( action_code == Release_Schedule ) { 251 verify( disable_preempt_count > 1 ); 252 unlock( *lock ); 253 ScheduleThread( thrd ); 254 } 255 else if( action_code == Release_Multi ) { 256 verify( disable_preempt_count > lock_count ); 257 for(int i = 0; i < lock_count; i++) { 258 unlock( *locks[i] ); 242 void finishRunning(processor * this) { 243 if( this->finish.action_code == Release ) { 244 unlock( *this->finish.lock ); 245 } 246 else if( this->finish.action_code == Schedule ) { 247 ScheduleThread( this->finish.thrd ); 248 } 249 else if( this->finish.action_code == Release_Schedule ) { 250 unlock( *this->finish.lock ); 251 ScheduleThread( this->finish.thrd ); 252 } 253 else if( this->finish.action_code == Release_Multi ) { 254 for(int i = 0; i < this->finish.lock_count; i++) { 255 unlock( *this->finish.locks[i] ); 259 256 } 260 257 } 261 else if( action_code == Release_Multi_Schedule ) {262 for(int i = 0; i < lock_count; i++) {263 unlock( * locks[i] );258 else if( this->finish.action_code == Release_Multi_Schedule ) { 259 for(int i = 0; i < this->finish.lock_count; i++) { 260 unlock( *this->finish.locks[i] ); 264 261 } 265 for(int i = 0; i < th rd_count; i++) {266 ScheduleThread( th rds[i] );262 for(int i = 0; i < this->finish.thrd_count; i++) { 263 ScheduleThread( this->finish.thrds[i] ); 267 264 } 268 265 } 269 266 else { 270 assert( action_code == No_Action);267 assert(this->finish.action_code == No_Action); 271 268 } 272 269 } … … 337 334 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 338 335 339 with( *this_processor->cltr ) { 340 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 341 append( ready_queue, thrd ); 342 unlock( ready_queue_lock ); 343 } 344 345 verify( disable_preempt_count > 0 ); 346 } 347 348 thread_desc * nextThread(cluster * this) with( *this ) { 349 verify( disable_preempt_count > 0 ); 350 lock( ready_queue_lock __cfaabi_dbg_ctx2 ); 351 thread_desc * head = pop_head( ready_queue ); 352 unlock( ready_queue_lock ); 336 lock( this_processor->cltr->ready_queue_lock __cfaabi_dbg_ctx2 ); 337 append( this_processor->cltr->ready_queue, thrd ); 338 unlock( this_processor->cltr->ready_queue_lock ); 339 340 verify( disable_preempt_count > 0 ); 341 } 342 343 thread_desc * nextThread(cluster * this) { 344 verify( disable_preempt_count > 0 ); 345 lock( this->ready_queue_lock __cfaabi_dbg_ctx2 ); 346 thread_desc * head = pop_head( this->ready_queue ); 347 unlock( this->ready_queue_lock ); 353 348 verify( disable_preempt_count > 0 ); 354 349 return head; … … 366 361 disable_interrupts(); 367 362 this_processor->finish.action_code = Release; 368 this_processor->finish.lock 369 370 verify( disable_preempt_count > 1);363 this_processor->finish.lock = lock; 364 365 verify( disable_preempt_count > 0 ); 371 366 suspend(); 372 367 verify( disable_preempt_count > 0 ); … … 376 371 377 372 void BlockInternal( thread_desc * thrd ) { 373 assert(thrd); 378 374 disable_interrupts(); 375 assert( thrd->self_cor.state != Halted ); 379 376 this_processor->finish.action_code = Schedule; 380 this_processor->finish.thrd 377 this_processor->finish.thrd = thrd; 381 378 382 379 verify( disable_preempt_count > 0 ); … … 391 388 disable_interrupts(); 392 389 this_processor->finish.action_code = Release_Schedule; 393 this_processor->finish.lock 394 this_processor->finish.thrd 395 396 verify( disable_preempt_count > 1);390 this_processor->finish.lock = lock; 391 this_processor->finish.thrd = thrd; 392 393 verify( disable_preempt_count > 0 ); 397 394 suspend(); 398 395 verify( disable_preempt_count > 0 ); … … 404 401 disable_interrupts(); 405 402 this_processor->finish.action_code = Release_Multi; 406 this_processor->finish.locks 407 this_processor->finish.lock_count 403 this_processor->finish.locks = locks; 404 this_processor->finish.lock_count = count; 408 405 409 406 verify( disable_preempt_count > 0 ); … … 417 414 disable_interrupts(); 418 415 this_processor->finish.action_code = Release_Multi_Schedule; 419 this_processor->finish.locks 420 this_processor->finish.lock_count 421 this_processor->finish.thrds 422 this_processor->finish.thrd_count 416 this_processor->finish.locks = locks; 417 this_processor->finish.lock_count = lock_count; 418 this_processor->finish.thrds = thrds; 419 this_processor->finish.thrd_count = thrd_count; 423 420 424 421 verify( disable_preempt_count > 0 ); … … 432 429 verify( disable_preempt_count > 0 ); 433 430 this_processor->finish.action_code = thrd ? Release_Schedule : Release; 434 this_processor->finish.lock 435 this_processor->finish.thrd 431 this_processor->finish.lock = lock; 432 this_processor->finish.thrd = thrd; 436 433 437 434 suspend(); … … 518 515 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n"); 519 516 } 520 521 //=============================================================================================522 // Unexpected Terminating logic523 //=============================================================================================524 525 517 526 518 static __spinlock_t kernel_abort_lock; … … 589 581 void ^?{}(semaphore & this) {} 590 582 591 void P(semaphore & this) with( this ){592 lock( lock __cfaabi_dbg_ctx2 );593 count -= 1;594 if ( count < 0 ) {583 void P(semaphore & this) { 584 lock( this.lock __cfaabi_dbg_ctx2 ); 585 this.count -= 1; 586 if ( this.count < 0 ) { 595 587 // queue current task 596 append( waiting, (thread_desc *)this_thread );588 append( this.waiting, (thread_desc *)this_thread ); 597 589 598 590 // atomically release spin lock and block 599 BlockInternal( & lock );591 BlockInternal( &this.lock ); 600 592 } 601 593 else { 602 unlock( lock );603 } 604 } 605 606 void V(semaphore & this) with( this ){594 unlock( this.lock ); 595 } 596 } 597 598 void V(semaphore & this) { 607 599 thread_desc * thrd = NULL; 608 lock( lock __cfaabi_dbg_ctx2 );609 count += 1;610 if ( count <= 0 ) {600 lock( this.lock __cfaabi_dbg_ctx2 ); 601 this.count += 1; 602 if ( this.count <= 0 ) { 611 603 // remove task at head of waiting list 612 thrd = pop_head( waiting );613 } 614 615 unlock( lock );604 thrd = pop_head( this.waiting ); 605 } 606 607 unlock( this.lock ); 616 608 617 609 // make new owner … … 619 611 } 620 612 621 //-----------------------------------------------------------------------------622 // Debug623 __cfaabi_dbg_debug_do(624 struct {625 thread_desc * tail;626 } __cfaabi_dbg_thread_list = { NULL };627 628 void __cfaabi_dbg_thread_register( thread_desc * thrd ) {629 if( !__cfaabi_dbg_thread_list.tail ) {630 __cfaabi_dbg_thread_list.tail = thrd;631 return;632 }633 __cfaabi_dbg_thread_list.tail->dbg_next = thrd;634 thrd->dbg_prev = __cfaabi_dbg_thread_list.tail;635 __cfaabi_dbg_thread_list.tail = thrd;636 }637 638 void __cfaabi_dbg_thread_unregister( thread_desc * thrd ) {639 thread_desc * prev = thrd->dbg_prev;640 thread_desc * next = thrd->dbg_next;641 642 if( next ) { next->dbg_prev = prev; }643 else {644 assert( __cfaabi_dbg_thread_list.tail == thrd );645 __cfaabi_dbg_thread_list.tail = prev;646 }647 648 if( prev ) { prev->dbg_next = next; }649 650 thrd->dbg_prev = NULL;651 thrd->dbg_next = NULL;652 }653 )654 613 // Local Variables: // 655 614 // mode: c // -
src/libcfa/concurrency/kernel_private.h
re2e7330 rbc6f918 85 85 extern void ThreadCtxSwitch(coroutine_desc * src, coroutine_desc * dst); 86 86 87 __cfaabi_dbg_debug_do(88 extern void __cfaabi_dbg_thread_register ( thread_desc * thrd );89 extern void __cfaabi_dbg_thread_unregister( thread_desc * thrd );90 )91 92 87 //----------------------------------------------------------------------------- 93 88 // Utils -
src/libcfa/concurrency/monitor.c
re2e7330 rbc6f918 53 53 static inline __lock_size_t aggregate ( monitor_desc * storage [], const __waitfor_mask_t & mask ); 54 54 55 #ifndef __CFA_LOCK_NO_YIELD 56 #define DO_LOCK lock_yield 57 #else 58 #define DO_LOCK lock 59 #endif 60 55 61 //----------------------------------------------------------------------------- 56 62 // Useful defines … … 84 90 static void __enter_monitor_desc( monitor_desc * this, const __monitor_group_t & group ) { 85 91 // Lock the monitor spinlock 86 lock( this->lock __cfaabi_dbg_ctx2 );92 DO_LOCK( this->lock __cfaabi_dbg_ctx2 ); 87 93 thread_desc * thrd = this_thread; 88 89 verify( disable_preempt_count > 0 );90 94 91 95 __cfaabi_dbg_print_safe("Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner); … … 117 121 // Some one else has the monitor, wait in line for it 118 122 append( this->entry_queue, thrd ); 119 120 verify( disable_preempt_count > 0 );121 122 123 BlockInternal( &this->lock ); 123 124 … … 137 138 static void __enter_monitor_dtor( monitor_desc * this, fptr_t func ) { 138 139 // Lock the monitor spinlock 139 lock( this->lock __cfaabi_dbg_ctx2 );140 DO_LOCK( this->lock __cfaabi_dbg_ctx2 ); 140 141 thread_desc * thrd = this_thread; 141 142 … … 200 201 // Leave single monitor 201 202 void __leave_monitor_desc( monitor_desc * this ) { 202 // Lock the monitor spinlock 203 lock( this->lock __cfaabi_dbg_ctx2 );203 // Lock the monitor spinlock, DO_LOCK to reduce contention 204 DO_LOCK( this->lock __cfaabi_dbg_ctx2 ); 204 205 205 206 __cfaabi_dbg_print_safe("Kernel : %10p Leaving mon %p (%p)\n", this_thread, this, this->owner); … … 247 248 248 249 // Lock the monitor now 249 lock( this->lock __cfaabi_dbg_ctx2 );250 DO_LOCK( this->lock __cfaabi_dbg_ctx2 ); 250 251 251 252 disable_interrupts(); … … 396 397 append( this.blocked, &waiter ); 397 398 398 verify( disable_preempt_count == 0 );399 400 399 // Lock all monitors (aggregates the locks as well) 401 400 lock_all( monitors, locks, count ); 402 403 // verifyf( disable_preempt_count == count, "Got %d, expected %d\n", disable_preempt_count, count );404 if(disable_preempt_count != count) { __cfaabi_dbg_print_buffer_decl("----------Gonna crash\n"); }405 401 406 402 // Find the next thread(s) to run … … 477 473 monitor_ctx( this.monitors, this.monitor_count ); 478 474 479 verify( disable_preempt_count == 0 );480 481 475 // Lock all monitors (aggregates the locks them as well) 482 476 lock_all( monitors, locks, count ); 483 484 // verify( disable_preempt_count == count );485 if(disable_preempt_count != count) { __cfaabi_dbg_print_buffer_decl("----------Gonna crash\n"); }486 487 477 488 478 // Create the node specific to this wait operation … … 747 737 static inline void lock_all( __spinlock_t * locks [], __lock_size_t count ) { 748 738 for( __lock_size_t i = 0; i < count; i++ ) { 749 lock( *locks[i] __cfaabi_dbg_ctx2 );739 DO_LOCK( *locks[i] __cfaabi_dbg_ctx2 ); 750 740 } 751 741 } … … 754 744 for( __lock_size_t i = 0; i < count; i++ ) { 755 745 __spinlock_t * l = &source[i]->lock; 756 lock( *l __cfaabi_dbg_ctx2 );746 DO_LOCK( *l __cfaabi_dbg_ctx2 ); 757 747 if(locks) locks[i] = l; 758 748 } -
src/libcfa/concurrency/preemption.c
re2e7330 rbc6f918 19 19 extern "C" { 20 20 #include <errno.h> 21 #include <execinfo.h> 22 #define __USE_GNU 23 #include <signal.h> 24 #undef __USE_GNU 21 25 #include <stdio.h> 22 26 #include <string.h> … … 25 29 #undef ftype 26 30 27 #include "bits/signal.h" 31 #ifdef __USE_STREAM__ 32 #include "fstream" 33 #endif 28 34 29 35 //TODO move to defaults … … 34 40 return __CFA_DEFAULT_PREEMPTION__; 35 41 } 42 43 // Short hands for signal context information 44 #define __CFA_SIGCXT__ ucontext_t * 45 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt 36 46 37 47 // FwdDeclarations : timeout handlers … … 43 53 void sigHandler_segv ( __CFA_SIGPARMS__ ); 44 54 void sigHandler_abort ( __CFA_SIGPARMS__ ); 55 56 // FwdDeclarations : sigaction wrapper 57 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ); 45 58 46 59 // FwdDeclarations : alarm thread main … … 60 73 static pthread_t alarm_thread; // pthread handle to alarm thread 61 74 62 void ?{}(event_kernel_t & this) with( this ){63 alarms{};64 lock{};75 void ?{}(event_kernel_t & this) { 76 (this.alarms){}; 77 (this.lock){}; 65 78 } 66 79 … … 149 162 // If counter reaches 0, execute any pending CtxSwitch 150 163 void enable_interrupts( __cfaabi_dbg_ctx_param ) { 151 processor * proc= this_processor; // Cache the processor now since interrupts can start happening after the atomic add164 processor * proc = this_processor; // Cache the processor now since interrupts can start happening after the atomic add 152 165 thread_desc * thrd = this_thread; // Cache the thread now since interrupts can start happening after the atomic add 153 166 … … 169 182 void enable_interrupts_noPoll() { 170 183 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 171 verify f( prev != 0u, "Incremented from %u\n", prev); // If this triggers someone is enabled already enabled interrupts184 verify( prev != 0u ); // If this triggers someone is enabled already enabled interrupts 172 185 } 173 186 } … … 233 246 // Setup proper signal handlers 234 247 __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // CtxSwitch handler 248 // __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); // Failure handler 249 // __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); // Failure handler 235 250 236 251 signal_block( SIGALRM ); … … 293 308 if( !preemption_ready() ) { return; } 294 309 295 __cfaabi_dbg_print_buffer_decl(" KERNEL: preempting core %p (%p).\n", this_processor, this_thread);310 // __cfaabi_dbg_print_buffer_decl(" KERNEL: preempting core %p (%p).\n", this_processor, this_thread); 296 311 297 312 preemption_in_progress = true; // Sync flag : prevent recursive calls to the signal handler … … 365 380 } 366 381 382 // Sigaction wrapper : register an signal handler 383 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) { 384 struct sigaction act; 385 386 act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler; 387 act.sa_flags = flags; 388 389 if ( sigaction( sig, &act, NULL ) == -1 ) { 390 __cfaabi_dbg_print_buffer_decl( 391 " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n", 392 sig, handler, flags, errno, strerror( errno ) 393 ); 394 _exit( EXIT_FAILURE ); 395 } 396 } 397 398 // Sigaction wrapper : restore default handler 399 static void __kernel_sigdefault( int sig ) { 400 struct sigaction act; 401 402 act.sa_handler = SIG_DFL; 403 act.sa_flags = 0; 404 sigemptyset( &act.sa_mask ); 405 406 if ( sigaction( sig, &act, NULL ) == -1 ) { 407 __cfaabi_dbg_print_buffer_decl( 408 " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n", 409 sig, errno, strerror( errno ) 410 ); 411 _exit( EXIT_FAILURE ); 412 } 413 } 414 415 //============================================================================================= 416 // Terminating Signals logic 417 //============================================================================================= 418 419 __cfaabi_dbg_debug_do( 420 static void __kernel_backtrace( int start ) { 421 // skip first N stack frames 422 423 enum { Frames = 50 }; 424 void * array[Frames]; 425 int size = backtrace( array, Frames ); 426 char ** messages = backtrace_symbols( array, size ); 427 428 // find executable name 429 *index( messages[0], '(' ) = '\0'; 430 #ifdef __USE_STREAM__ 431 serr | "Stack back trace for:" | messages[0] | endl; 432 #else 433 fprintf( stderr, "Stack back trace for: %s\n", messages[0]); 434 #endif 435 436 // skip last 2 stack frames after main 437 for ( int i = start; i < size && messages != NULL; i += 1 ) { 438 char * name = NULL; 439 char * offset_begin = NULL; 440 char * offset_end = NULL; 441 442 for ( char *p = messages[i]; *p; ++p ) { 443 // find parantheses and +offset 444 if ( *p == '(' ) { 445 name = p; 446 } 447 else if ( *p == '+' ) { 448 offset_begin = p; 449 } 450 else if ( *p == ')' ) { 451 offset_end = p; 452 break; 453 } 454 } 455 456 // if line contains symbol print it 457 int frameNo = i - start; 458 if ( name && offset_begin && offset_end && name < offset_begin ) { 459 // delimit strings 460 *name++ = '\0'; 461 *offset_begin++ = '\0'; 462 *offset_end++ = '\0'; 463 464 #ifdef __USE_STREAM__ 465 serr | "(" | frameNo | ")" | messages[i] | ":" 466 | name | "+" | offset_begin | offset_end | endl; 467 #else 468 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end); 469 #endif 470 } 471 // otherwise, print the whole line 472 else { 473 #ifdef __USE_STREAM__ 474 serr | "(" | frameNo | ")" | messages[i] | endl; 475 #else 476 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] ); 477 #endif 478 } 479 } 480 481 free( messages ); 482 } 483 ) 484 485 // void sigHandler_segv( __CFA_SIGPARMS__ ) { 486 // __cfaabi_dbg_debug_do( 487 // #ifdef __USE_STREAM__ 488 // serr | "*CFA runtime error* program cfa-cpp terminated with" 489 // | (sig == SIGSEGV ? "segment fault." : "bus error.") 490 // | endl; 491 // #else 492 // fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." ); 493 // #endif 494 495 // // skip first 2 stack frames 496 // __kernel_backtrace( 1 ); 497 // ) 498 // exit( EXIT_FAILURE ); 499 // } 500 501 // void sigHandler_abort( __CFA_SIGPARMS__ ) { 502 // // skip first 6 stack frames 503 // __cfaabi_dbg_debug_do( __kernel_backtrace( 6 ); ) 504 505 // // reset default signal handler 506 // __kernel_sigdefault( SIGABRT ); 507 508 // raise( SIGABRT ); 509 // } 510 367 511 // Local Variables: // 368 512 // mode: c // -
src/libcfa/concurrency/thread.c
re2e7330 rbc6f918 31 31 // Thread ctors and dtors 32 32 33 void ?{}(thread_desc& this) with( this ) { 34 self_cor{}; 35 self_cor.name = "Anonymous Coroutine"; 36 self_mon.owner = &this; 37 self_mon.recursion = 1; 38 self_mon_p = &self_mon; 39 next = NULL; 40 __cfaabi_dbg_debug_do( 41 dbg_next = NULL; 42 dbg_prev = NULL; 43 __cfaabi_dbg_thread_register(&this); 44 ) 33 void ?{}(thread_desc& this) { 34 (this.self_cor){}; 35 this.self_cor.name = "Anonymous Coroutine"; 36 this.self_mon.owner = &this; 37 this.self_mon.recursion = 1; 38 this.self_mon_p = &this.self_mon; 39 this.next = NULL; 45 40 46 monitors{ &self_mon_p, 1, (fptr_t)0 };41 (this.monitors){ &this.self_mon_p, 1, (fptr_t)0 }; 47 42 } 48 43 49 void ^?{}(thread_desc& this) with( this ){50 ^ self_cor{};44 void ^?{}(thread_desc& this) { 45 ^(this.self_cor){}; 51 46 } 52 47 53 48 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } ) 54 void ?{}( scoped(T)& this ) with( this ){55 handle{};56 __thrd_start( handle);49 void ?{}( scoped(T)& this ) { 50 (this.handle){}; 51 __thrd_start(this.handle); 57 52 } 58 53 59 54 forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T&, P); } ) 60 void ?{}( scoped(T)& this, P params ) with( this ){61 handle{ params };62 __thrd_start( handle);55 void ?{}( scoped(T)& this, P params ) { 56 (this.handle){ params }; 57 __thrd_start(this.handle); 63 58 } 64 59 65 60 forall( dtype T | sized(T) | is_thread(T) ) 66 void ^?{}( scoped(T)& this ) with( this ){67 ^ handle{};61 void ^?{}( scoped(T)& this ) { 62 ^(this.handle){}; 68 63 } 69 64 … … 73 68 void __thrd_start( T& this ) { 74 69 coroutine_desc* thrd_c = get_coroutine(this); 75 thread_desc *thrd_h = get_thread (this);70 thread_desc* thrd_h = get_thread (this); 76 71 thrd_c->last = this_coroutine; 77 72 -
src/libcfa/interpose.c
re2e7330 rbc6f918 22 22 #include <dlfcn.h> 23 23 #include <unistd.h> 24 #define __USE_GNU25 #include <signal.h>26 #undef __USE_GNU27 #include <execinfo.h>28 24 } 29 25 30 26 #include "bits/debug.h" 31 27 #include "bits/defs.h" 32 #include "bits/signal.h"33 28 #include "startup.h" 34 29 35 void __cfaabi_interpose_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));30 void interpose_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_CORE ) )); 36 31 37 32 typedef void (*generic_fptr_t)(void); … … 89 84 #define INIT_REALRTN( x, ver ) assign_ptr( (void**)&libc_##x, #x, ver) 90 85 91 void sigHandler_segv ( __CFA_SIGPARMS__ ); 92 void sigHandler_abort( __CFA_SIGPARMS__ ); 93 94 void __cfaabi_interpose_startup() { 86 void interpose_startup() { 95 87 const char *version = NULL; 96 88 97 89 INIT_REALRTN( abort, version ); 98 90 INIT_REALRTN( exit, version ); 99 100 __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); // Failure handler101 __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); // Failure handler102 __kernel_sigaction( SIGABRT, sigHandler_abort, SA_SIGINFO ); // Failure handler103 91 } 104 105 //=============================================================================================106 // Terminating Signals logic107 //=============================================================================================108 92 109 93 extern "C" { … … 155 139 } 156 140 157 // skip first 6 stack frames by default158 static void __kernel_backtrace() {159 // skip first N stack frames160 int start = 6;161 162 enum { Frames = 50 };163 void * array[Frames];164 int size = backtrace( array, Frames );165 char ** messages = backtrace_symbols( array, size );166 167 // find executable name168 *index( messages[0], '(' ) = '\0';169 __cfaabi_dbg_bits_print_nolock( "Stack back trace for: %s\n", messages[0]);170 171 // skip last 2 stack frames after main172 for ( int i = start; i < size && messages != NULL; i += 1 ) {173 char * name = NULL;174 char * offset_begin = NULL;175 char * offset_end = NULL;176 177 for ( char *p = messages[i]; *p; ++p ) {178 // find parantheses and +offset179 if ( *p == '(' ) {180 name = p;181 }182 else if ( *p == '+' ) {183 offset_begin = p;184 }185 else if ( *p == ')' ) {186 offset_end = p;187 break;188 }189 }190 191 // if line contains symbol print it192 int frameNo = i - start;193 if ( name && offset_begin && offset_end && name < offset_begin ) {194 // delimit strings195 *name++ = '\0';196 *offset_begin++ = '\0';197 *offset_end++ = '\0';198 199 __cfaabi_dbg_bits_print_nolock( "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);200 }201 // otherwise, print the whole line202 else {203 __cfaabi_dbg_bits_print_nolock( "(%i) %s\n", frameNo, messages[i] );204 }205 }206 207 free( messages );208 }209 210 void sigHandler_segv( __CFA_SIGPARMS__ ) {211 // skip first only 1 stack frames in case of segfault.212 abortf( "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );213 }214 215 void sigHandler_abort( __CFA_SIGPARMS__ ) {216 __kernel_backtrace();217 218 // reset default signal handler219 __kernel_sigdefault( SIGABRT );220 221 raise( SIGABRT );222 }223 224 141 // Local Variables: // 225 142 // mode: c // -
src/libcfa/interpose.h
re2e7330 rbc6f918 16 16 #pragma once 17 17 18 void * interpose_symbol( const char* symbol, const char *version );18 void * interpose_symbol( const char* symbol, , const char *version ); 19 19 20 20 extern __typeof__( abort ) libc_abort __attribute__(( noreturn )); -
src/prelude/prelude.cf
re2e7330 rbc6f918 39 39 // ------------------------------------------------------------ 40 40 41 _Bool ?++( _Bool & ), ?++( volatile _Bool & ); 42 _Bool ?--( _Bool & ), ?--( volatile _Bool & ); 41 43 signed short ?++( signed short & ), ?++( volatile signed short & ); 42 44 signed short ?--( signed short & ), ?--( volatile signed short & ); … … 92 94 // ------------------------------------------------------------ 93 95 96 _Bool ++?( _Bool & ), --?( _Bool & ); 94 97 signed short ++?( signed short & ), --?( signed short & ); 95 98 signed int ++?( signed int & ), --?( signed int & ); … … 122 125 forall( ftype FT ) FT & *?( FT * ); 123 126 124 _Bool +?( _Bool ), -?( _Bool ) ;127 _Bool +?( _Bool ), -?( _Bool ), ~?( _Bool ); 125 128 signed int +?( signed int ), -?( signed int ), ~?( signed int ); 126 129 unsigned int +?( unsigned int ), -?( unsigned int ), ~?( unsigned int ); … … 154 157 // ------------------------------------------------------------ 155 158 159 _Bool ?*?( _Bool, _Bool ), ?/?( _Bool, _Bool ), ?%?( _Bool, _Bool ); 156 160 signed int ?*?( signed int, signed int ), ?/?( signed int, signed int ), ?%?( signed int, signed int ); 157 161 unsigned int ?*?( unsigned int, unsigned int ), ?/?( unsigned int, unsigned int ), ?%?( unsigned int, unsigned int ); … … 211 215 // ------------------------------------------------------------ 212 216 217 _Bool ?<<?( _Bool, _Bool ), ?>>?( _Bool, _Bool ); 213 218 signed int ?<<?( signed int, signed int ), ?>>?( signed int, signed int ); 214 219 unsigned int ?<<?( unsigned int, unsigned int ), ?>>?( unsigned int, unsigned int ); … … 462 467 463 468 469 _Bool ?*=?( _Bool &, _Bool ), ?*=?( volatile _Bool &, _Bool ); 464 470 char ?*=?( char &, char ), ?*=?( volatile char &, char ); 465 471 char signed ?*=?( char signed &, char signed ), ?*=?( volatile char signed &, char signed ); … … 528 534 unsigned long long int ?-=?( unsigned long long int &, unsigned long long int ), ?-=?( volatile unsigned long long int &, unsigned long long int ); 529 535 536 _Bool ?<<=?( _Bool &, _Bool ), ?<<=?( volatile _Bool &, _Bool ); 530 537 char ?<<=?( char &, char ), ?<<=?( volatile char &, char ); 531 538 char signed ?<<=?( char signed &, char signed ), ?<<=?( volatile char signed &, char signed ); … … 540 547 unsigned long long int ?<<=?( unsigned long long int &, unsigned long long int ), ?<<=?( volatile unsigned long long int &, unsigned long long int ); 541 548 549 _Bool ?>>=?( _Bool &, _Bool ), ?>>=?( volatile _Bool &, _Bool ); 542 550 char ?>>=?( char &, char ), ?>>=?( volatile char &, char ); 543 551 char signed ?>>=?( char signed &, char signed ), ?>>=?( volatile char signed &, char signed ); -
src/tests/Makefile.am
re2e7330 rbc6f918 65 65 66 66 concurrency : 67 @+python test.py --debug=${debug} -Iconcurrent67 @+python test.py --debug=${debug} ${concurrent} ${concurrent_test} 68 68 69 69 .dummy : .dummy.c @CFA_BINDIR@/@CFA_NAME@ -
src/tests/Makefile.in
re2e7330 rbc6f918 743 743 744 744 concurrency : 745 @+python test.py --debug=${debug} -Iconcurrent745 @+python test.py --debug=${debug} ${concurrent} ${concurrent_test} 746 746 747 747 .dummy : .dummy.c @CFA_BINDIR@/@CFA_NAME@ -
src/tests/concurrent/examples/quickSort.c
re2e7330 rbc6f918 9 9 // Created On : Wed Dec 6 12:15:52 2017 10 10 // Last Modified By : Peter A. Buhr 11 // Last Modified On : Tue Jan 30 15:58:58201812 // Update Count : 1 6211 // Last Modified On : Mon Jan 29 08:41:37 2018 12 // Update Count : 155 13 13 // 14 14 … … 100 100 if ( argc != 1 ) { // do not use defaults 101 101 if ( argc < 2 || argc > 4 ) usage( argv ); // wrong number of options 102 if ( strcmp( argv[1], "-t" ) == 0 ) { // timing ? 102 // if ( strcmp( argv[1], "-t" ) == 0 ) { // timing ? 103 if ( argv[1][0] == '-' && argv[1][1] == 't' ) { // timing ? 103 104 &unsortedfile = (ifstream *)0; // no input 104 105 choose ( argc ) { -
src/tests/functions.c
re2e7330 rbc6f918 10 10 // Created On : Wed Aug 17 08:39:58 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jan 17 22:44:12 201813 // Update Count : 1 212 // Last Modified On : Mon Nov 27 18:08:54 2017 13 // Update Count : 11 14 14 // 15 15 … … 25 25 void g(void) 26 26 ) { 27 (* 27 (*g)(); 28 28 g(); 29 29 g = h; … … 32 32 int f1() {} 33 33 int (f2()) {} 34 int (* 35 int * 36 int ((* 37 int * 38 int * 39 int ** 40 int * const * 41 int (* 42 int (* 43 int ((* 34 int (*f3())() {} 35 int *((f4())) {} 36 int ((*f5()))() {} 37 int *f6() {} 38 int *(f7)() {} 39 int **f8() {} 40 int * const *(f9)() {} 41 int (*f10())[] {} 42 int (*f11())[][3] {} 43 int ((*f12())[])[3] {} 44 44 45 45 // "implicit int" otype specifier (not ANSI) … … 50 50 extern const fII4( int i ) {} 51 51 52 * 53 const * 54 const long * 55 static const long * 56 const static long * 52 *fII5() {} 53 const *fII6() {} 54 const long *fII7() {} 55 static const long *fII8() {} 56 const static long *fII9() {} 57 57 58 58 // K&R function definitions … … 117 117 [int](int) 118 118 ) { 119 int (* (*pc)[][10])[][3];119 int (*(*pc)[][10])[][3]; 120 120 * [][10] * [][3] int p; 121 121 * [] * [int](int) p; 122 122 } 123 123 124 static const int * 124 static const int *f1() {} 125 125 static [ const int ] f2() {} 126 126 static inline [ const * int ] f3() {} … … 133 133 int (), 134 134 135 int * 136 int ** 137 int * const * 135 int *(), 136 int **(), 137 int * const *(), 138 138 int * const * const (), 139 139 … … 141 141 int ([10]), 142 142 143 int * 144 int * 145 int ** 146 int ** 147 int * const * 148 int * const * 143 int *([]), 144 int *([10]), 145 int **([]), 146 int **([10]), 147 int * const *([]), 148 int * const *([10]), 149 149 int * const * const ([]), 150 150 int * const * const ([10]) … … 154 154 int (), 155 155 156 int * 157 int ** 158 int * const * 156 int *(), 157 int **(), 158 int * const *(), 159 159 int * const * const (), 160 160 … … 162 162 int ([10]), 163 163 164 int * 165 int * 166 int ** 167 int ** 168 int * const * 169 int * const * 164 int *([]), 165 int *([10]), 166 int **([]), 167 int **([10]), 168 int * const *([]), 169 int * const *([10]), 170 170 int * const * const ([]), 171 171 int * const * const ([10]) … … 175 175 typedef int T; 176 176 177 int f( T (* 177 int f( T (*f), T t ) { 178 178 T (T); 179 179 } … … 184 184 //int (f[])() {} 185 185 //int f[]() {} 186 //int ((* 186 //int ((*f15())())[] {} 187 187 188 188 // Local Variables: // -
src/tests/identFuncDeclarator.c
re2e7330 rbc6f918 10 10 // Created On : Wed Aug 17 08:36:34 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jan 17 22:39:13 201813 // Update Count : 212 // Last Modified On : Wed Aug 17 08:37:06 2016 13 // Update Count : 1 14 14 // 15 15 … … 18 18 int (f2); 19 19 20 int * 21 int ** 22 int * const * 20 int *f3; 21 int **f4; 22 int * const *f5; 23 23 int * const * const f6; 24 24 25 int * 26 int ** 27 int * const * 25 int *(f7); 26 int **(f8); 27 int * const *(f9); 28 28 int * const * const (f10); 29 29 30 int (* 31 int (** 32 int (* const * 30 int (*f11); 31 int (**f12); 32 int (* const *f13); 33 33 int (* const * const f14); 34 34 … … 38 38 int (f18[10]); 39 39 40 int * 41 int * 42 int ** 43 int ** 44 int * const * 45 int * const * 40 int *f19[2]; 41 int *f20[10]; 42 int **f21[2]; 43 int **f22[10]; 44 int * const *f23[2]; 45 int * const *f24[10]; 46 46 int * const * const f25[2]; 47 47 int * const * const f26[10]; 48 48 49 int * 50 int * 51 int ** 52 int ** 53 int * const * 54 int * const * 49 int *(f27[2]); 50 int *(f28[10]); 51 int **(f29[2]); 52 int **(f30[10]); 53 int * const *(f31[2]); 54 int * const *(f32[10]); 55 55 int * const * const (f33[2]); 56 56 int * const * const (f34[10]); 57 57 58 int (* 59 int (* 60 int (** 61 int (** 62 int (* const * 63 int (* const * 58 int (*f35[2]); 59 int (*f36[10]); 60 int (**f37[2]); 61 int (**f38[10]); 62 int (* const *f39[2]); 63 int (* const *f40[10]); 64 64 int (* const * const f41[2]); 65 65 int (* const * const f42[10]); … … 72 72 int ((f48[3]))[3]; 73 73 74 int * 75 int * 76 int ** 77 int ** 78 int * const * 79 int * const * 74 int *f49[2][3]; 75 int *f50[3][3]; 76 int **f51[2][3]; 77 int **f52[3][3]; 78 int * const *f53[2][3]; 79 int * const *f54[3][3]; 80 80 int * const * const f55[2][3]; 81 81 int * const * const f56[3][3]; 82 82 83 int (* 84 int (* 85 int (** 86 int (** 87 int (* const * 88 int (* const * 83 int (*f57[2][3]); 84 int (*f58[3][3]); 85 int (**f59[2][3]); 86 int (**f60[3][3]); 87 int (* const *f61[2][3]); 88 int (* const *f62[3][3]); 89 89 int (* const * const f63[2][3]); 90 90 int (* const * const f64[3][3]); … … 93 93 int (f66)(int); 94 94 95 int * 96 int ** 97 int * const * 95 int *f67(int); 96 int **f68(int); 97 int * const *f69(int); 98 98 int * const * const f70(int); 99 99 100 int * 101 int ** 102 int * const * 100 int *(f71)(int); 101 int **(f72)(int); 102 int * const *(f73)(int); 103 103 int * const * const (f74)(int); 104 104 105 int (* 106 int (** 107 int (* const * 105 int (*f75)(int); 106 int (**f76)(int); 107 int (* const *f77)(int); 108 108 int (* const * const f78)(int); 109 109 110 int (* (*f79)(int))();111 int (* 110 int (*(*f79)(int))(); 111 int (*(* const f80)(int))(); 112 112 int (* const(* const f81)(int))(); 113 113 } -
src/tests/identParamDeclarator.c
re2e7330 rbc6f918 10 10 // Created On : Wed Aug 17 08:37:56 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jan 17 22:36:11 201813 // Update Count : 212 // Last Modified On : Wed Aug 17 08:38:42 2016 13 // Update Count : 1 14 14 // 15 15 16 int fred 16 int fred( 17 17 int f1, 18 18 int (f2), … … 157 157 ); 158 158 159 int main( int argc, char const *argv[] ) { // dummy main 159 //Dummy main 160 int main(int argc, char const *argv[]) 161 { 160 162 return 0; 161 163 } -
src/tests/preempt_longrun/Makefile.am
re2e7330 rbc6f918 19 19 preempt=1_000ul 20 20 21 REPEAT = ${abs_top_srcdir}/tools/repeat 22 TIME = /usr/bin/time -f "%E" 21 REPEAT = ${abs_top_srcdir}/tools/repeat -s 23 22 24 23 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -debug -O2 -DPREEMPTION_RATE=${preempt} … … 38 37 ${AM_V_GEN}${CC} ${CFLAGS} ${<} -o ${@} 39 38 40 %.run : % ${REPEAT}41 @ time ${REPEAT} -r out.log -i -s$(repeats) timeout ${max_time} ./${<}39 %.run : % 40 @ time ${REPEAT} $(repeats) timeout ${max_time} ./${<} 42 41 @ rm ${<} 43 42 @ echo -e "${<}: SUCCESS\n" 44 45 %.time : % ${REPEAT}46 @ ${REPEAT} -i -s -- $(repeats) $(TIME) -a -o times.log ./${<}47 @ rm ${<}48 @ echo -e "${<}: SUCCESS\n"49 50 ${REPEAT}:51 @+make -C ${abs_top_srcdir}/tools/ -
src/tests/preempt_longrun/Makefile.in
re2e7330 rbc6f918 451 451 max_time = 600 452 452 preempt = 1_000ul 453 REPEAT = ${abs_top_srcdir}/tools/repeat 454 TIME = /usr/bin/time -f "%E" 453 REPEAT = ${abs_top_srcdir}/tools/repeat -s 455 454 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -debug -O2 -DPREEMPTION_RATE=${preempt} 456 455 TESTS = block create disjoint enter enter3 processor stack wait yield … … 875 874 ${AM_V_GEN}${CC} ${CFLAGS} ${<} -o ${@} 876 875 877 %.run : % ${REPEAT}878 @ time ${REPEAT} -r out.log -i -s$(repeats) timeout ${max_time} ./${<}876 %.run : % 877 @ time ${REPEAT} $(repeats) timeout ${max_time} ./${<} 879 878 @ rm ${<} 880 879 @ echo -e "${<}: SUCCESS\n" 881 882 %.time : % ${REPEAT}883 @ ${REPEAT} -i -s -- $(repeats) $(TIME) -a -o times.log ./${<}884 @ rm ${<}885 @ echo -e "${<}: SUCCESS\n"886 887 ${REPEAT}:888 @+make -C ${abs_top_srcdir}/tools/889 880 890 881 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
src/tests/preempt_longrun/block.c
re2e7330 rbc6f918 1 ../ concurrent/signal/block.c1 ../sched-int-block.c -
src/tests/preempt_longrun/create.c
re2e7330 rbc6f918 14 14 thread worker_t {}; 15 15 16 void main(worker_t &this) {}16 void main(worker_t * this) {} 17 17 18 18 int main(int argc, char* argv[]) { -
src/tests/preempt_longrun/disjoint.c
re2e7330 rbc6f918 1 ../ concurrent/signal/disjoint.c1 ../sched-int-disjoint.c -
src/tests/preempt_longrun/enter.c
re2e7330 rbc6f918 17 17 mon_t mon; 18 18 19 void foo( mon_t &mutex this ) {}19 void foo( mon_t * mutex this ) {} 20 20 21 21 thread worker_t {}; 22 22 23 void main( worker_t &this ) {23 void main( worker_t * this ) { 24 24 for( unsigned long i = 0; i < N; i++ ) { 25 foo( mon );25 foo( &mon ); 26 26 } 27 27 } -
src/tests/preempt_longrun/enter3.c
re2e7330 rbc6f918 17 17 mon_t mon1, mon2, mon3; 18 18 19 void foo( mon_t & mutex a, mon_t & mutex b, mon_t &mutex c ) {}19 void foo( mon_t * mutex a, mon_t * mutex b, mon_t * mutex c ) {} 20 20 21 21 thread worker_t {}; 22 22 23 void main( worker_t &this ) {23 void main( worker_t * this ) { 24 24 for( unsigned long i = 0; i < N; i++ ) { 25 foo( mon1, mon2,mon3 );25 foo( &mon1, &mon2, &mon3 ); 26 26 } 27 27 } -
src/tests/preempt_longrun/processor.c
re2e7330 rbc6f918 14 14 thread worker_t {}; 15 15 16 void main(worker_t &this) {}16 void main(worker_t * this) {} 17 17 18 18 int main(int argc, char* argv[]) { -
src/tests/preempt_longrun/stack.c
re2e7330 rbc6f918 14 14 thread worker_t {}; 15 15 16 void main(worker_t &this) {16 void main(worker_t * this) { 17 17 volatile long long p = 5_021_609ul; 18 18 volatile long long a = 326_417ul; -
src/tests/preempt_longrun/wait.c
re2e7330 rbc6f918 1 ../ concurrent/signal/wait.c1 ../sched-int-wait.c -
src/tests/preempt_longrun/yield.c
re2e7330 rbc6f918 14 14 thread worker_t {}; 15 15 16 void main(worker_t &this) {16 void main(worker_t * this) { 17 17 for(int i = 0; i < N; i++) { 18 18 yield();
Note: See TracChangeset
for help on using the changeset viewer.