Changeset 5e0b6657
- Timestamp:
- Dec 8, 2025, 11:29:33 AM (2 months ago)
- 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. - Files:
-
- 38 edited
- 1 moved
-
doc/LaTeXmacros/common.sty (modified) (2 diffs)
-
doc/LaTeXmacros/common.tex (modified) (2 diffs)
-
doc/bibliography/pl.bib (modified) (37 diffs)
-
doc/proposals/autogen.md (modified) (1 diff)
-
doc/theses/fangren_yu_MMath/test.adb (modified) (1 diff)
-
doc/theses/mike_brooks_MMath/intro.tex (modified) (9 diffs)
-
doc/theses/mike_brooks_MMath/uw-ethesis-frontpgs.tex (modified) (1 diff)
-
doc/uC++toCFA/uC++toCFA.tex (modified) (19 diffs)
-
libcfa/src/bits/defs.hfa (modified) (2 diffs)
-
libcfa/src/bits/weakso_locks.cfa (modified) (1 diff)
-
libcfa/src/bits/weakso_locks.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/barrier.hfa (modified) (1 diff)
-
libcfa/src/concurrency/channel.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/future.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (2 diffs)
-
libcfa/src/concurrency/locks.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (7 diffs)
-
libcfa/src/concurrency/monitor.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/monitor.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/select.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/select.hfa (modified) (3 diffs)
-
libcfa/src/strstream.cfa (modified) (3 diffs)
-
libcfa/src/strstream.hfa (modified) (2 diffs)
-
src/Concurrency/Waituntil.cpp (modified) (8 diffs)
-
tests/concurrency/barrier/generation.cfa (modified) (2 diffs)
-
tests/concurrency/barrier/last.cfa (modified) (2 diffs)
-
tests/concurrency/barrier/order.cfa (modified) (2 diffs)
-
tests/concurrency/examples/boundedBufferTHREAD.cfa (modified) (4 diffs)
-
tests/concurrency/examples/datingService.cfa (modified) (3 diffs)
-
tests/concurrency/futures/.expect/multi.txt.off (moved) (moved from tests/concurrency/futures/.expect/multi.txt )
-
tests/concurrency/futures/multi.cfa (modified) (1 diff)
-
tests/concurrency/futures/select_future.cfa (modified) (1 diff)
-
tests/concurrency/futures/typed.cfa (modified) (5 diffs)
-
tests/concurrency/once.cfa (modified) (1 diff)
-
tests/concurrency/readyQ/barrier_sleeper.cfa (modified) (1 diff)
-
tests/concurrency/signal/block.cfa (modified) (1 diff)
-
tests/concurrency/waituntil/futures.cfa (modified) (2 diffs)
-
tests/io/comp_basic.cfa (modified) (1 diff)
-
tests/io/comp_fair.cfa (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
doc/LaTeXmacros/common.sty
r8f448e0 r5e0b6657 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon May 5 21:37:13202514 %% Update Count : 66 613 %% Last Modified On : Sun Sep 21 22:17:15 2025 14 %% Update Count : 667 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 325 325 {<-}{$\leftarrow$}2 326 326 {=>}{$\Rightarrow$}2 327 {/*}{/{\raisebox{-2pt}{*}}}2 328 {*/}{{\raisebox{-2pt}{*}}/}2 327 329 % {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2, 328 330 }% lstset -
doc/LaTeXmacros/common.tex
r8f448e0 r5e0b6657 11 11 %% Created On : Sat Apr 9 10:06:17 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon May 5 21:34:53 202514 %% Update Count : 7 0913 %% Last Modified On : Sun Sep 21 22:16:43 2025 14 %% Update Count : 710 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 329 329 {<-}{$\leftarrow$}2 330 330 {=>}{$\Rightarrow$}2 331 {/*}{/{\raisebox{-2pt}{*}}}2 332 {*/}{{\raisebox{-2pt}{*}}/}2 331 333 % {->}{\raisebox{-1pt}{\texttt{-}}\kern-0.1ex\textgreater}2, 332 334 }% lstset -
doc/bibliography/pl.bib
r8f448e0 r5e0b6657 362 362 school = {University of Waterloo}, 363 363 year = 1991, 364 address = {Waterloo, Ontario, Canada , N2L 3G1},364 address = {Waterloo, Ontario, Canada}, 365 365 } 366 366 … … 426 426 year = 2010, 427 427 month = dec, 428 address = {Waterloo, Ontario, Canada , N2L 3G1},428 address = {Waterloo, Ontario, Canada}, 429 429 optnote = {\textsf{http://uwspace.uwaterloo.ca/\-bitstream/10012/\-5751\-/1/Krischer\_Roy.pdf}}, 430 430 note = {\url{http://uwspace.uwaterloo.ca/bitstream/10012/5751/1/Krischer_Roy.pdf}}, … … 929 929 930 930 % 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 } 931 941 932 942 @article{Michael13, … … 1154 1164 % C 1155 1165 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 1156 1176 @book{C, 1157 1177 keywords = {C}, … … 1247 1267 title = {\textsf{C}$\mathbf{\forall}$ Container Library}, 1248 1268 school = {School of Computer Science, University of Waterloo}, 1249 address = {Waterloo, Ontario, Canada , N2L 3G1},1269 address = {Waterloo, Ontario, Canada}, 1250 1270 publisher = {UWSpace}, 1251 1271 year = {2025}, 1252 note = {\url{https://hdl.handle.net/10012/ XXXXX}},1272 note = {\url{https://hdl.handle.net/10012/12345}}, 1253 1273 } 1254 1274 … … 1324 1344 title = {The \textsf{C}$\mathbf{\forall}$ Scheduler}, 1325 1345 school = {School of Computer Science, University of Waterloo}, 1326 address = {Waterloo, Ontario, Canada , N2L 3G1},1346 address = {Waterloo, Ontario, Canada}, 1327 1347 publisher = {UWSpace}, 1328 1348 year = 2022, … … 1345 1365 school = {School of Computer Science, University of Waterloo}, 1346 1366 year = 2004, 1347 address = {Waterloo, Ontario, Canada , N2L 3G1},1367 address = {Waterloo, Ontario, Canada}, 1348 1368 note = {\url{http://plg.uwaterloo.ca/theses/EstevesThesis.pdf}}, 1349 1369 } … … 1355 1375 school = {School of Computer Science, University of Waterloo}, 1356 1376 year = 2019, 1357 address = {Waterloo, Ontario, Canada , N2L 3G1},1377 address = {Waterloo, Ontario, Canada}, 1358 1378 note = {\url{https://hdl.handle.net/10012/14584}}, 1359 1379 } … … 1510 1530 title = {\textsf{C}$\mathbf{\forall}$ Users Guide, Version 0.1}, 1511 1531 institution = {Department of Computer Science, University of Waterloo}, 1512 address = {Waterloo, Ontario, Canada , N2L 3G1},1532 address = {Waterloo, Ontario, Canada}, 1513 1533 month = oct, 1514 1534 year = 2001, … … 1833 1853 year = 1997, 1834 1854 month = sep, 1835 address = {Waterloo, Ontario, Canada , N2L 3G1},1855 address = {Waterloo, Ontario, Canada}, 1836 1856 note = {\url{http://plg.uwaterloo.ca/theses/MokThesis.pdf}}, 1837 1857 } … … 2058 2078 school = {School of Computer Sc., University of Waterloo}, 2059 2079 year = 2015, 2060 address = {Waterloo, Ontario, Canada , N2L 3G1},2080 address = {Waterloo, Ontario, Canada}, 2061 2081 note = {\url{https://hdl.handle.net/10012/10013}}, 2062 2082 } … … 2104 2124 title = {Concurrency in \textsf{C}$\mathbf{\forall}$}, 2105 2125 school = {School of Computer Science, University of Waterloo}, 2106 address = {Waterloo, Ontario, Canada , N2L 3G1},2126 address = {Waterloo, Ontario, Canada}, 2107 2127 publisher = {UWSpace}, 2108 2128 year = 2018, … … 2116 2136 title = {Concurrency in {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}}}, 2117 2137 institution = {Department of Computer Science, University of Waterloo}, 2118 address = {Waterloo, Ontario, Canada , N2L 3G1},2138 address = {Waterloo, Ontario, Canada}, 2119 2139 number = {CS-90-18}, 2120 2140 month = may, … … 2209 2229 school = {Department of Computer Science, University of Waterloo}, 2210 2230 year = 1992, 2211 address = {Waterloo, Ontario, Canada , N2L 3G1},2231 address = {Waterloo, Ontario, Canada}, 2212 2232 note = {\url{http://plg.uwaterloo.ca/theses/DitchfieldThesis.pdf}} 2213 2233 } … … 3289 3309 title = {Enumerated Types in \textsf{C}$\mathbf{\forall}$}, 3290 3310 school = {School of Computer Science, University of Waterloo}, 3291 address = {Waterloo, Ontario, Canada , N2L 3G1},3311 address = {Waterloo, Ontario, Canada}, 3292 3312 publisher = {UWSpace}, 3293 3313 year = {2024}, … … 3496 3516 title = {Exception Handling in \textsf{C}$\mathbf{\forall}$}, 3497 3517 school = {School of Computer Science, University of Waterloo}, 3498 address = {Waterloo, Ontario, Canada , N2L 3G1},3518 address = {Waterloo, Ontario, Canada}, 3499 3519 publisher = {UWSpace}, 3500 3520 year = {2021}, … … 3752 3772 year = 2008, 3753 3773 month = jan, 3754 address = {Waterloo, Ontario, Canada , N2L 3G1},3774 address = {Waterloo, Ontario, Canada}, 3755 3775 note = {\url{http://uwspace.uwaterloo.ca/bitstream/10012/3501/1/Thesis.pdf}}, 3756 3776 } … … 4209 4229 year = 2009, 4210 4230 month = sep, 4211 address = {Waterloo, Ontario, Canada , N2L 3G1},4231 address = {Waterloo, Ontario, Canada}, 4212 4232 note = {\textsf{http://uwspace.uwaterloo.ca/bitstream/\-10012/\-4735/\-1/\-Chen-Jun.pdf}}, 4213 4233 } … … 4230 4250 author = {Haskell}, 4231 4251 title = {Haskell 2010 Language Report}, 4232 edition = {{S}imon {M}arlow},4252 optedition = {{S}imon {M}arlow}, 4233 4253 year = 2010, 4234 4254 note = {\url{https://haskell.org/definition/haskell2010.pdf}}, … … 4291 4311 title = {High Level Concurrency in \textsf{C}$\mathbf{\forall}$}, 4292 4312 school = {School of Computer Science, University of Waterloo}, 4293 address = {Waterloo, Ontario, Canada , N2L 3G1},4313 address = {Waterloo, Ontario, Canada}, 4294 4314 publisher = {UWSpace}, 4295 4315 year = {2023}, … … 4302 4322 author = {Mubeen Zulfiqar}, 4303 4323 title = {High-Performance Concurrent Memory Allocation}, 4304 school = {School of Comp uter Science, Universityof Waterloo},4324 school = {School of Comp. Sc., Univ. of Waterloo}, 4305 4325 year = 2022, 4306 address = {Waterloo, Ontario, Canada , N2L 3G1},4326 address = {Waterloo, Ontario, Canada}, 4307 4327 note = {\url{https://hdl.handle.net/10012/18329}}, 4308 4328 } … … 4323 4343 author = {Srihari Radhakrishnan}, 4324 4344 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}, 4326 4346 year = 2019, 4327 address = {Waterloo, Ontario, Canada , N2L 3G1},4347 address = {Waterloo, Ontario, Canada}, 4328 4348 note = {\url{https://hdl.handle.net/10012/14706}}, 4329 4349 } … … 4529 4549 author = {Richard C. Bilson}, 4530 4550 title = {Implementing Overloading and Polymorphism in \textsf{C}$\mathbf{\forall}$}, 4531 school = { School of Computer Science,University of Waterloo},4551 school = {University of Waterloo}, 4532 4552 year = 2003, 4533 address = {Waterloo, Ontario, Canada , N2L 3G1},4553 address = {Waterloo, Ontario, Canada}, 4534 4554 note = {\url{http://plg.uwaterloo.ca/theses/BilsonThesis.pdf}}, 4535 4555 } … … 4572 4592 year = 2018, 4573 4593 month = sep, 4574 address = {Waterloo, Ontario, Canada , N2L 3G1},4594 address = {Waterloo, Ontario, Canada}, 4575 4595 note = {\url{https://uwspace.uwaterloo.ca/handle/10012/13935}}, 4576 4596 } … … 5109 5129 school = {University of Waterloo}, 5110 5130 year = 1990, 5111 address = {Waterloo, Ontario, Canada , N2L 3G1}5131 address = {Waterloo, Ontario, Canada} 5112 5132 } 5113 5133 … … 5531 5551 title = {$\mu${S}ystem Annotated Reference Manual, Version 4.4.3}, 5532 5552 institution = {Department of Computer Science, University of Waterloo}, 5533 address = {Waterloo, Ontario, Canada , N2L 3G1},5553 address = {Waterloo, Ontario, Canada}, 5534 5554 month = sep, 5535 5555 year = 1994, … … 6273 6293 contributer = {pabuhr@plg}, 6274 6294 key = {OCaml}, 6275 title = {The {OC}aml system, release 5.1},6276 address = {Rust Project Developers},6277 year = 202 3,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}}, 6279 6299 } 6280 6300 … … 7733 7753 school = {School of Computer Science, University of Waterloo}, 7734 7754 year = 2017, 7735 address = {Waterloo, Ontario, Canada , N2L 3G1},7755 address = {Waterloo, Ontario, Canada}, 7736 7756 note = {\url{https://hdl.handle.net/10012/11830}}, 7737 7757 } … … 7819 7839 contributer = {pabuhr@plg}, 7820 7840 key = {Rust}, 7821 title = { {R}ust Programming Language},7822 address = {Rust ProjectDevelopers},7841 title = {The {R}ust Reference}, 7842 address = {Rust Developers}, 7823 7843 year = 2015, 7824 note = {\url{https://doc.rust-lang.org/ reference.html}},7844 note = {\url{https://doc.rust-lang.org/stable/reference}}, 7825 7845 } 7826 7846 … … 7875 7895 month = jun, 7876 7896 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, 7877 7909 } 7878 7910 … … 8321 8353 contributer = {pabuhr@plg}, 8322 8354 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+}}}}, 8324 8356 booktitle = {Proceedings of the USENIX {C}{\kern-.1em\hbox{\large\texttt{+\kern-.25em+}}} Conference}, 8325 8357 organization= {USENIX Association}, … … 8333 8365 keywords = {Polymorphic C}, 8334 8366 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}}, 8336 8368 author = {Smith, Geoffrey and Volpano, Dennis}, 8337 8369 journal = {Science of computer programming}, … … 8543 8575 school = {Department of Computer Science, University of Waterloo}, 8544 8576 year = 1989, 8545 address = {Waterloo, Ontario, Canada , N2L 3G1},8577 address = {Waterloo, Ontario, Canada}, 8546 8578 } 8547 8579 … … 8784 8816 volume = 40, 8785 8817 number = 6, 8786 month = jun,8818 optmonth = jun, 8787 8819 year = 2005, 8788 8820 pages = {261-268}, … … 8909 8941 } 8910 8942 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 8911 8954 @misc{Miller19, 8912 8955 keywords = {memory management, errors, unsafe}, 8913 8956 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}, 8915 8958 author = {Matt Miller}, 8916 8959 month = feb, … … 8926 8969 school = {Department of Computer Science, University of Waterloo}, 8927 8970 year = 1989, 8928 address = {Waterloo, Ontario, Canada , N2L 3G1},8971 address = {Waterloo, Ontario, Canada}, 8929 8972 } 8930 8973 … … 9087 9130 title = {Type Resolution in \textsf{C}$\mathbf{\forall}$}, 9088 9131 school = {School of Computer Science, University of Waterloo}, 9089 address = {Waterloo, Ontario, Canada , N2L 3G1},9132 address = {Waterloo, Ontario, Canada}, 9090 9133 publisher = {UWSpace}, 9091 9134 year = {2025}, -
doc/proposals/autogen.md
r8f448e0 r5e0b6657 100 100 The 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. 101 101 102 ### Automatic Remove Hides Everything 103 As 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 116 This 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 118 Users should have the option to adopt the idiom: All constructors funnel into the most private, all-member constructor. 119 120 ### Removed Functions Linger 121 Even 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 102 123 ## Other Problems & Requested Features 103 124 -
doc/theses/fangren_yu_MMath/test.adb
r8f448e0 r5e0b6657 6 6 Function Random return Float is begin return 3.5; end; 7 7 Function Random return Unbounded_String is begin return To_Unbounded_String( "abc" ); end; 8 8 9 9 Procedure Print( V : Integer ) is begin Put_Line( Integer'Image(V) ); end; 10 10 Procedure Print( V : Float ) is begin Put_Line( Float'Image(V) ); end; 11 11 Procedure Print( V : Unbounded_String ) is begin Put_Line( Ada.Strings.Unbounded.To_String(V) ); end; 12 12 13 13 Function Func( V : Integer ) return Integer is begin return V; end; 14 14 Function Func( V : Float ) return Float is begin return V; end; 15 15 Function Func( V : Unbounded_String ) return Unbounded_String is begin return V; end; 16 16 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; 19 19 J : Int; 20 20 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 2023 -- 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 recusion25 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 26 26 i : Integer; 27 27 f : Float; 28 28 s : Unbounded_String; 29 29 30 30 Type Complex is 31 record32 Re, Im : Float;33 end record;31 record 32 Re, Im : Float; 33 end record; 34 34 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 38 38 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; 41 41 function twice( X : T ) return T; 42 42 43 43 function twice( X: T ) return T is 44 44 begin 45 Put_Line( "XXX" ); return X + X;-- The formal operator "*".45 Put_Line( "XXX" ); return X + X; -- The formal operator "*". 46 46 end twice; 47 47 48 48 function Int_Twice is new Twice( Integer, "+" => "+" ); 49 49 function float_Twice is new Twice( float, "+" => "+" ); 50 51 -- generic units cannot be overloaded52 -- generic53 --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 is58 -- begin59 -- 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; 61 61 begin 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 71 71 i := Random; 72 Print( i );72 Print( i ); 73 73 f := Random; 74 Print( f );74 Print( f ); 75 75 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 84 84 Grind( X => (Re => 1.0, Im => 1.0) ); 85 85 Grind( c ); 86 86 Grind( To_Unbounded_String( "abc" ) ); 87 87 88 88 i := Int_Twice( 2 ); 89 89 Put_Line( Integer'Image(i) ); 90 90 f := float_Twice( 2.5 ); 91 Print( f );91 Print( f ); 92 92 end test; 93 93 -
doc/theses/mike_brooks_MMath/intro.tex
r8f448e0 r5e0b6657 2 2 3 3 All 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 stringfrom a combination of array and linked-list.4 Often 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. 5 5 For 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. 6 6 7 7 Unfortunately, these three aspects of C cause a significant number of memory errors~\cite{Oorschot23}. 8 Estimates suggest 50\%~\cite{Mendio24} of total reported open-source vulnerabilities occurring in C result from errors using these facilities (memory errors). 8 9 For operating system and browser vendors, who heavily use systems languages, 60\%--70\% of reported software vulnerabilities involved memory errors~\cite{Kehrer23}. 9 10 For Microsoft, 70\% of vulnerabilities addressed via security updates between 2006--2018 are memory safety issues~\cite[slide 10]{Miller19}. 10 11 In 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 .12 Therefore, hardening these three C types goes a long way to make the majority of C programs safer and eliminating major hacker attack-vectors. 12 13 13 14 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. … … 26 27 The array size can be static, dynamic but fixed after creation, or dynamic and variable after creation. 27 28 For 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).29 Because array layout has contiguous components, subscripting is a computation, \ie some form of pointer arithmetic. 29 30 30 31 C provides a simple array type as a language feature. 31 However, it adopts the controversial languageposition of treating pointer and array as duals, leading to multiple problems.32 However, it adopts the controversial position of treating pointer and array as duals, leading to multiple problems. 32 33 33 34 … … 36 37 A 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. 37 38 Subscripting 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 theelements (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);39 Linked types are dynamically sized by adding and removing nodes using link fields internal or external to the list elements (nodes). 40 If a programming language allows pointers to stack storage, linked-list nodes can be allocated on the stack and connected with stack addresses; 40 41 otherwise, elements are heap allocated with internal or external link fields. 41 42 … … 47 48 hash search table consisting of a key (string) with associated data (@<search.h>@) 48 49 \end{itemize} 49 Because these libraries are simple, awkward to use, and unsafe, C programmers commonly build bespoke linked data-structures.50 Because 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. 50 51 51 52 … … 54 55 A string provides a dynamic array of homogeneous elements, where the elements are (often) some form of human-readable characters. 55 56 What 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 individualcharacter level is considered poor practise, \ie underutilizing the powerful string operations.57 While subscripting individual elements is usually available, working at the character level is considered poor practise, \ie underutilizing the powerful string operations. 57 58 Therefore, 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. 58 59 The dynamic nature of a string means storage is normally heap allocated but often implicitly managed, even in unmanaged languages. 59 In somecases, string management is separate from heap management, \ie strings roll their own heap.60 In many cases, string management is separate from heap management, \ie strings roll their own heap. 60 61 61 62 The 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). 63 C adopts a terminating sentinel character, @'\0'@, to mark the end of a variable-length character-array versus a preceding length field. 64 Hence, the sentinel character is excluded from a string and determining the string length is an $O(N)$ operation. 63 65 The 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.66 Most of these operations are awkward to use and error prone. 65 67 66 68 … … 80 82 \begin{enumerate}[leftmargin=*] 81 83 \item 82 The se three aspects of C are difficult to understand, teach, and get right because they are correspondinglylow level.84 The three primary container types in C are difficult to understand, teach, and get right because they are too low level. 83 85 Providing higher-level, feature-rich versions of these containers in \CFA is a major component of the primary goal. 86 The result is a simplify programming experience, which increases productivity and maintainability. 84 87 \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. 88 The 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}. 89 Prior 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}. 90 Both 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. 91 Fixing these vulnerabilities negates this need, allowing C and its ecosystem to continue into the future. 87 92 \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.90 93 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. 94 While 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. 95 Even assuming automated conversion of C programs to other safe languages, who will maintain this massive new code-base? 93 96 Furthermore, 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). 97 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 features and idioms. 98 Finally, 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; 99 these languages are equivalent to switching to a different programming language. 100 Hence, rewriting and retraining costs for other languages are prohibitive when companies have a large C software-base (Google, Apple, Microsoft, Amazon, AMD, Nvidia). 96 101 97 102 … … 100 105 Like many established programming languages, C has a standards committee and multiple ANSI/\-ISO language manuals~\cite{C99,C11,C18,C23}. 101 106 However, 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. 107 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}, because a large part of the C library (runtime) system (@glibc@ on Linux) contains @gcc@ features. 104 108 Some key aspects of C need to be explained and understood by quoting from the language reference manual. 105 109 However, 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. 106 110 These example programs show 107 \begin{itemize} 111 \begin{itemize}[itemsep=0pt] 108 112 \item if the compiler accepts or rejects certain syntax, 109 113 \item prints output to buttress a behavioural claim, … … 111 115 \end{itemize} 112 116 These 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 isdiscussed.117 Any discovered anomalies among compilers, versions, or architectures are discussed. 114 118 In 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. 115 119 … … 118 122 119 123 Overall, 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. 121 125 The following are the detailed contributions, where performance and safety were always the motivating factors. 122 126 123 127 \subsection{Array} 124 128 125 Th is work's array improvements are:129 The improvements to C arrays are: 126 130 \begin{enumerate}[leftmargin=*] 127 131 \item 128 Introduce a small number of subtle changes to the typing rules for the C array, while still achieving significant backwards compatibility 132 Introduce a small number of subtle changes to the typing rules for the C array, while still achieving significant backwards compatibility. 129 133 \item 130 134 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}. -
doc/theses/mike_brooks_MMath/uw-ethesis-frontpgs.tex
r8f448e0 r5e0b6657 129 129 \begin{center}\textbf{Abstract}\end{center} 130 130 131 \CFA strives to fix mistakes in C, chief among them, safety. 132 This thesis presents a significant step forward in \CFA's goal to remove unsafe pointer operations. 133 The thesis presents improvements to the \CFA language design, both syntax and semantics, to support advanced container features. 134 These features are implemented across the \CFA compiler, libraries, and runtime system. 135 The results maintain another \CFA goal of remaining 99\% backwards compatible with C. 136 This thesis leverages preexisting work within the compiler's type and runtime systems generated by prior students working on the \CFA project. 137 131 138 All 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 stringfrom a combination of array and linked-list.139 Often 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. 133 140 For 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 involv edmemory errors, and 70\%--80\% of hacker attack-vectors target these types.141 Unfortunately, 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. 135 142 Therefore, hardening these three C types goes a long way to make the majority of C programs safer. 136 143 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. 144 Specifically, an array utility is provided that tracks length internally, relieving the user of managing explicit length parameters and stopping buffer-overrun errors. 145 This feature requires augmenting the \CFA type system, making array length available at compile and runtime. 146 A 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. 147 Finally, 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. 148 For all three utilities, performance is argued to be on-par with, and occasionally surpassing relevant comparators. 149 With 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. 150 With the linked list and string, empirical measures are compared with relevant libraries. 151 These 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. 155 152 156 153 \cleardoublepage -
doc/uC++toCFA/uC++toCFA.tex
r8f448e0 r5e0b6657 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon Sep 8 18:10:30202514 %% Update Count : 6 53413 %% Last Modified On : Mon Nov 17 11:14:48 2025 14 %% Update Count : 6677 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 345 345 346 346 \begin{cquote} 347 \setlength{\tabcolsep}{5pt} 347 348 \begin{tabular}{@{}l|ll@{}} 348 349 \begin{uC++} 349 350 350 351 351 void main() {352 void Coroutine::main() { 352 353 try { 353 354 _Enable { … … 357 358 catch( E & ) { ... } 358 359 } 360 void Coroutine::mem() { resume(); } 359 361 \end{uC++} 360 362 & … … 362 364 #define resumePoll( coroutine ) resume( coroutine ); poll() 363 365 #define suspendPoll suspend; poll() 364 void main( ) {366 void main( Coroutine & cor ) { 365 367 try { 366 368 enable_ehm(); … … 370 372 catch( E & ) { ... } 371 373 } 374 void mem( Coroutine & cor ) { resumePoll(); } 372 375 \end{cfa} 373 376 \end{tabular} … … 429 432 \end{tabular} 430 433 \end{cquote} 434 435 436 \section{Time} 437 438 \begin{cquote} 439 \setlength{\tabcolsep}{5pt} 440 \begin{tabular}{@{}l|l@{}} 441 \begin{uC++} 442 443 uTime start = uClock::currTime(); 444 ... 445 cout << "duration " << uClock::currTime() - start 446 << " sec." << endl; 447 \end{uC++} 448 & 449 \begin{cfa} 450 #include <clock.hfa> 451 Time start = timeHiRes(); // time with nanoseconds 452 ... 453 sout | "duration " | timeHiRes() - start | " sec."; 454 455 \end{cfa} 456 \end{tabular} 457 \end{cquote} 458 459 460 \section{Constructor / Destructor} 461 462 A 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 467 struct 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 }; 474 S s0, s1 = { 1, 2 }; 475 476 S * s2 = new S{ 1, 2 }; delete s2; 477 s2 = new S{ 1, 2 }; delete s2; 478 S & s3 = *new S{ 1, 2 }; delete &s3; 479 s3 = *new S{ 1, 2 }; delete &s3; 480 \end{uC++} 481 & 482 \begin{cfa} 483 #include <stdlib.hfa> // new (malloc) 484 struct S { int i, j; }; 485 486 void @?{}@( @S & s@ ) { s.i = s.j = 3; } $\C[3in]{// default}$ 487 void @?{}@( @S & s@, int i, int j ) { s.i = i; s.j = j; } $\C{// initializer}$ 488 void @?{}@( @S & s@, const S rhs ) { ?{}( s, rhs.i, rhs.j ); } $\C{// copy}$ 489 void @^?{}@( @S & s@ ) { s.i = 0; s.j = 0; } $\C{// destructor}\CRT$ 490 491 S s0, s1 = { 1, 2 }; 492 // bug, cannot use 0/1 (zero_t/one_t) with "new" 493 S * s2 = new( 0@n@, 2 ); /* suffix n => (natural int) */ delete( s2 ); 494 s2 = new( 1@n@, 2 ); delete( s2 ); 495 S & 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. 505 The 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++} 509 struct 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 }; 514 S s; 515 @s.@setter( 3 ); // object calls 516 int k = @s.@getter(); 517 \end{uC++} 518 & 519 \begin{cfa} 520 struct S { int i; }; 521 void ?{}( S & s ) { s.i = 0; } // explicit default constructor 522 int setter( @S & s,@ int j ) @with( s )@ { int t = i; i = j; return t; } 523 int getter( @S & s@ ) @with( s )@ { return i; } 524 525 S s; 526 setter( @s,@ 3 ); // normal calls 527 int k = getter( @s@ ); 528 \end{cfa} 529 \end{tabular} 530 \end{cquote} 531 Aggregate qualification is reduced or eliminated by opening scopes using the @with@ clause. 532 \begin{cfa} 533 struct S { int i; int j; double m; }; // field i has same type in structures S and T 534 struct T { int i; int k; int m; }; 535 void 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 546 In subsequent code examples, the left example is \CC/\uC and the right example is \CFA. 431 547 432 548 … … 474 590 475 591 592 \enlargethispage{1000pt} 476 593 \section{\texorpdfstring{\lstinline{uArray}}{uArray}} 477 594 … … 525 642 \end{cquote} 526 643 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> 654 using namespace std; 655 struct Node : @public uSeqable@ { 656 int i; 657 Node( int i ) : i( i ) {} 658 }; 659 660 661 int 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> 683 struct Node { 684 @inline dlink( Node );@ 685 int i; 686 }; 687 @P9_EMBEDDED( Node, dlink( Node ) );@ // magic 688 void ?{}( Node & node, int i ) { node.i = i; } 689 int 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 = &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@{}} 534 715 \begin{uC++} 535 716 struct 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 }; 719 S * s = new S; delete s; 720 S * sa = new S[10]; delete [] sa; 721 \end{uC++} 722 & 723 \begin{cfa} 724 #include <stdlib.hfa> 725 struct S { ... }; 726 void ?{}( S & ) { ... } void ^?{}( S & ) { ... } // ctor / dtor 727 S * s = new(); delete( s ); 728 S * sa = anew( 10 ); adelete( sa ); 622 729 \end{cfa} 623 730 \end{tabular} … … 660 767 } 661 768 \end{cfa} 662 \\663 \multicolumn{2}{@{}l@{}}{\lstinline{C c;}}664 769 \end{tabular} 665 770 \end{cquote} … … 708 813 709 814 \begin{cquote} 815 \setlength{\tabcolsep}{10pt} 710 816 \begin{tabular}{@{}l|ll@{}} 711 817 \begin{uC++} … … 738 844 } 739 845 \end{cfa} 740 \end{tabular} 741 \begin{tabular}{@{}l|ll@{}} 846 \\ 742 847 \begin{uC++} 743 848 _Actor Hello { ${\color{red}\LstCommentStyle{// : public uActor}}$ … … 829 934 830 935 uOwnerLock m; 831 uCondLock s;936 uCondLock c; 832 937 m.acquire(); 833 if ( ! s.empty() ) s.wait( m );938 if ( ! c.empty() ) c.wait( m ); 834 939 else { 835 940 m.release(); … … 841 946 #include <locks.hfa> 842 947 owner_lock m; 843 cond_lock( owner_lock ) s; // generic type on mutex lock948 cond_lock( owner_lock ) c; // generic type on mutex lock 844 949 lock( m ); 845 if ( ! empty( s ) ) wait( s, m );950 if ( ! empty( c ) ) wait( c, m ); 846 951 else { 847 952 unlock( m ); … … 852 957 \end{cquote} 853 958 959 \begin{cquote} 960 \begin{tabular}{@{}l|ll@{}} 961 \begin{uC++} 962 963 uSemaphore m, c; 964 m.P(); 965 if ( ! c.empty() ) c.P( m ); 966 else { 967 m.V(); 968 } 969 \end{uC++} 970 & 971 \begin{cfa} 972 #include <locks.hfa> 973 semaphore m, c; 974 P( m ); 975 if ( ! empty( c ) ) P( c, m ); 976 else { 977 V( m ); 978 } 979 \end{cfa} 980 \end{tabular} 981 \end{cquote} 982 983 984 \enlargethispage{1000pt} 854 985 855 986 \section{Barrier} … … 888 1019 #include <mutex_stmt.hfa> 889 1020 struct Barrier { 890 @ barrier b;@ // containment1021 @inline barrier;@ 891 1022 int total; 892 1023 893 1024 }; 894 void ?{}( Barrier & B, unsigned int group ) with(B) {895 @ ?{}( b, group );@ // initialize barrier1025 void ?{}( Barrier & b, unsigned int group ) with( b ) { 1026 @(b){ group };@ // initialize barrier 896 1027 total = 0; 897 1028 } 898 unsigned int block( Barrier & B, int subtotal ) with(B) {899 void @last@( ) { sout | total; } // called by Gth arriving thread1029 unsigned int block( Barrier & b, int subtotal ) with( b ) { 1030 void @last@(...) { sout | total; } // called by Gth arriving thread 900 1031 @mutex( b )@ { // use barrier's mutual exclusion 901 1032 total += subtotal; … … 909 1040 \end{cquote} 910 1041 1042 \newpage 911 1043 912 1044 \enlargethispage{1000pt} … … 916 1048 Internal Scheduling 917 1049 \begin{cquote} 1050 \setlength{\tabcolsep}{5pt} 918 1051 \begin{tabular}{@{}l|ll@{}} 919 1052 \begin{uC++} … … 979 1112 \end{cquote} 980 1113 981 \ newpage1114 \bigskip 982 1115 \noindent 983 1116 External Scheduling 984 1117 \begin{cquote} 1118 \setlength{\tabcolsep}{5pt} 985 1119 \begin{tabular}{@{}l|ll@{}} 986 1120 \begin{uC++} … … 1039 1173 1040 1174 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; 1187 struct Msg { int i, j; }; @Future_ISM@<Msg> fm; 1188 struct Stop {}; @Future_ISM@<Stop> fs; 1189 struct 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 }; 1205 int 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; 1219 struct Msg { int i, j; }; @future_rc@(Msg) fm; 1220 struct Stop {}; @future_rc@(Stop) fs; 1221 struct Cont {}; @future_rc@(Cont) fc; 1222 ExceptionDecl( Break ); 1223 thread Worker {}; 1224 void 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 } 1237 int 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} 1042 1250 1043 1251 % \bibliographystyle{plain} -
libcfa/src/bits/defs.hfa
r8f448e0 r5e0b6657 13 13 // Created On : Thu Nov 9 13:24:10 2017 14 14 // Last Modified By : Peter A. Buhr 15 // Last Modified On : Sat Oct 24 10:53:15 202016 // Update Count : 2 115 // Last Modified On : Mon Oct 27 22:40:05 2025 16 // Update Count : 23 17 17 // 18 18 … … 25 25 #define unlikely(x) __builtin_expect(!!(x), 0) 26 26 27 typedef void (* fptr_t)();27 typedef void (* fptr_t)(); 28 28 typedef int_fast16_t __lock_size_t; 29 29 -
libcfa/src/bits/weakso_locks.cfa
r8f448e0 r5e0b6657 28 28 void on_wakeup( blocking_lock &, size_t ) {} 29 29 size_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; }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; } 33 33 -
libcfa/src/bits/weakso_locks.hfa
r8f448e0 r5e0b6657 59 59 void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD; 60 60 size_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;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; 64 64 blocking_lock __CFA_select_get_type( blocking_lock this ) OPTIONAL_THREAD; 65 65 … … 78 78 static inline void on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 79 79 static 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 ); }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 ); } 83 83 multiple_acquisition_lock __CFA_select_get_type( multiple_acquisition_lock this ); -
libcfa/src/concurrency/barrier.hfa
r8f448e0 r5e0b6657 11 11 // Created On : Sun Nov 10 08:07:35 2024 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Thu Apr 24 22:41:11202514 // Update Count : 1213 // Last Modified On : Fri Oct 31 09:22:14 2025 14 // Update Count : 69 15 15 // 16 16 17 17 #pragma once 18 18 19 #include <locks.hfa> 19 20 #include <monitor.hfa> 20 21 21 22 // Plan 9 inheritance does not work with monitors. Two monitor locks are created. 22 23 24 typedef void (* barrier_fptr_t)( ... ); // like C++, () => void and ... => C () 25 23 26 monitor 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 26 31 }; 27 32 28 static inline void ?{}( barrier & b, unsigned int group ) { 29 b.group = b.arrivals = group; // arrivals count backward 33 static inline void ?{}( barrier & b, ssize_t group, barrier_fptr_t callback, void * arg ) with ( b ) { 34 [group$, arrivals$] = group; 35 [callback$, arg$] = [callback, arg]; 30 36 } 31 37 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 ); 38 static inline void ?{}( barrier & b, ssize_t group ) { (b){ group, 0p, 0p }; } // call base constructor 39 static inline ssize_t waiters( barrier & b ) with( b ) { return group$ - arrivals$; } 40 static 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. 48 static 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 39 55 } 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 43 60 } // if 44 61 return arrived; // return arrival order 45 62 } 63 64 static inline ssize_t block( barrier & b ) { return block( b, *0p, 0p, 0p ); } 65 static inline ssize_t block( barrier & b, owner_lock & olock ) { return block( b, olock, 0p, 0p ); } 66 static inline ssize_t block( barrier & b, barrier_fptr_t callback ) { return block( b, *0p, callback, 0p ); } 67 static inline ssize_t block( barrier & b, barrier_fptr_t callback, void * arg ) { return block( b, *0p, callback, arg ); } 68 static 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 411 411 } 412 412 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) { 414 414 lock( mutex_lock ); 415 415 node.extra = ret; // set .extra so that if it == 0p later in on_selected it is due to channel close … … 476 476 return true; 477 477 } 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) { 480 480 if ( unlikely(node.extra == 0p) ) { 481 481 if ( ! exception_in_flight() ) __closed_remove( *chan, *ret ); // check if woken up due to closed channel … … 491 491 492 492 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 ) { 494 494 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 ); } 499 499 500 500 void ?{}( chan_write(T) & cw, channel(T) * chan, T elem ) { … … 511 511 } 512 512 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) { 514 514 lock( mutex_lock ); 515 515 node.extra = &elem; // set .extra so that if it == 0p later in on_selected it is due to channel close … … 577 577 return true; 578 578 } 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) { 582 582 if ( unlikely(node.extra == 0p) ) { 583 583 if ( ! exception_in_flight() ) __closed_insert( *chan, elem ); // check if woken up due to closed channel -
libcfa/src/concurrency/future.hfa
r8f448e0 r5e0b6657 7 7 // concurrency/future.hfa -- 8 8 // 9 // Author : Thierry Delisle & Peiran Hong & Colby Parsons 9 // Author : Thierry Delisle & Peiran Hong & Colby Parsons & Peter Buhr 10 10 // Created On : Wed Jan 06 17:33:18 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 23 22:41:10202513 // Update Count : 22 12 // Last Modified On : Mon Nov 24 16:08:52 2025 13 // Update Count : 222 14 14 // 15 15 … … 21 21 #include "locks.hfa" 22 22 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 27 28 forall( 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 29 44 30 45 struct future { … … 32 47 T result; 33 48 exception_t * except; 49 futex_mutex lock; 34 50 dlist( select_node ) waiters; 35 futex_mutex lock;36 51 }; 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 ) { 68 105 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 132 114 void exceptCheck() { // helper 133 115 if ( except ) { … … 138 120 } 139 121 } 140 141 lock( lock );142 122 T ret_val; 143 if ( state == FUTURE_FULFILLED ) { 123 124 // LOCK ACQUIRED IN PUBLIC get 125 if ( state == FUTURE_FULFILLED$ ) { 144 126 exceptCheck(); 145 copy_T ( result, ret_val);127 copy_T$( ret_val, result ); 146 128 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 }; 151 133 insert_last( waiters, ((select_node &)node) ); 152 134 unlock( lock ); 153 135 park( ); 154 136 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 ) { 174 159 lock( lock ); 175 160 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 ); 178 163 unlock( lock ); 179 164 return [ret_val, true]; 180 165 } 181 166 unlock( lock ); 182 183 167 return [ret_val, false]; 184 168 } 185 169 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. 228 225 //-------------------------------------------------------------------------------------------------------- 229 226 230 227 forall( 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 326 forall( T ) { 327 // PUBLIC 328 231 329 struct single_future { 232 330 inline future_t; … … 235 333 236 334 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 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 23 15:27:18202513 // Update Count : 6 112 // Last Modified On : Fri Oct 31 08:46:59 2025 13 // Update Count : 67 14 14 // 15 15 … … 236 236 void * link_node; 237 237 238 // extra fields supporting task related features 239 uintptr_t shadow$; // user information for shadow queue 238 240 PRNG_STATE_T random_state; // fast random numbers 239 241 -
libcfa/src/concurrency/locks.cfa
r8f448e0 r5e0b6657 186 186 187 187 // waituntil() support 188 bool register_select ( blocking_lock & this, select_node & node ) with(this) {188 bool register_select$( blocking_lock & this, select_node & node ) with(this) { 189 189 lock( lock __cfaabi_dbg_ctx2 ); 190 190 thread$ * thrd = active_thread(); … … 218 218 } 219 219 220 bool unregister_select ( blocking_lock & this, select_node & node ) with(this) {220 bool unregister_select$( blocking_lock & this, select_node & node ) with(this) { 221 221 lock( lock __cfaabi_dbg_ctx2 ); 222 222 if ( isListed( node ) ) { … … 239 239 } 240 240 241 bool on_selected ( blocking_lock & this, select_node & node ) { return true; }241 bool on_selected$( blocking_lock & this, select_node & node ) { return true; } 242 242 243 243 //----------------------------------------------------------------------------- … … 583 583 } 584 584 } 585 585 586 //----------------------------------------------------------------------------- 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 589 void ?{}( semaphore & sem, ssize_t count = 1 ) with( sem ) { 590 count$ = count; 591 (lock$){}; 592 (waiting$){}; 593 } 594 595 bool 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 603 601 park(); 604 return true; 602 return false; 603 } // if 604 unlock( lock$ ); 605 return true; 606 } 607 608 bool 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 605 614 } 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(); 607 623 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 629 bool 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 640 bool V( semaphore & sem ) with( sem ) { 612 641 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 630 649 return thrd != 0p; 631 650 } 632 651 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 652 size_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 11 11 // Created On : Thu Jan 21 19:46:50 2021 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Thu Aug 21 22:36:44202514 // Update Count : 2313 // Last Modified On : Sun Nov 23 22:38:45 2025 14 // Update Count : 67 15 15 // 16 16 … … 81 81 82 82 83 84 // -----------------------------------------------------------------------------85 // Semaphore 83 //----------------------------------------------------------------------------- 84 // Semaphore, counting 85 86 86 struct 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 92 void ?{}( 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. 95 bool P( semaphore & sem ); 96 static inline bool P( semaphore & sem, uintptr_t shadow ) { active_thread()->shadow$ = shadow; return P( sem ); } 97 bool P( semaphore & sem, semaphore & lock ); // atomic block and release 98 bool try_P( semaphore & sem ); 99 static inline bool P( semaphore & sem, semaphore & lock, uintptr_t shadow ) { active_thread()->shadow$ = shadow; return P( sem, lock ); } 100 bool V( semaphore & sem ); 101 size_t V( semaphore & sem, size_t count ); 102 static 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 } 111 static 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 113 static inline bool empty( semaphore & sem ) with( sem ) { return count$ == 0; } // empty waiting queue 114 98 115 99 116 //---------- … … 110 127 static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 111 128 static 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 ); }129 static inline bool register_select$( single_acquisition_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); } 130 static inline bool unregister_select$( single_acquisition_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); } 131 static inline bool on_selected$( single_acquisition_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); } 115 132 __CFA_SELECT_GET_TYPE( single_acquisition_lock ); 116 133 … … 128 145 static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 129 146 static 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 ); }147 static inline bool register_select$( owner_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); } 148 static inline bool unregister_select$( owner_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); } 149 static inline bool on_selected$( owner_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); } 133 150 __CFA_SELECT_GET_TYPE( owner_lock ); 134 151 … … 594 611 595 612 // waituntil() support 596 static inline bool register_select ( simple_owner_lock & this, select_node & node ) with( this ) {613 static inline bool register_select$( simple_owner_lock & this, select_node & node ) with( this ) { 597 614 lock( lock __cfaabi_dbg_ctx2 ); 598 615 … … 626 643 } 627 644 628 static inline bool unregister_select ( simple_owner_lock & this, select_node & node ) with( this ) {645 static inline bool unregister_select$( simple_owner_lock & this, select_node & node ) with( this ) { 629 646 lock( lock __cfaabi_dbg_ctx2 ); 630 647 if ( isListed( node ) ) { … … 644 661 } 645 662 646 static inline bool on_selected ( simple_owner_lock & /*this*/, select_node & /*node*/ ) { return true; }663 static inline bool on_selected$( simple_owner_lock & /*this*/, select_node & /*node*/ ) { return true; } 647 664 __CFA_SELECT_GET_TYPE( simple_owner_lock ); 648 665 -
libcfa/src/concurrency/monitor.cfa
r8f448e0 r5e0b6657 10 10 // Created On : Thd Feb 23 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 25 07:20:22202513 // Update Count : 8 012 // Last Modified On : Tue Nov 4 22:03:41 2025 13 // Update Count : 82 14 14 // 15 15 … … 494 494 495 495 bool signal( condition & this ) libcfa_public { 496 if ( is_empty( this ) ) { return false; }496 if ( empty( this ) ) { return false; } 497 497 498 498 //Check that everything is as expected … … 581 581 // Access the user_info of the thread waiting at the front of the queue 582 582 uintptr_t front( condition & this ) libcfa_public { 583 verifyf( ! is_empty(this),583 verifyf( ! empty( this ), 584 584 "Attempt to access user data on an empty condition.\n" 585 585 "Possible cause is not checking if the condition is empty before reading stored data." -
libcfa/src/concurrency/monitor.hfa
r8f448e0 r5e0b6657 10 10 // Created On : Thd Feb 23 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Feb 2 11:29:21 202313 // Update Count : 1 212 // Last Modified On : Tue Nov 4 21:56:17 2025 13 // Update Count : 16 14 14 // 15 15 … … 146 146 } 147 147 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 ); 148 void wait( condition & this, uintptr_t user_info = 0 ); 149 static inline bool 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 ) { 153 bool ret = false; 154 while ( !empty( this ) ) { 155 ret = signal(this) || ret; 156 } 157 return ret; 158 } 159 uintptr_t front( condition & this ); 154 160 155 161 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/select.cfa
r8f448e0 r5e0b6657 10 10 // Author : Colby Alexander Parsons 11 11 // Created On : Thu Apr 21 19:46:50 2023 12 // Last Modified By : Kyoung Seo13 // Last Modified On : Wed Mar 19 12:00:00202514 // Update Count : 112 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Sun Nov 23 22:38:53 2025 14 // Update Count : 4 15 15 // 16 16 … … 39 39 40 40 // Selectable trait routines 41 bool register_select ( select_timeout_node & this, select_node & node ) {41 bool register_select$( select_timeout_node & this, select_node & node ) { 42 42 this.s_node = &node; 43 43 node.extra = 0p; … … 45 45 return false; 46 46 } 47 bool unregister_select ( select_timeout_node & this, select_node & node ) {47 bool unregister_select$( select_timeout_node & this, select_node & node ) { 48 48 unregister_self( &this.a_node ); 49 49 return false; 50 50 } 51 bool on_selected ( select_timeout_node & this, select_node & node ) { return true; }51 bool on_selected$( select_timeout_node & this, select_node & node ) { return true; } 52 52 -
libcfa/src/concurrency/select.hfa
r8f448e0 r5e0b6657 11 11 // Created On : Thu Jan 21 19:46:50 2023 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Fri Apr 25 07:31:26 202514 // Update Count : 513 // Last Modified On : Sun Nov 23 22:38:36 2025 14 // Update Count : 8 15 15 // 16 16 … … 87 87 // For registering a select stmt on a selectable concurrency primitive 88 88 // Returns bool that indicates if operation is already SAT 89 bool register_select ( T &, select_node & );89 bool register_select$( T &, select_node & ); 90 90 91 91 // For unregistering a select stmt on a selectable concurrency primitive 92 92 // 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 & ); 94 94 95 95 // This routine is run on the selecting thread prior to executing the statement corresponding to the select_node 96 96 // 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 & ); 98 98 }; 99 99 // Used inside the compiler to allow for overloading on return type for operations such as '?<<?' for channels … … 209 209 210 210 // 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 );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 ); 214 214 select_timeout_node __CFA_select_get_type( select_timeout_node this ); 215 215 -
libcfa/src/strstream.cfa
r8f448e0 r5e0b6657 10 10 // Created On : Thu Apr 22 22:24:35 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 14 20:45:00202513 // Update Count : 11 612 // Last Modified On : Sat Oct 11 15:10:56 2025 13 // Update Count : 119 14 14 // 15 15 … … 148 148 abort(); 149 149 } // if 150 os.cursor$ = 0; 150 151 return os; 151 152 } // write … … 155 156 } // write 156 157 158 void clear( ostrstream & os ) { 159 os.cursor$ = 0; 160 } // clear 157 161 158 162 // *********************************** istrstream *********************************** -
libcfa/src/strstream.hfa
r8f448e0 r5e0b6657 10 10 // Created On : Thu Apr 22 22:20:59 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 14 20:57:15202513 // Update Count : 6 112 // Last Modified On : Sat Oct 11 15:11:06 2025 13 // Update Count : 62 14 14 // 15 15 … … 75 75 void ?{}( ostrstream &, char buf[], size_t size ); 76 76 77 void clear( ostrstream & os ); 78 77 79 78 80 // *********************************** istrstream *********************************** -
src/Concurrency/Waituntil.cpp
r8f448e0 r5e0b6657 9 9 // Author : Andrew Beach 10 10 // Created On : Fri May 27 10:31:00 2022 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Jun 13 13:30:00 202213 // Update Count : 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Nov 23 22:37:39 2025 13 // Update Count : 3 14 14 // 15 15 … … 606 606 607 607 // 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$" ) ) ); 609 609 610 610 // generates: if ( when_cond ) { ... currBody ... } … … 638 638 { 639 639 new IfStmt( cLoc, 640 genSelectTraitCall( clause, data, "on_selected " ),640 genSelectTraitCall( clause, data, "on_selected$" ), 641 641 ast::deepCopy( clause->stmt ) 642 642 ) … … 715 715 ) 716 716 ), 717 new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select " ) )717 new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select$" ) ) 718 718 } 719 719 ) … … 1017 1017 const CodeLocation & cLoc = stmt->clauses.at(idx)->location; 1018 1018 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$" ); 1020 1020 Expr * ifCond; 1021 1021 … … 1150 1150 new IfStmt( cLoc, 1151 1151 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$" ) ) 1153 1153 ) 1154 1154 ); … … 1343 1343 ), 1344 1344 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$" ), 1346 1346 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast 1347 1347 ), … … 1372 1372 { 1373 1373 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$" ), 1375 1375 ast::deepCopy( stmt->clauses.at(i)->stmt ) 1376 1376 ) -
tests/concurrency/barrier/generation.cfa
r8f448e0 r5e0b6657 20 20 unsigned NUM_LAPS = 53; 21 21 22 #include < concurrency/barrier.hfa>22 #include <barrier.hfa> 23 23 #include <fstream.hfa> 24 24 #include <mutex_stmt.hfa> … … 45 45 46 46 // Block on the barrier 47 block( bar);47 block( bar ); 48 48 } 49 49 } -
tests/concurrency/barrier/last.cfa
r8f448e0 r5e0b6657 17 17 // function is called at the appropriate time. 18 18 19 #include < concurrency/barrier.hfa>19 #include <barrier.hfa> 20 20 #include <fstream.hfa> 21 21 #include <mutex_stmt.hfa> … … 34 34 volatile unsigned validate_calls = 0; 35 35 36 void validate( ) {36 void validate(...) { 37 37 unsigned vc = validate_calls; 38 38 unsigned expected = generation[0]; -
tests/concurrency/barrier/order.cfa
r8f448e0 r5e0b6657 10 10 // Created On : Fri Apr 01 11:39:09 2022 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Nov 10 11:22:56 202413 // Update Count : 2 012 // Last Modified On : Mon Oct 27 22:44:36 2025 13 // Update Count : 22 14 14 // 15 15 … … 24 24 25 25 volatile unsigned generation = 0; // count laps 26 void last( ) {26 void last( ... ) { 27 27 generation += 1; // last thread at barrier advances 28 28 } -
tests/concurrency/examples/boundedBufferTHREAD.cfa
r8f448e0 r5e0b6657 10 10 // Created On : Wed Apr 18 22:52:12 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 16 23:09:43 202013 // Update Count : 2 512 // Last Modified On : Wed Nov 5 08:05:24 2025 13 // Update Count : 28 14 14 // 15 15 16 #include <stdlib.hfa> // random17 16 #include <fstream.hfa> 18 17 #include <kernel.hfa> … … 65 64 void main( Producer & prod ) with( prod ) { 66 65 for ( i; 1 ~= N ) { 67 yield( random( 5 ) );66 yield( prng( 5 ) ); 68 67 insert( buffer, 1 ); 69 68 } // for … … 81 80 sum = 0; 82 81 for () { 83 yield( random( 5 ) );82 yield( prng( 5 ) ); 84 83 int item = remove( buffer ); 85 84 if ( item == Sentinel ) break; // sentinel ? … … 101 100 processor p; 102 101 103 //srandom( getpid() ); 104 srandom( 1003 ); 102 set_seed( 1003 ); 105 103 106 104 for ( i; Cons ) { // create consumers 107 cons[i] = new( &buffer, sums[i] ); 105 cons[i] = new( &buffer, sums[i] ); // NEW CANNOT HANDLE BUFFER REFERENCE 108 106 } // for 109 107 for ( i; Prods ) { // create producers -
tests/concurrency/examples/datingService.cfa
r8f448e0 r5e0b6657 10 10 // Created On : Mon Oct 30 12:56:20 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Sep 27 15:42:25 202013 // Update Count : 4 012 // Last Modified On : Tue Nov 4 21:58:29 2025 13 // Update Count : 41 14 14 // 15 15 … … 28 28 29 29 unsigned 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 ? 31 31 wait( Girls[ccode] ); // wait for boy 32 32 GirlPhoneNo = PhoneNo; // make phone number available … … 40 40 41 41 unsigned 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 ? 43 43 wait( Boys[ccode] ); // wait for girl 44 44 BoyPhoneNo = PhoneNo; // make phone number available -
tests/concurrency/futures/multi.cfa
r8f448e0 r5e0b6657 1 // DEPRECATED future type multi_future. Eventually remove this test. 2 1 3 #include <thread.hfa> 2 4 #include <future.hfa> -
tests/concurrency/futures/select_future.cfa
r8f448e0 r5e0b6657 1 1 #include <thread.hfa> 2 2 #include <future.hfa> 3 #include < concurrency/barrier.hfa>3 #include <barrier.hfa> 4 4 5 5 enum {NFUTURES = 10}; -
tests/concurrency/futures/typed.cfa
r8f448e0 r5e0b6657 8 8 }; 9 9 10 void ?{}( Server & this) {11 this.cnt = 0;12 for (i; NFUTURES) {13 this.requests[i] = 0p;10 void ?{}( Server & server ) with( server ) { 11 cnt = 0; 12 for ( i; NFUTURES ) { 13 requests[i] = 0p; 14 14 } 15 15 } 16 16 17 void ^?{}( Server & mutex this ){18 assert( this.cnt == 0);19 for (i; NFUTURES) {20 this.requests[i] = 0p;17 void ^?{}( Server & mutex server ) with( server ) { 18 assert( cnt == 0 ); 19 for ( i; NFUTURES ) { 20 requests[i] = 0p; 21 21 } 22 22 } 23 23 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);24 void 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 30 30 } 31 31 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++;32 void 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++; 37 37 return; 38 38 } … … 41 41 } 42 42 43 void main( Server & this) {43 void main( Server & server ) { 44 44 unsigned i = 0; 45 for () {46 waitfor ( ^?{} : this) {45 for () { 46 waitfor ( ^?{} : server ) { 47 47 break; 48 } 49 or when( this.cnt < NFUTURES ) waitfor( call: this ) {} 48 } or when( server.cnt < NFUTURES ) waitfor( call : server ) {} 50 49 or else { 51 process( this, i % NFUTURES );50 process( server, i % NFUTURES ); 52 51 i++; 53 52 } 54 53 } 55 54 56 for (i; NFUTURES) {57 process( this, i );55 for ( i; NFUTURES ) { 56 process( server, i ); 58 57 } 59 58 } … … 62 61 thread Worker {}; 63 62 64 void thrash( void) {63 void thrash() { 65 64 volatile int locals[250]; 66 for (i; 250) {65 for ( i; 250 ) { 67 66 locals[i] = 0xdeadbeef; 68 67 } 69 68 } 70 69 71 void work( void) {70 void work() { 72 71 single_future(int) mine; 73 72 call( *the_server, mine ); 74 wait( mine );73 mine(); // get 75 74 } 76 75 77 76 void main( Worker & ) { 78 for (150) {77 for ( 150 ) { 79 78 thrash(); 80 79 work(); … … 84 83 85 84 int main() { 86 printf( "start\n" ); // non-empty .expect file85 printf( "start\n" ); // non-empty .expect file 87 86 processor procs[2]; 88 87 { … … 93 92 } 94 93 } 95 printf( "done\n" ); // non-empty .expect file 96 94 printf( "done\n" ); // non-empty .expect file 97 95 } -
tests/concurrency/once.cfa
r8f448e0 r5e0b6657 9 9 volatile int check; 10 10 11 void reset( ) {11 void reset( ... ) { 12 12 (global){}; 13 13 check = 0; -
tests/concurrency/readyQ/barrier_sleeper.cfa
r8f448e0 r5e0b6657 17 17 // Processors and thread are removed in an interleaved fashion for a weirder case. 18 18 19 #include < concurrency/barrier.hfa>19 #include <barrier.hfa> 20 20 #include <fstream.hfa> 21 21 #include <time.hfa> -
tests/concurrency/signal/block.cfa
r8f448e0 r5e0b6657 80 80 [a.last_thread, b.last_thread, a.last_signaller, b.last_signaller] = active_thread(); 81 81 82 if( ! is_empty( cond ) ) {82 if( ! empty( cond ) ) { 83 83 84 84 thread$ * next = ( thread$ * ) front( cond ); -
tests/concurrency/waituntil/futures.cfa
r8f448e0 r5e0b6657 1 #include < select.hfa>1 #include <fstream.hfa> 2 2 #include <future.hfa> 3 3 #include <thread.hfa> … … 5 5 future(int) A, B, C; 6 6 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); 7 thread Server {}; 8 void main( Server & ) { 9 B( 3 ); // fulfil( B, 3 ); 10 A( 2 ); 11 C( 4 ); 22 12 } 23 13 24 14 int 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"; 61 55 } -
tests/io/comp_basic.cfa
r8f448e0 r5e0b6657 16 16 17 17 18 #include < concurrency/barrier.hfa>18 #include <barrier.hfa> 19 19 #include <fstream.hfa> 20 20 #include <iofwd.hfa> -
tests/io/comp_fair.cfa
r8f448e0 r5e0b6657 16 16 17 17 18 #include < concurrency/barrier.hfa>18 #include <barrier.hfa> 19 19 #include <fstream.hfa> 20 20 #include <iofwd.hfa>
Note:
See TracChangeset
for help on using the changeset viewer.