Changeset beefc34c
- Timestamp:
- Jun 7, 2018, 6:12:11 PM (7 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, with_gc
- Children:
- 6eb131c, 7b28e4a
- Parents:
- 174845e (diff), 85b1deb (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. - Files:
-
- 1 added
- 2 deleted
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/concurrency/Paper.tex
r174845e rbeefc34c 56 56 \newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}} 57 57 \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}}}61 58 \newcommand{\uC}{$\mu$\CC} 62 \newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace} 63 \newcommand{\TODO}{{\Textbf{TODO}}} 59 \newcommand{\TODO}[1]{{\Textbf{#1}}} 64 60 65 61 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% … … 258 254 \section{Introduction} 259 255 260 This paper provides a minimal concurrency \newterm{A bstractProgram Interface} (API) that is simple, efficient and can be used to build other concurrency features.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. 261 257 While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master. 262 258 An easier approach for programmers is to support higher-level constructs as the basis of concurrency. … … 587 583 As such, library support for threading is far from widespread. 588 584 At the time of writing the paper, neither \protect\lstinline|gcc| nor \protect\lstinline|clang| support ``threads.h'' in their standard libraries.}. 589 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.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. 590 586 As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages. 591 587 Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay. … … 625 621 \newbox\myboxA 626 622 \begin{lrbox}{\myboxA} 627 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]623 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 628 624 `int f1, f2, state = 1;` // single global variables 629 625 int fib() { … … 642 638 } 643 639 } 644 \end{ lstlisting}640 \end{cfa} 645 641 \end{lrbox} 646 642 647 643 \newbox\myboxB 648 644 \begin{lrbox}{\myboxB} 649 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]645 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 650 646 #define FIB_INIT `{ 0, 1 }` 651 647 typedef struct { int f2, f1; } Fib; … … 664 660 } 665 661 } 666 \end{ lstlisting}662 \end{cfa} 667 663 \end{lrbox} 668 664 … … 677 673 \newbox\myboxA 678 674 \begin{lrbox}{\myboxA} 679 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]675 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 680 676 `coroutine` Fib { int fn; }; 681 677 void main( Fib & fib ) with( fib ) { … … 697 693 } 698 694 } 699 \end{ lstlisting}695 \end{cfa} 700 696 \end{lrbox} 701 697 \newbox\myboxB 702 698 \begin{lrbox}{\myboxB} 703 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]699 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 704 700 `coroutine` Fib { int ret; }; 705 701 void main( Fib & f ) with( fib ) { … … 721 717 722 718 723 \end{ lstlisting}719 \end{cfa} 724 720 \end{lrbox} 725 721 \subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA} … … 769 765 \newbox\myboxA 770 766 \begin{lrbox}{\myboxA} 771 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]767 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 772 768 `coroutine` Format { 773 769 char ch; // used for communication … … 801 797 } 802 798 } 803 \end{ lstlisting}799 \end{cfa} 804 800 \end{lrbox} 805 801 806 802 \newbox\myboxB 807 803 \begin{lrbox}{\myboxB} 808 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]804 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 809 805 struct Format { 810 806 char ch; … … 838 834 format( &fmt ); 839 835 } 840 \end{ lstlisting}836 \end{cfa} 841 837 \end{lrbox} 842 838 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA} … … 1044 1040 }; 1045 1041 \end{cfa} 1046 & {\Large $\Rightarrow$} & 1042 & 1043 {\Large $\Rightarrow$} 1044 & 1047 1045 \begin{tabular}{@{}ccc@{}} 1048 1046 \begin{cfa} … … 1445 1443 \label{s:InternalScheduling} 1446 1444 1447 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.1445 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:GenericBoundedBuffer}, may be full/empty so produce/consumer threads must block. 1448 1446 Leaving the monitor and trying again (busy waiting) is impractical for high-level programming. 1449 1447 Monitors 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. 1450 1448 The 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.1449 \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. 1452 1450 1453 1451 Figure~\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@. … … 1458 1456 \begin{enumerate} 1459 1457 \item 1460 The signalling thread leaves immediately, and the signalled thread continues.1458 The signalling thread returns immediately, and the signalled thread continues. 1461 1459 \item 1462 The signalling thread continues and the signalled thread is marked for urgent unblocking at subsequent scheduling points(exit/wait).1460 The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait). 1463 1461 \item 1464 The signalling thread blocks but is marked for urgrent unblocking a nd the signalled thread continues.1462 The signalling thread blocks but is marked for urgrent unblocking at the next scheduling point and the signalled thread continues. 1465 1463 \end{enumerate} 1466 1464 The first approach is too restrictive, as it precludes solving a reasonable class of problems (\eg dating service). 1467 1465 \CFA supports the next two semantics as both are useful. 1468 1466 Finally, while it is common to store a @condition@ as a field of the monitor, in \CFA, a @condition@ variable can be created/stored independently. 1467 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. 1469 1468 1470 1469 \begin{figure} … … 1472 1471 \newbox\myboxA 1473 1472 \begin{lrbox}{\myboxA} 1474 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]1473 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1475 1474 forall( otype T ) { // distribute forall 1476 1475 monitor Buffer { … … 1496 1495 } 1497 1496 } 1498 \end{ lstlisting}1497 \end{cfa} 1499 1498 \end{lrbox} 1500 1499 1501 1500 \newbox\myboxB 1502 1501 \begin{lrbox}{\myboxB} 1503 \begin{ lstlisting}[aboveskip=0pt,belowskip=0pt]1502 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1504 1503 forall( otype T ) { // distribute forall 1505 1504 monitor Buffer { … … 1525 1524 } 1526 1525 } 1527 \end{ lstlisting}1526 \end{cfa} 1528 1527 \end{lrbox} 1529 1528 … … 1532 1531 \subfloat[External Scheduling]{\label{f:BBExt}\usebox\myboxB} 1533 1532 \caption{Generic Bounded-Buffer} 1534 \label{f: BoundedBuffer}1533 \label{f:GenericBoundedBuffer} 1535 1534 \end{figure} 1536 1535 … … 1538 1537 External 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. 1539 1538 If 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 wait outside (externally) of the monitor on a calling queue. 1541 1542 An important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads? 1539 Threads 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. 1540 1541 Both internal and external scheduling extend to multiple monitors in a natural way. 1542 \begin{cfa} 1543 monitor M { `condition e`; ... }; 1544 void foo( M & mutex m1, M & mutex m2 ) { 1545 ... wait( `e` ); ... $\C{// wait( e, m1, m2 )}$ 1546 ... wait( `e, m1` ); ... 1547 ... wait( `e, m2` ); ... 1548 } 1549 1550 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 ); 1551 void rtn$\(_2\)$( M & mutex m1 ); 1552 void bar( M & mutex m1, M & mutex m2 ) { 1553 ... waitfor( `rtn` ); ... $\C{// waitfor( rtn\(_1\), m1, m2 )}$ 1554 ... waitfor( `rtn, m1` ); ... $\C{// waitfor( rtn\(_2\), m1 )}$ 1555 } 1556 \end{cfa} 1557 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 )@. 1558 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@. 1559 Wait statically verifies the released monitors are the acquired mutex-parameters so unconditional release is safe. 1560 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 )@. 1561 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@. 1562 Waitfor statically verifies the released monitors are the same as the acquired mutex-parameters of the given routine or routine pointer. 1563 To statically verify the released monitors match with the accepted routine's mutex parameters, the routine (pointer) prototype must be accessible. 1564 1565 Given the ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock. 1566 \begin{cfa} 1567 void foo( M & mutex m1, M & mutex m2 ) { 1568 ... wait( `e, m1` ); ... $\C{// release m1, keeping m2 acquired )}$ 1569 void baz( M & mutex m1, M & mutex m2 ) { $\C{// must acquire m1 and m2 )}$ 1570 ... signal( `e` ); ... 1571 \end{cfa} 1572 The @wait@ only releases @m1@ so the signalling thread cannot acquire both @m1@ and @m2@ to enter @baz@ to get to the @signal@. 1573 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. 1574 1575 Finally, an important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads? 1543 1576 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). 1544 \CFA scheduling does \emph{not} have barging, which simplifies synchronization among threads in the monitor. 1577 \begin{quote} 1578 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. 1579 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} 1580 \end{quote} 1581 \CFA scheduling \emph{precludes} barging, which simplifies synchronization among threads in the monitor and increases correctness. 1582 For example, there are no loops in either bounded buffer solution in Figure~\ref{f:GenericBoundedBuffer}. 1545 1583 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. 1546 1584 1547 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. 1548 1549 First, here is a simple example of internal scheduling: 1550 1551 \begin{cfa} 1552 monitor A { 1553 condition e; 1554 } 1555 1556 void foo(A& mutex a1, A& mutex a2) { 1585 1586 \subsection{Barging Prevention} 1587 1588 Figure~\ref{f:BargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signalling semantics. 1589 The complexity begins at the end of the inner @mutex@ statement, where the semantics of internal scheduling need to be extended for multiple monitors. 1590 The problem is that bulk acquire is used in the inner @mutex@ statement where one of the monitors is already acquired. 1591 When 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. 1592 However, both the signalling and signalled threads still need monitor @m1@. 1593 1594 \begin{figure} 1595 \newbox\myboxA 1596 \begin{lrbox}{\myboxA} 1597 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1598 monitor M m1, m2; 1599 condition c; 1600 mutex( m1 ) { 1557 1601 ... 1558 // Wait for cooperation from bar() 1559 wait(a1.e); 1602 mutex( m1, m2 ) { 1603 ... `wait( c )`; // block and release m1, m2 1604 // m1, m2 acquired 1605 } // $\LstCommentStyle{\color{red}release m2}$ 1606 // m1 acquired 1607 } // release m1 1608 \end{cfa} 1609 \end{lrbox} 1610 1611 \newbox\myboxB 1612 \begin{lrbox}{\myboxB} 1613 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1614 1615 1616 mutex( m1 ) { 1560 1617 ... 1561 } 1562 1563 void 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 % ====================================================================== 1576 It is easy to understand the problem of multi-monitor scheduling using a series of pseudo-code examples. 1577 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. 1578 Indeed, @wait@ statements always use the implicit condition variable as parameters and explicitly name the monitors (A and B) associated with the condition. 1579 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. 1580 The example below shows the simple case of having two threads (one for each column) and a single monitor A. 1581 1582 \begin{multicols}{2} 1583 thread 1 1584 \begin{cfa} 1585 acquire A 1586 wait A 1587 release A 1588 \end{cfa} 1589 1590 \columnbreak 1591 1592 thread 2 1593 \begin{cfa} 1594 acquire A 1595 signal A 1596 release A 1597 \end{cfa} 1598 \end{multicols} 1599 One thread acquires before waiting (atomically blocking and releasing A) and the other acquires before signalling. 1600 It is important to note here that both @wait@ and @signal@ must be called with the proper monitor(s) already acquired. 1601 This semantic is a logical requirement for barging prevention. 1602 1603 A direct extension of the previous example is a bulk acquire version: 1604 \begin{multicols}{2} 1605 \begin{cfa} 1606 acquire A & B 1607 wait A & B 1608 release A & B 1609 \end{cfa} 1610 \columnbreak 1611 \begin{cfa} 1612 acquire A & B 1613 signal A & B 1614 release 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. 1618 Synchronization happens between the two threads in exactly the same way and order. 1619 The only difference is that mutual exclusion covers a group of monitors. 1620 On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate. 1621 1622 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. 1623 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. 1624 For example, the following cfa-code runs into the nested-monitor problem: 1625 \begin{multicols}{2} 1626 \begin{cfa} 1627 acquire A 1628 acquire B 1629 wait B 1630 release B 1631 release A 1632 \end{cfa} 1633 1634 \columnbreak 1635 1636 \begin{cfa} 1637 acquire A 1638 acquire B 1639 signal B 1640 release B 1641 release 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@. 1645 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@. 1646 1647 However, for monitors as for locks, it is possible to write a program using nesting without encountering any problems if nesting is done correctly. 1648 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}. 1649 1650 \begin{multicols}{2} 1651 \begin{cfa} 1652 acquire A 1653 acquire B 1654 wait B 1655 release B 1656 release A 1657 \end{cfa} 1658 1659 \columnbreak 1660 1661 \begin{cfa} 1662 1663 acquire B 1664 signal B 1665 release 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 1678 A larger example is presented to show complex issues for bulk acquire and its implementation options are analyzed. 1679 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}. 1680 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. 1681 1682 \begin{figure} 1683 \begin{multicols}{2} 1684 Waiting thread 1685 \begin{cfa}[numbers=left] 1686 acquire 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 1694 release A 1695 \end{cfa} 1696 \columnbreak 1697 Signalling thread 1698 \begin{cfa}[numbers=left, firstnumber=10,escapechar=|] 1699 acquire 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] 1714 monitor A a; 1715 monitor B b; 1716 condition c; 1717 \end{cfa} 1718 \end{center} 1719 \begin{multicols}{2} 1720 Waiting thread 1721 \begin{cfa} 1722 mutex(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 1733 Signalling thread 1734 \begin{cfa} 1735 mutex(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} 1749 Waiter 1750 \begin{cfa}[numbers=left] 1751 acquire A 1752 acquire A & B 1753 wait A & B 1754 release A & B 1755 release A 1756 \end{cfa} 1757 1758 \columnbreak 1759 1760 Signaller 1761 \begin{cfa}[numbers=left, firstnumber=6,escapechar=|] 1762 acquire A 1763 acquire A & B 1764 signal A & B 1765 release A & B 1766 |\label{line:secret}|// Secretly keep B here 1767 release 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} 1618 mutex( m1, m2 ) { 1619 ... `signal( c )`; ... 1620 // m1, m2 acquired 1621 } // $\LstCommentStyle{\color{red}release m2}$ 1622 // m1 acquired 1623 } // release m1 1624 \end{cfa} 1625 \end{lrbox} 1626 1627 \newbox\myboxC 1628 \begin{lrbox}{\myboxC} 1629 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1630 1631 1632 mutex( m1 ) { 1633 ... `wait( c )`; ... 1634 // m1 acquired 1635 } // $\LstCommentStyle{\color{red}release m1}$ 1636 1637 1638 1639 1640 \end{cfa} 1641 \end{lrbox} 1642 1643 \begin{cquote} 1644 \subfloat[Waiting Thread]{\label{f:WaitingThread}\usebox\myboxA} 1645 \hspace{2\parindentlnth} 1646 \subfloat[Signalling Thread]{\label{f:SignallingThread}\usebox\myboxB} 1647 \hspace{2\parindentlnth} 1648 \subfloat[Other Waiting Thread]{\label{f:SignallingThread}\usebox\myboxC} 1649 \end{cquote} 1650 \caption{Barging Prevention} 1651 \label{f:BargingPrevention} 1773 1652 \end{figure} 1774 1653 1775 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.1776 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.1777 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.1778 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@.1779 There are three options:1780 1781 \subsubsection{Delaying Signals}1782 1654 The 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. 1783 1655 It 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. … … 1792 1664 Depending on the order of signals (listing \ref{f:dependency} line \ref{line:signal-ab} and \ref{line:signal-a}) two cases can happen: 1793 1665 1666 \begin{comment} 1794 1667 \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. 1795 1668 \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. … … 1801 1674 In 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. 1802 1675 1676 1803 1677 \subsubsection{Dependency graphs} 1804 1805 1678 1806 1679 \begin{figure} … … 1881 1754 1882 1755 \subsubsection{Partial Signalling} \label{partial-sig} 1756 \end{comment} 1757 1883 1758 Finally, the solution that is chosen for \CFA is to use partial signalling. 1884 1759 Again 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@. … … 1895 1770 \end{itemize} 1896 1771 1897 % ====================================================================== 1898 % ====================================================================== 1772 1899 1773 \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] 1907 monitor DatingService { 1908 // compatibility codes 1909 enum{ CCodes = 20 }; 1910 1911 int girlPhoneNo 1912 int boyPhoneNo; 1774 1775 \begin{figure} 1776 \centering 1777 \newbox\myboxA 1778 \begin{lrbox}{\myboxA} 1779 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1780 enum { CCodes = 20 }; 1781 monitor DS { 1782 int GirlPhNo, BoyPhNo; 1783 condition Girls[CCodes], Boys[CCodes]; 1784 condition exchange; 1913 1785 }; 1914 1915 condition girls[CCodes]; 1916 condition boys [CCodes]; 1917 condition exchange; 1918 1919 int 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 1786 int girl( DS & mutex ds, int phNo, int ccode ) { 1787 if ( is_empty( Boys[ccode] ) ) { 1788 wait( Girls[ccode] ); 1789 GirlPhNo = phNo; 1790 exchange.signal(); 1925 1791 } 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 } 1932 int boy(int phoneNo, int cfa) { 1933 // same as above 1934 // with boy/girl interchanged 1935 } 1936 \end{cfa}&\begin{cfa}[tabsize=3] 1937 monitor DatingService { 1938 1939 enum{ CCodes = 20 }; // compatibility codes 1940 1941 int girlPhoneNo; 1942 int boyPhoneNo; 1792 GirlPhNo = phNo; 1793 signal( Boys[ccode] ); 1794 exchange.wait(); 1795 } // if 1796 return BoyPhNo; 1797 } 1798 int boy( DS & mutex ds, int phNo, int ccode ) { 1799 // as above with boy/girl interchanged 1800 } 1801 \end{cfa} 1802 \end{lrbox} 1803 1804 \newbox\myboxB 1805 \begin{lrbox}{\myboxB} 1806 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 1807 1808 monitor DS { 1809 int GirlPhNo, BoyPhNo; 1810 condition Girls[CCodes], Boys[CCodes]; 1811 1943 1812 }; 1944 1945 condition girls[CCodes]; 1946 condition boys [CCodes]; 1947 // exchange is not needed 1948 1949 int 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 1813 int girl( DS & mutex ds, int phNo, int ccode ) { 1814 if ( is_empty( Boys[ccode] ) ) { // no compatible 1815 wait( Girls[ccode] ); // wait for boy 1816 GirlPhNo = phNo; // make phone number available 1817 1955 1818 } 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 1965 int 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} 1819 GirlPhNo = phNo; // make phone number available 1820 signal_block( Boys[ccode] ); // restart boy 1821 1822 } // if 1823 return BoyPhNo; 1824 } 1825 int boy( DS & mutex ds, int phNo, int ccode ) { 1826 // as above with boy/girl interchanged 1827 } 1828 \end{cfa} 1829 \end{lrbox} 1830 1831 \subfloat[\lstinline@signal@]{\label{f:DatingSignal}\usebox\myboxA} 1832 \qquad 1833 \subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB} 1834 \caption{Dating service. } 1835 \label{f:Dating service} 1836 \end{figure} 1837 1974 1838 An important note is that, until now, signalling a monitor was a delayed operation. 1975 1839 The ownership of the monitor is transferred only when the monitor would have otherwise been released, not at the point of the @signal@ statement. … … 1988 1852 % ====================================================================== 1989 1853 An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}). 1854 1855 \begin{comment} 1990 1856 \begin{table} 1991 1857 \begin{tabular}{|c|c|c|} … … 2051 1917 \label{tbl:sched} 2052 1918 \end{table} 1919 \end{comment} 1920 2053 1921 This method is more constrained and explicit, which helps users reduce the non-deterministic nature of concurrency. 2054 1922 Indeed, 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
r174845e rbeefc34c 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 16 15:01:20201813 // Update Count : 912 // Last Modified On : Thu Jun 7 08:05:26 2018 13 // Update Count : 10 14 14 // 15 15 … … 97 97 void SemanticError( CodeLocation location, std::string error ) { 98 98 SemanticErrorThrow = true; 99 throw SemanticErrorException( location, error);99 throw SemanticErrorException( location, error ); 100 100 } 101 101 -
src/Parser/DeclarationNode.cc
r174845e rbeefc34c 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue May 22 08:39:29201813 // Update Count : 107 412 // Last Modified On : Thu Jun 7 12:08:55 2018 13 // Update Count : 1079 14 14 // 15 15 … … 174 174 } 175 175 176 DeclarationNode * DeclarationNode::newFunction( string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {176 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) { 177 177 DeclarationNode * newnode = new DeclarationNode; 178 178 newnode->name = name; … … 245 245 } // DeclarationNode::newForall 246 246 247 DeclarationNode * DeclarationNode::newFromTypedef( string * name ) {247 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) { 248 248 DeclarationNode * newnode = new DeclarationNode; 249 249 newnode->type = new TypeData( TypeData::SymbolicInst ); … … 268 268 } // DeclarationNode::newAggregate 269 269 270 DeclarationNode * DeclarationNode::newEnum( string * name, DeclarationNode * constants, bool body ) {270 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body ) { 271 271 assert( name ); 272 272 DeclarationNode * newnode = new DeclarationNode; … … 278 278 } // DeclarationNode::newEnum 279 279 280 DeclarationNode * DeclarationNode::newEnumConstant( string * name, ExpressionNode * constant ) {280 DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) { 281 281 DeclarationNode * newnode = new DeclarationNode; 282 282 newnode->name = name; … … 285 285 } // DeclarationNode::newEnumConstant 286 286 287 DeclarationNode * DeclarationNode::newName( string * name ) {287 DeclarationNode * DeclarationNode::newName( const string * name ) { 288 288 DeclarationNode * newnode = new DeclarationNode; 289 289 newnode->name = name; … … 291 291 } // DeclarationNode::newName 292 292 293 DeclarationNode * DeclarationNode::newFromTypeGen( string * name, ExpressionNode * params ) {293 DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) { 294 294 DeclarationNode * newnode = new DeclarationNode; 295 295 newnode->type = new TypeData( TypeData::SymbolicInst ); … … 300 300 } // DeclarationNode::newFromTypeGen 301 301 302 DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, string * name ) {302 DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, const string * name ) { 303 303 DeclarationNode * newnode = new DeclarationNode; 304 304 newnode->type = nullptr; … … 331 331 } // DeclarationNode::newTraitUse 332 332 333 DeclarationNode * DeclarationNode::newTypeDecl( string * name, DeclarationNode * typeParams ) {333 DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) { 334 334 DeclarationNode * newnode = new DeclarationNode; 335 335 newnode->name = name; … … 406 406 } // DeclarationNode::newBuiltinType 407 407 408 DeclarationNode * DeclarationNode::newAttr( string * name, ExpressionNode * expr ) {408 DeclarationNode * DeclarationNode::newAttr( const string * name, ExpressionNode * expr ) { 409 409 DeclarationNode * newnode = new DeclarationNode; 410 410 newnode->type = nullptr; … … 415 415 } 416 416 417 DeclarationNode * DeclarationNode::newAttr( string * name, DeclarationNode * type ) {417 DeclarationNode * DeclarationNode::newAttr( const string * name, DeclarationNode * type ) { 418 418 DeclarationNode * newnode = new DeclarationNode; 419 419 newnode->type = nullptr; … … 424 424 } 425 425 426 DeclarationNode * DeclarationNode::newAttribute( string * name, ExpressionNode * expr ) {426 DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) { 427 427 DeclarationNode * newnode = new DeclarationNode; 428 428 newnode->type = nullptr; … … 545 545 type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier 546 546 } 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 550 548 } // if 551 549 } else { // not polymorphic -
src/Parser/ParseNode.h
r174845e rbeefc34c 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jun 4 22:21:04201813 // Update Count : 8 3212 // Last Modified On : Wed Jun 6 16:17:18 2018 13 // Update Count : 843 14 14 // 15 15 … … 77 77 78 78 ParseNode * next = nullptr; 79 std::string * name = nullptr;79 const std::string * name = nullptr; 80 80 CodeLocation location = yylloc; 81 81 }; // ParseNode … … 171 171 }; 172 172 173 Expression * build_constantInteger( std::string & str );174 Expression * build_constantFloat( std::string & str );175 Expression * build_constantChar( std::string & str );176 Expression * build_constantStr( std::string & str );173 Expression * build_constantInteger( std::string & str ); // these 4 routines modify the string 174 Expression * build_constantFloat( std::string & str ); 175 Expression * build_constantChar( std::string & str ); 176 Expression * build_constantStr( std::string & str ); 177 177 Expression * build_field_name_FLOATING_FRACTIONconstant( const std::string & str ); 178 178 Expression * build_field_name_FLOATING_DECIMALconstant( const std::string & str ); … … 230 230 static DeclarationNode * newBuiltinType( BuiltinType ); 231 231 static DeclarationNode * newForall( DeclarationNode * ); 232 static DeclarationNode * newFromTypedef( std::string * );233 static DeclarationNode * newFunction( std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );232 static DeclarationNode * newFromTypedef( const std::string * ); 233 static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ); 234 234 static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ); 235 static DeclarationNode * newEnum( std::string * name, DeclarationNode * constants, bool body );236 static DeclarationNode * newEnumConstant( std::string * name, ExpressionNode * constant );237 static DeclarationNode * newName( std::string * );238 static DeclarationNode * newFromTypeGen( std::string *, ExpressionNode * params );239 static DeclarationNode * newTypeParam( TypeClass, std::string * );235 static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body ); 236 static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant ); 237 static DeclarationNode * newName( const std::string * ); 238 static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params ); 239 static DeclarationNode * newTypeParam( TypeClass, const std::string * ); 240 240 static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts ); 241 241 static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params ); 242 static DeclarationNode * newTypeDecl( std::string * name, DeclarationNode * typeParams );242 static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams ); 243 243 static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind ); 244 244 static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic ); … … 247 247 static DeclarationNode * newTuple( DeclarationNode * members ); 248 248 static DeclarationNode * newTypeof( ExpressionNode * expr ); 249 static DeclarationNode * newAttr( std::string *, ExpressionNode * expr ); // @ attributes250 static DeclarationNode * newAttr( std::string *, DeclarationNode * type ); // @ attributes251 static DeclarationNode * newAttribute( std::string *, ExpressionNode * expr = nullptr ); // gcc attributes249 static DeclarationNode * newAttr( const std::string *, ExpressionNode * expr ); // @ attributes 250 static DeclarationNode * newAttr( const std::string *, DeclarationNode * type ); // @ attributes 251 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 252 252 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement 253 253 static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message ); -
src/Parser/TypeData.cc
r174845e rbeefc34c 10 10 // Created On : Sat May 16 15:12:51 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 26 13:46:07201813 // Update Count : 60 312 // Last Modified On : Wed Jun 6 17:40:33 2018 13 // Update Count : 604 14 14 // 15 15 … … 610 610 611 611 if ( td->basictype == DeclarationNode::Float80 || td->basictype == DeclarationNode::Float128 ) { 612 if ( td->complextype != DeclarationNode::NoComplexType ) {613 genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype );614 }612 // if ( td->complextype != DeclarationNode::NoComplexType ) { 613 // genTSError( DeclarationNode::complexTypeNames[ td->complextype ], td->basictype ); 614 // } 615 615 if ( td->basictype == DeclarationNode::Float80 ) ret = BasicType::Float80; 616 616 else ret = BasicType::Float128; -
src/Parser/TypedefTable.cc
r174845e rbeefc34c 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 1 16:54:18201813 // Update Count : 1 5512 // Last Modified On : Thu Jun 7 13:17:56 2018 13 // Update Count : 192 14 14 // 15 15 … … 17 17 #include "TypedefTable.h" 18 18 #include <cassert> // for assert 19 #include <iostream> 19 20 20 21 #if 0 21 #include <iostream>22 22 #define debugPrint( code ) code 23 23 #else … … 27 27 using namespace std; // string, iostream 28 28 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 29 42 TypedefTable::~TypedefTable() { 30 43 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(); 32 46 } // if 33 47 } // TypedefTable::~TypedefTable … … 44 58 } // TypedefTable::isKind 45 59 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 => update49 } // TypedefTable::changeKind50 51 60 // SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by 52 61 // "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the 53 62 // name is explicitly used. 54 void TypedefTable::makeTypedef( const string & name ) { 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 // } 55 71 if ( ! typedefTable.exists( name ) ) { 56 typedefTable.addToEnclosingScope( name, TYPEDEFname, "MTD" );72 typedefTable.addToEnclosingScope( name, kind, "MTD" ); 57 73 } // if 58 74 } // TypedefTable::makeTypedef 59 75 60 void TypedefTable::addToScope( const st d::string & identifier, int kind, const char * locn __attribute__((unused)) ) {76 void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) { 61 77 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 ); 63 79 auto ret = kindTable.insertAt( scope, identifier, kind ); 64 80 if ( ! ret.second ) ret.first->second = kind; // exists => update 65 81 } // TypedefTable::addToScope 66 82 67 void TypedefTable::addToEnclosingScope( const st d::string & identifier, int kind, const char * locn __attribute__((unused)) ) {83 void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) { 68 84 assert( kindTable.currentScope() >= 1 ); 69 85 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 ); 71 87 auto ret = kindTable.insertAt( scope, identifier, kind ); 72 88 if ( ! ret.second ) ret.first->second = kind; // exists => update … … 93 109 debugPrint( cerr << endl << "[" << scope << "]" ); 94 110 } // while 95 debugPrint( cerr << " " << (*i).first << ":" << (*i).second);111 debugPrint( cerr << " " << (*i).first << ":" << kindName( (*i).second ) ); 96 112 } // for 97 113 while ( scope > 0 ) { -
src/Parser/TypedefTable.h
r174845e rbeefc34c 10 10 // Created On : Sat May 16 15:24:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu May 31 23:23:47 201813 // Update Count : 8 312 // Last Modified On : Thu Jun 7 12:10:17 2018 13 // Update Count : 85 14 14 // 15 15 … … 30 30 bool exists( const std::string & identifier ); 31 31 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 ); 34 33 void addToScope( const std::string & identifier, int kind, const char * ); 35 34 void addToEnclosingScope( const std::string & identifier, int kind, const char * ); -
src/Parser/lex.ll
r174845e rbeefc34c 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Thu May 3 13:42:40 201813 * Update Count : 67 612 * Last Modified On : Thu Jun 7 08:27:40 2018 13 * Update Count : 679 14 14 */ 15 15 … … 232 232 finally { KEYWORD_RETURN(FINALLY); } // CFA 233 233 float { KEYWORD_RETURN(FLOAT); } 234 _Float32 { KEYWORD_RETURN(FLOAT); } // GCC 235 _Float32x { KEYWORD_RETURN(FLOAT); } // GCC 236 _Float64 { KEYWORD_RETURN(DOUBLE); } // GCC 237 _Float64x { KEYWORD_RETURN(DOUBLE); } // GCC 234 238 __float80 { KEYWORD_RETURN(FLOAT80); } // GCC 235 239 float80 { KEYWORD_RETURN(FLOAT80); } // GCC 240 _Float128 { KEYWORD_RETURN(FLOAT128); } // GCC 241 _Float128x { KEYWORD_RETURN(FLOAT128); } // GCC 236 242 __float128 { KEYWORD_RETURN(FLOAT128); } // GCC 237 243 float128 { KEYWORD_RETURN(FLOAT128); } // GCC … … 446 452 447 453 %% 454 448 455 // ----end of lexer---- 449 456 450 457 void yyerror( const char * errmsg ) { 458 SemanticErrorThrow = true; 451 459 cout << (yyfilename ? yyfilename : "*unknown file*") << ':' << yylineno << ':' << column - yyleng + 1 452 460 << ": " << ErrorHelpers::error_str() << errmsg << " at token \"" << (yytext[0] == '\0' ? "EOF" : yytext) << '"' << endl; -
src/Parser/parser.yy
r174845e rbeefc34c 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jun 4 22:22:04201813 // Update Count : 3 49212 // Last Modified On : Thu Jun 7 10:07:12 2018 13 // Update Count : 3527 14 14 // 15 15 … … 503 503 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $5 ) ), $2 ) ); } 504 504 | type_name '.' no_attr_identifier // CFA, nested type 505 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 505 // { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 506 { $$ = nullptr; } 506 507 | type_name '.' '[' field_list ']' // CFA, nested type / tuple field selector 507 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 508 // { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 509 { $$ = nullptr; } 508 510 | GENERIC '(' assignment_expression ',' generic_assoc_list ')' // C11 509 511 { … … 1300 1302 ; 1301 1303 1302 KR_parameter_list_opt: // used to declare parameter types in K&R style functions1304 KR_parameter_list_opt: // used to declare parameter types in K&R style functions 1303 1305 // empty 1304 1306 { $$ = nullptr; } … … 1790 1792 { $$ = DeclarationNode::newFromTypedef( $1 ); } 1791 1793 | '.' TYPEDEFname 1792 { $$ = DeclarationNode::newFromTypedef( $2 ); } // FIX ME1794 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1793 1795 | type_name '.' TYPEDEFname 1794 { $$ = DeclarationNode::newFromTypedef( $3 ); } // FIX ME1796 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1795 1797 | typegen_name 1796 1798 | '.' typegen_name 1797 { $$ = $2; } // FIX ME1799 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1798 1800 | type_name '.' typegen_name 1799 { $$ = $3; } // FIX ME1801 { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; } 1800 1802 ; 1801 1803 … … 1822 1824 aggregate_key attribute_list_opt '{' field_declaration_list_opt '}' 1823 1825 { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), nullptr, $4, true )->addQualifiers( $2 ); } 1824 | aggregate_key attribute_list_opt no_attr_identifier _or_type_name1825 { 1826 typedefTable.makeTypedef( *$3 );// create typedef1827 if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update1826 | aggregate_key attribute_list_opt no_attr_identifier 1827 { 1828 typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname ); // create typedef 1829 //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update 1828 1830 forall = false; // reset 1829 1831 } 1830 1832 '{' field_declaration_list_opt '}' 1831 1833 { $$ = DeclarationNode::newAggregate( $1, $3, nullptr, $6, true )->addQualifiers( $2 ); } 1834 | aggregate_key attribute_list_opt type_name 1835 { 1836 typedefTable.makeTypedef( *$3->type->symbolic.name, forall ? TYPEGENname : TYPEDEFname ); // create typedef 1837 //if ( forall ) typedefTable.changeKind( *$3->type->symbolic.name, TYPEGENname ); // possibly update 1838 forall = false; // reset 1839 } 1840 '{' field_declaration_list_opt '}' 1841 { $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, nullptr, $6, true )->addQualifiers( $2 ); } 1832 1842 | aggregate_key attribute_list_opt '(' type_list ')' '{' field_declaration_list_opt '}' // CFA 1833 1843 { $$ = DeclarationNode::newAggregate( $1, new string( DeclarationNode::anonymous.newName() ), $4, $7, false )->addQualifiers( $2 ); } … … 1838 1848 aggregate_key attribute_list_opt no_attr_identifier 1839 1849 { 1840 typedefTable.makeTypedef( *$3 );1841 if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update1850 typedefTable.makeTypedef( *$3, forall ? TYPEGENname : TYPEDEFname ); 1851 //if ( forall ) typedefTable.changeKind( *$3, TYPEGENname ); // possibly update 1842 1852 forall = false; // reset 1843 1853 $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 ); 1844 1854 } 1845 | aggregate_key attribute_list_opt TYPEDEFname 1846 { 1847 typedefTable.makeTypedef( *$3 ); 1848 $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 ); 1849 } 1850 | aggregate_key attribute_list_opt typegen_name // CFA 1855 | aggregate_key attribute_list_opt type_name 1851 1856 { 1852 1857 // Create new generic declaration with same name as previous forward declaration, where the IDENTIFIER is … … 1943 1948 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 1944 1949 { $$ = DeclarationNode::newEnum( new string( DeclarationNode::anonymous.newName() ), $4, true )->addQualifiers( $2 ); } 1945 | ENUM attribute_list_opt no_attr_identifier _or_type_name1950 | ENUM attribute_list_opt no_attr_identifier 1946 1951 { typedefTable.makeTypedef( *$3 ); } 1947 1952 '{' enumerator_list comma_opt '}' 1948 1953 { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); } 1954 | ENUM attribute_list_opt type_name 1955 '{' enumerator_list comma_opt '}' 1956 { $$ = DeclarationNode::newEnum( $3->type->symbolic.name, $5, true )->addQualifiers( $2 ); } 1949 1957 | enum_type_nobody 1950 1958 ; 1951 1959 1952 1960 enum_type_nobody: // enum - {...} 1953 ENUM attribute_list_opt no_attr_identifier _or_type_name1961 ENUM attribute_list_opt no_attr_identifier 1954 1962 { 1955 1963 typedefTable.makeTypedef( *$3 ); 1956 1964 $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); 1965 } 1966 | ENUM attribute_list_opt type_name 1967 { 1968 typedefTable.makeTypedef( *$3->type->symbolic.name ); 1969 $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); 1957 1970 } 1958 1971 ; … … 3251 3264 3252 3265 %% 3266 3253 3267 // ----end of grammar---- 3254 3268 -
src/libcfa/bits/locks.h
r174845e rbeefc34c 18 18 #include "bits/debug.h" 19 19 #include "bits/defs.h" 20 #include <assert.h> 21 22 #ifdef __cforall 23 extern "C" { 24 #include <pthread.h> 25 } 26 #endif 20 27 21 28 // pause to prevent excess processor bus usage … … 112 119 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 113 120 } 121 122 123 #ifdef __CFA_WITH_VERIFY__ 124 extern bool __cfaabi_dbg_in_kernel(); 125 #endif 126 127 struct __bin_sem_t { 128 bool signaled; 129 pthread_mutex_t lock; 130 pthread_cond_t cond; 131 }; 132 133 static inline void ?{}(__bin_sem_t & this) with( this ) { 134 signaled = false; 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(!signaled) { // this must be a loop, not if! 148 pthread_cond_wait(&cond, &lock); 149 } 150 signaled = false; 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 157 pthread_mutex_lock(&lock); 158 bool needs_signal = !signaled; 159 signaled = true; 160 pthread_mutex_unlock(&lock); 161 162 if (needs_signal) 163 pthread_cond_signal(&cond); 164 } 114 165 #endif -
src/libcfa/concurrency/kernel
r174845e rbeefc34c 113 113 pthread_t kernel_thread; 114 114 115 // RunThread data 116 // Action to do after a thread is ran 117 struct FinishAction finish; 118 119 // Preemption data 120 // Node which is added in the discrete event simulaiton 121 struct alarm_node_t * preemption_alarm; 122 123 // If true, a preemption was triggered in an unsafe region, the processor must preempt as soon as possible 124 bool pending_preemption; 125 126 // Idle lock 127 __bin_sem_t idleLock; 128 115 129 // Termination 116 130 // Set to true to notify the processor should terminate … … 120 134 semaphore terminated; 121 135 122 // RunThread data123 // Action to do after a thread is ran124 struct FinishAction finish;125 126 // Preemption data127 // Node which is added in the discrete event simulaiton128 struct alarm_node_t * preemption_alarm;129 130 // If true, a preemption was triggered in an unsafe region, the processor must preempt as soon as possible131 bool pending_preemption;132 133 // Idle lock134 sem_t idleLock;135 136 136 // Link lists fields 137 struct {137 struct __dbg_node_proc { 138 138 struct processor * next; 139 139 struct processor * prev; … … 182 182 183 183 // Link lists fields 184 struct {184 struct __dbg_node_cltr { 185 185 cluster * next; 186 186 cluster * prev; -
src/libcfa/concurrency/kernel.c
r174845e rbeefc34c 16 16 //C Includes 17 17 #include <stddef.h> 18 #include <errno.h> 19 #include <string.h> 18 20 extern "C" { 19 21 #include <stdio.h> … … 49 51 thread_desc * mainThread; 50 52 51 struct { __dllist_t(cluster) list; __spinlock_t lock; } global_clusters; 53 extern "C" { 54 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 55 } 52 56 53 57 //----------------------------------------------------------------------------- … … 143 147 runner.proc = &this; 144 148 145 sem_init(&idleLock, 0, 0);149 idleLock{}; 146 150 147 151 start( &this ); … … 149 153 150 154 void ^?{}(processor & this) with( this ){ 151 if( ! do_terminate) {155 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 152 156 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 153 terminate(&this); 154 verify(this.do_terminate); 155 verify( kernelTLS.this_processor != &this); 157 158 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 159 wake( &this ); 160 156 161 P( terminated ); 157 162 verify( kernelTLS.this_processor != &this); 158 pthread_join( kernel_thread, NULL ); 159 } 160 161 sem_destroy(&idleLock); 163 } 164 165 pthread_join( kernel_thread, NULL ); 162 166 } 163 167 … … 198 202 199 203 thread_desc * readyThread = NULL; 200 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++ ) 201 205 { 202 206 readyThread = nextThread( this->cltr ); … … 217 221 else 218 222 { 219 spin(this, &spin_count); 223 // spin(this, &spin_count); 224 halt(this); 220 225 } 221 226 } … … 290 295 } 291 296 292 // Handles spinning logic293 // TODO : find some strategy to put cores to sleep after some time294 void spin(processor * this, unsigned int * spin_count) {295 // (*spin_count)++;296 halt(this);297 }298 299 297 // KERNEL_ONLY 300 298 // Context invoker for processors … … 403 401 unlock( ready_queue_lock ); 404 402 405 if( was_empty) {403 if(was_empty) { 406 404 lock (proc_list_lock __cfaabi_dbg_ctx2); 407 405 if(idles) { 408 wake (idles.head);406 wake_fast(idles.head); 409 407 } 410 408 unlock (proc_list_lock); 411 409 } 410 else if( struct processor * idle = idles.head ) { 411 wake_fast(idle); 412 } 413 412 414 } 413 415 … … 544 546 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 545 547 546 global_clusters.list{ __get };547 global_clusters.lock{};548 __cfa_dbg_global_clusters.list{ __get }; 549 __cfa_dbg_global_clusters.lock{}; 548 550 549 551 // Initialize the main cluster … … 626 628 // When its coroutine terminates, it return control to the mainThread 627 629 // which is currently here 628 mainProcessor->do_terminate = true;630 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 629 631 returnToKernel(); 632 mainThread->self_cor.state = Halted; 630 633 631 634 // THE SYSTEM IS NOW COMPLETELY STOPPED … … 643 646 ^(mainThread){}; 644 647 645 ^( global_clusters.list){};646 ^( global_clusters.lock){};648 ^(__cfa_dbg_global_clusters.list){}; 649 ^(__cfa_dbg_global_clusters.lock){}; 647 650 648 651 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n"); … … 654 657 655 658 void halt(processor * this) with( *this ) { 659 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 660 656 661 with( *cltr ) { 657 662 lock (proc_list_lock __cfaabi_dbg_ctx2); … … 663 668 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 664 669 665 verify( ({int sval = 0; sem_getvalue(&this->idleLock, &sval); sval; }) < 200); 666 int __attribute__((unused)) ret = sem_wait(&idleLock); 667 verify(ret > 0 || errno == EINTR); 670 wait( idleLock ); 668 671 669 672 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); … … 675 678 unlock (proc_list_lock); 676 679 } 677 }678 679 void wake(processor * this) {680 __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);681 int __attribute__((unused)) ret = sem_post(&this->idleLock);682 verify(ret > 0 || errno == EINTR);683 verify( ({int sval = 0; sem_getvalue(&this->idleLock, &sval); sval; }) < 200);684 680 } 685 681 … … 797 793 // Global Queues 798 794 void doregister( cluster & cltr ) { 799 lock ( global_clusters.lock __cfaabi_dbg_ctx2);800 push_front( global_clusters.list, cltr );801 unlock ( global_clusters.lock );795 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2); 796 push_front( __cfa_dbg_global_clusters.list, cltr ); 797 unlock ( __cfa_dbg_global_clusters.lock ); 802 798 } 803 799 804 800 void unregister( cluster & cltr ) { 805 lock ( global_clusters.lock __cfaabi_dbg_ctx2);806 remove( global_clusters.list, cltr );807 unlock( global_clusters.lock );801 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2); 802 remove( __cfa_dbg_global_clusters.list, cltr ); 803 unlock( __cfa_dbg_global_clusters.lock ); 808 804 } 809 805 -
src/libcfa/concurrency/kernel_private.h
r174845e rbeefc34c 58 58 void finishRunning(processor * this); 59 59 void halt(processor * this); 60 void wake(processor * this); 61 void terminate(processor * this); 62 void spin(processor * this, unsigned int * spin_count); 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 } 63 71 64 72 struct event_kernel_t { … … 68 76 69 77 extern 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;78 78 79 79 struct __cfa_kernel_preemption_state_t { -
src/libcfa/concurrency/preemption.c
r174845e rbeefc34c 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 9 13:52:39 201813 // Update Count : 3 612 // Last Modified On : Tue Jun 5 17:35:49 2018 13 // Update Count : 37 14 14 // 15 15 … … 116 116 // If there are still alarms pending, reset the timer 117 117 if( alarms->head ) { 118 __cfaabi_dbg_print_buffer_decl( " KERNEL: @% lu(%lu) resetting alarm to %lu.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);118 __cfaabi_dbg_print_buffer_decl( " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv); 119 119 Duration delta = alarms->head->alarm - currtime; 120 120 Duration caped = max(delta, 50`us); … … 263 263 } 264 264 265 // kill wrapper : signal a processor266 void terminate(processor * this) {267 this->do_terminate = true;268 wake(this);269 sigval_t value = { PREEMPT_TERMINATE };270 pthread_sigqueue( this->kernel_thread, SIGUSR1, value );271 }272 273 265 // reserved for future use 274 266 static void timeout( thread_desc * this ) { … … 369 361 choose(sfp->si_value.sival_int) { 370 362 case PREEMPT_NORMAL : ;// Normal case, nothing to do here 371 case PREEMPT_TERMINATE: verify( kernelTLS.this_processor->do_terminate);363 case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) ); 372 364 default: 373 365 abort( "internal error, signal value is %d", sfp->si_value.sival_int ); … … 488 480 } 489 481 482 #ifdef __CFA_WITH_VERIFY__ 483 bool __cfaabi_dbg_in_kernel() { 484 return !kernelTLS.preemption_state.enabled; 485 } 486 #endif 487 490 488 // Local Variables: // 491 489 // mode: c // -
src/libcfa/fstream
r174845e rbeefc34c 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Dec 7 15:17:26 201713 // Update Count : 13 012 // Last Modified On : Tue Jun 5 10:20:25 2018 13 // Update Count : 131 14 14 // 15 15 … … 54 54 void open( ofstream &, const char * name ); 55 55 void close( ofstream & ); 56 ofstream & write( ofstream &, const char * data, unsigned long int size );56 ofstream & write( ofstream &, const char * data, size_t size ); 57 57 int fmt( ofstream &, const char fmt[], ... ); 58 58 … … 74 74 void open( ifstream & is, const char * name ); 75 75 void close( ifstream & is ); 76 ifstream & read( ifstream & is, char * data, unsigned long int size );76 ifstream & read( ifstream & is, char * data, size_t size ); 77 77 ifstream & ungetc( ifstream & is, char c ); 78 78 int fmt( ifstream &, const char fmt[], ... ); -
src/libcfa/fstream.c
r174845e rbeefc34c 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Dec 9 09:31:23 201713 // Update Count : 2 7512 // Last Modified On : Tue Jun 5 17:02:56 2018 13 // Update Count : 281 14 14 // 15 15 … … 116 116 } // close 117 117 118 ofstream & write( ofstream & os, const char * data, unsigned long int size ) {118 ofstream & write( ofstream & os, const char * data, size_t size ) { 119 119 if ( fail( os ) ) { 120 120 fprintf( stderr, "attempt write I/O on failed stream\n" ); … … 198 198 } // close 199 199 200 ifstream & read( ifstream & is, char * data, unsigned long int size ) {200 ifstream & read( ifstream & is, char * data, size_t size ) { 201 201 if ( fail( is ) ) { 202 202 fprintf( stderr, "attempt read I/O on failed stream\n" ); -
src/libcfa/stdhdr/assert.h
r174845e rbeefc34c 33 33 #define verify(x) assert(x) 34 34 #define verifyf(x, ...) assertf(x, __VA_ARGS__) 35 #define __CFA_WITH_VERIFY__ 35 36 #else 36 37 #define verify(x) -
src/main.cc
r174845e rbeefc34c 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 30 17:53:14201813 // Update Count : 49 612 // Last Modified On : Wed Jun 6 15:51:47 2018 13 // Update Count : 498 14 14 // 15 15 … … 157 157 << "." << endl; 158 158 backtrace( 2 ); // skip first 2 stack frames 159 exit( EXIT_FAILURE ); 159 //_exit( EXIT_FAILURE ); 160 abort(); 160 161 } // sigSegvBusHandler 161 162 -
src/prelude/extras.regx
r174845e rbeefc34c 1 1 typedef.* size_t; 2 2 typedef.* ptrdiff_t; 3 typedef.* __int8_t; 4 typedef.* __int16_t; 5 typedef.* __int32_t; 6 typedef.* __int64_t; 7 typedef.* __uint8_t; 8 typedef.* __uint16_t; 9 typedef.* __uint32_t; 10 typedef.* __uint64_t; 3 11 typedef.* int8_t; 4 12 typedef.* int16_t; -
src/prelude/sync-builtins.cf
r174845e rbeefc34c 248 248 #endif 249 249 250 _Bool __atomic_load_n(const volatile _Bool *, int); 251 void __atomic_load(const volatile _Bool *, volatile _Bool *, int); 250 252 char __atomic_load_n(const volatile char *, int); 251 253 char __atomic_load_1(const volatile char *, int); … … 285 287 286 288 void __atomic_store_n(volatile _Bool *, _Bool, int); 287 void __atomic_store_1(volatile _Bool *, _Bool, int);288 289 void __atomic_store(volatile _Bool *, _Bool *, int); 289 290 void __atomic_store_n(volatile char *, char, int); -
src/tests/Makefile.am
r174845e rbeefc34c 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Nov 27 21:34:33 201714 ## Update Count : 4 813 ## Last Modified On : Wed Jun 6 16:42:20 2018 14 ## Update Count : 49 15 15 ############################################################################### 16 16 … … 92 92 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 93 93 94 literals : literals.c @CFA_BINDIR@/@CFA_NAME@95 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@}96 97 94 sched-ext-parse : sched-ext-parse.c @CFA_BINDIR@/@CFA_NAME@ 98 95 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
src/tests/Makefile.in
r174845e rbeefc34c 769 769 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} 770 770 771 literals : literals.c @CFA_BINDIR@/@CFA_NAME@772 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@}773 774 771 sched-ext-parse : sched-ext-parse.c @CFA_BINDIR@/@CFA_NAME@ 775 772 ${CC} ${AM_CFLAGS} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@} -
src/tests/ifwhileCtl.c
r174845e rbeefc34c 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // if cond.c --7 // ifwhileCtl.c -- 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Aug 26 10:13:11 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jun 4 22:46:48201813 // Update Count : 1912 // Last Modified On : Wed Jun 6 17:15:09 2018 13 // Update Count : 21 14 14 // 15 15 … … 72 72 // Local Variables: // 73 73 // tab-width: 4 // 74 // compile-command: "cfa if cond.c" //74 // compile-command: "cfa ifwhileCtl.c" // 75 75 // End: // -
src/tests/preempt_longrun/enter.c
r174845e rbeefc34c 15 15 16 16 monitor mon_t {}; 17 void foo( mon_t & mutex this ) {} 17 18 18 19 mon_t mon; 19 20 void foo( mon_t & mutex this ) {}21 22 20 thread worker_t {}; 23 24 21 void main( worker_t & this ) { 25 22 for( unsigned long i = 0; i < N; i++ ) { … … 28 25 } 29 26 30 extern "C" {31 static worker_t * workers;32 }33 34 27 int main(int argc, char * argv[] ) { 35 28 processor p; 36 29 { 37 30 worker_t w[7]; 38 workers = w;39 31 } 40 32 } -
src/tests/preempt_longrun/processor.c
r174845e rbeefc34c 2 2 #include <thread> 3 3 #include <time> 4 5 #include <unistd.h> 4 6 5 7 #ifndef PREEMPTION_RATE … … 11 13 } 12 14 13 static const unsigned long N = 5 _000ul;15 static const unsigned long N = 50_000ul; 14 16 15 17 int main(int argc, char* argv[]) { 16 18 processor * p[15]; 19 write(STDOUT_FILENO, "Preparing\n", sizeof("Preparing\n")); 17 20 for ( int pi = 0; pi < 15; pi++ ) { 18 21 p[pi] = new(); 19 22 } 23 write(STDOUT_FILENO, "Starting\n", sizeof("Starting\n")); 20 24 for ( int i = 0; i < N; i++) { 21 25 int pi = i % 15; … … 23 27 p[pi] = new(); 24 28 } 29 write(STDOUT_FILENO, "Stopping\n", sizeof("Stopping\n")); 25 30 for ( int pi = 0; pi < 15; pi++ ) { 26 31 delete( p[pi] ); 27 32 } 33 write(STDOUT_FILENO, "Done\n", sizeof("Done\n")); 28 34 }
Note: See TracChangeset
for help on using the changeset viewer.