Changes in / [61accc5:c2b10fa]


Ignore:
Files:
3 deleted
17 edited

Legend:

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

    r61accc5 rc2b10fa  
    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}}}
    5861\newcommand{\uC}{$\mu$\CC}
    59 \newcommand{\TODO}[1]{{\Textbf{#1}}}
     62\newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace}
     63\newcommand{\TODO}{{\Textbf{TODO}}}
    6064
    6165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    254258\section{Introduction}
    255259
    256 This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
     260This paper provides a minimal concurrency \newterm{Abstract Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
    257261While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master.
    258262An easier approach for programmers is to support higher-level constructs as the basis of concurrency.
     
    580584\subsection{\protect\CFA's Thread Building Blocks}
    581585
    582 An important missing feature in C is threading\footnote{While the C11 standard defines a \protect\lstinline@threads.h@ header, it is minimal and defined as optional.
     586An important missing feature in C is threading\footnote{While the C11 standard defines a ``threads.h'' header, it is minimal and defined as optional.
    583587As such, library support for threading is far from widespread.
    584 At the time of writing the paper, neither \protect\lstinline@gcc@ nor \protect\lstinline@clang@ support \protect\lstinline@threads.h@ in their standard libraries.}.
    585 In 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.
     588At the time of writing the paper, neither \protect\lstinline|gcc| nor \protect\lstinline|clang| support ``threads.h'' in their standard libraries.}.
     589On 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.
    586590As 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.
    587591Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay.
     
    621625\newbox\myboxA
    622626\begin{lrbox}{\myboxA}
    623 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     627\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    624628`int f1, f2, state = 1;`   // single global variables
    625629int fib() {
     
    638642        }
    639643}
    640 \end{cfa}
     644\end{lstlisting}
    641645\end{lrbox}
    642646
    643647\newbox\myboxB
    644648\begin{lrbox}{\myboxB}
    645 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     649\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    646650#define FIB_INIT `{ 0, 1 }`
    647651typedef struct { int f2, f1; } Fib;
     
    660664        }
    661665}
    662 \end{cfa}
     666\end{lstlisting}
    663667\end{lrbox}
    664668
     
    673677\newbox\myboxA
    674678\begin{lrbox}{\myboxA}
    675 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     679\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    676680`coroutine` Fib { int fn; };
    677681void main( Fib & fib ) with( fib ) {
     
    693697        }
    694698}
    695 \end{cfa}
     699\end{lstlisting}
    696700\end{lrbox}
    697701\newbox\myboxB
    698702\begin{lrbox}{\myboxB}
    699 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     703\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    700704`coroutine` Fib { int ret; };
    701705void main( Fib & f ) with( fib ) {
     
    717721
    718722
    719 \end{cfa}
     723\end{lstlisting}
    720724\end{lrbox}
    721725\subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA}
     
    765769\newbox\myboxA
    766770\begin{lrbox}{\myboxA}
    767 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     771\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    768772`coroutine` Format {
    769773        char ch;   // used for communication
     
    797801        }
    798802}
    799 \end{cfa}
     803\end{lstlisting}
    800804\end{lrbox}
    801805
    802806\newbox\myboxB
    803807\begin{lrbox}{\myboxB}
    804 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     808\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    805809struct Format {
    806810        char ch;
     
    834838        format( &fmt );
    835839}
    836 \end{cfa}
     840\end{lstlisting}
    837841\end{lrbox}
    838842\subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
     
    10401044};
    10411045\end{cfa}
    1042 &
    1043 {\Large $\Rightarrow$}
    1044 &
     1046& {\Large $\Rightarrow$} &
    10451047\begin{tabular}{@{}ccc@{}}
    10461048\begin{cfa}
     
    11401142}
    11411143\end{cfa}
    1142 A consequence of the strongly typed approach to main is that memory layout of parameters and return values to/from a thread are now explicitly specified in the \textbf{API}.
     1144A consequence of the strongly typed approach to main is that memory layout of parameters and return values to/from a thread are now explicitly specified in the \textbf{api}.
    11431145\end{comment}
    11441146
     
    14431445\label{s:InternalScheduling}
    14441446
    1445 While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed.
    1446 For example, Figure~\ref{f:GenericBoundedBuffer} shows a bounded buffer that 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:BoundedBuffer}, may be full/empty so produce/consumer threads must block.
    14471448Leaving the monitor and trying again (busy waiting) is impractical for high-level programming.
    14481449Monitors 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.
    1449 Synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling, where \newterm{scheduling} defines which thread acquires the critical section next.
    1450 \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.
     1450The 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.
     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 behalf of other threads attempting entry.
    14511452
    14521453Figure~\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@.
     
    14571458\begin{enumerate}
    14581459\item
    1459 The signalling thread returns immediately, and the signalled thread continues.
     1460The signalling thread leaves immediately, and the signalled thread continues.
    14601461\item
    1461 The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait).
     1462The signalling thread continues and the signalled thread is marked for urgent unblocking at subsequent scheduling points (exit/wait).
    14621463\item
    1463 The signalling thread blocks but is marked for urgrent unblocking at the next scheduling point and the signalled thread continues.
     1464The signalling thread blocks but is marked for urgrent unblocking and the signalled thread continues.
    14641465\end{enumerate}
    14651466The first approach is too restrictive, as it precludes solving a reasonable class of problems (\eg dating service).
    14661467\CFA supports the next two semantics as both are useful.
    14671468Finally, while it is common to store a @condition@ as a field of the monitor, in \CFA, a @condition@ variable can be created/stored independently.
    1468 Furthermore, 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.
    14691469
    14701470\begin{figure}
     
    14721472\newbox\myboxA
    14731473\begin{lrbox}{\myboxA}
    1474 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1474\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    14751475forall( otype T ) { // distribute forall
    14761476        monitor Buffer {
     
    14961496        }
    14971497}
    1498 \end{cfa}
     1498\end{lstlisting}
    14991499\end{lrbox}
    15001500
    15011501\newbox\myboxB
    15021502\begin{lrbox}{\myboxB}
    1503 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1503\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    15041504forall( otype T ) { // distribute forall
    15051505        monitor Buffer {
     
    15251525        }
    15261526}
    1527 \end{cfa}
     1527\end{lstlisting}
    15281528\end{lrbox}
    15291529
     
    15321532\subfloat[External Scheduling]{\label{f:BBExt}\usebox\myboxB}
    15331533\caption{Generic Bounded-Buffer}
    1534 \label{f:GenericBoundedBuffer}
     1534\label{f:BoundedBuffer}
    15351535\end{figure}
    15361536
     
    15381538External 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.
    15391539If 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.
    1540 Threads making calls to routines that are currently excluded block outside (external) of the monitor on a calling queue, versus blocking on condition queues inside (internal) of the monitor.
    1541 
    1542 For internal scheduling, non-blocking signalling (as in the producer/consumer example) is used when the signaller is providing the cooperation for a waiting thread;
    1543 the signaller enters the monitor and changes state, detects a waiting threads that can use the state, performs a non-blocking signal on the condition queue for the waiting thread, and exits the monitor to run concurrently.
    1544 The waiter unblocks next, takes the state, and exits the monitor.
    1545 Blocking signalling is the reverse, where the waiter is providing the cooperation for the signalling thread;
    1546 the signaller enters the monitor, detects a waiting thread providing the necessary state, performs a blocking signal to place it on the urgent queue and unblock the waiter.
    1547 The waiter changes state and exits the monitor, and the signaller unblocks next from the urgent queue to take the state.
    1548 
    1549 Figure~\ref{f:DatingService} shows a dating service demonstrating the two forms of signalling: non-blocking and blocking.
    1550 The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
    1551 A thread blocks until an appropriate partner arrives.
    1552 The complexity is exchanging phone number in the monitor,
    1553 While the non-barging monitor prevents a caller from stealing a phone number, the monitor mutual-exclusion property
    1554 
    1555 The dating service is an example of a monitor that cannot be written using external scheduling because:
    1556 
    1557 The example in table \ref{tbl:datingservice} highlights the difference in behaviour.
    1558 As mentioned, @signal@ only transfers ownership once the current critical section exits; this behaviour requires additional synchronization when a two-way handshake is needed.
    1559 To avoid this explicit synchronization, the @condition@ type offers the @signal_block@ routine, which handles the two-way handshake as shown in the example.
    1560 This feature removes the need for a second condition variables and simplifies programming.
    1561 Like every other monitor semantic, @signal_block@ uses barging prevention, which means mutual-exclusion is baton-passed both on the front end and the back end of the call to @signal_block@, meaning no other thread can acquire the monitor either before or after the call.
     1540Threads making calls to routines that are currently excluded wait outside (externally) of the monitor on a calling queue.
     1541
     1542An important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads?
     1543If 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).
     1544\CFA scheduling does \emph{not} have barging, which simplifies synchronization among threads in the monitor.
     1545Supporting 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.
     1546
     1547Indeed, 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.
     1548
     1549First, here is a simple example of internal scheduling:
     1550
     1551\begin{cfa}
     1552monitor A {
     1553        condition e;
     1554}
     1555
     1556void foo(A& mutex a1, A& mutex a2) {
     1557        ...
     1558        // Wait for cooperation from bar()
     1559        wait(a1.e);
     1560        ...
     1561}
     1562
     1563void bar(A& mutex a1, A& mutex a2) {
     1564        // Provide cooperation for foo()
     1565        ...
     1566        // Unblock foo
     1567        signal(a1.e);
     1568}
     1569\end{cfa}
     1570
     1571% ======================================================================
     1572% ======================================================================
     1573\subsection{Internal Scheduling - Multi-Monitor}
     1574% ======================================================================
     1575% ======================================================================
     1576It is easy to understand the problem of multi-monitor scheduling using a series of pseudo-code examples.
     1577Note 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.
     1578Indeed, @wait@ statements always use the implicit condition variable as parameters and explicitly name the monitors (A and B) associated with the condition.
     1579Note 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.
     1580The example below shows the simple case of having two threads (one for each column) and a single monitor A.
     1581
     1582\begin{multicols}{2}
     1583thread 1
     1584\begin{cfa}
     1585acquire A
     1586        wait A
     1587release A
     1588\end{cfa}
     1589
     1590\columnbreak
     1591
     1592thread 2
     1593\begin{cfa}
     1594acquire A
     1595        signal A
     1596release A
     1597\end{cfa}
     1598\end{multicols}
     1599One thread acquires before waiting (atomically blocking and releasing A) and the other acquires before signalling.
     1600It is important to note here that both @wait@ and @signal@ must be called with the proper monitor(s) already acquired.
     1601This semantic is a logical requirement for barging prevention.
     1602
     1603A direct extension of the previous example is a bulk acquire version:
     1604\begin{multicols}{2}
     1605\begin{cfa}
     1606acquire A & B
     1607        wait A & B
     1608release A & B
     1609\end{cfa}
     1610\columnbreak
     1611\begin{cfa}
     1612acquire A & B
     1613        signal A & B
     1614release A & B
     1615\end{cfa}
     1616\end{multicols}
     1617\noindent This version uses bulk acquire (denoted using the {\sf\&} symbol), but the presence of multiple monitors does not add a particularly new meaning.
     1618Synchronization happens between the two threads in exactly the same way and order.
     1619The only difference is that mutual exclusion covers a group of monitors.
     1620On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate.
     1621
     1622While 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.
     1623For 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.
     1624For example, the following cfa-code runs into the nested-monitor problem:
     1625\begin{multicols}{2}
     1626\begin{cfa}
     1627acquire A
     1628        acquire B
     1629                wait B
     1630        release B
     1631release A
     1632\end{cfa}
     1633
     1634\columnbreak
     1635
     1636\begin{cfa}
     1637acquire A
     1638        acquire B
     1639                signal B
     1640        release B
     1641release A
     1642\end{cfa}
     1643\end{multicols}
     1644\noindent The @wait@ only releases monitor @B@ so the signalling thread cannot acquire monitor @A@ to get to the @signal@.
     1645Attempting 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@.
     1646
     1647However, for monitors as for locks, it is possible to write a program using nesting without encountering any problems if nesting is done correctly.
     1648For 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}.
     1649
     1650\begin{multicols}{2}
     1651\begin{cfa}
     1652acquire A
     1653        acquire B
     1654                wait B
     1655        release B
     1656release A
     1657\end{cfa}
     1658
     1659\columnbreak
     1660
     1661\begin{cfa}
     1662
     1663acquire B
     1664        signal B
     1665release B
     1666
     1667\end{cfa}
     1668\end{multicols}
     1669
     1670\noindent However, this simple refactoring may not be possible, forcing more complex restructuring.
     1671
     1672% ======================================================================
     1673% ======================================================================
     1674\subsection{Internal Scheduling - In Depth}
     1675% ======================================================================
     1676% ======================================================================
     1677
     1678A larger example is presented to show complex issues for bulk acquire and its implementation options are analyzed.
     1679Figure~\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}.
     1680For 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.
    15621681
    15631682\begin{figure}
    1564 \centering
    1565 \newbox\myboxA
    1566 \begin{lrbox}{\myboxA}
    1567 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1568 enum { CCodes = 20 };
    1569 monitor DS {
    1570         int GirlPhNo, BoyPhNo;
    1571         condition Girls[CCodes], Boys[CCodes];
    1572         condition exchange;
    1573 };
    1574 int girl( DS & mutex ds, int phNo, int ccode ) {
    1575         if ( is_empty( Boys[ccode] ) ) {
    1576                 wait( Girls[ccode] );
    1577                 GirlPhNo = phNo;
    1578                 exchange.signal();
    1579         } else {
    1580                 GirlPhNo = phNo;
    1581                 signal( Boys[ccode] );
    1582                 exchange.wait();
    1583         } // if
    1584         return BoyPhNo;
    1585 }
    1586 int boy( DS & mutex ds, int phNo, int ccode ) {
    1587         // as above with boy/girl interchanged
    1588 }
    1589 \end{cfa}
    1590 \end{lrbox}
    1591 
    1592 \newbox\myboxB
    1593 \begin{lrbox}{\myboxB}
    1594 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1595 
    1596 monitor DS {
    1597         int GirlPhNo, BoyPhNo;
    1598         condition Girls[CCodes], Boys[CCodes];
    1599 
    1600 };
    1601 int girl( DS & mutex ds, int phNo, int ccode ) {
    1602         if ( is_empty( Boys[ccode] ) ) { // no compatible
    1603                 wait( Girls[ccode] ); // wait for boy
    1604                 GirlPhNo = phNo; // make phone number available
    1605 
    1606         } else {
    1607                 GirlPhNo = phNo; // make phone number available
    1608                 signal_block( Boys[ccode] ); // restart boy
    1609 
    1610         } // if
    1611         return BoyPhNo;
    1612 }
    1613 int boy( DS & mutex ds, int phNo, int ccode ) {
    1614         // as above with boy/girl interchanged
    1615 }
    1616 \end{cfa}
    1617 \end{lrbox}
    1618 
    1619 \subfloat[\lstinline@signal@]{\label{f:DatingSignal}\usebox\myboxA}
    1620 \qquad
    1621 \subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB}
    1622 \caption{Dating service. }
    1623 \label{f:DatingService}
     1683\begin{multicols}{2}
     1684Waiting thread
     1685\begin{cfa}[numbers=left]
     1686acquire A
     1687        // Code Section 1
     1688        acquire A & B
     1689                // Code Section 2
     1690                wait A & B
     1691                // Code Section 3
     1692        release A & B
     1693        // Code Section 4
     1694release A
     1695\end{cfa}
     1696\columnbreak
     1697Signalling thread
     1698\begin{cfa}[numbers=left, firstnumber=10,escapechar=|]
     1699acquire A
     1700        // Code Section 5
     1701        acquire A & B
     1702                // Code Section 6
     1703                |\label{line:signal1}|signal A & B
     1704                // Code Section 7
     1705        |\label{line:releaseFirst}|release A & B
     1706        // Code Section 8
     1707|\label{line:lastRelease}|release A
     1708\end{cfa}
     1709\end{multicols}
     1710\begin{cfa}[caption={Internal scheduling with bulk acquire},label={f:int-bulk-cfa}]
     1711\end{cfa}
     1712\begin{center}
     1713\begin{cfa}[xleftmargin=.4\textwidth]
     1714monitor A a;
     1715monitor B b;
     1716condition c;
     1717\end{cfa}
     1718\end{center}
     1719\begin{multicols}{2}
     1720Waiting thread
     1721\begin{cfa}
     1722mutex(a) {
     1723        // Code Section 1
     1724        mutex(a, b) {
     1725                // Code Section 2
     1726                wait(c);
     1727                // Code Section 3
     1728        }
     1729        // Code Section 4
     1730}
     1731\end{cfa}
     1732\columnbreak
     1733Signalling thread
     1734\begin{cfa}
     1735mutex(a) {
     1736        // Code Section 5
     1737        mutex(a, b) {
     1738                // Code Section 6
     1739                signal(c);
     1740                // Code Section 7
     1741        }
     1742        // Code Section 8
     1743}
     1744\end{cfa}
     1745\end{multicols}
     1746\begin{cfa}[caption={Equivalent \CFA code for listing \ref{f:int-bulk-cfa}},label={f:int-bulk-cfa}]
     1747\end{cfa}
     1748\begin{multicols}{2}
     1749Waiter
     1750\begin{cfa}[numbers=left]
     1751acquire A
     1752        acquire A & B
     1753                wait A & B
     1754        release A & B
     1755release A
     1756\end{cfa}
     1757
     1758\columnbreak
     1759
     1760Signaller
     1761\begin{cfa}[numbers=left, firstnumber=6,escapechar=|]
     1762acquire A
     1763        acquire A & B
     1764                signal A & B
     1765        release A & B
     1766        |\label{line:secret}|// Secretly keep B here
     1767release A
     1768// Wakeup waiter and transfer A & B
     1769\end{cfa}
     1770\end{multicols}
     1771\begin{cfa}[caption={Figure~\ref{f:int-bulk-cfa}, with delayed signalling comments},label={f:int-secret}]
     1772\end{cfa}
    16241773\end{figure}
    16251774
    1626 Both internal and external scheduling extend to multiple monitors in a natural way.
    1627 \begin{cquote}
    1628 \begin{tabular}{@{}l@{\hspace{3\parindentlnth}}l@{}}
    1629 \begin{cfa}
    1630 monitor M { `condition e`; ... };
    1631 void foo( M & mutex m1, M & mutex m2 ) {
    1632         ... wait( `e` ); ...   // wait( e, m1, m2 )
    1633         ... wait( `e, m1` ); ...
    1634         ... wait( `e, m2` ); ...
    1635 }
    1636 \end{cfa}
    1637 &
    1638 \begin{cfa}
    1639 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 );
    1640 void rtn$\(_2\)$( M & mutex m1 );
    1641 void bar( M & mutex m1, M & mutex m2 ) {
    1642         ... waitfor( `rtn` ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\), m1, m2 )}$
    1643         ... waitfor( `rtn, m1` ); ... // $\LstCommentStyle{waitfor( rtn\(_2\), m1 )}$
    1644 }
    1645 \end{cfa}
    1646 \end{tabular}
    1647 \end{cquote}
    1648 For @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 )@.
    1649 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
    1650 Wait statically verifies the released monitors are the acquired mutex-parameters so unconditional release is safe.
    1651 Finally, a signaller,
    1652 \begin{cfa}
    1653 void baz( M & mutex m1, M & mutex m2 ) {
    1654         ... signal( e ); ...
    1655 }
    1656 \end{cfa}
    1657 must have acquired monitor locks that are greater than or equal to the number of locks for the waiting thread signalled from the front of the condition queue.
    1658 In general, the signaller does not know the order of waiting threads, so in general, it must acquire the maximum number of mutex locks for the worst-case waiting thread.
    1659 
    1660 Similarly, 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 )@.
    1661 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@.
    1662 Waitfor statically verifies the released monitors are the same as the acquired mutex-parameters of the given routine or routine pointer.
    1663 To statically verify the released monitors match with the accepted routine's mutex parameters, the routine (pointer) prototype must be accessible.
    1664 
    1665 Given the ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock.
    1666 \begin{cfa}
    1667 void foo( M & mutex m1, M & mutex m2 ) {
    1668         ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired )}$
    1669 void baz( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2 )}$
    1670         ... signal( `e` ); ...
    1671 \end{cfa}
    1672 The @wait@ only releases @m1@ so the signalling thread cannot acquire both @m1@ and @m2@ to  enter @baz@ to get to the @signal@.
    1673 While deadlock issues can occur with multiple/nesting acquisition, this issue results from the fact that locks, and by extension monitors, are not perfectly composable.
    1674 
    1675 Finally, an important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads?
    1676 If 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).
    1677 \begin{quote}
    1678 However, 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.
    1679 It 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}
    1680 \end{quote}
    1681 \CFA scheduling \emph{precludes} barging, which simplifies synchronization among threads in the monitor and increases correctness.
    1682 For example, there are no loops in either bounded buffer solution in Figure~\ref{f:GenericBoundedBuffer}.
    1683 Supporting 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.
    1684 
    1685 
    1686 \subsection{Barging Prevention}
    1687 
    1688 Figure~\ref{f:BargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signalling semantics.
    1689 The complexity begins at the end of the inner @mutex@ statement, where the semantics of internal scheduling need to be extended for multiple monitors.
    1690 The problem is that bulk acquire is used in the inner @mutex@ statement where one of the monitors is already acquired.
    1691 When the signalling thread reaches the end of the inner @mutex@ statement, it should transfer ownership of @m1@ and @m2@ to the waiting threads to prevent barging into the outer @mutex@ statement by another thread.
    1692 However, both the signalling and waiting thread W1 still need monitor @m1@.
    1693 
    1694 \begin{figure}
    1695 \newbox\myboxA
    1696 \begin{lrbox}{\myboxA}
    1697 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1698 monitor M m1, m2;
    1699 condition c;
    1700 mutex( m1 ) { // $\LstCommentStyle{\color{red}outer}$
    1701         ...
    1702         mutex( m1, m2 ) { // $\LstCommentStyle{\color{red}inner}$
    1703                 ... `signal( c )`; ...
    1704                 // m1, m2 acquired
    1705         } // $\LstCommentStyle{\color{red}release m2}$
    1706         // m1 acquired
    1707 } // release m1
    1708 \end{cfa}
    1709 \end{lrbox}
    1710 
    1711 \newbox\myboxB
    1712 \begin{lrbox}{\myboxB}
    1713 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1714 
    1715 
    1716 mutex( m1 ) {
    1717         ...
    1718         mutex( m1, m2 ) {
    1719                 ... `wait( c )`; // block and release m1, m2
    1720                 // m1, m2 acquired
    1721         } // $\LstCommentStyle{\color{red}release m2}$
    1722         // m1 acquired
    1723 } // release m1
    1724 \end{cfa}
    1725 \end{lrbox}
    1726 
    1727 \newbox\myboxC
    1728 \begin{lrbox}{\myboxC}
    1729 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1730 
    1731 
    1732 mutex( m2 ) {
    1733         ... `wait( c )`; ...
    1734         // m2 acquired
    1735 } // $\LstCommentStyle{\color{red}release m2}$
    1736 
    1737 
    1738 
    1739 
    1740 \end{cfa}
    1741 \end{lrbox}
    1742 
    1743 \begin{cquote}
    1744 \subfloat[Signalling Thread]{\label{f:SignallingThread}\usebox\myboxA}
    1745 \hspace{2\parindentlnth}
    1746 \subfloat[Waiting Thread (W1)]{\label{f:WaitingThread}\usebox\myboxB}
    1747 \hspace{2\parindentlnth}
    1748 \subfloat[Waiting Thread (W2)]{\label{f:OtherWaitingThread}\usebox\myboxC}
    1749 \end{cquote}
    1750 \caption{Barging Prevention}
    1751 \label{f:BargingPrevention}
    1752 \end{figure}
    1753 
    1754 One scheduling solution is for the signaller to keep ownership of all locks until the last lock is ready to be transferred, because this semantics fits most closely to the behaviour of single-monitor scheduling.
    1755 However, Figure~\ref{f:OtherWaitingThread} shows this solution is complex depending on other waiters, resulting is choices when the signaller finishes the inner mutex-statement.
    1756 The singaller can retain @m2@ until completion of the outer mutex statement and pass the locks to waiter W1, or it can pass @m2@ to waiter W2 after completing the inner mutex-statement, while continuing to hold @m1@.
    1757 In the latter case, waiter W2 must eventually pass @m2@ to waiter W1, which is complex because W2 may have waited before W1 so it is unaware of W1.
    1758 Furthermore, there is an execution sequence where the signaller always finds waiter W2, and hence, waiter W1 starves.
    1759 
    1760 While a number of approaches were examined~\cite[\S~4.3]{Delisle18}, the solution chosen for \CFA is a novel techique called \newterm{partial signalling}.
    1761 Signalled threads are moved to an urgent queue and the waiter at the front defines the set of monitors necessary for it to unblock.
    1762 Partial signalling transfers ownership of monitors to the front waiter.
    1763 When the signaller thread exits or waits in the monitor the front waiter is unblocked if all its monitors are released.
    1764 This solution has the benefit that complexity is encapsulated into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met.
    1765 
    1766 \begin{comment}
     1775The 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.
     1776The 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.
     1777When 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.
     1778This 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@.
     1779There are three options:
     1780
     1781\subsubsection{Delaying Signals}
     1782The 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.
     1783It 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.
     1784This solution has the main benefit of transferring ownership of groups of monitors, which simplifies the semantics from multiple objects to a single group of objects, effectively making the existing single-monitor semantic viable by simply changing monitors to monitor groups.
     1785This solution releases the monitors once every monitor in a group can be released.
     1786However, since some monitors are never released (\eg the monitor of a thread), this interpretation means a group might never be released.
     1787A more interesting interpretation is to transfer the group until all its monitors are released, which means the group is not passed further and a thread can retain its locks.
     1788
     1789However, listing \ref{f:int-secret} shows this solution can become much more complicated depending on what is executed while secretly holding B at line \ref{line:secret}, while avoiding the need to transfer ownership of a subset of the condition monitors.
    17671790Figure~\ref{f:dependency} shows a slightly different example where a third thread is waiting on monitor @A@, using a different condition variable.
    17681791Because the third thread is signalled when secretly holding @B@, the goal  becomes unreachable.
     
    17781801In 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.
    17791802
    1780 
    17811803\subsubsection{Dependency graphs}
     1804
    17821805
    17831806\begin{figure}
     
    18581881
    18591882\subsubsection{Partial Signalling} \label{partial-sig}
    1860 \end{comment}
    1861 
    1862 
     1883Finally, the solution that is chosen for \CFA is to use partial signalling.
     1884Again 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@.
     1885Only when it reaches line \ref{line:lastRelease} does it actually wake up the waiting thread.
     1886This solution has the benefit that complexity is encapsulated into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met.
     1887This solution has a much simpler implementation than a dependency graph solving algorithms, which is why it was chosen.
     1888Furthermore, after being fully implemented, this solution does not appear to have any significant downsides.
     1889
     1890Using partial signalling, listing \ref{f:dependency} can be solved easily:
     1891\begin{itemize}
     1892        \item When thread $\gamma$ reaches line \ref{line:release-ab} it transfers monitor @B@ to thread $\alpha$ and continues to hold monitor @A@.
     1893        \item When thread $\gamma$ reaches line \ref{line:release-a}  it transfers monitor @A@ to thread $\beta$  and wakes it up.
     1894        \item When thread $\beta$  reaches line \ref{line:release-aa} it transfers monitor @A@ to thread $\alpha$ and wakes it up.
     1895\end{itemize}
     1896
     1897% ======================================================================
     1898% ======================================================================
     1899\subsection{Signalling: Now or Later}
     1900% ======================================================================
     1901% ======================================================================
     1902\begin{table}
     1903\begin{tabular}{|c|c|}
     1904@signal@ & @signal_block@ \\
     1905\hline
     1906\begin{cfa}[tabsize=3]
     1907monitor DatingService {
     1908        // compatibility codes
     1909        enum{ CCodes = 20 };
     1910
     1911        int girlPhoneNo
     1912        int boyPhoneNo;
     1913};
     1914
     1915condition girls[CCodes];
     1916condition boys [CCodes];
     1917condition exchange;
     1918
     1919int girl(int phoneNo, int cfa) {
     1920        // no compatible boy ?
     1921        if(empty(boys[cfa])) {
     1922                wait(girls[cfa]);               // wait for boy
     1923                girlPhoneNo = phoneNo;          // make phone number available
     1924                signal(exchange);               // wake boy from chair
     1925        } else {
     1926                girlPhoneNo = phoneNo;          // make phone number available
     1927                signal(boys[cfa]);              // wake boy
     1928                wait(exchange);         // sit in chair
     1929        }
     1930        return boyPhoneNo;
     1931}
     1932int boy(int phoneNo, int cfa) {
     1933        // same as above
     1934        // with boy/girl interchanged
     1935}
     1936\end{cfa}&\begin{cfa}[tabsize=3]
     1937monitor DatingService {
     1938
     1939        enum{ CCodes = 20 };    // compatibility codes
     1940
     1941        int girlPhoneNo;
     1942        int boyPhoneNo;
     1943};
     1944
     1945condition girls[CCodes];
     1946condition boys [CCodes];
     1947// exchange is not needed
     1948
     1949int girl(int phoneNo, int cfa) {
     1950        // no compatible boy ?
     1951        if(empty(boys[cfa])) {
     1952                wait(girls[cfa]);               // wait for boy
     1953                girlPhoneNo = phoneNo;          // make phone number available
     1954                signal(exchange);               // wake boy from chair
     1955        } else {
     1956                girlPhoneNo = phoneNo;          // make phone number available
     1957                signal_block(boys[cfa]);                // wake boy
     1958
     1959                // second handshake unnecessary
     1960
     1961        }
     1962        return boyPhoneNo;
     1963}
     1964
     1965int boy(int phoneNo, int cfa) {
     1966        // same as above
     1967        // with boy/girl interchanged
     1968}
     1969\end{cfa}
     1970\end{tabular}
     1971\caption{Dating service example using \protect\lstinline|signal| and \protect\lstinline|signal_block|. }
     1972\label{tbl:datingservice}
     1973\end{table}
     1974An important note is that, until now, signalling a monitor was a delayed operation.
     1975The ownership of the monitor is transferred only when the monitor would have otherwise been released, not at the point of the @signal@ statement.
     1976However, in some cases, it may be more convenient for users to immediately transfer ownership to the thread that is waiting for cooperation, which is achieved using the @signal_block@ routine.
     1977
     1978The example in table \ref{tbl:datingservice} highlights the difference in behaviour.
     1979As mentioned, @signal@ only transfers ownership once the current critical section exits; this behaviour requires additional synchronization when a two-way handshake is needed.
     1980To avoid this explicit synchronization, the @condition@ type offers the @signal_block@ routine, which handles the two-way handshake as shown in the example.
     1981This feature removes the need for a second condition variables and simplifies programming.
     1982Like every other monitor semantic, @signal_block@ uses barging prevention, which means mutual-exclusion is baton-passed both on the front end and the back end of the call to @signal_block@, meaning no other thread can acquire the monitor either before or after the call.
     1983
     1984% ======================================================================
     1985% ======================================================================
    18631986\section{External scheduling} \label{extsched}
    1864 
     1987% ======================================================================
     1988% ======================================================================
    18651989An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}).
    1866 
    1867 \begin{comment}
    18681990\begin{table}
    18691991\begin{tabular}{|c|c|c|}
     
    19292051\label{tbl:sched}
    19302052\end{table}
    1931 \end{comment}
    1932 
    19332053This method is more constrained and explicit, which helps users reduce the non-deterministic nature of concurrency.
    19342054Indeed, as the following examples demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occurring.
  • doc/proposals/user_conversions.md

    r61accc5 rc2b10fa  
    55There is also a set of _explicit_ conversions that are only allowed through a
    66cast expression.
    7 I propose that safe, unsafe, and explicit (cast) conversions be expressed as
    8 constructor variants.
     7Based on Glen's notes on conversions [1], I propose that safe and unsafe
     8conversions be expressed as constructor variants, though I make explicit
     9(cast) conversions a constructor variant as well rather than a dedicated
     10operator.
    911Throughout this article, I will use the following operator names for
    1012constructors and conversion functions from `From` to `To`:
    1113
    12         void ?{} ( To&, To );            // copy constructor
    13         void ?{} ( To&, From );          // explicit constructor
    14         void ?{explicit} ( To&, From );  // explicit cast conversion
    15         void ?{safe} ( To&, From );      // implicit safe conversion
    16         void ?{unsafe} ( To&, From );    // implicit unsafe conversion
    17 
    18 It has been suggested that all constructors would define unsafe implicit
     14        void ?{} ( To*, To );            // copy constructor
     15        void ?{} ( To*, From );          // explicit constructor
     16        void ?{explicit} ( To*, From );  // explicit cast conversion
     17        void ?{safe} ( To*, From );      // implicit safe conversion
     18        void ?{unsafe} ( To*, From );    // implicit unsafe conversion
     19
     20[1] http://plg.uwaterloo.ca/~cforall/Conversions/index.html
     21
     22Glen's design made no distinction between constructors and unsafe implicit
    1923conversions; this is elegant, but interacts poorly with tuples.
    2024Essentially, without making this distinction, a constructor like the following
     
    2226multiplying the space of possible interpretations of all functions:
    2327
    24         void ?{}( Coord& this, int x, int y );
     28        void ?{}( Coord *this, int x, int y );
    2529
    2630That said, it would certainly be possible to make a multiple-argument implicit
     
    2832used infrequently:
    2933
    30         void ?{unsafe}( Coord& this, int x, int y );
     34        void ?{unsafe}( Coord *this, int x, int y );
    3135
    3236An alternate possibility would be to only count two-arg constructors
    33 `void ?{} ( To&, From )` as unsafe conversions; under this semantics, safe and
     37`void ?{} ( To*, From )` as unsafe conversions; under this semantics, safe and
    3438explicit conversions should also have a compiler-enforced restriction to
    3539ensure that they are two-arg functions (this restriction may be valuable
     
    3943is convertable to `To`.
    4044If user-defined conversions are not added to the language,
    41 `void ?{} ( To&, From )` may be a suitable representation, relying on
     45`void ?{} ( To*, From )` may be a suitable representation, relying on
    4246conversions on the argument types to account for transitivity.
    43 Since `To&` should be an exact match on `To`, this should put all the implicit
    44 conversions on the RHS.
    45 On the other hand, under some models (like [1]), implicit conversions are not
    46 allowed in assertion parameters, so another assertion syntax specific to
    47 conversions may be required, e.g. `From -> To`.
    48 It has also been suggested that, for programmer control, no implicit
    49 conversions (except, possibly, for polymorphic specialization) should be
    50 allowed in resolution of cast operators.
    51 
    52 [1] ../working/assertion_resolution.md
     47On the other hand, `To*` should perhaps match its target type exactly, so
     48another assertion syntax specific to conversions may be required, e.g.
     49`From -> To`.
    5350
    5451### Constructor Idiom ###
     
    5653that we can use the full range of Cforall features for conversions, including
    5754polymorphism.
    58 In an earlier version of this proposal, Glen Ditchfield defines a
    59 _constructor idiom_ that can be used to create chains of safe conversions
    60 without duplicating code; given a type `Safe` which members of another type
    61 `From` can be directly converted to, the constructor idiom allows us to write
    62 a conversion for any type `To` which `Safe` converts to:
    63 
    64         forall(otype To | { void ?{safe}( To&, Safe ) })
    65         void ?{safe}( To& this, From that ) {
     55Glen [1] defines a _constructor idiom_ that can be used to create chains of
     56safe conversions without duplicating code; given a type `Safe` which members
     57of another type `From` can be directly converted to, the constructor idiom
     58allows us to write a conversion for any type `To` which `Safe` converts to:
     59
     60        forall(otype To | { void ?{safe}( To*, Safe ) })
     61        void ?{safe}( To *this, From that ) {
    6662                Safe tmp = /* some expression involving that */;
    67                 this{ tmp }; // initialize from assertion parameter
     63                *this = tmp; // uses assertion parameter
    6864        }
    6965
     
    7167unsafe conversions.
    7268
    73 Glen's original suggestion said the copy constructor for `To` should also be
    74 accepted as a resolution for `void ?{safe}( To&, Safe )` (`Safe` == `To`),
    75 allowing this same code to be used for the single-step conversion as well.
    76 This proposal does come at the cost of an extra copy initialization of the
    77 target value, though.
    78 
    79 Contrariwise, if a monomorphic conversion from `From` to `Safe` is written,
    80 e.g:
    81 
    82         void ?{safe}( Safe& this, From that ) {
    83                 this{ /* some parameters involving that */ };
    84         }
    85 
    86 Then the code for a transitive conversion from `From` to any `To` type
    87 convertable from `Safe` is written:
    88 
    89         forall(otype To | { void ?{safe}( To&, Safe ) })
    90         void ?{safe}( To& this, From that ) {
    91                 Safe tmp = that;  // uses monomorphic conversion
    92                 this{ tmp };      // initialize from assertion parameter
    93         }
    94 
    95 Given the entirely-boilerplate nature of this code, but negative performance
    96 implications of the unmodified constructor idiom, it might be fruitful to have
    97 transitive and single step conversion operators, and let CFA build the
    98 transitive conversions; some possible names:
    99 
    100         void ?{safe}  (To&, From);    void ?{final safe} (To&, From);  // single-step
    101         void ?{safe*} (To&, From);    void ?{safe}       (To&, From);  // transitive
    102 
    10369What selective non-use of the constructor idiom gives us is the ability to
    10470define a conversion that may only be the *last* conversion in a chain of such.
    105 One use for this is to solve the problem that `explicit` conversions were
    106 added to C++ for, that of conversions to `bool` chaining to become conversions
    107 to any arithmetic type.
    108 Another use is to unambiguously represent the full hierarchy of implicit
    109 conversions in C by making sign conversions non-transitive, allowing the
    110 compiler to resolve e.g. `int -> unsigned long` as
    111 `int -> long -> unsigned long` over `int -> unsigned int -> unsigned long`.
    112 See [2] for more details.
    113 
    114 [2] ../working/glen_conversions/index.html#usual
     71Constructing a conversion graph able to unambiguously represent the full
     72hierarchy of implicit conversions in C is provably impossible using only
     73single-step conversions with no additional information (see Appendix A), but
     74this mechanism is sufficiently powerful (see [1], though the design there has
     75some minor bugs; the general idea is to use the constructor idiom to define
     76two chains of conversions, one among the signed integral types, another among
     77the unsigned, and to use monomorphic conversions to allow conversions between
     78signed and unsigned integer types).
    11579
    11680### Appendix A: Partial and Total Orders ###
     
    189153convert from `int` to `unsigned long`, so we just put in a direct conversion
    190154and make the compiler smart enough to figure out the costs" - this is the
    191 approach taken by the existing compiler, but given that in a user-defined
     155approach taken by the existing compipler, but given that in a user-defined
    192156conversion proposal the users can build an arbitrary graph of conversions,
    193157this case still needs to be handled.
     
    196160exists a chain of conversions from `a` to `b` (see Appendix A for description
    197161of preorders and related constructs).
    198 This preorder roughly corresponds to a more usual type-theoretic concept of
     162This preorder corresponds roughly to a more usual type-theoretic concept of
    199163subtyping ("if I can convert `a` to `b`, `a` is a more specific type than
    200164`b`"); however, since this graph is arbitrary, it may contain cycles, so if
     
    228192and so is considered to be the nearer type.
    229193By transitivity, then, the conversion from `X` to `Y2` should be cheaper than
    230 the conversion from `X` to `W`, but in this case the `Y2` and `W` are
     194the conversion from `X` to `W`, but in this case the `X` and `W` are
    231195incomparable by the conversion preorder, so the tie is broken by the shorter
    232196path from `X` to `W` in favour of `W`, contradicting the transitivity property
  • src/Common/SemanticError.cc

    r61accc5 rc2b10fa  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun  7 08:05:26 2018
    13 // Update Count     : 10
     12// Last Modified On : Wed May 16 15:01:20 2018
     13// Update Count     : 9
    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

    r61accc5 rc2b10fa  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun  7 12:08:55 2018
    13 // Update Count     : 1079
     12// Last Modified On : Wed Jun  6 15:57:50 2018
     13// Update Count     : 1076
    1414//
    1515
     
    545545                                        type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier
    546546                                } else {                                                                // not polymorphic
    547                                         type->aggregate.params = q->type->forall; // set forall qualifier
     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 );
    548550                                } // if
    549551                        } else {                                                                        // not polymorphic
  • src/Parser/TypedefTable.cc

    r61accc5 rc2b10fa  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun  7 13:17:56 2018
    13 // Update Count     : 192
     12// Last Modified On : Fri Jun  1 16:54:18 2018
     13// Update Count     : 155
    1414//
    1515
     
    1717#include "TypedefTable.h"
    1818#include <cassert>                                                                              // for assert
    19 #include <iostream>
    2019
    2120#if 0
     21#include <iostream>
    2222#define debugPrint( code ) code
    2323#else
     
    2727using namespace std;                                                                    // string, iostream
    2828
    29 debugPrint(
    30 static 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 
    4229TypedefTable::~TypedefTable() {
    4330        if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) {
    44                 cerr << "Error: cfa-cpp internal error, scope failure " << kindTable.currentScope() << endl;
    45                 abort();
     31                std::cerr << "scope failure " << kindTable.currentScope() << endl;
    4632        } // if
    4733} // TypedefTable::~TypedefTable
     
    5844} // TypedefTable::isKind
    5945
     46void 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
    6051// SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by
    6152// "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the
    6253// name is explicitly used.
    63 void 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 //        }
     54void TypedefTable::makeTypedef( const string & name ) {
    7155        if ( ! typedefTable.exists( name ) ) {
    72                 typedefTable.addToEnclosingScope( name, kind, "MTD" );
     56                typedefTable.addToEnclosingScope( name, TYPEDEFname, "MTD" );
    7357        } // if
    7458} // TypedefTable::makeTypedef
    7559
    76 void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
     60void TypedefTable::addToScope( const std::string & identifier, int kind, const char * locn __attribute__((unused)) ) {
    7761        auto scope = kindTable.currentScope();
    78         debugPrint( cerr << "Adding current at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl );
     62        debugPrint( cerr << "Adding at " << locn << " " << identifier << " as kind " << kind << " scope " << scope << endl );
    7963        auto ret = kindTable.insertAt( scope, identifier, kind );
    8064        if ( ! ret.second ) ret.first->second = kind;           // exists => update
    8165} // TypedefTable::addToScope
    8266
    83 void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
     67void TypedefTable::addToEnclosingScope( const std::string & identifier, int kind, const char * locn __attribute__((unused)) ) {
    8468        assert( kindTable.currentScope() >= 1 );
    8569        auto scope = kindTable.currentScope() - 1;
    86         debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl );
     70        debugPrint( cerr << "Adding+1 at " << locn << " " << identifier << " as kind " << kind << " scope " << scope << endl );
    8771        auto ret = kindTable.insertAt( scope, identifier, kind );
    8872        if ( ! ret.second ) ret.first->second = kind;           // exists => update
     
    10993                        debugPrint( cerr << endl << "[" << scope << "]" );
    11094                } // while
    111                 debugPrint( cerr << " " << (*i).first << ":" << kindName( (*i).second ) );
     95                debugPrint( cerr << " " << (*i).first << ":" << (*i).second );
    11296        } // for
    11397        while ( scope > 0 ) {
  • src/Parser/TypedefTable.h

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

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

    r61accc5 rc2b10fa  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun  7 10:07:12 2018
    13 // Update Count     : 3527
     12// Last Modified On : Wed Jun  6 14:53:38 2018
     13// Update Count     : 3522
    1414//
    1515
     
    18261826        | aggregate_key attribute_list_opt no_attr_identifier
    18271827                {
    1828                         typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname ); // create typedef
    1829                         //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
     1828                        typedefTable.makeTypedef( *$3 );                        // 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, forall ? TYPEGENname : TYPEDEFname ); // create typedef
    1837                         //if ( forall ) typedefTable.changeKind( *$3->type->symbolic.name, TYPEGENname ); // possibly update
     1836                        typedefTable.makeTypedef( *$3->type->symbolic.name ); // 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, forall ? TYPEGENname : TYPEDEFname );
    1851                         //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update
     1850                        typedefTable.makeTypedef( *$3 );
     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 
    32673266// ----end of grammar----
    32683267
  • src/libcfa/bits/locks.h

    r61accc5 rc2b10fa  
    126126
    127127        struct __bin_sem_t {
    128                 bool                    signaled;
    129                 pthread_mutex_t         lock;
    130                 pthread_cond_t          cond;
     128                int_fast8_t     counter;
     129                pthread_mutex_t lock;
     130                pthread_cond_t  cond;
    131131        };
    132132
    133133        static inline void ?{}(__bin_sem_t & this) with( this ) {
    134                 signaled = false;
     134                counter = 0;
    135135                pthread_mutex_init(&lock, NULL);
    136136                pthread_cond_init (&cond, NULL);
     
    145145                verify(__cfaabi_dbg_in_kernel());
    146146                pthread_mutex_lock(&lock);
    147                         if(!signaled) {   // this must be a loop, not if!
    148                                 pthread_cond_wait(&cond, &lock);
    149                         }
    150                         signaled = false;
     147                if(counter != 0) {   // this must be a loop, not if!
     148                        pthread_cond_wait(&cond, &lock);
     149                }
     150                counter = 1;
    151151                pthread_mutex_unlock(&lock);
    152152        }
     
    154154        static inline void post(__bin_sem_t & this) with( this ) {
    155155                verify(__cfaabi_dbg_in_kernel());
    156 
    157156                pthread_mutex_lock(&lock);
    158                         bool needs_signal = !signaled;
    159                         signaled = true;
     157                bool needs_signal = counter == 0;
     158                counter = 1;
    160159                pthread_mutex_unlock(&lock);
    161 
    162                 if (needs_signal)
     160                if (!needs_signal)
    163161                        pthread_cond_signal(&cond);
    164         }
     162                }
    165163#endif
  • src/libcfa/concurrency/kernel

    r61accc5 rc2b10fa  
    113113        pthread_t kernel_thread;
    114114
     115        // Termination
     116        // Set to true to notify the processor should terminate
     117        volatile bool do_terminate;
     118
     119        // Termination synchronisation
     120        semaphore terminated;
     121
    115122        // RunThread data
    116123        // Action to do after a thread is ran
     
    125132
    126133        // Idle lock
    127         __bin_sem_t idleLock;
    128 
    129         // Termination
    130         // Set to true to notify the processor should terminate
    131         volatile bool do_terminate;
    132 
    133         // Termination synchronisation
    134         semaphore terminated;
     134        sem_t idleLock;
     135        // __bin_sem_t idleLock;
    135136
    136137        // Link lists fields
  • src/libcfa/concurrency/kernel.c

    r61accc5 rc2b10fa  
    147147        runner.proc = &this;
    148148
    149         idleLock{};
     149        sem_init(&idleLock, 0, 0);
    150150
    151151        start( &this );
     
    155155        if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
    156156                __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
    157 
    158                 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
    159                 wake( &this );
    160 
     157                terminate(&this);
     158                verify( __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
     159                verify( kernelTLS.this_processor != &this);
    161160                P( terminated );
    162161                verify( kernelTLS.this_processor != &this);
    163         }
    164 
    165         pthread_join( kernel_thread, NULL );
     162                pthread_join( kernel_thread, NULL );
     163        }
     164
     165        sem_destroy(&idleLock);
    166166}
    167167
     
    295295}
    296296
     297// Handles spinning logic
     298// TODO : find some strategy to put cores to sleep after some time
     299void spin(processor * this, unsigned int * spin_count) {
     300        // (*spin_count)++;
     301        halt(this);
     302}
     303
    297304// KERNEL_ONLY
    298305// Context invoker for processors
     
    401408                unlock( ready_queue_lock );
    402409
    403                 if(was_empty) {
     410                if( was_empty ) {
    404411                        lock      (proc_list_lock __cfaabi_dbg_ctx2);
    405412                        if(idles) {
    406                                 wake_fast(idles.head);
     413                                wake(idles.head);
    407414                        }
    408415                        unlock    (proc_list_lock);
    409416                }
    410                 else if( struct processor * idle = idles.head ) {
    411                         wake_fast(idle);
    412                 }
    413 
    414417        }
    415418
     
    657660
    658661void halt(processor * this) with( *this ) {
    659         // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
     662        verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    660663
    661664        with( *cltr ) {
     
    668671        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
    669672
    670         wait( idleLock );
     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) );
     680        int __attribute__((unused)) ret = sem_wait(&idleLock);
     681        // verifyf(ret >= 0 || errno == EINTR, "Sem_wait returned %d (errno %d : %s\n", ret, errno, strerror(errno));
     682
     683        // wait( idleLock );
    671684
    672685        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
     
    678691                unlock    (proc_list_lock);
    679692        }
     693}
     694
     695void wake(processor * this) {
     696        __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
     697        int __attribute__((unused)) ret = sem_post(&this->idleLock);
     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 );
    680707}
    681708
  • src/libcfa/concurrency/kernel_private.h

    r61accc5 rc2b10fa  
    5858void finishRunning(processor * this);
    5959void halt(processor * this);
    60 
    61 static inline void wake_fast(processor * this) {
    62         __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
    63         post( this->idleLock );
    64 }
    65 
    66 static inline void wake(processor * this) {
    67         disable_interrupts();
    68         wake_fast(this);
    69         enable_interrupts( __cfaabi_dbg_ctx );
    70 }
     60void wake(processor * this);
     61void terminate(processor * this);
     62void spin(processor * this, unsigned int * spin_count);
    7163
    7264struct event_kernel_t {
     
    7668
    7769extern event_kernel_t * event_kernel;
     70
     71//extern thread_local coroutine_desc * volatile this_coroutine;
     72//extern thread_local thread_desc *    volatile this_thread;
     73//extern thread_local processor *      volatile this_processor;
     74
     75// extern volatile thread_local bool preemption_in_progress;
     76// extern volatile thread_local bool preemption_enabled;
     77// extern volatile thread_local unsigned short disable_preempt_count;
    7878
    7979struct __cfa_kernel_preemption_state_t {
  • src/libcfa/concurrency/preemption.c

    r61accc5 rc2b10fa  
    260260static void preempt( processor * this ) {
    261261        sigval_t value = { PREEMPT_NORMAL };
     262        pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
     263}
     264
     265// kill wrapper : signal a processor
     266void terminate(processor * this) {
     267        disable_interrupts();
     268        __atomic_store_n(&this->do_terminate, true, __ATOMIC_SEQ_CST);
     269        wake( this );
     270        sigval_t value = { PREEMPT_TERMINATE };
     271        enable_interrupts( __cfaabi_dbg_ctx );
    262272        pthread_sigqueue( this->kernel_thread, SIGUSR1, value );
    263273}
  • src/tests/preempt_longrun/Makefile.am

    r61accc5 rc2b10fa  
    3434
    3535clean-local:
    36         rm -f ${TESTS} core* out.log
     36        rm -f ${TESTS}
    3737
    3838% : %.c ${CC}
  • src/tests/preempt_longrun/Makefile.in

    r61accc5 rc2b10fa  
    878878
    879879clean-local:
    880         rm -f ${TESTS} core* out.log
     880        rm -f ${TESTS}
    881881
    882882% : %.c ${CC}
  • src/tests/preempt_longrun/enter.c

    r61accc5 rc2b10fa  
    1515
    1616monitor mon_t {};
     17
     18mon_t mon;
     19
    1720void foo( mon_t & mutex this ) {}
    1821
    19 mon_t mon;
    2022thread worker_t {};
     23
    2124void main( worker_t & this ) {
    2225        for( unsigned long i = 0; i < N; i++ ) {
     
    2528}
    2629
     30extern "C" {
     31static worker_t * workers;
     32}
     33
    2734int main(int argc, char * argv[] ) {
    2835        processor p;
    2936        {
    3037                worker_t w[7];
     38                workers = w;
    3139        }
    3240}
  • src/tests/preempt_longrun/processor.c

    r61accc5 rc2b10fa  
    1313}
    1414
    15 static const unsigned long N = 50_000ul;
     15static const unsigned long N = 5_000ul;
    1616
    1717int main(int argc, char* argv[]) {
    1818        processor * p[15];
    19         write(STDOUT_FILENO, "Preparing\n", sizeof("Preparing\n"));
     19        write(STDERR_FILENO, "Preparing\n", sizeof("Preparing\n"));
    2020        for ( int pi = 0; pi < 15; pi++ ) {
    2121                p[pi] = new();
    2222        }
    23         write(STDOUT_FILENO, "Starting\n", sizeof("Starting\n"));
     23        write(STDERR_FILENO, "Starting\n", sizeof("Starting\n"));
    2424        for ( int i = 0; i < N; i++) {
    2525                int pi = i % 15;
     
    2727                p[pi] = new();
    2828        }
    29         write(STDOUT_FILENO, "Stopping\n", sizeof("Stopping\n"));
     29        write(STDERR_FILENO, "Stopping\n", sizeof("Stopping\n"));
    3030        for ( int pi = 0; pi < 15; pi++ ) {
    3131                delete( p[pi] );
    3232        }
    33         write(STDOUT_FILENO, "Done\n", sizeof("Done\n"));
     33        write(STDERR_FILENO, "Done\n", sizeof("Done\n"));
    3434}
Note: See TracChangeset for help on using the changeset viewer.