Changeset 5e0b6657


Ignore:
Timestamp:
Dec 8, 2025, 11:29:33 AM (2 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master
Children:
79ba50c
Parents:
8f448e0 (diff), 79ec8c3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge remote-tracking branch 'refs/remotes/origin/master'

Files:
38 edited
1 moved

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.sty

    r8f448e0 r5e0b6657  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon May  5 21:37:13 2025
    14 %% Update Count     : 666
     13%% Last Modified On : Sun Sep 21 22:17:15 2025
     14%% Update Count     : 667
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    325325  {<-}{$\leftarrow$}2
    326326  {=>}{$\Rightarrow$}2
     327  {/*}{/{\raisebox{-2pt}{*}}}2
     328  {*/}{{\raisebox{-2pt}{*}}/}2
    327329%  {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2,
    328330}% lstset
  • doc/LaTeXmacros/common.tex

    r8f448e0 r5e0b6657  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon May  5 21:34:53 2025
    14 %% Update Count     : 709
     13%% Last Modified On : Sun Sep 21 22:16:43 2025
     14%% Update Count     : 710
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    329329  {<-}{$\leftarrow$}2
    330330  {=>}{$\Rightarrow$}2
     331  {/*}{/{\raisebox{-2pt}{*}}}2
     332  {*/}{{\raisebox{-2pt}{*}}/}2
    331333%  {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2,
    332334}% lstset
  • doc/bibliography/pl.bib

    r8f448e0 r5e0b6657  
    362362    school      = {University of Waterloo},
    363363    year        = 1991,
    364     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     364    address     = {Waterloo, Ontario, Canada},
    365365}
    366366
     
    426426    year        = 2010,
    427427    month       = dec,
    428     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     428    address     = {Waterloo, Ontario, Canada},
    429429    optnote     = {\textsf{http://uwspace.uwaterloo.ca/\-bitstream/10012/\-5751\-/1/Krischer\_Roy.pdf}},
    430430    note        = {\url{http://uwspace.uwaterloo.ca/bitstream/10012/5751/1/Krischer_Roy.pdf}},
     
    929929
    930930% B
     931
     932@misc{ONCD,
     933    keywords    = {programming lnaguage safety},
     934    contributer = {pabuhr@plg},
     935    key         = {Final-ONCD-Technical-Report},
     936    title       = {Back to the Building Blocks: A Path Toward Secure and Measurable Software},
     937    author      = {},
     938    howpublished= {\url{https://bidenwhitehouse.archives.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf}},
     939    year        = 2024,
     940}
    931941
    932942@article{Michael13,
     
    11541164% C
    11551165
     1166@mastersthesis{HummelViirola25,
     1167    keywords    = {C, Rust, conversion},
     1168    contributer = {pabuhr@plg},
     1169    author      = {Johan Hummel and Ella Viirola},
     1170    title       = {From C 2 Rust: Evaluating the Feasibility of Translating C to a Memory-Safe Programming Language at Ericsson},
     1171    school      = {Lund University},
     1172    year        = 2025,
     1173    address     = {Lund, Sweden},
     1174}
     1175
    11561176@book{C,
    11571177    keywords    = {C},
     
    12471267    title       = {\textsf{C}$\mathbf{\forall}$ Container Library},
    12481268    school      = {School of Computer Science, University of Waterloo},
    1249     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1269    address     = {Waterloo, Ontario, Canada},
    12501270    publisher   = {UWSpace},
    12511271    year        = {2025},
    1252     note        = {\url{https://hdl.handle.net/10012/XXXXX}},
     1272    note        = {\url{https://hdl.handle.net/10012/12345}},
    12531273}
    12541274
     
    13241344    title       = {The \textsf{C}$\mathbf{\forall}$ Scheduler},
    13251345    school      = {School of Computer Science, University of Waterloo},
    1326     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1346    address     = {Waterloo, Ontario, Canada},
    13271347    publisher   = {UWSpace},
    13281348    year        = 2022,
     
    13451365    school      = {School of Computer Science, University of Waterloo},
    13461366    year        = 2004,
    1347     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1367    address     = {Waterloo, Ontario, Canada},
    13481368    note        = {\url{http://plg.uwaterloo.ca/theses/EstevesThesis.pdf}},
    13491369}
     
    13551375    school      = {School of Computer Science, University of Waterloo},
    13561376    year        = 2019,
    1357     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1377    address     = {Waterloo, Ontario, Canada},
    13581378    note        = {\url{https://hdl.handle.net/10012/14584}},
    13591379}
     
    15101530    title       = {\textsf{C}$\mathbf{\forall}$ Users Guide, Version 0.1},
    15111531    institution = {Department of Computer Science, University of Waterloo},
    1512     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1532    address     = {Waterloo, Ontario, Canada},
    15131533    month       = oct,
    15141534    year        = 2001,
     
    18331853    year        = 1997,
    18341854    month       = sep,
    1835     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1855    address     = {Waterloo, Ontario, Canada},
    18361856    note        = {\url{http://plg.uwaterloo.ca/theses/MokThesis.pdf}},
    18371857}
     
    20582078    school      = {School of Computer Sc., University of Waterloo},
    20592079    year        = 2015,
    2060     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     2080    address     = {Waterloo, Ontario, Canada},
    20612081    note        = {\url{https://hdl.handle.net/10012/10013}},
    20622082}
     
    21042124    title       = {Concurrency in \textsf{C}$\mathbf{\forall}$},
    21052125    school      = {School of Computer Science, University of Waterloo},
    2106     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     2126    address     = {Waterloo, Ontario, Canada},
    21072127    publisher   = {UWSpace},
    21082128    year        = 2018,
     
    21162136    title       = {Concurrency in {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}},
    21172137    institution = {Department of Computer Science, University of Waterloo},
    2118     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     2138    address     = {Waterloo, Ontario, Canada},
    21192139    number      = {CS-90-18},
    21202140    month       = may,
     
    22092229    school      = {Department of Computer Science, University of Waterloo},
    22102230    year        = 1992,
    2211     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     2231    address     = {Waterloo, Ontario, Canada},
    22122232    note        = {\url{http://plg.uwaterloo.ca/theses/DitchfieldThesis.pdf}}
    22132233}
     
    32893309    title       = {Enumerated Types in \textsf{C}$\mathbf{\forall}$},
    32903310    school      = {School of Computer Science, University of Waterloo},
    3291     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     3311    address     = {Waterloo, Ontario, Canada},
    32923312    publisher   = {UWSpace},
    32933313    year        = {2024},
     
    34963516    title       = {Exception Handling in \textsf{C}$\mathbf{\forall}$},
    34973517    school      = {School of Computer Science, University of Waterloo},
    3498     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     3518    address     = {Waterloo, Ontario, Canada},
    34993519    publisher   = {UWSpace},
    35003520    year        = {2021},
     
    37523772    year        = 2008,
    37533773    month       = jan,
    3754     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     3774    address     = {Waterloo, Ontario, Canada},
    37553775    note        = {\url{http://uwspace.uwaterloo.ca/bitstream/10012/3501/1/Thesis.pdf}},
    37563776}
     
    42094229    year        = 2009,
    42104230    month       = sep,
    4211     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4231    address     = {Waterloo, Ontario, Canada},
    42124232    note        = {\textsf{http://uwspace.uwaterloo.ca/bitstream/\-10012/\-4735/\-1/\-Chen-Jun.pdf}},
    42134233}
     
    42304250    author      = {Haskell},
    42314251    title       = {Haskell 2010 Language Report},
    4232     edition     = {{S}imon {M}arlow},
     4252    optedition  = {{S}imon {M}arlow},
    42334253    year        = 2010,
    42344254    note        = {\url{https://haskell.org/definition/haskell2010.pdf}},
     
    42914311    title       = {High Level Concurrency in \textsf{C}$\mathbf{\forall}$},
    42924312    school      = {School of Computer Science, University of Waterloo},
    4293     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4313    address     = {Waterloo, Ontario, Canada},
    42944314    publisher   = {UWSpace},
    42954315    year        = {2023},
     
    43024322    author      = {Mubeen Zulfiqar},
    43034323    title       = {High-Performance Concurrent Memory Allocation},
    4304     school      = {School of Computer Science, University of Waterloo},
     4324    school      = {School of Comp. Sc., Univ. of Waterloo},
    43054325    year        = 2022,
    4306     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4326    address     = {Waterloo, Ontario, Canada},
    43074327    note        = {\url{https://hdl.handle.net/10012/18329}},
    43084328}
     
    43234343    author      = {Srihari Radhakrishnan},
    43244344    title       = {High Performance Web Servers: A Study In Concurrent Programming Models},
    4325     school      = {School of Computer Sc., University of Waterloo},
     4345    school      = {School of Computer Science, University of Waterloo},
    43264346    year        = 2019,
    4327     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4347    address     = {Waterloo, Ontario, Canada},
    43284348    note        = {\url{https://hdl.handle.net/10012/14706}},
    43294349}
     
    45294549    author      = {Richard C. Bilson},
    45304550    title       = {Implementing Overloading and Polymorphism in \textsf{C}$\mathbf{\forall}$},
    4531     school      = {School of Computer Science, University of Waterloo},
     4551    school      = {University of Waterloo},
    45324552    year        = 2003,
    4533     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4553    address     = {Waterloo, Ontario, Canada},
    45344554    note        = {\url{http://plg.uwaterloo.ca/theses/BilsonThesis.pdf}},
    45354555}
     
    45724592    year        = 2018,
    45734593    month       = sep,
    4574     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4594    address     = {Waterloo, Ontario, Canada},
    45754595    note        = {\url{https://uwspace.uwaterloo.ca/handle/10012/13935}},
    45764596}
     
    51095129    school      = {University of Waterloo},
    51105130    year        = 1990,
    5111     address     = {Waterloo, Ontario, Canada, N2L 3G1}
     5131    address     = {Waterloo, Ontario, Canada}
    51125132}
    51135133
     
    55315551    title       = {$\mu${S}ystem Annotated Reference Manual, Version 4.4.3},
    55325552    institution = {Department of Computer Science, University of Waterloo},
    5533     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     5553    address     = {Waterloo, Ontario, Canada},
    55345554    month       = sep,
    55355555    year        = 1994,
     
    62736293    contributer = {pabuhr@plg},
    62746294    key         = {OCaml},
    6275     title       = {The {OC}aml system, release 5.1},
    6276     address     = {Rust Project Developers},
    6277     year        = 2023,
    6278     note        = {\url{https://v2.ocaml.org/manual/}},
     6295    author      = {Xavier Leroy, Damien Doligez, Alain Frisch, Jacques Garrigue, Didier Rémy and Jérôme Vouillon},
     6296    title       = {The {OC}aml system, release 5.4},
     6297    year        = 2025,
     6298    note        = {\url{https://v2.ocaml.org/manual}},
    62796299}
    62806300
     
    77337753    school      = {School of Computer Science, University of Waterloo},
    77347754    year        = 2017,
    7735     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     7755    address     = {Waterloo, Ontario, Canada},
    77367756    note        = {\url{https://hdl.handle.net/10012/11830}},
    77377757}
     
    78197839    contributer = {pabuhr@plg},
    78207840    key         = {Rust},
    7821     title       = {{R}ust Programming Language},
    7822     address     = {Rust Project Developers},
     7841    title       = {The {R}ust Reference},
     7842    address     = {Rust Developers},
    78237843    year        = 2015,
    7824     note        = {\url{https://doc.rust-lang.org/reference.html}},
     7844    note        = {\url{https://doc.rust-lang.org/stable/reference}},
    78257845}
    78267846
     
    78757895    month       = jun,
    78767896    pages       = {35-46},
     7897}
     7898
     7899@inproceedings{Kashyap17,
     7900    contributer = {pabuhr@plg},
     7901    author      = {Sanidhya Kashyap and Changwoo Min and Taesoo Kim},
     7902    title       = {Scalable {NUMA-aware} Blocking Synchronization Primitives},
     7903    booktitle   = {2017 USENIX Annual Tech. Conf.},
     7904    address     = {Santa Clara, CA},
     7905    pages       = {603-615},
     7906    publisher   = {USENIX Assoc.},
     7907    year        = 2017,
     7908    month       = jul,
    78777909}
    78787910
     
    83218353    contributer = {pabuhr@plg},
    83228354    author      = {Michael D. Tiemann},
    8323     title       = {Solving the RPC problem in GNU {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}},
     8355    title       = {Solving the {RPC} problem in {GNU} {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}},
    83248356    booktitle   = {Proceedings of the USENIX {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Conference},
    83258357    organization= {USENIX Association},
     
    83338365    keywords    = {Polymorphic C},
    83348366    contributor = {a3moss@uwaterloo.ca},
    8335     title       = {A sound polymorphic type system for a dialect of {C}},
     8367    title       = {A Sound Polymorphic Type System for a Dialect of {C}},
    83368368    author      = {Smith, Geoffrey and Volpano, Dennis},
    83378369    journal     = {Science of computer programming},
     
    85438575    school      = {Department of Computer Science, University of Waterloo},
    85448576    year        = 1989,
    8545     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     8577    address     = {Waterloo, Ontario, Canada},
    85468578}
    85478579
     
    87848816    volume      = 40,
    87858817    number      = 6,
    8786     month       = jun,
     8818    optmonth    = jun,
    87878819    year        = 2005,
    87888820    pages       = {261-268},
     
    89098941}
    89108942
     8943@misc{Tractor,
     8944    keywords    = {Rust, C conversion},
     8945    contributer = {pabuhr@plg},
     8946    key         = {Tractor},
     8947    title       = {TRACTOR: Translating All C to Rust},
     8948    author      = {Dan Wallach},
     8949    note        = {DARPA},
     8950    howpublished= {\url{https://www.darpa.mil/research/programs/translating-all-c-to-rust}},
     8951    year        = 2024,
     8952}
     8953
    89118954@misc{Miller19,
    89128955    keywords    = {memory management, errors, unsafe},
    89138956    contributer = {pabuhr@plg},
    8914     title       = {Trends, challenges, and strategic shifts in the software vulnerability mitigation landscape},
     8957    title       = {Trends, Challenges, and Strategic Shifts in the Software Vulnerability Mitigation Landscape},
    89158958    author      = {Matt Miller},
    89168959    month       = feb,
     
    89268969    school      = {Department of Computer Science, University of Waterloo},
    89278970    year        = 1989,
    8928     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     8971    address     = {Waterloo, Ontario, Canada},
    89298972}
    89308973
     
    90879130    title       = {Type Resolution in \textsf{C}$\mathbf{\forall}$},
    90889131    school      = {School of Computer Science, University of Waterloo},
    9089     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     9132    address     = {Waterloo, Ontario, Canada},
    90909133    publisher   = {UWSpace},
    90919134    year        = {2025},
  • doc/proposals/autogen.md

    r8f448e0 r5e0b6657  
    100100The main reason to manually remove functions is to enforce a behaviour based interface for a type, as opposed to a data based one. To enforce that new interface, this would have to interact with visibility.
    101101
     102### Automatic Remove Hides Everything
     103As soon as you declare a custom constructor, _all_ autogenerated constructors become inaccessible. Often, this behaviour is good, and it agrees with C++. But the desire dual to "manually remove" exists: "manually keep." Furthermore, there is a use case for invoking an automatically provided constructor as a helper, when implementing a custom constructor.
     104
     105        struct S {
     106            int i;
     107            int & j;
     108        };
     109        void ?{}( S & s, int & w ) {
     110            // Unique best alternative includes deleted identifier in:
     111            s{ 3, w };
     112            // intended meaning / workaround:
     113            // s.i = 3; &s.j = &w;
     114        }
     115
     116This use case should be considered also, along with visibility. A private helper constructor should be usable in the implementation of a public value-add constructor. The private helper being an autogen is one such arrangement.
     117
     118Users should have the option to adopt the idiom: All constructors funnel into the most private, all-member constructor.
     119
     120### Removed Functions Linger
     121Even if a function is made CFA-uncallable, it still shows in the emitted C code (`cfa -CFA`). An uncallable function shows identically to a callable function, with no indication of, "This declaration has been deleted," or, "Here is a redaction of X." This quirk reduces the utility of inspecting -CFA to answer, "What constructors would be available to me?" or, "What's the net effect of the constructor declarations and deletions that I've given?"
     122
    102123## Other Problems & Requested Features
    103124
  • doc/theses/fangren_yu_MMath/test.adb

    r8f448e0 r5e0b6657  
    66        Function Random return Float is begin return 3.5; end;
    77        Function Random return Unbounded_String is begin return To_Unbounded_String( "abc" ); end;
    8        
     8
    99        Procedure Print( V : Integer ) is begin Put_Line( Integer'Image(V) ); end;
    1010        Procedure Print( V : Float ) is begin Put_Line( Float'Image(V) ); end;
    1111        Procedure Print( V : Unbounded_String ) is begin Put_Line( Ada.Strings.Unbounded.To_String(V) ); end;
    12        
     12
    1313        Function Func( V : Integer ) return Integer is begin return V; end;
    1414        Function Func( V : Float ) return Float is begin return V; end;
    1515        Function Func( V : Unbounded_String ) return Unbounded_String is begin return V; end;
    1616        Function Func( V1 : Integer; V2 : Float ) return Float is begin return Float(V1) + V2; end;
    17        
    18         subtype Int      is Integer;
     17
     18        subtype Int              is Integer;
    1919        J : Int;
    2020        Function "-"( L, R : Int ) return Int is begin Put_Line( "X" ); return Integer(L) + (-Integer(R)); end; --  prevent infinite recusion
    21        
    22 --      duplicate body for "-" declared at line 20
    23 --      subtype SInt is Integer range -10 .. 10;
    24 --      Function "-"( L, R : SInt ) return SInt is begin Put_Line( "X" ); return Integer(L) + (-Integer(R)); end; --  prevent infinite recusion
    25        
     21
     22        --      duplicate body for "-" declared at line 20
     23        --      subtype SInt is Integer range -10 .. 10;
     24        --      Function "-"( L, R : SInt ) return SInt is begin Put_Line( "X" ); return Integer(L) + (-Integer(R)); end; --  prevent infinite recusion
     25
    2626        i : Integer;
    2727        f : Float;
    2828        s : Unbounded_String;
    29        
     29
    3030        Type Complex is
    31         record
    32             Re, Im : Float;
    33         end record;
     31                record
     32                Re, Im : Float;
     33                end record;
    3434        c : Complex := (Re => 1.0, Im => 1.0);
    35     Procedure Grind (X : Complex) is begin Put_Line( "Grind1" ); end;
    36     Procedure Grind (X : Unbounded_String) is begin Put_Line( "Grind2" ); end;
    37        
     35        Procedure Grind (X : Complex) is begin Put_Line( "Grind1" ); end;
     36        Procedure Grind (X : Unbounded_String) is begin Put_Line( "Grind2" ); end;
     37
    3838        generic
    39            type T is private;
    40            with function "+"( X, Y: T ) return T;
     39                type T is private;
     40                with function "+"( X, Y: T ) return T;
    4141        function twice( X : T ) return T;
    42        
     42
    4343        function twice( X: T ) return T is
    4444        begin
    45            Put_Line( "XXX" ); return X + X;   -- The formal operator "*".
     45                Put_Line( "XXX" ); return X + X;        -- The formal operator "*".
    4646        end twice;
    4747
    4848        function Int_Twice is new Twice( Integer, "+" => "+" );
    4949        function float_Twice is new Twice( float, "+" => "+" );
    50        
    51 --      generic units cannot be overloaded
    52 --      generic
    53 --        type T is private;
    54 --        with function "+"( X, Y: T ) return T;
    55 --      function twice( X : T; Y : T ) return T;
    56        
    57 --      function twice( X: T; Y : T ) return T is
    58 --      begin
    59 --        Put_Line( "XXX" ); return X + X;   -- The formal operator "*".
    60 --      end twice;
     50
     51        --      generic units cannot be overloaded
     52        --      generic
     53        --              type T is private;
     54        --              with function "+"( X, Y: T ) return T;
     55        --      function twice( X : T; Y : T ) return T;
     56
     57        --      function twice( X: T; Y : T ) return T is
     58        --      begin
     59        --              Put_Line( "XXX" ); return X + X;        -- The formal operator "*".
     60        --      end twice;
    6161begin
    62    I := 3;
    63    I := 7 - 3;
    64         Print( i );
    65    F := 3.8;
    66    I := 7 - 2;
    67         Print( i );
    68    J := 7 - 3;
    69         Print( j );
    70    
     62        I := 3;
     63        I := 7 - 3;
     64        Print( i );
     65        F := 3.8;
     66        I := 7 - 2;
     67        Print( i );
     68        J := 7 - 3;
     69        Print( j );
     70
    7171        i := Random;
    72         Print( i );
     72        Print( i );
    7373        f := Random;
    74         Print( f );
     74        Print( f );
    7575        s := Random;
    76         Print( s );
    77        
    78         Print( Func( V => 7 ) );
    79         Print( Func( 7.5 ) );
    80         Print( Func( To_Unbounded_String( "abc" ) ) );
    81         Print( Func( 3, 3.5 ) );
    82 --      Print( Func( 3, 3 ) );
    83        
     76        Print( s );
     77
     78        Print( Func( V => 7 ) );
     79        Print( Func( 7.5 ) );
     80        Print( Func( To_Unbounded_String( "abc" ) ) );
     81        Print( Func( 3, 3.5 ) );
     82        --              Print( Func( 3, 3 ) );
     83
    8484        Grind( X => (Re => 1.0, Im => 1.0) );
    8585        Grind( c );
    8686        Grind( To_Unbounded_String( "abc" ) );
    87        
     87
    8888        i := Int_Twice( 2 );
    8989        Put_Line( Integer'Image(i) );
    9090        f := float_Twice( 2.5 );
    91         Print( f );
     91        Print( f );
    9292end test;
    9393
  • doc/theses/mike_brooks_MMath/intro.tex

    r8f448e0 r5e0b6657  
    22
    33All modern programming languages provide three high-level containers (collections): array, linked-list, and string.
    4 Often array is part of the programming language, while linked-list is built from (recursive) pointer types, and string from a combination of array and linked-list.
     4Often array is part of the programming language, while linked-lists are built from (recursive) pointer types, and strings from a combination of array and linked-list.
    55For all three types, languages and/or their libraries supply varying degrees of high-level mechanisms for manipulating these objects at the bulk and component level, such as copying, slicing, extracting, and iterating among elements.
    66
    77Unfortunately, these three aspects of C cause a significant number of memory errors~\cite{Oorschot23}.
     8Estimates suggest 50\%~\cite{Mendio24} of total reported open-source vulnerabilities occurring in C result from errors using these facilities (memory errors).
    89For operating system and browser vendors, who heavily use systems languages, 60\%--70\% of reported software vulnerabilities involved memory errors~\cite{Kehrer23}.
    910For Microsoft, 70\% of vulnerabilities addressed via security updates between 2006--2018 are memory safety issues~\cite[slide 10]{Miller19}.
    1011In a study of software exploits in the U.S. National Vulnerability Database over 2013--2017, the top reported vulnerability is (memory) buffer errors, among 19 vulnerability categories~\cite{Cifuentes19}.
    11 Therefore, hardening these three C types goes a long way to make the majority of C programs safer.
     12Therefore, hardening these three C types goes a long way to make the majority of C programs safer and eliminating major hacker attack-vectors.
    1213
    1314This work looks at extending these three foundational container types in the programming language \CFA, which is a new dialect of the C programming language.
     
    2627The array size can be static, dynamic but fixed after creation, or dynamic and variable after creation.
    2728For static and dynamic-fixed, an array can be stack allocated, while dynamic-variable requires the heap.
    28 Because array layout has contiguous components, subscripting is a computation (some form of pointer arithmetic).
     29Because array layout has contiguous components, subscripting is a computation, \ie some form of pointer arithmetic.
    2930
    3031C provides a simple array type as a language feature.
    31 However, it adopts the controversial language position of treating pointer and array as duals, leading to multiple problems.
     32However, it adopts the controversial position of treating pointer and array as duals, leading to multiple problems.
    3233
    3334
     
    3637A linked-list provides a homogeneous container often with $O(log N)$ or $O(N)$ access to elements using successor and predecessor operations that normally involve pointer chasing.
    3738Subscripting by value (rather than position or location as for array) is sometimes available, \eg hash table.
    38 Linked types are normally dynamically sized by adding and removing nodes using link fields internal or external to the elements (nodes).
    39 If a programming language allows pointers to stack storage, linked-list nodes can be allocated on the stack and connected with stack addresses (pointers);
     39Linked types are dynamically sized by adding and removing nodes using link fields internal or external to the list elements (nodes).
     40If a programming language allows pointers to stack storage, linked-list nodes can be allocated on the stack and connected with stack addresses;
    4041otherwise, elements are heap allocated with internal or external link fields.
    4142
     
    4748hash search table consisting of a key (string) with associated data (@<search.h>@)
    4849\end{itemize}
    49 Because these libraries are simple, awkward to use, and unsafe, C programmers commonly build bespoke linked data-structures.
     50Because these container libraries can be restrictive, awkward to use, and unsafe, C programmers often build bespoke linked data-structures, which further increases the potential for memory errors.
    5051
    5152
     
    5455A string provides a dynamic array of homogeneous elements, where the elements are (often) some form of human-readable characters.
    5556What differentiates a string from other types in that many of its operations work on groups of elements for scanning and changing, \eg @index@ and @substr@.
    56 While subscripting individual elements is usually available, working at the individual character level is considered poor practise, \ie underutilizing the powerful string operations.
     57While subscripting individual elements is usually available, working at the character level is considered poor practise, \ie underutilizing the powerful string operations.
    5758Therefore, the cost of a string operation is usually less important than the power of the operation to accomplish complex text manipulation, \eg search, analysing, composing, and decomposing string text.
    5859The dynamic nature of a string means storage is normally heap allocated but often implicitly managed, even in unmanaged languages.
    59 In some cases, string management is separate from heap management, \ie strings roll their own heap.
     60In many cases, string management is separate from heap management, \ie strings roll their own heap.
    6061
    6162The C string type is just a character array and requires user storage-management to handle varying size.
    62 The character array uses the convention of marking its (variable) array length by placing the 0-valued control character at the end (null-terminated).
     63C adopts a terminating sentinel character, @'\0'@, to mark the end of a variable-length character-array versus a preceding length field.
     64Hence, the sentinel character is excluded from a string and determining the string length is an $O(N)$ operation.
    6365The C standard library includes a number of high-level operations for working with this representation.
    64 Most of these operations are awkward and error prone.
     66Most of these operations are awkward to use and error prone.
    6567
    6668
     
    8082\begin{enumerate}[leftmargin=*]
    8183\item
    82 These three aspects of C are difficult to understand, teach, and get right because they are correspondingly low level.
     84The three primary container types in C are difficult to understand, teach, and get right because they are too low level.
    8385Providing higher-level, feature-rich versions of these containers in \CFA is a major component of the primary goal.
     86The result is a simplify programming experience, which increases productivity and maintainability.
    8487\item
    85 These three aspects of C cause the greatest safety issues because there are few or no safe guards when a programmer misunderstands or misuses these features~\cite{Elliott18, Blache19, Ruef19, Oorschot23}.
    86 Estimates suggest 50\%~\cite{Mendio24} of total reported open-source vulnerabilities occurring in C result from errors using these facilities (memory errors), providing the major hacker attack-vectors.
     88The new container types must be as correct and safe to use as those in other modern programming languages, which has been shown to a primary concern of industry, government, and military~\cite{ONCD}.
     89Prior approaches focus on out-of-bound array accesses using a model-based approach (ASCET) in embedded systems (\eg cars)~\cite{Blache19}, and general and null-terminated string arrays using a \CC template syntax (Checked C)~\cite{Elliott18,Ruef19}.
     90Both White House~\cite{WhiteHouse24} and DARPA~\cite{DARPA24} recently released a recommendation to \emph{move away} from C and \CC, because of cybersecurity threats exploiting vulnerabilities in these languages.
     91Fixing these vulnerabilities negates this need, allowing C and its ecosystem to continue into the future.
    8792\end{enumerate}
    88 Both White House~\cite{WhiteHouse24} and DARPA~\cite{DARPA24} recently released a recommendation to move away from C and \CC, because of cybersecurity threats exploiting vulnerabilities in these older languages.
    89 Hardening these three types goes a long way to make the majority of C programs safer.
    9093
    91 
    92 While multiple new languages purport to be systems languages replacing C, the reality is that rewriting massive C code-bases is impractical and a non-starter if the new runtime uses garage collection.
     94While new languages, \eg Go, Rust, Swift, purport to be systems languages replacing C, the reality is that rewriting massive C code-bases is impractical and a non-starter if the runtime uses garbage collection.
     95Even assuming automated conversion of C programs to other safe languages, who will maintain this massive new code-base?
    9396Furthermore, new languages must still interact with the underlying C operating system through fragile, type-unsafe, interlanguage-communication.
    94 Switching to \CC is equally impractical as its complex and interdependent type-system (\eg objects, overloading, inheritance, templates) means idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning new \CC.
    95 Hence, rewriting and retraining costs for these languages can be prohibitive for companies with a large C software-base (Google, Apple, Microsoft, Amazon, AMD, Nvidia).
     97Switching to \CC is equally impractical as its complex and interdependent type-system (\eg objects, overloading, inheritance, templates) means idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning new \CC features and idioms.
     98Finally, projects claiming to be modern C replacements (Cyclone~\cite{Grossman06}, Polymorphic C~\cite{Smith98}, GObject~\cite{GObject}) do not retain C backwards compatibility in syntax, programing model, or semantic compatibility;
     99these languages are equivalent to switching to a different programming language.
     100Hence, rewriting and retraining costs for other languages are prohibitive when companies have a large C software-base (Google, Apple, Microsoft, Amazon, AMD, Nvidia).
    96101
    97102
     
    100105Like many established programming languages, C has a standards committee and multiple ANSI/\-ISO language manuals~\cite{C99,C11,C18,C23}.
    101106However, most programming languages are only partially explained by their standard's manual(s).
    102 When it comes to explaining how C works, the definitive source is the @gcc@ compiler, which is mimicked by other C compilers, such as Clang~\cite{clang}.
    103 Often other C compilers \emph{must} mimic @gcc@ because a large part of the C library (runtime) system (@glibc@ on Linux) contains @gcc@ features.
     107When it comes to explaining how C works, the definitive source is the @gcc@ compiler, which is mimicked by other C compilers, such as Clang~\cite{clang}, because a large part of the C library (runtime) system (@glibc@ on Linux) contains @gcc@ features.
    104108Some key aspects of C need to be explained and understood by quoting from the language reference manual.
    105109However, to illustrate actual program semantics, this thesis constructs multiple small programs whose behaviour exercises a particular point and then confirms the behaviour by running the program using multiple @gcc@ compilers.
    106110These example programs show
    107 \begin{itemize}
     111\begin{itemize}[itemsep=0pt]
    108112        \item if the compiler accepts or rejects certain syntax,
    109113        \item prints output to buttress a behavioural claim,
     
    111115\end{itemize}
    112116These programs are tested across @gcc@ versions 8--14 and clang versions 10--14 running on ARM, AMD, and Intel architectures.
    113 Any discovered anomalies among compilers, versions, or architectures is discussed.
     117Any discovered anomalies among compilers, versions, or architectures are discussed.
    114118In general, it is never clear whether the \emph{truth} lies in the C standard or the compiler(s), which may be true for other programming languages.
    115119
     
    118122
    119123Overall, this work has produced significant syntactic and semantic improvements to C's arrays, linked-lists and string types.
    120 As well, a strong plan for general iteration has been sketched out.
     124% As well, a strong plan for general iteration has been sketched out.
    121125The following are the detailed contributions, where performance and safety were always the motivating factors.
    122126
    123127\subsection{Array}
    124128
    125 This work's array improvements are:
     129The improvements to C arrays are:
    126130\begin{enumerate}[leftmargin=*]
    127131\item
    128 Introduce a small number of subtle changes to the typing rules for the C array, while still achieving significant backwards compatibility
     132Introduce a small number of subtle changes to the typing rules for the C array, while still achieving significant backwards compatibility.
    129133\item
    130134Create a new polymorphic mechanism in the \CFA @forall@ clause to specify array dimension values, similar to a fixed-typed parameter in a \CC \lstinline[language=C++]{template}.
  • doc/theses/mike_brooks_MMath/uw-ethesis-frontpgs.tex

    r8f448e0 r5e0b6657  
    129129\begin{center}\textbf{Abstract}\end{center}
    130130
     131\CFA strives to fix mistakes in C, chief among them, safety.
     132This thesis presents a significant step forward in \CFA's goal to remove unsafe pointer operations.
     133The thesis presents improvements to the \CFA language design, both syntax and semantics, to support advanced container features.
     134These features are implemented across the \CFA compiler, libraries, and runtime system.
     135The results maintain another \CFA goal of remaining 99\% backwards compatible with C.
     136This thesis leverages preexisting work within the compiler's type and runtime systems generated by prior students working on the \CFA project.
     137
    131138All modern programming languages provide three high-level containers (collections): array, linked-list, and string.
    132 Often array is part of the programming language, while linked-list is built from (recursive) pointer types, and string from a combination of array and linked-list.
     139Often array is part of the programming language, while linked-lists are built from (recursive) pointer types, and strings from a combination of array and linked-list.
    133140For all three types, languages and/or their libraries supply varying degrees of high-level mechanisms for manipulating these objects at the bulk and component level, such as copying, slicing, extracting, and iterating among elements.
    134 Unfortunately, these three aspects of C cause 60\%--70\% of the reported software vulnerabilities involved memory errors, and 70\%--80\% of hacker attack-vectors target these types.
     141Unfortunately, these three aspects of C cause 60\%--70\% of the reported software vulnerabilities involving memory errors, and 70\%--80\% of hacker attack-vectors target these types.
    135142Therefore, hardening these three C types goes a long way to make the majority of C programs safer.
    136143
    137 This work looks at extending these three foundational container types in the programming language \CFA, which is a new dialect of the C programming language.
    138 The thesis describes improvements made to the \CFA language design, both syntax and semantics, to support the container features, and the source code created within the \CFA compiler, libraries, and runtime system to implement these features.
    139 This work leverages preexisting work within the compiler's type and runtime systems generated by prior students working on the \CFA project.
    140 
    141 Overall, this work has produced significant syntactic and semantic improvements to C's container types.
    142 \begin{enumerate}[leftmargin=*]
    143 \item
    144 Introduce a small number of subtle changes to the typing rules for the C array, while still achieving significant backwards compatibility.
    145 \item
    146 Create a new polymorphic mechanism in the \CFA @forall@ clause to specify array dimension values, similar to a fixed-typed parameter in a \CC \lstinline[language=C++]{template}.
    147 The new array type, enabled by prior features, defines an array with guaranteed runtime bound checks (often optimizer-removable) and implicit (guaranteed accurate) inter-function length communication.
    148 \item
    149 Create a new polymorphic list type and its runtime library following the established design pattern of intrusive link-fields for performance reasons, especially in concurrent programs.
    150 \item
    151 Create a new string type and runtime library comparable to the \CC @string@ type, including analogous coexistence with raw-character pointers, enabling programs to work with strings by value, without incurring excessive copying.
    152 Substrings are supported, including the ability for overlapping ranges to share edits transparently.
    153 \end{enumerate}
    154 The thesis includes a performance evaluation that shows the new \CFA containers perform comparably with their C counterparts in many programming cases.
     144Specifically, an array utility is provided that tracks length internally, relieving the user of managing explicit length parameters and stopping buffer-overrun errors.
     145This feature requires augmenting the \CFA type system, making array length available at compile and runtime.
     146A linked-list utility is provided, which obviates many explicit recursive pointers by catering directly to system-programming uses (intrusive lists) for which a library solution is often dismissed.
     147Finally, a string utility is provided with implicit memory management of text in a specialized heap, relieving error-prone buffer management, including overrun, and providing a copy-on-write speed boost.
     148For all three utilities, performance is argued to be on-par with, and occasionally surpassing relevant comparators.
     149With the array, this case is made by showing complete erasure down to a naked C array, modulo runtime bound checks, which are removable more often than with Java-style length management.
     150With the linked list and string, empirical measures are compared with relevant libraries.
     151These utilities offer a system programmer workable alternatives to hand-rolling several common causes of system vulnerabilities, thereby improving \CFA's position as a safety-forward system-programming alternative.
    155152
    156153\cleardoublepage
  • doc/uC++toCFA/uC++toCFA.tex

    r8f448e0 r5e0b6657  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Sep  8 18:10:30 2025
    14 %% Update Count     : 6534
     13%% Last Modified On : Mon Nov 17 11:14:48 2025
     14%% Update Count     : 6677
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    345345
    346346\begin{cquote}
     347\setlength{\tabcolsep}{5pt}
    347348\begin{tabular}{@{}l|ll@{}}
    348349\begin{uC++}
    349350
    350351
    351 void main() {
     352void Coroutine::main() {
    352353        try {
    353354                _Enable {
     
    357358          catch( E & ) { ... }
    358359}
     360void Coroutine::mem() { resume(); }
    359361\end{uC++}
    360362&
     
    362364#define resumePoll( coroutine ) resume( coroutine ); poll()
    363365#define suspendPoll suspend; poll()
    364 void main() {
     366void main( Coroutine & cor ) {
    365367        try {
    366368                enable_ehm();
     
    370372          catch( E & ) { ... }
    371373}
     374void mem( Coroutine & cor ) { resumePoll(); }
    372375\end{cfa}
    373376\end{tabular}
     
    429432\end{tabular}
    430433\end{cquote}
     434
     435
     436\section{Time}
     437
     438\begin{cquote}
     439\setlength{\tabcolsep}{5pt}
     440\begin{tabular}{@{}l|l@{}}
     441\begin{uC++}
     442
     443uTime start = uClock::currTime();
     444...
     445cout << "duration " << uClock::currTime() - start
     446        << " sec." << endl;
     447\end{uC++}
     448&
     449\begin{cfa}
     450#include <clock.hfa>
     451Time start = timeHiRes(); // time with nanoseconds
     452...
     453sout | "duration " | timeHiRes() - start | " sec.";
     454
     455\end{cfa}
     456\end{tabular}
     457\end{cquote}
     458
     459
     460\section{Constructor / Destructor}
     461
     462A constructor/destructor must have its structure type as the first parameter and be a reference.
     463\begin{cquote}
     464\begin{tabular}{@{}l|l@{}}
     465\begin{uC++}
     466
     467struct S {
     468        int i, j;
     469        @S@() { i = j = 3; }
     470        @S@( int i, int j ) { S::i = i; S::j = j; }
     471        @S@( const S & s ) { *this = s; }
     472        @~S@() {}
     473};
     474S s0, s1 = { 1, 2 };
     475
     476S * s2 = new S{ 1, 2 };   delete s2;
     477s2 = new S{ 1, 2 };   delete s2;
     478S & s3 = *new S{ 1, 2 };   delete &s3;
     479s3 = *new S{ 1, 2 };   delete &s3;
     480\end{uC++}
     481&
     482\begin{cfa}
     483#include <stdlib.hfa> // new (malloc)
     484struct S { int i, j; };
     485
     486void @?{}@( @S & s@ ) { s.i = s.j = 3; } $\C[3in]{// default}$
     487void @?{}@( @S & s@, int i, int j ) { s.i = i; s.j = j; } $\C{// initializer}$
     488void @?{}@( @S & s@, const S rhs ) { ?{}( s, rhs.i, rhs.j ); } $\C{// copy}$
     489void @^?{}@( @S & s@ ) { s.i = 0; s.j = 0; } $\C{// destructor}\CRT$
     490
     491S s0, s1 = { 1, 2 };
     492// bug, cannot use 0/1 (zero_t/one_t) with "new"
     493S * s2 = new( 0@n@, 2 );   /* suffix n => (natural int) */  delete( s2 );
     494s2 = new( 1@n@, 2 );   delete( s2 );
     495S & s3 = *new( 2, 2 );   delete( &s3 );
     496&s3 = &*new( 3, 2 );   delete( &s3 );
     497\end{cfa}
     498\end{tabular}
     499\end{cquote}
     500
     501
     502\section{\texorpdfstring{Structures (object-oriented \protect\vs routine style)}{Structures (object-oriented vs. routine style)}}
     503
     504\CFA is NOT an object-oriented programming-language, so there is no receiver (\lstinline[language=c++]{this}) or nested structure routines.
     505The equivalent of a \emph{member} routine has an explicit structure parameter in any parameter position (often the first).
     506\begin{cquote}
     507\begin{tabular}{@{}l|l@{}}
     508\begin{uC++}
     509struct S {
     510        int i = 0;  // cheat, implicit default constructor
     511        int setter( int j ) { int t = i; i = j; return t; }
     512        int getter() { return i; }
     513};
     514S s;
     515@s.@setter( 3 );  // object calls
     516int k = @s.@getter();
     517\end{uC++}
     518&
     519\begin{cfa}
     520struct S {  int i;  };
     521void ?{}( S & s ) { s.i = 0; } // explicit default constructor
     522int setter( @S & s,@ int j ) @with( s )@ { int t = i; i = j; return t; }
     523int getter( @S & s@ ) @with( s )@ { return i; }
     524
     525S s;
     526setter( @s,@ 3 );  // normal calls
     527int k = getter( @s@ );
     528\end{cfa}
     529\end{tabular}
     530\end{cquote}
     531Aggregate qualification is reduced or eliminated by opening scopes using the @with@ clause.
     532\begin{cfa}
     533struct S { int i; int j; double m; };  // field i has same type in structures S and T
     534struct T { int i; int k; int m; };
     535void foo( S s, T t ) @with( s, t )@ {   // open structure scope s and t in parallel
     536        j + k;                          $\C[1.6in]{// unambiguous, s.j + t.k}$
     537        m = 5.0;                        $\C{// unambiguous, s.m = 5.0}$
     538        m = 1;                          $\C{// unambiguous, t.m = 1}$
     539        int a = m;                      $\C{// unambiguous, a = t.m}$
     540        double b = m;           $\C{// unambiguous, b = s.m}$
     541        int c = s.i + t.i;      $\C{// unambiguous with qualification}$
     542        (double)m;                      $\C{// unambiguous with cast s.m}\CRT$
     543}
     544\end{cfa}
     545\noindent
     546In subsequent code examples, the left example is \CC/\uC and the right example is \CFA.
    431547
    432548
     
    474590
    475591
     592\enlargethispage{1000pt}
    476593\section{\texorpdfstring{\lstinline{uArray}}{uArray}}
    477594
     
    525642\end{cquote}
    526643
    527 
    528 \section{\texorpdfstring{Structures (object-oriented \protect\vs routine style)}{Structures (object-oriented vs. routine style)}}
    529 
    530 \CFA is NOT an object-oriented programming-language, so there is no receiver (\lstinline[language=c++]{this}) or nested structure routines.
    531 The equivalent of a \emph{member} routine has an explicit structure parameter in any parameter position (often the first).
    532 \begin{cquote}
    533 \begin{tabular}{@{}l|l@{}}
     644\newpage
     645
     646
     647\section{Doubly-Linked Intrusive List}
     648
     649\begin{cquote}
     650\setlength{\tabcolsep}{10pt}
     651\begin{tabular}{@{}l|l@{}}
     652\begin{uC++}
     653#include <iostream>
     654using namespace std;
     655struct Node : @public uSeqable@ {
     656        int i;
     657        Node( int i ) : i( i ) {}
     658};
     659
     660
     661int main() {
     662        @uSequence<Node> dlist;@
     663        Node n1{ 1 }, n2{ 2 }, n3{ 3 };
     664        dlist.addTail( &n1 );
     665        dlist.addHead( &n2 );  // out of order
     666        dlist.insertAft( &n1, &n3 );  // insertBef
     667        for ( Node * it = dlist.head(); it; it = dlist.succ( it ) ) {
     668                cout << it->i << endl;
     669        }
     670        dlist.remove( &n3 );  // shorten list
     671        dlist.dropTail();  // dropHead
     672        Node * it;
     673        for ( uSeqIter<Node> seqit(dlist);  // uSeqIterRev
     674                          seqit >> it; ) {
     675                cout << it->i << endl;
     676        }
     677}
     678\end{uC++}
     679&
     680\begin{cfa}
     681#include <fstream.hfa>
     682#include <list.hfa>
     683struct Node {
     684        @inline dlink( Node );@
     685        int i;
     686};
     687@P9_EMBEDDED( Node, dlink( Node ) );@  // magic
     688void ?{}( Node & node, int i ) { node.i = i; }
     689int main() {
     690        @dlist( Node ) dlist;@
     691        Node n1{ 1 }, n2{ 2 }, n3{ 3 };
     692        insert_last( dlist, n1 );
     693        insert_first( dlist, n2 );  // out of order
     694        insert_after( n1, n3 );  // insert_before
     695        for ( Node & it = first( dlist ); &it; &it = &next( it ) ) {
     696                sout | it.i;
     697        }
     698        remove( n3 );  // shorten list
     699        remove_last( dlist );  // remove_first
     700
     701        FOREACH( dlist, it ) {  // FOREACH_REV
     702
     703                sout | it.i;
     704        }
     705}
     706\end{cfa}
     707\end{tabular}
     708\end{cquote}
     709
     710
     711\section{RAII Dynamic Allocation}
     712
     713\begin{cquote}
     714\begin{tabular}{@{}l|ll@{}}
    534715\begin{uC++}
    535716struct S {
    536         int i = 0;  // cheat, implicit default constructor
    537         int setter( int j ) { int t = i; i = j; return t; }
    538         int getter() { return i; }
    539 };
    540 S s;
    541 @s.@setter( 3 );  // object calls
    542 int k = @s.@getter();
    543 \end{uC++}
    544 &
    545 \begin{cfa}
    546 struct S {  int i;  };
    547 void ?{}( S & s ) { s.i = 0; } // explicit default constructor
    548 int setter( @S & s,@ int j ) @with( s )@ { int t = i; i = j; return t; }
    549 int getter( @S & s@ ) @with( s )@ { return i; }
    550 
    551 S s;
    552 setter( @s,@ 3 );  // normal calls
    553 int k = getter( @s@ );
    554 \end{cfa}
    555 \end{tabular}
    556 \end{cquote}
    557 Aggregate qualification is reduced or eliminated by opening scopes using the @with@ clause.
    558 \begin{cfa}
    559 struct S { int i; int j; double m; };  // field i has same type in structures S and T
    560 struct T { int i; int k; int m; };
    561 void foo( S s, T t ) @with( s, t )@ {   // open structure scope s and t in parallel
    562         j + k;                          $\C[1.6in]{// unambiguous, s.j + t.k}$
    563         m = 5.0;                        $\C{// unambiguous, s.m = 5.0}$
    564         m = 1;                          $\C{// unambiguous, t.m = 1}$
    565         int a = m;                      $\C{// unambiguous, a = t.m}$
    566         double b = m;           $\C{// unambiguous, b = s.m}$
    567         int c = s.i + t.i;      $\C{// unambiguous with qualification}$
    568         (double)m;                      $\C{// unambiguous with cast s.m}\CRT$
    569 }
    570 \end{cfa}
    571 \noindent
    572 In subsequent code examples, the left example is \CC/\uC and the right example is \CFA.
    573 
    574 
    575 \section{Constructor / Destructor}
    576 
    577 A constructor/destructor must have its structure type as the first parameter and be a reference.
    578 \begin{cquote}
    579 \begin{tabular}{@{}l|l@{}}
    580 \begin{uC++}
    581 
    582 struct S {
    583         int i, j;
    584         @S@() { i = j = 3; }
    585         @S@( int i, int j ) { S::i = i; S::j = j; }
    586         @S@( const S & s ) { *this = s; }
    587         @~S@() {}
    588 };
    589 S s0;
    590 S s1 = { 1, 2 };
    591 
    592 S * s2 = new S{ 1, 2 };
    593 delete s2;
    594 s2 = new S{ 1, 2 };
    595 delete s2;
    596 S & s3 = *new S{ 1, 2 };
    597 delete &s3;
    598 s3 = *new S{ 1, 2 };
    599 delete &s3;
    600 \end{uC++}
    601 &
    602 \begin{cfa}
    603 #include <stdlib.hfa> // new (malloc)
    604 struct S { int i, j; };
    605 
    606 void @?{}@( @S & s@ ) { s.i = s.j = 3; } $\C[3in]{// default}$
    607 void @?{}@( @S & s@, int i, int j ) { s.i = i; s.j = j; } $\C{// initializer}$
    608 void @?{}@( @S & s@, const S rhs ) { ?{}( s, rhs.i, rhs.j ); } $\C{// copy}$
    609 void @^?{}@( @S & s@ ) { s.i = 0; s.j = 0; } $\C{// destructor}\CRT$
    610 
    611 S s0;
    612 S s1 = { 1, 2 };
    613 // bug, cannot use 0/1 (zero_t/one_t) with "new"
    614 S * s2 = new( 0@n@, 2 ); // suffix n => (natural int)
    615 delete( s2 );
    616 s2 = new( 1@n@, 2 );
    617 delete( s2 );
    618 S & s3 = *new( 2, 2 );
    619 delete( &s3 );
    620 &s3 = &*new( 3, 2 );
    621 delete( &s3 );
     717        ...    S() { ... }    ~S() { ... }   // ctor / dtor
     718};
     719S * s = new S;             delete s;
     720S * sa = new S[10];     delete [] sa;
     721\end{uC++}
     722&
     723\begin{cfa}
     724#include <stdlib.hfa>
     725struct S { ... };
     726void ?{}( S & ) { ... }    void ^?{}( S & ) { ... }   // ctor / dtor
     727S * s = new();        delete( s );
     728S * sa = anew( 10 );    adelete( sa );
    622729\end{cfa}
    623730\end{tabular}
     
    660767}
    661768\end{cfa}
    662 \\
    663 \multicolumn{2}{@{}l@{}}{\lstinline{C c;}}
    664769\end{tabular}
    665770\end{cquote}
     
    708813
    709814\begin{cquote}
     815\setlength{\tabcolsep}{10pt}
    710816\begin{tabular}{@{}l|ll@{}}
    711817\begin{uC++}
     
    738844}
    739845\end{cfa}
    740 \end{tabular}
    741 \begin{tabular}{@{}l|ll@{}}
     846\\
    742847\begin{uC++}
    743848_Actor Hello { ${\color{red}\LstCommentStyle{// : public uActor}}$
     
    829934
    830935uOwnerLock m;
    831 uCondLock s;
     936uCondLock c;
    832937m.acquire();
    833 if ( ! s.empty() ) s.wait( m );
     938if ( ! c.empty() ) c.wait( m );
    834939else {
    835940        m.release();
     
    841946#include <locks.hfa>
    842947owner_lock m;
    843 cond_lock( owner_lock ) s;  // generic type on mutex lock
     948cond_lock( owner_lock ) c;  // generic type on mutex lock
    844949lock( m );
    845 if ( ! empty( s ) ) wait( s, m );
     950if ( ! empty( c ) ) wait( c, m );
    846951else {
    847952        unlock( m );
     
    852957\end{cquote}
    853958
     959\begin{cquote}
     960\begin{tabular}{@{}l|ll@{}}
     961\begin{uC++}
     962
     963uSemaphore m, c;
     964m.P();
     965if ( ! c.empty() ) c.P( m );
     966else {
     967        m.V();
     968}
     969\end{uC++}
     970&
     971\begin{cfa}
     972#include <locks.hfa>
     973semaphore m, c;
     974P( m );
     975if ( ! empty( c ) ) P( c, m );
     976else {
     977        V( m );
     978}
     979\end{cfa}
     980\end{tabular}
     981\end{cquote}
     982
     983
     984\enlargethispage{1000pt}
    854985
    855986\section{Barrier}
     
    8881019#include <mutex_stmt.hfa>
    8891020struct Barrier {
    890         @barrier b;@                    // containment
     1021        @inline barrier;@
    8911022        int total;
    8921023
    8931024};
    894 void ?{}( Barrier & B, unsigned int group ) with(B) {
    895         @?{}( b, group );@              // initialize barrier
     1025void ?{}( Barrier & b, unsigned int group ) with( b ) {
     1026        @(b){ group };@         // initialize barrier
    8961027        total = 0;
    8971028}
    898 unsigned int block( Barrier & B, int subtotal ) with(B) {
    899         void @last@() { sout | total; } // called by Gth arriving thread
     1029unsigned int block( Barrier & b, int subtotal ) with( b ) {
     1030        void @last@(...) { sout | total; }      // called by Gth arriving thread
    9001031        @mutex( b )@ {  // use barrier's mutual exclusion
    9011032                total += subtotal;
     
    9091040\end{cquote}
    9101041
     1042\newpage
    9111043
    9121044\enlargethispage{1000pt}
     
    9161048Internal Scheduling
    9171049\begin{cquote}
     1050\setlength{\tabcolsep}{5pt}
    9181051\begin{tabular}{@{}l|ll@{}}
    9191052\begin{uC++}
     
    9791112\end{cquote}
    9801113
    981 \newpage
     1114\bigskip
    9821115\noindent
    9831116External Scheduling
    9841117\begin{cquote}
     1118\setlength{\tabcolsep}{5pt}
    9851119\begin{tabular}{@{}l|ll@{}}
    9861120\begin{uC++}
     
    10391173
    10401174
    1041 \input{uC++toCFA.ind}
     1175\newpage
     1176
     1177\section{Futures (reference counting)}
     1178
     1179
     1180{\lstset{tabsize=3}
     1181\setlength{\tabcolsep}{5pt}
     1182\begin{tabular}{@{}l|ll@{}}
     1183\begin{uC++}
     1184#include <uFuture.h>
     1185@Future_ISM@<int> fi;
     1186@Future_ISM@<double> fd;
     1187struct Msg { int i, j; }; @Future_ISM@<Msg> fm;
     1188struct Stop {}; @Future_ISM@<Stop> fs;
     1189struct Cont {}; @Future_ISM@<Cont> fc;
     1190
     1191_Task Worker {
     1192        void main() {
     1193
     1194                for ( ;; ) {
     1195                        _Select( fi ) { cout << fi() << endl; fi.reset(); }
     1196                        and _Select( fd ) { cout << fd() << endl; fd.reset(); }
     1197                        and _Select( fm ) {
     1198                                cout << fm().i << " " << fm().j << endl; fm.reset();
     1199                        } or _Select( fs ) { cout << "stop" << endl; break; }
     1200                        fc.delivery( (Cont){} );        // synchronize
     1201                }
     1202        }
     1203
     1204};
     1205int main() {
     1206        Worker worker;
     1207        for ( int i = 0; i < 10; i += 1 ) {
     1208                fi( i );   fd( i + 2.5 );   fm( (Msg){ i, 2 } ); // fulfil
     1209                fc(); fc.reset();                               // synchronize
     1210        }
     1211        fs( (Stop){} );
     1212} // wait for worker to terminate
     1213\end{uC++}
     1214&
     1215\begin{cfa}
     1216#include <future.hfa>
     1217@future_rc@(int) fi;
     1218@future_rc@(double) fd;
     1219struct Msg { int i, j; }; @future_rc@(Msg) fm;
     1220struct Stop {}; @future_rc@(Stop) fs;
     1221struct Cont {}; @future_rc@(Cont) fc;
     1222ExceptionDecl( Break );
     1223thread Worker {};
     1224void main( Worker & ) {
     1225        try {
     1226                for () {
     1227                        waituntil( fi ) { sout | fi(); reset( fi ); }
     1228                        and waituntil( fd ) { sout | fd(); reset( fd ); }
     1229                        and waituntil( fm ) { sout | fm().i | fm().j; reset( fm ); }
     1230                        or waituntil( fs ) { sout | "stop";
     1231                                throw ExceptionInst( Break );
     1232                        }
     1233                        fc( (Cont){} );         // synchronize
     1234                }
     1235        } catch( Break * ) {}
     1236}
     1237int main() {
     1238        Worker worker;
     1239        for ( i; 10 ) {
     1240                fi( i );   fd( i + 2.5 );   fm( (Msg){ i, 2 } ); // fulfil
     1241                fc(); reset( fc );              // synchronize
     1242        }
     1243        fs( (Stop){} );
     1244} // wait for worker to terminate
     1245\end{cfa}
     1246\end{tabular}
     1247}%
     1248
     1249%\input{uC++toCFA.ind}
    10421250
    10431251% \bibliographystyle{plain}
  • libcfa/src/bits/defs.hfa

    r8f448e0 r5e0b6657  
    1313// Created On       : Thu Nov  9 13:24:10 2017
    1414// Last Modified By : Peter A. Buhr
    15 // Last Modified On : Sat Oct 24 10:53:15 2020
    16 // Update Count     : 21
     15// Last Modified On : Mon Oct 27 22:40:05 2025
     16// Update Count     : 23
    1717//
    1818
     
    2525#define unlikely(x) __builtin_expect(!!(x), 0)
    2626
    27 typedef void (*fptr_t)();
     27typedef void (* fptr_t)();
    2828typedef int_fast16_t __lock_size_t;
    2929
  • libcfa/src/bits/weakso_locks.cfa

    r8f448e0 r5e0b6657  
    2828void on_wakeup( blocking_lock &, size_t ) {}
    2929size_t wait_count( blocking_lock & ) { return 0; }
    30 bool register_select( blocking_lock & this, select_node & node ) { return false; }
    31 bool unregister_select( blocking_lock & this, select_node & node ) { return false; }
    32 bool on_selected( blocking_lock & this, select_node & node ) { return true; }
     30bool register_select$( blocking_lock & this, select_node & node ) { return false; }
     31bool unregister_select$( blocking_lock & this, select_node & node ) { return false; }
     32bool on_selected$( blocking_lock & this, select_node & node ) { return true; }
    3333
  • libcfa/src/bits/weakso_locks.hfa

    r8f448e0 r5e0b6657  
    5959void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD;
    6060size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD;
    61 bool register_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    62 bool unregister_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    63 bool on_selected( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     61bool register_select$( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     62bool unregister_select$( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     63bool on_selected$( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    6464blocking_lock __CFA_select_get_type( blocking_lock this ) OPTIONAL_THREAD;
    6565
     
    7878static inline void   on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    7979static inline void   on_notify( multiple_acquisition_lock & this, struct thread$ * t ){ on_notify( (blocking_lock &)this, t ); }
    80 static inline bool   register_select( multiple_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    81 static inline bool   unregister_select( multiple_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    82 static inline bool   on_selected( multiple_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
     80static inline bool   register_select$( multiple_acquisition_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); }
     81static inline bool   unregister_select$( multiple_acquisition_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); }
     82static inline bool   on_selected$( multiple_acquisition_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); }
    8383multiple_acquisition_lock __CFA_select_get_type( multiple_acquisition_lock this );
  • libcfa/src/concurrency/barrier.hfa

    r8f448e0 r5e0b6657  
    1111// Created On       : Sun Nov 10 08:07:35 2024
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Thu Apr 24 22:41:11 2025
    14 // Update Count     : 12
     13// Last Modified On : Fri Oct 31 09:22:14 2025
     14// Update Count     : 69
    1515//
    1616
    1717#pragma once
    1818
     19#include <locks.hfa>
    1920#include <monitor.hfa>
    2021
    2122// Plan 9 inheritance does not work with monitors. Two monitor locks are created.
    2223
     24typedef void (* barrier_fptr_t)( ... );                                 // like C++, () => void and ... => C ()
     25
    2326monitor barrier {
    24         unsigned int group, arrivals;                                           // group size, arrival counter
    25         condition c;                                                                            // wait for group to form
     27        size_t group$, arrivals$;                                                       // group size, arrival counter (backward)
     28        condition c$;                                                                           // wait for group to form
     29        barrier_fptr_t callback$;                                                       // global callback
     30        void * arg$;                                                                            // global callback argument
    2631};
    2732
    28 static inline void ?{}( barrier & b, unsigned int group ) {
    29         b.group = b.arrivals = group;                                           // arrivals count backward
     33static inline void ?{}( barrier & b, ssize_t group, barrier_fptr_t callback, void * arg ) with ( b ) {
     34        [group$, arrivals$] = group;
     35        [callback$, arg$] = [callback, arg];
    3036}
    3137
    32 // Returns a value indicating the reverse order the threads arrived, i.e. last thread returns 0 (and does not block)
    33 // hook is an optional hook that is called by the Gth thread before unblocking the other threads.
    34 static inline unsigned int block( barrier & mutex b, fptr_t hook = (fptr_t)0 ) with( b ) {
    35         arrivals -= 1;                                                                          // prefix decrement so last is 0 not 1
    36         unsigned arrived = b.arrivals;                                          // note arrival order
    37         if ( arrivals != 0 ) {                                                          // wait for group to form
    38                 wait( b.c );
     38static inline void ?{}( barrier & b, ssize_t group ) { (b){ group, 0p, 0p }; }  // call base constructor
     39static inline ssize_t waiters( barrier & b ) with( b ) { return group$ - arrivals$; }
     40static inline ssize_t total( barrier & b ) with( b ) { return group$; }
     41
     42// Returns a value indicating the reverse order the threads arrived, i.e., the Gth thread returns 0 (and does not
     43// block).  olock is an optional mutex lock held by the called and atomically released and block. callback is an
     44// optional function that is called by the Gth thread before unblocking the other threads. arg is an optional (void *)
     45// argument passed to the callback.
     46
     47// Barrier is a monitor => implicit mutual exclusion.
     48static inline ssize_t block( barrier & mutex b, owner_lock & olock, barrier_fptr_t callback, void * arg ) with( b ) {
     49        arrivals$ -= 1;                                                                         // prefix decrement so last is 0 not 1
     50        typeof( arrivals$ ) arrived = arrivals$;                        // note arrival order
     51        if ( arrivals$ != 0 ) {                                                         // wait for group to form
     52                if ( &olock != 0p ) unlock( olock );                    // if lock specified, release it
     53                wait( c$ );
     54                // DO NOT REACQUIRE LOCK TO ALLOW BARGING PREVENTION
    3955        } else {                                                                                        // group formed
    40                 if ( hook ) hook();                                                             // safe to call
    41                 signal_all( c );                                                                // unblock group
    42                 arrivals = group;                                                               // reset
     56                if ( callback ) callback( arg );                                // if callback specified, safe to call with argument
     57                else if ( callback$ ) callback$( arg$ );                // if callback specified, safe to call with argument
     58                signal_all( c$ );                                                               // unblock group
     59                arrivals$ = group$;                                                             // reset
    4360        } // if
    4461        return arrived;                                                                         // return arrival order
    4562}
     63
     64static inline ssize_t block( barrier & b ) { return block( b, *0p, 0p, 0p ); }
     65static inline ssize_t block( barrier & b, owner_lock & olock ) { return block( b, olock, 0p, 0p ); }
     66static inline ssize_t block( barrier & b, barrier_fptr_t callback ) { return block( b, *0p, callback, 0p ); }
     67static inline ssize_t block( barrier & b, barrier_fptr_t callback, void * arg ) { return block( b, *0p, callback, arg ); }
     68static inline ssize_t block( barrier & b, owner_lock & olock, barrier_fptr_t callback ) { return block( b, olock, callback, 0p ); }
  • libcfa/src/concurrency/channel.hfa

    r8f448e0 r5e0b6657  
    411411        }
    412412
    413         bool register_select( chan_read(T) & this, select_node & node ) with(*this.chan, this) {
     413        bool register_select$( chan_read(T) & this, select_node & node ) with(*this.chan, this) {
    414414            lock( mutex_lock );
    415415            node.extra = ret; // set .extra so that if it == 0p later in on_selected it is due to channel close
     
    476476            return true;
    477477        }
    478         bool unregister_select( chan_read(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
    479         bool on_selected( chan_read(T) & this, select_node & node ) with(this) {
     478        bool unregister_select$( chan_read(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
     479        bool on_selected$( chan_read(T) & this, select_node & node ) with(this) {
    480480            if ( unlikely(node.extra == 0p) ) {
    481481                if ( ! exception_in_flight() ) __closed_remove( *chan, *ret ); // check if woken up due to closed channel
     
    491491
    492492        chan_read_no_ret(T) remove( channel(T) & chan ) { chan_read_no_ret(T) c_read{ chan }; return c_read; }
    493         bool register_select( chan_read_no_ret(T) & this, select_node & node ) {
     493        bool register_select$( chan_read_no_ret(T) & this, select_node & node ) {
    494494            this.c_read.ret = &this.retval;
    495             return register_select( this.c_read, node );
    496         }
    497         bool unregister_select( chan_read_no_ret(T) & this, select_node & node ) { return unregister_select( this.c_read, node ); }
    498         bool on_selected( chan_read_no_ret(T) & this, select_node & node ) { return on_selected( this.c_read, node ); }
     495            return register_select$( this.c_read, node );
     496        }
     497        bool unregister_select$( chan_read_no_ret(T) & this, select_node & node ) { return unregister_select$( this.c_read, node ); }
     498        bool on_selected$( chan_read_no_ret(T) & this, select_node & node ) { return on_selected$( this.c_read, node ); }
    499499
    500500        void ?{}( chan_write(T) & cw, channel(T) * chan, T elem ) {
     
    511511        }
    512512
    513         bool register_select( chan_write(T) & this, select_node & node ) with(*this.chan, this) {
     513        bool register_select$( chan_write(T) & this, select_node & node ) with(*this.chan, this) {
    514514            lock( mutex_lock );
    515515            node.extra = &elem; // set .extra so that if it == 0p later in on_selected it is due to channel close
     
    577577                return true;
    578578        }
    579         bool unregister_select( chan_write(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
    580 
    581         bool on_selected( chan_write(T) & this, select_node & node ) with(this) {
     579        bool unregister_select$( chan_write(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
     580
     581        bool on_selected$( chan_write(T) & this, select_node & node ) with(this) {
    582582                if ( unlikely(node.extra == 0p) ) {
    583583                        if ( ! exception_in_flight() ) __closed_insert( *chan, elem ); // check if woken up due to closed channel
  • libcfa/src/concurrency/future.hfa

    r8f448e0 r5e0b6657  
    77// concurrency/future.hfa --
    88//
    9 // Author           : Thierry Delisle & Peiran Hong & Colby Parsons
     9// Author           : Thierry Delisle & Peiran Hong & Colby Parsons & Peter Buhr
    1010// Created On       : Wed Jan 06 17:33:18 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 23 22:41:10 2025
    13 // Update Count     : 22
     12// Last Modified On : Mon Nov 24 16:08:52 2025
     13// Update Count     : 222
    1414//
    1515
     
    2121#include "locks.hfa"
    2222
    23 //----------------------------------------------------------------------------
    24 // future
    25 // I don't use future_t here as I need to use a lock for this future since it supports multiple consumers.
    26 // future_t is lockfree and uses atomics which aren't needed given we use locks here
     23//--------------------------------------------------------------------------------------------------------
     24// future does not use future_t as it needs a lock to support multiple consumers.  future_t is lockfree
     25// and uses atomics which are not needed.
     26//--------------------------------------------------------------------------------------------------------
     27
    2728forall( T ) {
    28         enum { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 };
     29        // PRIVATE
     30
     31        struct future_node$ {
     32                inline select_node;
     33                T * my_result;
     34        };
     35
     36        static inline {
     37                // memcpy wrapper to help copy values
     38                void copy_T$( T & to, T & from ) { memcpy( (void *)&to, (void *)&from, sizeof(T) ); }
     39        } // distribution
     40
     41        enum { FUTURE_EMPTY$ = 0, FUTURE_FULFILLED$ = 1 };
     42
     43        // PUBLIC
    2944
    3045        struct future {
     
    3247                T result;
    3348                exception_t * except;
     49                futex_mutex lock;
    3450                dlist( select_node ) waiters;
    35                 futex_mutex lock;
    3651        };
    37         __CFA_SELECT_GET_TYPE( future(T) );
    38 
    39         struct future_node {
    40                 inline select_node;
    41                 T * my_result;
    42         };
    43 
    44         static inline {
    45 
    46                 void ?{}( future_node(T) & this, thread$ * blocked_thread, T * my_result ) {
    47                         ((select_node &)this){ blocked_thread };
    48                         this.my_result = my_result;
    49                 }
    50 
    51                 void ?{}( future(T) & this ) {
    52                         this.waiters{};
    53                         this.except = 0p;
    54                         this.state = FUTURE_EMPTY;
    55                         this.lock{};
    56                 }
    57 
    58                 void ^?{}( future(T) & this ) {
    59                         free( this.except );
    60                 }
    61 
    62                 // Reset future back to original state
    63                 void reset( future(T) & this ) with(this) {
    64                         lock( lock );
    65                         if ( ! isEmpty( waiters ) )
    66                                 abort("Attempting to reset a future with blocked waiters");
    67                         state = FUTURE_EMPTY;
     52        __CFA_SELECT_GET_TYPE( future(T) );                                     // magic
     53
     54        static inline {
     55                // PRIVATE
     56
     57                bool register_select$( future(T) & fut, select_node & s ) with( fut ) { // for waituntil statement
     58                        lock( lock );
     59
     60                        // check if we can complete operation. If so race to establish winner in special OR case
     61                        if ( !s.park_counter && state != FUTURE_EMPTY$ ) {
     62                                if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering
     63                                        unlock( lock );
     64                                        return false;
     65                                }
     66                        }
     67
     68                        // future not ready -> insert select node and return
     69                  if ( state == FUTURE_EMPTY$ ) {
     70                                insert_last( waiters, s );
     71                                unlock( lock );
     72                                return false;
     73                        }
     74
     75                        __make_select_node_available( s );
     76                        unlock( lock );
     77                        return true;
     78                }
     79
     80                bool unregister_select$( future(T) & fut, select_node & s ) with( fut ) { // for waituntil statement
     81                  if ( ! isListed( s ) ) return false;
     82                        lock( lock );
     83                        if ( isListed( s ) ) remove( s );
     84                        unlock( lock );
     85                        return false;
     86                }
     87
     88                bool on_selected$( future(T) &, select_node & ) { return true; } // for waituntil statement
     89
     90                // PUBLIC
     91
     92                // General
     93
     94                void ?{}( future_node$(T) & fut, thread$ * blocked_thread, T * my_result ) {
     95                        ((select_node &)fut){ blocked_thread };
     96                        fut.my_result = my_result;
     97                }
     98
     99                void ?{}( future(T) & fut ) with( fut ) {
     100                        except = 0p;
     101                        state = FUTURE_EMPTY$;
     102                }
     103
     104                void ^?{}( future(T) & fut ) with( fut ) {
    68105                        free( except );
    69                         except = 0p;
    70                         unlock( lock );
    71                 }
    72 
    73                 // check if the future is available
    74                 // currently no mutual exclusion because I can't see when you need this call to be synchronous or protected
    75                 bool available( future(T) & this ) { return __atomic_load_n( &this.state, __ATOMIC_RELAXED ); }
    76 
    77 
    78                 // memcpy wrapper to help copy values
    79                 void copy_T( T & from, T & to ) {
    80                         memcpy((void *)&to, (void *)&from, sizeof(T));
    81                 }
    82 
    83                 bool fulfil$( future(T) & this ) with(this) {   // helper
    84                         bool ret_val = ! isEmpty( waiters );
    85                         state = FUTURE_FULFILLED;
    86                         while ( ! isEmpty( waiters ) ) {
    87                                 if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case
    88                                         break; // if handle_OR returns false then waiters is empty so break
    89                                 select_node &s = remove_first( waiters );
    90 
    91                                 if ( s.clause_status == 0p )                    // poke in result so that woken threads do not need to reacquire any locks
    92                                         copy_T( result, *(((future_node(T) &)s).my_result) );
    93 
    94                                 wake_one( waiters, s );
    95                         }
    96                         unlock( lock );
    97                         return ret_val;
    98                 }
    99 
    100                 // Fulfil the future, returns whether or not someone was unblocked
    101                 bool fulfil( future(T) & this, T val ) with(this) {
    102                         lock( lock );
    103                         if ( state != FUTURE_EMPTY )
    104                                 abort("Attempting to fulfil a future that has already been fulfilled");
    105 
    106                         copy_T( val, result );
    107                         return fulfil$( this );
    108                 }
    109 
    110                 bool ?()( future(T) & this, T val ) {                   // alternate interface
    111                         return fulfil( this, val );
    112                 }
    113 
    114                 // Load an exception to the future, returns whether or not someone was unblocked
    115                 bool fulfil( future(T) & this, exception_t * ex ) with(this) {
    116                         lock( lock );
    117                         if ( state != FUTURE_EMPTY )
    118                                 abort("Attempting to fulfil a future that has already been fulfilled");
    119 
    120                         except = ( exception_t * ) malloc( ex->virtual_table->size );
    121                         ex->virtual_table->copy( except, ex );
    122                         return fulfil$( this );
    123                 }
    124 
    125                 bool ?()( future(T) & this, exception_t * ex ) { // alternate interface
    126                         return fulfil( this, ex );
    127                 }
    128 
    129                 // Wait for the future to be fulfilled
    130                 // Also return whether the thread had to block or not
    131                 [T, bool] get( future(T) & this ) with( this ) {
     106                }
     107
     108                // Used by Client
     109
     110                // PRIVATE
     111
     112                // Return a value/exception from the future.
     113                T get$( future(T) & fut ) with( fut ) {                 // helper
    132114                        void exceptCheck() {                                            // helper
    133115                                if ( except ) {
     
    138120                                }
    139121                        }
    140 
    141                         lock( lock );
    142122                        T ret_val;
    143                         if ( state == FUTURE_FULFILLED ) {
     123
     124                        // LOCK ACQUIRED IN PUBLIC get
     125                        if ( state == FUTURE_FULFILLED$ ) {
    144126                                exceptCheck();
    145                                 copy_T( result, ret_val );
     127                                copy_T$( ret_val, result );
    146128                                unlock( lock );
    147                                 return [ret_val, false];
    148                         }
    149 
    150                         future_node(T) node = { active_thread(), &ret_val };
     129                                return ret_val;
     130                        }
     131
     132                        future_node$(T) node = { active_thread(), &ret_val };
    151133                        insert_last( waiters, ((select_node &)node) );
    152134                        unlock( lock );
    153135                        park( );
    154136                        exceptCheck();
    155 
    156                         return [ret_val, true];
    157                 }
    158 
    159                 // Wait for the future to be fulfilled
    160                 T get( future(T) & this ) {
    161                         [T, bool] tt;
    162                         tt = get(this);
    163                         return tt.0;
    164                 }
    165 
    166                 T ?()( future(T) & this ) {                                             // alternate interface
    167                         return get( this );
    168                 }
    169 
    170                 // Gets value if it is available and returns [ val, true ]
    171                 // otherwise returns [ default_val, false]
    172                 // will not block
    173                 [T, bool] try_get( future(T) & this ) with(this) {
     137                        return ret_val;
     138                }
     139
     140                // PUBLIC
     141
     142                bool available( future( T ) & fut ) { return __atomic_load_n( &fut.state, __ATOMIC_RELAXED ); } // future result available ?
     143
     144                // Return a value/exception from the future.
     145                [T, bool] get( future(T) & fut ) with( fut ) {
     146                        lock( lock );
     147                        bool ret = state == FUTURE_EMPTY$;
     148                        return [ get$( fut ), ret ];
     149                }
     150
     151                T get( future(T) & fut ) with( fut ) {
     152                        lock( lock );
     153                        return get$( fut );
     154                }
     155                T ?()( future(T) & fut ) { return get( fut ); } // alternate interface
     156
     157                // Non-blocking get: true => return defined value, false => value return undefined.
     158                [T, bool] try_get( future(T) & fut ) with( fut ) {
    174159                        lock( lock );
    175160                        T ret_val;
    176                         if ( state == FUTURE_FULFILLED ) {
    177                                 copy_T( result, ret_val );
     161                        if ( state == FUTURE_FULFILLED$ ) {
     162                                copy_T$( ret_val, result );
    178163                                unlock( lock );
    179164                                return [ret_val, true];
    180165                        }
    181166                        unlock( lock );
    182 
    183167                        return [ret_val, false];
    184168                }
    185169
    186                 bool register_select( future(T) & this, select_node & s ) with(this) {
    187                         lock( lock );
    188 
    189                         // check if we can complete operation. If so race to establish winner in special OR case
    190                         if ( !s.park_counter && state != FUTURE_EMPTY ) {
    191                                 if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering
    192                                         unlock( lock );
    193                                         return false;
    194                                 }
    195                         }
    196 
    197                         // future not ready -> insert select node and return
    198                         if ( state == FUTURE_EMPTY ) {
    199                                 insert_last( waiters, s );
    200                                 unlock( lock );
    201                                 return false;
    202                         }
    203 
    204                         __make_select_node_available( s );
    205                         unlock( lock );
    206                         return true;
    207                 }
    208 
    209                 bool unregister_select( future(T) & this, select_node & s ) with(this) {
    210                         if ( ! isListed( s ) ) return false;
    211                         lock( lock );
    212                         if ( isListed( s ) ) remove( s );
    213                         unlock( lock );
    214                         return false;
    215                 }
    216 
    217                 bool on_selected( future(T) &, select_node & ) { return true; }
    218         }
    219 }
    220 
    221 //--------------------------------------------------------------------------------------------------------
    222 // These futures below do not support select statements so they may not have as many features as 'future'
    223 //  however the 'single_future' is cheap and cheerful and is most likely more performant than 'future'
    224 //  since it uses raw atomics and no locks
    225 //
    226 // As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future'
    227 //  since it is monitor based and also is not compatible with select statements
     170                // Used by Server
     171
     172                // PRIVATE
     173
     174                bool fulfil$( future(T) & fut ) with( fut ) {   // helper
     175                        bool ret_val = ! isEmpty( waiters );
     176                        state = FUTURE_FULFILLED$;
     177                        while ( ! isEmpty( waiters ) ) {
     178                                if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case
     179                                        break; // if handle_OR returns false then waiters is empty so break
     180                                select_node &s = remove_first( waiters );
     181
     182                                if ( s.clause_status == 0p )                    // poke in result so that woken threads do not need to reacquire any locks
     183                                        copy_T$( *(((future_node$(T) &)s).my_result), result );
     184
     185                                wake_one( waiters, s );
     186                        }
     187                        unlock( lock );
     188                        return ret_val;
     189                }
     190
     191                // PUBLIC
     192
     193                // Load a value/exception into the future, returns whether or not waiting threads.
     194                bool fulfil( future(T) & fut, T val ) with( fut ) {
     195                        lock( lock );
     196                  if ( state != FUTURE_EMPTY$ ) abort("Attempting to fulfil a future that has already been fulfilled");
     197                        copy_T$( result, val );
     198                        return fulfil$( fut );
     199                }
     200                bool ?()( future(T) & fut, T val ) { return fulfil( fut, val ); } // alternate interface
     201
     202                bool fulfil( future(T) & fut, exception_t * ex ) with( fut ) {
     203                        lock( lock );
     204                  if ( state != FUTURE_EMPTY$ ) abort( "Attempting to fulfil a future that has already been fulfilled" );
     205                        except = ( exception_t * ) malloc( ex->virtual_table->size );
     206                        ex->virtual_table->copy( except, ex );
     207                        return fulfil$( fut );
     208                }
     209                bool ?()( future(T) & fut, exception_t * ex ) { return fulfil( fut, ex ); } // alternate interface
     210
     211                void reset( future(T) & fut ) with( fut ) {             // mark future as empty (for reuse)
     212                        lock( lock );
     213                  if ( ! isEmpty( waiters ) ) abort( "Attempting to reset a future with blocked waiters" );
     214                        state = FUTURE_EMPTY$;
     215                        free( except );
     216                        except = 0p;
     217                        unlock( lock );
     218                }
     219        } // static inline
     220} // forall( T )
     221
     222//--------------------------------------------------------------------------------------------------------
     223// future_rc uses reference counting to eliminate explicit storage-management and support the waituntil
     224// statement.
    228225//--------------------------------------------------------------------------------------------------------
    229226
    230227forall( T ) {
     228        // PRIVATE
     229
     230        struct future_rc_impl$ {
     231                futex_mutex lock;                                                               // concurrent protection
     232                size_t refCnt;                                                                  // number of references to future
     233                future(T) fut;                                                                  // underlying future
     234        }; // future_rc_impl$
     235
     236        static inline {
     237                size_t incRef$( future_rc_impl$( T ) & impl ) with( impl ) {
     238                        return __atomic_fetch_add( &refCnt, 1, __ATOMIC_SEQ_CST );
     239                } // incRef$
     240
     241                size_t decRef$( future_rc_impl$( T ) & impl ) with( impl ) {
     242                        return __atomic_fetch_add( &refCnt, -1, __ATOMIC_SEQ_CST );
     243                } // decRef$
     244
     245                void ?{}( future_rc_impl$( T ) & frc ) with( frc ) {
     246                        refCnt = 1;                                                                     // count initial object
     247                } // ?{}
     248        } // static inline
     249       
     250        // PUBLIC
     251
     252        struct future_rc {
     253                future_rc_impl$(T) * impl;             
     254        }; // future_rc
     255        __CFA_SELECT_GET_TYPE( future_rc(T) );                          // magic
     256               
     257        static inline {
     258                // PRIVATE
     259
     260                bool register_select$( future_rc(T) & frc, select_node & s ) with( frc ) { // for waituntil statement
     261                        return register_select$( frc.impl->fut, s );
     262                }
     263
     264                bool unregister_select$( future_rc(T) & frc, select_node & s ) with( frc ) { // for waituntil statement
     265                        return unregister_select$( frc.impl->fut, s );
     266                }
     267
     268                bool on_selected$( future_rc(T) &, select_node & ) { return true; } // for waituntil statement
     269
     270                // PUBLIC
     271
     272                // General
     273
     274                void ?{}( future_rc( T ) & frc ) with( frc ) {  // default constructor
     275                        impl = new();
     276                } // ?{}
     277
     278                void ?{}( future_rc( T ) & to, future_rc( T ) & from ) with( to ) { // copy constructor
     279                        impl = from.impl;                                                       // point at new impl
     280                        incRef$( *impl );
     281                } // ?{}
     282
     283                void ^?{}( future_rc( T ) & frc ) with( frc ) {
     284                        if ( decRef$( *impl ) == 1 ) { delete( impl ); impl = 0p; }
     285                } // ^?{}
     286
     287                future_rc( T ) & ?=?( future_rc( T ) & lhs, future_rc( T ) & rhs ) with( lhs ) {
     288                  if ( impl == rhs.impl ) return lhs;                   // self assignment ?
     289                        if ( decRef$( *impl ) == 1 ) { delete( impl ); impl = 0p; } // no references ? => delete current impl
     290                        impl = rhs.impl;                                                        // point at new impl
     291                        incRef$( *impl );                                                       //   and increment reference count
     292                        return lhs;
     293                } // ?+?
     294
     295                // Used by Client
     296
     297                bool available( future_rc( T ) & frc ) { return available( frc.impl->fut ); } // future result available ?
     298
     299                // Return a value/exception from the future.
     300                [T, bool] get( future_rc(T) & frc ) with( frc ) { return get( impl->fut ); } // return future value
     301                T get( future_rc(T) & frc ) with( frc ) { return get( impl->fut ); } // return future value
     302                T ?()( future_rc(T) & frc ) with( frc ) { return get( frc ); } // alternate interface
     303                [T, bool] try_get( future_rc(T) & frc ) with( frc ) { return try_get( impl->fut ); }
     304
     305                int ?==?( future_rc( T ) & lhs, future_rc( T ) & rhs ) { return lhs.impl == rhs.impl; } // referential equality
     306
     307                // Used by Server
     308
     309                // Load a value/exception into the future, returns whether or not waiting threads.
     310                bool fulfil( future_rc(T) & frc, T val ) with( frc ) { return fulfil( impl->fut, val ); } // copy-in future value
     311                bool ?()( future_rc(T) & frc, T val ) { return fulfil( frc, val ); } // alternate interface
     312
     313                bool fulfil( future_rc(T) & frc, exception_t * ex ) with( frc ) { return fulfil( impl->fut, ex ); } // insert future exception
     314                bool ?()( future_rc(T) & frc, exception_t * ex ) { return fulfil( frc, ex ); } // alternate interface
     315
     316                void reset( future_rc(T) & frc ) with( frc ) { reset( impl->fut ); } // mark future as empty (for reuse)
     317        } // static inline
     318} // forall( T )
     319
     320//--------------------------------------------------------------------------------------------------------
     321// This future does not support waituntil statements so it does not have as many features as 'future'.
     322// However, it is cheap and cheerful and is more performant than 'future' since it uses raw atomics
     323// and no locks
     324//--------------------------------------------------------------------------------------------------------
     325
     326forall( T ) {
     327        // PUBLIC
     328
    231329        struct single_future {
    232330                inline future_t;
     
    235333
    236334        static inline {
    237                 // Reset future back to original state
    238                 void reset(single_future(T) & this) { reset( (future_t&)this ); }
    239 
    240                 // check if the future is available
    241                 bool available( single_future(T) & this ) { return available( (future_t&)this ); }
    242 
    243                 // Mark the future as abandoned, meaning it will be deleted by the server
    244                 // This doesn't work beause of the potential need for a destructor
    245                 // void abandon( single_future(T) & this );
    246 
    247                 // Fulfil the future, returns whether or not someone was unblocked
    248                 thread$ * fulfil( single_future(T) & this, T result ) {
    249                         this.result = result;
    250                         return fulfil( (future_t&)this );
    251                 }
    252 
    253                 // Wait for the future to be fulfilled
    254                 // Also return whether the thread had to block or not
    255                 [T, bool] wait( single_future(T) & this ) {
    256                         bool r = wait( (future_t&)this );
    257                         return [this.result, r];
    258                 }
    259 
    260                 // Wait for the future to be fulfilled
    261                 T wait( single_future(T) & this ) {
    262                         [T, bool] tt;
    263                         tt = wait(this);
    264                         return tt.0;
    265                 }
    266         }
    267 }
    268 
    269 forall( T ) {
    270         monitor multi_future {
    271                 inline future_t;
    272                 condition blocked;
    273                 bool has_first;
    274                 T result;
    275         };
    276 
    277         static inline {
    278                 void ?{}(multi_future(T) & this) {
    279                         this.has_first = false;
    280                 }
    281 
    282                 bool $first( multi_future(T) & mutex this ) {
    283                         if ( this.has_first ) {
    284                                 wait( this.blocked );
    285                                 return false;
    286                         }
    287 
    288                         this.has_first = true;
    289                         return true;
    290                 }
    291 
    292                 void $first_done( multi_future(T) & mutex this ) {
    293                         this.has_first = false;
    294                         signal_all( this.blocked );
    295                 }
    296 
    297                 // Reset future back to original state
    298                 void reset(multi_future(T) & mutex this) {
    299                         if ( this.has_first != false ) abort("Attempting to reset a multi_future with at least one blocked threads");
    300                         if ( !is_empty(this.blocked) ) abort("Attempting to reset a multi_future with multiple blocked threads");
    301                         reset( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) );
    302                 }
    303 
    304                 // Fulfil the future, returns whether or not someone was unblocked
    305                 bool fulfil( multi_future(T) & this, T result ) {
    306                         this.result = result;
    307                         return fulfil( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) ) != 0p;
    308                 }
    309 
    310                 // Wait for the future to be fulfilled
    311                 // Also return whether the thread had to block or not
    312                 [T, bool] wait( multi_future(T) & this ) {
    313                         bool sw = $first( this );
    314                         bool w = !sw;
    315                         if ( sw ) {
    316                                 w = wait( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) );
    317                                 $first_done( this );
    318                         }
    319 
    320                         return [this.result, w];
    321                 }
    322 
    323                 // Wait for the future to be fulfilled
    324                 T wait( multi_future(T) & this ) {
    325                         return wait(this).0;
    326                 }
    327         }
    328 }
     335                // PUBLIC
     336
     337                bool available( single_future(T) & fut ) { return available( (future_t &)fut ); } // future result available ?
     338
     339                // Return a value/exception from the future.
     340                [T, bool] get( single_future(T) & fut ) { return [fut.result, wait( fut )]; }
     341                T get( single_future(T) & fut ) { wait( fut ); return fut.result; }
     342                T ?()( single_future(T) & fut ) { return get( fut ); }  // alternate interface
     343
     344                // Load a value into the future, returns whether or not waiting threads.
     345                bool fulfil( single_future(T) & fut, T result ) {
     346                        fut.result = result;
     347                        return fulfil( (future_t &)fut ) != 0p;
     348                }
     349                bool ?()( single_future(T) & fut, T val ) { return fulfil( fut, val ); } // alternate interface
     350
     351                void reset( single_future(T) & fut ) { reset( (future_t &)fut ); } // mark future as empty (for reuse)
     352        } // static inline
     353} // forall( T )
  • libcfa/src/concurrency/invoke.h

    r8f448e0 r5e0b6657  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 23 15:27:18 2025
    13 // Update Count     : 61
     12// Last Modified On : Fri Oct 31 08:46:59 2025
     13// Update Count     : 67
    1414//
    1515
     
    236236        void * link_node;
    237237
     238                // extra fields supporting task related features
     239                uintptr_t shadow$;                                                              // user information for shadow queue
    238240                PRNG_STATE_T random_state;                                              // fast random numbers
    239241
  • libcfa/src/concurrency/locks.cfa

    r8f448e0 r5e0b6657  
    186186
    187187// waituntil() support
    188 bool register_select( blocking_lock & this, select_node & node ) with(this) {
     188bool register_select$( blocking_lock & this, select_node & node ) with(this) {
    189189        lock( lock __cfaabi_dbg_ctx2 );
    190190        thread$ * thrd = active_thread();
     
    218218}
    219219
    220 bool unregister_select( blocking_lock & this, select_node & node ) with(this) {
     220bool unregister_select$( blocking_lock & this, select_node & node ) with(this) {
    221221        lock( lock __cfaabi_dbg_ctx2 );
    222222        if ( isListed( node ) ) {
     
    239239}
    240240
    241 bool on_selected( blocking_lock & this, select_node & node ) { return true; }
     241bool on_selected$( blocking_lock & this, select_node & node ) { return true; }
    242242
    243243//-----------------------------------------------------------------------------
     
    583583        }
    584584}
     585
    585586//-----------------------------------------------------------------------------
    586 // Semaphore
    587 void ?{}( semaphore & this, int count = 1 ) {
    588         (this.lock){};
    589         this.count = count;
    590         (this.waiting){};
    591 }
    592 void ^?{}(semaphore & this) {}
    593 
    594 bool P(semaphore & this) with( this ){
    595         lock( lock __cfaabi_dbg_ctx2 );
    596         count -= 1;
    597         if ( count < 0 ) {
    598                 // queue current task
    599                 append( waiting, active_thread() );
    600 
    601                 // atomically release spin lock and block
    602                 unlock( lock );
     587// Semaphore, counting
     588
     589void ?{}( semaphore & sem, ssize_t count = 1 ) with( sem ) {
     590        count$ = count;
     591        (lock$){};
     592        (waiting$){};
     593}
     594
     595bool P( semaphore & sem ) with( sem ) {
     596        lock( lock$ __cfaabi_dbg_ctx2 );
     597        count$ -= 1;
     598        if ( count$ < 0 ) {                                                                     // in use ?
     599                append( waiting$, active_thread() );                    // queue current task
     600                unlock( lock$ );                                                                // atomically release spin lock and block
    603601                park();
    604                 return true;
     602                return false;
     603        } // if
     604        unlock( lock$ );
     605        return true;
     606}
     607
     608bool P( semaphore & sem, semaphore & lock ) with( sem ) {
     609        lock( lock$ __cfaabi_dbg_ctx2 );
     610        if ( &sem == &lock ) {                                                          // perform operation on self ?
     611                if ( count$ < 0 ) {                                                             // V my semaphore
     612                        unpark( pop_head( waiting$ ) );                         // unblock task at head of waiting list
     613                } // if
    605614        } else {
    606                 unlock( lock );
     615                V( lock );                                                                              // V mutex semaphore
     616                count$ -= 1;
     617        } // if
     618
     619        if ( count$ < 0 ) {                                                                     // in use ?
     620                append( waiting$, active_thread() );                    // queue current task
     621                unlock( lock$ );                                                                // atomically release spin lock and block
     622                park();
    607623                return false;
    608         }
    609 }
    610 
    611 thread$ * V (semaphore & this, const bool doUnpark ) with( this ) {
     624        } // if
     625        unlock( lock$ );
     626        return true;
     627}
     628
     629bool try_P( semaphore & sem ) with( sem ) {
     630        lock( lock$ __cfaabi_dbg_ctx2 );
     631        if ( count$ <= 0 ) {                                                            // in use ?
     632                unlock( lock$ );
     633                return false;
     634        } // if
     635        count$ -= 1;                                                                            // acquire
     636        unlock( lock$ );
     637        return true;
     638}
     639
     640bool V( semaphore & sem ) with( sem ) {
    612641        thread$ * thrd = 0p;
    613         lock( lock __cfaabi_dbg_ctx2 );
    614         count += 1;
    615         if ( count <= 0 ) {
    616                 // remove task at head of waiting list
    617                 thrd = pop_head( waiting );
    618         }
    619 
    620         unlock( lock );
    621 
    622         // make new owner
    623         if ( doUnpark ) unpark( thrd );
    624 
    625         return thrd;
    626 }
    627 
    628 bool V(semaphore & this) with( this ) {
    629         thread$ * thrd = V(this, true);
     642        lock( lock$ __cfaabi_dbg_ctx2 );
     643        count$ += 1;
     644        if ( count$ <= 0 ) {
     645                thrd = pop_head( waiting$ );                                    // remove task at head of waiting list
     646        }
     647        unlock( lock$ );
     648        if ( true ) unpark( thrd );                                             // make new owner
    630649        return thrd != 0p;
    631650}
    632651
    633 bool V(semaphore & this, unsigned diff) with( this ) {
    634         thread$ * thrd = 0p;
    635         lock( lock __cfaabi_dbg_ctx2 );
    636         int release = max(-count, (int)diff);
    637         count += diff;
    638         for(release) {
    639                 unpark( pop_head( waiting ) );
    640         }
    641 
    642         unlock( lock );
    643 
    644         return thrd != 0p;
    645 }
    646 
     652size_t V( semaphore & sem, size_t count ) with( sem ) {
     653        lock( lock$ __cfaabi_dbg_ctx2 );
     654        size_t release = max( (size_t)-count$, count );
     655        count$ += count;
     656        for ( release ) unpark( pop_head( waiting$ ) );
     657        unlock( lock$ );
     658        return release;
     659}
  • libcfa/src/concurrency/locks.hfa

    r8f448e0 r5e0b6657  
    1111// Created On       : Thu Jan 21 19:46:50 2021
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Thu Aug 21 22:36:44 2025
    14 // Update Count     : 23
     13// Last Modified On : Sun Nov 23 22:38:45 2025
     14// Update Count     : 67
    1515//
    1616
     
    8181
    8282
    83 
    84 //-----------------------------------------------------------------------------
    85 // Semaphore
     83//-----------------------------------------------------------------------------
     84// Semaphore, counting
     85
    8686struct semaphore {
    87         __spinlock_t lock;
    88         int count;
    89         __queue_t( thread$) waiting;
    90 };
    91 
    92 void ?{}( semaphore & this, int count = 1 );
    93 void ^?{}( semaphore & this );
    94 bool P( semaphore & this );
    95 bool V( semaphore & this );
    96 bool V( semaphore & this, unsigned count );
    97 thread$ * V( semaphore & this, bool );
     87        ssize_t count$;                                                                          // - => # waiting threads, 0 => block, + => acquire
     88        __spinlock_t lock$;                                                                      // protect blocking-lock critical sections
     89        __queue_t( thread$ ) waiting$;                                           // waiting threads
     90};
     91
     92void ?{}( semaphore & sem, ssize_t count = 1 );
     93// Return values are used for composition. Calling threads know if a thread is unblocked, which can be useful for
     94// debugging, performance instrumentation and other metadata tracking purposes.
     95bool P( semaphore & sem );
     96static inline bool P( semaphore & sem, uintptr_t shadow ) { active_thread()->shadow$ = shadow; return P( sem ); }
     97bool P( semaphore & sem, semaphore & lock );                    // atomic block and release
     98bool try_P( semaphore & sem );
     99static inline bool P( semaphore & sem, semaphore & lock, uintptr_t shadow ) { active_thread()->shadow$ = shadow; return P( sem, lock ); }
     100bool V( semaphore & sem );
     101size_t V( semaphore & sem, size_t count );
     102static inline uintptr_t front( semaphore & sem ) with( sem ) { // return shadow information for first waiting thread
     103        #ifdef __CFA_DEBUG__
     104        if ( waiting$ ) {                                                                       // condition queue must not be empty
     105                abort( "Attempt to access user data on an empty semaphore lock.\n"
     106                           "Possible cause is not checking if the condition lock is empty before reading stored data." );
     107        } // if
     108        #endif // __CFA_DEBUG__
     109        return waiting$.head->shadow$;                                          // return condition information stored with blocked task
     110}
     111static inline ssize_t counter( semaphore & sem ) with( sem ) { return count$; } // - => # waiting threads, 0 => block, + => acquire
     112//static inline int ?!=?( semaphore & sem, zero_t ) with( sem ) { return count$ != 0; } // empty waiting queue
     113static inline bool empty( semaphore & sem ) with( sem ) { return count$ == 0; } // empty waiting queue
     114
    98115
    99116//----------
     
    110127static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    111128static inline void on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    112 static inline bool register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    113 static inline bool unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    114 static inline bool on_selected( single_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
     129static inline bool register_select$( single_acquisition_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); }
     130static inline bool unregister_select$( single_acquisition_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); }
     131static inline bool on_selected$( single_acquisition_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); }
    115132__CFA_SELECT_GET_TYPE( single_acquisition_lock );
    116133
     
    128145static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    129146static inline void on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    130 static inline bool register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    131 static inline bool unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    132 static inline bool on_selected( owner_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
     147static inline bool register_select$( owner_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); }
     148static inline bool unregister_select$( owner_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); }
     149static inline bool on_selected$( owner_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); }
    133150__CFA_SELECT_GET_TYPE( owner_lock );
    134151
     
    594611
    595612// waituntil() support
    596 static inline bool register_select( simple_owner_lock & this, select_node & node ) with( this ) {
     613static inline bool register_select$( simple_owner_lock & this, select_node & node ) with( this ) {
    597614        lock( lock __cfaabi_dbg_ctx2 );
    598615
     
    626643}
    627644
    628 static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with( this ) {
     645static inline bool unregister_select$( simple_owner_lock & this, select_node & node ) with( this ) {
    629646        lock( lock __cfaabi_dbg_ctx2 );
    630647        if ( isListed( node ) ) {
     
    644661}
    645662
    646 static inline bool on_selected( simple_owner_lock & /*this*/, select_node & /*node*/ ) { return true; }
     663static inline bool on_selected$( simple_owner_lock & /*this*/, select_node & /*node*/ ) { return true; }
    647664__CFA_SELECT_GET_TYPE( simple_owner_lock );
    648665
  • libcfa/src/concurrency/monitor.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 25 07:20:22 2025
    13 // Update Count     : 80
     12// Last Modified On : Tue Nov  4 22:03:41 2025
     13// Update Count     : 82
    1414//
    1515
     
    494494
    495495bool signal( condition & this ) libcfa_public {
    496         if ( is_empty( this ) ) { return false; }
     496        if ( empty( this ) ) { return false; }
    497497
    498498        //Check that everything is as expected
     
    581581// Access the user_info of the thread waiting at the front of the queue
    582582uintptr_t front( condition & this ) libcfa_public {
    583         verifyf( ! is_empty(this),
     583        verifyf( ! empty( this ),
    584584                "Attempt to access user data on an empty condition.\n"
    585585                "Possible cause is not checking if the condition is empty before reading stored data."
  • libcfa/src/concurrency/monitor.hfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  2 11:29:21 2023
    13 // Update Count     : 12
     12// Last Modified On : Tue Nov  4 21:56:17 2025
     13// Update Count     : 16
    1414//
    1515
     
    146146}
    147147
    148               void wait        ( condition & this, uintptr_t user_info = 0 );
    149 static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
    150               bool signal      ( condition & this );
    151               bool signal_block( condition & this );
    152 static inline bool signal_all  ( condition & this ) { bool ret = false; while(!is_empty(this)) { ret = signal(this) || ret; } return ret; }
    153          uintptr_t front       ( condition & this );
     148void wait( condition & this, uintptr_t user_info = 0 );
     149static inline bool empty( condition & this ) { return this.blocked.head == 1p; }
     150bool signal ( condition & this );
     151bool signal_block( condition & this );
     152static inline bool signal_all( condition & this ) {
     153        bool ret = false;
     154        while ( !empty( this ) ) {
     155                ret = signal(this) || ret;
     156        }
     157        return ret;
     158}
     159uintptr_t front( condition & this );
    154160
    155161//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/select.cfa

    r8f448e0 r5e0b6657  
    1010// Author           : Colby Alexander Parsons
    1111// Created On       : Thu Apr 21 19:46:50 2023
    12 // Last Modified By : Kyoung Seo
    13 // Last Modified On : Wed Mar 19 12:00:00 2025
    14 // Update Count     : 1
     12// Last Modified By : Peter A. Buhr
     13// Last Modified On : Sun Nov 23 22:38:53 2025
     14// Update Count     : 4
    1515//
    1616
     
    3939
    4040// Selectable trait routines
    41 bool register_select( select_timeout_node & this, select_node & node ) {
     41bool register_select$( select_timeout_node & this, select_node & node ) {
    4242    this.s_node = &node;
    4343    node.extra = 0p;
     
    4545    return false;
    4646}
    47 bool unregister_select( select_timeout_node & this, select_node & node ) {
     47bool unregister_select$( select_timeout_node & this, select_node & node ) {
    4848    unregister_self( &this.a_node );
    4949    return false;
    5050}
    51 bool on_selected( select_timeout_node & this, select_node & node ) { return true; }
     51bool on_selected$( select_timeout_node & this, select_node & node ) { return true; }
    5252
  • libcfa/src/concurrency/select.hfa

    r8f448e0 r5e0b6657  
    1111// Created On       : Thu Jan 21 19:46:50 2023
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Fri Apr 25 07:31:26 2025
    14 // Update Count     : 5
     13// Last Modified On : Sun Nov 23 22:38:36 2025
     14// Update Count     : 8
    1515//
    1616
     
    8787        // For registering a select stmt on a selectable concurrency primitive
    8888        // Returns bool that indicates if operation is already SAT
    89         bool register_select( T &, select_node & );
     89        bool register_select$( T &, select_node & );
    9090
    9191        // For unregistering a select stmt on a selectable concurrency primitive
    9292        // If true is returned then the corresponding code block is run (only in non-special OR case and only if node status is not RUN)
    93         bool unregister_select( T &, select_node & );
     93        bool unregister_select$( T &, select_node & );
    9494
    9595        // This routine is run on the selecting thread prior to executing the statement corresponding to the select_node
    9696        //      passed as an arg to this routine. If true is returned proceed as normal, if false is returned the statement is skipped
    97         bool on_selected( T &, select_node & );
     97        bool on_selected$( T &, select_node & );
    9898};
    9999// Used inside the compiler to allow for overloading on return type for operations such as '?<<?' for channels
     
    209209
    210210// Selectable trait routines
    211 bool register_select( select_timeout_node & this, select_node & node );
    212 bool unregister_select( select_timeout_node & this, select_node & node );
    213 bool on_selected( select_timeout_node & this, select_node & node );
     211bool register_select$( select_timeout_node & this, select_node & node );
     212bool unregister_select$( select_timeout_node & this, select_node & node );
     213bool on_selected$( select_timeout_node & this, select_node & node );
    214214select_timeout_node __CFA_select_get_type( select_timeout_node this );
    215215
  • libcfa/src/strstream.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thu Apr 22 22:24:35 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 14 20:45:00 2025
    13 // Update Count     : 116
     12// Last Modified On : Sat Oct 11 15:10:56 2025
     13// Update Count     : 119
    1414//
    1515
     
    148148                abort();
    149149        } // if
     150        os.cursor$ = 0;
    150151        return os;
    151152} // write
     
    155156} // write
    156157
     158void clear( ostrstream & os ) {
     159        os.cursor$ = 0;
     160} // clear
    157161
    158162// *********************************** istrstream ***********************************
  • libcfa/src/strstream.hfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thu Apr 22 22:20:59 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 14 20:57:15 2025
    13 // Update Count     : 61
     12// Last Modified On : Sat Oct 11 15:11:06 2025
     13// Update Count     : 62
    1414//
    1515
     
    7575void ?{}( ostrstream &, char buf[], size_t size );
    7676
     77void clear( ostrstream & os );
     78
    7779
    7880// *********************************** istrstream ***********************************
  • src/Concurrency/Waituntil.cpp

    r8f448e0 r5e0b6657  
    99// Author           : Andrew Beach
    1010// Created On       : Fri May 27 10:31:00 2022
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Jun 13 13:30:00 2022
    13 // Update Count     : 0
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Nov 23 22:37:39 2025
     13// Update Count     : 3
    1414//
    1515
     
    606606
    607607        // Generates: register_select(A, clause1);
    608         currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
     608        currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select$" ) ) );
    609609
    610610        // generates: if ( when_cond ) { ... currBody ... }
     
    638638                {
    639639                        new IfStmt( cLoc,
    640                                 genSelectTraitCall( clause, data, "on_selected" ),
     640                                genSelectTraitCall( clause, data, "on_selected$" ),
    641641                                ast::deepCopy( clause->stmt )
    642642                        )
     
    715715                                                                )
    716716                                                            ),
    717                                                             new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
     717                                                            new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select$" ) )
    718718                                                        }
    719719                                                    )
     
    10171017        const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
    10181018
    1019         Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
     1019        Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select$" );
    10201020        Expr * ifCond;
    10211021
     
    11501150                        new IfStmt( cLoc,
    11511151                                ifCond,
    1152                                 new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) )
     1152                                new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select$" ) )
    11531153                        )
    11541154                );
     
    13431343                        ),
    13441344                        new CastExpr( cLoc,
    1345                                 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
     1345                                genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select$" ),
    13461346                                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    13471347                        ),
     
    13721372                                    {
    13731373                                        new IfStmt( cLoc,
    1374                                             genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
     1374                                            genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected$" ),
    13751375                                            ast::deepCopy( stmt->clauses.at(i)->stmt )
    13761376                                        )
  • tests/concurrency/barrier/generation.cfa

    r8f448e0 r5e0b6657  
    2020unsigned NUM_LAPS = 53;
    2121
    22 #include <concurrency/barrier.hfa>
     22#include <barrier.hfa>
    2323#include <fstream.hfa>
    2424#include <mutex_stmt.hfa>
     
    4545
    4646                        // Block on the barrier
    47                         block(bar);
     47                        block( bar );
    4848                }
    4949}
  • tests/concurrency/barrier/last.cfa

    r8f448e0 r5e0b6657  
    1717// function is called at the appropriate time.
    1818
    19 #include <concurrency/barrier.hfa>
     19#include <barrier.hfa>
    2020#include <fstream.hfa>
    2121#include <mutex_stmt.hfa>
     
    3434volatile unsigned validate_calls = 0;
    3535
    36 void validate() {
     36void validate(...) {
    3737        unsigned vc = validate_calls;
    3838        unsigned expected = generation[0];
  • tests/concurrency/barrier/order.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Fri Apr 01 11:39:09 2022
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Nov 10 11:22:56 2024
    13 // Update Count     : 20
     12// Last Modified On : Mon Oct 27 22:44:36 2025
     13// Update Count     : 22
    1414//
    1515
     
    2424
    2525volatile unsigned generation = 0;                                               // count laps
    26 void last() {
     26void last( ... ) {
    2727        generation += 1;                                                                        // last thread at barrier advances
    2828}
  • tests/concurrency/examples/boundedBufferTHREAD.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 16 23:09:43 2020
    13 // Update Count     : 25
     12// Last Modified On : Wed Nov  5 08:05:24 2025
     13// Update Count     : 28
    1414//
    1515
    16 #include <stdlib.hfa>                                                                   // random
    1716#include <fstream.hfa>
    1817#include <kernel.hfa>
     
    6564void main( Producer & prod ) with( prod ) {
    6665        for ( i; 1 ~= N ) {
    67                 yield( random( 5 ) );
     66                yield( prng( 5 ) );
    6867                insert( buffer, 1 );
    6968        } // for
     
    8180        sum = 0;
    8281        for () {
    83                 yield( random( 5 ) );
     82                yield( prng( 5 ) );
    8483                int item = remove( buffer );
    8584          if ( item == Sentinel ) break;                                        // sentinel ?
     
    101100        processor p;
    102101
    103         //srandom( getpid() );
    104         srandom( 1003 );
     102        set_seed( 1003 );
    105103
    106104        for ( i; Cons ) {                                                                       // create consumers
    107                 cons[i] = new( &buffer, sums[i] );
     105                cons[i] = new( &buffer, sums[i] );                              // NEW CANNOT HANDLE BUFFER REFERENCE
    108106        } // for
    109107        for ( i; Prods ) {                                                                      // create producers
  • tests/concurrency/examples/datingService.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Mon Oct 30 12:56:20 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Sep 27 15:42:25 2020
    13 // Update Count     : 40
     12// Last Modified On : Tue Nov  4 21:58:29 2025
     13// Update Count     : 41
    1414//
    1515
     
    2828
    2929unsigned int girl( DatingService & mutex ds, unsigned int PhoneNo, unsigned int ccode ) with( ds ) {
    30         if ( is_empty( Boys[ccode] ) ) {                                        // no compatible boy ?
     30        if ( empty( Boys[ccode] ) ) {                                           // no compatible boy ?
    3131                wait( Girls[ccode] );                                                   // wait for boy
    3232                GirlPhoneNo = PhoneNo;                                                  // make phone number available
     
    4040
    4141unsigned int boy( DatingService & mutex ds, unsigned int PhoneNo, unsigned int ccode ) with( ds ) {
    42         if ( is_empty( Girls[ccode] ) ) {                                       // no compatible girl ?
     42        if ( empty( Girls[ccode] ) ) {                                          // no compatible girl ?
    4343                wait( Boys[ccode] );                                                    // wait for girl
    4444                BoyPhoneNo = PhoneNo;                                                   // make phone number available
  • tests/concurrency/futures/multi.cfa

    r8f448e0 r5e0b6657  
     1// DEPRECATED future type multi_future. Eventually remove this test.
     2
    13#include <thread.hfa>
    24#include <future.hfa>
  • tests/concurrency/futures/select_future.cfa

    r8f448e0 r5e0b6657  
    11#include <thread.hfa>
    22#include <future.hfa>
    3 #include <concurrency/barrier.hfa>
     3#include <barrier.hfa>
    44
    55enum {NFUTURES = 10};
  • tests/concurrency/futures/typed.cfa

    r8f448e0 r5e0b6657  
    88};
    99
    10 void ?{}( Server & this ) {
    11         this.cnt = 0;
    12         for(i; NFUTURES) {
    13                 this.requests[i] = 0p;
     10void ?{}( Server & server ) with( server ) {
     11        cnt = 0;
     12        for ( i; NFUTURES ) {
     13                requests[i] = 0p;
    1414        }
    1515}
    1616
    17 void ^?{}( Server & mutex this ) {
    18         assert(this.cnt == 0);
    19         for(i; NFUTURES) {
    20                 this.requests[i] = 0p;
     17void ^?{}( Server & mutex server ) with( server ) {
     18        assert( cnt == 0 );
     19        for ( i; NFUTURES ) {
     20                requests[i] = 0p;
    2121        }
    2222}
    2323
    24 void process( Server & this, int i ) {
    25         if( this.requests[i] == 0p ) return;
    26         single_future(int) * f = this.requests[i];
    27         this.requests[i] = 0p;
    28         this.cnt--;
    29         fulfil( *f , i);
     24void process( Server & server, int i ) with( server ) {
     25  if ( requests[i] == 0p ) return;
     26        single_future(int) * f = requests[i];
     27        requests[i] = 0p;
     28        cnt--;
     29        (*f)( i );                                                                                      // fulfil
    3030}
    3131
    32 void call( Server & mutex this, single_future(int) & f ) {
    33         for(i; NFUTURES) {
    34                 if( this.requests[i] == 0p ) {
    35                         this.requests[i] = &f;
    36                         this.cnt++;
     32void call( Server & mutex server, single_future(int) & f ) with( server ) {
     33        for ( i; NFUTURES ) {
     34                if ( requests[i] == 0p ) {
     35                        requests[i] = &f;
     36                        cnt++;
    3737                        return;
    3838                }
     
    4141}
    4242
    43 void main( Server & this ) {
     43void main( Server & server ) {
    4444        unsigned i = 0;
    45         for() {
    46                 waitfor( ^?{} : this ) {
     45        for () {
     46                waitfor ( ^?{} : server ) {
    4747                        break;
    48                 }
    49                 or when( this.cnt < NFUTURES ) waitfor( call: this ) {}
     48                } or when( server.cnt < NFUTURES ) waitfor( call : server ) {}
    5049                or else {
    51                         process( this, i % NFUTURES );
     50                        process( server, i % NFUTURES );
    5251                        i++;
    5352                }
    5453        }
    5554
    56         for(i; NFUTURES) {
    57                 process( this, i );
     55        for ( i; NFUTURES ) {
     56                process( server, i );
    5857        }
    5958}
     
    6261thread Worker {};
    6362
    64 void thrash(void) {
     63void thrash() {
    6564        volatile int locals[250];
    66         for(i; 250) {
     65        for ( i; 250 ) {
    6766                locals[i] = 0xdeadbeef;
    6867        }
    6968}
    7069
    71 void work(void) {
     70void work() {
    7271        single_future(int) mine;
    7372        call( *the_server, mine );
    74         wait( mine );
     73        mine();                                                                                         // get
    7574}
    7675
    7776void main( Worker & ) {
    78         for(150) {
     77        for ( 150 ) {
    7978                thrash();
    8079                work();
     
    8483
    8584int main() {
    86         printf( "start\n" );                            // non-empty .expect file
     85        printf( "start\n" );                                                            // non-empty .expect file
    8786        processor procs[2];
    8887        {
     
    9392                }
    9493        }
    95         printf( "done\n" );                             // non-empty .expect file
    96 
     94        printf( "done\n" );                                                                     // non-empty .expect file
    9795}
  • tests/concurrency/once.cfa

    r8f448e0 r5e0b6657  
    99volatile int check;
    1010
    11 void reset() {
     11void reset( ... ) {
    1212        (global){};
    1313        check = 0;
  • tests/concurrency/readyQ/barrier_sleeper.cfa

    r8f448e0 r5e0b6657  
    1717// Processors and thread are removed in an interleaved fashion for a weirder case.
    1818
    19 #include <concurrency/barrier.hfa>
     19#include <barrier.hfa>
    2020#include <fstream.hfa>
    2121#include <time.hfa>
  • tests/concurrency/signal/block.cfa

    r8f448e0 r5e0b6657  
    8080        [a.last_thread, b.last_thread, a.last_signaller, b.last_signaller] = active_thread();
    8181
    82         if( !is_empty( cond ) ) {
     82        if( ! empty( cond ) ) {
    8383
    8484                thread$ * next = ( thread$ * ) front( cond );
  • tests/concurrency/waituntil/futures.cfa

    r8f448e0 r5e0b6657  
    1 #include <select.hfa>
     1#include <fstream.hfa>
    22#include <future.hfa>
    33#include <thread.hfa>
     
    55future(int) A, B, C;
    66
    7 semaphore s{0};
    8 
    9 thread Server1 {};
    10 void main( Server1 & ) {
    11     fulfil(B, 3);
    12     P( s );
    13     fulfil(A, 2);
    14     fulfil(C, 4);
    15 }
    16 
    17 thread Server2 {};
    18 void main( Server2 & ) {
    19     fulfil(B, 6);
    20     fulfil(A, 5);
    21     fulfil(C, 7);
     7thread Server {};
     8void main( Server & ) {
     9        B( 3 ); // fulfil( B, 3 );
     10        A( 2 );
     11        C( 4 );
    2212}
    2313
    2414int main() {
    25     processor proc[1];
    26     printf("start\n"); // currently not working
    27     {
    28         Server1 s1;
    29         waituntil( A ) { get(A); }
    30         or waituntil( B ) { get(B); V( s ); }
    31         and waituntil( C ) { get(C); }
    32     }
    33     reset(A);
    34     reset(B);
    35     reset(C);
    36     for ( int i = 0; i < 8; i++ ) {
    37         {
    38             Server2 s2;
    39             when( i % 2 == 0 ) waituntil( A ) { get(A); }
    40             or when( i % 4 < 2 ) waituntil( B ) { get(B); }
    41             and when( i < 4 ) waituntil( C ) { get(C); }
    42         }
    43         reset(A);
    44         reset(B);
    45         reset(C);
    46         {
    47             Server2 s2;
    48             (
    49                 when( i % 2 == 0 ) waituntil( A ) { get(A); }
    50                 or when( i % 4 < 2 ) waituntil( B ) { get(B); }
    51             )
    52             and when( i < 4 ) waituntil( C ) { get(C); }
    53         }
    54         reset(A);
    55         reset(B);
    56         reset(C);
    57     }
    58 
    59     printf("end\n");
    60     return 0;
     15        processor p;
     16    sout | "start";
     17        {
     18                size_t count = 0;
     19                Server s;
     20                for ( ; count < 3; ) {
     21                        waituntil( A ) { count += 1; A(); /* get( A ) */ }
     22                        or waituntil( B ) { count += 1; B(); }
     23                        or waituntil( C ) { count += 1; C(); }
     24                }
     25                reset( A ); reset( B ); reset( C );
     26        }
     27        {
     28                size_t count = 0;
     29                Server s;
     30                for ( ; count < 3; ) {
     31                        waituntil( A ) { count += 1; A(); /* get( A ) */ }
     32                        or waituntil( B ) { count += 1; B(); }
     33                        and waituntil( C ) { count += 1; C(); }
     34                }
     35                reset( A ); reset( B ); reset( C );
     36        }
     37        size_t count = 0;
     38        for ( i; 8 ) {
     39                {
     40                        Server s;
     41                        when( i % 2 == 0 ) waituntil( A ) { count += 1; A(); }
     42                        or when( i % 4 < 2 ) waituntil( B ) { count += 1; B(); }
     43                        and when( i < 4 ) waituntil( C ) { count += 1; C(); }
     44                }
     45                reset( A ); reset( B ); reset( C );
     46                {
     47                        Server s;
     48                        ( when( i % 2 == 0 ) waituntil( A ) { count += 1; A(); }
     49                          or when( i % 4 < 2 ) waituntil( B ) { count += 1; B(); }
     50                        ) and when( i < 4 ) waituntil( C ) { count += 1; C(); }
     51                }
     52                reset( A ); reset( B ); reset( C );
     53        } // for
     54        sout | "end";
    6155}
  • tests/io/comp_basic.cfa

    r8f448e0 r5e0b6657  
    1616
    1717
    18 #include <concurrency/barrier.hfa>
     18#include <barrier.hfa>
    1919#include <fstream.hfa>
    2020#include <iofwd.hfa>
  • tests/io/comp_fair.cfa

    r8f448e0 r5e0b6657  
    1616
    1717
    18 #include <concurrency/barrier.hfa>
     18#include <barrier.hfa>
    1919#include <fstream.hfa>
    2020#include <iofwd.hfa>
Note: See TracChangeset for help on using the changeset viewer.