Changeset 7951100


Ignore:
Timestamp:
Jun 7, 2018, 4:40:05 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
b067d9b
Parents:
b4e1876 (diff), 08b5a7e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
14 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/concurrency/Paper.tex

    rb4e1876 r7951100  
    5656\newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}}
    5757\newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}}
    58 \newcommand{\R}[1]{\Textbf{#1}}
    59 \newcommand{\B}[1]{{\Textbf[blue]{#1}}}
    60 \newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}
    6158\newcommand{\uC}{$\mu$\CC}
    62 \newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace}
    63 \newcommand{\TODO}{{\Textbf{TODO}}}
     59\newcommand{\TODO}[1]{{\Textbf{#1}}}
    6460
    6561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    260256\section{Introduction}
    261257
    262 This paper provides a minimal concurrency \newterm{Abstract Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
     258This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
    263259While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master.
    264260An easier approach for programmers is to support higher-level constructs as the basis of concurrency.
     
    589585As such, library support for threading is far from widespread.
    590586At the time of writing the paper, neither \protect\lstinline|gcc| nor \protect\lstinline|clang| support ``threads.h'' in their standard libraries.}.
    591 On modern architectures, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.
     587In modern programming languages, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.
    592588As 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.
    593589Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay.
     
    627623\newbox\myboxA
    628624\begin{lrbox}{\myboxA}
    629 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     625\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    630626`int f1, f2, state = 1;`   // single global variables
    631627int fib() {
     
    644640        }
    645641}
    646 \end{lstlisting}
     642\end{cfa}
    647643\end{lrbox}
    648644
    649645\newbox\myboxB
    650646\begin{lrbox}{\myboxB}
    651 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     647\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    652648#define FIB_INIT `{ 0, 1 }`
    653649typedef struct { int f2, f1; } Fib;
     
    666662        }
    667663}
    668 \end{lstlisting}
     664\end{cfa}
    669665\end{lrbox}
    670666
     
    679675\newbox\myboxA
    680676\begin{lrbox}{\myboxA}
    681 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     677\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    682678`coroutine` Fib { int fn; };
    683679void main( Fib & fib ) with( fib ) {
     
    699695        }
    700696}
    701 \end{lstlisting}
     697\end{cfa}
    702698\end{lrbox}
    703699\newbox\myboxB
    704700\begin{lrbox}{\myboxB}
    705 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     701\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    706702`coroutine` Fib { int ret; };
    707703void main( Fib & f ) with( fib ) {
     
    723719
    724720
    725 \end{lstlisting}
     721\end{cfa}
    726722\end{lrbox}
    727723\subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA}
     
    771767\newbox\myboxA
    772768\begin{lrbox}{\myboxA}
    773 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     769\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    774770`coroutine` Format {
    775771        char ch;   // used for communication
     
    803799        }
    804800}
    805 \end{lstlisting}
     801\end{cfa}
    806802\end{lrbox}
    807803
    808804\newbox\myboxB
    809805\begin{lrbox}{\myboxB}
    810 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     806\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    811807struct Format {
    812808        char ch;
     
    840836        format( &fmt );
    841837}
    842 \end{lstlisting}
     838\end{cfa}
    843839\end{lrbox}
    844840\subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
     
    10461042};
    10471043\end{cfa}
    1048 & {\Large $\Rightarrow$} &
     1044&
     1045{\Large $\Rightarrow$}
     1046&
    10491047\begin{tabular}{@{}ccc@{}}
    10501048\begin{cfa}
     
    14471445\label{s:InternalScheduling}
    14481446
    1449 While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer, Figure~\ref{f:BoundedBuffer}, may be full/empty so produce/consumer threads must block.
     1447While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer, Figure~\ref{f:GenericBoundedBuffer}, may be full/empty so produce/consumer threads must block.
    14501448Leaving the monitor and trying again (busy waiting) is impractical for high-level programming.
    14511449Monitors eliminate busy waiting by providing internal synchronization to schedule threads needing access to the shared data, where the synchronization is blocking (threads are parked) versus spinning.
    14521450The synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling, where \newterm{scheduling} is defined as indicating which thread acquires the critical section next.
    1453 \newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and behalf of other threads attempting entry.
     1451\newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and on behalf of other threads attempting entry.
    14541452
    14551453Figure~\ref{f:BBInt} shows a \CFA bounded-buffer with internal scheduling, where producers/consumers enter the monitor, see the buffer is full/empty, and block on an appropriate condition lock, @full@/@empty@.
     
    14601458\begin{enumerate}
    14611459\item
    1462 The signalling thread leaves immediately, and the signalled thread continues.
     1460The signalling thread returns immediately, and the signalled thread continues.
    14631461\item
    1464 The signalling thread continues and the signalled thread is marked for urgent unblocking at subsequent scheduling points (exit/wait).
     1462The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait).
    14651463\item
    1466 The signalling thread blocks but is marked for urgrent unblocking and the signalled thread continues.
     1464The signalling thread blocks but is marked for urgrent unblocking at the next scheduling point and the signalled thread continues.
    14671465\end{enumerate}
    14681466The first approach is too restrictive, as it precludes solving a reasonable class of problems (\eg dating service).
    14691467\CFA supports the next two semantics as both are useful.
    14701468Finally, while it is common to store a @condition@ as a field of the monitor, in \CFA, a @condition@ variable can be created/stored independently.
     1469Furthermore, a condition variable is tied to a \emph{group} of monitors on first use (called \newterm{branding}), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors.
    14711470
    14721471\begin{figure}
     
    14741473\newbox\myboxA
    14751474\begin{lrbox}{\myboxA}
    1476 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     1475\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    14771476forall( otype T ) { // distribute forall
    14781477        monitor Buffer {
     
    14981497        }
    14991498}
    1500 \end{lstlisting}
     1499\end{cfa}
    15011500\end{lrbox}
    15021501
    15031502\newbox\myboxB
    15041503\begin{lrbox}{\myboxB}
    1505 \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
     1504\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    15061505forall( otype T ) { // distribute forall
    15071506        monitor Buffer {
     
    15271526        }
    15281527}
    1529 \end{lstlisting}
     1528\end{cfa}
    15301529\end{lrbox}
    15311530
     
    15341533\subfloat[External Scheduling]{\label{f:BBExt}\usebox\myboxB}
    15351534\caption{Generic Bounded-Buffer}
    1536 \label{f:BoundedBuffer}
     1535\label{f:GenericBoundedBuffer}
    15371536\end{figure}
    15381537
     
    15401539External scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the routine calls that can next acquire mutual exclusion.
    15411540If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer.
    1542 Threads making calls to routines that are currently excluded wait outside (externally) of the monitor on a calling queue.
    1543 
    1544 An important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads?
     1541Threads making calls to routines that are currently excluded block outside (externally) of the monitor on a calling queue, versus blocking on condition queues inside the monitor.
     1542
     1543Both internal and external scheduling extend to multiple monitors in a natural way.
     1544\begin{cfa}
     1545monitor M { `condition e`; ... };
     1546void foo( M & mutex m1, M & mutex m2 ) {
     1547        ... wait( `e` ); ...                                    $\C{// wait( e, m1, m2 )}$
     1548        ... wait( `e, m1` ); ...
     1549        ... wait( `e, m2` ); ...
     1550}
     1551
     1552void rtn$\(_1\)$( M & mutex m1, M & mutex m2 );
     1553void rtn$\(_2\)$( M & mutex m1 );
     1554void bar( M & mutex m1, M & mutex m2 ) {
     1555        ... waitfor( `rtn` ); ...                               $\C{// waitfor( rtn\(_1\), m1, m2 )}$
     1556        ... waitfor( `rtn, m1` ); ...                   $\C{// waitfor( rtn\(_2\), m1 )}$
     1557}
     1558\end{cfa}
     1559For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex types in the parameter list, \ie @wait( e, m1, m2 )@.
     1560To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
     1561Wait statically verifies the released monitors are the acquired mutex-parameters so unconditional release is safe.
     1562Similarly, for @waitfor( rtn, ... )@, the default semantics is to atomically block the acceptor and release all acquired mutex types in the parameter list, \ie @waitfor( rtn, m1, m2 )@.
     1563To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@.
     1564Waitfor statically verifies the released monitors are the same as the acquired mutex-parameters of the given routine or routine pointer.
     1565To statically verify the released monitors match with the accepted routine's mutex parameters, the routine (pointer) prototype must be accessible.
     1566
     1567Given the ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock.
     1568\begin{cfa}
     1569void foo( M & mutex m1, M & mutex m2 ) {
     1570        ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired )}$
     1571void baz( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2 )}$
     1572        ... signal( `e` ); ...
     1573\end{cfa}
     1574The @wait@ only releases @m1@ so the signalling thread cannot acquire both @m1@ and @m2@ to  enter @baz@ to get to the @signal@.
     1575While deadlock issues can occur with multiple/nesting acquisition, this issue results from the fact that locks, and by extension monitors, are not perfectly composable.
     1576
     1577Finally, an important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads?
    15451578If barging is allowed, synchronization between a singller and signallee is difficult, often requiring multiple unblock/block cycles (looping around a wait rechecking if a condition is met).
    1546 \CFA scheduling does \emph{not} have barging, which simplifies synchronization among threads in the monitor.
     1579\begin{quote}
     1580However, we decree that a signal operation be followed immediately by resumption of a waiting program, without possibility of an intervening procedure call from yet a third program.
     1581It is only in this way that a waiting program has an absolute guarantee that it can acquire the resource just released by the signalling program without any danger that a third program will interpose a monitor entry and seize the resource instead.~\cite[p.~550]{Hoare74}
     1582\end{quote}
     1583\CFA scheduling \emph{precludes} barging, which simplifies synchronization among threads in the monitor and increases correctness.
     1584For example, there are no loops in either bounded buffer solution in Figure~\ref{f:GenericBoundedBuffer}.
    15471585Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in the design and implementation of \CFA concurrency.
    15481586
    1549 Indeed, like the bulk acquire semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side.
    1550 
    1551 First, here is a simple example of internal scheduling:
    1552 
    1553 \begin{cfa}
    1554 monitor A {
    1555         condition e;
    1556 }
    1557 
    1558 void foo(A& mutex a1, A& mutex a2) {
     1587
     1588\subsection{Barging Prevention}
     1589
     1590Figure~\ref{f:BargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signalling semantics.
     1591The complexity begins at the end of the inner @mutex@ statement, where the semantics of internal scheduling need to be extended for multiple monitors.
     1592The problem is that bulk acquire is used in the inner @mutex@ statement where one of the monitors is already acquired.
     1593When the signalling thread reaches the end of the inner @mutex@ statement, it should transfer ownership of @m1@ and @m2@ to the waiting thread to prevent barging into the outer @mutex@ statement by another thread.
     1594However, both the signalling and signalled threads still need monitor @m1@.
     1595
     1596\begin{figure}
     1597\newbox\myboxA
     1598\begin{lrbox}{\myboxA}
     1599\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1600monitor M m1, m2;
     1601condition c;
     1602mutex( m1 ) {
    15591603        ...
    1560         // Wait for cooperation from bar()
    1561         wait(a1.e);
     1604        mutex( m1, m2 ) {
     1605                ... `wait( c )`; // block and release m1, m2
     1606                // m1, m2 acquired
     1607        } // $\LstCommentStyle{\color{red}release m2}$
     1608        // m1 acquired
     1609} // release m1
     1610\end{cfa}
     1611\end{lrbox}
     1612
     1613\newbox\myboxB
     1614\begin{lrbox}{\myboxB}
     1615\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1616
     1617
     1618mutex( m1 ) {
    15621619        ...
    1563 }
    1564 
    1565 void bar(A& mutex a1, A& mutex a2) {
    1566         // Provide cooperation for foo()
    1567         ...
    1568         // Unblock foo
    1569         signal(a1.e);
    1570 }
    1571 \end{cfa}
    1572 
    1573 % ======================================================================
    1574 % ======================================================================
    1575 \subsection{Internal Scheduling - Multi-Monitor}
    1576 % ======================================================================
    1577 % ======================================================================
    1578 It is easy to understand the problem of multi-monitor scheduling using a series of pseudo-code examples.
    1579 Note that for simplicity in the following snippets of pseudo-code, waiting and signalling is done using an implicit condition variable, like Java built-in monitors.
    1580 Indeed, @wait@ statements always use the implicit condition variable as parameters and explicitly name the monitors (A and B) associated with the condition.
    1581 Note that in \CFA, condition variables are tied to a \emph{group} of monitors on first use (called branding), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors.
    1582 The example below shows the simple case of having two threads (one for each column) and a single monitor A.
    1583 
    1584 \begin{multicols}{2}
    1585 thread 1
    1586 \begin{cfa}
    1587 acquire A
    1588         wait A
    1589 release A
    1590 \end{cfa}
    1591 
    1592 \columnbreak
    1593 
    1594 thread 2
    1595 \begin{cfa}
    1596 acquire A
    1597         signal A
    1598 release A
    1599 \end{cfa}
    1600 \end{multicols}
    1601 One thread acquires before waiting (atomically blocking and releasing A) and the other acquires before signalling.
    1602 It is important to note here that both @wait@ and @signal@ must be called with the proper monitor(s) already acquired.
    1603 This semantic is a logical requirement for barging prevention.
    1604 
    1605 A direct extension of the previous example is a bulk acquire version:
    1606 \begin{multicols}{2}
    1607 \begin{cfa}
    1608 acquire A & B
    1609         wait A & B
    1610 release A & B
    1611 \end{cfa}
    1612 \columnbreak
    1613 \begin{cfa}
    1614 acquire A & B
    1615         signal A & B
    1616 release A & B
    1617 \end{cfa}
    1618 \end{multicols}
    1619 \noindent This version uses bulk acquire (denoted using the {\sf\&} symbol), but the presence of multiple monitors does not add a particularly new meaning.
    1620 Synchronization happens between the two threads in exactly the same way and order.
    1621 The only difference is that mutual exclusion covers a group of monitors.
    1622 On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate.
    1623 
    1624 While deadlock issues can occur when nesting monitors, these issues are only a symptom of the fact that locks, and by extension monitors, are not perfectly composable.
    1625 For monitors, a well-known deadlock problem is the Nested Monitor Problem~\cite{Lister77}, which occurs when a @wait@ is made by a thread that holds more than one monitor.
    1626 For example, the following cfa-code runs into the nested-monitor problem:
    1627 \begin{multicols}{2}
    1628 \begin{cfa}
    1629 acquire A
    1630         acquire B
    1631                 wait B
    1632         release B
    1633 release A
    1634 \end{cfa}
    1635 
    1636 \columnbreak
    1637 
    1638 \begin{cfa}
    1639 acquire A
    1640         acquire B
    1641                 signal B
    1642         release B
    1643 release A
    1644 \end{cfa}
    1645 \end{multicols}
    1646 \noindent The @wait@ only releases monitor @B@ so the signalling thread cannot acquire monitor @A@ to get to the @signal@.
    1647 Attempting release of all acquired monitors at the @wait@ introduces a different set of problems, such as releasing monitor @C@, which has nothing to do with the @signal@.
    1648 
    1649 However, for monitors as for locks, it is possible to write a program using nesting without encountering any problems if nesting is done correctly.
    1650 For example, the next cfa-code snippet acquires monitors {\sf A} then {\sf B} before waiting, while only acquiring {\sf B} when signalling, effectively avoiding the Nested Monitor Problem~\cite{Lister77}.
    1651 
    1652 \begin{multicols}{2}
    1653 \begin{cfa}
    1654 acquire A
    1655         acquire B
    1656                 wait B
    1657         release B
    1658 release A
    1659 \end{cfa}
    1660 
    1661 \columnbreak
    1662 
    1663 \begin{cfa}
    1664 
    1665 acquire B
    1666         signal B
    1667 release B
    1668 
    1669 \end{cfa}
    1670 \end{multicols}
    1671 
    1672 \noindent However, this simple refactoring may not be possible, forcing more complex restructuring.
    1673 
    1674 % ======================================================================
    1675 % ======================================================================
    1676 \subsection{Internal Scheduling - In Depth}
    1677 % ======================================================================
    1678 % ======================================================================
    1679 
    1680 A larger example is presented to show complex issues for bulk acquire and its implementation options are analyzed.
    1681 Figure~\ref{f:int-bulk-cfa} shows an example where bulk acquire adds a significant layer of complexity to the internal signalling semantics, and listing \ref{f:int-bulk-cfa} shows the corresponding \CFA code to implement the cfa-code in listing \ref{f:int-bulk-cfa}.
    1682 For the purpose of translating the given cfa-code into \CFA-code, any method of introducing a monitor is acceptable, \eg @mutex@ parameters, global variables, pointer parameters, or using locals with the @mutex@ statement.
    1683 
    1684 \begin{figure}
    1685 \begin{multicols}{2}
    1686 Waiting thread
    1687 \begin{cfa}[numbers=left]
    1688 acquire A
    1689         // Code Section 1
    1690         acquire A & B
    1691                 // Code Section 2
    1692                 wait A & B
    1693                 // Code Section 3
    1694         release A & B
    1695         // Code Section 4
    1696 release A
    1697 \end{cfa}
    1698 \columnbreak
    1699 Signalling thread
    1700 \begin{cfa}[numbers=left, firstnumber=10,escapechar=|]
    1701 acquire A
    1702         // Code Section 5
    1703         acquire A & B
    1704                 // Code Section 6
    1705                 |\label{line:signal1}|signal A & B
    1706                 // Code Section 7
    1707         |\label{line:releaseFirst}|release A & B
    1708         // Code Section 8
    1709 |\label{line:lastRelease}|release A
    1710 \end{cfa}
    1711 \end{multicols}
    1712 \begin{cfa}[caption={Internal scheduling with bulk acquire},label={f:int-bulk-cfa}]
    1713 \end{cfa}
    1714 \begin{center}
    1715 \begin{cfa}[xleftmargin=.4\textwidth]
    1716 monitor A a;
    1717 monitor B b;
    1718 condition c;
    1719 \end{cfa}
    1720 \end{center}
    1721 \begin{multicols}{2}
    1722 Waiting thread
    1723 \begin{cfa}
    1724 mutex(a) {
    1725         // Code Section 1
    1726         mutex(a, b) {
    1727                 // Code Section 2
    1728                 wait(c);
    1729                 // Code Section 3
    1730         }
    1731         // Code Section 4
    1732 }
    1733 \end{cfa}
    1734 \columnbreak
    1735 Signalling thread
    1736 \begin{cfa}
    1737 mutex(a) {
    1738         // Code Section 5
    1739         mutex(a, b) {
    1740                 // Code Section 6
    1741                 signal(c);
    1742                 // Code Section 7
    1743         }
    1744         // Code Section 8
    1745 }
    1746 \end{cfa}
    1747 \end{multicols}
    1748 \begin{cfa}[caption={Equivalent \CFA code for listing \ref{f:int-bulk-cfa}},label={f:int-bulk-cfa}]
    1749 \end{cfa}
    1750 \begin{multicols}{2}
    1751 Waiter
    1752 \begin{cfa}[numbers=left]
    1753 acquire A
    1754         acquire A & B
    1755                 wait A & B
    1756         release A & B
    1757 release A
    1758 \end{cfa}
    1759 
    1760 \columnbreak
    1761 
    1762 Signaller
    1763 \begin{cfa}[numbers=left, firstnumber=6,escapechar=|]
    1764 acquire A
    1765         acquire A & B
    1766                 signal A & B
    1767         release A & B
    1768         |\label{line:secret}|// Secretly keep B here
    1769 release A
    1770 // Wakeup waiter and transfer A & B
    1771 \end{cfa}
    1772 \end{multicols}
    1773 \begin{cfa}[caption={Figure~\ref{f:int-bulk-cfa}, with delayed signalling comments},label={f:int-secret}]
    1774 \end{cfa}
     1620        mutex( m1, m2 ) {
     1621                ... `signal( c )`; ...
     1622                // m1, m2 acquired
     1623        } // $\LstCommentStyle{\color{red}release m2}$
     1624        // m1 acquired
     1625} // release m1
     1626\end{cfa}
     1627\end{lrbox}
     1628
     1629\newbox\myboxC
     1630\begin{lrbox}{\myboxC}
     1631\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1632
     1633
     1634mutex( m1 ) {
     1635        ... `wait( c )`; ...
     1636        // m1 acquired
     1637} // $\LstCommentStyle{\color{red}release m1}$
     1638
     1639
     1640
     1641
     1642\end{cfa}
     1643\end{lrbox}
     1644
     1645\begin{cquote}
     1646\subfloat[Waiting Thread]{\label{f:WaitingThread}\usebox\myboxA}
     1647\hspace{2\parindentlnth}
     1648\subfloat[Signalling Thread]{\label{f:SignallingThread}\usebox\myboxB}
     1649\hspace{2\parindentlnth}
     1650\subfloat[Other Waiting Thread]{\label{f:SignallingThread}\usebox\myboxC}
     1651\end{cquote}
     1652\caption{Barging Prevention}
     1653\label{f:BargingPrevention}
    17751654\end{figure}
    17761655
    1777 The complexity begins at code sections 4 and 8 in listing \ref{f:int-bulk-cfa}, which are where the existing semantics of internal scheduling needs to be extended for multiple monitors.
    1778 The root of the problem is that bulk acquire is used in a context where one of the monitors is already acquired, which is why it is important to define the behaviour of the previous cfa-code.
    1779 When the signaller thread reaches the location where it should ``release @A & B@'' (listing \ref{f:int-bulk-cfa} line \ref{line:releaseFirst}), it must actually transfer ownership of monitor @B@ to the waiting thread.
    1780 This ownership transfer is required in order to prevent barging into @B@ by another thread, since both the signalling and signalled threads still need monitor @A@.
    1781 There are three options:
    1782 
    1783 \subsubsection{Delaying Signals}
    17841656The obvious solution to the problem of multi-monitor scheduling is to keep ownership of all locks until the last lock is ready to be transferred.
    17851657It can be argued that that moment is when the last lock is no longer needed, because this semantics fits most closely to the behaviour of single-monitor scheduling.
     
    17941666Depending on the order of signals (listing \ref{f:dependency} line \ref{line:signal-ab} and \ref{line:signal-a}) two cases can happen:
    17951667
     1668\begin{comment}
    17961669\paragraph{Case 1: thread $\alpha$ goes first.} In this case, the problem is that monitor @A@ needs to be passed to thread $\beta$ when thread $\alpha$ is done with it.
    17971670\paragraph{Case 2: thread $\beta$ goes first.} In this case, the problem is that monitor @B@ needs to be retained and passed to thread $\alpha$ along with monitor @A@, which can be done directly or possibly using thread $\beta$ as an intermediate.
     
    18031676In both cases, the threads need to be able to distinguish, on a per monitor basis, which ones need to be released and which ones need to be transferred, which means knowing when to release a group becomes complex and inefficient (see next section) and therefore effectively precludes this approach.
    18041677
     1678
    18051679\subsubsection{Dependency graphs}
    1806 
    18071680
    18081681\begin{figure}
     
    18831756
    18841757\subsubsection{Partial Signalling} \label{partial-sig}
     1758\end{comment}
     1759
    18851760Finally, the solution that is chosen for \CFA is to use partial signalling.
    18861761Again using listing \ref{f:int-bulk-cfa}, the partial signalling solution transfers ownership of monitor @B@ at lines \ref{line:signal1} to the waiter but does not wake the waiting thread since it is still using monitor @A@.
     
    18971772\end{itemize}
    18981773
    1899 % ======================================================================
    1900 % ======================================================================
     1774
    19011775\subsection{Signalling: Now or Later}
    1902 % ======================================================================
    1903 % ======================================================================
    1904 \begin{table}
    1905 \begin{tabular}{|c|c|}
    1906 @signal@ & @signal_block@ \\
    1907 \hline
    1908 \begin{cfa}[tabsize=3]
    1909 monitor DatingService {
    1910         // compatibility codes
    1911         enum{ CCodes = 20 };
    1912 
    1913         int girlPhoneNo
    1914         int boyPhoneNo;
     1776
     1777\begin{figure}
     1778\centering
     1779\newbox\myboxA
     1780\begin{lrbox}{\myboxA}
     1781\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1782enum { CCodes = 20 };
     1783monitor DS {
     1784        int GirlPhNo, BoyPhNo;
     1785        condition Girls[CCodes], Boys[CCodes];
     1786        condition exchange;
    19151787};
    1916 
    1917 condition girls[CCodes];
    1918 condition boys [CCodes];
    1919 condition exchange;
    1920 
    1921 int girl(int phoneNo, int cfa) {
    1922         // no compatible boy ?
    1923         if(empty(boys[cfa])) {
    1924                 wait(girls[cfa]);               // wait for boy
    1925                 girlPhoneNo = phoneNo;          // make phone number available
    1926                 signal(exchange);               // wake boy from chair
     1788int girl( DS & mutex ds, int phNo, int ccode ) {
     1789        if ( is_empty( Boys[ccode] ) ) {
     1790                wait( Girls[ccode] );
     1791                GirlPhNo = phNo;
     1792                exchange.signal();
    19271793        } else {
    1928                 girlPhoneNo = phoneNo;          // make phone number available
    1929                 signal(boys[cfa]);              // wake boy
    1930                 wait(exchange);         // sit in chair
    1931         }
    1932         return boyPhoneNo;
    1933 }
    1934 int boy(int phoneNo, int cfa) {
    1935         // same as above
    1936         // with boy/girl interchanged
    1937 }
    1938 \end{cfa}&\begin{cfa}[tabsize=3]
    1939 monitor DatingService {
    1940 
    1941         enum{ CCodes = 20 };    // compatibility codes
    1942 
    1943         int girlPhoneNo;
    1944         int boyPhoneNo;
     1794                GirlPhNo = phNo;
     1795                signal( Boys[ccode] );
     1796                exchange.wait();
     1797        } // if
     1798        return BoyPhNo;
     1799}
     1800int boy( DS & mutex ds, int phNo, int ccode ) {
     1801        // as above with boy/girl interchanged
     1802}
     1803\end{cfa}
     1804\end{lrbox}
     1805
     1806\newbox\myboxB
     1807\begin{lrbox}{\myboxB}
     1808\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1809
     1810monitor DS {
     1811        int GirlPhNo, BoyPhNo;
     1812        condition Girls[CCodes], Boys[CCodes];
     1813
    19451814};
    1946 
    1947 condition girls[CCodes];
    1948 condition boys [CCodes];
    1949 // exchange is not needed
    1950 
    1951 int girl(int phoneNo, int cfa) {
    1952         // no compatible boy ?
    1953         if(empty(boys[cfa])) {
    1954                 wait(girls[cfa]);               // wait for boy
    1955                 girlPhoneNo = phoneNo;          // make phone number available
    1956                 signal(exchange);               // wake boy from chair
     1815int girl( DS & mutex ds, int phNo, int ccode ) {
     1816        if ( is_empty( Boys[ccode] ) ) { // no compatible
     1817                wait( Girls[ccode] ); // wait for boy
     1818                GirlPhNo = phNo; // make phone number available
     1819
    19571820        } else {
    1958                 girlPhoneNo = phoneNo;          // make phone number available
    1959                 signal_block(boys[cfa]);                // wake boy
    1960 
    1961                 // second handshake unnecessary
    1962 
    1963         }
    1964         return boyPhoneNo;
    1965 }
    1966 
    1967 int boy(int phoneNo, int cfa) {
    1968         // same as above
    1969         // with boy/girl interchanged
    1970 }
    1971 \end{cfa}
    1972 \end{tabular}
    1973 \caption{Dating service example using \protect\lstinline|signal| and \protect\lstinline|signal_block|. }
    1974 \label{tbl:datingservice}
    1975 \end{table}
     1821                GirlPhNo = phNo; // make phone number available
     1822                signal_block( Boys[ccode] ); // restart boy
     1823
     1824        } // if
     1825        return BoyPhNo;
     1826}
     1827int boy( DS & mutex ds, int phNo, int ccode ) {
     1828        // as above with boy/girl interchanged
     1829}
     1830\end{cfa}
     1831\end{lrbox}
     1832
     1833\subfloat[\lstinline@signal@]{\label{f:DatingSignal}\usebox\myboxA}
     1834\qquad
     1835\subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB}
     1836\caption{Dating service. }
     1837\label{f:Dating service}
     1838\end{figure}
     1839
    19761840An important note is that, until now, signalling a monitor was a delayed operation.
    19771841The ownership of the monitor is transferred only when the monitor would have otherwise been released, not at the point of the @signal@ statement.
     
    19901854% ======================================================================
    19911855An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}).
     1856
     1857\begin{comment}
    19921858\begin{table}
    19931859\begin{tabular}{|c|c|c|}
     
    20531919\label{tbl:sched}
    20541920\end{table}
     1921\end{comment}
     1922
    20551923This method is more constrained and explicit, which helps users reduce the non-deterministic nature of concurrency.
    20561924Indeed, as the following examples demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occurring.
  • src/Common/SemanticError.cc

    rb4e1876 r7951100  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May 16 15:01:20 2018
    13 // Update Count     : 9
     12// Last Modified On : Thu Jun  7 08:05:26 2018
     13// Update Count     : 10
    1414//
    1515
     
    9797void SemanticError( CodeLocation location, std::string error ) {
    9898        SemanticErrorThrow = true;
    99         throw SemanticErrorException(location, error);
     99        throw SemanticErrorException( location, error );
    100100}
    101101
  • src/Parser/DeclarationNode.cc

    rb4e1876 r7951100  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun  6 15:57:50 2018
    13 // Update Count     : 1076
     12// Last Modified On : Thu Jun  7 12:08:55 2018
     13// Update Count     : 1079
    1414//
    1515
     
    545545                                        type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier
    546546                                } else {                                                                // not polymorphic
    547                                         type->aggregate.params = q->type->forall; // make polymorphic type
    548                                         // change implicit typedef from TYPEDEFname to TYPEGENname
    549                                         typedefTable.changeKind( *type->aggregate.name, TYPEGENname );
     547                                        type->aggregate.params = q->type->forall; // set forall qualifier
    550548                                } // if
    551549                        } else {                                                                        // not polymorphic
  • src/Parser/TypedefTable.cc

    rb4e1876 r7951100  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun  1 16:54:18 2018
    13 // Update Count     : 155
     12// Last Modified On : Thu Jun  7 13:17:56 2018
     13// Update Count     : 192
    1414//
    1515
     
    1717#include "TypedefTable.h"
    1818#include <cassert>                                                                              // for assert
     19#include <iostream>
    1920
    2021#if 0
    21 #include <iostream>
    2222#define debugPrint( code ) code
    2323#else
     
    2727using namespace std;                                                                    // string, iostream
    2828
     29debugPrint(
     30static const char *kindName( int kind ) {
     31        switch ( kind ) {
     32          case IDENTIFIER: return "identifier";
     33          case TYPEDEFname: return "typedef";
     34          case TYPEGENname: return "typegen";
     35          default:
     36                cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
     37                abort();
     38        } // switch
     39} // kindName
     40)
     41
    2942TypedefTable::~TypedefTable() {
    3043        if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) {
    31                 std::cerr << "scope failure " << kindTable.currentScope() << endl;
     44                cerr << "Error: cfa-cpp internal error, scope failure " << kindTable.currentScope() << endl;
     45                abort();
    3246        } // if
    3347} // TypedefTable::~TypedefTable
     
    4458} // TypedefTable::isKind
    4559
    46 void TypedefTable::changeKind( const string & identifier, int kind ) {
    47         KindTable::iterator posn = kindTable.find( identifier );
    48         if ( posn != kindTable.end() ) posn->second = kind;     // exists => update
    49 } // TypedefTable::changeKind
    50 
    5160// SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by
    5261// "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the
    5362// name is explicitly used.
    54 void TypedefTable::makeTypedef( const string & name ) {
     63void TypedefTable::makeTypedef( const string & name, int kind ) {
     64//    Check for existence is necessary to handle:
     65//        struct Fred {};
     66//        void Fred();
     67//        void fred() {
     68//           struct Fred act; // do not add as type in this scope
     69//           Fred();
     70//        }
    5571        if ( ! typedefTable.exists( name ) ) {
    56                 typedefTable.addToEnclosingScope( name, TYPEDEFname, "MTD" );
     72                typedefTable.addToEnclosingScope( name, kind, "MTD" );
    5773        } // if
    5874} // TypedefTable::makeTypedef
    5975
    60 void TypedefTable::addToScope( const std::string & identifier, int kind, const char * locn __attribute__((unused)) ) {
     76void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
    6177        auto scope = kindTable.currentScope();
    62         debugPrint( cerr << "Adding at " << locn << " " << identifier << " as kind " << kind << " scope " << scope << endl );
     78        debugPrint( cerr << "Adding current at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl );
    6379        auto ret = kindTable.insertAt( scope, identifier, kind );
    6480        if ( ! ret.second ) ret.first->second = kind;           // exists => update
    6581} // TypedefTable::addToScope
    6682
    67 void TypedefTable::addToEnclosingScope( const std::string & identifier, int kind, const char * locn __attribute__((unused)) ) {
     83void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
    6884        assert( kindTable.currentScope() >= 1 );
    6985        auto scope = kindTable.currentScope() - 1;
    70         debugPrint( cerr << "Adding+1 at " << locn << " " << identifier << " as kind " << kind << " scope " << scope << endl );
     86        debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl );
    7187        auto ret = kindTable.insertAt( scope, identifier, kind );
    7288        if ( ! ret.second ) ret.first->second = kind;           // exists => update
     
    93109                        debugPrint( cerr << endl << "[" << scope << "]" );
    94110                } // while
    95                 debugPrint( cerr << " " << (*i).first << ":" << (*i).second );
     111                debugPrint( cerr << " " << (*i).first << ":" << kindName( (*i).second ) );
    96112        } // for
    97113        while ( scope > 0 ) {
  • src/Parser/TypedefTable.h

    rb4e1876 r7951100  
    1010// Created On       : Sat May 16 15:24:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu May 31 23:23:47 2018
    13 // Update Count     : 83
     12// Last Modified On : Thu Jun  7 12:10:17 2018
     13// Update Count     : 85
    1414//
    1515
     
    3030        bool exists( const std::string & identifier );
    3131        int isKind( const std::string & identifier ) const;
    32         void changeKind( const std::string & identifier, int kind );
    33         void makeTypedef( const std::string & name );
     32        void makeTypedef( const std::string & name, int kind = TYPEDEFname );
    3433        void addToScope( const std::string & identifier, int kind, const char * );
    3534        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/lex.ll

    rb4e1876 r7951100  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Wed Jun  6 17:31:09 2018
    13  * Update Count     : 677
     12 * Last Modified On : Thu Jun  7 08:27:40 2018
     13 * Update Count     : 679
    1414 */
    1515
     
    452452
    453453%%
     454
    454455// ----end of lexer----
    455456
    456457void yyerror( const char * errmsg ) {
     458        SemanticErrorThrow = true;
    457459        cout << (yyfilename ? yyfilename : "*unknown file*") << ':' << yylineno << ':' << column - yyleng + 1
    458460                 << ": " << ErrorHelpers::error_str() << errmsg << " at token \"" << (yytext[0] == '\0' ? "EOF" : yytext) << '"' << endl;
  • src/Parser/parser.yy

    rb4e1876 r7951100  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun  6 14:53:38 2018
    13 // Update Count     : 3522
     12// Last Modified On : Thu Jun  7 10:07:12 2018
     13// Update Count     : 3527
    1414//
    1515
     
    18261826        | aggregate_key attribute_list_opt no_attr_identifier
    18271827                {
    1828                         typedefTable.makeTypedef( *$3 );                        // create typedef
    1829                         if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
     1828                        typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname ); // create typedef
     1829                        //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
    18301830                        forall = false;                                                         // reset
    18311831                }
     
    18341834        | aggregate_key attribute_list_opt type_name
    18351835                {
    1836                         typedefTable.makeTypedef( *$3->type->symbolic.name ); // create typedef
    1837                         if ( forall ) typedefTable.changeKind( *$3->type->symbolic.name, TYPEGENname ); // possibly update
     1836                        typedefTable.makeTypedef( *$3->type->symbolic.name, forall ? TYPEGENname : TYPEDEFname ); // create typedef
     1837                        //if ( forall ) typedefTable.changeKind( *$3->type->symbolic.name, TYPEGENname ); // possibly update
    18381838                        forall = false;                                                         // reset
    18391839                }
     
    18481848        aggregate_key attribute_list_opt no_attr_identifier
    18491849                {
    1850                         typedefTable.makeTypedef( *$3 );
    1851                         if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
     1850                        typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname );
     1851                        //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
    18521852                        forall = false;                                                         // reset
    18531853                        $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 );
     
    32643264
    32653265%%
     3266
    32663267// ----end of grammar----
    32673268
  • src/libcfa/bits/locks.h

    rb4e1876 r7951100  
    1818#include "bits/debug.h"
    1919#include "bits/defs.h"
     20#include <assert.h>
     21
     22#ifdef __cforall
     23        extern "C" {
     24                #include <pthread.h>
     25        }
     26#endif
    2027
    2128// pause to prevent excess processor bus usage
     
    112119                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
    113120        }
     121
     122
     123        #ifdef __CFA_WITH_VERIFY__
     124                extern bool __cfaabi_dbg_in_kernel();
     125        #endif
     126
     127        struct __bin_sem_t {
     128                int_fast8_t     counter;
     129                pthread_mutex_t lock;
     130                pthread_cond_t  cond;
     131        };
     132
     133        static inline void ?{}(__bin_sem_t & this) with( this ) {
     134                counter = 0;
     135                pthread_mutex_init(&lock, NULL);
     136                pthread_cond_init (&cond, NULL);
     137        }
     138
     139        static inline void ^?{}(__bin_sem_t & this) with( this ) {
     140                pthread_mutex_destroy(&lock);
     141                pthread_cond_destroy (&cond);
     142        }
     143
     144        static inline void wait(__bin_sem_t & this) with( this ) {
     145                verify(__cfaabi_dbg_in_kernel());
     146                pthread_mutex_lock(&lock);
     147                if(counter != 0) {   // this must be a loop, not if!
     148                        pthread_cond_wait(&cond, &lock);
     149                }
     150                counter = 1;
     151                pthread_mutex_unlock(&lock);
     152        }
     153
     154        static inline void post(__bin_sem_t & this) with( this ) {
     155                verify(__cfaabi_dbg_in_kernel());
     156                pthread_mutex_lock(&lock);
     157                bool needs_signal = counter == 0;
     158                counter = 1;
     159                pthread_mutex_unlock(&lock);
     160                if (!needs_signal)
     161                        pthread_cond_signal(&cond);
     162                }
    114163#endif
  • src/libcfa/concurrency/kernel

    rb4e1876 r7951100  
    133133        // Idle lock
    134134        sem_t idleLock;
     135        // __bin_sem_t idleLock;
    135136
    136137        // Link lists fields
    137         struct {
     138        struct __dbg_node_proc {
    138139                struct processor * next;
    139140                struct processor * prev;
     
    182183
    183184        // Link lists fields
    184         struct {
     185        struct __dbg_node_cltr {
    185186                cluster * next;
    186187                cluster * prev;
  • src/libcfa/concurrency/kernel.c

    rb4e1876 r7951100  
    1717#include <stddef.h>
    1818#include <errno.h>
     19#include <string.h>
    1920extern "C" {
    2021#include <stdio.h>
     
    5051thread_desc * mainThread;
    5152
    52 struct { __dllist_t(cluster) list; __spinlock_t lock; } global_clusters;
     53extern "C" {
     54struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
     55}
    5356
    5457//-----------------------------------------------------------------------------
     
    150153
    151154void ^?{}(processor & this) with( this ){
    152         if( ! do_terminate ) {
     155        if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
    153156                __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
    154157                terminate(&this);
    155                 verify(this.do_terminate);
     158                verify( __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    156159                verify( kernelTLS.this_processor != &this);
    157160                P( terminated );
     
    199202
    200203                thread_desc * readyThread = NULL;
    201                 for( unsigned int spin_count = 0; ! this->do_terminate; spin_count++ )
     204                for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ )
    202205                {
    203206                        readyThread = nextThread( this->cltr );
     
    218221                        else
    219222                        {
    220                                 spin(this, &spin_count);
     223                                // spin(this, &spin_count);
     224                                halt(this);
    221225                        }
    222226                }
     
    545549        __cfaabi_dbg_print_safe("Kernel : Starting\n");
    546550
    547         global_clusters.list{ __get };
    548         global_clusters.lock{};
     551        __cfa_dbg_global_clusters.list{ __get };
     552        __cfa_dbg_global_clusters.lock{};
    549553
    550554        // Initialize the main cluster
     
    627631        // When its coroutine terminates, it return control to the mainThread
    628632        // which is currently here
    629         mainProcessor->do_terminate = true;
     633        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
    630634        returnToKernel();
     635        mainThread->self_cor.state = Halted;
    631636
    632637        // THE SYSTEM IS NOW COMPLETELY STOPPED
     
    644649        ^(mainThread){};
    645650
    646         ^(global_clusters.list){};
    647         ^(global_clusters.lock){};
     651        ^(__cfa_dbg_global_clusters.list){};
     652        ^(__cfa_dbg_global_clusters.lock){};
    648653
    649654        __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
     
    655660
    656661void halt(processor * this) with( *this ) {
     662        verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
     663
    657664        with( *cltr ) {
    658665                lock      (proc_list_lock __cfaabi_dbg_ctx2);
     
    664671        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
    665672
    666         verify( ({int sval = 0; sem_getvalue(&this->idleLock, &sval); sval; }) < 200);
     673        // #ifdef __CFA_WITH_VERIFY__
     674        //      int sval = 0;
     675        //      sem_getvalue(&this->idleLock, &sval);
     676        //      verifyf(sval < 200, "Binary semaphore reached value %d : \n", sval);
     677        // #endif
     678
     679        verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    667680        int __attribute__((unused)) ret = sem_wait(&idleLock);
    668         verify(ret > 0 || errno == EINTR);
     681        // verifyf(ret >= 0 || errno == EINTR, "Sem_wait returned %d (errno %d : %s\n", ret, errno, strerror(errno));
     682
     683        // wait( idleLock );
    669684
    670685        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
     
    681696        __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
    682697        int __attribute__((unused)) ret = sem_post(&this->idleLock);
    683         verify(ret > 0 || errno == EINTR);
    684         verify( ({int sval = 0; sem_getvalue(&this->idleLock, &sval); sval; }) < 200);
     698        // verifyf(ret >= 0 || errno == EINTR, "Sem_post returned %d (errno %d : %s\n", ret, errno, strerror(errno));
     699
     700        // #ifdef __CFA_WITH_VERIFY__
     701        //      int sval = 0;
     702        //      sem_getvalue(&this->idleLock, &sval);
     703        //      verifyf(sval < 200, "Binary semaphore reached value %d\n", sval);
     704        // #endif
     705
     706        // post( this->idleLock );
    685707}
    686708
     
    798820// Global Queues
    799821void doregister( cluster     & cltr ) {
    800         lock      ( global_clusters.lock __cfaabi_dbg_ctx2);
    801         push_front( global_clusters.list, cltr );
    802         unlock    ( global_clusters.lock );
     822        lock      ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
     823        push_front( __cfa_dbg_global_clusters.list, cltr );
     824        unlock    ( __cfa_dbg_global_clusters.lock );
    803825}
    804826
    805827void unregister( cluster     & cltr ) {
    806         lock  ( global_clusters.lock __cfaabi_dbg_ctx2);
    807         remove( global_clusters.list, cltr );
    808         unlock( global_clusters.lock );
     828        lock  ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
     829        remove( __cfa_dbg_global_clusters.list, cltr );
     830        unlock( __cfa_dbg_global_clusters.lock );
    809831}
    810832
  • src/libcfa/concurrency/preemption.c

    rb4e1876 r7951100  
    265265// kill wrapper : signal a processor
    266266void terminate(processor * this) {
    267         this->do_terminate = true;
    268         wake(this);
     267        disable_interrupts();
     268        __atomic_store_n(&this->do_terminate, true, __ATOMIC_SEQ_CST);
     269        wake( this );
    269270        sigval_t value = { PREEMPT_TERMINATE };
     271        enable_interrupts( __cfaabi_dbg_ctx );
    270272        pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
    271273}
     
    369371        choose(sfp->si_value.sival_int) {
    370372                case PREEMPT_NORMAL   : ;// Normal case, nothing to do here
    371                 case PREEMPT_TERMINATE: verify( kernelTLS.this_processor->do_terminate);
     373                case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
    372374                default:
    373375                        abort( "internal error, signal value is %d", sfp->si_value.sival_int );
     
    488490}
    489491
     492#ifdef __CFA_WITH_VERIFY__
     493bool __cfaabi_dbg_in_kernel() {
     494        return !kernelTLS.preemption_state.enabled;
     495}
     496#endif
     497
    490498// Local Variables: //
    491499// mode: c //
  • src/libcfa/stdhdr/assert.h

    rb4e1876 r7951100  
    3333        #define verify(x) assert(x)
    3434        #define verifyf(x, ...) assertf(x, __VA_ARGS__)
     35        #define __CFA_WITH_VERIFY__
    3536#else
    3637        #define verify(x)
  • src/prelude/sync-builtins.cf

    rb4e1876 r7951100  
    248248#endif
    249249
     250_Bool __atomic_load_n(const volatile _Bool *, int);
     251void __atomic_load(const volatile _Bool *, volatile _Bool *, int);
    250252char __atomic_load_n(const volatile char *, int);
    251253char __atomic_load_1(const volatile char *, int);
     
    285287
    286288void __atomic_store_n(volatile _Bool *, _Bool, int);
    287 void __atomic_store_1(volatile _Bool *, _Bool, int);
    288289void __atomic_store(volatile _Bool *, _Bool *, int);
    289290void __atomic_store_n(volatile char *, char, int);
  • src/tests/preempt_longrun/processor.c

    rb4e1876 r7951100  
    22#include <thread>
    33#include <time>
     4
     5#include <unistd.h>
    46
    57#ifndef PREEMPTION_RATE
     
    1517int main(int argc, char* argv[]) {
    1618        processor * p[15];
     19        write(STDERR_FILENO, "Preparing\n", sizeof("Preparing\n"));
    1720        for ( int pi = 0; pi < 15; pi++ ) {
    1821                p[pi] = new();
    1922        }
     23        write(STDERR_FILENO, "Starting\n", sizeof("Starting\n"));
    2024        for ( int i = 0; i < N; i++) {
    2125                int pi = i % 15;
     
    2327                p[pi] = new();
    2428        }
     29        write(STDERR_FILENO, "Stopping\n", sizeof("Stopping\n"));
    2530        for ( int pi = 0; pi < 15; pi++ ) {
    2631                delete( p[pi] );
    2732        }
     33        write(STDERR_FILENO, "Done\n", sizeof("Done\n"));
    2834}
Note: See TracChangeset for help on using the changeset viewer.