Changes in / [5407cdc:feacef9]
- Files:
-
- 49 added
- 110 deleted
- 183 edited
-
Jenkins/FullBuild (modified) (2 diffs)
-
Jenkinsfile (modified) (1 diff)
-
benchmark/Makefile.am (modified) (1 diff)
-
benchmark/basic/ttst_lock.c (modified) (1 diff)
-
benchmark/benchcltr.hfa (modified) (3 diffs)
-
benchmark/io/http/http_ring.cpp (modified) (15 diffs)
-
benchmark/io/http/main.cfa (modified) (8 diffs)
-
benchmark/io/http/options.cfa (modified) (7 diffs)
-
benchmark/io/http/options.hfa (modified) (3 diffs)
-
benchmark/io/http/protocol.cfa (modified) (11 diffs)
-
benchmark/io/http/protocol.hfa (modified) (2 diffs)
-
benchmark/io/http/worker.cfa (modified) (5 diffs)
-
benchmark/io/http/worker.hfa (modified) (1 diff)
-
benchmark/io/readv-posix.c (modified) (2 diffs)
-
benchmark/io/readv.cfa (modified) (2 diffs)
-
benchmark/readyQ/cycle.cc (modified) (2 diffs)
-
benchmark/readyQ/cycle.cfa (modified) (2 diffs)
-
benchmark/readyQ/cycle.cpp (modified) (3 diffs)
-
benchmark/readyQ/locality.cc (deleted)
-
benchmark/readyQ/locality.cfa (modified) (2 diffs)
-
benchmark/readyQ/locality.cpp (modified) (3 diffs)
-
benchmark/readyQ/rq_bench.hfa (modified) (3 diffs)
-
benchmark/readyQ/rq_bench.hpp (modified) (6 diffs)
-
benchmark/readyQ/transfer.cfa (deleted)
-
benchmark/readyQ/transfer.cpp (deleted)
-
benchmark/readyQ/yield.cfa (modified) (2 diffs)
-
doc/LaTeXmacros/lstlang.sty (modified) (2 diffs)
-
doc/bibliography/pl.bib (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/Makefile (modified) (5 diffs)
-
doc/theses/andrew_beach_MMath/exception-hierarchy.fig (deleted)
-
doc/theses/andrew_beach_MMath/existing.tex (modified) (12 diffs)
-
doc/theses/andrew_beach_MMath/features.tex (modified) (17 diffs)
-
doc/theses/andrew_beach_MMath/future.tex (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/implement.tex (modified) (21 diffs)
-
doc/theses/andrew_beach_MMath/stack-marking.fig (deleted)
-
doc/theses/andrew_beach_MMath/thesis-frontpgs.tex (added)
-
doc/theses/andrew_beach_MMath/thesis.bib (added)
-
doc/theses/andrew_beach_MMath/thesis.tex (added)
-
doc/theses/andrew_beach_MMath/uw-ethesis.cls (added)
-
doc/theses/andrew_beach_MMath/uw-ethesis.tex (modified) (5 diffs)
-
doc/theses/mubeen_zulfiqar_MMath/.gitignore (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/AllocDS1.fig (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/AllocDS2.fig (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/Makefile (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/allocator.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/background.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/conclusion.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/intro.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/thesis.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis-frontpgs.tex (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.bib (deleted)
-
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex (deleted)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp (deleted)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/links2.hpp (deleted)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/ntmove.cpp (deleted)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp (modified) (5 diffs)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp (modified) (11 diffs)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp (modified) (2 diffs)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp (modified) (4 diffs)
-
doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp (modified) (7 diffs)
-
doc/user/figures/Cdecl.fig (modified) (3 diffs)
-
doc/user/user.tex (modified) (140 diffs)
-
example/io/batch-readv.c (modified) (2 diffs)
-
example/io/tty-echo.cfa (deleted)
-
libcfa/configure.ac (modified) (2 diffs)
-
libcfa/prelude/builtins.c (modified) (5 diffs)
-
libcfa/prelude/defines.hfa.in (modified) (1 diff)
-
libcfa/src/Makefile.am (modified) (3 diffs)
-
libcfa/src/bits/debug.hfa (modified) (1 diff)
-
libcfa/src/bits/defs.hfa (modified) (1 diff)
-
libcfa/src/bits/locks.hfa (modified) (3 diffs)
-
libcfa/src/bits/queue.hfa (modified) (2 diffs)
-
libcfa/src/bits/weakso_locks.cfa (modified) (1 diff)
-
libcfa/src/bits/weakso_locks.hfa (modified) (2 diffs)
-
libcfa/src/clock.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/alarm.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/clib/cfathread.h (modified) (2 diffs)
-
libcfa/src/concurrency/coroutine.cfa (modified) (5 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/future.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/invoke.c (modified) (2 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (3 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/io/call.cfa.in (modified) (27 diffs)
-
libcfa/src/concurrency/io/setup.cfa (modified) (12 diffs)
-
libcfa/src/concurrency/io/types.hfa (modified) (7 diffs)
-
libcfa/src/concurrency/iofwd.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (33 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (12 diffs)
-
libcfa/src/concurrency/kernel/fwd.hfa (modified) (6 diffs)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (20 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/locks.cfa (modified) (9 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/monitor.hfa (modified) (1 diff)
-
libcfa/src/concurrency/preemption.cfa (modified) (12 diffs)
-
libcfa/src/concurrency/ready_queue.cfa (modified) (19 diffs)
-
libcfa/src/concurrency/ready_subqueue.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/stats.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/stats.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (7 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (4 diffs)
-
libcfa/src/containers/array.hfa (deleted)
-
libcfa/src/containers/list.hfa (modified) (9 diffs)
-
libcfa/src/containers/queueLockFree.hfa (deleted)
-
libcfa/src/exception.c (modified) (3 diffs)
-
libcfa/src/exception.h (modified) (4 diffs)
-
libcfa/src/exception.hfa (modified) (3 diffs)
-
libcfa/src/fstream.cfa (modified) (19 diffs)
-
libcfa/src/fstream.hfa (modified) (7 diffs)
-
libcfa/src/gmp.hfa (modified) (2 diffs)
-
libcfa/src/heap.cfa (modified) (8 diffs)
-
libcfa/src/iostream.cfa (modified) (65 diffs)
-
libcfa/src/iostream.hfa (modified) (20 diffs)
-
libcfa/src/math.hfa (modified) (2 diffs)
-
libcfa/src/startup.cfa (modified) (1 diff)
-
libcfa/src/stdhdr/bfdlink.h (added)
-
libcfa/src/stdhdr/hwloc.h (added)
-
libcfa/src/stdhdr/krb5.h (added)
-
libcfa/src/stdhdr/libltdl/lt_dlloader.h (deleted)
-
libcfa/src/stdhdr/sys/socket.h (deleted)
-
libcfa/src/stdlib.hfa (modified) (7 diffs)
-
libcfa/src/strstream.cfa (deleted)
-
libcfa/src/strstream.hfa (deleted)
-
libcfa/src/time.hfa (modified) (5 diffs)
-
libcfa/src/virtual.c (modified) (2 diffs)
-
src/AST/Convert.cpp (modified) (3 diffs)
-
src/AST/Decl.hpp (modified) (2 diffs)
-
src/AST/Expr.cpp (modified) (1 diff)
-
src/AST/Expr.hpp (modified) (1 diff)
-
src/AST/Fwd.hpp (modified) (2 diffs)
-
src/AST/Node.cpp (modified) (2 diffs)
-
src/AST/Pass.hpp (modified) (1 diff)
-
src/AST/Pass.impl.hpp (modified) (1 diff)
-
src/AST/Print.cpp (modified) (1 diff)
-
src/AST/Type.cpp (modified) (3 diffs)
-
src/AST/Visitor.hpp (modified) (2 diffs)
-
src/CodeGen/CodeGenerator.cc (modified) (2 diffs)
-
src/CodeGen/CodeGenerator.h (modified) (2 diffs)
-
src/Common/CodeLocationTools.cpp (modified) (2 diffs)
-
src/Common/PassVisitor.h (modified) (2 diffs)
-
src/Common/PassVisitor.impl.h (modified) (1 diff)
-
src/Concurrency/Keywords.cc (modified) (10 diffs)
-
src/Parser/DeclarationNode.cc (modified) (10 diffs)
-
src/Parser/ParseNode.h (modified) (3 diffs)
-
src/Parser/TypeData.h (modified) (3 diffs)
-
src/Parser/TypedefTable.cc (modified) (2 diffs)
-
src/Parser/lex.ll (modified) (6 diffs)
-
src/Parser/parser.yy (modified) (53 diffs)
-
src/ResolvExpr/CurrentObject.cc (modified) (1 diff)
-
src/SynTree/Constant.cc (modified) (1 diff)
-
src/SynTree/Constant.h (modified) (1 diff)
-
src/SynTree/Declaration.cc (modified) (2 diffs)
-
src/SynTree/Declaration.h (modified) (2 diffs)
-
src/SynTree/Mutator.h (modified) (2 diffs)
-
src/SynTree/SynTree.h (modified) (2 diffs)
-
src/SynTree/Visitor.h (modified) (2 diffs)
-
src/Virtual/ExpandCasts.cc (modified) (7 diffs)
-
src/Virtual/Tables.cc (modified) (8 diffs)
-
src/Virtual/Tables.h (modified) (3 diffs)
-
src/main.cc (modified) (12 diffs)
-
tests/.expect/KRfunctions.nast.arm64.txt (modified) (1 diff)
-
tests/.expect/KRfunctions.nast.x64.txt (modified) (1 diff)
-
tests/.expect/KRfunctions.nast.x86.txt (modified) (1 diff)
-
tests/.expect/KRfunctions.oast.x64.txt (modified) (1 diff)
-
tests/.expect/attributes.nast.arm64.txt (modified) (21 diffs)
-
tests/.expect/attributes.nast.x64.txt (modified) (19 diffs)
-
tests/.expect/attributes.nast.x86.txt (modified) (19 diffs)
-
tests/.expect/attributes.oast.x64.txt (modified) (19 diffs)
-
tests/.expect/attributes.oast.x86.txt (modified) (19 diffs)
-
tests/.expect/bitmanip2.nast.x86.txt (deleted)
-
tests/.expect/bitmanip2.x86.txt (added)
-
tests/.expect/declarationSpecifier.arm64.txt (modified) (1 diff)
-
tests/.expect/declarationSpecifier.x64.txt (modified) (1 diff)
-
tests/.expect/declarationSpecifier.x86.txt (modified) (1 diff)
-
tests/.expect/extension.arm64.txt (modified) (1 diff)
-
tests/.expect/extension.x64.txt (modified) (1 diff)
-
tests/.expect/extension.x86.txt (modified) (1 diff)
-
tests/.expect/gccExtensions.arm64.txt (modified) (1 diff)
-
tests/.expect/gccExtensions.x64.txt (modified) (1 diff)
-
tests/.expect/gccExtensions.x86.txt (modified) (1 diff)
-
tests/.expect/io1.txt (added)
-
tests/.expect/io2.txt (added)
-
tests/.expect/manipulatorsInput.arm64.txt (added)
-
tests/.expect/manipulatorsInput.x64.txt (added)
-
tests/.expect/manipulatorsInput.x86.txt (added)
-
tests/.expect/manipulatorsOutput1.arm64.txt (added)
-
tests/.expect/manipulatorsOutput1.x64.txt (added)
-
tests/.expect/manipulatorsOutput1.x86.txt (added)
-
tests/.expect/manipulatorsOutput2.arm64.txt (added)
-
tests/.expect/manipulatorsOutput2.x64.txt (added)
-
tests/.expect/manipulatorsOutput2.x86.txt (added)
-
tests/.expect/manipulatorsOutput3.arm64.txt (added)
-
tests/.expect/manipulatorsOutput3.x64.txt (added)
-
tests/.expect/math.nast.arm64.txt (deleted)
-
tests/.expect/math.nast.x64.txt (deleted)
-
tests/.expect/math.nast.x86.txt (deleted)
-
tests/.expect/math1.arm64.txt (added)
-
tests/.expect/math1.oast.arm64.txt (deleted)
-
tests/.expect/math1.oast.x64.txt (deleted)
-
tests/.expect/math1.oast.x86.txt (deleted)
-
tests/.expect/math1.x64.txt (added)
-
tests/.expect/math1.x86.txt (added)
-
tests/.expect/math2.arm64.txt (added)
-
tests/.expect/math2.oast.arm64.txt (deleted)
-
tests/.expect/math2.oast.x64.txt (deleted)
-
tests/.expect/math2.oast.x86.txt (deleted)
-
tests/.expect/math2.x64.txt (added)
-
tests/.expect/math2.x86.txt (added)
-
tests/.expect/math3.arm64.txt (added)
-
tests/.expect/math3.oast.arm64.txt (deleted)
-
tests/.expect/math3.oast.x64.txt (deleted)
-
tests/.expect/math3.oast.x86.txt (deleted)
-
tests/.expect/math3.x64.txt (added)
-
tests/.expect/math3.x86.txt (added)
-
tests/.expect/math4.arm64.txt (added)
-
tests/.expect/math4.oast.arm64.txt (deleted)
-
tests/.expect/math4.oast.x64.txt (deleted)
-
tests/.expect/math4.oast.x86.txt (deleted)
-
tests/.expect/math4.x64.txt (added)
-
tests/.expect/math4.x86.txt (added)
-
tests/.expect/mathX.nast.arm64.txt (deleted)
-
tests/.expect/mathX.nast.x64.txt (deleted)
-
tests/.expect/mathX.nast.x86.txt (deleted)
-
tests/.expect/quasiKeyword.txt (deleted)
-
tests/.expect/strstream.txt (deleted)
-
tests/.in/io.data (added)
-
tests/.in/manipulatorsInput.txt (added)
-
tests/Makefile.am (modified) (6 diffs)
-
tests/array-container/.expect/array-basic.x64.txt (deleted)
-
tests/array-container/array-basic.cfa (deleted)
-
tests/attributes.cfa (modified) (5 diffs)
-
tests/collections/.expect/atomic_mpsc.txt (deleted)
-
tests/collections/atomic_mpsc.cfa (deleted)
-
tests/concurrent/.expect/clib_tls.txt (deleted)
-
tests/concurrent/.expect/semaphore.txt (deleted)
-
tests/concurrent/.expect/spinaphore.txt (deleted)
-
tests/concurrent/clib.c (modified) (6 diffs)
-
tests/concurrent/clib_tls.c (deleted)
-
tests/concurrent/coroutineYield.cfa (modified) (1 diff)
-
tests/concurrent/futures/multi.cfa (modified) (4 diffs)
-
tests/concurrent/semaphore.cfa (deleted)
-
tests/concurrent/spinaphore.cfa (deleted)
-
tests/errors/.expect/completeType.nast.arm64.txt (modified) (10 diffs)
-
tests/exceptions/.expect/resume-threads.txt (modified) (1 diff)
-
tests/exceptions/.expect/resume.txt (modified) (1 diff)
-
tests/exceptions/.expect/terminate-threads.txt (modified) (1 diff)
-
tests/exceptions/.expect/terminate.txt (modified) (1 diff)
-
tests/exceptions/cancel/coroutine.cfa (modified) (2 diffs)
-
tests/exceptions/cancel/thread.cfa (modified) (2 diffs)
-
tests/exceptions/conditional.cfa (modified) (3 diffs)
-
tests/exceptions/data-except.cfa (modified) (1 diff)
-
tests/exceptions/defaults.cfa (modified) (5 diffs)
-
tests/exceptions/finally.cfa (modified) (1 diff)
-
tests/exceptions/interact.cfa (modified) (8 diffs)
-
tests/exceptions/polymorphic.cfa (modified) (5 diffs)
-
tests/exceptions/resume.cfa (modified) (8 diffs)
-
tests/exceptions/terminate.cfa (modified) (8 diffs)
-
tests/exceptions/trash.cfa (modified) (1 diff)
-
tests/exceptions/type-check.cfa (modified) (1 diff)
-
tests/exceptions/virtual-cast.cfa (modified) (4 diffs)
-
tests/exceptions/virtual-poly.cfa (modified) (7 diffs)
-
tests/include/.expect/includes.nast.txt (deleted)
-
tests/include/.expect/vector-containers.txt (deleted)
-
tests/include/.expect/vector-fstream.txt (deleted)
-
tests/include/.expect/vector-sequence.txt (deleted)
-
tests/include/about.txt (deleted)
-
tests/include/includes.cfa (deleted)
-
tests/include/vector-containers.cfa (deleted)
-
tests/include/vector-fstream.cfa (deleted)
-
tests/include/vector-sequence.cfa (deleted)
-
tests/includes/.expect/vector-containers.txt (added)
-
tests/includes/.expect/vector-fstream.txt (added)
-
tests/includes/.expect/vector-sequence.txt (added)
-
tests/includes/about.txt (added)
-
tests/includes/vector-containers.cfa (added)
-
tests/includes/vector-fstream.cfa (added)
-
tests/includes/vector-sequence.cfa (added)
-
tests/io/.expect/io-acquire.txt (deleted)
-
tests/io/.expect/io.nast.txt (deleted)
-
tests/io/.expect/io1.oast.txt (deleted)
-
tests/io/.expect/io2.oast.txt (deleted)
-
tests/io/.expect/manipulatorsInput.arm64.txt (deleted)
-
tests/io/.expect/manipulatorsInput.x64.txt (deleted)
-
tests/io/.expect/manipulatorsInput.x86.txt (deleted)
-
tests/io/.expect/manipulatorsOutput1.arm64.txt (deleted)
-
tests/io/.expect/manipulatorsOutput1.x64.txt (deleted)
-
tests/io/.expect/manipulatorsOutput1.x86.txt (deleted)
-
tests/io/.expect/manipulatorsOutput2.arm64.txt (deleted)
-
tests/io/.expect/manipulatorsOutput2.x64.txt (deleted)
-
tests/io/.expect/manipulatorsOutput2.x86.txt (deleted)
-
tests/io/.expect/manipulatorsOutput3.arm64.txt (deleted)
-
tests/io/.expect/manipulatorsOutput3.x64.txt (deleted)
-
tests/io/.expect/manipulatorsOutput4.x64.txt (deleted)
-
tests/io/.expect/many_read.txt (deleted)
-
tests/io/.in/io-acquire.txt (deleted)
-
tests/io/.in/io.data (deleted)
-
tests/io/.in/manipulatorsInput.txt (deleted)
-
tests/io/.in/many_read.data (deleted)
-
tests/io/io-acquire.cfa (deleted)
-
tests/io/io.cfa (deleted)
-
tests/io/io1.cfa (deleted)
-
tests/io/io2.cfa (deleted)
-
tests/io/manipulatorsInput.cfa (deleted)
-
tests/io/manipulatorsOutput1.cfa (deleted)
-
tests/io/manipulatorsOutput2.cfa (deleted)
-
tests/io/manipulatorsOutput3.cfa (deleted)
-
tests/io/manipulatorsOutput4.cfa (deleted)
-
tests/io/many_read.cfa (deleted)
-
tests/io1.cfa (added)
-
tests/io2.cfa (added)
-
tests/linking/.expect/io-acquire.txt (deleted)
-
tests/linking/.in/io-acquire.txt (deleted)
-
tests/linking/exception-nothreads.cfa (modified) (1 diff)
-
tests/linking/exception-withthreads.cfa (modified) (1 diff)
-
tests/linking/io-acquire.cfa (deleted)
-
tests/linking/weakso_nothd.cfa (modified) (1 diff)
-
tests/manipulatorsInput.cfa (added)
-
tests/manipulatorsOutput1.cfa (added)
-
tests/manipulatorsOutput2.cfa (added)
-
tests/manipulatorsOutput3.cfa (added)
-
tests/math.cfa (deleted)
-
tests/mathX.cfa (deleted)
-
tests/meta/.expect/archVast.nast.arm64.txt (modified) (2 diffs)
-
tests/quasiKeyword.cfa (deleted)
-
tests/strstream.cfa (deleted)
-
tests/time.cfa (modified) (2 diffs)
-
tests/unified_locking/.expect/fast.txt (deleted)
-
tests/unified_locking/.expect/locks.txt (modified) (1 diff)
-
tests/unified_locking/.expect/mcs.txt (deleted)
-
tests/unified_locking/fast.cfa (deleted)
-
tests/unified_locking/locks.cfa (modified) (3 diffs)
-
tests/unified_locking/mcs.cfa (deleted)
-
tests/vector_math/.expect/vec4_float.txt (modified) (1 diff)
-
tests/zombies/includes.c (added)
-
tools/gdb/utils-gdb.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/FullBuild
r5407cdc rfeacef9 18 18 19 19 parallel ( 20 gcc_8_x86_new: { trigger_build( 'gcc-8', 'x86', true ) }, 21 gcc_7_x86_new: { trigger_build( 'gcc-7', 'x86', true ) }, 22 gcc_6_x86_new: { trigger_build( 'gcc-6', 'x86', true ) }, 23 gcc_9_x64_new: { trigger_build( 'gcc-9', 'x64', true ) }, 24 gcc_8_x64_new: { trigger_build( 'gcc-8', 'x64', true ) }, 25 gcc_7_x64_new: { trigger_build( 'gcc-7', 'x64', true ) }, 26 gcc_6_x64_new: { trigger_build( 'gcc-6', 'x64', true ) }, 27 gcc_5_x64_new: { trigger_build( 'gcc-5', 'x64', true ) }, 20 gcc_8_x86_old: { trigger_build( 'gcc-8', 'x86', false ) }, 21 gcc_7_x86_old: { trigger_build( 'gcc-7', 'x86', false ) }, 22 gcc_6_x86_old: { trigger_build( 'gcc-6', 'x86', false ) }, 23 gcc_9_x64_old: { trigger_build( 'gcc-9', 'x64', false ) }, 24 gcc_8_x64_old: { trigger_build( 'gcc-8', 'x64', false ) }, 25 gcc_7_x64_old: { trigger_build( 'gcc-7', 'x64', false ) }, 26 gcc_6_x64_old: { trigger_build( 'gcc-6', 'x64', false ) }, 27 gcc_5_x64_old: { trigger_build( 'gcc-5', 'x64', false ) }, 28 clang_x64_old: { trigger_build( 'clang', 'x64', false ) }, 28 29 clang_x64_new: { trigger_build( 'clang', 'x64', true ) }, 29 clang_x64_old: { trigger_build( 'clang', 'x64', false ) },30 30 ) 31 31 } … … 66 66 67 67 def trigger_build(String cc, String arch, boolean new_ast) { 68 // Randomly delay the builds by a random amount to avoid hitting the SC server to hard69 sleep(time: 5 * Math.random(), unit:"MINUTES")70 71 // Run the build72 // Don't propagate, it doesn't play nice with our email setup73 68 def result = build job: 'Cforall/master', \ 74 69 parameters: [ \ -
Jenkinsfile
r5407cdc rfeacef9 148 148 def test() { 149 149 try { 150 // Print potential limits before testing151 // in case jenkins messes with them152 sh 'free -h'153 sh 'ulimit -a'154 155 150 Tools.BuildStage('Test: short', !Settings.RunAllTests) { 156 151 dir (BuildDir) { -
benchmark/Makefile.am
r5407cdc rfeacef9 502 502 503 503 compile-io$(EXEEXT): 504 $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io /io.cfa504 $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io1.cfa 505 505 506 506 compile-monitor$(EXEEXT): -
benchmark/basic/ttst_lock.c
r5407cdc rfeacef9 9 9 #define CALIGN __attribute__(( aligned (CACHE_ALIGN) )) 10 10 #define CACHE_ALIGN 128 11 #if defined( __i386 ) || defined( __x86_64 ) 12 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 13 #elif defined( __ARM_ARCH ) 14 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 15 #else 16 #error unsupported architecture 17 #endif 11 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 18 12 19 13 typedef uintptr_t TYPE; // addressable word-size -
benchmark/benchcltr.hfa
r5407cdc rfeacef9 114 114 for() { 115 115 sleep(100`ms); 116 end = timeHiRes();116 end = getTimeNsec(); 117 117 Duration delta = end - start; 118 118 /*if(is_tty)*/ { … … 126 126 } 127 127 #else 128 uint64_t timeHiRes() {128 uint64_t getTimeNsec() { 129 129 timespec curr; 130 130 clock_gettime( CLOCK_REALTIME, &curr ); … … 140 140 for(;;) { 141 141 usleep(100000); 142 end = timeHiRes();142 end = getTimeNsec(); 143 143 uint64_t delta = end - start; 144 144 /*if(is_tty)*/ { -
benchmark/io/http/http_ring.cpp
r5407cdc rfeacef9 20 20 socklen_t *addrlen; 21 21 int flags; 22 unsigned cnt;23 22 } acpt; 24 23 … … 68 67 thread_local stats_block_t stats; 69 68 stats_block_t global_stats; 70 71 thread_local struct __attribute__((aligned(128))) {72 size_t to_submit = 0;73 } local;74 69 75 70 // Get an array of current connections … … 197 192 static void submit(struct io_uring * ring, struct io_uring_sqe * sqe, connection * conn) { 198 193 (void)ring; 199 local.to_submit++;200 194 #ifdef USE_ASYNC 201 195 io_uring_sqe_set_flags(sqe, IOSQE_ASYNC); … … 412 406 switch(state) { 413 407 case ACCEPTING: 414 //connection::accept(ring, opt);408 connection::accept(ring, opt); 415 409 newconn(ring, res); 416 410 break; … … 426 420 427 421 //========================================================= 428 extern "C" {429 #include <sys/eventfd.h> // use for termination430 }431 432 422 // Main loop of the WebServer 433 423 // Effectively uses one thread_local copy of everything per kernel thread … … 437 427 struct io_uring * ring = opt.ring; 438 428 439 int blockfd = eventfd(0, 0);440 if (blockfd < 0) {441 fprintf( stderr, "eventfd create error: (%d) %s\n", (int)errno, strerror(errno) );442 exit(EXIT_FAILURE);443 }444 445 int ret = io_uring_register_eventfd(ring, blockfd);446 if (ret < 0) {447 fprintf( stderr, "io_uring S&W error: (%d) %s\n", (int)-ret, strerror(-ret) );448 exit(EXIT_FAILURE);449 }450 451 429 // Track the shutdown using a event_fd 452 430 char endfd_buf[8]; … … 455 433 // Accept our first connection 456 434 // May not take effect until io_uring_submit_and_wait 457 for(unsigned i = 0; i < opt.acpt.cnt; i++) { 458 connection::accept(ring, opt); 459 } 435 connection::accept(ring, opt); 460 436 461 437 int reset = 1; // Counter to print stats once in a while … … 465 441 while(!done) { 466 442 // Submit all the answers we have and wait for responses 467 int ret = io_uring_submit(ring); 468 local.to_submit = 0; 443 int ret = io_uring_submit_and_wait(ring, 1); 469 444 470 445 // check errors … … 477 452 sqes += ret; 478 453 call++; 479 480 481 eventfd_t val;482 ret = eventfd_read(blockfd, &val);483 484 // check errors485 if (ret < 0) {486 fprintf( stderr, "eventfd read error: (%d) %s\n", (int)errno, strerror(errno) );487 exit(EXIT_FAILURE);488 }489 454 490 455 struct io_uring_cqe *cqe; … … 498 463 break; 499 464 } 500 501 if(local.to_submit > 30) break;502 465 503 466 auto req = (class connection *)cqe->user_data; … … 546 509 #include <pthread.h> // for pthreads 547 510 #include <signal.h> // for signal(SIGPIPE, SIG_IGN); 511 #include <sys/eventfd.h> // use for termination 548 512 #include <sys/socket.h> // for sockets in general 549 513 #include <netinet/in.h> // for sockaddr_in, AF_INET … … 564 528 unsigned entries = 256; // number of entries per ring/kernel thread 565 529 unsigned backlog = 262144; // backlog argument to listen 566 unsigned preaccept = 1; // start by accepting X per threads567 530 bool attach = false; // Whether or not to attach all the rings 568 531 bool sqpoll = false; // Whether or not to use SQ Polling … … 571 534 // Arguments Parsing 572 535 int c; 573 while ((c = getopt (argc, argv, "t:p:e:b: c:aS")) != -1) {536 while ((c = getopt (argc, argv, "t:p:e:b:aS")) != -1) { 574 537 switch (c) 575 538 { … … 585 548 case 'b': 586 549 backlog = atoi(optarg); 587 break;588 case 'c':589 preaccept = atoi(optarg);590 550 break; 591 551 case 'a': … … 721 681 thrd_opts[i].acpt.addrlen = (socklen_t*)&addrlen; 722 682 thrd_opts[i].acpt.flags = 0; 723 thrd_opts[i].acpt.cnt = preaccept;724 683 thrd_opts[i].endfd = efd; 725 684 thrd_opts[i].ring = &thrd_rings[i].storage; -
benchmark/io/http/main.cfa
r5407cdc rfeacef9 29 29 30 30 //============================================================================================= 31 // Globals 32 //============================================================================================= 33 struct ServerProc { 34 processor self; 35 }; 36 37 void ?{}( ServerProc & this ) { 38 /* paranoid */ assert( options.clopts.instance != 0p ); 39 (this.self){ "Benchmark Processor", *options.clopts.instance }; 40 41 #if !defined(__CFA_NO_STATISTICS__) 42 if( options.clopts.procstats ) { 43 print_stats_at_exit( this.self, options.clopts.instance->print_stats ); 44 } 45 if( options.clopts.viewhalts ) { 46 print_halts( this.self ); 47 } 48 #endif 49 } 50 51 extern void init_protocol(void); 52 extern void deinit_protocol(void); 53 54 //============================================================================================= 31 55 // Stats Printer 32 56 //=============================================================================================' … … 34 58 thread StatsPrinter {}; 35 59 36 void ?{}( StatsPrinter & this, cluster & cl ) { 37 ((thread&)this){ "Stats Printer Thread", cl }; 38 } 39 40 void ^?{}( StatsPrinter & mutex this ) {} 60 void ?{}( StatsPrinter & this ) { 61 ((thread&)this){ "Stats Printer Thread" }; 62 } 41 63 42 64 void main(StatsPrinter & this) { … … 49 71 sleep(10`s); 50 72 51 print_stats_now( *active_cluster(), CFA_STATS_READY_Q | CFA_STATS_IO ); 52 } 53 } 54 55 //============================================================================================= 56 // Globals 57 //============================================================================================= 58 struct ServerCluster { 59 cluster self; 60 processor * procs; 61 // io_context * ctxs; 62 StatsPrinter * prnt; 63 64 }; 65 66 void ?{}( ServerCluster & this ) { 67 (this.self){ "Server Cluster", options.clopts.params }; 68 69 this.procs = alloc(options.clopts.nprocs); 70 for(i; options.clopts.nprocs) { 71 (this.procs[i]){ "Benchmark Processor", this.self }; 72 73 #if !defined(__CFA_NO_STATISTICS__) 74 if( options.clopts.procstats ) { 75 print_stats_at_exit( *this.procs, this.self.print_stats ); 76 } 77 if( options.clopts.viewhalts ) { 78 print_halts( *this.procs ); 79 } 80 #endif 81 } 82 83 if(options.stats) { 84 this.prnt = alloc(); 85 (*this.prnt){ this.self }; 86 } else { 87 this.prnt = 0p; 88 } 89 90 #if !defined(__CFA_NO_STATISTICS__) 91 print_stats_at_exit( this.self, CFA_STATS_READY_Q | CFA_STATS_IO ); 92 #endif 93 94 options.clopts.instance[options.clopts.cltr_cnt] = &this.self; 95 options.clopts.cltr_cnt++; 96 } 97 98 void ^?{}( ServerCluster & this ) { 99 delete(this.prnt); 100 101 for(i; options.clopts.nprocs) { 102 ^(this.procs[i]){}; 103 } 104 free(this.procs); 105 106 ^(this.self){}; 107 } 108 109 extern void init_protocol(void); 110 extern void deinit_protocol(void); 73 print_stats_now( *options.clopts.instance, CFA_STATS_READY_Q | CFA_STATS_IO ); 74 } 75 } 111 76 112 77 //============================================================================================= … … 172 137 // Run Server Cluster 173 138 { 139 cluster cl = { "Server Cluster", options.clopts.params }; 140 #if !defined(__CFA_NO_STATISTICS__) 141 print_stats_at_exit( cl, CFA_STATS_READY_Q | CFA_STATS_IO ); 142 #endif 143 options.clopts.instance = &cl; 144 145 174 146 int pipe_cnt = options.clopts.nworkers * 2; 175 147 int pipe_off; … … 181 153 } 182 154 183 //if(options.file_cache.path && options.file_cache.fixed_fds) {184 //register_fixed_files(cl, fds, pipe_off);185 //}155 if(options.file_cache.path && options.file_cache.fixed_fds) { 156 register_fixed_files(cl, fds, pipe_off); 157 } 186 158 187 159 { 188 ServerCluster cl[options.clopts.nclusters]; 160 ServerProc procs[options.clopts.nprocs]; 161 StatsPrinter printer; 189 162 190 163 init_protocol(); … … 207 180 unpark( workers[i] ); 208 181 } 209 sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors /" | options.clopts.nclusters | "clusters"; 210 for(i; options.clopts.nclusters) { 211 sout | options.clopts.thrd_cnt[i] | nonl; 212 } 213 sout | nl; 182 sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors"; 214 183 { 215 184 char buffer[128]; 216 for() { 217 int ret = cfa_read(0, buffer, 128, 0); 218 if(ret == 0) break; 185 while(int ret = cfa_read(0, buffer, 128, 0, -1`s, 0p, 0p); ret != 0) { 219 186 if(ret < 0) abort( "main read error: (%d) %s\n", (int)errno, strerror(errno) ); 220 sout | "User wrote '" | "" | nonl;221 write(sout, buffer, ret - 1);222 sout | "'";223 187 } 224 188 … … 229 193 for(i; options.clopts.nworkers) { 230 194 workers[i].done = true; 195 cancel(workers[i].cancel); 231 196 } 232 197 sout | "done"; … … 256 221 sout | "done"; 257 222 258 sout | "Stopping processors /clusters..." | nonl; flush( sout );223 sout | "Stopping processors..." | nonl; flush( sout ); 259 224 } 260 225 sout | "done"; -
benchmark/io/http/options.cfa
r5407cdc rfeacef9 13 13 #include <kernel.hfa> 14 14 #include <parseargs.hfa> 15 #include <stdlib.hfa>16 15 17 16 #include <stdlib.h> … … 20 19 Options options @= { 21 20 false, // log 22 false, // stats23 21 24 22 { // file_cache … … 38 36 39 37 { // cluster 40 1, // nclusters;41 38 1, // nprocs; 42 39 1, // nworkers; … … 49 46 50 47 void parse_options( int argc, char * argv[] ) { 51 // bool fixedfd = false; 52 // bool sqkpoll = false; 53 // bool iokpoll = false; 48 bool subthrd = false; 49 bool eagrsub = false; 50 bool fixedfd = false; 51 bool sqkpoll = false; 52 bool iokpoll = false; 53 unsigned sublen = 16; 54 54 unsigned nentries = 16; 55 bool isolate = false;56 55 57 56 … … 60 59 { 'c', "cpus", "Number of processors to use", options.clopts.nprocs}, 61 60 { 't', "threads", "Number of worker threads to use", options.clopts.nworkers}, 62 {'\0', "isolate", "Create one cluster per processor", isolate, parse_settrue},63 61 {'\0', "log", "Enable logs", options.log, parse_settrue}, 64 {'\0', "stats", "Enable statistics", options.stats, parse_settrue},65 62 {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog}, 66 63 {'\0', "request_len", "Maximum number of bytes in the http request, requests with more data will be answered with Http Code 414", options.socket.buflen}, … … 68 65 {'\0', "cache-size", "Size of the cache to use, if set to small, will uses closes power of 2", options.file_cache.size }, 69 66 {'\0', "list-files", "List the files in the specified path and exit", options.file_cache.list, parse_settrue }, 70 // { 'f', "fixed-fds", "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue}, 71 // { 'k', "kpollsubmit", "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue }, 72 // { 'i', "kpollcomplete", "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue }, 73 {'e', "numentries", "Number of I/O entries", nentries }, 67 { 's', "submitthread", "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue }, 68 { 'e', "eagersubmit", "If set, cluster submits I/O eagerly but still aggregates submits", eagrsub, parse_settrue}, 69 { 'f', "fixed-fds", "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue}, 70 { 'k', "kpollsubmit", "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue }, 71 { 'i', "kpollcomplete", "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue }, 72 {'\0', "submitlength", "Max number of submitions that can be submitted together", sublen }, 73 {'\0', "numentries", "Number of I/O entries", nentries }, 74 74 75 75 }; … … 91 91 nentries = v; 92 92 } 93 if(isolate) {94 options.clopts.nclusters = options.clopts.nprocs;95 options.clopts.nprocs = 1;96 }97 93 options.clopts.params.num_entries = nentries; 98 options.clopts.instance = alloc(options.clopts.nclusters); 99 options.clopts.thrd_cnt = alloc(options.clopts.nclusters); 100 options.clopts.cltr_cnt = 0; 101 for(i; options.clopts.nclusters) { 102 options.clopts.thrd_cnt[i] = 0; 94 95 options.clopts.params.poller_submits = subthrd; 96 options.clopts.params.eager_submits = eagrsub; 97 98 if( fixedfd ) { 99 options.file_cache.fixed_fds = true; 103 100 } 104 101 102 if( sqkpoll ) { 103 options.clopts.params.poll_submit = true; 104 options.file_cache.fixed_fds = true; 105 } 105 106 106 // if( fixedfd ) { 107 // options.file_cache.fixed_fds = true; 108 // } 107 if( iokpoll ) { 108 options.clopts.params.poll_complete = true; 109 options.file_cache.open_flags |= O_DIRECT; 110 } 109 111 110 // if( sqkpoll ) { 111 // options.file_cache.fixed_fds = true; 112 // } 113 114 // if( iokpoll ) { 115 // options.file_cache.open_flags |= O_DIRECT; 116 // } 112 options.clopts.params.num_ready = sublen; 117 113 118 114 if( left[0] == 0p ) { return; } -
benchmark/io/http/options.hfa
r5407cdc rfeacef9 9 9 struct Options { 10 10 bool log; 11 bool stats;12 11 13 12 struct { … … 27 26 28 27 struct { 29 int nclusters;30 28 int nprocs; 31 29 int nworkers; … … 33 31 bool procstats; 34 32 bool viewhalts; 35 cluster ** instance; 36 size_t * thrd_cnt; 37 size_t cltr_cnt; 33 cluster * instance; 38 34 } clopts; 39 35 }; -
benchmark/io/http/protocol.cfa
r5407cdc rfeacef9 5 5 #include <fcntl.h> 6 6 } 7 8 #define xstr(s) str(s)9 #define str(s) #s10 7 11 8 #include <fstream.hfa> … … 23 20 #include "options.hfa" 24 21 25 #define PLAINTEXT_1WRITE 26 #define PLAINTEXT_MEMCPY 27 #define PLAINTEXT_NOCOPY 28 29 struct https_msg_str { 30 char msg[512]; 31 size_t len; 32 }; 33 34 const https_msg_str * volatile http_msgs[KNOWN_CODES] = { 0 }; 22 const char * volatile date = 0p; 23 24 const char * http_msgs[] = { 25 "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: %zu \n\n", 26 "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 27 "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 28 "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 29 "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 30 "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 31 "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 32 }; 35 33 36 34 _Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0]))); 37 35 38 const int http_codes[KNOWN_CODES] = { 39 200, 36 const int http_codes[] = { 40 37 200, 41 38 400, … … 56 53 while(len > 0) { 57 54 // Call write 58 int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY); 55 int ret = cfa_write(fd, it, len, 0, -1`s, 0p, 0p); 56 // int ret = write(fd, it, len); 59 57 if( ret < 0 ) { 60 58 if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET; … … 74 72 /* paranoid */ assert( code < KNOWN_CODES && code != OK200 ); 75 73 int idx = (int)code; 76 return answer( fd, http_msgs[idx] ->msg, http_msgs[idx]->len);74 return answer( fd, http_msgs[idx], strlen( http_msgs[idx] ) ); 77 75 } 78 76 79 77 int answer_header( int fd, size_t size ) { 80 char buffer[512]; 81 char * it = buffer; 82 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 83 it += http_msgs[OK200]->len; 84 int len = http_msgs[OK200]->len; 85 len += snprintf(it, 512 - len, "%d \n\n", size); 78 const char * fmt = http_msgs[OK200]; 79 int len = 200; 80 char buffer[len]; 81 len = snprintf(buffer, len, fmt, date, size); 86 82 return answer( fd, buffer, len ); 87 83 } 88 84 89 #if defined(PLAINTEXT_NOCOPY) 90 int answer_plaintext( int fd ) { 91 return answer(fd, http_msgs[OK200_PlainText]->msg, http_msgs[OK200_PlainText]->len); // +1 cause snprintf doesn't count nullterminator 92 } 93 #elif defined(PLAINTEXT_MEMCPY) 94 #define TEXTSIZE 15 95 int answer_plaintext( int fd ) { 96 char text[] = "Hello, World!\n\n"; 97 char ts[] = xstr(TEXTSIZE) " \n\n"; 98 _Static_assert(sizeof(text) - 1 == TEXTSIZE); 99 char buffer[512 + TEXTSIZE]; 100 char * it = buffer; 101 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 102 it += http_msgs[OK200]->len; 103 int len = http_msgs[OK200]->len; 104 memcpy(it, ts, sizeof(ts) - 1); 105 it += sizeof(ts) - 1; 106 len += sizeof(ts) - 1; 107 memcpy(it, text, TEXTSIZE); 108 return answer(fd, buffer, len + TEXTSIZE); 109 } 110 #elif defined(PLAINTEXT_1WRITE) 111 int answer_plaintext( int fd ) { 112 char text[] = "Hello, World!\n\n"; 113 char buffer[512 + sizeof(text)]; 114 char * it = buffer; 115 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 116 it += http_msgs[OK200]->len; 117 int len = http_msgs[OK200]->len; 118 int r = snprintf(it, 512 - len, "%d \n\n", sizeof(text)); 119 it += r; 120 len += r; 121 memcpy(it, text, sizeof(text)); 122 return answer(fd, buffer, len + sizeof(text)); 123 } 124 #else 125 int answer_plaintext( int fd ) { 126 char text[] = "Hello, World!\n\n"; 127 int ret = answer_header(fd, sizeof(text)); 85 int answer_plain( int fd, char buffer[], size_t size ) { 86 int ret = answer_header(fd, size); 128 87 if( ret < 0 ) return ret; 129 return answer(fd, text, sizeof(text)); 130 } 131 #endif 88 return answer(fd, buffer, size); 89 } 132 90 133 91 int answer_empty( int fd ) { … … 136 94 137 95 138 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len ) {96 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation * cancel) { 139 97 char * it = buffer; 140 98 size_t count = len - 1; … … 142 100 READ: 143 101 for() { 144 int ret = cfa_re cv(fd, (void*)it, count, 0, CFA_IO_LAZY);102 int ret = cfa_read(fd, (void*)it, count, 0, -1`s, cancel, 0p); 145 103 // int ret = read(fd, (void*)it, count); 146 104 if(ret == 0 ) return [OK200, true, 0, 0]; … … 181 139 ssize_t ret; 182 140 SPLICE1: while(count > 0) { 183 ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, CFA_IO_LAZY); 141 ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, 0, -1`s, 0p, 0p); 142 // ret = splice(ans_fd, &offset, pipe[1], 0p, count, sflags); 184 143 if( ret < 0 ) { 185 144 if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1; … … 193 152 size_t in_pipe = ret; 194 153 SPLICE2: while(in_pipe > 0) { 195 ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, CFA_IO_LAZY); 154 ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, 0, -1`s, 0p, 0p); 155 // ret = splice(pipe[0], 0p, fd, 0p, in_pipe, sflags); 196 156 if( ret < 0 ) { 197 157 if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2; … … 213 173 #include <thread.hfa> 214 174 215 const char * original_http_msgs[] = {216 "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",217 "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 15\n\nHello, World!\n\n",218 "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",219 "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",220 "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",221 "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",222 "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",223 "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",224 };225 226 175 struct date_buffer { 227 https_msg_str strs[KNOWN_CODES];176 char buff[100]; 228 177 }; 229 178 … … 234 183 235 184 void ?{}( DateFormater & this ) { 236 ((thread&)this){ "Server Date Thread", *options.clopts.instance [0]};185 ((thread&)this){ "Server Date Thread", *options.clopts.instance }; 237 186 this.idx = 0; 238 memset( &this.buffers[0], 0, sizeof(this.buffers[0]) );239 memset( &this.buffers[1], 0, sizeof(this.buffers[1]) );187 memset( this.buffers[0].buff, 0, sizeof(this.buffers[0]) ); 188 memset( this.buffers[1].buff, 0, sizeof(this.buffers[1]) ); 240 189 } 241 190 … … 247 196 or else {} 248 197 249 250 char buff[100]; 251 Time now = timeHiRes(); 252 strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now ); 253 sout | "Updated date to '" | buff | "'"; 254 255 for(i; KNOWN_CODES) { 256 size_t len = snprintf( this.buffers[this.idx].strs[i].msg, 512, original_http_msgs[i], buff ); 257 this.buffers[this.idx].strs[i].len = len; 258 } 259 260 for(i; KNOWN_CODES) { 261 https_msg_str * next = &this.buffers[this.idx].strs[i]; 262 __atomic_exchange_n((https_msg_str * volatile *)&http_msgs[i], next, __ATOMIC_SEQ_CST); 263 } 198 Time now = getTimeNsec(); 199 200 strftime( this.buffers[this.idx].buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now ); 201 202 char * next = this.buffers[this.idx].buff; 203 __atomic_exchange_n((char * volatile *)&date, next, __ATOMIC_SEQ_CST); 264 204 this.idx = (this.idx + 1) % 2; 265 266 sout | "Date thread sleeping";267 205 268 206 sleep(1`s); -
benchmark/io/http/protocol.hfa
r5407cdc rfeacef9 1 1 #pragma once 2 3 struct io_cancellation; 2 4 3 5 enum HttpCode { 4 6 OK200 = 0, 5 OK200_PlainText,6 7 E400, 7 8 E404, … … 17 18 int answer_error( int fd, HttpCode code ); 18 19 int answer_header( int fd, size_t size ); 19 int answer_plain text( int fd);20 int answer_plain( int fd, char buffer [], size_t size ); 20 21 int answer_empty( int fd ); 21 22 22 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len );23 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation *); 23 24 24 25 int sendfile( int pipe[2], int fd, int ans_fd, size_t count ); -
benchmark/io/http/worker.cfa
r5407cdc rfeacef9 17 17 //============================================================================================= 18 18 void ?{}( Worker & this ) { 19 size_t cli = rand() % options.clopts.cltr_cnt; 20 ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 512000 }; 21 options.clopts.thrd_cnt[cli]++; 19 ((thread&)this){ "Server Worker Thread", *options.clopts.instance }; 22 20 this.pipe[0] = -1; 23 21 this.pipe[1] = -1; … … 37 35 for() { 38 36 if( options.log ) sout | "=== Accepting connection ==="; 39 int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], CFA_IO_LAZY ); 37 int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], 0, -1`s, &this.cancel, 0p ); 38 // int fd = accept4( this.[sockfd, addr, addrlen, flags] ); 40 39 if(fd < 0) { 41 40 if( errno == ECONNABORTED ) break; … … 43 42 abort( "accept error: (%d) %s\n", (int)errno, strerror(errno) ); 44 43 } 45 if(this.done) break;46 44 47 45 if( options.log ) sout | "=== New connection" | fd | "" | ", waiting for requests ==="; … … 57 55 char buffer[len]; 58 56 if( options.log ) sout | "=== Reading request ==="; 59 [code, closed, file, name_size] = http_read(fd, buffer, len );57 [code, closed, file, name_size] = http_read(fd, buffer, len, &this.cancel); 60 58 61 59 // if we are done, break out of the loop … … 72 70 if( options.log ) sout | "=== Request for /plaintext ==="; 73 71 74 int ret = answer_plaintext(fd); 72 char text[] = "Hello, World!\n"; 73 74 // Send the header 75 int ret = answer_plain(fd, text, sizeof(text)); 75 76 if( ret == -ECONNRESET ) break REQUEST; 76 77 -
benchmark/io/http/worker.hfa
r5407cdc rfeacef9 17 17 socklen_t * addrlen; 18 18 int flags; 19 io_cancellation cancel; 19 20 volatile bool done; 20 21 }; -
benchmark/io/readv-posix.c
r5407cdc rfeacef9 111 111 printf("Starting\n"); 112 112 bool is_tty = isatty(STDOUT_FILENO); 113 start = timeHiRes();113 start = getTimeNsec(); 114 114 run = true; 115 115 … … 118 118 119 119 run = false; 120 end = timeHiRes();120 end = getTimeNsec(); 121 121 printf("\nDone\n"); 122 122 -
benchmark/io/readv.cfa
r5407cdc rfeacef9 147 147 printf("Starting\n"); 148 148 bool is_tty = isatty(STDOUT_FILENO); 149 start = timeHiRes();149 start = getTimeNsec(); 150 150 run = true; 151 151 … … 156 156 157 157 run = false; 158 end = timeHiRes();158 end = getTimeNsec(); 159 159 printf("\nDone\n"); 160 160 } -
benchmark/readyQ/cycle.cc
r5407cdc rfeacef9 89 89 90 90 bool is_tty = isatty(STDOUT_FILENO); 91 start = timeHiRes();91 start = getTimeNsec(); 92 92 93 93 for(int i = 0; i < nthreads; i++) { … … 97 97 98 98 stop = true; 99 end = timeHiRes();99 end = getTimeNsec(); 100 100 printf("\nDone\n"); 101 101 -
benchmark/readyQ/cycle.cfa
r5407cdc rfeacef9 65 65 66 66 bool is_tty = isatty(STDOUT_FILENO); 67 start = timeHiRes();67 start = getTimeNsec(); 68 68 69 69 for(i; nthreads) { … … 73 73 74 74 stop = true; 75 end = timeHiRes();75 end = getTimeNsec(); 76 76 printf("\nDone\n"); 77 77 -
benchmark/readyQ/cycle.cpp
r5407cdc rfeacef9 3 3 #include <libfibre/fibre.h> 4 4 5 class __attribute__((aligned(128))) bench_sem { 6 Fibre * volatile ptr = nullptr; 7 public: 8 inline bool wait() { 9 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull); 10 for(;;) { 11 Fibre * expected = this->ptr; 12 if(expected == ready) { 13 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 14 return false; 15 } 16 } 17 else { 18 /* paranoid */ assert( expected == nullptr ); 19 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 20 fibre_park(); 21 return true; 22 } 23 } 24 25 } 26 } 27 28 inline bool post() { 29 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull); 30 for(;;) { 31 Fibre * expected = this->ptr; 32 if(expected == ready) return false; 33 if(expected == nullptr) { 34 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 35 return false; 36 } 37 } 38 else { 39 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 40 fibre_unpark( expected ); 41 return true; 42 } 43 } 44 } 45 } 46 }; 5 47 struct Partner { 6 48 unsigned long long count = 0; … … 51 93 52 94 bool is_tty = isatty(STDOUT_FILENO); 53 start = timeHiRes();95 start = getTimeNsec(); 54 96 55 97 for(int i = 0; i < nthreads; i++) { … … 59 101 60 102 stop = true; 61 end = timeHiRes();103 end = getTimeNsec(); 62 104 printf("\nDone\n"); 63 105 -
benchmark/readyQ/locality.cfa
r5407cdc rfeacef9 232 232 233 233 bool is_tty = isatty(STDOUT_FILENO); 234 start = timeHiRes();234 start = getTimeNsec(); 235 235 236 236 for(i; nthreads) { … … 240 240 241 241 stop = true; 242 end = timeHiRes();242 end = getTimeNsec(); 243 243 printf("\nDone\n"); 244 244 -
benchmark/readyQ/locality.cpp
r5407cdc rfeacef9 9 9 uint64_t dmigs = 0; 10 10 uint64_t gmigs = 0; 11 }; 12 13 class __attribute__((aligned(128))) bench_sem { 14 Fibre * volatile ptr = nullptr; 15 public: 16 inline bool wait() { 17 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull); 18 for(;;) { 19 Fibre * expected = this->ptr; 20 if(expected == ready) { 21 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 22 return false; 23 } 24 } 25 else { 26 /* paranoid */ assert( expected == nullptr ); 27 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 28 fibre_park(); 29 return true; 30 } 31 } 32 33 } 34 } 35 36 inline bool post() { 37 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull); 38 for(;;) { 39 Fibre * expected = this->ptr; 40 if(expected == ready) return false; 41 if(expected == nullptr) { 42 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 43 return false; 44 } 45 } 46 else { 47 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 48 fibre_unpark( expected ); 49 return true; 50 } 51 } 52 } 53 } 11 54 }; 12 55 … … 244 287 245 288 bool is_tty = isatty(STDOUT_FILENO); 246 start = timeHiRes();289 start = getTimeNsec(); 247 290 248 291 for(size_t i = 0; i < nthreads; i++) { … … 252 295 253 296 stop = true; 254 end = timeHiRes();297 end = getTimeNsec(); 255 298 printf("\nDone\n"); 256 299 -
benchmark/readyQ/rq_bench.hfa
r5407cdc rfeacef9 4 4 #include <stdio.h> 5 5 #include <stdlib.hfa> 6 #include <stats.hfa>7 6 #include <thread.hfa> 8 7 #include <time.hfa> … … 64 63 (*p){ "Benchmark Processor", this.cl }; 65 64 } 66 #if !defined(__CFA_NO_STATISTICS__)67 print_stats_at_exit( this.cl, CFA_STATS_READY_Q );68 #endif69 65 } 70 66 … … 77 73 for() { 78 74 sleep(100`ms); 79 Time end = timeHiRes();75 Time end = getTimeNsec(); 80 76 Duration delta = end - start; 81 77 if(is_tty) { -
benchmark/readyQ/rq_bench.hpp
r5407cdc rfeacef9 6 6 #include <time.h> // timespec 7 7 #include <sys/time.h> // timeval 8 9 typedef __uint128_t __lehmer64_state_t;10 static inline uint64_t __lehmer64( __lehmer64_state_t & state ) {11 state *= 0xda942042e4dd58b5;12 return state >> 64;13 }14 8 15 9 enum { TIMEGRAN = 1000000000LL }; // nanosecond granularity, except for timeval … … 52 46 } 53 47 54 uint64_t timeHiRes() {48 uint64_t getTimeNsec() { 55 49 timespec curr; 56 50 clock_gettime( CLOCK_REALTIME, &curr ); … … 66 60 for(;;) { 67 61 Sleeper::usleep(100000); 68 uint64_t end = timeHiRes();62 uint64_t end = getTimeNsec(); 69 63 uint64_t delta = end - start; 70 64 if(is_tty) { … … 80 74 } 81 75 } 82 83 class Fibre;84 int fibre_park();85 int fibre_unpark( Fibre * );86 Fibre * fibre_self();87 88 class __attribute__((aligned(128))) bench_sem {89 Fibre * volatile ptr = nullptr;90 public:91 inline bool wait() {92 static Fibre * const ready = reinterpret_cast<Fibre *>(1ull);93 for(;;) {94 Fibre * expected = this->ptr;95 if(expected == ready) {96 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {97 return false;98 }99 }100 else {101 /* paranoid */ assert( expected == nullptr );102 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {103 fibre_park();104 return true;105 }106 }107 108 }109 }110 111 inline bool post() {112 static Fibre * const ready = reinterpret_cast<Fibre *>(1ull);113 for(;;) {114 Fibre * expected = this->ptr;115 if(expected == ready) return false;116 if(expected == nullptr) {117 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {118 return false;119 }120 }121 else {122 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {123 fibre_unpark( expected );124 return true;125 }126 }127 }128 }129 };130 76 131 77 // ========================================================================================== … … 242 188 this->help = help; 243 189 this->variable = reinterpret_cast<void*>(&variable); 244 #pragma GCC diagnostic push 245 #pragma GCC diagnostic ignored "-Wcast-function-type" 246 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse)); 247 #pragma GCC diagnostic pop 190 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse)); 248 191 } 249 192 … … 254 197 this->help = help; 255 198 this->variable = reinterpret_cast<void*>(&variable); 256 #pragma GCC diagnostic push 257 #pragma GCC diagnostic ignored "-Wcast-function-type" 258 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(parse); 259 #pragma GCC diagnostic pop 199 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(parse); 260 200 } 261 201 }; -
benchmark/readyQ/yield.cfa
r5407cdc rfeacef9 66 66 67 67 bool is_tty = isatty(STDOUT_FILENO); 68 start = timeHiRes();68 start = getTimeNsec(); 69 69 run = true; 70 70 … … 75 75 76 76 run = false; 77 end = timeHiRes();77 end = getTimeNsec(); 78 78 printf("\nDone\n"); 79 79 } -
doc/LaTeXmacros/lstlang.sty
r5407cdc rfeacef9 8 8 %% Created On : Sat May 13 16:34:42 2017 9 9 %% Last Modified By : Peter A. Buhr 10 %% Last Modified On : Wed Feb 17 09:21:15 202111 %% Update Count : 2 710 %% Last Modified On : Wed Sep 23 22:40:04 2020 11 %% Update Count : 24 12 12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 13 … … 113 113 morekeywords={ 114 114 _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__, 115 auto, basetypeof,_Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,116 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, fixup,115 auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__, 116 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, 117 117 __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__, 118 118 inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or, 119 otype, restrict, __restrict, __restrict__, recover, report, __signed, __signed__, _Static_assert, suspend,120 thread,_Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,119 otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread, 120 _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__, 121 121 virtual, __volatile, __volatile__, waitfor, when, with, zero_t, 122 122 }, -
doc/bibliography/pl.bib
r5407cdc rfeacef9 1797 1797 } 1798 1798 1799 @article{Delisle2 1,1799 @article{Delisle20, 1800 1800 keywords = {concurrency, Cforall}, 1801 1801 contributer = {pabuhr@plg}, 1802 1802 author = {Thierry Delisle and Peter A. Buhr}, 1803 1803 title = {Advanced Control-flow and Concurrency in \textsf{C}$\mathbf{\forall}$}, 1804 year = 2020, 1804 1805 journal = spe, 1805 month = may, 1806 year = 2021, 1807 volume = 51, 1808 number = 5, 1809 pages = {1005-1042}, 1810 note = {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}}, 1806 pages = {1-38}, 1807 note = {\href{https://doi-org.proxy.lib.uwaterloo.ca/10.1002/spe.2925}{https://\-doi-org.proxy.lib.uwaterloo.ca/\-10.1002/\-spe.2925}}, 1808 note = {}, 1811 1809 } 1812 1810 … … 3302 3300 month = jan, 3303 3301 address = {Waterloo, Ontario, Canada, N2L 3G1}, 3304 note = {\ href{http://uwspace.uwaterloo.ca/bitstream/10012/3501/1/Thesis.pdf}{http://\-uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}},3302 note = {\textsf{http://uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}}, 3305 3303 } 3306 3304 -
doc/theses/andrew_beach_MMath/Makefile
r5407cdc rfeacef9 4 4 BUILD=out 5 5 TEXSRC=$(wildcard *.tex) 6 FIGSRC=$(wildcard *.fig)7 6 BIBSRC=$(wildcard *.bib) 8 7 STYSRC=$(wildcard *.sty) … … 14 13 BASE= ${DOC:%.pdf=%} 15 14 16 RAWSRC=${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC}17 FIGTEX=${FIGSRC:%.fig=${BUILD}/%.tex}18 19 15 ### Special Rules: 20 16 … … 22 18 23 19 ### Commands: 24 LATEX=TEXINPUTS=${TEXLIB} latex -halt-on-error -output-directory=${BUILD}20 LATEX=TEXINPUTS=${TEXLIB} pdflatex -halt-on-error -output-directory=${BUILD} 25 21 BIBTEX=BIBINPUTS=${BIBLIB} bibtex 26 22 GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite … … 30 26 all: ${DOC} 31 27 32 # The main rule, it does all the tex/latex processing. 33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD} 28 ${BUILD}/${DOC}: ${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC} Makefile | ${BUILD} 34 29 ${LATEX} ${BASE} 35 30 ${BIBTEX} ${BUILD}/${BASE} … … 38 33 ${LATEX} ${BASE} 39 34 40 # Convert xfig output to tex. (Generates \special declarations.) 41 ${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD} 42 fig2dev -L eepic $< > $@ 43 44 # Step through dvi & postscript to handle xfig specials. 45 %.pdf : ${BUILD}/%.dvi 46 dvipdf $^ $@ 35 ${DOC}: ${BUILD}/${DOC} 36 cp $< $@ 47 37 48 38 ${BUILD}: -
doc/theses/andrew_beach_MMath/existing.tex
r5407cdc rfeacef9 14 14 \section{Overloading and \lstinline{extern}} 15 15 \CFA has extensive overloading, allowing multiple definitions of the same name 16 to be defined ~\cite{Moss18}.16 to be defined.~\cite{Moss18} 17 17 \begin{cfa} 18 18 char i; int i; double i; $\C[3.75in]{// variable overload}$ … … 46 46 pointers using the ampersand (@&@) instead of the pointer asterisk (@*@). \CFA 47 47 references may also be mutable or non-mutable. If mutable, a reference variable 48 may be assigned using the address-of operator (@&@), which converts the48 may be assigned to using the address-of operator (@&@), which converts the 49 49 reference to a pointer. 50 50 \begin{cfa} … … 58 58 \section{Constructors and Destructors} 59 59 60 Both constructors and destructors are operators, which means they are 60 Both constructors and destructors are operators, which means they are just 61 61 functions with special operator names rather than type names in \Cpp. The 62 62 special operator names may be used to call the functions explicitly (not … … 64 64 65 65 In general, operator names in \CFA are constructed by bracketing an operator 66 token with @?@, which indicates the position ofthe arguments. For example, infixed66 token with @?@, which indicates where the arguments. For example, infixed 67 67 multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it 68 68 easy to tell the difference between prefix operations (such as @++?@) and … … 89 89 definition, \CFA creates a default and copy constructor, destructor and 90 90 assignment (like \Cpp). It is possible to define constructors/destructors for 91 basic and existing types (unlike \Cpp).91 basic and existing types. 92 92 93 93 \section{Polymorphism} … … 120 120 do_once(value); 121 121 } 122 void do_once( @int@i) { ... } // provide assertion123 @int@i;122 void do_once(int i) { ... } // provide assertion 123 int i; 124 124 do_twice(i); // implicitly pass assertion do_once to do_twice 125 125 \end{cfa} … … 172 172 declarations instead of parameters, returns, and local variable declarations. 173 173 \begin{cfa} 174 forall(dtype @T@)174 forall(dtype T) 175 175 struct node { 176 node(@T@) * next; // generic linked node 177 @T@ * data; 178 } 179 node(@int@) inode; 176 node(T) * next; // generic linked node 177 T * data; 178 } 180 179 \end{cfa} 181 180 The generic type @node(T)@ is an example of a polymorphic-type usage. Like \Cpp 182 template usage, a polymorphic-type usage must specify a type parameter.181 templates usage, a polymorphic-type usage must specify a type parameter. 183 182 184 183 There are many other polymorphism features in \CFA but these are the ones used 185 184 by the exception system. 186 185 187 \section{Con trol Flow}188 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, @monitor@, @mutex@ parameters, and @thread@.189 The two features that interact with190 the exception system are @ coroutine@ and @thread@; they and their supporting186 \section{Concurrency} 187 \CFA has a number of concurrency features: @thread@, @monitor@, @mutex@ 188 parameters, @coroutine@ and @generator@. The two features that interact with 189 the exception system are @thread@ and @coroutine@; they and their supporting 191 190 constructs are described here. 192 191 … … 217 216 CountUp countup; 218 217 \end{cfa} 219 Each coroutine has a@main@ function, which takes a reference to a coroutine218 Each coroutine has @main@ function, which takes a reference to a coroutine 220 219 object and returns @void@. 221 220 \begin{cfa}[numbers=left] … … 231 230 In this function, or functions called by this function (helper functions), the 232 231 @suspend@ statement is used to return execution to the coroutine's caller 233 without terminating the coroutine 's function.232 without terminating the coroutine. 234 233 235 234 A coroutine is resumed by calling the @resume@ function, \eg @resume(countup)@. … … 243 242 @resume(countup).next@. 244 243 245 \subsection{Monitor and Mutex Parameter}244 \subsection{Monitors and Mutex} 246 245 Concurrency does not guarantee ordering; without ordering results are 247 246 non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@ … … 261 260 and only one runs at a time. 262 261 263 \subsection{Thread }262 \subsection{Threads} 264 263 Functions, generators, and coroutines are sequential so there is only a single 265 264 (but potentially sophisticated) execution path in a program. Threads introduce … … 269 268 monitors and mutex parameters. For threads to work safely with other threads, 270 269 also requires mutual exclusion in the form of a communication rendezvous, which 271 also supports internal synchronization as for mutex objects. For exceptions ,272 only t wo basic thread operations are important:fork and join.270 also supports internal synchronization as for mutex objects. For exceptions 271 only the basic two basic operations are important: thread fork and join. 273 272 274 273 Threads are created like coroutines with an associated @main@ function: -
doc/theses/andrew_beach_MMath/features.tex
r5407cdc rfeacef9 2 2 3 3 This chapter covers the design and user interface of the \CFA 4 exception-handling mechanism (EHM). % or exception system. 5 6 We will begin with an overview of EHMs in general. It is not a strict 7 definition of all EHMs nor an exaustive list of all possible features. 8 However it does cover the most common structure and features found in them. 9 10 % We should cover what is an exception handling mechanism and what is an 11 % exception before this. Probably in the introduction. Some of this could 12 % move there. 13 \paragraph{Raise / Handle} 14 An exception operation has two main parts: raise and handle. 15 These terms are sometimes also known as throw and catch but this work uses 16 throw/catch as a particular kind of raise/handle. 17 These are the two parts that the user will write themselves and may 18 be the only two pieces of the EHM that have any syntax in the language. 19 20 \subparagraph{Raise} 21 The raise is the starting point for exception handling. It marks the beginning 22 of exception handling by \newterm{raising} an excepion, which passes it to 23 the EHM. 24 25 Some well known examples include the @throw@ statements of \Cpp and Java and 26 the \codePy{raise} statement from Python. In real systems a raise may preform 27 some other work (such as memory management) but for the purposes of this 28 overview that can be ignored. 29 30 \subparagraph{Handle} 31 The purpose of most exception operations is to run some user code to handle 32 that exception. This code is given, with some other information, in a handler. 33 34 A handler has three common features: the previously mentioned user code, a 35 region of code they cover and an exception label/condition that matches 36 certain exceptions. 37 Only raises inside the covered region and raising exceptions that match the 38 label can be handled by a given handler. 39 Different EHMs will have different rules to pick a handler 40 if multipe handlers could be used such as ``best match" or ``first found". 41 42 The @try@ statements of \Cpp, Java and Python are common examples. All three 43 also show another common feature of handlers, they are grouped by the covered 44 region. 45 46 \paragraph{Propagation} 47 After an exception is raised comes what is usually the biggest step for the 48 EHM: finding and setting up the handler. The propogation from raise to 49 handler can be broken up into three different tasks: searching for a handler, 50 matching against the handler and installing the handler. 51 52 \subparagraph{Searching} 53 The EHM begins by searching for handlers that might be used to handle 54 the exception. Searching is usually independent of the exception that was 55 thrown as it looks for handlers that have the raise site in their covered 56 region. 57 This includes handlers in the current function, as well as any in callers 58 on the stack that have the function call in their covered region. 59 60 \subparagraph{Matching} 61 Each handler found has to be matched with the raised exception. The exception 62 label defines a condition that be use used with exception and decides if 63 there is a match or not. 64 65 In languages where the first match is used this step is intertwined with 66 searching, a match check is preformed immediately after the search finds 67 a possible handler. 68 69 \subparagraph{Installing} 70 After a handler is chosen it must be made ready to run. 71 The implementation can vary widely to fit with the rest of the 72 design of the EHM. The installation step might be trivial or it could be 73 the most expensive step in handling an exception. The latter tends to be the 74 case when stack unwinding is involved. 75 76 If a matching handler is not guarantied to be found the EHM will need a 77 different course of action here in the cases where no handler matches. 78 This is only required with unchecked exceptions as checked exceptions 79 (such as in Java) can make than guaranty. 80 This different action can also be installing a handler but it is usually an 81 implicat and much more general one. 82 83 \subparagraph{Hierarchy} 84 A common way to organize exceptions is in a hierarchical structure. 85 This is especially true in object-orientated languages where the 86 exception hierarchy is a natural extension of the object hierarchy. 87 88 Consider the following hierarchy of exceptions: 4 exception-handling mechanism. 5 6 \section{Virtuals} 7 Virtual types and casts are not part of the exception system nor are they 8 required for an exception system. But an object-oriented style hierarchy is a 9 great way of organizing exceptions so a minimal virtual system has been added 10 to \CFA. 11 12 The pattern of a simple hierarchy was borrowed from object-oriented 13 programming was chosen for several reasons. 14 The first is that it allows new exceptions to be added in user code 15 and in libraries independently of each other. Another is it allows for 16 different levels of exception grouping (all exceptions, all IO exceptions or 17 a particular IO exception). Also it also provides a simple way of passing 18 data back and forth across the throw. 19 20 Virtual types and casts are not required for a basic exception-system but are 21 useful for advanced exception features. However, \CFA is not object-oriented so 22 there is no obvious concept of virtuals. Hence, to create advanced exception 23 features for this work, I needed to design and implement a virtual-like 24 system for \CFA. 25 26 % NOTE: Maybe we should but less of the rational here. 27 Object-oriented languages often organized exceptions into a simple hierarchy, 28 \eg Java. 89 29 \begin{center} 90 \input{exception-hierarchy} 30 \setlength{\unitlength}{4000sp}% 31 \begin{picture}(1605,612)(2011,-1951) 32 \put(2100,-1411){\vector(1, 0){225}} 33 \put(3450,-1411){\vector(1, 0){225}} 34 \put(3550,-1411){\line(0,-1){225}} 35 \put(3550,-1636){\vector(1, 0){150}} 36 \put(3550,-1636){\line(0,-1){225}} 37 \put(3550,-1861){\vector(1, 0){150}} 38 \put(2025,-1490){\makebox(0,0)[rb]{\LstBasicStyle{exception}}} 39 \put(2400,-1460){\makebox(0,0)[lb]{\LstBasicStyle{arithmetic}}} 40 \put(3750,-1460){\makebox(0,0)[lb]{\LstBasicStyle{underflow}}} 41 \put(3750,-1690){\makebox(0,0)[lb]{\LstBasicStyle{overflow}}} 42 \put(3750,-1920){\makebox(0,0)[lb]{\LstBasicStyle{zerodivide}}} 43 \end{picture}% 91 44 \end{center} 92 93 A handler labelled with any given exception can handle exceptions of that 94 type or any child type of that exception. The root of the exception hierarchy 95 (here \codeC{exception}) acts as a catch-all, leaf types catch single types 96 and the exceptions in the middle can be used to catch different groups of 97 related exceptions. 98 99 This system has some notable advantages, such as multiple levels of grouping, 100 the ability for libraries to add new exception types and the isolation 101 between different sub-hierarchies. 102 This design is used in \CFA even though it is not a object-orientated 103 language using different tools to create the hierarchy. 104 105 % Could I cite the rational for the Python IO exception rework? 106 107 \paragraph{Completion} 108 After the handler has finished the entire exception operation has to complete 109 and continue executing somewhere else. This step is usually simple, 110 both logically and in its implementation, as the installation of the handler 111 is usually set up to do most of the work. 112 113 The EHM can return control to many different places, 114 the most common are after the handler definition and after the raise. 115 116 \paragraph{Communication} 117 For effective exception handling, additional information is usually passed 118 from the raise to the handler. 119 So far only communication of the exceptions' identity has been covered. 120 A common method is putting fields into the exception instance and giving the 121 handler access to them. 122 123 \section{Virtuals} 124 Virtual types and casts are not part of \CFA's EHM nor are they required for 125 any EHM. But \CFA uses a hierarchial system of exceptions and this feature 126 is leveraged to create that. 127 128 % Maybe talk about why the virtual system is so minimal. 129 % Created for but not a part of the exception system. 130 131 The virtual system supports multiple ``trees" of types. Each tree is 132 a simple hierarchy with a single root type. Each type in a tree has exactly 133 one parent -- except for the root type which has zero parents -- and any 134 number of children. 135 Any type that belongs to any of these trees is called a virtual type. 136 137 % A type's ancestors are its parent and its parent's ancestors. 138 % The root type has no ancestors. 139 % A type's decendents are its children and its children's decendents. 140 141 Every virtual type also has a list of virtual members. Children inherit 142 their parent's list of virtual members but may add new members to it. 143 It is important to note that these are virtual members, not virtual methods 144 of object-orientated programming, and can be of any type. 145 However, since \CFA has function pointers and they are allowed, virtual 146 members can be used to mimic virtual methods. 147 148 Each virtual type has a unique id. 149 This unique id and all the virtual members are combined 150 into a virtual table type. Each virtual type has a pointer to a virtual table 151 as a hidden field. 152 153 Up until this point the virtual system is similar to ones found in 154 object-orientated languages but this where \CFA diverges. Objects encapsulate a 155 single set of behaviours in each type, universally across the entire program, 156 and indeed all programs that use that type definition. In this sense the 157 types are ``closed" and cannot be altered. 158 159 In \CFA types do not encapsulate any behaviour. Traits are local and 160 types can begin to statify a trait, stop satifying a trait or satify the same 161 trait in a different way at any lexical location in the program. 162 In this sense they are ``open" as they can change at any time. This means it 163 is implossible to pick a single set of functions that repersent the type's 164 implementation across the program. 165 166 \CFA side-steps this issue by not having a single virtual table for each 167 type. A user can define virtual tables which are filled in at their 168 declaration and given a name. Anywhere that name is visible, even if it was 169 defined locally inside a function (although that means it will not have a 170 static lifetime), it can be used. 171 Specifically, a virtual type is ``bound" to a virtual table which 172 sets the virtual members for that object. The virtual members can be accessed 173 through the object. 45 The hierarchy provides the ability to handle an exception at different degrees 46 of specificity (left to right). Hence, it is possible to catch a more general 47 exception-type in higher-level code where the implementation details are 48 unknown, which reduces tight coupling to the lower-level implementation. 49 Otherwise, low-level code changes require higher-level code changes, \eg, 50 changing from raising @underflow@ to @overflow@ at the low level means changing 51 the matching catch at the high level versus catching the general @arithmetic@ 52 exception. In detail, each virtual type may have a parent and can have any 53 number of children. A type's descendants are its children and its children's 54 descendants. A type may not be its own descendant. 55 56 The exception hierarchy allows a handler (@catch@ clause) to match multiple 57 exceptions, \eg a base-type handler catches both base and derived 58 exception-types. 59 \begin{cfa} 60 try { 61 ... 62 } catch(arithmetic &) { 63 ... // handle arithmetic, underflow, overflow, zerodivide 64 } 65 \end{cfa} 66 Most exception mechanisms perform a linear search of the handlers and select 67 the first matching handler, so the order of handers is now important because 68 matching is many to one. 69 70 Each virtual type needs an associated virtual table. A virtual table is a 71 structure with fields for all the virtual members of a type. A virtual type has 72 all the virtual members of its parent and can add more. It may also update the 73 values of the virtual members and often does. 174 74 175 75 While much of the virtual infrastructure is created, it is currently only used … … 183 83 \Cpp syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be 184 84 a pointer to a virtual type. 185 The cast dynamically checks if the @EXPRESSION@ type is the same or a sub -type85 The cast dynamically checks if the @EXPRESSION@ type is the same or a subtype 186 86 of @TYPE@, and if true, returns a pointer to the 187 87 @EXPRESSION@ object, otherwise it returns @0p@ (null pointer). … … 201 101 \end{cfa} 202 102 The trait is defined over two types, the exception type and the virtual table 203 type. This should be one-to-one :each exception type has only one virtual103 type. This should be one-to-one, each exception type has only one virtual 204 104 table type and vice versa. The only assertion in the trait is 205 105 @get_exception_vtable@, which takes a pointer of the exception type and 206 106 returns a reference to the virtual table type instance. 207 107 208 % TODO: This section, and all references to get_exception_vtable, are209 % out-of-data. Perhaps wait until the update is finished before rewriting it.210 108 The function @get_exception_vtable@ is actually a constant function. 211 Re gardless of the value passed in (including the null pointer) it should109 Recardless of the value passed in (including the null pointer) it should 212 110 return a reference to the virtual table instance for that type. 213 111 The reason it is a function instead of a constant is that it make type … … 221 119 % similar system I know of (except Agda's I guess) so I took it out. 222 120 223 There are two more traits for exceptions defined as follows: 121 There are two more traits for exceptions @is_termination_exception@ and 122 @is_resumption_exception@. They are defined as follows: 123 224 124 \begin{cfa} 225 125 trait is_termination_exception( … … 233 133 }; 234 134 \end{cfa} 235 Both traits ensure a pair of types are an exception type and its virtual table 236 and defines one of the two default handlers. The default handlers are used 237 as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}. 238 239 However, all three of these traits can be tricky to use directly. 240 While there is a bit of repetition required, 135 136 In other words they make sure that a given type and virtual type is an 137 exception and defines one of the two default handlers. These default handlers 138 are used in the main exception handling operations \see{Exception Handling} 139 and their use will be detailed there. 140 141 However all three of these traits can be trickly to use directly. 142 There is a bit of repetition required but 241 143 the largest issue is that the virtual table type is mangled and not in a user 242 facing way. So the se three macros are provided to wrap these traits to243 simplify referringto the names:144 facing way. So there are three macros that can be used to wrap these traits 145 when you need to refer to the names: 244 146 @IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@. 245 147 246 All t hree take one or two arguments. The first argument is the name of the247 exception type. The macro passes its unmangled and mangled formto the trait.148 All take one or two arguments. The first argument is the name of the 149 exception type. Its unmangled and mangled form are passed to the trait. 248 150 The second (optional) argument is a parenthesized list of polymorphic 249 arguments. This argument is only usedwith polymorphic exceptions and the250 list isbe passed to both types.251 In the current set-up , the two types always have the same polymorphic252 arguments so these macros can be used without losing flexibility.151 arguments. This argument should only with polymorphic exceptions and the 152 list will be passed to both types. 153 In the current set-up the base name and the polymorphic arguments have to 154 match so these macros can be used without losing flexability. 253 155 254 156 For example consider a function that is polymorphic over types that have a … … 260 162 261 163 \section{Exception Handling} 262 \ label{s:ExceptionHandling}263 \CFA provides two kinds of exception handling: termination and resumption. 264 These twin operations are the core of \CFA's exception handling mechanism.164 \CFA provides two kinds of exception handling, termination and resumption. 165 These twin operations are the core of the exception handling mechanism and 166 are the reason for the features of exceptions. 265 167 This section will cover the general patterns shared by the two operations and 266 168 then go on to cover the details each individual operation. 267 169 268 Both operations follow the same set of steps. 269 Both start with the user preforming a raise on an exception. 270 Then the exception propogates up the stack. 271 If a handler is found the exception is caught and the handler is run. 272 After that control returns to normal execution. 170 Both operations follow the same set of steps to do their operation. They both 171 start with the user preforming a throw on an exception. 172 Then there is the search for a handler, if one is found than the exception 173 is caught and the handler is run. After that control returns to normal 174 execution. 175 273 176 If the search fails a default handler is run and then control 274 returns to normal execution after the raise. 275 276 This general description covers what the two kinds have in common. 277 Differences include how propogation is preformed, where exception continues 278 after an exception is caught and handled and which default handler is run. 177 returns to normal execution immediately. That is where the default handlers 178 @defaultTermiationHandler@ and @defaultResumptionHandler@ are used. 279 179 280 180 \subsection{Termination} 281 181 \label{s:Termination} 282 Termination handling is the familiar kind and used in most programming 182 183 Termination handling is more familiar kind and used in most programming 283 184 languages with exception handling. 284 It is dynamic, non-local goto. If the raised exception is matched and 285 handled the stack is unwound and control will (usually) continue the function 286 on the call stack that defined the handler. 287 Termination is commonly used when an error has occurred and recovery is 288 impossible locally. 185 It is dynamic, non-local goto. If a throw is successful then the stack will 186 be unwound and control will (usually) continue in a different function on 187 the call stack. They are commonly used when an error has occured and recovery 188 is impossible in the current function. 289 189 290 190 % (usually) Control can continue in the current function but then a different 291 191 % control flow construct should be used. 292 192 293 A termination raiseis started with the @throw@ statement:193 A termination throw is started with the @throw@ statement: 294 194 \begin{cfa} 295 195 throw EXPRESSION; 296 196 \end{cfa} 297 197 The expression must return a reference to a termination exception, where the 298 termination exception is any type that satisfies the trait 299 @is_termination_exception@ at the call site. 300 Through \CFA's trait system the trait functions are implicity passed into the 301 throw code and the EHM. 302 A new @defaultTerminationHandler@ can be defined in any scope to 198 termination exception is any type that satifies @is_termination_exception@ 199 at the call site. 200 Through \CFA's trait system the functions in the traits are passed into the 201 throw code. A new @defaultTerminationHandler@ can be defined in any scope to 303 202 change the throw's behavior (see below). 304 203 305 The throw will copy the provided exception into managed memory to ensure 306 the exception is not destroyed if the stack is unwound. 307 It is the user's responsibility to ensure the original exception is cleaned 308 up wheither the stack is unwound or not. Allocating it on the stack is 309 usually sufficient. 310 311 Then propogation starts with the search. \CFA uses a ``first match" rule so 312 matching is preformed with the copied exception as the search continues. 313 It starts from the throwing function and proceeds to the base of the stack, 204 The throw will copy the provided exception into managed memory. It is the 205 user's responcibility to ensure the original exception is cleaned up if the 206 stack is unwound (allocating it on the stack should be sufficient). 207 208 Then the exception system searches the stack using the copied exception. 209 It starts starts from the throw and proceeds to the base of the stack, 314 210 from callee to caller. 315 211 At each stack frame, a check is made for resumption handlers defined by the … … 318 214 try { 319 215 GUARDED_BLOCK 320 } catch (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) {216 } catch (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) { 321 217 HANDLER_BLOCK$\(_1\)$ 322 } catch (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) {218 } catch (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) { 323 219 HANDLER_BLOCK$\(_2\)$ 324 220 } 325 221 \end{cfa} 326 When viewed on its own , a try statement will simply execute the statements327 in@GUARDED_BLOCK@ and when those are finished the try statement finishes.222 When viewed on its own a try statement will simply exceute the statements in 223 @GUARDED_BLOCK@ and when those are finished the try statement finishes. 328 224 329 225 However, while the guarded statements are being executed, including any 330 invoked functions, all the handlers in the statement are now on the search 331 path. If a termination exception is thrown and not handled further up the 332 stack they will be matched against the exception. 333 334 Exception matching checks the handler in each catch clause in the order 335 they appear, top to bottom. If the representation of the thrown exception type 336 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ 337 (if provided) is 226 functions they invoke, all the handlers following the try block are now 227 or any functions invoked from those 228 statements, throws an exception, and the exception 229 is not handled by a try statement further up the stack, the termination 230 handlers are searched for a matching exception type from top to bottom. 231 232 Exception matching checks the representation of the thrown exception-type is 233 the same or a descendant type of the exception types in the handler clauses. If 234 it is the same of a descendent of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ is 338 235 bound to a pointer to the exception and the statements in @HANDLER_BLOCK@$_i$ 339 236 are executed. If control reaches the end of the handler, the exception is 340 237 freed and control continues after the try statement. 341 238 342 If no termination handler is found during the search then the default handler 343 (@defaultTerminationHandler@) is run. 239 If no handler is found during the search then the default handler is run. 344 240 Through \CFA's trait system the best match at the throw sight will be used. 345 241 This function is run and is passed the copied exception. After the default 346 242 handler is run control continues after the throw statement. 347 243 348 There is a global @defaultTerminationHandler@ that is polymorphic over all 349 exception types. Since it is so general a more specific handler can be 350 defined and will be used for those types, effectively overriding the handler 351 for particular exception type. 352 The global default termination handler performs a cancellation 353 \see{\VRef{s:Cancellation}} on the current stack with the copied exception. 244 There is a global @defaultTerminationHandler@ that cancels the current stack 245 with the copied exception. However it is generic over all exception types so 246 new default handlers can be defined for different exception types and so 247 different exception types can have different default handlers. 354 248 355 249 \subsection{Resumption} 356 250 \label{s:Resumption} 357 251 358 Resumption exception handling is less commonthan termination but is359 just as old~\cite{Goodenough75} and is simpler in many ways.360 It is a dynamic, non-local function call. If the raised exception is361 matched a closure will be taken from up the stack and executed, 362 after which the raisingfunction will continue executing.363 These are most often used when an error occur red and if the error is repaired252 Resumption exception handling is a less common form than termination but is 253 just as old~\cite{Goodenough75} and is in some sense simpler. 254 It is a dynamic, non-local function call. If the throw is successful a 255 closure will be taken from up the stack and executed, after which the throwing 256 function will continue executing. 257 These are most often used when an error occured and if the error is repaired 364 258 then the function can continue. 365 259 … … 368 262 throwResume EXPRESSION; 369 263 \end{cfa} 370 It works much the same way as the termination throw. 371 The expression must return a reference to a resumption exception, 372 where the resumption exception is any type that satisfies the trait 373 @is_resumption_exception@ at the call site. 374 The assertions from this trait are available to 264 The semantics of the @throwResume@ statement are like the @throw@, but the 265 expression has return a reference a type that satifies the trait 266 @is_resumption_exception@. The assertions from this trait are available to 375 267 the exception system while handling the exception. 376 268 377 At run-time, no exception copy is made. 378 As the stack is not unwound the exception and 269 At runtime, no copies are made. As the stack is not unwound the exception and 379 270 any values on the stack will remain in scope while the resumption is handled. 380 271 381 The EHM then begins propogation. The search starts from the raise in the 382 resuming function and proceeds to the base of the stack, from callee to caller. 272 Then the exception system searches the stack using the provided exception. 273 It starts starts from the throw and proceeds to the base of the stack, 274 from callee to caller. 383 275 At each stack frame, a check is made for resumption handlers defined by the 384 276 @catchResume@ clauses of a @try@ statement. … … 386 278 try { 387 279 GUARDED_BLOCK 388 } catchResume (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) {280 } catchResume (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) { 389 281 HANDLER_BLOCK$\(_1\)$ 390 } catchResume (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) {282 } catchResume (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) { 391 283 HANDLER_BLOCK$\(_2\)$ 392 284 } 393 285 \end{cfa} 394 % I wonder if there would be some good central place for this. 395 Note that termination handlers and resumption handlers may be used together 396 in a single try statement, intermixing @catch@ and @catchResume@ freely. 397 Each type of handler will only interact with exceptions from the matching 398 type of raise. 399 When a try statement is executed it simply executes the statements in the 400 @GUARDED_BLOCK@ and then finishes. 401 402 However, while the guarded statements are being executed, including any 403 invoked functions, all the handlers in the statement are now on the search 404 path. If a resumption exception is reported and not handled further up the 405 stack they will be matched against the exception. 406 407 Exception matching checks the handler in each catch clause in the order 408 they appear, top to bottom. If the representation of the thrown exception type 409 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ 410 (if provided) is bound to a pointer to the exception and the statements in 411 @HANDLER_BLOCK@$_i$ are executed. 412 If control reaches the end of the handler, execution continues after the 413 the raise statement that raised the handled exception. 286 If the handlers are not involved in a search this will simply execute the 287 @GUARDED_BLOCK@ and then continue to the next statement. 288 Its purpose is to add handlers onto the stack. 289 (Note, termination and resumption handlers may be intermixed in a @try@ 290 statement but the kind of throw must be the same as the handler for it to be 291 considered as a possible match.) 292 293 If a search for a resumption handler reaches a try block it will check each 294 @catchResume@ clause, top-to-bottom. 295 At each handler if the thrown exception is or is a child type of 296 @EXCEPTION_TYPE@$_i$ then the a pointer to the exception is bound to 297 @NAME@$_i$ and then @HANDLER_BLOCK@$_i$ is executed. After the block is 298 finished control will return to the @throwResume@ statement. 414 299 415 300 Like termination, if no resumption handler is found, the default handler … … 417 302 call sight according to \CFA's overloading rules. The default handler is 418 303 passed the exception given to the throw. When the default handler finishes 419 execution continues after the raisestatement.304 execution continues after the throw statement. 420 305 421 306 There is a global @defaultResumptionHandler@ is polymorphic over all 422 307 termination exceptions and preforms a termination throw on the exception. 423 The @defaultTerminationHandler@ for that raiseis matched at the original424 raisestatement (the resumption @throwResume@) and it can be customized by308 The @defaultTerminationHandler@ for that throw is matched at the original 309 throw statement (the resumption @throwResume@) and it can be customized by 425 310 introducing a new or better match as well. 426 311 427 \subsubsection{Resumption Marking} 312 % \subsubsection? 313 428 314 A key difference between resumption and termination is that resumption does 429 315 not unwind the stack. A side effect that is that when a handler is matched … … 445 331 search and match the handler in the @catchResume@ clause. This will be 446 332 call and placed on the stack on top of the try-block. The second throw then 447 throws and will sea rch the same try block and put call another instance of the333 throws and will seach the same try block and put call another instance of the 448 334 same handler leading to an infinite loop. 449 335 … … 451 337 can form with multiple handlers and different exception types. 452 338 453 To prevent all of these cases we mark try statements on the stack. 454 A try statement is marked when a match check is preformed with it and an 455 exception. The statement will be unmarked when the handling of that exception 456 is completed or the search completes without finding a handler. 457 While a try statement is marked its handlers are never matched, effectify 458 skipping over it to the next try statement. 459 460 \begin{center} 461 \input{stack-marking} 462 \end{center} 463 464 These rules mirror what happens with termination. 465 When a termination throw happens in a handler the search will not look at 466 any handlers from the original throw to the original catch because that 467 part of the stack has been unwound. 468 A resumption raise in the same situation wants to search the entire stack, 469 but it will not try to match the exception with try statements in the section 470 that would have been unwound as they are marked. 471 472 The symmetry between resumption termination is why this pattern was picked. 473 Other patterns, such as marking just the handlers that caught, also work but 474 lack the symmetry means there are less rules to remember. 339 To prevent all of these cases we mask sections of the stack, or equvilantly 340 the try statements on the stack, so that the resumption seach skips over 341 them and continues with the next unmasked section of the stack. 342 343 A section of the stack is marked when it is searched to see if it contains 344 a handler for an exception and unmarked when that exception has been handled 345 or the search was completed without finding a handler. 346 347 % This might need a diagram. But it is an important part of the justification 348 % of the design of the traversal order. 349 \begin{verbatim} 350 throwResume2 ----------. 351 | | 352 generated from handler | 353 | | 354 handler | 355 | | 356 throwResume1 -----. : 357 | | : 358 try | : search skip 359 | | : 360 catchResume <----' : 361 | | 362 \end{verbatim} 363 364 The rules can be remembered as thinking about what would be searched in 365 termination. So when a throw happens in a handler; a termination handler 366 skips everything from the original throw to the original catch because that 367 part of the stack has been unwound, a resumption handler skips the same 368 section of stack because it has been masked. 369 A throw in a default handler will preform the same search as the original 370 throw because; for termination nothing has been unwound, for resumption 371 the mask will be the same. 372 373 The symmetry with termination is why this pattern was picked. Other patterns, 374 such as marking just the handlers that caught, also work but lack the 375 symmetry whih means there is more to remember. 475 376 476 377 \section{Conditional Catch} … … 478 379 condition to further control which exceptions they handle: 479 380 \begin{cfa} 480 catch (EXCEPTION_TYPE * [NAME]; CONDITION)381 catch (EXCEPTION_TYPE * NAME ; CONDITION) 481 382 \end{cfa} 482 383 First, the same semantics is used to match the exception type. Second, if the … … 486 387 matches. Otherwise, the exception search continues as if the exception type 487 388 did not match. 488 489 The condition matching allows finer matching by allowing the match to check 490 more kinds of information than just the exception type. 491 \begin{cfa} 492 try { 493 handle1 = open( f1, ... ); 494 handle2 = open( f2, ... ); 495 handle3 = open( f3, ... ); 389 \begin{cfa} 390 try { 391 f1 = open( ... ); 392 f2 = open( ... ); 496 393 ... 497 394 } catch( IOFailure * f ; fd( f ) == f1 ) { 498 // Only handle IO failure for f1. 499 } catch( IOFailure * f ; fd( f ) == f3 ) { 500 // Only handle IO failure for f3. 501 } 502 // Can't handle a failure relating to f2 here. 503 \end{cfa} 504 In this example the file that experianced the IO error is used to decide 505 which handler should be run, if any at all. 506 507 \begin{comment} 508 % I know I actually haven't got rid of them yet, but I'm going to try 509 % to write it as if I had and see if that makes sense: 510 \section{Reraising} 511 \label{s:Reraising} 395 // only handle IO failure for f1 396 } 397 \end{cfa} 398 Note, catching @IOFailure@, checking for @f1@ in the handler, and reraising the 399 exception if not @f1@ is different because the reraise does not examine any of 400 remaining handlers in the current try statement. 401 402 \section{Rethrowing} 403 \colour{red}{From Andrew: I recomend we talk about why the language doesn't 404 have rethrows/reraises instead.} 405 406 \label{s:Rethrowing} 512 407 Within the handler block or functions called from the handler block, it is 513 408 possible to reraise the most recently caught exception with @throw@ or … … 528 423 is part of an unwound stack frame. To prevent this problem, a new default 529 424 handler is generated that does a program-level abort. 530 \end{comment}531 532 \subsection{Comparison with Reraising}533 A more popular way to allow handlers to match in more detail is to reraise534 the exception after it has been caught if it could not be handled here.535 On the surface these two features seem interchangable.536 537 If we used @throw;@ to start a termination reraise then these two statements538 would have the same behaviour:539 \begin{cfa}540 try {541 do_work_may_throw();542 } catch(exception_t * exc ; can_handle(exc)) {543 handle(exc);544 }545 \end{cfa}546 547 \begin{cfa}548 try {549 do_work_may_throw();550 } catch(exception_t * exc) {551 if (can_handle(exc)) {552 handle(exc);553 } else {554 throw;555 }556 }557 \end{cfa}558 If there are further handlers after this handler only the first version will559 check them. If multiple handlers on a single try block could handle the same560 exception the translations get more complex but they are equivilantly561 powerful.562 563 Until stack unwinding comes into the picture. In termination handling, a564 conditional catch happens before the stack is unwound, but a reraise happens565 afterwards. Normally this might only cause you to loose some debug566 information you could get from a stack trace (and that can be side stepped567 entirely by collecting information during the unwind). But for \CFA there is568 another issue, if the exception isn't handled the default handler should be569 run at the site of the original raise.570 571 There are two problems with this: the site of the original raise doesn't572 exist anymore and the default handler might not exist anymore. The site will573 always be removed as part of the unwinding, often with the entirety of the574 function it was in. The default handler could be a stack allocated nested575 function removed during the unwind.576 577 This means actually trying to pretend the catch didn't happening, continuing578 the original raise instead of starting a new one, is infeasible.579 That is the expected behaviour for most languages and we can't replicate580 that behaviour.581 425 582 426 \section{Finally Clauses} 583 \label{s:FinallyClauses}584 427 Finally clauses are used to preform unconditional clean-up when leaving a 585 scope and are placed at the end of a try statement after any handler clauses:428 scope. They are placed at the end of a try statement: 586 429 \begin{cfa} 587 430 try { … … 599 442 600 443 Execution of the finally block should always finish, meaning control runs off 601 the end of the block. This requirement ensures control always continues as if 602 the finally clause is not present, \ie finally is for cleanup not changing 603 control flow. 604 Because of this requirement, local control flow out of the finally block 444 the end of the block. This requirement ensures always continues as if the 445 finally clause is not present, \ie finally is for cleanup not changing control 446 flow. Because of this requirement, local control flow out of the finally block 605 447 is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or 606 448 @return@ that causes control to leave the finally block. Other ways to leave 607 449 the finally block, such as a long jump or termination are much harder to check, 608 and at best requiring additional run-time overhead, and so are only450 and at best requiring additional run-time overhead, and so are mearly 609 451 discouraged. 610 452 611 Not all languages with unwindinghave finally clauses. Notably \Cpp does453 Not all languages with exceptions have finally clauses. Notably \Cpp does 612 454 without it as descructors serve a similar role. Although destructors and 613 455 finally clauses can be used in many of the same areas they have their own 614 456 use cases like top-level functions and lambda functions with closures. 615 457 Destructors take a bit more work to set up but are much easier to reuse while 616 finally clauses are good for one-off uses and 617 can easily include local information. 458 finally clauses are good for once offs and can include local information. 618 459 619 460 \section{Cancellation} 620 \label{s:Cancellation}621 461 Cancellation is a stack-level abort, which can be thought of as as an 622 uncatchable termination. It unwinds the entire current stack, and if462 uncatchable termination. It unwinds the entirety of the current stack, and if 623 463 possible forwards the cancellation exception to a different stack. 624 464 … … 626 466 There is no special statement for starting a cancellation; instead the standard 627 467 library function @cancel_stack@ is called passing an exception. Unlike a 628 raise, this exception is not used in matching only to pass information about468 throw, this exception is not used in matching only to pass information about 629 469 the cause of the cancellation. 630 (This also means matching cannot fail so there is no default handler .)631 632 After @cancel_stack@ is called the exception is copied into the EHM's memory633 andthe current stack is470 (This also means matching cannot fail so there is no default handler either.) 471 472 After @cancel_stack@ is called the exception is copied into the exception 473 handling mechanism's memory. Then the entirety of the current stack is 634 474 unwound. After that it depends one which stack is being cancelled. 635 475 \begin{description} 636 476 \item[Main Stack:] 637 477 The main stack is the one used by the program main at the start of execution, 638 and is the only stack in a sequential program. 639 After the main stack is unwound there is a program-level abort. 640 641 There are two reasons for this. The first is that it obviously had to do this 642 in a sequential program as there is nothing else to notify and the simplicity 643 of keeping the same behaviour in sequential and concurrent programs is good. 644 Also, even in concurrent programs there is no stack that an innate connection 645 to, so it would have be explicitly managed. 478 and is the only stack in a sequential program. Even in a concurrent program 479 the main stack is only dependent on the environment that started the program. 480 Hence, when the main stack is cancelled there is nowhere else in the program 481 to notify. After the stack is unwound, there is a program-level abort. 646 482 647 483 \item[Thread Stack:] 648 A thread stack is created for a \CFA @thread@ object or object that satisfies 649 the @is_thread@ trait. 650 After a thread stack is unwound there exception is stored until another 651 thread attempts to join with it. Then the exception @ThreadCancelled@, 652 which stores a reference to the thread and to the exception passed to the 653 cancellation, is reported from the join. 654 There is one difference between an explicit join (with the @join@ function) 655 and an implicit join (from a destructor call). The explicit join takes the 656 default handler (@defaultResumptionHandler@) from its calling context while 657 the implicit join provides its own which does a program abort if the 658 @ThreadCancelled@ exception cannot be handled. 659 660 Communication is done at join because a thread only has to have to points of 661 communication with other threads: start and join. 662 Since a thread must be running to perform a cancellation (and cannot be 663 cancelled from another stack), the cancellation must be after start and 664 before the join. So join is the one that we will use. 665 666 % TODO: Find somewhere to discuss unwind collisions. 667 The difference between the explicit and implicit join is for safety and 668 debugging. It helps prevent unwinding collisions by avoiding throwing from 669 a destructor and prevents cascading the error across multiple threads if 670 the user is not equipped to deal with it. 671 Also you can always add an explicit join if that is the desired behaviour. 672 673 \item[Coroutine Stack:] 674 A coroutine stack is created for a @coroutine@ object or object that 675 satisfies the @is_coroutine@ trait. 676 After a coroutine stack is unwound control returns to the resume function 677 that most recently resumed it. The resume statement reports a 678 @CoroutineCancelled@ exception, which contains a references to the cancelled 679 coroutine and the exception used to cancel it. 680 The resume function also takes the @defaultResumptionHandler@ from the 681 caller's context and passes it to the internal report. 682 683 A coroutine knows of two other coroutines, its starter and its last resumer. 684 The starter has a much more distant connection while the last resumer just 685 (in terms of coroutine state) called resume on this coroutine, so the message 686 is passed to the latter. 484 A thread stack is created for a @thread@ object or object that satisfies the 485 @is_thread@ trait. A thread only has two points of communication that must 486 happen: start and join. As the thread must be running to perform a 487 cancellation, it must occur after start and before join, so join is used 488 for communication here. 489 After the stack is unwound, the thread halts and waits for 490 another thread to join with it. The joining thread checks for a cancellation, 491 and if present, resumes exception @ThreadCancelled@. 492 493 There is a subtle difference between the explicit join (@join@ function) and 494 implicit join (from a destructor call). The explicit join takes the default 495 handler (@defaultResumptionHandler@) from its calling context, which is used if 496 the exception is not caught. The implicit join does a program abort instead. 497 498 This semantics is for safety. If an unwind is triggered while another unwind 499 is underway only one of them can proceed as they both want to ``consume'' the 500 stack. Letting both try to proceed leads to very undefined behaviour. 501 Both termination and cancellation involve unwinding and, since the default 502 @defaultResumptionHandler@ preforms a termination that could more easily 503 happen in an implicate join inside a destructor. So there is an error message 504 and an abort instead. 505 \todo{Perhaps have a more general disucssion of unwind collisions before 506 this point.} 507 508 The recommended way to avoid the abort is to handle the intial resumption 509 from the implicate join. If required you may put an explicate join inside a 510 finally clause to disable the check and use the local 511 @defaultResumptionHandler@ instead. 512 513 \item[Coroutine Stack:] A coroutine stack is created for a @coroutine@ object 514 or object that satisfies the @is_coroutine@ trait. A coroutine only knows of 515 two other coroutines, its starter and its last resumer. Of the two the last 516 resumer has the tightest coupling to the coroutine it activated and the most 517 up-to-date information. 518 519 Hence, cancellation of the active coroutine is forwarded to the last resumer 520 after the stack is unwound. When the resumer restarts, it resumes exception 521 @CoroutineCancelled@, which is polymorphic over the coroutine type and has a 522 pointer to the cancelled coroutine. 523 524 The resume function also has an assertion that the @defaultResumptionHandler@ 525 for the exception. So it will use the default handler like a regular throw. 687 526 \end{description} -
doc/theses/andrew_beach_MMath/future.tex
r5407cdc rfeacef9 83 83 patterns to find the handler. 84 84 85 \section{Checked Exceptions}86 Checked exceptions make exceptions part of a function's type by adding the87 exception signature. An exception signature must declare all checked88 exceptions that could propogate from the function (either because they were89 raised inside the function or came from a sub-function). This improves safety90 by making sure every checked exception is either handled or consciously91 passed on.92 93 However checked exceptions were never seriously considered for this project94 for two reasons. The first is due to time constraints, even copying an95 existing checked exception system would be pushing the remaining time and96 trying to address the second problem would take even longer. The second97 problem is that checked exceptions have some real usability trade-offs in98 exchange for the increased safety.99 100 These trade-offs are most problematic when trying to pass exceptions through101 higher-order functions from the functions the user passed into the102 higher-order function. There are no well known solutions to this problem103 that were statifactory for \CFA (which carries some of C's flexability104 over safety design) so one would have to be researched and developed.105 106 Follow-up work might add checked exceptions to \CFA, possibly using107 polymorphic exception signatures, a form of tunneling\cite{Zhang19} or108 checked and unchecked raises.109 110 85 \section{Zero-Cost Try} 111 86 \CFA does not have zero-cost try-statements because the compiler generates C -
doc/theses/andrew_beach_MMath/implement.tex
r5407cdc rfeacef9 13 13 library. 14 14 15 \subsection{Virtual Type}16 Virtual types only have one change to their structure, the addition of a17 pointer to the virtual table. This is always the first field so that18 if it is cast to a supertype the field's location is still known.19 20 This field is set as part of all new generated constructors.21 \todo{They only come as part exceptions and don't work.}22 After the object is created the field is constant.23 24 However it can be read from, internally it is just a regular field called25 @virtual_table@. Dereferencing it gives the virtual table and access to the26 type's virtual members.27 28 15 \subsection{Virtual Table} 29 Every time a virtual type is defined the new virtual table type must also be30 defined.31 32 The unique instance is important because the address of the virtual table33 instance is used as the identifier for the virtual type. So a pointer to the34 virtual table and the ID for the virtual type are interchangable.35 \todo{Unique instances might be going so we will have to talk about the new36 system instead.}37 38 The first step in putting it all together is to create the virtual table type.39 The virtual table type is just a structure and can be described in terms of40 its fields. The first field is always the parent type ID (or a pointer to41 the parent virtual table) or 0 (the null pointer).42 Next are other fields on the parent virtual table are repeated.43 Finally are the fields used to store any new virtual members of the new44 The virtual type45 46 16 The virtual system is accessed through a private constant field inserted at the 47 17 beginning of every virtual type, called the virtual-table pointer. This field 48 18 points at a type's virtual table and is assigned during the object's 49 construction. The address of a virtual table acts as the unique identifier for19 construction. The address of a virtual table acts as the unique identifier for 50 20 the virtual type, and the first field of a virtual table is a pointer to the 51 parent virtual-table or @0p@. The remaining fields are duplicated from the21 parent virtual-table or @0p@. The remaining fields are duplicated from the 52 22 parent tables in this type's inheritance chain, followed by any fields this type 53 introduces. Parent fields are duplicated so they can be changed ( all virtual54 members are overridable), so that references to the dispatched type23 introduces. Parent fields are duplicated so they can be changed (\CC 24 \lstinline[language=c++]|override|), so that references to the dispatched type 55 25 are replaced with the current virtual type. 26 \PAB{Can you create a simple diagram of the layout?} 56 27 % These are always taken by pointer or reference. 57 58 % Simple ascii diragram:59 \begin{verbatim}60 parent_pointer \61 parent_field0 |62 ... | Same layout as parent.63 parent_fieldN /64 child_field065 ...66 child_fieldN67 \end{verbatim}68 \todo{Refine the diagram}69 28 70 29 % For each virtual type, a virtual table is constructed. This is both a new type … … 75 34 A virtual table is created when the virtual type is created. The name of the 76 35 type is created by mangling the name of the base type. The name of the instance 77 is also generated by name mangling. The fields are initialized automatically.36 is also generated by name mangling. The fields are initialized automatically. 78 37 The parent field is initialized by getting the type of the parent field and 79 38 using that to calculate the mangled name of the parent's virtual table type. … … 108 67 \begin{sloppypar} 109 68 Coroutines and threads need instances of @CoroutineCancelled@ and 110 @ThreadCancelled@ respectively to use all of their functionality. When a new69 @ThreadCancelled@ respectively to use all of their functionality. When a new 111 70 data type is declared with @coroutine@ or @thread@ the forward declaration for 112 71 the instance is created as well. The definition of the virtual table is created … … 121 80 The function is 122 81 \begin{cfa} 123 void * __cfa__virtual_cast( 124 struct __cfa__parent_vtable const * parent, 82 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 125 83 struct __cfa__parent_vtable const * const * child ); 84 } 126 85 \end{cfa} 127 and it is implemented in the standard library. The structure reperents the 128 head of a vtable which is the pointer to the parent virtual table. The 129 @parent@ points directly at the parent type virtual table while the @child@ 130 points at the object of the (possibe) child type. 131 132 In terms of the virtual cast expression, @parent@ comes from looking up the 133 type being cast to and @child@ is the result of the expression being cast. 134 Because the complier outputs C code, some type C type casts are also used. 135 The last bit of glue is an map that saves every virtual type the compiler 136 sees. This is used to check the type used in a virtual cast is a virtual 137 type and to get its virtual table. 138 (It also checks for conflicting definitions.) 139 140 Inside the function it is a simple conditional. If the type repersented by 141 @parent@ is or is an ancestor of the type repersented by @*child@ (it 142 requires one more level of derefence to pass through the object) then @child@ 143 is returned, otherwise the null pointer is returned. 144 145 The check itself is preformed is a simple linear search. If the child 146 virtual table or any of its ancestors (which are retreved through the first 147 field of every virtual table) are the same as the parent virtual table then 148 the cast succeeds. 86 and it is implemented in the standard library. It takes a pointer to the target 87 type's virtual table and the object pointer being cast. The function performs a 88 linear search starting at the object's virtual-table and walking through the 89 the parent pointers, checking to if it or any of its ancestors are the same as 90 the target-type virtual table-pointer. 91 92 For the generated code, a forward declaration of the virtual works as follows. 93 There is a forward declaration of @__cfa__virtual_cast@ in every \CFA file so 94 it can just be used. The object argument is the expression being cast so that 95 is just placed in the argument list. 96 97 To build the target type parameter, the compiler creates a mapping from 98 concrete type-name -- so for polymorphic types the parameters are filled in -- 99 to virtual table address. Every virtual table declaration is added to the this 100 table; repeats are ignored unless they have conflicting definitions. Note, 101 these declarations do not have to be in scope, but they should usually be 102 introduced as part of the type definition. 103 104 \PAB{I do not understood all of \VRef{s:VirtualSystem}. I think you need to 105 write more to make it clear.} 106 149 107 150 108 \section{Exceptions} … … 163 121 stack. On function entry and return, unwinding is handled directly by the code 164 122 embedded in the function. Usually, the stack-frame size is known statically 165 based on parameter and local variable declarations. For dynamically-sized123 based on parameter and local variable declarations. For dynamically-sized 166 124 local variables, a runtime computation is necessary to know the frame 167 125 size. Finally, a function's frame-size may change during execution as local … … 221 179 222 180 To use libunwind, each function must have a personality function and a Language 223 Specific Data Area (LSDA). The LSDA has the unique information for each181 Specific Data Area (LSDA). The LSDA has the unique information for each 224 182 function to tell the personality function where a function is executing, its 225 current stack frame, and what handlers should be checked. Theoretically, the183 current stack frame, and what handlers should be checked. Theoretically, the 226 184 LSDA can contain any information but conventionally it is a table with entries 227 185 representing regions of the function and what has to be done there during … … 238 196 239 197 The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and 240 attaches its personality function. However, this 241 flag only handles the cleanup attribute: 242 \todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive 243 and that's all I know.} 198 attaches its personality function. \PAB{to what is it attached?} However, this 199 flag only handles the cleanup attribute 244 200 \begin{cfa} 245 201 void clean_up( int * var ) { ... } 246 int avar __attribute__(( cleanup(clean_up) ));202 int avar __attribute__(( __cleanup(clean_up) )); 247 203 \end{cfa} 248 which is used on a variable and specifies a function, in this case @clean_up@, 249 run when the variable goes out of scope. 250 The function is passed a pointer to the object being removed from the stack 251 so it can be used to mimic destructors. 252 However, this feature cannot be used to mimic @try@ statements as it cannot 253 control the unwinding. 204 which is used on a variable and specifies a function, \eg @clean_up@, run when 205 the variable goes out of scope. The function is passed a pointer to the object 206 so it can be used to mimic destructors. However, this feature cannot be used to 207 mimic @try@ statements. 254 208 255 209 \subsection{Personality Functions} 256 Personality functions have a complex interface specified by libunwind. This210 Personality functions have a complex interface specified by libunwind. This 257 211 section covers some of the important parts of the interface. 258 212 259 A personality function can preform different actions depending on how it is260 called.213 A personality function performs four tasks, although not all have to be 214 present. 261 215 \begin{lstlisting}[language=C,{moredelim=**[is][\color{red}]{@}{@}}] 262 216 typedef _Unwind_Reason_Code (*@_Unwind_Personality_Fn@) ( … … 271 225 \item 272 226 @_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function 273 to check for handlers. If there is a handler in a stack frame, as defined by227 to check for handlers. If there is a handler in a stack frame, as defined by 274 228 the language, the personality function returns @_URC_HANDLER_FOUND@; otherwise 275 229 it return @_URC_CONTINUE_UNWIND@. … … 342 296 \end{cfa} 343 297 It also unwinds the stack but it does not use the search phase. Instead another 344 function, the stop function, is used to stop searching. The exception is the298 function, the stop function, is used to stop searching. The exception is the 345 299 same as the one passed to raise exception. The extra arguments are the stop 346 300 function and the stop parameter. The stop function has a similar interface as a … … 364 318 365 319 \begin{sloppypar} 366 Its arguments are the same as the paired personality function. The actions320 Its arguments are the same as the paired personality function. The actions 367 321 @_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always set when it is 368 322 called. Beyond the libunwind standard, both GCC and Clang add an extra action … … 389 343 strong symbol replacing the sequential version. 390 344 391 The sequential @this_exception_context@ returns a hard-coded pointer to the 392 global execption context. 393 The concurrent version adds the exception context to the data stored at the 394 base of each stack. When @this_exception_context@ is called it retrieves the 395 active stack and returns the address of the context saved there. 345 % The version of the function defined in @libcfa@ is very simple. It returns a 346 % pointer to a global static variable. With only one stack this global instance 347 % is associated with the only stack. 348 349 For coroutines, @this_exception_context@ accesses the exception context stored 350 at the base of the stack. For threads, @this_exception_context@ uses the 351 concurrency library to access the current stack of the thread or coroutine 352 being executed by the thread, and then accesses the exception context stored at 353 the base of this stack. 396 354 397 355 \section{Termination} … … 411 369 per-exception storage. 412 370 413 [Quick ASCII diagram to get started.] 414 \begin{verbatim} 415 Fixed Header | _Unwind_Exception <- pointer target 416 | 417 | Cforall storage 418 | 419 Variable Body | the exception <- fixed offset 420 V ... 421 \end{verbatim} 422 423 Exceptions are stored in variable-sized blocks. 424 The first component is a fixed sized data structure that contains the 371 Exceptions are stored in variable-sized blocks. \PAB{Show a memory layout 372 figure.} The first component is a fixed sized data structure that contains the 425 373 information for libunwind and the exception system. The second component is an 426 374 area of memory big enough to store the exception. Macros with pointer arthritic … … 440 388 exception type. The size and copy function are used immediately to copy an 441 389 exception into managed memory. After the exception is handled the free function 442 is used to clean up the exception and then the entire node is passed to free 443 so the memory can be given back to the heap. 390 is used to clean up the exception and then the entire node is passed to free. 444 391 445 392 \subsection{Try Statements and Catch Clauses} … … 452 399 library. The contents of a try block and the termination handlers are converted 453 400 into functions. These are then passed to the try terminate function and it 454 calls them. 455 Because this function is known and fixed (and not an arbitrary function that 456 happens to contain a try statement) this means the LSDA can be generated ahead 457 of time. 458 459 Both the LSDA and the personality function are set ahead of time using 460 embedded assembly. This is handcrafted using C @asm@ statements and contains 461 enough information for the single try statement the function repersents. 401 calls them. This approach puts a try statement in its own functions so that no 402 function has to deal with both termination handlers and destructors. \PAB{I do 403 not understand the previous sentence.} 404 405 This function has some custom embedded assembly that defines \emph{its} 406 personality function and LSDA. The assembly is created with handcrafted C @asm@ 407 statements, which is why there is only one version of it. The personality 408 function is structured so that it can be expanded, but currently it only 409 handles this one function. Notably, it does not handle any destructors so the 410 function is constructed so that it does need to run it. \PAB{I do not 411 understand the previous sentence.} 462 412 463 413 The three functions passed to try terminate are: … … 469 419 470 420 \item[match function:] This function is called during the search phase and 471 decides if a catch clause matches the termination exception. It is constructed421 decides if a catch clause matches the termination exception. It is constructed 472 422 from the conditional part of each handler and runs each check, top to bottom, 473 423 in turn, first checking to see if the exception type matches and then if the … … 478 428 \item[handler function:] This function handles the exception. It takes a 479 429 pointer to the exception and the handler's id and returns nothing. It is called 480 after the cleanup phase. It is constructed by stitching together the bodies of430 after the cleanup phase. It is constructed by stitching together the bodies of 481 431 each handler and dispatches to the selected handler. 482 432 \end{description} … … 484 434 can be used to create closures, functions that can refer to the state of other 485 435 functions on the stack. This approach allows the functions to refer to all the 486 variables in scope for the function containing the @try@ statement. These436 variables in scope for the function containing the @try@ statement. These 487 437 nested functions and all other functions besides @__cfaehm_try_terminate@ in 488 438 \CFA use the GCC personality function and the @-fexceptions@ flag to generate … … 505 455 handler that matches. If no handler matches then the function returns 506 456 false. Otherwise the matching handler is run; if it completes successfully, the 507 function returns true. Re throwing, through the @throwResume;@ statement,508 causesthe function to return true.457 function returns true. Reresume, through the @throwResume;@ statement, cause 458 the function to return true. 509 459 510 460 % Recursive Resumption Stuff: … … 532 482 providing zero-cost enter/exit using the LSDA. Unfortunately, there is no way 533 483 to return from a libunwind search without installing a handler or raising an 534 error. Although workarounds might be possible, they are beyond the scope of484 error. Although workarounds might be possible, they are beyond the scope of 535 485 this thesis. The current resumption implementation has simplicity in its 536 486 favour. … … 553 503 554 504 Cancellation also uses libunwind to do its stack traversal and unwinding, 555 however it uses a different primary function @_Unwind_ForcedUnwind@. Details505 however it uses a different primary function @_Unwind_ForcedUnwind@. Details 556 506 of its interface can be found in the \VRef{s:ForcedUnwind}. 557 507 … … 561 511 its main coroutine and the coroutine it is currently executing. 562 512 563 So if the active thread's main and current coroutine are the same. If they 564 are then the current stack is a thread stack, otherwise it is a coroutine 565 stack. If it is a thread stack then an equality check with the stored main 566 thread pointer and current thread pointer is enough to tell if the current 567 thread is the main thread or not. 513 The first check is if the current thread's main and current coroutine do not 514 match, implying a coroutine cancellation; otherwise, it is a thread 515 cancellation. Otherwise it is a main thread cancellation. \PAB{Previous 516 sentence does not make sense.} 568 517 569 518 However, if the threading library is not linked, the sequential execution is on -
doc/theses/andrew_beach_MMath/uw-ethesis.tex
r5407cdc rfeacef9 74 74 % ====================================================================== 75 75 % D O C U M E N T P R E A M B L E 76 \RequirePackage{etoolbox} 77 78 % Control if this for print (set true) or will stay digital (default). 79 % Print is two sided, digital uses more colours. 80 \newtoggle{printversion} 81 %\toggletrue{printversion} 82 83 \iftoggle{printversion}{% 84 \documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book} 85 }{% 86 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book} 87 } 76 % Specify the document class, default style attributes, page dimensions, etc. 77 % For hyperlinked PDF, suitable for viewing on a computer, use this: 78 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book} 79 80 % For PDF, suitable for double-sided printing, change the PrintVersion 81 % variable below to "true" and use this \documentclass line instead of the 82 % one above: 83 %\documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book} 84 85 \usepackage{etoolbox} 88 86 89 87 % Some LaTeX commands I define for my own nomenclature. … … 96 94 % Anything defined here may be redefined by packages added below... 97 95 98 % For a nomenclature (optional; available from ctan.org) 99 %\usepackage{nomencl} 96 % This package allows if-then-else control structures. 97 \usepackage{ifthen} 98 \newboolean{PrintVersion} 99 \setboolean{PrintVersion}{false} 100 % CHANGE THIS VALUE TO "true" as necessary, to improve printed results for 101 % hard copies by overriding some options of the hyperref package, called below. 102 103 %\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org) 100 104 % Lots of math symbols and environments 101 105 \usepackage{amsmath,amssymb,amstext} 102 % For including graphics (must match graphics driver) 103 \usepackage{epic,eepic} 104 \usepackage{graphicx} 106 % For including graphics N.B. pdftex graphics driver 107 \usepackage[pdftex]{graphicx} 105 108 % Removes large sections of the document. 106 109 \usepackage{comment} 107 110 % Adds todos (Must be included after comment.) 108 111 \usepackage{todonotes} 112 109 113 110 114 % Hyperlinks make it very easy to navigate an electronic document. … … 113 117 % Use the "hyperref" package 114 118 % N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE 115 \usepackage[pagebackref=true]{hyperref} 119 \usepackage[pdftex,pagebackref=true]{hyperref} % with basic options 120 %\usepackage[pdftex,pagebackref=true]{hyperref} 116 121 % N.B. pagebackref=true provides links back from the References to the body 117 122 % text. This can cause trouble for printing. … … 123 128 pdffitwindow=false, % window fit to page when opened 124 129 pdfstartview={FitH}, % fits the width of the page to the window 130 % pdftitle={uWaterloo\ LaTeX\ Thesis\ Template}, % title: CHANGE THIS TEXT! 131 % pdfauthor={Author}, % author: CHANGE THIS TEXT! and uncomment this line 132 % pdfsubject={Subject}, % subject: CHANGE THIS TEXT! and uncomment this line 133 % pdfkeywords={keyword1} {key2} {key3}, % optional list of keywords 125 134 pdfnewwindow=true, % links in new window 126 135 colorlinks=true, % false: boxed links; true: colored links 136 linkcolor=blue, % color of internal links 137 citecolor=green, % color of links to bibliography 138 filecolor=magenta, % color of file links 139 urlcolor=cyan % color of external links 127 140 } 128 \iftoggle{printversion}{ 129 \hypersetup{ 130 citecolor=black, % colour of links to bibliography 131 filecolor=black, % colour of file links 132 linkcolor=black, % colour of internal links 133 urlcolor=black, % colour of external links 134 } 135 }{ % Digital Version 136 \hypersetup{ 137 citecolor=green, 138 filecolor=magenta, 139 linkcolor=blue, 140 urlcolor=cyan, 141 } 142 } 143 144 \hypersetup{ 145 pdftitle={Exception Handling in Cforall}, 146 pdfauthor={Andrew James Beach}, 147 pdfsubject={Computer Science}, 148 pdfkeywords={programming languages} {exceptions} 149 {language design} {language implementation}, 150 } 141 % for improved print quality, change some hyperref options 142 \ifthenelse{\boolean{PrintVersion}}{ 143 \hypersetup{ % override some previously defined hyperref options 144 % colorlinks,% 145 citecolor=black,% 146 filecolor=black,% 147 linkcolor=black,% 148 urlcolor=black} 149 }{} % end of ifthenelse (no else) 151 150 152 151 % Exception to the rule of hyperref being the last add-on package … … 218 217 \pdfstringdefDisableCommands{\def\Cpp{C++}} 219 218 220 % Wrappers for inline code snippits.221 \newrobustcmd*\codeCFA[1]{\lstinline[language=CFA]{#1}}222 \newrobustcmd*\codeC[1]{\lstinline[language=C]{#1}}223 \newrobustcmd*\codeCpp[1]{\lstinline[language=C++]{#1}}224 \newrobustcmd*\codePy[1]{\lstinline[language=Python]{#1}}225 226 219 % Colour text, formatted in LaTeX style instead of TeX style. 227 220 \newcommand*\colour[2]{{\color{#1}#2}} -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp
r5407cdc rfeacef9 117 117 } 118 118 119 unsignedlong long ts() const {119 long long ts() const { 120 120 return before._links.ts; 121 121 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp
r5407cdc rfeacef9 39 39 while( __builtin_expect(ll.exchange(true),false) ) { 40 40 while(ll.load(std::memory_order_relaxed)) 41 Pause();41 asm volatile("pause"); 42 42 } 43 43 /* paranoid */ assert(ll); … … 93 93 && ready.compare_exchange_weak(copy, n + 1) ) 94 94 break; 95 Pause();95 asm volatile("pause"); 96 96 } 97 97 … … 133 133 // Step 1 : make sure no writer are in the middle of the critical section 134 134 while(lock.load(std::memory_order_relaxed)) 135 Pause();135 asm volatile("pause"); 136 136 137 137 // Fence needed because we don't want to start trying to acquire the lock … … 195 195 // to simply lock their own lock and enter. 196 196 while(lock.load(std::memory_order_relaxed)) 197 Pause();197 asm volatile("pause"); 198 198 199 199 // Step 2 : lock per-proc lock … … 204 204 for(uint_fast32_t i = 0; i < s; i++) { 205 205 while(data[i].lock.load(std::memory_order_relaxed)) 206 Pause();206 asm volatile("pause"); 207 207 } 208 208 -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp
r5407cdc rfeacef9 21 21 target = (target - (target % total)) + total; 22 22 while(waiting < target) 23 Pause();23 asm volatile("pause"); 24 24 25 25 assert(waiting < (1ul << 60)); -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp
r5407cdc rfeacef9 123 123 target = (target - (target % total)) + total; 124 124 while(waiting < target) 125 Pause();125 asm volatile("pause"); 126 126 127 127 assert(waiting < (1ul << 60)); -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp
r5407cdc rfeacef9 206 206 std::cout << "Total ops : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n"; 207 207 #ifndef NO_STATS 208 LIST_VARIANT<Node>::stats_print(std::cout , duration);208 LIST_VARIANT<Node>::stats_print(std::cout); 209 209 #endif 210 210 } … … 368 368 369 369 for(Node * & node : nodes) { 370 node = nullptr; 371 while(!node) { 372 node = list.pop(); 373 } 370 node = list.pop(); 371 assert(node); 374 372 local.crc_out += node->value; 375 373 local.out++; … … 693 691 694 692 for(const auto & n : nodes) { 695 local.valmax = std::max(local.valmax, size_t(n.value));696 local.valmin = std::min(local.valmin, size_t(n.value));693 local.valmax = max(local.valmax, size_t(n.value)); 694 local.valmin = min(local.valmin, size_t(n.value)); 697 695 } 698 696 … … 775 773 try { 776 774 arg = optarg = argv[optind]; 777 nnodes = st d::stoul(optarg, &len);775 nnodes = stoul(optarg, &len); 778 776 if(len != arg.size()) { throw std::invalid_argument(""); } 779 777 } catch(std::invalid_argument &) { … … 794 792 try { 795 793 arg = optarg = argv[optind]; 796 nnodes = st d::stoul(optarg, &len);794 nnodes = stoul(optarg, &len); 797 795 if(len != arg.size()) { throw std::invalid_argument(""); } 798 796 } catch(std::invalid_argument &) { … … 814 812 try { 815 813 arg = optarg = argv[optind]; 816 nnodes = st d::stoul(optarg, &len);814 nnodes = stoul(optarg, &len); 817 815 if(len != arg.size()) { throw std::invalid_argument(""); } 818 816 nslots = nnodes; … … 825 823 try { 826 824 arg = optarg = argv[optind]; 827 nnodes = st d::stoul(optarg, &len);825 nnodes = stoul(optarg, &len); 828 826 if(len != arg.size()) { throw std::invalid_argument(""); } 829 827 } catch(std::invalid_argument &) { … … 833 831 try { 834 832 arg = optarg = argv[optind + 1]; 835 nslots = st d::stoul(optarg, &len);833 nslots = stoul(optarg, &len); 836 834 if(len != arg.size()) { throw std::invalid_argument(""); } 837 835 } catch(std::invalid_argument &) { … … 886 884 case 'd': 887 885 try { 888 duration = st d::stod(optarg, &len);886 duration = stod(optarg, &len); 889 887 if(len != arg.size()) { throw std::invalid_argument(""); } 890 888 } catch(std::invalid_argument &) { … … 895 893 case 't': 896 894 try { 897 nthreads = st d::stoul(optarg, &len);895 nthreads = stoul(optarg, &len); 898 896 if(len != arg.size()) { throw std::invalid_argument(""); } 899 897 } catch(std::invalid_argument &) { … … 904 902 case 'q': 905 903 try { 906 nqueues = st d::stoul(optarg, &len);904 nqueues = stoul(optarg, &len); 907 905 if(len != arg.size()) { throw std::invalid_argument(""); } 908 906 } catch(std::invalid_argument &) { -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp
r5407cdc rfeacef9 168 168 for(int i = 0; i < width; i++) { 169 169 int idx = i % hwdith; 170 std::cout << i << " -> " << idx + width << std::endl; 170 171 leafs[i].parent = &nodes[ idx ]; 171 172 } … … 173 174 for(int i = 0; i < root; i++) { 174 175 int idx = (i / 2) + hwdith; 176 std::cout << i + width << " -> " << idx + width << std::endl; 175 177 nodes[i].parent = &nodes[ idx ]; 176 178 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp
r5407cdc rfeacef9 159 159 std::cout << "SNZI: " << depth << "x" << width << "(" << mask - 1 << ") " << (sizeof(snzi_t::node) * (root + 1)) << " bytes" << std::endl; 160 160 for(int i = 0; i < root; i++) { 161 std::cout << i << " -> " << (i / base) + width << std::endl; 161 162 nodes[i].parent = &nodes[(i / base) + width]; 162 163 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp
r5407cdc rfeacef9 11 11 #include <sys/sysinfo.h> 12 12 13 // #include <x86intrin.h> 13 #include <x86intrin.h> 14 15 // Barrier from 16 class barrier_t { 17 public: 18 barrier_t(size_t total) 19 : waiting(0) 20 , total(total) 21 {} 22 23 void wait(unsigned) { 24 size_t target = waiting++; 25 target = (target - (target % total)) + total; 26 while(waiting < target) 27 asm volatile("pause"); 28 29 assert(waiting < (1ul << 60)); 30 } 31 32 private: 33 std::atomic<size_t> waiting; 34 size_t total; 35 }; 14 36 15 37 // class Random { … … 80 102 }; 81 103 82 static inline long long int rdtscl(void) { 83 #if defined( __i386 ) || defined( __x86_64 ) 84 unsigned int lo, hi; 85 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 86 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 87 #elif defined( __aarch64__ ) || defined( __arm__ ) 88 // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116 89 long long int virtual_timer_value; 90 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); 91 return virtual_timer_value; 92 #else 93 #error unsupported hardware architecture 94 #endif 95 } 96 97 #if defined( __i386 ) || defined( __x86_64 ) 98 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 99 #elif defined( __ARM_ARCH ) 100 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 101 #else 102 #error unsupported architecture 103 #endif 104 static inline long long rdtscl(void) { 105 unsigned int lo, hi; 106 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 107 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 108 } 104 109 105 110 static inline void affinity(int tid) { … … 190 195 } 191 196 192 // Barrier from193 class barrier_t {194 public:195 barrier_t(size_t total)196 : waiting(0)197 , total(total)198 {}199 200 void wait(unsigned) {201 size_t target = waiting++;202 target = (target - (target % total)) + total;203 while(waiting < target)204 Pause();205 206 assert(waiting < (1ul << 60));207 }208 209 private:210 std::atomic<size_t> waiting;211 size_t total;212 };213 214 197 struct spinlock_t { 215 198 std::atomic_bool ll = { false }; … … 218 201 while( __builtin_expect(ll.exchange(true),false) ) { 219 202 while(ll.load(std::memory_order_relaxed)) 220 Pause();203 asm volatile("pause"); 221 204 } 222 205 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp
r5407cdc rfeacef9 6 6 #include <memory> 7 7 #include <mutex> 8 #include <thread>9 8 #include <type_traits> 10 9 … … 12 11 #include "utils.hpp" 13 12 #include "links.hpp" 14 #include "links2.hpp"15 13 #include "snzi.hpp" 16 14 17 // #include <x86intrin.h>18 19 15 using namespace std; 20 21 static const long long lim = 2000;22 static const unsigned nqueues = 2;23 24 struct __attribute__((aligned(128))) timestamp_t {25 volatile unsigned long long val = 0;26 };27 28 template<typename node_t>29 struct __attribute__((aligned(128))) localQ_t {30 #ifdef NO_MPSC31 intrusive_queue_t<node_t> list;32 33 inline auto ts() { return list.ts(); }34 inline auto lock() { return list.lock.lock(); }35 inline auto try_lock() { return list.lock.try_lock(); }36 inline auto unlock() { return list.lock.unlock(); }37 38 inline auto push( node_t * node ) { return list.push( node ); }39 inline auto pop() { return list.pop(); }40 #else41 mpsc_queue<node_t> queue = {};42 spinlock_t _lock = {};43 44 inline auto ts() { auto h = queue.head(); return h ? h->_links.ts : 0ull; }45 inline auto lock() { return _lock.lock(); }46 inline auto try_lock() { return _lock.try_lock(); }47 inline auto unlock() { return _lock.unlock(); }48 49 inline auto push( node_t * node ) { return queue.push( node ); }50 inline auto pop() { return queue.pop(); }51 #endif52 53 54 };55 16 56 17 template<typename node_t> … … 64 25 65 26 work_stealing(unsigned _numThreads, unsigned) 66 : numThreads(_numThreads * nqueues) 67 , lists(new localQ_t<node_t>[numThreads]) 68 // , lists(new intrusive_queue_t<node_t>[numThreads]) 69 , times(new timestamp_t[numThreads]) 70 // , snzi( std::log2( numThreads / 2 ), 2 ) 27 : numThreads(_numThreads) 28 , lists(new intrusive_queue_t<node_t>[numThreads]) 29 , snzi( std::log2( numThreads / 2 ), 2 ) 71 30 72 31 { … … 81 40 __attribute__((noinline, hot)) void push(node_t * node) { 82 41 node->_links.ts = rdtscl(); 83 // node->_links.ts = 1; 84 85 auto & list = *({ 86 unsigned i; 87 #ifdef NO_MPSC 88 do { 89 #endif 90 tls.stats.push.attempt++; 91 // unsigned r = tls.rng1.next(); 92 unsigned r = tls.it++; 93 if(tls.my_queue == outside) { 94 i = r % numThreads; 95 } else { 96 i = tls.my_queue + (r % nqueues); 42 if( node->_links.hint > numThreads ) { 43 node->_links.hint = tls.rng.next() % numThreads; 44 tls.stat.push.nhint++; 45 } 46 47 unsigned i = node->_links.hint; 48 auto & list = lists[i]; 49 list.lock.lock(); 50 51 if(list.push( node )) { 52 snzi.arrive(i); 53 } 54 55 list.lock.unlock(); 56 } 57 58 __attribute__((noinline, hot)) node_t * pop() { 59 node_t * node; 60 while(true) { 61 if(!snzi.query()) { 62 return nullptr; 63 } 64 65 { 66 unsigned i = tls.my_queue; 67 auto & list = lists[i]; 68 if( list.ts() != 0 ) { 69 list.lock.lock(); 70 if((node = try_pop(i))) { 71 tls.stat.pop.local.success++; 72 break; 73 } 74 else { 75 tls.stat.pop.local.elock++; 76 } 97 77 } 98 #ifdef NO_MPSC 99 } while(!lists[i].try_lock()); 100 #endif 101 &lists[i]; 102 }); 103 104 list.push( node ); 105 #ifdef NO_MPSC 106 list.unlock(); 78 else { 79 tls.stat.pop.local.espec++; 80 } 81 } 82 83 tls.stat.pop.steal.tried++; 84 85 int i = tls.rng.next() % numThreads; 86 auto & list = lists[i]; 87 if( list.ts() == 0 ) { 88 tls.stat.pop.steal.empty++; 89 continue; 90 } 91 92 if( !list.lock.try_lock() ) { 93 tls.stat.pop.steal.locked++; 94 continue; 95 } 96 97 if((node = try_pop(i))) { 98 tls.stat.pop.steal.success++; 99 break; 100 } 101 } 102 103 #if defined(READ) 104 const unsigned f = READ; 105 if(0 == (tls.it % f)) { 106 unsigned i = tls.it / f; 107 lists[i % numThreads].ts(); 108 } 109 // lists[tls.it].ts(); 110 tls.it++; 107 111 #endif 108 // tls.rng2.set_raw_state( tls.rng1.get_raw_state()); 109 // count++; 110 tls.stats.push.success++; 111 } 112 113 __attribute__((noinline, hot)) node_t * pop() { 114 if(tls.my_queue != outside) { 115 // if( tls.myfriend == outside ) { 116 // auto r = tls.rng1.next(); 117 // tls.myfriend = r % numThreads; 118 // // assert(lists[(tls.it % nqueues) + tls.my_queue].ts() >= lists[((tls.it + 1) % nqueues) + tls.my_queue].ts()); 119 // tls.mytime = std::min(lists[(tls.it % nqueues) + tls.my_queue].ts(), lists[((tls.it + 1) % nqueues) + tls.my_queue].ts()); 120 // // times[tls.myfriend].val = 0; 121 // // lists[tls.myfriend].val = 0; 122 // } 123 // // else if(times[tls.myfriend].val == 0) { 124 // // else if(lists[tls.myfriend].val == 0) { 125 // else if(times[tls.myfriend].val < tls.mytime) { 126 // // else if(times[tls.myfriend].val < lists[(tls.it % nqueues) + tls.my_queue].ts()) { 127 // node_t * n = try_pop(tls.myfriend, tls.stats.pop.help); 128 // tls.stats.help++; 129 // tls.myfriend = outside; 130 // if(n) return n; 131 // } 132 // if( tls.myfriend == outside ) { 133 // auto r = tls.rng1.next(); 134 // tls.myfriend = r % numThreads; 135 // tls.mytime = lists[((tls.it + 1) % nqueues) + tls.my_queue].ts(); 136 // } 137 // else { 138 // if(times[tls.myfriend].val + 1000 < tls.mytime) { 139 // node_t * n = try_pop(tls.myfriend, tls.stats.pop.help); 140 // tls.stats.help++; 141 // if(n) return n; 142 // } 143 // tls.myfriend = outside; 144 // } 145 146 node_t * n = local(); 147 if(n) return n; 148 } 149 150 // try steal 151 for(int i = 0; i < 25; i++) { 152 node_t * n = steal(); 153 if(n) return n; 154 } 155 156 return search(); 157 } 158 159 private: 160 inline node_t * local() { 161 unsigned i = (--tls.it % nqueues) + tls.my_queue; 162 node_t * n = try_pop(i, tls.stats.pop.local); 163 if(n) return n; 164 i = (--tls.it % nqueues) + tls.my_queue; 165 return try_pop(i, tls.stats.pop.local); 166 } 167 168 inline node_t * steal() { 169 unsigned i = tls.rng2.prev() % numThreads; 170 return try_pop(i, tls.stats.pop.steal); 171 } 172 173 inline node_t * search() { 174 unsigned offset = tls.rng2.prev(); 175 for(unsigned i = 0; i < numThreads; i++) { 176 unsigned idx = (offset + i) % numThreads; 177 node_t * thrd = try_pop(idx, tls.stats.pop.search); 178 if(thrd) { 179 return thrd; 180 } 181 } 182 183 return nullptr; 184 } 185 186 private: 187 struct attempt_stat_t { 188 std::size_t attempt = { 0 }; 189 std::size_t elock = { 0 }; 190 std::size_t eempty = { 0 }; 191 std::size_t espec = { 0 }; 192 std::size_t success = { 0 }; 193 }; 194 195 node_t * try_pop(unsigned i, attempt_stat_t & stat) { 196 assert(i < numThreads); 112 113 114 return node; 115 } 116 117 private: 118 node_t * try_pop(unsigned i) { 197 119 auto & list = lists[i]; 198 stat.attempt++;199 200 // If the list is empty, don't try201 if(list.ts() == 0) { stat.espec++; return nullptr; }202 203 // If we can't get the lock, move on204 if( !list.try_lock() ) { stat.elock++; return nullptr; }205 120 206 121 // If list is empty, unlock and retry 207 122 if( list.ts() == 0 ) { 208 list.unlock(); 209 stat.eempty++; 123 list.lock.unlock(); 210 124 return nullptr; 211 125 } 212 126 213 auto node = list.pop(); 214 list.unlock(); 215 stat.success++; 216 #ifdef NO_MPSC 217 // times[i].val = 1; 218 times[i].val = node.first->_links.ts; 219 // lists[i].val = node.first->_links.ts; 220 return node.first; 221 #else 222 times[i].val = node->_links.ts; 223 return node; 224 #endif 127 // Actually pop the list 128 node_t * node; 129 bool emptied; 130 std::tie(node, emptied) = list.pop(); 131 assert(node); 132 133 if(emptied) { 134 snzi.depart(i); 135 } 136 137 // Unlock and return 138 list.lock.unlock(); 139 return node; 225 140 } 226 141 … … 229 144 230 145 static std::atomic_uint32_t ticket; 231 static const unsigned outside = 0xFFFFFFFF;232 233 static inline unsigned calc_preferred() {234 unsigned t = ticket++;235 if(t == 0) return outside;236 unsigned i = (t - 1) * nqueues;237 return i;238 }239 240 146 static __attribute__((aligned(128))) thread_local struct TLS { 241 Random rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) }; 242 Random rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) }; 243 unsigned it = 0; 244 unsigned my_queue = calc_preferred(); 245 unsigned myfriend = outside; 246 unsigned long long int mytime = 0; 147 Random rng = { int(rdtscl()) }; 148 unsigned my_queue = ticket++; 247 149 #if defined(READ) 248 150 unsigned it = 0; … … 250 152 struct { 251 153 struct { 252 std::size_t attempt = { 0 }; 253 std::size_t success = { 0 }; 154 std::size_t nhint = { 0 }; 254 155 } push; 255 156 struct { 256 attempt_stat_t help; 257 attempt_stat_t local; 258 attempt_stat_t steal; 259 attempt_stat_t search; 157 struct { 158 std::size_t success = { 0 }; 159 std::size_t espec = { 0 }; 160 std::size_t elock = { 0 }; 161 } local; 162 struct { 163 std::size_t tried = { 0 }; 164 std::size_t locked = { 0 }; 165 std::size_t empty = { 0 }; 166 std::size_t success = { 0 }; 167 } steal; 260 168 } pop; 261 std::size_t help = { 0 }; 262 } stats; 169 } stat; 263 170 } tls; 264 171 265 172 private: 266 173 const unsigned numThreads; 267 std::unique_ptr<localQ_t<node_t> []> lists; 268 // std::unique_ptr<intrusive_queue_t<node_t> []> lists; 269 std::unique_ptr<timestamp_t []> times; 270 __attribute__((aligned(128))) std::atomic_size_t count; 174 std::unique_ptr<intrusive_queue_t<node_t> []> lists; 175 __attribute__((aligned(64))) snzi_t snzi; 271 176 272 177 #ifndef NO_STATS … … 274 179 static struct GlobalStats { 275 180 struct { 276 std::atomic_size_t attempt = { 0 }; 277 std::atomic_size_t success = { 0 }; 181 std::atomic_size_t nhint = { 0 }; 278 182 } push; 279 183 struct { 280 184 struct { 281 std::atomic_size_t attempt = { 0 };282 std::atomic_size_t elock = { 0 };283 std::atomic_size_t eempty = { 0 };284 std::atomic_size_t espec = { 0 };285 185 std::atomic_size_t success = { 0 }; 286 } help; 287 struct { 288 std::atomic_size_t attempt = { 0 }; 289 std::atomic_size_t elock = { 0 }; 290 std::atomic_size_t eempty = { 0 }; 291 std::atomic_size_t espec = { 0 }; 292 std::atomic_size_t success = { 0 }; 186 std::atomic_size_t espec = { 0 }; 187 std::atomic_size_t elock = { 0 }; 293 188 } local; 294 189 struct { 295 std::atomic_size_t attempt = { 0 }; 296 std::atomic_size_t elock = { 0 }; 297 std::atomic_size_t eempty = { 0 }; 298 std::atomic_size_t espec = { 0 }; 190 std::atomic_size_t tried = { 0 }; 191 std::atomic_size_t locked = { 0 }; 192 std::atomic_size_t empty = { 0 }; 299 193 std::atomic_size_t success = { 0 }; 300 194 } steal; 301 struct {302 std::atomic_size_t attempt = { 0 };303 std::atomic_size_t elock = { 0 };304 std::atomic_size_t eempty = { 0 };305 std::atomic_size_t espec = { 0 };306 std::atomic_size_t success = { 0 };307 } search;308 195 } pop; 309 std::atomic_size_t help = { 0 };310 196 } global_stats; 311 197 312 198 public: 313 199 static void stats_tls_tally() { 314 global_stats.push.attempt += tls.stats.push.attempt; 315 global_stats.push.success += tls.stats.push.success; 316 global_stats.pop.help .attempt += tls.stats.pop.help .attempt; 317 global_stats.pop.help .elock += tls.stats.pop.help .elock ; 318 global_stats.pop.help .eempty += tls.stats.pop.help .eempty ; 319 global_stats.pop.help .espec += tls.stats.pop.help .espec ; 320 global_stats.pop.help .success += tls.stats.pop.help .success; 321 global_stats.pop.local .attempt += tls.stats.pop.local .attempt; 322 global_stats.pop.local .elock += tls.stats.pop.local .elock ; 323 global_stats.pop.local .eempty += tls.stats.pop.local .eempty ; 324 global_stats.pop.local .espec += tls.stats.pop.local .espec ; 325 global_stats.pop.local .success += tls.stats.pop.local .success; 326 global_stats.pop.steal .attempt += tls.stats.pop.steal .attempt; 327 global_stats.pop.steal .elock += tls.stats.pop.steal .elock ; 328 global_stats.pop.steal .eempty += tls.stats.pop.steal .eempty ; 329 global_stats.pop.steal .espec += tls.stats.pop.steal .espec ; 330 global_stats.pop.steal .success += tls.stats.pop.steal .success; 331 global_stats.pop.search.attempt += tls.stats.pop.search.attempt; 332 global_stats.pop.search.elock += tls.stats.pop.search.elock ; 333 global_stats.pop.search.eempty += tls.stats.pop.search.eempty ; 334 global_stats.pop.search.espec += tls.stats.pop.search.espec ; 335 global_stats.pop.search.success += tls.stats.pop.search.success; 336 global_stats.help += tls.stats.help; 337 } 338 339 static void stats_print(std::ostream & os, double duration ) { 200 global_stats.push.nhint += tls.stat.push.nhint; 201 global_stats.pop.local.success += tls.stat.pop.local.success; 202 global_stats.pop.local.espec += tls.stat.pop.local.espec ; 203 global_stats.pop.local.elock += tls.stat.pop.local.elock ; 204 global_stats.pop.steal.tried += tls.stat.pop.steal.tried ; 205 global_stats.pop.steal.locked += tls.stat.pop.steal.locked ; 206 global_stats.pop.steal.empty += tls.stat.pop.steal.empty ; 207 global_stats.pop.steal.success += tls.stat.pop.steal.success; 208 } 209 210 static void stats_print(std::ostream & os ) { 340 211 std::cout << "----- Work Stealing Stats -----" << std::endl; 341 212 342 double push_suc = (100.0 * double(global_stats.push.success) / global_stats.push.attempt); 343 double push_len = double(global_stats.push.attempt ) / global_stats.push.success; 344 os << "Push Pick : " << push_suc << " %, len " << push_len << " (" << global_stats.push.attempt << " / " << global_stats.push.success << ")\n"; 345 346 double hlp_suc = (100.0 * double(global_stats.pop.help.success) / global_stats.pop.help.attempt); 347 double hlp_len = double(global_stats.pop.help.attempt ) / global_stats.pop.help.success; 348 os << "Help : " << hlp_suc << " %, len " << hlp_len << " (" << global_stats.pop.help.attempt << " / " << global_stats.pop.help.success << ")\n"; 349 os << "Help Fail : " << global_stats.pop.help.espec << "s, " << global_stats.pop.help.eempty << "e, " << global_stats.pop.help.elock << "l\n"; 350 351 double pop_suc = (100.0 * double(global_stats.pop.local.success) / global_stats.pop.local.attempt); 352 double pop_len = double(global_stats.pop.local.attempt ) / global_stats.pop.local.success; 353 os << "Local : " << pop_suc << " %, len " << pop_len << " (" << global_stats.pop.local.attempt << " / " << global_stats.pop.local.success << ")\n"; 354 os << "Local Fail : " << global_stats.pop.local.espec << "s, " << global_stats.pop.local.eempty << "e, " << global_stats.pop.local.elock << "l\n"; 355 356 double stl_suc = (100.0 * double(global_stats.pop.steal.success) / global_stats.pop.steal.attempt); 357 double stl_len = double(global_stats.pop.steal.attempt ) / global_stats.pop.steal.success; 358 os << "Steal : " << stl_suc << " %, len " << stl_len << " (" << global_stats.pop.steal.attempt << " / " << global_stats.pop.steal.success << ")\n"; 359 os << "Steal Fail : " << global_stats.pop.steal.espec << "s, " << global_stats.pop.steal.eempty << "e, " << global_stats.pop.steal.elock << "l\n"; 360 361 double srh_suc = (100.0 * double(global_stats.pop.search.success) / global_stats.pop.search.attempt); 362 double srh_len = double(global_stats.pop.search.attempt ) / global_stats.pop.search.success; 363 os << "Search : " << srh_suc << " %, len " << srh_len << " (" << global_stats.pop.search.attempt << " / " << global_stats.pop.search.success << ")\n"; 364 os << "Search Fail : " << global_stats.pop.search.espec << "s, " << global_stats.pop.search.eempty << "e, " << global_stats.pop.search.elock << "l\n"; 365 os << "Helps : " << std::setw(15) << std::scientific << global_stats.help / duration << "/sec (" << global_stats.help << ")\n"; 213 double stealSucc = double(global_stats.pop.steal.success) / global_stats.pop.steal.tried; 214 os << "Push to new Q : " << std::setw(15) << global_stats.push.nhint << "\n"; 215 os << "Local Pop : " << std::setw(15) << global_stats.pop.local.success << "\n"; 216 os << "Steal Pop : " << std::setw(15) << global_stats.pop.steal.success << "(" << global_stats.pop.local.espec << "s, " << global_stats.pop.local.elock << "l)\n"; 217 os << "Steal Success : " << std::setw(15) << stealSucc << "(" << global_stats.pop.steal.tried << " tries)\n"; 218 os << "Steal Fails : " << std::setw(15) << global_stats.pop.steal.empty << "e, " << global_stats.pop.steal.locked << "l\n"; 366 219 } 367 220 private: -
doc/user/figures/Cdecl.fig
r5407cdc rfeacef9 1 #FIG 3.2 Produced by xfig version 3.2. 7b1 #FIG 3.2 Produced by xfig version 3.2.5b 2 2 Landscape 3 3 Center 4 4 Inches 5 Letter 5 Letter 6 6 100.00 7 7 Single … … 19 19 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 20 20 2850 1200 3600 1200 3600 1350 2850 1350 2850 1200 21 4 1 0 50 -1 4 11 0.0000 2 120 105 3075 1335 1\00122 4 1 0 50 -1 4 11 0.0000 2 120 105 3225 1335 2\00123 4 1 0 50 -1 4 11 0.0000 2 120 105 3375 1335 3\00124 4 1 0 50 -1 4 11 0.0000 2 120 105 3525 1335 4\00125 4 1 0 50 -1 4 11 0.0000 2 120 105 2925 1335 0\00121 4 1 0 50 -1 4 11 0.0000 2 120 90 2925 1325 0\001 22 4 1 0 50 -1 4 11 0.0000 2 120 90 3075 1325 1\001 23 4 1 0 50 -1 4 11 0.0000 2 120 90 3225 1325 2\001 24 4 1 0 50 -1 4 11 0.0000 2 120 90 3375 1325 3\001 25 4 1 0 50 -1 4 11 0.0000 2 120 90 3525 1325 4\001 26 26 -6 27 27 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 … … 55 55 1 1 1.00 45.00 60.00 56 56 2550 1275 2850 1275 57 4 1 0 50 -1 4 11 0.0000 2 120 1051350 1650 0\00158 4 1 0 50 -1 4 11 0.0000 2 120 1051500 1650 1\00159 4 1 0 50 -1 4 11 0.0000 2 120 1051650 1650 2\00160 4 1 0 50 -1 4 11 0.0000 2 120 1051800 1650 3\00161 4 1 0 50 -1 4 11 0.0000 2 120 1051950 1650 4\00157 4 1 0 50 -1 4 11 0.0000 2 120 90 1350 1650 0\001 58 4 1 0 50 -1 4 11 0.0000 2 120 90 1500 1650 1\001 59 4 1 0 50 -1 4 11 0.0000 2 120 90 1650 1650 2\001 60 4 1 0 50 -1 4 11 0.0000 2 120 90 1800 1650 3\001 61 4 1 0 50 -1 4 11 0.0000 2 120 90 1950 1650 4\001 62 62 4 1 0 50 -1 4 11 0.0000 2 90 90 1200 1325 x\001 63 63 4 1 0 50 -1 4 11 0.0000 2 90 90 2400 1325 x\001 -
doc/user/user.tex
r5407cdc rfeacef9 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun Apr 25 19:03:03 202114 %% Update Count : 4 95113 %% Last Modified On : Mon Feb 15 13:48:53 2021 14 %% Update Count : 4452 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 66 66 % math escape $...$ (dollar symbol) 67 67 \input{common} % common CFA document macros 68 \setlength{\gcolumnposn}{3in}69 68 \CFAStyle % use default CFA format-style 70 69 \lstset{language=CFA} % CFA default lnaguage 71 70 \lstnewenvironment{C++}[1][] % use C++ style 72 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{ ®}{®},#1}}71 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{@}{@},#1}} 73 72 {} 74 73 … … 82 81 \newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}} 83 82 \newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}} 84 \newcommand{\R}[1]{ {\color{red}#1}}85 \newcommand{\R B}[1]{\Textbf{#1}}83 \newcommand{\R}[1]{\Textbf{#1}} 84 \newcommand{\RC}[1]{\Textbf{\LstBasicStyle{#1}}} 86 85 \newcommand{\B}[1]{{\Textbf[blue]{#1}}} 87 86 \newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}} … … 177 176 int main( void ) { 178 177 int x = 0, y = 1, z = 2; 179 ®printf( "%d %d %d\n", x, y, z );®178 @printf( "%d %d %d\n", x, y, z );@ 180 179 } 181 180 \end{cfa} … … 186 185 int main( void ) { 187 186 int x = 0, y = 1, z = 2; 188 ®sout | x | y | z;®$\indexc{sout}$187 @sout | x | y | z;@$\indexc{sout}$ 189 188 } 190 189 \end{cfa} … … 195 194 int main() { 196 195 int x = 0, y = 1, z = 2; 197 ®cout<<x<<" "<<y<<" "<<z<<endl;®196 @cout<<x<<" "<<y<<" "<<z<<endl;@ 198 197 } 199 198 \end{cfa} … … 225 224 \begin{tabular}{@{}rcccccccc@{}} 226 225 & 2021 & 2016 & 2011 & 2006 & 2001 & 1996 & 1991 & 1986 \\ \hline 227 \R B{C} & \RB{1}& \RB{2}& \RB{2}& \RB{1}& \RB{1}& \RB{1}& \RB{1}& \RB{1}\\226 \R{C} & \R{1} & \R{2} & \R{2} & \R{1} & \R{1} & \R{1} & \R{1} & \R{1} \\ 228 227 Java & 2 & 1 & 1 & 2 & 3 & 28 & - & - \\ 229 228 Python & 3 & 5 & 6 & 7 & 23 & 13 & - & - \\ … … 259 258 The signature feature of \CFA is \emph{\Index{overload}able} \Index{parametric-polymorphic} functions~\cite{forceone:impl,Cormack90,Duggan96} with functions generalized using a ©forall© clause (giving the language its name): 260 259 \begin{cfa} 261 ®forall( otype T )®T identity( T val ) { return val; }260 @forall( otype T )@ T identity( T val ) { return val; } 262 261 int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$ 263 262 \end{cfa} … … 323 322 Whereas, \CFA wraps each of these routines into one overloaded name ©abs©: 324 323 \begin{cfa} 325 char ®abs®( char );326 extern "C" { int ®abs®( int ); } $\C{// use default C routine for int}$327 long int ®abs®( long int );328 long long int ®abs®( long long int );329 float ®abs®( float );330 double ®abs®( double );331 long double ®abs®( long double );332 float _Complex ®abs®( float _Complex );333 double _Complex ®abs®( double _Complex );334 long double _Complex ®abs®( long double _Complex );324 char @abs@( char ); 325 extern "C" { int @abs@( int ); } $\C{// use default C routine for int}$ 326 long int @abs@( long int ); 327 long long int @abs@( long long int ); 328 float @abs@( float ); 329 double @abs@( double ); 330 long double @abs@( long double ); 331 float _Complex @abs@( float _Complex ); 332 double _Complex @abs@( double _Complex ); 333 long double _Complex @abs@( long double _Complex ); 335 334 \end{cfa} 336 335 The problem is \Index{name clash} between the C name ©abs© and the \CFA names ©abs©, resulting in two name linkages\index{C linkage}: ©extern "C"© and ©extern "Cforall"© (default). … … 359 358 The 2011 C standard plus GNU extensions. 360 359 \item 361 \Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline] {-fgnu89-inline}}}360 \Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline]$-fgnu89-inline$}} 362 361 Use the traditional GNU semantics for inline routines in C11 mode, which allows inline routines in header files. 363 362 \end{description} … … 531 530 Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism: 532 531 \begin{cfa} 533 int ®``®otype = 3; $\C{// make keyword an identifier}$534 double ®``®forall = 3.5;532 int @``@otype = 3; $\C{// make keyword an identifier}$ 533 double @``@forall = 3.5; 535 534 \end{cfa} 536 535 … … 543 542 // include file uses the CFA keyword "with". 544 543 #if ! defined( with ) $\C{// nesting ?}$ 545 #define with ®``®with $\C{// make keyword an identifier}$544 #define with @``@with $\C{// make keyword an identifier}$ 546 545 #define __CFA_BFD_H__ 547 546 #endif … … 561 560 Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg: 562 561 \begin{cfa} 563 2 ®_®147®_®483®_®648; $\C{// decimal constant}$564 56 ®_®ul; $\C{// decimal unsigned long constant}$565 0 ®_®377; $\C{// octal constant}$566 0x ®_®ff®_®ff; $\C{// hexadecimal constant}$567 0x ®_®ef3d®_®aa5c; $\C{// hexadecimal constant}$568 3.141 ®_®592®_®654; $\C{// floating constant}$569 10 ®_®e®_®+1®_®00; $\C{// floating constant}$570 0x ®_®ff®_®ff®_®p®_®3; $\C{// hexadecimal floating}$571 0x ®_®1.ffff®_®ffff®_®p®_®128®_®l; $\C{// hexadecimal floating long constant}$572 L ®_®$"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$562 2@_@147@_@483@_@648; $\C{// decimal constant}$ 563 56@_@ul; $\C{// decimal unsigned long constant}$ 564 0@_@377; $\C{// octal constant}$ 565 0x@_@ff@_@ff; $\C{// hexadecimal constant}$ 566 0x@_@ef3d@_@aa5c; $\C{// hexadecimal constant}$ 567 3.141@_@592@_@654; $\C{// floating constant}$ 568 10@_@e@_@+1@_@00; $\C{// floating constant}$ 569 0x@_@ff@_@ff@_@p@_@3; $\C{// hexadecimal floating}$ 570 0x@_@1.ffff@_@ffff@_@p@_@128@_@l; $\C{// hexadecimal floating long constant}$ 571 L@_@$"\texttt{\textbackslash{x}}$@_@$\texttt{ff}$@_@$\texttt{ee}"$; $\C{// wide character constant}$ 573 572 \end{cfa} 574 573 The rules for placement of underscores are: … … 603 602 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative. 604 603 \begin{cfa} 605 sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\®2.1606 | (1.0f+2.0fi) ®\®(3.0f+2.0fi);607 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0®-0.015625 18.3791736799526 0.264715-1.1922i604 sout | 1 @\@ 0 | 1 @\@ 1 | 2 @\@ 8 | -4 @\@ 3 | 5 @\@ 3 | 5 @\@ 32 | 5L @\@ 32 | 5L @\@ 64 | -4 @\@ -3 | -4.0 @\@ -3 | 4.0 @\@ 2.1 605 | (1.0f+2.0fi) @\@ (3.0f+2.0fi); 606 1 1 256 -64 125 @0@ 3273344365508751233 @0@ @0@ -0.015625 18.3791736799526 0.264715-1.1922i 608 607 \end{cfa} 609 608 Note, ©5 \ 32© and ©5L \ 64© overflow, and ©-4 \ -3© is a fraction but stored in an integer so all three computations generate an integral zero. … … 613 612 \begin{cfa} 614 613 forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } ) 615 T ? ®\®?( T ep, unsigned int y );614 T ?@\@?( T ep, unsigned int y ); 616 615 forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } ) 617 T ? ®\®?( T ep, unsigned long int y );616 T ?@\@?( T ep, unsigned long int y ); 618 617 \end{cfa} 619 618 The user type ©T© must define multiplication, one (©1©), and ©*©. … … 625 624 626 625 627 %\subsection{\texorpdfstring{\protect\lstinline {if}/\protect\lstinline{while}Statement}{if Statement}}626 %\subsection{\texorpdfstring{\protect\lstinline@if@/\protect\lstinline@while@ Statement}{if Statement}} 628 627 \subsection{\texorpdfstring{\LstKeywordStyle{if} / \LstKeywordStyle{while} Statement}{if / while Statement}} 629 628 … … 631 630 Declarations in the ©do©-©while© condition are not useful because they appear after the loop body.} 632 631 \begin{cfa} 633 if ( ®int x = f()®) ... $\C{// x != 0}$634 if ( ®int x = f(), y = g()®) ... $\C{// x != 0 \&\& y != 0}$635 if ( ®int x = f(), y = g(); x < y®) ... $\C{// relational expression}$636 if ( ®struct S { int i; } x = { f() }; x.i < 4®) $\C{// relational expression}$637 638 while ( ®int x = f()®) ... $\C{// x != 0}$639 while ( ®int x = f(), y = g()®) ... $\C{// x != 0 \&\& y != 0}$640 while ( ®int x = f(), y = g(); x < y®) ... $\C{// relational expression}$641 while ( ®struct S { int i; } x = { f() }; x.i < 4®) ... $\C{// relational expression}$632 if ( @int x = f()@ ) ... $\C{// x != 0}$ 633 if ( @int x = f(), y = g()@ ) ... $\C{// x != 0 \&\& y != 0}$ 634 if ( @int x = f(), y = g(); x < y@ ) ... $\C{// relational expression}$ 635 if ( @struct S { int i; } x = { f() }; x.i < 4@ ) $\C{// relational expression}$ 636 637 while ( @int x = f()@ ) ... $\C{// x != 0}$ 638 while ( @int x = f(), y = g()@ ) ... $\C{// x != 0 \&\& y != 0}$ 639 while ( @int x = f(), y = g(); x < y@ ) ... $\C{// relational expression}$ 640 while ( @struct S { int i; } x = { f() }; x.i < 4@ ) ... $\C{// relational expression}$ 642 641 \end{cfa} 643 642 Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the ©if©/©while© expression, and the results are combined using the logical ©&&© operator. … … 646 645 647 646 648 %\section{\texorpdfstring{\protect\lstinline {case}Clause}{case Clause}}647 %\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}} 649 648 \subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}} 650 649 \label{s:caseClause} … … 659 658 \begin{cfa} 660 659 switch ( i ) { 661 case ®1, 3, 5®:660 case @1, 3, 5@: 662 661 ... 663 case ®2, 4, 6®:662 case @2, 4, 6@: 664 663 ... 665 664 } … … 686 685 \end{cquote} 687 686 In addition, subranges are allowed to specify case values.\footnote{ 688 gcc has the same mechanism but awkward syntax, \lstinline {2 ...42}, because a space is required after a number, otherwise the period is a decimal point.}687 gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.} 689 688 \begin{cfa} 690 689 switch ( i ) { 691 case ®1~5:®$\C{// 1, 2, 3, 4, 5}$690 case @1~5:@ $\C{// 1, 2, 3, 4, 5}$ 692 691 ... 693 case ®10~15:®$\C{// 10, 11, 12, 13, 14, 15}$692 case @10~15:@ $\C{// 10, 11, 12, 13, 14, 15}$ 694 693 ... 695 694 } … … 697 696 Lists of subranges are also allowed. 698 697 \begin{cfa} 699 case ®1~5, 12~21, 35~42®:700 \end{cfa} 701 702 703 %\section{\texorpdfstring{\protect\lstinline {switch}Statement}{switch Statement}}698 case @1~5, 12~21, 35~42@: 699 \end{cfa} 700 701 702 %\section{\texorpdfstring{\protect\lstinline@switch@ Statement}{switch Statement}} 704 703 \subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}} 705 704 … … 741 740 if ( argc == 3 ) { 742 741 // open output file 743 ®// open input file744 ®} else if ( argc == 2 ) {745 ®// open input file (duplicate)746 747 ®} else {742 @// open input file 743 @} else if ( argc == 2 ) { 744 @// open input file (duplicate) 745 746 @} else { 748 747 // usage message 749 748 } … … 756 755 \begin{cfa} 757 756 switch ( i ) { 758 ®case 1: case 3: case 5:®// odd values757 @case 1: case 3: case 5:@ // odd values 759 758 // odd action 760 759 break; 761 ®case 2: case 4: case 6:®// even values760 @case 2: case 4: case 6:@ // even values 762 761 // even action 763 762 break; … … 775 774 if ( j < k ) { 776 775 ... 777 ®case 1:®// transfer into "if" statement776 @case 1:@ // transfer into "if" statement 778 777 ... 779 778 } // if … … 781 780 while ( j < 5 ) { 782 781 ... 783 ®case 3:®// transfer into "while" statement782 @case 3:@ // transfer into "while" statement 784 783 ... 785 784 } // while … … 822 821 \begin{cfa} 823 822 switch ( x ) { 824 ®int y = 1;®$\C{// unreachable initialization}$825 ®x = 7;®$\C{// unreachable code without label/branch}$823 @int y = 1;@ $\C{// unreachable initialization}$ 824 @x = 7;@ $\C{// unreachable code without label/branch}$ 826 825 case 0: ... 827 826 ... 828 ®int z = 0;®$\C{// unreachable initialization, cannot appear after case}$827 @int z = 0;@ $\C{// unreachable initialization, cannot appear after case}$ 829 828 z = 2; 830 829 case 1: 831 ®x = z;®$\C{// without fall through, z is uninitialized}$830 @x = z;@ $\C{// without fall through, z is uninitialized}$ 832 831 } 833 832 \end{cfa} … … 861 860 Therefore, to preserve backwards compatibility, it is necessary to introduce a new kind of ©switch© statement, called ©choose©, with no implicit fall-through semantics and an explicit fall-through if the last statement of a case-clause ends with the new keyword ©fallthrough©/©fallthru©, \eg: 862 861 \begin{cfa} 863 ®choose®( i ) {862 @choose@ ( i ) { 864 863 case 1: case 2: case 3: 865 864 ... 866 ®// implicit end of switch (break)867 ®case 5:865 @// implicit end of switch (break) 866 @case 5: 868 867 ... 869 ®fallthru®; $\C{// explicit fall through}$868 @fallthru@; $\C{// explicit fall through}$ 870 869 case 7: 871 870 ... 872 ®break®$\C{// explicit end of switch (redundant)}$871 @break@ $\C{// explicit end of switch (redundant)}$ 873 872 default: 874 873 j = 3; … … 891 890 \begin{cfa} 892 891 switch ( x ) { 893 ®int i = 0;®$\C{// allowed only at start}$892 @int i = 0;@ $\C{// allowed only at start}$ 894 893 case 0: 895 894 ... 896 ®int j = 0;®$\C{// disallowed}$895 @int j = 0;@ $\C{// disallowed}$ 897 896 case 1: 898 897 { 899 ®int k = 0;®$\C{// allowed at different nesting levels}$898 @int k = 0;@ $\C{// allowed at different nesting levels}$ 900 899 ... 901 ®case 2:®$\C{// disallow case in nested statements}$900 @case 2:@ $\C{// disallow case in nested statements}$ 902 901 } 903 902 ... … … 916 915 case 3: 917 916 if ( ... ) { 918 ... ®fallthru;®// goto case 4917 ... @fallthru;@ // goto case 4 919 918 } else { 920 919 ... … … 931 930 choose ( ... ) { 932 931 case 3: 933 ... ®fallthrough common;®932 ... @fallthrough common;@ 934 933 case 4: 935 ... ®fallthrough common;®936 937 ®common:®// below fallthrough934 ... @fallthrough common;@ 935 936 @common:@ // below fallthrough 938 937 // at case-clause level 939 938 ... // common code for cases 3/4 … … 951 950 for ( ... ) { 952 951 // multi-level transfer 953 ... ®fallthru common;®952 ... @fallthru common;@ 954 953 } 955 954 ... 956 955 } 957 956 ... 958 ®common:®// below fallthrough957 @common:@ // below fallthrough 959 958 // at case-clause level 960 959 \end{cfa} … … 971 970 \hline 972 971 \begin{cfa} 973 while ®($\,$)®{ sout | "empty"; break; }974 do { sout | "empty"; break; } while ®($\,$)®;975 for ®($\,$)®{ sout | "empty"; break; }976 for ( ®0®) { sout | "A"; } sout | "zero";977 for ( ®1®) { sout | "A"; }978 for ( ®10®) { sout | "A"; }979 for ( ®= 10®) { sout | "A"; }980 for ( ®1 ~= 10 ~ 2®) { sout | "B"; }981 for ( ®10 -~= 1 ~ 2®) { sout | "C"; }982 for ( ®0.5 ~ 5.5®) { sout | "D"; }983 for ( ®5.5 -~ 0.5®) { sout | "E"; }984 for ( ®i; 10®) { sout | i; }985 for ( ®i; = 10®) { sout | i; }986 for ( ®i; 1 ~= 10 ~ 2®) { sout | i; }987 for ( ®i; 10 -~= 1 ~ 2®) { sout | i; }988 for ( ®i; 0.5 ~ 5.5®) { sout | i; }989 for ( ®i; 5.5 -~ 0.5®) { sout | i; }990 for ( ®ui; 2u ~= 10u ~ 2u®) { sout | ui; }991 for ( ®ui; 10u -~= 2u ~ 2u®) { sout | ui; }972 while @($\,$)@ { sout | "empty"; break; } 973 do { sout | "empty"; break; } while @($\,$)@; 974 for @($\,$)@ { sout | "empty"; break; } 975 for ( @0@ ) { sout | "A"; } sout | "zero"; 976 for ( @1@ ) { sout | "A"; } 977 for ( @10@ ) { sout | "A"; } 978 for ( @= 10@ ) { sout | "A"; } 979 for ( @1 ~= 10 ~ 2@ ) { sout | "B"; } 980 for ( @10 -~= 1 ~ 2@ ) { sout | "C"; } 981 for ( @0.5 ~ 5.5@ ) { sout | "D"; } 982 for ( @5.5 -~ 0.5@ ) { sout | "E"; } 983 for ( @i; 10@ ) { sout | i; } 984 for ( @i; = 10@ ) { sout | i; } 985 for ( @i; 1 ~= 10 ~ 2@ ) { sout | i; } 986 for ( @i; 10 -~= 1 ~ 2@ ) { sout | i; } 987 for ( @i; 0.5 ~ 5.5@ ) { sout | i; } 988 for ( @i; 5.5 -~ 0.5@ ) { sout | i; } 989 for ( @ui; 2u ~= 10u ~ 2u@ ) { sout | ui; } 990 for ( @ui; 10u -~= 2u ~ 2u@ ) { sout | ui; } 992 991 enum { N = 10 }; 993 for ( ®N®) { sout | "N"; }994 for ( ®i; N®) { sout | i; }995 for ( ®i; N -~ 0®) { sout | i; }992 for ( @N@ ) { sout | "N"; } 993 for ( @i; N@ ) { sout | i; } 994 for ( @i; N -~ 0@ ) { sout | i; } 996 995 const int start = 3, comp = 10, inc = 2; 997 for ( ®i; start ~ comp ~ inc + 1®) { sout | i; }998 for ( i; 1 ~ ®@®) { if ( i > 10 ) break; sout | i; }999 for ( i; 10 -~ ®@®) { if ( i < 0 ) break; sout | i; }1000 for ( i; 2 ~ ®@®~ 2 ) { if ( i > 10 ) break; sout | i; }1001 for ( i; 2.1 ~ ®@® ~ ®@®) { if ( i > 10.5 ) break; sout | i; i += 1.7; }1002 for ( i; 10 -~ ®@®~ 2 ) { if ( i < 0 ) break; sout | i; }1003 for ( i; 12.1 ~ ®@® ~ ®@®) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }1004 for ( i; 5 ®:® j; -5 ~ @) { sout | i | j; }1005 for ( i; 5 ®:® j; -5 -~ @) { sout | i | j; }1006 for ( i; 5 ®:® j; -5 ~ @~ 2 ) { sout | i | j; }1007 for ( i; 5 ®:® j; -5 -~ @~ 2 ) { sout | i | j; }1008 for ( i; 5 ®:® j; -5 ~ @) { sout | i | j; }1009 for ( i; 5 ®:® j; -5 -~ @) { sout | i | j; }1010 for ( i; 5 ®:® j; -5 ~ @~ 2 ) { sout | i | j; }1011 for ( i; 5 ®:® j; -5 -~ @~ 2 ) { sout | i | j; }1012 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @) { sout | i | j | k; }1013 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @) { sout | i | j | k; }1014 for ( i; 5 ®:® k; 1.5 ~ @ ®:® j; -5 -~ @~ 2 ) { sout | i | j | k; }996 for ( @i; start ~ comp ~ inc + 1@ ) { sout | i; } 997 for ( i; 1 ~ $\R{@}$ ) { if ( i > 10 ) break; sout | i; } 998 for ( i; 10 -~ $\R{@}$ ) { if ( i < 0 ) break; sout | i; } 999 for ( i; 2 ~ $\R{@}$ ~ 2 ) { if ( i > 10 ) break; sout | i; } 1000 for ( i; 2.1 ~ $\R{@}$ ~ $\R{@}$ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } 1001 for ( i; 10 -~ $\R{@}$ ~ 2 ) { if ( i < 0 ) break; sout | i; } 1002 for ( i; 12.1 ~ $\R{@}$ ~ $\R{@}$ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } 1003 for ( i; 5 @:@ j; -5 ~ $@$ ) { sout | i | j; } 1004 for ( i; 5 @:@ j; -5 -~ $@$ ) { sout | i | j; } 1005 for ( i; 5 @:@ j; -5 ~ $@$ ~ 2 ) { sout | i | j; } 1006 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j; } 1007 for ( i; 5 @:@ j; -5 ~ $@$ ) { sout | i | j; } 1008 for ( i; 5 @:@ j; -5 -~ $@$ ) { sout | i | j; } 1009 for ( i; 5 @:@ j; -5 ~ $@$ ~ 2 ) { sout | i | j; } 1010 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j; } 1011 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$ ) { sout | i | j | k; } 1012 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$ ) { sout | i | j | k; } 1013 for ( i; 5 @:@ k; 1.5 ~ $@$ @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j | k; } 1015 1014 \end{cfa} 1016 1015 & … … 1090 1089 The loop index is polymorphic in the type of the comparison value N (when the start value is implicit) or the start value M. 1091 1090 \begin{cfa} 1092 for ( i; ®5®) $\C[2.5in]{// typeof(5) i; 5 is comparison value}$1093 for ( i; ®1.5®~5.5~0.5 ) $\C{// typeof(1.5) i; 1.5 is start value}$1091 for ( i; @5@ ) $\C[2.5in]{// typeof(5) i; 5 is comparison value}$ 1092 for ( i; @1.5@~5.5~0.5 ) $\C{// typeof(1.5) i; 1.5 is start value}$ 1094 1093 \end{cfa} 1095 1094 \item 1096 1095 An empty conditional implies comparison value of ©1© (true). 1097 1096 \begin{cfa} 1098 while ( ®/*empty*/® )$\C{// while ( true )}$1099 for ( ®/*empty*/®) $\C{// for ( ; true; )}$1100 do ... while ( ®/*empty*/® )$\C{// do ... while ( true )}$1097 while ( $\R{/*empty*/}$ ) $\C{// while ( true )}$ 1098 for ( $\R{/*empty*/}$ ) $\C{// for ( ; true; )}$ 1099 do ... while ( $\R{/*empty*/}$ ) $\C{// do ... while ( true )}$ 1101 1100 \end{cfa} 1102 1101 \item 1103 1102 A comparison N is implicit up-to exclusive range [0,N\R{)}. 1104 1103 \begin{cfa} 1105 for ( ®5®) $\C{// for ( typeof(5) i; i < 5; i += 1 )}$1104 for ( @5@ ) $\C{// for ( typeof(5) i; i < 5; i += 1 )}$ 1106 1105 \end{cfa} 1107 1106 \item 1108 1107 A comparison ©=© N is implicit up-to inclusive range [0,N\R{]}. 1109 1108 \begin{cfa} 1110 for ( ®=®5 ) $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$1109 for ( @=@5 ) $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$ 1111 1110 \end{cfa} 1112 1111 \item 1113 1112 The up-to range M ©~©\index{~@©~©} N means exclusive range [M,N\R{)}. 1114 1113 \begin{cfa} 1115 for ( 1 ®~®5 ) $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$1114 for ( 1@~@5 ) $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$ 1116 1115 \end{cfa} 1117 1116 \item 1118 1117 The up-to range M ©~=©\index{~=@©~=©} N means inclusive range [M,N\R{]}. 1119 1118 \begin{cfa} 1120 for ( 1 ®~=®5 ) $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$1119 for ( 1@~=@5 ) $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$ 1121 1120 \end{cfa} 1122 1121 \item 1123 1122 The down-to range M ©-~©\index{-~@©-~©} N means exclusive range [N,M\R{)}. 1124 1123 \begin{cfa} 1125 for ( 1 ®-~®5 ) $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$1124 for ( 1@-~@5 ) $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$ 1126 1125 \end{cfa} 1127 1126 \item 1128 1127 The down-to range M ©-~=©\index{-~=@©-~=©} N means inclusive range [N,M\R{]}. 1129 1128 \begin{cfa} 1130 for ( 1 ®-~=®5 ) $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$1129 for ( 1@-~=@5 ) $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$ 1131 1130 \end{cfa} 1132 1131 \item 1133 1132 ©@© means put nothing in this field. 1134 1133 \begin{cfa} 1135 for ( 1~ ®@®~2 )$\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$1134 for ( 1~$\R{@}$~2 ) $\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$ 1136 1135 \end{cfa} 1137 1136 \item 1138 1137 ©:© means start another index. 1139 1138 \begin{cfa} 1140 for ( i; 5 ®:®j; 2~12~3 ) $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$1139 for ( i; 5 @:@ j; 2~12~3 ) $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$ 1141 1140 \end{cfa} 1142 1141 \end{itemize} 1143 1142 1144 1143 1145 %\subsection{\texorpdfstring{Labelled \protect\lstinline {continue} / \protect\lstinline{break}}{Labelled continue / break}}1144 %\subsection{\texorpdfstring{Labelled \protect\lstinline@continue@ / \protect\lstinline@break@}{Labelled continue / break}} 1146 1145 \subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break} Statement}{Labelled continue / break Statement}} 1147 1146 … … 1158 1157 \begin{lrbox}{\myboxA} 1159 1158 \begin{cfa}[tabsize=3] 1160 ®Compound:®{1161 ®Try:®try {1162 ®For:®for ( ... ) {1163 ®While:®while ( ... ) {1164 ®Do:®do {1165 ®If:®if ( ... ) {1166 ®Switch:®switch ( ... ) {1159 @Compound:@ { 1160 @Try:@ try { 1161 @For:@ for ( ... ) { 1162 @While:@ while ( ... ) { 1163 @Do:@ do { 1164 @If:@ if ( ... ) { 1165 @Switch:@ switch ( ... ) { 1167 1166 case 3: 1168 ®break Compound®;1169 ®break Try®;1170 ®break For®; /* or */ ®continue For®;1171 ®break While®; /* or */ ®continue While®;1172 ®break Do®; /* or */ ®continue Do®;1173 ®break If®;1174 ®break Switch®;1167 @break Compound@; 1168 @break Try@; 1169 @break For@; /* or */ @continue For@; 1170 @break While@; /* or */ @continue While@; 1171 @break Do@; /* or */ @continue Do@; 1172 @break If@; 1173 @break Switch@; 1175 1174 } // switch 1176 1175 } else { 1177 ... ®break If®; ... // terminate if1176 ... @break If@; ... // terminate if 1178 1177 } // if 1179 1178 } while ( ... ); // do 1180 1179 } // while 1181 1180 } // for 1182 } ®finally®{ // always executed1181 } @finally@ { // always executed 1183 1182 } // try 1184 1183 } // compound … … 1190 1189 { 1191 1190 1192 ®ForC:®for ( ... ) {1193 ®WhileC:®while ( ... ) {1194 ®DoC:®do {1191 @ForC:@ for ( ... ) { 1192 @WhileC:@ while ( ... ) { 1193 @DoC:@ do { 1195 1194 if ( ... ) { 1196 1195 switch ( ... ) { 1197 1196 case 3: 1198 ®goto Compound®;1199 ®goto Try®;1200 ®goto ForB®; /* or */ ®goto ForC®;1201 ®goto WhileB®; /* or */ ®goto WhileC®;1202 ®goto DoB®; /* or */ ®goto DoC®;1203 ®goto If®;1204 ®goto Switch®;1205 } ®Switch:®;1197 @goto Compound@; 1198 @goto Try@; 1199 @goto ForB@; /* or */ @goto ForC@; 1200 @goto WhileB@; /* or */ @goto WhileC@; 1201 @goto DoB@; /* or */ @goto DoC@; 1202 @goto If@; 1203 @goto Switch@; 1204 } @Switch:@ ; 1206 1205 } else { 1207 ... ®goto If®; ... // terminate if1208 } ®If:®;1209 } while ( ... ); ®DoB:®;1210 } ®WhileB:®;1211 } ®ForB:®;1212 1213 1214 } ®Compound:®;1206 ... @goto If@; ... // terminate if 1207 } @If:@; 1208 } while ( ... ); @DoB:@ ; 1209 } @WhileB:@ ; 1210 } @ForB:@ ; 1211 1212 1213 } @Compound:@ ; 1215 1214 \end{cfa} 1216 1215 \end{lrbox} … … 1241 1240 1242 1241 1243 %\subsection{\texorpdfstring{\protect\lstinline {with}Statement}{with Statement}}1242 %\subsection{\texorpdfstring{\protect\lstinline@with@ Statement}{with Statement}} 1244 1243 \subsection{\texorpdfstring{\LstKeywordStyle{with} Statement}{with Statement}} 1245 1244 \label{s:WithStatement} … … 1256 1255 \begin{cfa} 1257 1256 Person p 1258 ®p.®name; ®p.®address; ®p.®sex; $\C{// access containing fields}$1257 @p.@name; @p.@address; @p.@sex; $\C{// access containing fields}$ 1259 1258 \end{cfa} 1260 1259 which extends to multiple levels of qualification for nested aggregates and multiple aggregates. 1261 1260 \begin{cfa} 1262 1261 struct Ticket { ... } t; 1263 ®p.name®.first; ®p.address®.street; $\C{// access nested fields}$1264 ®t.®departure; ®t.®cost; $\C{// access multiple aggregate}$1262 @p.name@.first; @p.address@.street; $\C{// access nested fields}$ 1263 @t.@departure; @t.@cost; $\C{// access multiple aggregate}$ 1265 1264 \end{cfa} 1266 1265 Repeated aggregate qualification is tedious and makes code difficult to read. … … 1285 1284 \begin{C++} 1286 1285 struct S { 1287 char ®c®; int ®i®; double ®d®;1286 char @c@; int @i@; double @d@; 1288 1287 void f( /* S * this */ ) { $\C{// implicit ``this'' parameter}$ 1289 ®c®; ®i®; ®d®; $\C{// this->c; this->i; this->d;}$1288 @c@; @i@; @d@; $\C{// this->c; this->i; this->d;}$ 1290 1289 } 1291 1290 } … … 1295 1294 \begin{cfa} 1296 1295 struct T { 1297 char ®m®; int ®i®; double ®n®; $\C{// derived class variables}$1296 char @m@; int @i@; double @n@; $\C{// derived class variables}$ 1298 1297 }; 1299 1298 struct S : public T { 1300 char ®c®; int ®i®; double ®d®; $\C{// class variables}$1301 void g( double ®d®, T & t ) {1302 d; ®t®.m; ®t®.i; ®t®.n; $\C{// function parameter}$1303 c; i; ®this->®d; ®S::®d; $\C{// class S variables}$1304 m; ®T::®i; n; $\C{// class T variables}$1299 char @c@; int @i@; double @d@; $\C{// class variables}$ 1300 void g( double @d@, T & t ) { 1301 d; @t@.m; @t@.i; @t@.n; $\C{// function parameter}$ 1302 c; i; @this->@d; @S::@d; $\C{// class S variables}$ 1303 m; @T::@i; n; $\C{// class T variables}$ 1305 1304 } 1306 1305 }; … … 1312 1311 Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block. 1313 1312 \begin{cfa} 1314 void f( S & this ) ®with ( this )®{ $\C{// with statement}$1315 ®c®; ®i®; ®d®; $\C{// this.c, this.i, this.d}$1313 void f( S & this ) @with ( this )@ { $\C{// with statement}$ 1314 @c@; @i@; @d@; $\C{// this.c, this.i, this.d}$ 1316 1315 } 1317 1316 \end{cfa} 1318 1317 with the generality of opening multiple aggregate-parameters: 1319 1318 \begin{cfa} 1320 void g( S & s, T & t ) ®with ( s, t )®{ $\C{// multiple aggregate parameters}$1321 c; ®s.®i; d; $\C{// s.c, s.i, s.d}$1322 m; ®t.®i; n; $\C{// t.m, t.i, t.n}$1319 void g( S & s, T & t ) @with ( s, t )@ { $\C{// multiple aggregate parameters}$ 1320 c; @s.@i; d; $\C{// s.c, s.i, s.d}$ 1321 m; @t.@i; n; $\C{// t.m, t.i, t.n}$ 1323 1322 } 1324 1323 \end{cfa} … … 1339 1338 The difference between parallel and nesting occurs for fields with the same name and type: 1340 1339 \begin{cfa} 1341 struct Q { int ®i®; int k; int ®m®; } q, w;1342 struct R { int ®i®; int j; double ®m®; } r, w;1340 struct Q { int @i@; int k; int @m@; } q, w; 1341 struct R { int @i@; int j; double @m@; } r, w; 1343 1342 with ( r, q ) { 1344 1343 j + k; $\C{// unambiguous, r.j + q.k}$ … … 1373 1372 \begin{cfa} 1374 1373 void ?{}( S & s, int i ) with ( s ) { $\C{// constructor}$ 1375 ®s.i = i;®j = 3; m = 5.5; $\C{// initialize fields}$1374 @s.i = i;@ j = 3; m = 5.5; $\C{// initialize fields}$ 1376 1375 } 1377 1376 \end{cfa} … … 1386 1385 and implicitly opened \emph{after} a function-body open, to give them higher priority: 1387 1386 \begin{cfa} 1388 void ?{}( S & s, int ®i® ) with ( s ) ®with( $\emph{\R{params}}$ )®{ // syntax not allowed, illustration only1389 s.i = ®i®; j = 3; m = 5.5;1387 void ?{}( S & s, int @i@ ) with ( s ) @with( $\emph{\R{params}}$ )@ { // syntax not allowed, illustration only 1388 s.i = @i@; j = 3; m = 5.5; 1390 1389 } 1391 1390 \end{cfa} … … 1470 1469 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way: 1471 1470 \begin{cfa} 1472 int ®(*®f®())[®5®]®{...}; $\C{// definition}$1473 ... ®(*®f®())[®3®]®+= 1; $\C{// usage}$1471 int @(*@f@())[@5@]@ {...}; $\C{// definition}$ 1472 ... @(*@f@())[@3@]@ += 1; $\C{// usage}$ 1474 1473 \end{cfa} 1475 1474 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). … … 1487 1486 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1488 1487 \begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}] 1489 #[5] *# ®int®x1;1490 #* [5]# ®int®x2;1491 #[* [5] int]# f ®( int p )®;1488 #[5] *# @int@ x1; 1489 #* [5]# @int@ x2; 1490 #[* [5] int]# f@( int p )@; 1492 1491 \end{cfa} 1493 1492 & 1494 1493 \begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}] 1495 ®int®#*# x1 #[5]#;1496 ®int®#(*#x2#)[5]#;1497 #int (*#f ®( int p )®#)[5]#;1494 @int@ #*# x1 #[5]#; 1495 @int@ #(*#x2#)[5]#; 1496 #int (*#f@( int p )@#)[5]#; 1498 1497 \end{cfa} 1499 1498 \end{tabular} … … 1507 1506 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1508 1507 \begin{cfa} 1509 ®*®int x, y;1508 @*@ int x, y; 1510 1509 \end{cfa} 1511 1510 & 1512 1511 \begin{cfa} 1513 int ®*®x, ®*®y;1512 int @*@x, @*@y; 1514 1513 \end{cfa} 1515 1514 \end{tabular} … … 1520 1519 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1521 1520 \begin{cfa} 1522 ®*®int x;1521 @*@ int x; 1523 1522 int y; 1524 1523 \end{cfa} 1525 1524 & 1526 1525 \begin{cfa} 1527 int ®*®x, y;1526 int @*@x, y; 1528 1527 1529 1528 \end{cfa} … … 1661 1660 & 1662 1661 \begin{cfa} 1663 int * ®const®x = (int *)1001662 int * @const@ x = (int *)100 1664 1663 *x = 3; // implicit dereference 1665 int * ®const®y = (int *)104;1664 int * @const@ y = (int *)104; 1666 1665 *y = *x; // implicit dereference 1667 1666 \end{cfa} … … 1701 1700 \begin{tabular}{@{}l@{\hspace{2em}}l@{}} 1702 1701 \begin{cfa} 1703 int x, y, ®*® p1, ®*® p2, ®**®p3;1704 p1 = ®&®x; // p1 points to x1702 int x, y, @*@ p1, @*@ p2, @**@ p3; 1703 p1 = @&@x; // p1 points to x 1705 1704 p2 = p1; // p2 points to x 1706 p1 = ®&®y; // p1 points to y1705 p1 = @&@y; // p1 points to y 1707 1706 p3 = &p2; // p3 points to p2 1708 1707 \end{cfa} … … 1730 1729 \begin{cfa} 1731 1730 p1 = p2; $\C{// pointer address assignment}$ 1732 ®*®p2 = ®*®p1 + x; $\C{// pointed-to value assignment / operation}$1731 @*@p2 = @*@p1 + x; $\C{// pointed-to value assignment / operation}$ 1733 1732 \end{cfa} 1734 1733 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©). … … 1746 1745 To support this common case, a reference type is introduced in \CFA, denoted by ©&©, which is the opposite dereference semantics to a pointer type, making the value at the pointed-to location the implicit semantics for dereferencing (similar but not the same as \CC \Index{reference type}s). 1747 1746 \begin{cfa} 1748 int x, y, ®&® r1, ®&® r2, ®&&®r3;1749 ®&®r1 = &x; $\C{// r1 points to x}$1750 ®&®r2 = &r1; $\C{// r2 points to x}$1751 ®&®r1 = &y; $\C{// r1 points to y}$1752 ®&&®r3 = ®&®&r2; $\C{// r3 points to r2}$1747 int x, y, @&@ r1, @&@ r2, @&&@ r3; 1748 @&@r1 = &x; $\C{// r1 points to x}$ 1749 @&@r2 = &r1; $\C{// r2 points to x}$ 1750 @&@r1 = &y; $\C{// r1 points to y}$ 1751 @&&@r3 = @&@&r2; $\C{// r3 points to r2}$ 1753 1752 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); $\C{// implicit dereferencing}$ 1754 1753 \end{cfa} … … 1757 1756 One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in a declaration, so the previous example becomes: 1758 1757 \begin{cfa} 1759 ®*®r2 = ((®*®r1 + ®*®r2) ®*® (®**®r3 - ®*®r1)) / (®**®r3 - 15);1758 @*@r2 = ((@*@r1 + @*@r2) @*@ (@**@r3 - @*@r1)) / (@**@r3 - 15); 1760 1759 \end{cfa} 1761 1760 When a reference operation appears beside a dereference operation, \eg ©&*©, they cancel out. … … 1766 1765 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}): 1767 1766 \begin{cfa} 1768 (& ®*®)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$1767 (&@*@)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$ 1769 1768 \end{cfa} 1770 1769 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}): 1771 1770 \begin{cfa} 1772 (&(& ®*®)®*®)r3 = &(&®*®)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$1771 (&(&@*@)@*@)r3 = &(&@*@)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$ 1773 1772 \end{cfa} 1774 1773 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth. … … 1793 1792 const int cx = 5; $\C{// cannot change cx;}$ 1794 1793 const int & cr = cx; $\C{// cannot change what cr points to}$ 1795 ®&®cr = &cx; $\C{// can change cr}$1794 @&@cr = &cx; $\C{// can change cr}$ 1796 1795 cr = 7; $\C{// error, cannot change cx}$ 1797 1796 int & const rc = x; $\C{// must be initialized}$ 1798 ®&®rc = &x; $\C{// error, cannot change rc}$1797 @&@rc = &x; $\C{// error, cannot change rc}$ 1799 1798 const int & const crc = cx; $\C{// must be initialized}$ 1800 1799 crc = 7; $\C{// error, cannot change cx}$ 1801 ®&®crc = &cx; $\C{// error, cannot change crc}$1800 @&@crc = &cx; $\C{// error, cannot change crc}$ 1802 1801 \end{cfa} 1803 1802 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}: … … 1820 1819 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1821 1820 \begin{cfa} 1822 ®const® * ®const®* const int ccp;1823 ®const® & ®const®& const int ccr;1821 @const@ * @const@ * const int ccp; 1822 @const@ & @const@ & const int ccr; 1824 1823 \end{cfa} 1825 1824 & 1826 1825 \begin{cfa} 1827 const int * ®const® * ®const®ccp;1826 const int * @const@ * @const@ ccp; 1828 1827 1829 1828 \end{cfa} … … 1857 1856 \begin{cfa} 1858 1857 int * p = &x; $\C{// assign address of x}$ 1859 ®int * p = x;®$\C{// assign value of x}$1858 @int * p = x;@ $\C{// assign value of x}$ 1860 1859 int & r = x; $\C{// must have address of x}$ 1861 1860 \end{cfa} … … 1881 1880 When a pointer/reference parameter has a ©const© value (immutable), it is possible to pass literals and expressions. 1882 1881 \begin{cfa} 1883 void f( ®const®int & cr );1884 void g( ®const®int * cp );1885 f( 3 ); g( ®&®3 );1886 f( x + y ); g( ®&®(x + y) );1882 void f( @const@ int & cr ); 1883 void g( @const@ int * cp ); 1884 f( 3 ); g( @&@3 ); 1885 f( x + y ); g( @&@(x + y) ); 1887 1886 \end{cfa} 1888 1887 Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter. … … 1895 1894 void f( int & r ); 1896 1895 void g( int * p ); 1897 f( 3 ); g( ®&®3 ); $\C{// compiler implicit generates temporaries}$1898 f( x + y ); g( ®&®(x + y) ); $\C{// compiler implicit generates temporaries}$1896 f( 3 ); g( @&@3 ); $\C{// compiler implicit generates temporaries}$ 1897 f( x + y ); g( @&@(x + y) ); $\C{// compiler implicit generates temporaries}$ 1899 1898 \end{cfa} 1900 1899 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{ … … 1917 1916 Instead, a routine object should be referenced by a ©const© reference: 1918 1917 \begin{cfa} 1919 ®const® void (®&®fr)( int ) = f; $\C{// routine reference}$1918 @const@ void (@&@ fr)( int ) = f; $\C{// routine reference}$ 1920 1919 fr = ... $\C{// error, cannot change code}$ 1921 1920 &fr = ...; $\C{// changing routine reference}$ … … 1979 1978 \begin{cfa} 1980 1979 int x, &r = x, f( int p ); 1981 x = ®r® + f( ®r®); $\C{// lvalue reference converts to rvalue}$1980 x = @r@ + f( @r@ ); $\C{// lvalue reference converts to rvalue}$ 1982 1981 \end{cfa} 1983 1982 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped. 1984 1983 1985 1984 \item 1986 lvalue to reference conversion: \lstinline[deletekeywords=lvalue] {lvalue-type cv1 T}converts to ©cv2 T &©, which allows implicitly converting variables to references.1987 \begin{cfa} 1988 int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$1989 f( ®x®); $\C{// lvalue variable (int) convert to reference (int \&)}$1985 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references. 1986 \begin{cfa} 1987 int x, &r = @x@, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$ 1988 f( @x@ ); $\C{// lvalue variable (int) convert to reference (int \&)}$ 1990 1989 \end{cfa} 1991 1990 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost. … … 1997 1996 \begin{cfa} 1998 1997 int x, & f( int & p ); 1999 f( ®x + 3®); $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$2000 ®&f®(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$1998 f( @x + 3@ ); $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$ 1999 @&f@(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$ 2001 2000 \end{cfa} 2002 2001 In both case, modifications to the temporary are inaccessible (\Index{warning}). … … 2165 2164 2166 2165 2167 \section{Enumeration}2168 2169 An \newterm{enumeration} is a compile-time mechanism to alias names to constants, like ©typedef© is a mechanism to alias names to types.2170 Its purpose is to define a restricted-value type providing code-readability and maintenance -- changing an enum's value automatically updates all name usages during compilation.2171 2172 An enumeration type is a set of names, each called an \newterm{enumeration constant} (shortened to \newterm{enum}) aliased to a fixed value (constant).2173 \begin{cfa}2174 enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; // enumeration type definition, set of 7 names & values2175 Days days = Mon; // enumeration type declaration and initialization2176 \end{cfa}2177 The set of enums are injected into the variable namespace at the definition scope.2178 Hence, enums may be overloaded with enum/variable/function names.2179 \begin{cfa}2180 enum Foo { Bar };2181 enum Goo { Bar }; $\C[1.75in]{// overload Foo.Bar}$2182 int Foo; $\C{// type/variable separate namespace}$2183 double Bar; $\C{// overload Foo.Bar, Goo.Bar}\CRT$2184 \end{cfa}2185 An anonymous enumeration injects enums with specific values into a scope.2186 \begin{cfa}2187 enum { Prime = 103, BufferSize = 1024 };2188 \end{cfa}2189 An enumeration is better than using C \Index{preprocessor} or constant declarations.2190 \begin{cquote}2191 \begin{tabular}{@{}l@{\hspace{4em}}l@{}}2192 \begin{cfa}2193 #define Mon 02194 ...2195 #define Sun 62196 \end{cfa}2197 &2198 \begin{cfa}2199 const int Mon = 0,2200 ...,2201 Sun = 6;2202 \end{cfa}2203 \end{tabular}2204 \end{cquote}2205 because the enumeration is succinct, has automatic numbering, can appear in ©case© labels, does not use storage, and is part of the language type-system.2206 Finally, the type of an enum is implicitly or explicitly specified and the constant value can be implicitly or explicitly specified.2207 Note, enum values may be repeated in an enumeration.2208 2209 2210 \subsection{Enum type}2211 2212 The type of enums can be any type, and an enum's value comes from this type.2213 Because an enum is a constant, it cannot appear in a mutable context, \eg ©Mon = Sun© is disallowed, and has no address (it is an rvalue).2214 Therefore, an enum is automatically converted to its constant's base-type, \eg comparing/printing an enum compares/prints its value rather than the enum name;2215 there is no mechanism to print the enum name.2216 2217 The default enum type is ©int©.2218 Hence, ©Days© is the set type ©Mon©, ©Tue©, ...\,, ©Sun©, while the type of each enum is ©int© and each enum represents a fixed integral value.2219 If no values are specified for an integral enum type, the enums are automatically numbered by one from left to right starting at zero.2220 Hence, the value of enum ©Mon© is 0, ©Tue© is 1, ...\,, ©Sun© is 6.2221 If an enum value is specified, numbering continues by one from that value for subsequent unnumbered enums.2222 If an enum value is an expression, the compiler performs constant-folding to obtain a constant value.2223 2224 \CFA allows other integral types with associated values.2225 \begin{cfa}2226 enum( ®char® ) Letter { A ®= 'A'®, B, C, I ®= 'I'®, J, K };2227 enum( ®long long int® ) BigNum { X = 123_456_789_012_345, Y = 345_012_789_456_123 };2228 \end{cfa}2229 For enumeration ©Letter©, enum ©A©'s value is explicitly set to ©'A'©, with ©B© and ©C© implicitly numbered with increasing values from ©'A'©, and similarly for enums ©I©, ©J©, and ©K©.2230 2231 Non-integral enum types must be explicitly initialized, \eg ©double© is not automatically numbered by one.2232 \begin{cfa}2233 // non-integral numeric2234 enum( ®double® ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 }2235 // pointer2236 enum( ®char *® ) Name { Fred = "Fred", Mary = "Mary", Jane = "Jane" };2237 int i, j, k;2238 enum( ®int *® ) ptr { I = &i, J = &j, K = &k };2239 enum( ®int &® ) ref { I = i, J = j, K = k };2240 // tuple2241 enum( ®[int, int]® ) { T = [ 1, 2 ] };2242 // function2243 void f() {...} void g() {...}2244 enum( ®void (*)()® ) funs { F = f, F = g };2245 // aggregate2246 struct S { int i, j; };2247 enum( ®S® ) s { A = { 3, 4 }, B = { 7, 8 } };2248 // enumeration2249 enum( ®Letter® ) Greek { Alph = A, Beta = B, /* more enums */ }; // alphabet intersection2250 \end{cfa}2251 Enumeration ©Greek© may have more or less enums than ©Letter©, but the enum values \emph{must} be from ©Letter©.2252 Therefore, ©Greek© enums are a subset of type ©Letter© and are type compatible with enumeration ©Letter©, but ©Letter© enums are not type compatible with enumeration ©Greek©.2253 2254 The following examples illustrate the difference between the enumeration type and the type of its enums.2255 \begin{cfa}2256 Math m = PI; $\C[1.5in]{// allowed}$2257 double d = PI; $\C{// allowed, conversion to base type}$2258 m = E; $\C{// allowed}$2259 m = Alph; $\C{// {\color{red}disallowed}}$2260 m = 3.141597; $\C{// {\color{red}disallowed}}$2261 d = m; $\C{// allowed}$2262 d = Alph; $\C{// {\color{red}disallowed}}$2263 Letter l = A; $\C{// allowed}$2264 Greek g = Alph; $\C{// allowed}$2265 l = Alph; $\C{// allowed, conversion to base type}$2266 g = A; $\C{// {\color{red}disallowed}}\CRT$2267 \end{cfa}2268 2269 A constructor \emph{cannot} be used to initialize enums because a constructor executes at runtime.2270 A fallback is explicit C-style initialization using ©@=©.2271 \begin{cfa}2272 enum( struct vec3 ) Axis { Up @= { 1, 0, 0 }, Left @= { 0, 1, 0 }, Front @= { 0, 0, 1 } }2273 \end{cfa}2274 Finally, enumeration variables are assignable and comparable only if the appropriate operators are defined for its enum type.2275 2276 2277 \subsection{Inheritance}2278 2279 \Index{Plan-9}\index{inheritance!enumeration} inheritance may be used with enumerations.2280 \begin{cfa}2281 enum( char * ) Name2 { ®inline Name®, Jack = "Jack", Jill = "Jill" };2282 enum ®/* inferred */® Name3 { ®inline Name2®, Sue = "Sue", Tom = "Tom" };2283 \end{cfa}2284 Enumeration ©Name2© inherits all the enums and their values from enumeration ©Name© by containment, and a ©Name© enumeration is a subtype of enumeration ©Name2©.2285 Note, enums must be unique in inheritance but enum values may be repeated.2286 The enum type for the inheriting type must be the same as the inherited type;2287 hence the enum type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for ©Name3©.2288 When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important, \eg the placement of ©Sue© and ©Tom© before or after ©inline Name2©.2289 2290 Specifically, the inheritance relationship for ©Name©s is:2291 \begin{cfa}2292 Name $\(\subseteq\)$ Name2 $\(\subseteq\)$ Name3 $\(\subseteq\)$ const char * // enum type of Name2293 \end{cfa}2294 Hence, given2295 \begin{cfa}2296 void f( Name );2297 void g( Name2 );2298 void h( Name3 );2299 void j( const char * );2300 \end{cfa}2301 the following calls are valid2302 \begin{cfa}2303 f( Fred );2304 g( Fred ); g( Jill );2305 h( Fred ); h( Jill ); h( Sue );2306 j( Fred ); j( Jill ); j( Sue ); j( 'W' );2307 \end{cfa}2308 Note, the validity of calls is the same for call-by-reference as for call-by-value, and ©const© restrictions are the same as for other types.2309 2310 Enums cannot be created at runtime, so inheritence problems, such as contra-variance do not apply.2311 Only instances of the enum base-type may be created at runtime.2312 2313 \begin{comment}2314 The invariance of references, as I show at the bottom, is easy to overlook. Not shown, but on the same topic, is that returns work in the opposite direction as parameters. Hopefully our existing type rules already know both those facts, so that we'd only have to provide the rules that I suggest using the by-value parameters.2315 2316 The Fred, Jack, and Mary declarations are picked verbatim from our earlier whiteboard, just repeated here for reference.2317 2318 \begin{cfa}2319 // Fred is a subset of char *2320 enum( char *) Fred { A = "A", B = "B", C = "C" };2321 // Jack is a subset of Fred2322 enum( enum Fred ) Jack { W = A, Y = C};2323 // Mary is a superset of Fred2324 enum Mary { inline Fred, D = "hello" };2325 2326 // Demonstrating invariance of references2327 2328 [void] frcs( & * char x ) { char * x0 = x; x = "bye"; }2329 [void] frf ( & Fred x ) { Fred x0 = x; x = B; }2330 [void] frj ( & Jack x ) { Jack x0 = x; x = W; }2331 [void] frm ( & Mary x ) { Mary x0 = x; x = D; }2332 2333 char * vcs;2334 Fred vf;2335 Jack vj;2336 Mary vm;2337 2338 // all variant calls: bad (here are noteworthy examples)2339 frcs( vf ); // can't assign "bye" to vf2340 frm ( vf ); // can't assign D to vf2341 frf ( vj ); // can't assign B to vj2342 vf = B ; frj ( vf ); // can't assign B to frj.x02343 vcs = "bye"; frf ( vcs ); // can't assign "bye" to frf.x02344 \end{cfa}2345 2346 This example is really great. However, I think it's work explicitly doing one with ©const &©.2347 \end{comment}2348 2349 2350 2166 \section{Routine Definition} 2351 2167 2352 \CFA supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.2168 \CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax. 2353 2169 The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg: 2354 2170 \begin{cfa} 2355 ®[ int o1, int o2, char o3 ]®f( int i1, char i2, char i3 ) {2171 @[ int o1, int o2, char o3 ]@ f( int i1, char i2, char i3 ) { 2356 2172 $\emph{routine body}$ 2357 2173 } 2358 2174 \end{cfa} 2359 2175 where routine ©f© has three output (return values) and three input parameters. 2360 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type -specifications.2176 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type specifications. 2361 2177 2362 2178 In detail, the brackets, ©[]©, enclose the result type, where each return value is named and that name is a local variable of the particular return type.\footnote{ … … 2365 2181 Declaration qualifiers can only appear at the start of a routine definition, \eg: 2366 2182 \begin{cfa} 2367 ®extern®[ int x ] g( int y ) {$\,$}2183 @extern@ [ int x ] g( int y ) {$\,$} 2368 2184 \end{cfa} 2369 2185 Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified; … … 2384 2200 int (*f(x))[ 5 ] int x; {} 2385 2201 \end{cfa} 2386 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x©of type array of 5 integers.2202 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter x of type array of 5 integers. 2387 2203 Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string. 2388 2204 As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity: … … 2423 2239 \begin{minipage}{\linewidth} 2424 2240 \begin{cfa} 2425 ®[ int x, int y ]®f() {2241 @[ int x, int y ]@ f() { 2426 2242 int z; 2427 2243 ... x = 0; ... y = z; ... 2428 ®return;®$\C{// implicitly return x, y}$2244 @return;@ $\C{// implicitly return x, y}$ 2429 2245 } 2430 2246 \end{cfa} … … 2758 2574 2759 2575 int fred() { 2760 s.t.c = ®S.®R; // type qualification2761 struct ®S.®T t = { ®S.®R, 1, 2 };2762 enum ®S.®C c;2763 union ®S.T.®U u;2576 s.t.c = @S.@R; // type qualification 2577 struct @S.@T t = { @S.@R, 1, 2 }; 2578 enum @S.@C c; 2579 union @S.T.@U u; 2764 2580 } 2765 2581 \end{cfa} … … 2787 2603 qsort( ia, size ); $\C{// sort ascending order using builtin ?<?}$ 2788 2604 { 2789 ®int ?<?( int x, int y ) { return x > y; }®$\C{// nested routine}$2605 @int ?<?( int x, int y ) { return x > y; }@ $\C{// nested routine}$ 2790 2606 qsort( ia, size ); $\C{// sort descending order by local redefinition}$ 2791 2607 } … … 2797 2613 \begin{cfa} 2798 2614 [* [int]( int )] foo() { $\C{// int (* foo())( int )}$ 2799 int ®i®= 7;2615 int @i@ = 7; 2800 2616 int bar( int p ) { 2801 ®i®+= 1; $\C{// dependent on local variable}$2802 sout | ®i®;2617 @i@ += 1; $\C{// dependent on local variable}$ 2618 sout | @i@; 2803 2619 } 2804 2620 return bar; $\C{// undefined because of local dependence}$ … … 2818 2634 In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call. 2819 2635 \begin{cfa} 2820 f( ®2, x, 3 + i®); $\C{// element list}$2636 f( @2, x, 3 + i@ ); $\C{// element list}$ 2821 2637 \end{cfa} 2822 2638 A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}. … … 2931 2747 In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}. 2932 2748 \begin{cfa} 2933 [int, int] ®qr®= div( 13, 5 ); $\C{// initialize tuple variable}$2934 printf( "%d %d\n", ®qr®); $\C{// print quotient/remainder}$2749 [int, int] @qr@ = div( 13, 5 ); $\C{// initialize tuple variable}$ 2750 printf( "%d %d\n", @qr@ ); $\C{// print quotient/remainder}$ 2935 2751 \end{cfa} 2936 2752 It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}. … … 3596 3412 \begin{cfa} 3597 3413 int x = 1, y = 2, z = 3; 3598 sout | x ®|® y ®|®z;3414 sout | x @|@ y @|@ z; 3599 3415 \end{cfa} 3600 3416 & 3601 3417 \begin{cfa} 3602 3418 3603 cout << x ®<< " "® << y ®<< " "®<< z << endl;3419 cout << x @<< " "@ << y @<< " "@ << z << endl; 3604 3420 \end{cfa} 3605 3421 & … … 3610 3426 \\ 3611 3427 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3612 1 ® ®2® ®33428 1@ @2@ @3 3613 3429 \end{cfa} 3614 3430 & 3615 3431 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3616 1 ® ®2® ®33432 1@ @2@ @3 3617 3433 \end{cfa} 3618 3434 & 3619 3435 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3620 1 ® ®2® ®33436 1@ @2@ @3 3621 3437 \end{cfa} 3622 3438 \end{tabular} 3623 3439 \end{cquote} 3624 3440 The \CFA form has half the characters of the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators and newline. 3625 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true] {, }''.3441 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]@, @''. 3626 3442 \begin{cfa} 3627 3443 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ]; … … 3629 3445 \end{cfa} 3630 3446 \begin{cfa}[showspaces=true,aboveskip=0pt] 3631 1 ®, ®2®, ®3 4®, ®5®, ®63447 1@, @2@, @3 4@, @5@, @6 3632 3448 \end{cfa} 3633 3449 Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority \emph{overloadable} operator, other than assignment. … … 3638 3454 & 3639 3455 \begin{cfa} 3640 sout | x * 3 | y + 1 | z << 2 | x == y | ®(®x | y®)® | ®(®x || y®)® | ®(®x > z ? 1 : 2®)®;3456 sout | x * 3 | y + 1 | z << 2 | x == y | @(@x | y@)@ | @(@x || y@)@ | @(@x > z ? 1 : 2@)@; 3641 3457 \end{cfa} 3642 3458 \\ … … 3644 3460 & 3645 3461 \begin{cfa} 3646 cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << ®(®x | y®)® << ®(®x || y®)® << ®(®x > z ? 1 : 2®)®<< endl;3462 cout << x * 3 << y + 1 << @(@z << 2@)@ << @(@x == y@)@ << @(@x | y@)@ << @(@x || y@)@ << @(@x > z ? 1 : 2@)@ << endl; 3647 3463 \end{cfa} 3648 3464 \\ … … 3679 3495 \\ 3680 3496 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3681 ®1® ®2.5® ®A® 3497 @1@ @2.5@ @A@ 3682 3498 3683 3499 … … 3685 3501 & 3686 3502 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3687 ®1® ®2.5® ®A® 3503 @1@ @2.5@ @A@ 3688 3504 3689 3505 … … 3691 3507 & 3692 3508 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3693 ®1® 3694 ®2.5® 3695 ®A® 3509 @1@ 3510 @2.5@ 3511 @A@ 3696 3512 \end{cfa} 3697 3513 \end{tabular} … … 3729 3545 3730 3546 \item 3731 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} isa closing citation mark.3547 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} a closing citation mark. 3732 3548 \begin{cfa} 3733 3549 sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x" … … 3735 3551 \end{cfa} 3736 3552 \begin{cfa}[showspaces=true] 3737 1 ®,® x 2®.® x 3®;® x 4®!® x 5®?® x 6®%® x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9®)® x 10®]® x 11®}®x3553 1@,@ x 2@.@ x 3@;@ x 4@!@ x 5@?@ x 6@%@ x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9@)@ x 10@]@ x 11@}@ x 3738 3554 \end{cfa} 3739 3555 … … 3742 3558 %$ 3743 3559 \begin{cfa} 3744 sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $ \LstStringStyle{\textdollar}$" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$"3560 sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$" 3745 3561 | 7 | "x $\LstStringStyle{\textexclamdown}$" | 8 | "x $\LstStringStyle{\textquestiondown}$" | 9 | "x $\LstStringStyle{\guillemotleft}$" | 10; 3746 3562 \end{cfa} 3747 3563 %$ 3748 3564 \begin{cfa}[showspaces=true] 3749 x ®(®1 x ®[®2 x ®{®3 x ®=®4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$103565 x @(@1 x @[@2 x @{@3 x @=@4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$10 3750 3566 \end{cfa} 3751 3567 %$ 3752 3568 3753 3569 \item 3754 A sep arator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n}3570 A seperator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n} 3755 3571 \begin{cfa} 3756 3572 sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx"; 3757 3573 \end{cfa} 3758 3574 \begin{cfa}[showspaces=true,showtabs=true] 3759 x ®`®1®`®x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x®:®4®:®x® ®5® ®x® ®6® ®x3575 x@`@1@`@x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x@:@4@:@x@ @5@ @x@ @6@ @x 3760 3576 \end{cfa} 3761 3577 … … 3766 3582 \end{cfa} 3767 3583 \begin{cfa}[showspaces=true,showtabs=true] 3768 x ( ® ®1® ®) x 2® ®, x 3® ®:x:® ®43584 x (@ @1@ @) x 2@ @, x 3@ @:x:@ @4 3769 3585 \end{cfa} 3770 3586 \end{enumerate} … … 3779 3595 \Indexc{sepSet}\index{manipulator!sepSet@©sepSet©} and \Indexc{sep}\index{manipulator!sep@©sep©}/\Indexc{sepGet}\index{manipulator!sepGet@©sepGet©} set and get the separator string. 3780 3596 The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters). 3781 \begin{cfa}[belowskip=0pt] 3782 sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); $\C{// set separator from " " to ", \$"}$ 3783 sout | 1 | 2 | 3 | " \"" | ®sep® | "\""; 3784 \end{cfa} 3785 \begin{cfa}[showspaces=true,aboveskip=0pt] 3786 1®, $\LstStringStyle{\textdollar}$®2®, $\LstStringStyle{\textdollar}$®3 ®", $\LstStringStyle{\textdollar}$"® 3787 \end{cfa} 3597 \begin{cfa}[escapechar=off,belowskip=0pt] 3598 sepSet( sout, ", $" ); $\C{// set separator from " " to ", \$"}$ 3599 sout | 1 | 2 | 3 | " \"" | @sep@ | "\""; 3600 \end{cfa} 3601 %$ 3602 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt] 3603 1@, $@2@, $@3 @", $"@ 3604 \end{cfa} 3605 %$ 3788 3606 \begin{cfa}[belowskip=0pt] 3789 3607 sepSet( sout, " " ); $\C{// reset separator to " "}$ 3790 sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )®| "\"";3608 sout | 1 | 2 | 3 | " \"" | @sepGet( sout )@ | "\""; 3791 3609 \end{cfa} 3792 3610 \begin{cfa}[showspaces=true,aboveskip=0pt] 3793 1 ® ®2® ®3 ®" "®3611 1@ @2@ @3 @" "@ 3794 3612 \end{cfa} 3795 3613 ©sepGet© can be used to store a separator and then restore it: 3796 3614 \begin{cfa}[belowskip=0pt] 3797 char store[ ®sepSize®]; $\C{// sepSize is the maximum separator size}$3615 char store[@sepSize@]; $\C{// sepSize is the maximum separator size}$ 3798 3616 strcpy( store, sepGet( sout ) ); $\C{// copy current separator}$ 3799 3617 sepSet( sout, "_" ); $\C{// change separator to underscore}$ … … 3801 3619 \end{cfa} 3802 3620 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3803 1 ®_®2®_®33621 1@_@2@_@3 3804 3622 \end{cfa} 3805 3623 \begin{cfa}[belowskip=0pt] … … 3808 3626 \end{cfa} 3809 3627 \begin{cfa}[showspaces=true,aboveskip=0pt] 3810 1 ® ®2® ®33628 1@ @2@ @3 3811 3629 \end{cfa} 3812 3630 … … 3816 3634 \begin{cfa}[belowskip=0pt] 3817 3635 sepSetTuple( sout, " " ); $\C{// set tuple separator from ", " to " "}$ 3818 sout | t1 | t2 | " \"" | ®sepTuple®| "\"";3636 sout | t1 | t2 | " \"" | @sepTuple@ | "\""; 3819 3637 \end{cfa} 3820 3638 \begin{cfa}[showspaces=true,aboveskip=0pt] 3821 1 2 3 4 5 6 ®" "®3639 1 2 3 4 5 6 @" "@ 3822 3640 \end{cfa} 3823 3641 \begin{cfa}[belowskip=0pt] 3824 3642 sepSetTuple( sout, ", " ); $\C{// reset tuple separator to ", "}$ 3825 sout | t1 | t2 | " \"" | ®sepGetTuple( sout )®| "\"";3643 sout | t1 | t2 | " \"" | @sepGetTuple( sout )@ | "\""; 3826 3644 \end{cfa} 3827 3645 \begin{cfa}[showspaces=true,aboveskip=0pt] 3828 1, 2, 3 4, 5, 6 ®", "®3646 1, 2, 3 4, 5, 6 @", "@ 3829 3647 \end{cfa} 3830 3648 As for ©sepGet©, ©sepGetTuple© can be use to store a tuple separator and then restore it. … … 3878 3696 \end{cfa} 3879 3697 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3880 ® ®1 2 3® ® 3698 @ @1 2 3@ @ 3881 3699 \end{cfa} 3882 3700 \end{enumerate} … … 3898 3716 For example, in: 3899 3717 \begin{cfa} 3900 sin | i | ®nl®| j;3901 1 ®2®3718 sin | i | @nl@ | j; 3719 1 @2@ 3902 3720 3 3903 3721 \end{cfa} … … 3940 3758 0b0 0b11011 0b11011 0b11011 0b11011 3941 3759 sout | bin( -27HH ) | bin( -27H ) | bin( -27 ) | bin( -27L ); 3942 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b ®(58 1s)®1001013760 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b@(58 1s)@100101 3943 3761 \end{cfa} 3944 3762 … … 3976 3794 3977 3795 \item 3978 \Indexc{eng}( floating-point )\index{manipulator!eng@©eng©} print value in engineering notation with exponent, which means the exponent is adjusted to a multiple of 3.3979 \begin{cfa}[belowskip=0pt]3980 sout | eng( 0.0 ) | eng( 27000.5 ) | eng( -27.5e7 );3981 0®e0® 27.0005®e3® -275®e6®3982 \end{cfa}3983 3984 \item3985 \Indexc{unit}( engineering-notation )\index{manipulator!unit@©unit©} print engineering exponent as a letter between the range $10^{-24}$ and $10^{24}$:3986 ©y© $\Rightarrow 10^{-24}$, ©z© $\Rightarrow 10^{-21}$, ©a© $\Rightarrow 10^{-18}$, ©f© $\Rightarrow 10^{-15}$, ©p© $\Rightarrow 10^{-12}$, ©n© $\Rightarrow 10^{-9}$, ©u© $\Rightarrow 10^{-6}$, ©m© $\Rightarrow 10^{-3}$, ©K© $\Rightarrow 10^{3}$, ©M© $\Rightarrow 10^{6}$, ©G© $\Rightarrow 10^{9}$, ©T© $\Rightarrow 10^{12}$, ©P© $\Rightarrow 10^{15}$, ©E© $\Rightarrow 10^{18}$, ©Z© $\Rightarrow 10^{21}$, ©Y© $\Rightarrow 10^{24}$.3987 For exponent $10^{0}$, no decimal point or letter is printed.3988 \begin{cfa}[belowskip=0pt]3989 sout | unit(eng( 0.0 )) | unit(eng( 27000.5 )) | unit(eng( -27.5e7 ));3990 0 27.0005®K® -275®M®3991 \end{cfa}3992 3993 \item3994 3796 \Indexc{upcase}( bin / hex / floating-point )\index{manipulator!upcase@©upcase©} print letters in a value in upper case. Lower case is the default. 3995 3797 \begin{cfa}[belowskip=0pt] 3996 3798 sout | upcase( bin( 27 ) ) | upcase( hex( 27 ) ) | upcase( 27.5e-10 ) | upcase( hex( 27.5 ) ); 3997 0 ®B®11011 0®X®1®B® 2.75®E®-09 0®X®1.®B®8®P®+43799 0@B@11011 0@X@1@B@ 2.75@E@-09 0@X@1.@B@8@P@+4 3998 3800 \end{cfa} 3999 3801 … … 4011 3813 \begin{cfa}[belowskip=0pt] 4012 3814 sout | 0. | nodp( 0. ) | 27.0 | nodp( 27.0 ) | nodp( 27.5 ); 4013 0.0 ®0® 27.0 ®27®27.53815 0.0 @0@ 27.0 @27@ 27.5 4014 3816 \end{cfa} 4015 3817 … … 4018 3820 \begin{cfa}[belowskip=0pt] 4019 3821 sout | sign( 27 ) | sign( -27 ) | sign( 27. ) | sign( -27. ) | sign( 27.5 ) | sign( -27.5 ); 4020 ®+®27 -27 ®+®27.0 -27.0 ®+®27.5 -27.54021 \end{cfa} 4022 4023 \item 4024 \Indexc{wd} ( minimum, value )\index{manipulator!wd@©wd©}, ©wd©( minimum, precision, value )4025 For all types, minimum is thenumber of printed characters.3822 @+@27 -27 @+@27.0 -27.0 @+@27.5 -27.5 3823 \end{cfa} 3824 3825 \item 3826 \Indexc{wd}©( unsigned char minimum, T val )©\index{manipulator!wd@©wd©}, ©wd( unsigned char minimum, unsigned char precision, T val )© 3827 For all types, ©minimum© is the minimum number of printed characters. 4026 3828 If the value is shorter than the minimum, it is padded on the right with spaces. 4027 3829 \begin{cfa}[belowskip=0pt] … … 4031 3833 \end{cfa} 4032 3834 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4033 ® ®34 ® ®34 344034 ® ®4.000000 ® ®4.000000 4.0000004035 ® ®ab ® ®ab ab4036 \end{cfa} 4037 If the value is larger, it is printed without truncation, ignoring the minimum.3835 @ @34 @ @34 34 3836 @ @4.000000 @ @4.000000 4.000000 3837 @ @ab @ @ab ab 3838 \end{cfa} 3839 If the value is larger, it is printed without truncation, ignoring the ©minimum©. 4038 3840 \begin{cfa}[belowskip=0pt] 4039 3841 sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 ); … … 4042 3844 \end{cfa} 4043 3845 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4044 3456 ®7® 345®67® 34®567®4045 3456 ®.® 345®6.® 34®56.®4046 abcd ®e® abc®de® ab®cde®4047 \end{cfa} 4048 4049 For integer types, precisionis the minimum number of printed digits.3846 3456@7@ 345@67@ 34@567@ 3847 3456@.@ 345@6.@ 34@56.@ 3848 abcd@e@ abc@de@ ab@cde@ 3849 \end{cfa} 3850 3851 For integer types, ©precision© is the minimum number of printed digits. 4050 3852 If the value is shorter, it is padded on the left with leading zeros. 4051 3853 \begin{cfa}[belowskip=0pt] … … 4053 3855 \end{cfa} 4054 3856 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4055 ®0®34 ®00®34 ®00000000®344056 \end{cfa} 4057 If the value is larger, it is printed without truncation, ignoring the precision.3857 @0@34 @00@34 @00000000@34 3858 \end{cfa} 3859 If the value is larger, it is printed without truncation, ignoring the ©precision©. 4058 3860 \begin{cfa}[belowskip=0pt] 4059 3861 sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 ); … … 4062 3864 3456 3456 3456 4063 3865 \end{cfa} 4064 If precisionis 0, nothing is printed for zero.4065 If precisionis greater than the minimum, it becomes the minimum.3866 If ©precision© is 0, nothing is printed for zero. 3867 If ©precision© is greater than the minimum, it becomes the minimum. 4066 3868 \begin{cfa}[belowskip=0pt] 4067 3869 sout | wd( 4,0, 0 ) | wd( 3,10, 34 ); 4068 3870 \end{cfa} 4069 3871 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4070 ® ® ®00000000®344071 \end{cfa} 4072 For floating-point types, precisionis the minimum number of digits after the decimal point.3872 @ @ @00000000@34 3873 \end{cfa} 3874 For floating-point types, ©precision© is the minimum number of digits after the decimal point. 4073 3875 \begin{cfa}[belowskip=0pt] 4074 3876 sout | wd( 6,3, 27.5 ) | wd( 8,1, 27.5 ) | wd( 8,0, 27.5 ) | wd( 3,8, 27.5 ); 4075 3877 \end{cfa} 4076 3878 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4077 27. ®500® 27.®5® 28. 27.®50000000®4078 \end{cfa} 4079 For the C-string type, precisionis the maximum number of printed characters, so the string is truncated if it exceeds the maximum.3879 27.@500@ 27.@5@ 28. 27.@50000000@ 3880 \end{cfa} 3881 For the C-string type, ©precision© is the maximum number of printed characters, so the string is truncated if it exceeds the maximum. 4080 3882 \begin{cfa}[belowskip=0pt] 4081 3883 sout | wd( 6,8, "abcd" ) | wd( 6,8, "abcdefghijk" ) | wd( 6,3, "abcd" ); … … 4086 3888 4087 3889 \item 4088 \begin{sloppypar} 4089 \Indexc{ws}( minimum, significant, floating-point )\index{manipulator!ws@©ws©} 4090 For floating-point types, minimum is the same as for manipulator ©wd©, but significant is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©). 4091 If a value's significant digits is greater than significant, the last significant digit is rounded up. 4092 \end{sloppypar} 3890 \Indexc{ws( unsigned char minimum, unsigned char significant, floating-point )}\index{manipulator!ws@©ws©} 3891 For floating-point type, ©minimum© is the same as for manipulator ©wd©, but ©significant© is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©). 3892 If a value's significant digits is greater than ©significant©, the last significant digit is rounded up. 4093 3893 \begin{cfa}[belowskip=0pt] 4094 3894 sout | ws(6,6, 234.567) | ws(6,5, 234.567) | ws(6,4, 234.567) | ws(6,3, 234.567); 4095 3895 \end{cfa} 4096 3896 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4097 234.567 234.5 ®7® 234.®6® 23®5®4098 \end{cfa} 4099 If a value's magnitude is greater than significant, the value is printed in scientific notation with the specified number of significant digits.3897 234.567 234.5@7@ 234.@6@ 23@5@ 3898 \end{cfa} 3899 If a value's magnitude is greater than ©significant©, the value is printed in scientific notation with the specified number of significant digits. 4100 3900 \begin{cfa}[belowskip=0pt] 4101 3901 sout | ws(6,6, 234567.) | ws(6,5, 234567.) | ws(6,4, 234567.) | ws(6,3, 234567.); 4102 3902 \end{cfa} 4103 3903 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4104 234567. 2.3457 ®e+05® 2.346®e+05® 2.35®e+05®4105 \end{cfa} 4106 If significant is greater than minimum, it defines the number of printed characters.3904 234567. 2.3457@e+05@ 2.346@e+05@ 2.35@e+05@ 3905 \end{cfa} 3906 If ©significant© is greater than ©minimum©, it defines the number of printed characters. 4107 3907 \begin{cfa}[belowskip=0pt] 4108 3908 sout | ws(3,6, 234567.) | ws(4,6, 234567.) | ws(5,6, 234567.) | ws(6,6, 234567.); … … 4118 3918 \end{cfa} 4119 3919 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4120 27 ® ® 27.000000 27.500000 027 27.500® ®3920 27@ @ 27.000000 27.500000 027 27.500@ @ 4121 3921 \end{cfa} 4122 3922 … … 4125 3925 \begin{cfa}[belowskip=0pt] 4126 3926 sout | pad0( wd( 4, 27 ) ) | pad0( wd( 4,3, 27 ) ) | pad0( wd( 8,3, 27.5 ) ); 4127 ®00®27 ®0®27 ®00®27.5003927 @00@27 @0@27 @00@27.500 4128 3928 \end{cfa} 4129 3929 \end{enumerate} … … 4189 3989 4190 3990 The format of numeric input values in the same as C constants without a trailing type suffix, as the input value-type is denoted by the input variable. 4191 For © bool© type, the constants are ©true© and ©false©.3991 For ©_Bool© type, the constants are ©true© and ©false©. 4192 3992 For integral types, any number of digits, optionally preceded by a sign (©+© or ©-©), where a 4193 3993 \begin{itemize} … … 4210 4010 \begin{enumerate} 4211 4011 \item 4212 \Indexc{skip}( pattern )\index{manipulator!skip@©skip©}, ©skip©( length ) 4213 The pattern is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character. 4214 The length is composed of the next $N$ characters, including the newline character. 4012 \Indexc{skip( const char * pattern )}\index{manipulator!skip@©skip©} / ©skip( unsigned int length )© / ©const char * pattern© 4013 The argument defines a ©pattern© or ©length©. 4014 The ©pattern© is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character. 4015 The ©length© is composed of the next $N$ characters, including the newline character. 4215 4016 If the match successes, the input characters are discarded, and input continues with the next character. 4216 4017 If the match fails, the input characters are left unread. … … 4220 4021 \end{cfa} 4221 4022 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4222 ®abc ® 4223 ®abc ® 4224 ®xx® 4225 \end{cfa} 4226 4227 \item 4228 \Indexc{wdi} ( maximum, reference-value )\index{manipulator!wdi@©wdi©}4229 For all types except ©char©, maximumis the maximum number of characters read for the current operation.4023 @abc @ 4024 @abc @ 4025 @xx@ 4026 \end{cfa} 4027 4028 \item 4029 \Indexc{wdi}©( unsigned int maximum, T & val )©\index{manipulator!wdi@©wdi©} 4030 For all types except ©char©, ©maximum© is the maximum number of characters read for the current operation. 4230 4031 \begin{cfa}[belowskip=0pt] 4231 4032 char s[10]; int i; double d; … … 4233 4034 \end{cfa} 4234 4035 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4235 ®abcd1233.456E+2® 4036 @abcd1233.456E+2@ 4236 4037 \end{cfa} 4237 4038 Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types. … … 4239 4040 4240 4041 \item 4241 \Indexc{ignore }( reference-value )\index{manipulator!ignore@©ignore©}4042 \Indexc{ignore( T & val )}\index{manipulator!ignore@©ignore©} 4242 4043 For all types, the data is read from the stream depending on the argument type but ignored, \ie it is not stored in the argument. 4243 4044 \begin{cfa}[belowskip=0pt] … … 4246 4047 \end{cfa} 4247 4048 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4248 ® -75.35e-4®254249 \end{cfa} 4250 4251 \item 4252 \Indexc{incl }( scanset, input-string )\index{manipulator!incl@©incl©}4253 For C-string types, the scanset matches any number of characters \emph{in} the set.4254 Matching characters are read into the C input-string and null terminated.4049 @ -75.35e-4@ 25 4050 \end{cfa} 4051 4052 \item 4053 \Indexc{incl( const char * scanset, char * s )}\index{manipulator!incl@©incl©} 4054 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{in} the set. 4055 Matching characters are read into the C string and null terminated. 4255 4056 \begin{cfa}[belowskip=0pt] 4256 4057 char s[10]; … … 4258 4059 \end{cfa} 4259 4060 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4260 ®bca®xyz4261 \end{cfa} 4262 4263 \item 4264 \Indexc{excl }( scanset, input-string )\index{manipulator!excl@©excl©}4265 For C-string types, the scanset matches any number of characters \emph{not in} the set.4266 Non-matching characters are read into the C input-string and null terminated.4061 @bca@xyz 4062 \end{cfa} 4063 4064 \item 4065 \Indexc{excl( const char * scanset, char * s )}\index{manipulator!excl@©excl©} 4066 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{not in} the set. 4067 Non-matching characters are read into the C string and null terminated. 4267 4068 \begin{cfa}[belowskip=0pt] 4268 4069 char s[10]; … … 4270 4071 \end{cfa} 4271 4072 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4272 ®xyz®bca4073 @xyz@bca 4273 4074 \end{cfa} 4274 4075 \end{enumerate} 4275 4076 4276 4077 4277 \subsection{Concurrent Stream Access}4278 4279 When a stream is shared by multiple threads, input or output characters can be intermixed or cause failure.4280 For example, if two threads execute the following:4281 \begin{cfa}4282 $\emph{thread\(_1\)}$ : sout | "abc " | "def ";4283 $\emph{thread\(_2\)}$ : sout | "uvw " | "xyz ";4284 \end{cfa}4285 possible outputs are:4286 \begin{cquote}4287 \begin{tabular}{@{}l|l|l|l|l@{}}4288 \begin{cfa}4289 abc def4290 uvw xyz4291 \end{cfa}4292 &4293 \begin{cfa}4294 abc uvw xyz4295 def4296 \end{cfa}4297 &4298 \begin{cfa}4299 uvw abc xyz def4300 4301 \end{cfa}4302 &4303 \begin{cfa}4304 abuvwc dexf4305 yz4306 \end{cfa}4307 &4308 \begin{cfa}4309 uvw abc def4310 xyz4311 \end{cfa}4312 \end{tabular}4313 \end{cquote}4314 Concurrent operations can even corrupt the internal state of the stream resulting in failure.4315 As a result, some form of mutual exclusion is required for concurrent stream access.4316 4317 A coarse-grained solution is to perform all stream operations via a single thread or within a monitor providing the necessary mutual exclusion for the stream.4318 A fine-grained solution is to have a lock for each stream, which is acquired and released around stream operations by each thread.4319 \CFA provides a fine-grained solution where a \Index{recursive lock} is acquired and released indirectly via a manipulator ©acquire© or instantiating an \Index{RAII} type specific for the kind of stream: ©osacquire©\index{ostream@©ostream©!osacquire@©osacquire©} for output streams and ©isacquire©\index{isacquire@©isacquire©}\index{istream@©istream©!isacquire@©isacquire©} for input streams.4320 4321 The common usage is manipulator ©acquire©\index{ostream@©ostream©!acquire@©acquire©} to lock a stream during a single cascaded I/O expression, with the manipulator appearing as the first item in a cascade list, \eg:4322 \begin{cfa}4323 $\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def "; // manipulator4324 $\emph{thread\(_2\)}$ : sout | ®acquire® | "uvw " | "xyz ";4325 \end{cfa}4326 Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order.4327 \begin{cquote}4328 \def\VRfont{\fontfamily{pcr}\upshape\selectfont}4329 \begin{tabular}{@{}l|l@{}}4330 \begin{cfa}4331 abc def4332 uvw xyz4333 \end{cfa}4334 &4335 \begin{cfa}4336 uvw xyz4337 abc def4338 \end{cfa}4339 \end{tabular}4340 \end{cquote}4341 In summary, the stream lock is acquired by the ©acquire© manipulator and implicitly released at the end of the cascaded I/O expression ensuring all operations in the expression occur atomically.4342 4343 To lock a stream across multiple I/O operations, an object of type ©osacquire© or ©isacquire© is declared to implicitly acquire/release the stream lock providing mutual exclusion for the object's duration, \eg:4344 \begin{cfa}4345 { // acquire sout for block duration4346 ®osacquire® acq = { sout }; $\C{// named stream locker}$4347 sout | 1;4348 sout | ®acquire® | 2 | 3; $\C{// unnecessary, but ok to acquire and release again}$4349 sout | 4;4350 } // implicitly release the lock when "acq" is deallocated4351 \end{cfa}4352 Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread.4353 Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}.4354 4355 The previous values written by threads 1 and 2 can be read in concurrently:4356 \begin{cfa}4357 { // acquire sin lock for block duration4358 ®isacquire acq = { sin };® $\C{// named stream locker}$4359 int x, y, z, w;4360 sin | x;4361 sin | ®acquire® | y | z; $\C{// unnecessary, but ok to acquire and release again}$4362 sin | w;4363 } // implicitly release the lock when "acq" is deallocated4364 \end{cfa}4365 Again, the order of the reading threads is non-deterministic.4366 Note, non-deterministic reading is rare.4367 4368 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:4369 \begin{cfa}4370 sout | ®acquire® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$4371 \end{cfa}4372 If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it.4373 This scenario can lead to \Index{deadlock}, if the thread that is going to unblock the thread waiting in the monitor first writes to ©sout© (deadly embrace).4374 To prevent nested locking, a simple precaution is to factor out the blocking call from the expression, \eg:4375 \begin{cfa}4376 int ®data® = rtn( mon );4377 sout | acquire | "data:" | ®data®;4378 \end{cfa}4379 4380 \Textbf{WARNING:} ©printf©\index{printf@©printf©}, ©scanf©\index{scanf@©scanf©} and their derivatives are unsafe when used with user-level threading, as in \CFA.4381 These stream routines use kernel-thread locking (©futex©\index{futex@©futex©}), which block kernel threads, to prevent interleaving of I/O.4382 However, the following simple example illustrates how a deadlock can occur (other complex scenarios are possible).4383 Assume a single kernel thread and two user-level threads calling ©printf©.4384 One user-level thread acquires the I/O lock and is time-sliced while performing ©printf©.4385 The other user-level thread then starts execution, calls ©printf©, and blocks the only kernel thread because it cannot acquire the I/O lock.4386 It does not help if the kernel lock is multiple acquisition, \ie, the lock owner can acquire it multiple times, because it then results in two user threads in the ©printf© critical section, corrupting the stream.4387 4388 4389 \begin{comment}4390 4078 \section{Types} 4391 4079 … … 4466 4154 process((int) s); // type is converted, no function is called 4467 4155 \end{cfa} 4468 \end{comment}4469 4156 4470 4157 … … 4600 4287 In C, the integer constants 0 and 1 suffice because the integer promotion rules can convert them to any arithmetic type, and the rules for pointer expressions treat constant expressions evaluating to 0 as a special case. 4601 4288 However, user-defined arithmetic types often need the equivalent of a 1 or 0 for their functions or operators, polymorphic functions often need 0 and 1 constants of a type matching their polymorphic parameters, and user-defined pointer-like types may need a null value. 4602 Defining special constants for a user-defined type is more efficient than defining a conversion to the type from © bool©.4289 Defining special constants for a user-defined type is more efficient than defining a conversion to the type from ©_Bool©. 4603 4290 4604 4291 Why just 0 and 1? Why not other integers? No other integers have special status in C. … … 4682 4369 \begin{table}[hbt] 4683 4370 \centering 4684 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} 4685 \begin{tabular}{@{}ll@{}} 4686 ©?[?]© & subscripting \impl{?[?]} \\ 4687 ©?()© & function call \impl{?()} \\ 4688 ©?++© & postfix increment \impl{?++} \\ 4689 ©?--© & postfix decrement \impl{?--} \\ 4690 ©++?© & prefix increment \impl{++?} \\ 4691 ©--?© & prefix decrement \impl{--?} \\ 4692 ©*?© & dereference \impl{*?} \\ 4693 ©+?© & unary plus \impl{+?} \\ 4694 ©-?© & arithmetic negation \impl{-?} \\ 4695 ©~?© & bitwise negation \impl{~?} \\ 4696 ©!?© & logical complement \impl{"!?} \\ 4697 ©?\?© & exponentiation \impl{?\?} \\ 4698 ©?*?© & multiplication \impl{?*?} \\ 4699 ©?/?© & division \impl{?/?} \\ 4700 ©?%?© & remainder \impl{?%?} \\ 4701 \end{tabular} 4702 & 4703 \begin{tabular}{@{}ll@{}} 4704 ©?+?© & addition \impl{?+?} \\ 4705 ©?-?© & subtraction \impl{?-?} \\ 4706 ©?<<?© & left shift \impl{?<<?} \\ 4707 ©?>>?© & right shift \impl{?>>?} \\ 4708 ©?<?© & less than \impl{?<?} \\ 4709 ©?<=?© & less than or equal \impl{?<=?} \\ 4710 ©?>=?© & greater than or equal \impl{?>=?} \\ 4711 ©?>?© & greater than \impl{?>?} \\ 4712 ©?==?© & equality \impl{?==?} \\ 4713 ©?!=?© & inequality \impl{?"!=?} \\ 4714 ©?&?© & bitwise AND \impl{?&?} \\ 4715 ©?^?© & exclusive OR \impl{?^?} \\ 4716 ©?|?© & inclusive OR \impl{?"|?} \\ 4717 \\ 4718 \\ 4719 \end{tabular} 4720 & 4721 \begin{tabular}{@{}ll@{}} 4722 ©?=?© & simple assignment \impl{?=?} \\ 4723 ©?\=?© & exponentiation assignment \impl{?\=?} \\ 4724 ©?*=?© & multiplication assignment \impl{?*=?} \\ 4725 ©?/=?© & division assignment \impl{?/=?} \\ 4726 ©?%=?© & remainder assignment \impl{?%=?} \\ 4727 ©?+=?© & addition assignment \impl{?+=?} \\ 4728 ©?-=?© & subtraction assignment \impl{?-=?} \\ 4729 ©?<<=?© & left-shift assignment \impl{?<<=?} \\ 4730 ©?>>=?© & right-shift assignment \impl{?>>=?} \\ 4731 ©?&=?© & bitwise AND assignment \impl{?&=?} \\ 4732 ©?^=?© & exclusive OR assignment \impl{?^=?} \\ 4733 ©?|=?© & inclusive OR assignment \impl{?"|=?} \\ 4734 \\ 4735 \\ 4736 \\ 4737 \end{tabular} 4738 \end{tabular} 4371 \input{../refrat/operidents} 4739 4372 \caption{Operator Identifiers} 4740 4373 \label{opids} … … 4824 4457 For example, given 4825 4458 \begin{cfa} 4826 auto j = ®...®4459 auto j = @...@ 4827 4460 \end{cfa} 4828 4461 and the need to write a routine to compute using ©j© 4829 4462 \begin{cfa} 4830 void rtn( ®...®parm );4463 void rtn( @...@ parm ); 4831 4464 rtn( j ); 4832 4465 \end{cfa} … … 5065 4698 \begin{figure} 5066 4699 \begin{cfa} 5067 #include <fstream .hfa>5068 #include ®<coroutine.hfa>®5069 5070 ®coroutine®Fibonacci {4700 #include <fstream> 4701 #include <coroutine> 4702 4703 coroutine Fibonacci { 5071 4704 int fn; $\C{// used for communication}$ 5072 4705 }; 5073 5074 void main( Fibonacci & fib ) with( fib ) { $\C{// called on first resume}$ 4706 void ?{}( Fibonacci * this ) { 4707 this->fn = 0; 4708 } 4709 void main( Fibonacci * this ) { 5075 4710 int fn1, fn2; $\C{// retained between resumes}$ 5076 fn = 0; fn1 = fn; $\C{// 1st case}$ 5077 ®suspend;® $\C{// restart last resume}$ 5078 fn = 1; fn2 = fn1; fn1 = fn; $\C{// 2nd case}$ 5079 ®suspend;® $\C{// restart last resume}$ 5080 for () { 5081 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; $\C{// general case}$ 5082 ®suspend;® $\C{// restart last resume}$ 5083 } 5084 } 5085 int next( Fibonacci & fib ) with( fib ) { 5086 ®resume( fib );® $\C{// restart last suspend}$ 5087 return fn; 4711 this->fn = 0; $\C{// case 0}$ 4712 fn1 = this->fn; 4713 suspend(); $\C{// return to last resume}$ 4714 4715 this->fn = 1; $\C{// case 1}$ 4716 fn2 = fn1; 4717 fn1 = this->fn; 4718 suspend(); $\C{// return to last resume}$ 4719 4720 for ( ;; ) { $\C{// general case}$ 4721 this->fn = fn1 + fn2; 4722 fn2 = fn1; 4723 fn1 = this->fn; 4724 suspend(); $\C{// return to last resume}$ 4725 } // for 4726 } 4727 int next( Fibonacci * this ) { 4728 resume( this ); $\C{// transfer to last suspend}$ 4729 return this->fn; 5088 4730 } 5089 4731 int main() { 5090 4732 Fibonacci f1, f2; 5091 for ( 10 ) { $\C{// print N Fibonacci values}$ 5092 sout | next( f1 ) | next( f2 ); 5093 } 5094 } 5095 \end{cfa} 5096 \vspace*{-5pt} 4733 for ( int i = 1; i <= 10; i += 1 ) { 4734 sout | next( &f1 ) | ' ' | next( &f2 ); 4735 } // for 4736 } 4737 \end{cfa} 5097 4738 \caption{Fibonacci Coroutine} 5098 4739 \label{f:FibonacciCoroutine} … … 5120 4761 \begin{figure} 5121 4762 \begin{cfa} 5122 #include <fstream.hfa> 5123 #include ®<thread.hfa>® 5124 5125 ®monitor® AtomicCnt { int counter; }; 5126 void ?{}( AtomicCnt & c, int init = 0 ) with(c) { counter = init; } 5127 int inc( AtomicCnt & ®mutex® c, int inc = 1 ) with(c) { return counter += inc; } 5128 int dec( AtomicCnt & ®mutex® c, int dec = 1 ) with(c) { return counter -= dec; } 5129 forall( ostype & | ostream( ostype ) ) { $\C{// print any stream}$ 5130 ostype & ?|?( ostype & os, AtomicCnt c ) { return os | c.counter; } 5131 void ?|?( ostype & os, AtomicCnt c ) { (ostype &)(os | c.counter); ends( os ); } 5132 } 5133 5134 AtomicCnt global; $\C{// shared}$ 4763 #include <fstream> 4764 #include <kernel> 4765 #include <monitor> 4766 #include <thread> 4767 4768 monitor global_t { 4769 int value; 4770 }; 4771 4772 void ?{}(global_t * this) { 4773 this->value = 0; 4774 } 4775 4776 static global_t global; 4777 4778 void increment3( global_t * mutex this ) { 4779 this->value += 1; 4780 } 4781 void increment2( global_t * mutex this ) { 4782 increment3( this ); 4783 } 4784 void increment( global_t * mutex this ) { 4785 increment2( this ); 4786 } 5135 4787 5136 4788 thread MyThread {}; 5137 void main( MyThread & ) { 5138 for ( i; 100_000) {5139 inc( global );5140 dec(global );4789 4790 void main( MyThread* this ) { 4791 for(int i = 0; i < 1_000_000; i++) { 4792 increment( &global ); 5141 4793 } 5142 4794 } 5143 int main() { 5144 enum { Threads = 4 }; 5145 processor p[Threads - 1]; $\C{// + starting processor}$ 4795 int main(int argc, char* argv[]) { 4796 processor p; 5146 4797 { 5147 MyThread t[Threads];4798 MyThread f[4]; 5148 4799 } 5149 sout | global ; $\C{// print 0}$4800 sout | global.value; 5150 4801 } 5151 4802 \end{cfa} 5152 4803 \caption{Atomic-Counter Monitor} 5153 \ label{f:AtomicCounterMonitor}4804 \caption{f:AtomicCounterMonitor} 5154 4805 \end{figure} 5155 4806 … … 6614 6265 6615 6266 C has a number of syntax ambiguities, which are resolved by taking the longest sequence of overlapping characters that constitute a token. 6616 For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true] {x ++ ++ + y}because operator tokens ©++© and ©+© overlap.6617 Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true] {x ++ + ++ y}might yield a correct expression.6267 For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true]@x ++ ++ + y@ because operator tokens ©++© and ©+© overlap. 6268 Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true]@x ++ + ++ y@ might yield a correct expression. 6618 6269 Hence, C programmers are aware that spaces have to added to disambiguate certain syntactic cases. 6619 6270 … … 6635 6286 requiring arbitrary whitespace look-ahead for the routine-call parameter-list to disambiguate. 6636 6287 However, the dereference operator \emph{must} have a parameter/argument to dereference ©*?(...)©. 6637 Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true] {* ?()}does not preclude any meaningful program.6288 Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true]@* ?()@ does not preclude any meaningful program. 6638 6289 6639 6290 The remaining cases are with the increment/decrement operators and conditional expression, \eg: … … 6743 6394 \begin{cfa} 6744 6395 int i; $\C{// forward definition}$ 6745 int *j = ®&i®; $\C{// forward reference, valid in C, invalid in \CFA}$6396 int *j = @&i@; $\C{// forward reference, valid in C, invalid in \CFA}$ 6746 6397 int i = 0; $\C{// definition}$ 6747 6398 \end{cfa} … … 6751 6402 struct X { int i; struct X *next; }; 6752 6403 static struct X a; $\C{// forward definition}$ 6753 static struct X b = { 0, ®&a®};$\C{// forward reference, valid in C, invalid in \CFA}$6404 static struct X b = { 0, @&a@ };$\C{// forward reference, valid in C, invalid in \CFA}$ 6754 6405 static struct X a = { 1, &b }; $\C{// definition}$ 6755 6406 \end{cfa} … … 6764 6415 \item[Change:] have ©struct© introduce a scope for nested types: 6765 6416 \begin{cfa} 6766 enum ®Colour®{ R, G, B, Y, C, M };6417 enum @Colour@ { R, G, B, Y, C, M }; 6767 6418 struct Person { 6768 enum ®Colour®{ R, G, B }; $\C[7cm]{// nested type}$6419 enum @Colour@ { R, G, B }; $\C[7cm]{// nested type}$ 6769 6420 struct Face { $\C{// nested type}$ 6770 ®Colour®Eyes, Hair; $\C{// type defined outside (1 level)}$6421 @Colour@ Eyes, Hair; $\C{// type defined outside (1 level)}$ 6771 6422 }; 6772 ®.Colour®shirt; $\C{// type defined outside (top level)}$6773 ®Colour®pants; $\C{// type defined same level}$6423 @.Colour@ shirt; $\C{// type defined outside (top level)}$ 6424 @Colour@ pants; $\C{// type defined same level}$ 6774 6425 Face looks[10]; $\C{// type defined same level}$ 6775 6426 }; 6776 ®Colour®c = R; $\C{// type/enum defined same level}$6777 Person ®.Colour® pc = Person®.®R;$\C{// type/enum defined inside}$6778 Person ®.®Face pretty; $\C{// type defined inside}\CRT$6427 @Colour@ c = R; $\C{// type/enum defined same level}$ 6428 Person@.Colour@ pc = Person@.@R;$\C{// type/enum defined inside}$ 6429 Person@.@Face pretty; $\C{// type defined inside}\CRT$ 6779 6430 \end{cfa} 6780 6431 In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing. … … 6851 6502 \label{s:CFAKeywords} 6852 6503 6853 \CFA introduces the following new \Index{keyword}s, which cannot be used as identifiers.6504 \CFA introduces the following new keywords. 6854 6505 6855 6506 \begin{cquote} 6856 \begin{tabular}{@{}lllllll@{}} 6857 \begin{tabular}{@{}l@{}} 6858 \Indexc{basetypeof} \\ 6859 \Indexc{choose} \\ 6860 \Indexc{coroutine} \\ 6861 \Indexc{disable} \\ 6862 \end{tabular} 6863 & 6864 \begin{tabular}{@{}l@{}} 6865 \Indexc{enable} \\ 6866 \Indexc{exception} \\ 6867 \Indexc{fallthrough} \\ 6868 \Indexc{fallthru} \\ 6869 \end{tabular} 6870 & 6871 \begin{tabular}{@{}l@{}} 6872 \Indexc{finally} \\ 6873 \Indexc{fixup} \\ 6874 \Indexc{forall} \\ 6875 \Indexc{generator} \\ 6876 \end{tabular} 6877 & 6878 \begin{tabular}{@{}l@{}} 6879 \Indexc{int128} \\ 6880 \Indexc{monitor} \\ 6881 \Indexc{mutex} \\ 6882 \Indexc{one_t} \\ 6883 \end{tabular} 6884 & 6885 \begin{tabular}{@{}l@{}} 6886 \Indexc{report} \\ 6887 \Indexc{suspend} \\ 6888 \Indexc{throw} \\ 6889 \Indexc{throwResume} \\ 6890 \end{tabular} 6891 & 6892 \begin{tabular}{@{}l@{}} 6893 \Indexc{trait} \\ 6894 \Indexc{try} \\ 6895 \Indexc{virtual} \\ 6896 \Indexc{waitfor} \\ 6897 \end{tabular} 6898 & 6899 \begin{tabular}{@{}l@{}} 6900 \Indexc{when} \\ 6901 \Indexc{with} \\ 6902 \Indexc{zero_t} \\ 6903 \\ 6904 \end{tabular} 6905 \end{tabular} 6507 \input{../refrat/keywords} 6906 6508 \end{cquote} 6907 \CFA introduces the following new \Index{quasi-keyword}s, which can be used as identifiers. 6908 \begin{cquote} 6909 \begin{tabular}{@{}ll@{}} 6910 \begin{tabular}{@{}l@{}} 6911 \Indexc{catch} \\ 6912 \Indexc{catchResume} \\ 6913 \Indexc{finally} \\ 6914 \end{tabular} 6915 & 6916 \begin{tabular}{@{}l@{}} 6917 \Indexc{fixup} \\ 6918 \Indexc{or} \\ 6919 \Indexc{timeout} \\ 6920 \end{tabular} 6921 \end{tabular} 6922 \end{cquote} 6509 6923 6510 6924 6511 \section{Standard Headers} … … 7079 6666 // assume ?|? operator for printing an S 7080 6667 7081 S & sp = * ®new®( 3 ); $\C{// call constructor after allocation}$6668 S & sp = *@new@( 3 ); $\C{// call constructor after allocation}$ 7082 6669 sout | sp.i; 7083 ®delete®( &sp );7084 7085 S * spa = ®anew®( 10, 5 ); $\C{// allocate array and initialize each array element}$6670 @delete@( &sp ); 6671 6672 S * spa = @anew@( 10, 5 ); $\C{// allocate array and initialize each array element}$ 7086 6673 for ( i; 10 ) sout | spa[i] | nonl; 7087 6674 sout | nl; 7088 ®adelete®( 10, spa );6675 @adelete@( 10, spa ); 7089 6676 \end{cfa} 7090 6677 Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor. … … 7322 6909 [ int, long double ] remquo( long double, long double ); 7323 6910 6911 float div( float, float, int * );$\indexc{div}$ $\C{// alternative name for remquo}$ 6912 double div( double, double, int * ); 6913 long double div( long double, long double, int * ); 7324 6914 [ int, float ] div( float, float ); 7325 6915 [ int, double ] div( double, double ); … … 7382 6972 long double _Complex log( long double _Complex ); 7383 6973 7384 int log2( unsigned int );$\indexc{log2}$ 7385 long int log2( unsigned long int ); 7386 long long int log2( unsigned long long int ) 7387 float log2( float ); 6974 float log2( float );$\indexc{log2}$ 7388 6975 double log2( double ); 7389 6976 long double log2( long double ); … … 7567 7154 \leavevmode 7568 7155 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7569 // n / align * align7570 signed char floor( signed char n, signed char align );7571 unsigned char floor( unsigned char n, unsigned char align );7572 short int floor( short int n, short int align );7573 unsigned short int floor( unsigned short int n, unsigned short int align );7574 int floor( int n, int align );7575 unsigned int floor( unsigned int n, unsigned int align );7576 long int floor( long int n, long int align );7577 unsigned long int floor( unsigned long int n, unsigned long int align );7578 long long int floor( long long int n, long long int align );7579 unsigned long long int floor( unsigned long long int n, unsigned long long int align );7580 7581 // (n + (align - 1)) / align7582 signed char ceiling_div( signed char n, char align );7583 unsigned char ceiling_div( unsigned char n, unsigned char align );7584 short int ceiling_div( short int n, short int align );7585 unsigned short int ceiling_div( unsigned short int n, unsigned short int align );7586 int ceiling_div( int n, int align );7587 unsigned int ceiling_div( unsigned int n, unsigned int align );7588 long int ceiling_div( long int n, long int align );7589 unsigned long int ceiling_div( unsigned long int n, unsigned long int align );7590 long long int ceiling_div( long long int n, long long int align );7591 unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align );7592 7593 // floor( n + (n % align != 0 ? align - 1 : 0), align )7594 signed char ceiling( signed char n, signed char align );7595 unsigned char ceiling( unsigned char n, unsigned char align );7596 short int ceiling( short int n, short int align );7597 unsigned short int ceiling( unsigned short int n, unsigned short int align );7598 int ceiling( int n, int align );7599 unsigned int ceiling( unsigned int n, unsigned int align );7600 long int ceiling( long int n, long int align );7601 unsigned long int ceiling( unsigned long int n, unsigned long int align );7602 long long int ceiling( long long int n, long long int align );7603 unsigned long long int ceiling( unsigned long long int n, unsigned long long int align );7604 7605 7156 float floor( float );$\indexc{floor}$ 7606 7157 double floor( double ); … … 7698 7249 7699 7250 7700 %\subsection{\texorpdfstring{\protect\lstinline {Duration}}{Duration}}7251 %\subsection{\texorpdfstring{\protect\lstinline@Duration@}{Duration}} 7701 7252 \subsection{\texorpdfstring{\LstBasicStyle{Duration}}{Duration}} 7702 7253 \label{s:Duration} … … 7705 7256 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7706 7257 struct Duration { 7707 int64_t t n; $\C{// nanoseconds}$7258 int64_t tv; $\C{// nanoseconds}$ 7708 7259 }; 7709 7260 7710 7261 void ?{}( Duration & dur ); 7711 7262 void ?{}( Duration & dur, zero_t ); 7712 void ?{}( Duration & dur, timeval t )7713 void ?{}( Duration & dur, timespec t )7714 7263 7715 7264 Duration ?=?( Duration & dur, zero_t ); 7716 Duration ?=?( Duration & dur, timeval t )7717 Duration ?=?( Duration & dur, timespec t )7718 7265 7719 7266 Duration +?( Duration rhs ); … … 7737 7284 Duration ?%=?( Duration & lhs, Duration rhs ); 7738 7285 7739 bool ?==?( Duration lhs, zero_t);7740 bool ?!=?( Duration lhs, zero_t);7741 bool ?<? ( Duration lhs, zero_t);7742 bool ?<=?( Duration lhs, zero_t);7743 bool ?>? ( Duration lhs, zero_t);7744 bool ?>=?( Duration lhs, zero_t);7745 7746 bool ?==?( Duration lhs, Duration rhs);7747 bool ?!=?( Duration lhs, Duration rhs);7748 bool ?<? ( Duration lhs, Duration rhs);7749 bool ?<=?( Duration lhs, Duration rhs);7750 bool ?>? ( Duration lhs, Duration rhs);7751 bool ?>=?( Duration lhs, Duration rhs);7286 _Bool ?==?( Duration lhs, Duration rhs ); 7287 _Bool ?!=?( Duration lhs, Duration rhs ); 7288 _Bool ?<? ( Duration lhs, Duration rhs ); 7289 _Bool ?<=?( Duration lhs, Duration rhs ); 7290 _Bool ?>? ( Duration lhs, Duration rhs ); 7291 _Bool ?>=?( Duration lhs, Duration rhs ); 7292 7293 _Bool ?==?( Duration lhs, zero_t ); 7294 _Bool ?!=?( Duration lhs, zero_t ); 7295 _Bool ?<? ( Duration lhs, zero_t ); 7296 _Bool ?<=?( Duration lhs, zero_t ); 7297 _Bool ?>? ( Duration lhs, zero_t ); 7298 _Bool ?>=?( Duration lhs, zero_t ); 7752 7299 7753 7300 Duration abs( Duration rhs ); … … 7776 7323 int64_t ?`w( Duration dur ); 7777 7324 7778 double ?`dns( Duration dur );7779 double ?`dus( Duration dur );7780 double ?`dms( Duration dur );7781 double ?`ds( Duration dur );7782 double ?`dm( Duration dur );7783 double ?`dh( Duration dur );7784 double ?`dd( Duration dur );7785 double ?`dw( Duration dur );7786 7787 7325 Duration max( Duration lhs, Duration rhs ); 7788 7326 Duration min( Duration lhs, Duration rhs ); 7789 7790 forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Duration dur ); 7791 \end{cfa} 7792 7793 7794 %\subsection{\texorpdfstring{\protect\lstinline{timeval}}{timeval}} 7327 \end{cfa} 7328 7329 7330 %\subsection{\texorpdfstring{\protect\lstinline@\timeval@}{timeval}} 7795 7331 \subsection{\texorpdfstring{\LstBasicStyle{timeval}}{timeval}} 7796 7332 \label{s:timeval} … … 7799 7335 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7800 7336 void ?{}( timeval & t ); 7801 void ?{}( timeval & t, zero_t );7802 7337 void ?{}( timeval & t, time_t sec, suseconds_t usec ); 7803 7338 void ?{}( timeval & t, time_t sec ); 7339 void ?{}( timeval & t, zero_t ); 7804 7340 void ?{}( timeval & t, Time time ); 7805 7341 … … 7807 7343 timeval ?+?( timeval & lhs, timeval rhs ); 7808 7344 timeval ?-?( timeval & lhs, timeval rhs ); 7809 bool ?==?( timeval lhs, timeval rhs );7810 bool ?!=?( timeval lhs, timeval rhs );7811 \end{cfa} 7812 7813 7814 %\subsection{\texorpdfstring{\protect\lstinline {timespec}}{timespec}}7345 _Bool ?==?( timeval lhs, timeval rhs ); 7346 _Bool ?!=?( timeval lhs, timeval rhs ); 7347 \end{cfa} 7348 7349 7350 %\subsection{\texorpdfstring{\protect\lstinline@timespec@}{timespec}} 7815 7351 \subsection{\texorpdfstring{\LstBasicStyle{timespec}}{timespec}} 7816 7352 \label{s:timespec} … … 7819 7355 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7820 7356 void ?{}( timespec & t ); 7821 void ?{}( timespec & t, zero_t );7822 7357 void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec ); 7823 7358 void ?{}( timespec & t, time_t sec ); 7359 void ?{}( timespec & t, zero_t ); 7824 7360 void ?{}( timespec & t, Time time ); 7825 7361 … … 7827 7363 timespec ?+?( timespec & lhs, timespec rhs ); 7828 7364 timespec ?-?( timespec & lhs, timespec rhs ); 7829 bool ?==?( timespec lhs, timespec rhs );7830 bool ?!=?( timespec lhs, timespec rhs );7831 \end{cfa} 7832 7833 7834 %\subsection{\texorpdfstring{\protect\lstinline {itimerval}}{itimerval}}7365 _Bool ?==?( timespec lhs, timespec rhs ); 7366 _Bool ?!=?( timespec lhs, timespec rhs ); 7367 \end{cfa} 7368 7369 7370 %\subsection{\texorpdfstring{\protect\lstinline@itimerval@}{itimerval}} 7835 7371 \subsection{\texorpdfstring{\LstBasicStyle{itimerval}}{itimerval}} 7836 7372 \label{s:itimerval} … … 7843 7379 7844 7380 7845 %\subsection{\texorpdfstring{\protect\lstinline {Time}}{Time}}7381 %\subsection{\texorpdfstring{\protect\lstinline@Time@}{Time}} 7846 7382 \subsection{\texorpdfstring{\LstBasicStyle{Time}}{Time}} 7847 7383 \label{s:Time} … … 7850 7386 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7851 7387 struct Time { 7852 uint64_t t n; $\C{// nanoseconds since UNIX epoch}$7388 uint64_t tv; $\C{// nanoseconds since UNIX epoch}$ 7853 7389 }; 7854 7390 7855 7391 void ?{}( Time & time ); 7856 7392 void ?{}( Time & time, zero_t ); 7393 7394 Time ?=?( Time & time, zero_t ); 7395 7857 7396 void ?{}( Time & time, timeval t ); 7397 Time ?=?( Time & time, timeval t ); 7398 7858 7399 void ?{}( Time & time, timespec t ); 7859 7860 Time ?=?( Time & time, zero_t );7861 Time ?=?( Time & time, timeval t );7862 7400 Time ?=?( Time & time, timespec t ); 7863 7401 … … 7869 7407 Time ?-?( Time lhs, Duration rhs ); 7870 7408 Time ?-=?( Time & lhs, Duration rhs ); 7871 bool ?==?( Time lhs, Time rhs ); 7872 bool ?!=?( Time lhs, Time rhs ); 7873 bool ?<?( Time lhs, Time rhs ); 7874 bool ?<=?( Time lhs, Time rhs ); 7875 bool ?>?( Time lhs, Time rhs ); 7876 bool ?>=?( Time lhs, Time rhs ); 7877 7878 int64_t ?`ns( Time t ); 7409 _Bool ?==?( Time lhs, Time rhs ); 7410 _Bool ?!=?( Time lhs, Time rhs ); 7411 _Bool ?<?( Time lhs, Time rhs ); 7412 _Bool ?<=?( Time lhs, Time rhs ); 7413 _Bool ?>?( Time lhs, Time rhs ); 7414 _Bool ?>=?( Time lhs, Time rhs ); 7879 7415 7880 7416 char * yy_mm_dd( Time time, char * buf ); 7881 char * ?`ymd( Time time, char * buf ); // short form 7417 char * ?`ymd( Time time, char * buf ) { // short form 7418 return yy_mm_dd( time, buf ); 7419 } // ymd 7882 7420 7883 7421 char * mm_dd_yy( Time time, char * buf ); 7884 char * ?`mdy( Time time, char * buf ); // short form 7422 char * ?`mdy( Time time, char * buf ) { // short form 7423 return mm_dd_yy( time, buf ); 7424 } // mdy 7885 7425 7886 7426 char * dd_mm_yy( Time time, char * buf ); 7887 char * ?`dmy( Time time, char * buf ); // short form 7427 char * ?`dmy( Time time, char * buf ) { // short form 7428 return dd_mm_yy( time, buf );; 7429 } // dmy 7888 7430 7889 7431 size_t strftime( char * buf, size_t size, const char * fmt, Time time ); 7890 7891 forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time ); 7432 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time ); 7892 7433 \end{cfa} 7893 7434 … … 7909 7450 7910 7451 7911 %\subsection{\texorpdfstring{\protect\lstinline {Clock}}{Clock}}7452 %\subsection{\texorpdfstring{\protect\lstinline@Clock@}{Clock}} 7912 7453 \subsection{\texorpdfstring{\LstBasicStyle{Clock}}{Clock}} 7913 7454 \label{s:Clock} … … 7915 7456 \leavevmode 7916 7457 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7917 struct Clock { $\C{// virtual clock}$ 7918 Duration offset; $\C{// offset from computer real-time}$ 7458 struct Clock { 7459 Duration offset; $\C{// for virtual clock: contains offset from real-time}$ 7460 int clocktype; $\C{// implementation only -1 (virtual), CLOCK\_REALTIME}$ 7919 7461 }; 7920 7462 7921 void ?{}( Clock & clk ); $\C{// create no offset}$ 7922 void ?{}( Clock & clk, Duration adj ); $\C{// create with offset}$ 7923 void reset( Clock & clk, Duration adj ); $\C{// change offset}$ 7924 7925 Duration resolutionHi(); $\C{// clock resolution in nanoseconds (fine)}$ 7926 Duration resolution(); $\C{// clock resolution without nanoseconds (coarse)}$ 7927 7928 Time timeHiRes(); $\C{// real time with nanoseconds}$ 7929 Time time(); $\C{// real time without nanoseconds}$ 7930 Time time( Clock & clk ); $\C{// real time for given clock}$ 7931 Time ?()( Clock & clk ); $\C{//\ \ \ \ alternative syntax}$ 7932 timeval time( Clock & clk ); $\C{// convert to C time format}$ 7933 tm time( Clock & clk ); 7934 Duration processor(); $\C{// non-monotonic duration of kernel thread}$ 7935 Duration program(); $\C{// non-monotonic duration of program CPU}$ 7936 Duration boot(); $\C{// monotonic duration since computer boot}$ 7463 void resetClock( Clock & clk ); 7464 void resetClock( Clock & clk, Duration adj ); 7465 void ?{}( Clock & clk ); 7466 void ?{}( Clock & clk, Duration adj ); 7467 7468 Duration getResNsec(); $\C{// with nanoseconds}$ 7469 Duration getRes(); $\C{// without nanoseconds}$ 7470 7471 Time getTimeNsec(); $\C{// with nanoseconds}$ 7472 Time getTime(); $\C{// without nanoseconds}$ 7473 Time getTime( Clock & clk ); 7474 Time ?()( Clock & clk ); 7475 timeval getTime( Clock & clk ); 7476 tm getTime( Clock & clk ); 7937 7477 \end{cfa} 7938 7478 … … 8105 7645 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp ); 8106 7646 \end{cfa} 8107 \VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces. 7647 7648 The following factorial programs contrast using GMP with the \CFA and C interfaces, where the output from these programs appears in \VRef[Figure]{f:MultiPrecisionFactorials}. 8108 7649 (Compile with flag \Indexc{-lgmp} to link with the GMP library.) 8109 8110 \begin{figure}8111 7650 \begin{cquote} 8112 7651 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}} 8113 \multicolumn{1}{ @{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}} \\7652 \multicolumn{1}{c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}} \\ 8114 7653 \hline 8115 7654 \begin{cfa} … … 8120 7659 8121 7660 sout | 0 | fact; 8122 for ( i; 40) {7661 for ( unsigned int i = 1; i <= 40; i += 1 ) { 8123 7662 fact *= i; 8124 7663 sout | i | fact; … … 8130 7669 #include <gmp.h>$\indexc{gmp.h}$ 8131 7670 int main( void ) { 8132 ®gmp_printf®( "Factorial Numbers\n" );8133 ®mpz_t®fact;8134 ®mpz_init_set_ui®( fact, 1 );8135 ®gmp_printf®( "%d %Zd\n", 0, fact );7671 @gmp_printf@( "Factorial Numbers\n" ); 7672 @mpz_t@ fact; 7673 @mpz_init_set_ui@( fact, 1 ); 7674 @gmp_printf@( "%d %Zd\n", 0, fact ); 8136 7675 for ( unsigned int i = 1; i <= 40; i += 1 ) { 8137 ®mpz_mul_ui®( fact, fact, i );8138 ®gmp_printf®( "%d %Zd\n", i, fact );7676 @mpz_mul_ui@( fact, fact, i ); 7677 @gmp_printf@( "%d %Zd\n", i, fact ); 8139 7678 } 8140 7679 } … … 8142 7681 \end{tabular} 8143 7682 \end{cquote} 8144 \small 7683 7684 \begin{figure} 8145 7685 \begin{cfa} 8146 7686 Factorial Numbers -
example/io/batch-readv.c
r5407cdc rfeacef9 66 66 } 67 67 68 uint64_t timeHiRes() {68 uint64_t getTimeNsec() { 69 69 timespec curr; 70 70 clock_gettime( CLOCK_REALTIME, &curr ); … … 163 163 164 164 printf("Running for %f second, reading %d bytes in batches of %d\n", duration, buflen, batch); 165 uint64_t start = timeHiRes();166 uint64_t end = timeHiRes();167 uint64_t prev = timeHiRes();165 uint64_t start = getTimeNsec(); 166 uint64_t end = getTimeNsec(); 167 uint64_t prev = getTimeNsec(); 168 168 for(;;) { 169 169 submit_and_drain(&iov, batch); 170 end = timeHiRes();170 end = getTimeNsec(); 171 171 uint64_t delta = end - start; 172 172 if( to_fseconds(end - prev) > 0.1 ) { -
libcfa/configure.ac
r5407cdc rfeacef9 169 169 AH_TEMPLATE([CFA_HAVE_IOSQE_FIXED_FILE],[Defined if io_uring support is present when compiling libcfathread and supports the flag FIXED_FILE.]) 170 170 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_DRAIN],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_DRAIN.]) 171 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.]) 171 172 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_LINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_LINK.]) 172 173 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_HARDLINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_HARDLINK.]) 173 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])174 AH_TEMPLATE([CFA_HAVE_IOSQE_BUFFER_SELECT],[Defined if io_uring support is present when compiling libcfathread and supports the flag BUFFER_SELEC.])175 174 AH_TEMPLATE([CFA_HAVE_SPLICE_F_FD_IN_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the flag SPLICE_F_FD_IN_FIXED.]) 176 175 AH_TEMPLATE([CFA_HAVE_IORING_SETUP_ATTACH_WQ],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_SETUP_ATTACH_WQ.]) … … 183 182 184 183 define(ioring_ops, [IORING_OP_NOP,IORING_OP_READV,IORING_OP_WRITEV,IORING_OP_FSYNC,IORING_OP_READ_FIXED,IORING_OP_WRITE_FIXED,IORING_OP_POLL_ADD,IORING_OP_POLL_REMOVE,IORING_OP_SYNC_FILE_RANGE,IORING_OP_SENDMSG,IORING_OP_RECVMSG,IORING_OP_TIMEOUT,IORING_OP_TIMEOUT_REMOVE,IORING_OP_ACCEPT,IORING_OP_ASYNC_CANCEL,IORING_OP_LINK_TIMEOUT,IORING_OP_CONNECT,IORING_OP_FALLOCATE,IORING_OP_OPENAT,IORING_OP_CLOSE,IORING_OP_FILES_UPDATE,IORING_OP_STATX,IORING_OP_READ,IORING_OP_WRITE,IORING_OP_FADVISE,IORING_OP_MADVISE,IORING_OP_SEND,IORING_OP_RECV,IORING_OP_OPENAT2,IORING_OP_EPOLL_CTL,IORING_OP_SPLICE,IORING_OP_PROVIDE_BUFFERS,IORING_OP_REMOVE_BUFFER,IORING_OP_TEE]) 185 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_ IO_LINK,IOSQE_IO_HARDLINK,IOSQE_ASYNC,IOSQE_BUFFER_SELECT,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])184 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_ASYNC,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ]) 186 185 187 186 define(ioring_from_decls, [ -
libcfa/prelude/builtins.c
r5407cdc rfeacef9 9 9 // Author : Peter A. Buhr 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue Apr 13 17:26:32 202113 // Update Count : 11 711 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 14:42:00 2020 13 // Update Count : 111 14 14 // 15 15 … … 125 125 } // distribution 126 126 127 #define __CFA_BASE_COMP_1__() if ( x== 1 ) return 1128 #define __CFA_BASE_COMP_2__() if ( x == 2 ) return x<< (y - 1)127 #define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1 128 #define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1) 129 129 #define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0 130 130 … … 134 134 __CFA_BASE_COMP_2__(); /* special case, positive shifting for integral types */ \ 135 135 __CFA_EXP_OVERFLOW__(); /* immediate overflow, negative exponent > 2^size-1 */ \ 136 typeof( x) op = 1; /* accumulate odd product */ \136 typeof(ep) op = 1; /* accumulate odd product */ \ 137 137 for ( ; y > 1; y >>= 1 ) { /* squaring exponentiation, O(log2 y) */ \ 138 if ( (y & 1) == 1 ) op = op * x; /* odd ? */ \139 x = x * x; \138 if ( (y & 1) == 1 ) op = op * ep; /* odd ? */ \ 139 ep = ep * ep; \ 140 140 } \ 141 return x* op141 return ep * op 142 142 143 143 static inline { 144 long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); } 145 long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); } 146 long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); } 144 long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); } 145 long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); } 147 146 // unsigned computation may be faster and larger 148 unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); } 149 unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); } 150 unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); } 147 unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); } 148 unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); } 151 149 } // distribution 152 150 … … 159 157 160 158 static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) { 161 OT ?\?( OT x, unsigned int y ) { __CFA_EXP__(); } 162 OT ?\?( OT x, unsigned long int y ) { __CFA_EXP__(); } 163 OT ?\?( OT x, unsigned long long int y ) { __CFA_EXP__(); } 159 OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); } 160 OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); } 164 161 } // distribution 165 162 … … 169 166 170 167 static inline { 171 long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }172 168 long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; } 173 long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; }174 unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }175 169 unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; } 176 unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; } 170 int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; } 171 unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; } 177 172 } // distribution 178 173 -
libcfa/prelude/defines.hfa.in
r5407cdc rfeacef9 149 149 150 150 /* Defined if io_uring support is present when compiling libcfathread and 151 supports the flag BUFFER_SELEC. */152 #undef CFA_HAVE_IOSQE_BUFFER_SELECT153 154 /* Defined if io_uring support is present when compiling libcfathread and155 151 supports the flag FIXED_FILE. */ 156 152 #undef CFA_HAVE_IOSQE_FIXED_FILE -
libcfa/src/Makefile.am
r5407cdc rfeacef9 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Sat Apr 24 09:09:56 202114 ## Update Count : 25 413 ## Last Modified On : Wed Dec 9 22:46:14 2020 14 ## Update Count : 250 15 15 ############################################################################### 16 16 … … 56 56 bits/queue.hfa \ 57 57 bits/sequence.hfa \ 58 containers/array.hfa \59 58 concurrency/iofwd.hfa \ 60 59 containers/list.hfa \ 61 containers/queueLockFree.hfa \62 60 containers/stackLockFree.hfa \ 63 61 vec/vec.hfa \ … … 69 67 common.hfa \ 70 68 fstream.hfa \ 71 strstream.hfa \72 69 heap.hfa \ 73 70 iostream.hfa \ -
libcfa/src/bits/debug.hfa
r5407cdc rfeacef9 101 101 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_buffer(STDERR_FILENO, __VA_ARGS__)) 102 102 #define __cfadbg_print_buffer_decl(group, ...) \ 103 __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO,__dbg_text, __dbg_len ))103 __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len )) 104 104 #define __cfadbg_print_buffer_local(group, ...) \ 105 105 __CFADBG_PRINT_GROUP_##group(__dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write(STDERR_FILENO, __dbg_text, __dbg_len)) -
libcfa/src/bits/defs.hfa
r5407cdc rfeacef9 74 74 #error unsupported architecture 75 75 #endif 76 77 #define CFA_IO_LAZY (1_l64u << 32_l64u) -
libcfa/src/bits/locks.hfa
r5407cdc rfeacef9 37 37 extern "C" { 38 38 extern void disable_interrupts() OPTIONAL_THREAD; 39 extern void enable_interrupts ( bool poll = true) OPTIONAL_THREAD;39 extern void enable_interrupts_noPoll() OPTIONAL_THREAD; 40 40 41 41 #ifdef __CFA_DEBUG__ … … 57 57 __cfaabi_dbg_record_lock( this, caller ); 58 58 } else { 59 enable_interrupts ( false);59 enable_interrupts_noPoll(); 60 60 } 61 61 return result; … … 90 90 static inline void unlock( __spinlock_t & this ) { 91 91 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 92 enable_interrupts ( false);92 enable_interrupts_noPoll(); 93 93 } 94 94 #endif -
libcfa/src/bits/queue.hfa
r5407cdc rfeacef9 15 15 }; 16 16 17 staticinline {17 inline { 18 18 // wrappers to make Collection have T 19 19 T & head( Queue(T) & q ) with( q ) { … … 154 154 struct QueueIter { 155 155 inline ColIter; // Plan 9 inheritance 156 }; 156 }; 157 157 158 staticinline {158 inline { 159 159 void ?{}( QueueIter(T) & qi ) with( qi ) { 160 160 ((ColIter &)qi){}; -
libcfa/src/bits/weakso_locks.cfa
r5407cdc rfeacef9 18 18 #include "bits/weakso_locks.hfa" 19 19 20 void ?{}( blocking_lock & , bool, bool) {}21 void ^?{}( blocking_lock & ) {}20 void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {} 21 void ^?{}( blocking_lock & this ) {} 22 22 23 void lock( blocking_lock & ) {} 24 bool try_lock( blocking_lock & ) { return false; } 25 void unlock( blocking_lock & ) {} 26 void on_notify( blocking_lock &, struct $thread * ) {} 27 size_t on_wait( blocking_lock & ) { return 0; } 28 void on_wakeup( blocking_lock &, size_t ) {} 29 size_t wait_count( blocking_lock & ) { return 0; } 23 void lock( blocking_lock & this ) {} 24 bool try_lock( blocking_lock & this ) { return false; } 25 void unlock( blocking_lock & this ) {} 26 void on_notify( blocking_lock & this, struct $thread * t ) {} 27 void on_wait( blocking_lock & this ) {} 28 size_t wait_count( blocking_lock & this ) { return 0; } 29 void set_recursion_count( blocking_lock & this, size_t recursion ) {} 30 size_t get_recursion_count( blocking_lock & this ) { return 0; } -
libcfa/src/bits/weakso_locks.hfa
r5407cdc rfeacef9 56 56 void unlock( blocking_lock & this ) OPTIONAL_THREAD; 57 57 void on_notify( blocking_lock & this, struct $thread * t ) OPTIONAL_THREAD; 58 size_t on_wait( blocking_lock & this ) OPTIONAL_THREAD; 59 void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD; 58 void on_wait( blocking_lock & this ) OPTIONAL_THREAD; 60 59 size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD; 60 void set_recursion_count( blocking_lock & this, size_t recursion ) OPTIONAL_THREAD; 61 size_t get_recursion_count( blocking_lock & this ) OPTIONAL_THREAD; 61 62 62 63 //---------- … … 68 69 static inline void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };} 69 70 static inline void ^?{}( multiple_acquisition_lock & this ) {} 70 static inline void lock ( multiple_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 71 static inline bool try_lock ( multiple_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); } 72 static inline void unlock ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 73 static inline size_t on_wait ( multiple_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); } 74 static inline void on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 71 static inline void lock ( multiple_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 72 static inline void unlock ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 73 static inline void on_wait ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); } 75 74 static inline void on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 75 static inline void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); } 76 static inline size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } -
libcfa/src/clock.hfa
r5407cdc rfeacef9 10 10 // Created On : Thu Apr 12 14:36:06 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Apr 18 08:12:16 202113 // Update Count : 2812 // Last Modified On : Mon Jan 6 12:49:58 2020 13 // Update Count : 9 14 14 // 15 15 … … 27 27 //######################### Clock ######################### 28 28 29 struct Clock { // virtual clock 30 // private 31 Duration offset; // offset from computer real-time 29 struct Clock { // private 30 Duration offset; // for virtual clock: contains offset from real-time 32 31 }; 33 32 34 33 static inline { 35 void reset ( Clock & clk, Duration adj ) with( clk ) { // change offset34 void resetClock( Clock & clk, Duration adj ) with( clk ) { 36 35 offset = adj + __timezone`s; // timezone (global) is (UTC - local time) in seconds 37 } // reset 36 } // resetClock 38 37 39 void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); } // create no offset 40 void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); } // create with offset 38 void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); } 41 39 42 // System-wide clock that measures real, i.e., wall-clock) time. This clock is affected by discontinuous jumps in 43 // the system time. For example, manual changes of the clock, and incremental adjustments performed by adjtime(3) 44 // and NTP (daylight saving (Fall back). 45 Duration resolutionHi() { // clock resolution in nanoseconds (fine) 40 Duration getResNsec() { 46 41 struct timespec res; 47 42 clock_getres( CLOCK_REALTIME, &res ); 48 43 return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns; 49 } // resolutionHi44 } // getRes 50 45 51 Duration resolution() { // clock resolution without nanoseconds (coarse)46 Duration getRes() { 52 47 struct timespec res; 53 48 clock_getres( CLOCK_REALTIME_COARSE, &res ); 54 49 return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns; 55 } // resolution50 } // getRes 56 51 57 Time timeHiRes() { // real timewith nanoseconds52 Time getTimeNsec() { // with nanoseconds 58 53 timespec curr; 59 54 clock_gettime( CLOCK_REALTIME, &curr ); 60 55 return (Time){ curr }; 61 } // timeHiRes56 } // getTimeNsec 62 57 63 Time time() { // real timewithout nanoseconds58 Time getTime() { // without nanoseconds 64 59 timespec curr; 65 60 clock_gettime( CLOCK_REALTIME_COARSE, &curr ); 66 61 curr.tv_nsec = 0; 67 62 return (Time){ curr }; 68 } // time63 } // getTime 69 64 70 Time time( Clock & clk ) with( clk ) { // real time for given clock71 return time() + offset;72 } // time65 Time getTime( Clock & clk ) with( clk ) { 66 return getTime() + offset; 67 } // getTime 73 68 74 69 Time ?()( Clock & clk ) with( clk ) { // alternative syntax 75 return time() + offset;76 } // ?()70 return getTime() + offset; 71 } // getTime 77 72 78 timeval time( Clock & clk ) { // convert to C time format73 timeval getTime( Clock & clk ) { 79 74 return (timeval){ clk() }; 80 } // time75 } // getTime 81 76 82 tm time( Clock & clk ) with( clk ) {77 tm getTime( Clock & clk ) with( clk ) { 83 78 tm ret; 84 localtime_r( time( clk ).tv_sec, &ret );79 localtime_r( getTime( clk ).tv_sec, &ret ); 85 80 return ret; 86 } // time81 } // getTime 87 82 88 // CFA processor CPU-time watch that ticks when the processor (kernel thread) is running. This watch is affected by 89 // discontinuous jumps when the OS is not running the kernal thread. A duration is returned because the value is 90 // relative and cannot be converted to real-time (wall-clock) time. 91 Duration processor() { // non-monotonic duration of kernel thread 83 Time getCPUTime() { 92 84 timespec ts; 93 85 clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts ); 94 return (Duration){ ts }; 95 } // processor 96 97 // Program CPU-time watch measures CPU time consumed by all processors (kernel threads) in the UNIX process. This 98 // watch is affected by discontinuous jumps when the OS is not running the kernel threads. A duration is returned 99 // because the value is relative and cannot be converted to real-time (wall-clock) time. 100 Duration program() { // non-monotonic duration of program CPU 101 timespec ts; 102 clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &ts ); 103 return (Duration){ ts }; 104 } // program 105 106 // Monotonic duration from machine boot and including system suspension. This watch is unaffected by discontinuous 107 // jumps resulting from manual changes of the clock, and incremental adjustments performed by adjtime(3) and NTP 108 // (Fall back). A duration is returned because the value is relative and cannot be converted to real-time 109 // (wall-clock) time. 110 Duration boot() { // monotonic duration since computer boot 111 timespec ts; 112 clock_gettime( CLOCK_BOOTTIME, &ts ); 113 return (Duration){ ts }; 114 } // boot 86 return (Time){ ts }; 87 } // getCPUTime 115 88 } // distribution 116 89 -
libcfa/src/concurrency/alarm.cfa
r5407cdc rfeacef9 15 15 16 16 #define __cforall_thread__ 17 // #define __CFA_DEBUG_PRINT_PREEMPTION__18 17 19 18 #include <errno.h> … … 108 107 bool first = ! & alarms`first; 109 108 110 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn );111 109 insert( &alarms, this ); 112 110 if( first ) { … … 116 114 unlock( event_kernel->lock ); 117 115 this->set = true; 118 enable_interrupts( );116 enable_interrupts( __cfaabi_dbg_ctx ); 119 117 } 120 118 … … 127 125 } 128 126 unlock( event_kernel->lock ); 129 enable_interrupts( );127 enable_interrupts( __cfaabi_dbg_ctx ); 130 128 this->set = false; 131 129 } -
libcfa/src/concurrency/clib/cfathread.cfa
r5407cdc rfeacef9 14 14 // 15 15 16 #include "fstream.hfa"17 #include "locks.hfa"18 16 #include "kernel.hfa" 19 #include "stats.hfa"20 17 #include "thread.hfa" 21 #include "time.hfa"22 18 23 #include "cfathread.h" 19 thread CRunner { 20 void (*themain)( CRunner * ); 21 }; 24 22 25 extern void ?{}(processor &, const char[], cluster &, $thread *); 26 extern "C" { 27 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 23 static void ?{}( CRunner & this, void (*themain)( CRunner * ) ) { 24 this.themain = themain; 28 25 } 29 26 30 //================================================================================ 31 // Thread run y the C Interface 32 33 struct cfathread_object { 34 $thread self; 35 void * (*themain)( void * ); 36 void * arg; 37 void * ret; 38 }; 39 void main(cfathread_object & this); 40 void ^?{}(cfathread_object & mutex this); 41 42 static inline $thread * get_thread( cfathread_object & this ) { return &this.self; } 43 44 typedef ThreadCancelled(cfathread_object) cfathread_exception; 45 typedef ThreadCancelled_vtable(cfathread_object) cfathread_vtable; 46 47 void defaultResumptionHandler(ThreadCancelled(cfathread_object) & except) { 48 abort | "A thread was cancelled"; 27 void main( CRunner & this ) { 28 this.themain( &this ); 49 29 } 50 30 51 cfathread_vtable _cfathread_vtable_instance; 31 processor * procs = 0p; 32 int proc_cnt = 1; 52 33 53 cfathread_vtable & const _default_vtable = _cfathread_vtable_instance;54 55 cfathread_vtable const & get_exception_vtable(cfathread_exception *) {56 return _cfathread_vtable_instance;57 }58 59 static void ?{}( cfathread_object & this, cluster & cl, void *(*themain)( void * ), void * arg ) {60 this.themain = themain;61 this.arg = arg;62 (this.self){"C-thread", cl};63 __thrd_start(this, main);64 }65 66 void ^?{}(cfathread_object & mutex this) {67 ^(this.self){};68 }69 70 void main( cfathread_object & this ) {71 __attribute__((unused)) void * const thrd_obj = (void*)&this;72 __attribute__((unused)) void * const thrd_hdl = (void*)active_thread();73 /* paranoid */ verify( thrd_obj == thrd_hdl );74 75 this.ret = this.themain( this.arg );76 }77 78 //================================================================================79 // Special Init Thread responsible for the initialization or processors80 struct __cfainit {81 $thread self;82 void (*init)( void * );83 void * arg;84 };85 void main(__cfainit & this);86 void ^?{}(__cfainit & mutex this);87 88 static inline $thread * get_thread( __cfainit & this ) { return &this.self; }89 90 typedef ThreadCancelled(__cfainit) __cfainit_exception;91 typedef ThreadCancelled_vtable(__cfainit) __cfainit_vtable;92 93 void defaultResumptionHandler(ThreadCancelled(__cfainit) & except) {94 abort | "The init thread was cancelled";95 }96 97 __cfainit_vtable ___cfainit_vtable_instance;98 99 __cfainit_vtable const & get_exception_vtable(__cfainit_exception *) {100 return ___cfainit_vtable_instance;101 }102 103 static void ?{}( __cfainit & this, void (*init)( void * ), void * arg ) {104 this.init = init;105 this.arg = arg;106 (this.self){"Processir Init"};107 108 // Don't use __thrd_start! just prep the context manually109 $thread * this_thrd = get_thread(this);110 void (*main_p)(__cfainit &) = main;111 112 disable_interrupts();113 __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread);114 115 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];116 /* paranoid */ verify( this_thrd->context.SP );117 118 this_thrd->state = Ready;119 enable_interrupts();120 }121 122 void ^?{}(__cfainit & mutex this) {123 ^(this.self){};124 }125 126 void main( __cfainit & this ) {127 __attribute__((unused)) void * const thrd_obj = (void*)&this;128 __attribute__((unused)) void * const thrd_hdl = (void*)active_thread();129 /* paranoid */ verify( thrd_obj == thrd_hdl );130 131 this.init( this.arg );132 }133 134 //================================================================================135 // Main Api136 34 extern "C" { 137 int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) { 138 *cl = new(); 139 return 0; 35 //-------------------- 36 // Basic thread management 37 CRunner * cfathread_create( void (*main)( CRunner * ) ) { 38 return new( main ); 140 39 } 141 40 142 cfathread_cluster_t cfathread_cluster_self(void) { 143 return active_cluster(); 144 } 145 146 int cfathread_cluster_print_stats( cfathread_cluster_t cl ) { 147 #if !defined(__CFA_NO_STATISTICS__) 148 print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO ); 149 print_stats_now( *cl, CFA_STATS_READY_Q | CFA_STATS_IO ); 150 #endif 151 return 0; 152 } 153 154 int cfathread_cluster_add_worker(cfathread_cluster_t cl, pthread_t* tid, void (*init_routine) (void *), void * arg) { 155 __cfainit * it = 0p; 156 if(init_routine) { 157 it = alloc(); 158 (*it){init_routine, arg}; 159 } 160 processor * proc = alloc(); 161 (*proc){ "C-processor", *cl, get_thread(*it) }; 162 163 // Wait for the init thread to return before continuing 164 if(it) { 165 ^(*it){}; 166 free(it); 167 } 168 169 if(tid) *tid = proc->kernel_thread; 170 return 0; 171 } 172 173 int cfathread_cluster_pause (cfathread_cluster_t) { 174 abort | "Pausing clusters is not supported"; 175 exit(1); 176 } 177 178 int cfathread_cluster_resume(cfathread_cluster_t) { 179 abort | "Resuming clusters is not supported"; 180 exit(1); 181 } 182 183 //-------------------- 184 // Thread attributes 185 int cfathread_attr_init(cfathread_attr_t *attr) __attribute__((nonnull (1))) { 186 attr->cl = active_cluster(); 187 return 0; 188 } 189 190 //-------------------- 191 // Thread 192 int cfathread_create( cfathread_t * handle, const cfathread_attr_t * attr, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1))) { 193 cluster * cl = attr ? attr->cl : active_cluster(); 194 cfathread_t thrd = alloc(); 195 (*thrd){ *cl, main, arg }; 196 *handle = thrd; 197 return 0; 198 } 199 200 int cfathread_join( cfathread_t thrd, void ** retval ) { 201 void * ret = join( *thrd ).ret; 202 ^( *thrd ){}; 203 free(thrd); 204 if(retval) { 205 *retval = ret; 206 } 207 return 0; 208 } 209 210 int cfathread_get_errno(void) { 211 return errno; 212 } 213 214 cfathread_t cfathread_self(void) { 215 return (cfathread_t)active_thread(); 216 } 217 218 int cfathread_usleep(useconds_t usecs) { 219 sleep(usecs`us); 220 return 0; 221 } 222 223 int cfathread_sleep(unsigned int secs) { 224 sleep(secs`s); 225 return 0; 41 void cfathread_join( CRunner * thrd ) { 42 delete( thrd ); 226 43 } 227 44 … … 230 47 } 231 48 232 void cfathread_unpark( cfathread_tthrd ) {49 void cfathread_unpark( CRunner * thrd ) { 233 50 unpark( *thrd ); 234 51 } … … 238 55 } 239 56 240 typedef struct cfathread_mutex * cfathread_mutex_t; 57 //-------------------- 58 // Basic kernel features 59 void cfathread_setproccnt( int ncnt ) { 60 assert( ncnt >= 1 ); 61 adelete( procs ); 241 62 242 //-------------------- 243 // Mutex 244 struct cfathread_mutex { 245 fast_lock impl; 246 }; 247 int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; } 248 int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))) { delete( *mut ); return 0; } 249 int cfathread_mutex_lock (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { lock( (*mut)->impl ); return 0; } 250 int cfathread_mutex_unlock (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { unlock( (*mut)->impl ); return 0; } 251 int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1))) { 252 bool ret = try_lock( (*mut)->impl ); 253 if( ret ) return 0; 254 else return EBUSY; 255 } 256 257 //-------------------- 258 // Condition 259 struct cfathread_condition { 260 condition_variable(fast_lock) impl; 261 }; 262 int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; } 263 int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1))) { notify_one( (*cond)->impl ); return 0; } 264 int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2))) { wait( (*cond)->impl, (*mut)->impl ); return 0; } 265 int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))) { 266 Time t = { *abstime }; 267 if( wait( (*cond)->impl, (*mut)->impl, t ) ) { 268 return 0; 269 } 270 errno = ETIMEDOUT; 271 return ETIMEDOUT; 63 proc_cnt = ncnt - 1; 64 procs = anew(proc_cnt); 272 65 } 273 66 } 274 275 #include <iofwd.hfa>276 277 extern "C" {278 #include <unistd.h>279 #include <sys/types.h>280 #include <sys/socket.h>281 282 //--------------------283 // IO operations284 int cfathread_socket(int domain, int type, int protocol) {285 return socket(domain, type, protocol);286 }287 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {288 return bind(socket, address, address_len);289 }290 291 int cfathread_listen(int socket, int backlog) {292 return listen(socket, backlog);293 }294 295 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {296 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY);297 }298 299 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {300 return cfa_connect(socket, address, address_len, CFA_IO_LAZY);301 }302 303 int cfathread_dup(int fildes) {304 return dup(fildes);305 }306 307 int cfathread_close(int fildes) {308 return cfa_close(fildes, CFA_IO_LAZY);309 }310 311 ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) {312 return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY);313 }314 315 ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) {316 // Use send rather then write for socket since it's faster317 return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY);318 }319 320 ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len) {321 struct iovec iov;322 iov.iov_base = buffer;323 iov.iov_len = length;324 325 struct msghdr msg;326 msg.msg_name = address;327 msg.msg_namelen = address_len ? (socklen_t)*address_len : (socklen_t)0;328 msg.msg_iov = &iov;329 msg.msg_iovlen = 1;330 msg.msg_control = 0p;331 msg.msg_controllen = 0;332 333 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY);334 335 if(address_len) *address_len = msg.msg_namelen;336 return ret;337 }338 339 ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) {340 // Use recv rather then read for socket since it's faster341 return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY);342 }343 344 } -
libcfa/src/concurrency/clib/cfathread.h
r5407cdc rfeacef9 14 14 // 15 15 16 #include "stddef.h" 17 #include "invoke.h" 18 16 19 #if defined(__cforall) || defined(__cplusplus) 17 20 extern "C" { 18 21 #endif 19 #include <asm/types.h>20 #include <errno.h>21 #include <unistd.h>22 22 //-------------------- 23 // Basic types 24 struct cfathread_CRunner_t; 25 typedef struct cfathread_CRunner_t * cfathread_t; 23 26 24 27 //-------------------- 25 // Basic types 26 27 typedef struct cluster * cfathread_cluster_t; 28 29 int cfathread_cluster_create(cfathread_cluster_t * cluster); 30 cfathread_cluster_t cfathread_cluster_self(void); 31 int cfathread_cluster_print_stats(cfathread_cluster_t cluster); 32 int cfathread_cluster_add_worker(cfathread_cluster_t cluster, pthread_t* tid, void (*init_routine) (void *), void * arg); 33 int cfathread_cluster_pause (cfathread_cluster_t cluster); 34 int cfathread_cluster_resume(cfathread_cluster_t cluster); 35 36 //-------------------- 37 // thread attribute 38 typedef struct cfathread_attr { 39 cfathread_cluster_t cl; 40 } cfathread_attr_t; 41 42 int cfathread_attr_init(cfathread_attr_t * attr) __attribute__((nonnull (1))); 43 static inline int cfathread_attr_destroy(cfathread_attr_t * attr) __attribute__((nonnull (1))); 44 static inline int cfathread_attr_destroy(cfathread_attr_t * attr) { return 0; } 45 static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) __attribute__((nonnull (1))); 46 static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) { return 0; } 47 static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) __attribute__((nonnull (1))); 48 static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) { attr->cl = cl; return 0; } 49 50 //-------------------- 51 // thread type 52 struct cfathread_object; 53 typedef struct cfathread_object * cfathread_t; 54 55 int cfathread_create( cfathread_t * h, const cfathread_attr_t * a, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1))); 56 int cfathread_join( cfathread_t, void ** retval ); 57 58 int cfathread_get_errno(void); 59 cfathread_t cfathread_self(void); 60 61 int cfathread_usleep(useconds_t usecs); 62 int cfathread_sleep(unsigned int secs); 28 // Basic thread support 29 cfathread_t cfathread_create( void (*main)( cfathread_t ) ); 30 void cfathread_join( cfathread_t ); 63 31 64 32 void cfathread_park( void ); … … 67 35 68 36 //-------------------- 69 // mutex and condition70 struct timespec;37 // Basic kernel features 38 void cfathread_setproccnt( int ); 71 39 72 typedef struct cfathread_mutex_attr {73 } cfathread_mutexattr_t;74 typedef struct cfathread_mutex * cfathread_mutex_t;75 int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1)));76 int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1)));77 int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));78 int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));79 int cfathread_mutex_unlock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));80 81 typedef struct cfathread_cond_attr {82 } cfathread_condattr_t;83 typedef struct cfathread_condition * cfathread_cond_t;84 int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict attr) __attribute__((nonnull (1)));85 int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2)));86 int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3)));87 int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1)));88 89 //--------------------90 // IO operations91 struct sockaddr;92 struct msghdr;93 int cfathread_socket(int domain, int type, int protocol);94 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len);95 int cfathread_listen(int socket, int backlog);96 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);97 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len);98 int cfathread_dup(int fildes);99 int cfathread_close(int fildes);100 ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags);101 ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte);102 ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);103 ssize_t cfathread_read(int fildes, void *buf, size_t nbyte);104 40 105 41 #if defined(__cforall) || defined(__cplusplus) -
libcfa/src/concurrency/coroutine.cfa
r5407cdc rfeacef9 46 46 47 47 //----------------------------------------------------------------------------- 48 FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t)) 49 50 forall(T &) 51 void mark_exception(CoroutineCancelled(T) *) {} 52 48 53 forall(T &) 49 54 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { … … 60 65 // This code should not be inlined. It is the error path on resume. 61 66 forall(T & | is_coroutine(T)) 62 void __cfaehm_cancelled_coroutine( 63 T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) { 67 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) { 64 68 verify( desc->cancellation ); 65 69 desc->state = Cancelled; … … 68 72 // TODO: Remove explitate vtable set once trac#186 is fixed. 69 73 CoroutineCancelled(T) except; 70 except.virtual_table = & _default_vtable;74 except.virtual_table = &get_exception_vtable(&except); 71 75 except.the_coroutine = &cor; 72 76 except.the_exception = except; 73 // Why does this need a cast? 74 throwResume (CoroutineCancelled(T) &)except; 77 throwResume except; 75 78 76 79 except->virtual_table->free( except ); … … 145 148 // Part of the Public API 146 149 // Not inline since only ever called once per coroutine 147 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })150 forall(T & | is_coroutine(T)) 148 151 void prime(T& cor) { 149 152 $coroutine* this = get_coroutine(cor); … … 193 196 194 197 void __stack_clean ( __stack_info_t * this ) { 198 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t); 195 199 void * storage = this->storage->limit; 196 200 197 201 #if CFA_COROUTINE_USE_MMAP 198 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);199 202 storage = (void *)(((intptr_t)storage) - __page_size); 200 203 if(munmap(storage, size + __page_size) == -1) { -
libcfa/src/concurrency/coroutine.hfa
r5407cdc rfeacef9 22 22 //----------------------------------------------------------------------------- 23 23 // Exception thrown from resume when a coroutine stack is cancelled. 24 EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) ( 25 25 coroutine_t * the_coroutine; 26 26 exception_t * the_exception; … … 60 60 //----------------------------------------------------------------------------- 61 61 // Public coroutine API 62 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })62 forall(T & | is_coroutine(T)) 63 63 void prime(T & cor); 64 64 … … 130 130 131 131 forall(T & | is_coroutine(T)) 132 void __cfaehm_cancelled_coroutine( 133 T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ); 132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ); 134 133 135 134 // Resume implementation inlined for performance 136 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })135 forall(T & | is_coroutine(T)) 137 136 static inline T & resume(T & cor) { 138 137 // optimization : read TLS once and reuse it … … 164 163 $ctx_switch( src, dst ); 165 164 if ( unlikely(dst->cancellation) ) { 166 __cfaehm_cancelled_coroutine( cor, dst , _default_vtable);165 __cfaehm_cancelled_coroutine( cor, dst ); 167 166 } 168 167 -
libcfa/src/concurrency/future.hfa
r5407cdc rfeacef9 37 37 38 38 // Fulfil the future, returns whether or not someone was unblocked 39 $thread *fulfil( future(T) & this, T result ) {39 bool fulfil( future(T) & this, T result ) { 40 40 this.result = result; 41 41 return fulfil( (future_t&)this ); … … 96 96 bool fulfil( multi_future(T) & this, T result ) { 97 97 this.result = result; 98 return fulfil( (future_t&)this ) != 0p;98 return fulfil( (future_t&)this ); 99 99 } 100 100 -
libcfa/src/concurrency/invoke.c
r5407cdc rfeacef9 34 34 35 35 extern void disable_interrupts() OPTIONAL_THREAD; 36 extern void enable_interrupts( _ Bool poll);36 extern void enable_interrupts( __cfaabi_dbg_ctx_param ); 37 37 38 38 void __cfactx_invoke_coroutine( … … 82 82 ) { 83 83 // Officially start the thread by enabling preemption 84 enable_interrupts( true);84 enable_interrupts( __cfaabi_dbg_ctx ); 85 85 86 86 // Call the main of the thread -
libcfa/src/concurrency/invoke.h
r5407cdc rfeacef9 148 148 struct $thread * prev; 149 149 volatile unsigned long long ts; 150 unsignedpreferred;150 int preferred; 151 151 }; 152 152 … … 200 200 } node; 201 201 202 struct processor * last_proc;203 204 202 #if defined( __CFA_WITH_VERIFY__ ) 205 203 void * canary; … … 226 224 } 227 225 228 static inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) {229 return this->seqable.next;230 }231 232 226 static inline $thread *& Back( $thread * this ) __attribute__((const)) { 233 227 return this->seqable.back; -
libcfa/src/concurrency/io.cfa
r5407cdc rfeacef9 32 32 extern "C" { 33 33 #include <sys/syscall.h> 34 #include <sys/eventfd.h>35 34 36 35 #include <linux/io_uring.h> … … 40 39 #include "kernel.hfa" 41 40 #include "kernel/fwd.hfa" 42 #include "kernel_private.hfa"43 41 #include "io/types.hfa" 44 42 … … 81 79 }; 82 80 83 static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want ); 84 static void __ioarbiter_submit( $io_context * , __u32 idxs[], __u32 have, bool lazy ); 85 static void __ioarbiter_flush ( $io_context & ); 86 static inline void __ioarbiter_notify( $io_context & ctx ); 81 // returns true of acquired as leader or second leader 82 static inline bool try_lock( __leaderlock_t & this ) { 83 const uintptr_t thrd = 1z | (uintptr_t)active_thread(); 84 bool block; 85 disable_interrupts(); 86 for() { 87 struct $thread * expected = this.value; 88 if( 1p != expected && 0p != expected ) { 89 /* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader 90 enable_interrupts( __cfaabi_dbg_ctx ); 91 return false; 92 } 93 struct $thread * desired; 94 if( 0p == expected ) { 95 // If the lock isn't locked acquire it, no need to block 96 desired = 1p; 97 block = false; 98 } 99 else { 100 // If the lock is already locked try becomming the next leader 101 desired = (struct $thread *)thrd; 102 block = true; 103 } 104 if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break; 105 } 106 if( block ) { 107 enable_interrupts( __cfaabi_dbg_ctx ); 108 park(); 109 disable_interrupts(); 110 } 111 return true; 112 } 113 114 static inline bool next( __leaderlock_t & this ) { 115 /* paranoid */ verify( ! __preemption_enabled() ); 116 struct $thread * nextt; 117 for() { 118 struct $thread * expected = this.value; 119 /* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked 120 121 struct $thread * desired; 122 if( 1p == expected ) { 123 // No next leader, just unlock 124 desired = 0p; 125 nextt = 0p; 126 } 127 else { 128 // There is a next leader, remove but keep locked 129 desired = 1p; 130 nextt = (struct $thread *)(~1z & (uintptr_t)expected); 131 } 132 if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break; 133 } 134 135 if(nextt) { 136 unpark( nextt ); 137 enable_interrupts( __cfaabi_dbg_ctx ); 138 return true; 139 } 140 enable_interrupts( __cfaabi_dbg_ctx ); 141 return false; 142 } 143 144 //============================================================================================= 145 // I/O Syscall 146 //============================================================================================= 147 static int __io_uring_enter( struct __io_data & ring, unsigned to_submit, bool get ) { 148 bool need_sys_to_submit = false; 149 bool need_sys_to_complete = false; 150 unsigned flags = 0; 151 152 TO_SUBMIT: 153 if( to_submit > 0 ) { 154 if( !(ring.ring_flags & IORING_SETUP_SQPOLL) ) { 155 need_sys_to_submit = true; 156 break TO_SUBMIT; 157 } 158 if( (*ring.submit_q.flags) & IORING_SQ_NEED_WAKEUP ) { 159 need_sys_to_submit = true; 160 flags |= IORING_ENTER_SQ_WAKEUP; 161 } 162 } 163 164 if( get && !(ring.ring_flags & IORING_SETUP_SQPOLL) ) { 165 flags |= IORING_ENTER_GETEVENTS; 166 if( (ring.ring_flags & IORING_SETUP_IOPOLL) ) { 167 need_sys_to_complete = true; 168 } 169 } 170 171 int ret = 0; 172 if( need_sys_to_submit || need_sys_to_complete ) { 173 __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING enter %d %u %u\n", ring.fd, to_submit, flags); 174 ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, 0, flags, (sigset_t *)0p, _NSIG / 8); 175 __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING %d returned %d\n", ring.fd, ret); 176 177 if( ret < 0 ) { 178 switch((int)errno) { 179 case EAGAIN: 180 case EINTR: 181 case EBUSY: 182 ret = -1; 183 break; 184 default: 185 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) ); 186 } 187 } 188 } 189 190 // Memory barrier 191 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 192 return ret; 193 } 194 87 195 //============================================================================================= 88 196 // I/O Polling 89 197 //============================================================================================= 90 static inline unsigned __flush( struct $io_context & ); 91 static inline __u32 __release_sqes( struct $io_context & ); 92 extern void __kernel_unpark( $thread * thrd ); 93 94 bool __cfa_io_drain( processor * proc ) { 198 static unsigned __collect_submitions( struct __io_data & ring ); 199 static __u32 __release_consumed_submission( struct __io_data & ring ); 200 static inline void __clean( volatile struct io_uring_sqe * sqe ); 201 202 // Process a single completion message from the io_uring 203 // This is NOT thread-safe 204 static inline void process( volatile struct io_uring_cqe & cqe ) { 205 struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data; 206 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future ); 207 208 fulfil( *future, cqe.res ); 209 } 210 211 static [int, bool] __drain_io( & struct __io_data ring ) { 95 212 /* paranoid */ verify( ! __preemption_enabled() ); 96 /* paranoid */ verify( ready_schedule_islocked() ); 97 /* paranoid */ verify( proc ); 98 /* paranoid */ verify( proc->io.ctx ); 213 214 unsigned to_submit = 0; 215 if( ring.poller_submits ) { 216 // If the poller thread also submits, then we need to aggregate the submissions which are ready 217 to_submit = __collect_submitions( ring ); 218 } 219 220 int ret = __io_uring_enter(ring, to_submit, true); 221 if( ret < 0 ) { 222 return [0, true]; 223 } 224 225 // update statistics 226 if (to_submit > 0) { 227 __STATS__( true, 228 if( to_submit > 0 ) { 229 io.submit_q.submit_avg.rdy += to_submit; 230 io.submit_q.submit_avg.csm += ret; 231 io.submit_q.submit_avg.cnt += 1; 232 } 233 ) 234 } 235 236 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 237 238 // Release the consumed SQEs 239 __release_consumed_submission( ring ); 99 240 100 241 // Drain the queue 101 $io_context * ctx = proc->io.ctx; 102 unsigned head = *ctx->cq.head; 103 unsigned tail = *ctx->cq.tail; 104 const __u32 mask = *ctx->cq.mask; 242 unsigned head = *ring.completion_q.head; 243 unsigned tail = *ring.completion_q.tail; 244 const __u32 mask = *ring.completion_q.mask; 245 246 // Nothing was new return 0 247 if (head == tail) { 248 return [0, to_submit > 0]; 249 } 105 250 106 251 __u32 count = tail - head; 107 __STATS__( false, io.calls.drain++; io.calls.completed += count; ) 108 109 if(count == 0) return false; 110 252 /* paranoid */ verify( count != 0 ); 111 253 for(i; count) { 112 254 unsigned idx = (head + i) & mask; 113 volatile struct io_uring_cqe & cqe = ctx->cq.cqes[idx];255 volatile struct io_uring_cqe & cqe = ring.completion_q.cqes[idx]; 114 256 115 257 /* paranoid */ verify(&cqe); 116 258 117 struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data; 118 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future ); 119 120 __kernel_unpark( fulfil( *future, cqe.res, false ) ); 121 } 122 123 __cfadbg_print_safe(io, "Kernel I/O : %u completed\n", count); 259 process( cqe ); 260 } 124 261 125 262 // Mark to the kernel that the cqe has been seen 126 263 // Ensure that the kernel only sees the new value of the head index after the CQEs have been read. 127 __atomic_store_n( ctx->cq.head, head + count, __ATOMIC_SEQ_CST ); 128 129 /* paranoid */ verify( ready_schedule_islocked() ); 130 /* paranoid */ verify( ! __preemption_enabled() ); 131 132 return true; 133 } 134 135 void __cfa_io_flush( processor * proc ) { 136 /* paranoid */ verify( ! __preemption_enabled() ); 137 /* paranoid */ verify( proc ); 138 /* paranoid */ verify( proc->io.ctx ); 139 140 $io_context & ctx = *proc->io.ctx; 141 142 __ioarbiter_flush( ctx ); 143 144 __STATS__( true, io.calls.flush++; ) 145 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0, 0, (sigset_t *)0p, _NSIG / 8); 146 if( ret < 0 ) { 147 switch((int)errno) { 148 case EAGAIN: 149 case EINTR: 150 case EBUSY: 264 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_SEQ_CST ); 265 266 return [count, count > 0 || to_submit > 0]; 267 } 268 269 void main( $io_ctx_thread & this ) { 270 __ioctx_register( this ); 271 272 __cfadbg_print_safe(io_core, "Kernel I/O : IO poller %d (%p) ready\n", this.ring->fd, &this); 273 274 const int reset_cnt = 5; 275 int reset = reset_cnt; 276 // Then loop until we need to start 277 LOOP: 278 while(!__atomic_load_n(&this.done, __ATOMIC_SEQ_CST)) { 279 // Drain the io 280 int count; 281 bool again; 282 disable_interrupts(); 283 [count, again] = __drain_io( *this.ring ); 284 285 if(!again) reset--; 286 151 287 // Update statistics 152 __STATS__( false, io.calls.errors.busy ++; ) 153 return; 154 default: 155 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) ); 156 } 157 } 158 159 __cfadbg_print_safe(io, "Kernel I/O : %u submitted to io_uring %d\n", ret, ctx.fd); 160 __STATS__( true, io.calls.submitted += ret; ) 161 /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num ); 162 /* paranoid */ verify( ctx.sq.to_submit >= ret ); 163 164 ctx.sq.to_submit -= ret; 165 166 /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num ); 167 168 // Release the consumed SQEs 169 __release_sqes( ctx ); 170 171 /* paranoid */ verify( ! __preemption_enabled() ); 172 173 ctx.proc->io.pending = false; 288 __STATS__( true, 289 io.complete_q.completed_avg.val += count; 290 io.complete_q.completed_avg.cnt += 1; 291 ) 292 enable_interrupts( __cfaabi_dbg_ctx ); 293 294 // If we got something, just yield and check again 295 if(reset > 1) { 296 yield(); 297 continue LOOP; 298 } 299 300 // We alread failed to find completed entries a few time. 301 if(reset == 1) { 302 // Rearm the context so it can block 303 // but don't block right away 304 // we need to retry one last time in case 305 // something completed *just now* 306 __ioctx_prepare_block( this ); 307 continue LOOP; 308 } 309 310 __STATS__( false, 311 io.complete_q.blocks += 1; 312 ) 313 __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %d (%p)\n", this.ring->fd, &this); 314 315 // block this thread 316 wait( this.sem ); 317 318 // restore counter 319 reset = reset_cnt; 320 } 321 322 __cfadbg_print_safe(io_core, "Kernel I/O : Fast poller %d (%p) stopping\n", this.ring->fd, &this); 323 324 __ioctx_unregister( this ); 174 325 } 175 326 … … 193 344 // head and tail must be fully filled and shouldn't ever be touched again. 194 345 // 195 //=============================================================================================196 // Allocation197 // for user's convenience fill the sqes from the indexes198 static inline void __fill(struct io_uring_sqe * out_sqes[], __u32 want, __u32 idxs[], struct $io_context * ctx) {199 struct io_uring_sqe * sqes = ctx->sq.sqes;200 for(i; want) {201 __cfadbg_print_safe(io, "Kernel I/O : filling loop\n");202 out_sqes[i] = &sqes[idxs[i]];203 }204 }205 206 // Try to directly allocate from the a given context207 // Not thread-safe208 static inline bool __alloc(struct $io_context * ctx, __u32 idxs[], __u32 want) {209 __sub_ring_t & sq = ctx->sq;210 const __u32 mask = *sq.mask;211 __u32 fhead = sq.free_ring.head; // get the current head of the queue212 __u32 ftail = sq.free_ring.tail; // get the current tail of the queue213 214 // If we don't have enough sqes, fail215 if((ftail - fhead) < want) { return false; }216 217 // copy all the indexes we want from the available list218 for(i; want) {219 __cfadbg_print_safe(io, "Kernel I/O : allocating loop\n");220 idxs[i] = sq.free_ring.array[(fhead + i) & mask];221 }222 223 // Advance the head to mark the indexes as consumed224 __atomic_store_n(&sq.free_ring.head, fhead + want, __ATOMIC_RELEASE);225 226 // return success227 return true;228 }229 346 230 347 // Allocate an submit queue entry. … … 233 350 // for convenience, return both the index and the pointer to the sqe 234 351 // sqe == &sqes[idx] 235 struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) { 236 __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want); 237 238 disable_interrupts(); 239 processor * proc = __cfaabi_tls.this_processor; 240 $io_context * ctx = proc->io.ctx; 241 /* paranoid */ verify( __cfaabi_tls.this_processor ); 242 /* paranoid */ verify( ctx ); 243 244 __cfadbg_print_safe(io, "Kernel I/O : attempting to fast allocation\n"); 245 246 // We can proceed to the fast path 247 if( __alloc(ctx, idxs, want) ) { 248 // Allocation was successful 249 __STATS__( true, io.alloc.fast += 1; ) 250 enable_interrupts(); 251 252 __cfadbg_print_safe(io, "Kernel I/O : fast allocation successful from ring %d\n", ctx->fd); 253 254 __fill( sqes, want, idxs, ctx ); 255 return ctx; 256 } 257 // The fast path failed, fallback 258 __STATS__( true, io.alloc.fail += 1; ) 259 260 // Fast path failed, fallback on arbitration 261 __STATS__( true, io.alloc.slow += 1; ) 262 enable_interrupts(); 263 264 $io_arbiter * ioarb = proc->cltr->io.arbiter; 265 /* paranoid */ verify( ioarb ); 266 267 __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for allocation\n"); 268 269 struct $io_context * ret = __ioarbiter_allocate(*ioarb, idxs, want); 270 271 __cfadbg_print_safe(io, "Kernel I/O : slow allocation completed from ring %d\n", ret->fd); 272 273 __fill( sqes, want, idxs,ret ); 274 return ret; 275 } 276 277 278 //============================================================================================= 279 // submission 280 static inline void __submit( struct $io_context * ctx, __u32 idxs[], __u32 have, bool lazy) { 281 // We can proceed to the fast path 282 // Get the right objects 283 __sub_ring_t & sq = ctx->sq; 284 const __u32 mask = *sq.mask; 285 __u32 tail = *sq.kring.tail; 286 287 // Add the sqes to the array 288 for( i; have ) { 289 __cfadbg_print_safe(io, "Kernel I/O : __submit loop\n"); 290 sq.kring.array[ (tail + i) & mask ] = idxs[i]; 291 } 292 293 // Make the sqes visible to the submitter 294 __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE); 295 sq.to_submit++; 296 297 ctx->proc->io.pending = true; 298 ctx->proc->io.dirty = true; 299 if(sq.to_submit > 30 || !lazy) { 300 __cfa_io_flush( ctx->proc ); 301 } 302 } 303 304 void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) { 305 __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager"); 306 307 disable_interrupts(); 308 processor * proc = __cfaabi_tls.this_processor; 309 $io_context * ctx = proc->io.ctx; 310 /* paranoid */ verify( __cfaabi_tls.this_processor ); 311 /* paranoid */ verify( ctx ); 312 313 // Can we proceed to the fast path 314 if( ctx == inctx ) // We have the right instance? 352 [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) { 353 /* paranoid */ verify( data != 0 ); 354 355 // Prepare the data we need 356 __attribute((unused)) int len = 0; 357 __attribute((unused)) int block = 0; 358 __u32 cnt = *ring.submit_q.num; 359 __u32 mask = *ring.submit_q.mask; 360 361 __u32 off = thread_rand(); 362 363 // Loop around looking for an available spot 364 for() { 365 // Look through the list starting at some offset 366 for(i; cnt) { 367 __u64 expected = 3; 368 __u32 idx = (i + off) & mask; // Get an index from a random 369 volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx]; 370 volatile __u64 * udata = &sqe->user_data; 371 372 // Allocate the entry by CASing the user_data field from 0 to the future address 373 if( *udata == expected && 374 __atomic_compare_exchange_n( udata, &expected, data, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) 375 { 376 // update statistics 377 __STATS__( false, 378 io.submit_q.alloc_avg.val += len; 379 io.submit_q.alloc_avg.block += block; 380 io.submit_q.alloc_avg.cnt += 1; 381 ) 382 383 // debug log 384 __cfadbg_print_safe( io, "Kernel I/O : allocated [%p, %u] for %p (%p)\n", sqe, idx, active_thread(), (void*)data ); 385 386 // Success return the data 387 return [sqe, idx]; 388 } 389 verify(expected != data); 390 391 // This one was used 392 len ++; 393 } 394 395 block++; 396 397 yield(); 398 } 399 } 400 401 static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) { 402 /* paranoid */ verify( idx <= mask ); 403 /* paranoid */ verify( idx != -1ul32 ); 404 405 // We need to find a spot in the ready array 406 __attribute((unused)) int len = 0; 407 __attribute((unused)) int block = 0; 408 __u32 ready_mask = ring.submit_q.ready_cnt - 1; 409 410 __u32 off = thread_rand(); 411 412 __u32 picked; 413 LOOKING: for() { 414 for(i; ring.submit_q.ready_cnt) { 415 picked = (i + off) & ready_mask; 416 __u32 expected = -1ul32; 417 if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) { 418 break LOOKING; 419 } 420 verify(expected != idx); 421 422 len ++; 423 } 424 425 block++; 426 427 __u32 released = __release_consumed_submission( ring ); 428 if( released == 0 ) { 429 yield(); 430 } 431 } 432 433 // update statistics 434 __STATS__( false, 435 io.submit_q.look_avg.val += len; 436 io.submit_q.look_avg.block += block; 437 io.submit_q.look_avg.cnt += 1; 438 ) 439 440 return picked; 441 } 442 443 void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) { 444 __io_data & ring = *ctx->thrd.ring; 445 315 446 { 316 __submit(ctx, idxs, have, lazy); 317 318 // Mark the instance as no longer in-use, re-enable interrupts and return 319 __STATS__( true, io.submit.fast += 1; ) 320 enable_interrupts(); 321 322 __cfadbg_print_safe(io, "Kernel I/O : submitted on fast path\n"); 323 return; 324 } 325 326 // Fast path failed, fallback on arbitration 327 __STATS__( true, io.submit.slow += 1; ) 328 enable_interrupts(); 329 330 __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for submission\n"); 331 332 __ioarbiter_submit(inctx, idxs, have, lazy); 333 } 334 335 //============================================================================================= 336 // Flushing 447 __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx]; 448 __cfadbg_print_safe( io, 449 "Kernel I/O : submitting %u (%p) for %p\n" 450 " data: %p\n" 451 " opcode: %s\n" 452 " fd: %d\n" 453 " flags: %d\n" 454 " prio: %d\n" 455 " off: %p\n" 456 " addr: %p\n" 457 " len: %d\n" 458 " other flags: %d\n" 459 " splice fd: %d\n" 460 " pad[0]: %llu\n" 461 " pad[1]: %llu\n" 462 " pad[2]: %llu\n", 463 idx, sqe, 464 active_thread(), 465 (void*)sqe->user_data, 466 opcodes[sqe->opcode], 467 sqe->fd, 468 sqe->flags, 469 sqe->ioprio, 470 (void*)sqe->off, 471 (void*)sqe->addr, 472 sqe->len, 473 sqe->accept_flags, 474 sqe->splice_fd_in, 475 sqe->__pad2[0], 476 sqe->__pad2[1], 477 sqe->__pad2[2] 478 ); 479 } 480 481 482 // Get now the data we definetely need 483 volatile __u32 * const tail = ring.submit_q.tail; 484 const __u32 mask = *ring.submit_q.mask; 485 486 // There are 2 submission schemes, check which one we are using 487 if( ring.poller_submits ) { 488 // If the poller thread submits, then we just need to add this to the ready array 489 __submit_to_ready_array( ring, idx, mask ); 490 491 post( ctx->thrd.sem ); 492 493 __cfadbg_print_safe( io, "Kernel I/O : Added %u to ready for %p\n", idx, active_thread() ); 494 } 495 else if( ring.eager_submits ) { 496 __attribute__((unused)) __u32 picked = __submit_to_ready_array( ring, idx, mask ); 497 498 #if defined(LEADER_LOCK) 499 if( !try_lock(ring.submit_q.submit_lock) ) { 500 __STATS__( false, 501 io.submit_q.helped += 1; 502 ) 503 return; 504 } 505 /* paranoid */ verify( ! __preemption_enabled() ); 506 __STATS__( true, 507 io.submit_q.leader += 1; 508 ) 509 #else 510 for() { 511 yield(); 512 513 if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) { 514 __STATS__( false, 515 io.submit_q.leader += 1; 516 ) 517 break; 518 } 519 520 // If some one else collected our index, we are done 521 #warning ABA problem 522 if( ring.submit_q.ready[picked] != idx ) { 523 __STATS__( false, 524 io.submit_q.helped += 1; 525 ) 526 return; 527 } 528 529 __STATS__( false, 530 io.submit_q.busy += 1; 531 ) 532 } 533 #endif 534 535 // We got the lock 536 // Collect the submissions 537 unsigned to_submit = __collect_submitions( ring ); 538 539 // Actually submit 540 int ret = __io_uring_enter( ring, to_submit, false ); 541 542 #if defined(LEADER_LOCK) 543 /* paranoid */ verify( ! __preemption_enabled() ); 544 next(ring.submit_q.submit_lock); 545 #else 546 unlock(ring.submit_q.submit_lock); 547 #endif 548 if( ret < 0 ) { 549 return; 550 } 551 552 // Release the consumed SQEs 553 __release_consumed_submission( ring ); 554 555 // update statistics 556 __STATS__( false, 557 io.submit_q.submit_avg.rdy += to_submit; 558 io.submit_q.submit_avg.csm += ret; 559 io.submit_q.submit_avg.cnt += 1; 560 ) 561 562 __cfadbg_print_safe( io, "Kernel I/O : submitted %u (among %u) for %p\n", idx, ret, active_thread() ); 563 } 564 else 565 { 566 // get mutual exclusion 567 #if defined(LEADER_LOCK) 568 while(!try_lock(ring.submit_q.submit_lock)); 569 #else 570 lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2); 571 #endif 572 573 /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 3ul64, 574 /* paranoid */ "index %u already reclaimed\n" 575 /* paranoid */ "head %u, prev %u, tail %u\n" 576 /* paranoid */ "[-0: %u,-1: %u,-2: %u,-3: %u]\n", 577 /* paranoid */ idx, 578 /* paranoid */ *ring.submit_q.head, ring.submit_q.prev_head, *tail 579 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 0) & (*ring.submit_q.mask) ] 580 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 1) & (*ring.submit_q.mask) ] 581 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 2) & (*ring.submit_q.mask) ] 582 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 3) & (*ring.submit_q.mask) ] 583 /* paranoid */ ); 584 585 // Append to the list of ready entries 586 587 /* paranoid */ verify( idx <= mask ); 588 ring.submit_q.array[ (*tail) & mask ] = idx; 589 __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST); 590 591 // Submit however, many entries need to be submitted 592 int ret = __io_uring_enter( ring, 1, false ); 593 if( ret < 0 ) { 594 switch((int)errno) { 595 default: 596 abort( "KERNEL ERROR: IO_URING SUBMIT - %s\n", strerror(errno) ); 597 } 598 } 599 600 /* paranoid */ verify(ret == 1); 601 602 // update statistics 603 __STATS__( false, 604 io.submit_q.submit_avg.csm += 1; 605 io.submit_q.submit_avg.cnt += 1; 606 ) 607 608 { 609 __attribute__((unused)) volatile __u32 * const head = ring.submit_q.head; 610 __attribute__((unused)) __u32 last_idx = ring.submit_q.array[ ((*head) - 1) & mask ]; 611 __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[last_idx]; 612 613 __cfadbg_print_safe( io, 614 "Kernel I/O : last submitted is %u (%p)\n" 615 " data: %p\n" 616 " opcode: %s\n" 617 " fd: %d\n" 618 " flags: %d\n" 619 " prio: %d\n" 620 " off: %p\n" 621 " addr: %p\n" 622 " len: %d\n" 623 " other flags: %d\n" 624 " splice fd: %d\n" 625 " pad[0]: %llu\n" 626 " pad[1]: %llu\n" 627 " pad[2]: %llu\n", 628 last_idx, sqe, 629 (void*)sqe->user_data, 630 opcodes[sqe->opcode], 631 sqe->fd, 632 sqe->flags, 633 sqe->ioprio, 634 (void*)sqe->off, 635 (void*)sqe->addr, 636 sqe->len, 637 sqe->accept_flags, 638 sqe->splice_fd_in, 639 sqe->__pad2[0], 640 sqe->__pad2[1], 641 sqe->__pad2[2] 642 ); 643 } 644 645 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 646 // Release the consumed SQEs 647 648 __release_consumed_submission( ring ); 649 // ring.submit_q.sqes[idx].user_data = 3ul64; 650 651 #if defined(LEADER_LOCK) 652 next(ring.submit_q.submit_lock); 653 #else 654 unlock(ring.submit_q.submit_lock); 655 #endif 656 657 __cfadbg_print_safe( io, "Kernel I/O : submitted %u for %p\n", idx, active_thread() ); 658 } 659 } 660 661 // #define PARTIAL_SUBMIT 32 662 663 // go through the list of submissions in the ready array and moved them into 664 // the ring's submit queue 665 static unsigned __collect_submitions( struct __io_data & ring ) { 666 /* paranoid */ verify( ring.submit_q.ready != 0p ); 667 /* paranoid */ verify( ring.submit_q.ready_cnt > 0 ); 668 669 unsigned to_submit = 0; 670 __u32 tail = *ring.submit_q.tail; 671 const __u32 mask = *ring.submit_q.mask; 672 #if defined(PARTIAL_SUBMIT) 673 #if defined(LEADER_LOCK) 674 #error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist 675 #endif 676 const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt; 677 const __u32 offset = ring.submit_q.prev_ready; 678 ring.submit_q.prev_ready += cnt; 679 #else 680 const __u32 cnt = ring.submit_q.ready_cnt; 681 const __u32 offset = 0; 682 #endif 683 684 // Go through the list of ready submissions 685 for( c; cnt ) { 686 __u32 i = (offset + c) % ring.submit_q.ready_cnt; 687 688 // replace any submission with the sentinel, to consume it. 689 __u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED); 690 691 // If it was already the sentinel, then we are done 692 if( idx == -1ul32 ) continue; 693 694 // If we got a real submission, append it to the list 695 ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask; 696 to_submit++; 697 } 698 699 // Increment the tail based on how many we are ready to submit 700 __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST); 701 702 return to_submit; 703 } 704 337 705 // Go through the ring's submit queue and release everything that has already been consumed 338 706 // by io_uring 339 // This cannot be done by multiple threads 340 static __u32 __release_sqes( struct $io_context & ctx ) { 341 const __u32 mask = *ctx.sq.mask; 342 707 static __u32 __release_consumed_submission( struct __io_data & ring ) { 708 const __u32 smask = *ring.submit_q.mask; 709 710 // We need to get the lock to copy the old head and new head 711 if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0; 343 712 __attribute__((unused)) 344 __u32 ctail = * ctx.sq.kring.tail;// get the current tail of the queue345 __u32 chead = * ctx.sq.kring.head;// get the current head of the queue346 __u32 phead = ctx.sq.kring.released;// get the head the last time we were here347 348 __u32 ftail = ctx.sq.free_ring.tail; // get the current tail of the queue713 __u32 ctail = *ring.submit_q.tail; // get the current tail of the queue 714 __u32 chead = *ring.submit_q.head; // get the current head of the queue 715 __u32 phead = ring.submit_q.prev_head; // get the head the last time we were here 716 ring.submit_q.prev_head = chead; // note up to were we processed 717 unlock(ring.submit_q.release_lock); 349 718 350 719 // the 3 fields are organized like this diagram … … 365 734 __u32 count = chead - phead; 366 735 367 if(count == 0) {368 return 0;369 }370 371 736 // We acquired an previous-head/current-head range 372 737 // go through the range and release the sqes 373 738 for( i; count ) { 374 __cfadbg_print_safe(io, "Kernel I/O : release loop\n"); 375 __u32 idx = ctx.sq.kring.array[ (phead + i) & mask ]; 376 ctx.sq.free_ring.array[ (ftail + i) & mask ] = idx; 377 } 378 379 ctx.sq.kring.released = chead; // note up to were we processed 380 __atomic_store_n(&ctx.sq.free_ring.tail, ftail + count, __ATOMIC_SEQ_CST); 381 382 __ioarbiter_notify(ctx); 383 739 __u32 idx = ring.submit_q.array[ (phead + i) & smask ]; 740 741 /* paranoid */ verify( 0 != ring.submit_q.sqes[ idx ].user_data ); 742 __clean( &ring.submit_q.sqes[ idx ] ); 743 } 384 744 return count; 385 745 } 386 746 387 //============================================================================================= 388 // I/O Arbiter 389 //============================================================================================= 390 static inline void block(__outstanding_io_queue & queue, __outstanding_io & item) { 391 // Lock the list, it's not thread safe 392 lock( queue.lock __cfaabi_dbg_ctx2 ); 393 { 394 // Add our request to the list 395 add( queue.queue, item ); 396 397 // Mark as pending 398 __atomic_store_n( &queue.empty, false, __ATOMIC_SEQ_CST ); 399 } 400 unlock( queue.lock ); 401 402 wait( item.sem ); 403 } 404 405 static inline bool empty(__outstanding_io_queue & queue ) { 406 return __atomic_load_n( &queue.empty, __ATOMIC_SEQ_CST); 407 } 408 409 static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want ) { 410 __cfadbg_print_safe(io, "Kernel I/O : arbiter allocating\n"); 411 412 __STATS__( false, io.alloc.block += 1; ) 413 414 // No one has any resources left, wait for something to finish 415 // We need to add ourself to a list of pending allocs and wait for an answer 416 __pending_alloc pa; 417 pa.idxs = idxs; 418 pa.want = want; 419 420 block(this.pending, (__outstanding_io&)pa); 421 422 return pa.ctx; 423 424 } 425 426 static void __ioarbiter_notify( $io_arbiter & this, $io_context * ctx ) { 427 /* paranoid */ verify( !empty(this.pending.queue) ); 428 429 lock( this.pending.lock __cfaabi_dbg_ctx2 ); 430 { 431 while( !empty(this.pending.queue) ) { 432 __cfadbg_print_safe(io, "Kernel I/O : notifying\n"); 433 __u32 have = ctx->sq.free_ring.tail - ctx->sq.free_ring.head; 434 __pending_alloc & pa = (__pending_alloc&)head( this.pending.queue ); 435 436 if( have > pa.want ) goto DONE; 437 drop( this.pending.queue ); 438 439 /* paranoid */__attribute__((unused)) bool ret = 440 441 __alloc(ctx, pa.idxs, pa.want); 442 443 /* paranoid */ verify( ret ); 444 445 pa.ctx = ctx; 446 447 post( pa.sem ); 448 } 449 450 this.pending.empty = true; 451 DONE:; 452 } 453 unlock( this.pending.lock ); 454 } 455 456 static void __ioarbiter_notify( $io_context & ctx ) { 457 if(!empty( ctx.arbiter->pending )) { 458 __ioarbiter_notify( *ctx.arbiter, &ctx ); 459 } 460 } 461 462 // Simply append to the pending 463 static void __ioarbiter_submit( $io_context * ctx, __u32 idxs[], __u32 have, bool lazy ) { 464 __cfadbg_print_safe(io, "Kernel I/O : submitting %u from the arbiter to context %u\n", have, ctx->fd); 465 466 __cfadbg_print_safe(io, "Kernel I/O : waiting to submit %u\n", have); 467 468 __external_io ei; 469 ei.idxs = idxs; 470 ei.have = have; 471 ei.lazy = lazy; 472 473 block(ctx->ext_sq, (__outstanding_io&)ei); 474 475 __cfadbg_print_safe(io, "Kernel I/O : %u submitted from arbiter\n", have); 476 } 477 478 static void __ioarbiter_flush( $io_context & ctx ) { 479 if(!empty( ctx.ext_sq )) { 480 __STATS__( false, io.flush.external += 1; ) 481 482 __cfadbg_print_safe(io, "Kernel I/O : arbiter flushing\n"); 483 484 lock( ctx.ext_sq.lock __cfaabi_dbg_ctx2 ); 485 { 486 while( !empty(ctx.ext_sq.queue) ) { 487 __external_io & ei = (__external_io&)drop( ctx.ext_sq.queue ); 488 489 __submit(&ctx, ei.idxs, ei.have, ei.lazy); 490 491 post( ei.sem ); 492 } 493 494 ctx.ext_sq.empty = true; 495 } 496 unlock(ctx.ext_sq.lock ); 497 } 747 void __sqe_clean( volatile struct io_uring_sqe * sqe ) { 748 __clean( sqe ); 749 } 750 751 static inline void __clean( volatile struct io_uring_sqe * sqe ) { 752 // If we are in debug mode, thrash the fields to make sure we catch reclamation errors 753 __cfaabi_dbg_debug_do( 754 memset(sqe, 0xde, sizeof(*sqe)); 755 sqe->opcode = (sizeof(opcodes) / sizeof(const char *)) - 1; 756 ); 757 758 // Mark the entry as unused 759 __atomic_store_n(&sqe->user_data, 3ul64, __ATOMIC_SEQ_CST); 498 760 } 499 761 #endif -
libcfa/src/concurrency/io/call.cfa.in
r5407cdc rfeacef9 54 54 | IOSQE_IO_DRAIN 55 55 #endif 56 #if defined(CFA_HAVE_IOSQE_ASYNC) 57 | IOSQE_ASYNC 58 #endif 59 ; 60 61 static const __u32 LINK_FLAGS = 0 56 62 #if defined(CFA_HAVE_IOSQE_IO_LINK) 57 63 | IOSQE_IO_LINK … … 60 66 | IOSQE_IO_HARDLINK 61 67 #endif 62 #if defined(CFA_HAVE_IOSQE_ASYNC)63 | IOSQE_ASYNC64 #endif65 #if defined(CFA_HAVE_IOSQE_BUFFER_SELECTED)66 | IOSQE_BUFFER_SELECTED67 #endif68 68 ; 69 69 … … 74 74 ; 75 75 76 extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want) __attribute__((nonnull (1,2))); 77 extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2))); 76 extern [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ); 77 extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))); 78 79 static inline io_context * __get_io_context( void ) { 80 cluster * cltr = active_cluster(); 81 82 /* paranoid */ verifyf( cltr, "No active cluster for io operation\\n"); 83 assertf( cltr->io.cnt > 0, "Cluster %p has no default io contexts and no context was specified\\n", cltr ); 84 85 /* paranoid */ verifyf( cltr->io.ctxs, "default io contexts for cluster %p are missing\\n", cltr); 86 return &cltr->io.ctxs[ thread_rand() % cltr->io.cnt ]; 87 } 78 88 #endif 79 89 … … 88 98 89 99 extern "C" { 90 #include < asm/types.h>100 #include <sys/types.h> 91 101 #include <sys/socket.h> 92 102 #include <sys/syscall.h> … … 132 142 extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 133 143 134 extern ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags);144 extern ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags); 135 145 extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags); 136 146 } … … 185 195 return ', '.join(args_a) 186 196 187 AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, __u64 submit_flags) {{197 AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context) {{ 188 198 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_{op}) 189 199 ssize_t res = {name}({args}); … … 195 205 }} 196 206 #else 207 // we don't support LINK yet 208 if( 0 != (submit_flags & LINK_FLAGS) ) {{ 209 errno = ENOTSUP; return -1; 210 }} 211 212 if( !context ) {{ 213 context = __get_io_context(); 214 }} 215 if(cancellation) {{ 216 cancellation->target = (__u64)(uintptr_t)&future; 217 }} 218 197 219 __u8 sflags = REGULAR_FLAGS & submit_flags; 220 struct __io_data & ring = *context->thrd.ring; 221 198 222 __u32 idx; 199 223 struct io_uring_sqe * sqe; 200 struct $io_context * ctx = cfa_io_allocate( &sqe, &idx, 1);224 [(volatile struct io_uring_sqe *) sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future ); 201 225 202 226 sqe->opcode = IORING_OP_{op}; 203 sqe->user_data = (uintptr_t)&future;204 227 sqe->flags = sflags; 205 228 sqe->ioprio = 0; … … 215 238 asm volatile("": : :"memory"); 216 239 217 verify( sqe->user_data == ( uintptr_t)&future );218 cfa_io_submit( ctx, &idx, 1, 0 != (submit_flags & CFA_IO_LAZY));240 verify( sqe->user_data == (__u64)(uintptr_t)&future ); 241 __submit( context, idx ); 219 242 #endif 220 243 }}""" 221 244 222 SyncTemplate = """{ret} cfa_{name}({params}, __u64 submit_flags) {{ 245 SyncTemplate = """{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {{ 246 if( timeout >= 0 ) {{ 247 errno = ENOTSUP; 248 return -1; 249 }} 223 250 io_future_t future; 224 251 225 async_{name}( future, {args}, submit_flags );252 async_{name}( future, {args}, submit_flags, cancellation, context ); 226 253 227 254 wait( future ); … … 238 265 'fd' : 'fd', 239 266 'off' : 'offset', 240 'addr': '( uintptr_t)iov',267 'addr': '(__u64)iov', 241 268 'len' : 'iovcnt', 242 269 }, define = 'CFA_HAVE_PREADV2'), … … 245 272 'fd' : 'fd', 246 273 'off' : 'offset', 247 'addr': '( uintptr_t)iov',274 'addr': '(__u64)iov', 248 275 'len' : 'iovcnt' 249 276 }, define = 'CFA_HAVE_PWRITEV2'), … … 257 284 'addr': 'fd', 258 285 'len': 'op', 259 'off': '( uintptr_t)event'286 'off': '(__u64)event' 260 287 }), 261 288 # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE … … 269 296 Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', { 270 297 'fd': 'sockfd', 271 'addr': '( uintptr_t)(struct msghdr *)msg',298 'addr': '(__u64)(struct msghdr *)msg', 272 299 'len': '1', 273 300 'msg_flags': 'flags' … … 276 303 Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', { 277 304 'fd': 'sockfd', 278 'addr': '( uintptr_t)(struct msghdr *)msg',305 'addr': '(__u64)(struct msghdr *)msg', 279 306 'len': '1', 280 307 'msg_flags': 'flags' … … 283 310 Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', { 284 311 'fd': 'sockfd', 285 'addr': '( uintptr_t)buf',312 'addr': '(__u64)buf', 286 313 'len': 'len', 287 314 'msg_flags': 'flags' … … 290 317 Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', { 291 318 'fd': 'sockfd', 292 'addr': '( uintptr_t)buf',319 'addr': '(__u64)buf', 293 320 'len': 'len', 294 321 'msg_flags': 'flags' … … 297 324 Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', { 298 325 'fd': 'sockfd', 299 'addr': '( uintptr_t)addr',300 'addr2': '( uintptr_t)addrlen',326 'addr': '(__u64)addr', 327 'addr2': '(__u64)addrlen', 301 328 'accept_flags': 'flags' 302 329 }), … … 304 331 Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', { 305 332 'fd': 'sockfd', 306 'addr': '( uintptr_t)addr',333 'addr': '(__u64)addr', 307 334 'off': 'addrlen' 308 335 }), … … 310 337 Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', { 311 338 'fd': 'fd', 312 'addr': '( uintptr_t)len',339 'addr': '(__u64)len', 313 340 'len': 'mode', 314 341 'off': 'offset' … … 323 350 # CFA_HAVE_IORING_OP_MADVISE 324 351 Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', { 325 'addr': '( uintptr_t)addr',352 'addr': '(__u64)addr', 326 353 'len': 'length', 327 354 'fadvise_advice': 'advice' … … 330 357 Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', { 331 358 'fd': 'dirfd', 332 'addr': '( uintptr_t)pathname',359 'addr': '(__u64)pathname', 333 360 'len': 'mode', 334 361 'open_flags': 'flags;' … … 339 366 'addr': 'pathname', 340 367 'len': 'sizeof(*how)', 341 'off': '( uintptr_t)how',368 'off': '(__u64)how', 342 369 }, define = 'CFA_HAVE_OPENAT2'), 343 370 # CFA_HAVE_IORING_OP_CLOSE … … 348 375 Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', { 349 376 'fd': 'dirfd', 350 'off': '( uintptr_t)statxbuf',377 'off': '(__u64)statxbuf', 351 378 'addr': 'pathname', 352 379 'len': 'mask', … … 356 383 Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', { 357 384 'fd': 'fd', 358 'addr': '( uintptr_t)buf',385 'addr': '(__u64)buf', 359 386 'len': 'count' 360 387 }), … … 362 389 Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', { 363 390 'fd': 'fd', 364 'addr': '( uintptr_t)buf',391 'addr': '(__u64)buf', 365 392 'len': 'count' 366 393 }), 367 394 # CFA_HAVE_IORING_OP_SPLICE 368 Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags)', {395 Call('SPLICE', 'ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)', { 369 396 'splice_fd_in': 'fd_in', 370 397 'splice_off_in': 'off_in ? (__u64)*off_in : (__u64)-1', … … 388 415 if c.define: 389 416 print("""#if defined({define}) 390 {ret} cfa_{name}({params}, __u64 submit_flags);417 {ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 391 418 #endif""".format(define=c.define,ret=c.ret, name=c.name, params=c.params)) 392 419 else: 393 print("{ret} cfa_{name}({params}, __u64 submit_flags);"420 print("{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);" 394 421 .format(ret=c.ret, name=c.name, params=c.params)) 395 422 … … 399 426 if c.define: 400 427 print("""#if defined({define}) 401 void async_{name}(io_future_t & future, {params}, __u64 submit_flags);428 void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context); 402 429 #endif""".format(define=c.define,name=c.name, params=c.params)) 403 430 else: 404 print("void async_{name}(io_future_t & future, {params}, __u64 submit_flags);"431 print("void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);" 405 432 .format(name=c.name, params=c.params)) 406 433 print("\n") … … 447 474 448 475 print(""" 476 //----------------------------------------------------------------------------- 477 bool cancel(io_cancellation & this) { 478 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_ASYNC_CANCEL) 479 return false; 480 #else 481 io_future_t future; 482 483 io_context * context = __get_io_context(); 484 485 __u8 sflags = 0; 486 struct __io_data & ring = *context->thrd.ring; 487 488 __u32 idx; 489 volatile struct io_uring_sqe * sqe; 490 [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future ); 491 492 sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0; 493 sqe->opcode = IORING_OP_ASYNC_CANCEL; 494 sqe->flags = sflags; 495 sqe->addr = this.target; 496 497 verify( sqe->user_data == (__u64)(uintptr_t)&future ); 498 __submit( context, idx ); 499 500 wait(future); 501 502 if( future.result == 0 ) return true; // Entry found 503 if( future.result == -EALREADY) return true; // Entry found but in progress 504 if( future.result == -ENOENT ) return false; // Entry not found 505 return false; 506 #endif 507 } 508 449 509 //----------------------------------------------------------------------------- 450 510 // Check if a function is has asynchronous -
libcfa/src/concurrency/io/setup.cfa
r5407cdc rfeacef9 26 26 27 27 #if !defined(CFA_HAVE_LINUX_IO_URING_H) 28 void __kernel_io_startup() { 29 // Nothing to do without io_uring 30 } 31 32 void __kernel_io_shutdown() { 33 // Nothing to do without io_uring 34 } 35 28 36 void ?{}(io_context_params & this) {} 29 37 30 void ?{}($io_context & this, struct cluster & cl) {} 31 void ^?{}($io_context & this) {} 32 33 void __cfa_io_start( processor * proc ) {} 34 void __cfa_io_flush( processor * proc ) {} 35 void __cfa_io_stop ( processor * proc ) {} 36 37 $io_arbiter * create(void) { return 0p; } 38 void destroy($io_arbiter *) {} 38 void ?{}(io_context & this, struct cluster & cl) {} 39 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) {} 40 41 void ^?{}(io_context & this) {} 42 void ^?{}(io_context & this, bool cluster_context) {} 43 44 void register_fixed_files( io_context &, int *, unsigned ) {} 45 void register_fixed_files( cluster &, int *, unsigned ) {} 39 46 40 47 #else … … 61 68 void ?{}(io_context_params & this) { 62 69 this.num_entries = 256; 70 this.num_ready = 256; 71 this.submit_aff = -1; 72 this.eager_submits = false; 73 this.poller_submits = false; 74 this.poll_submit = false; 75 this.poll_complete = false; 63 76 } 64 77 … … 93 106 94 107 //============================================================================================= 108 // I/O Startup / Shutdown logic + Master Poller 109 //============================================================================================= 110 111 // IO Master poller loop forward 112 static void * iopoll_loop( __attribute__((unused)) void * args ); 113 114 static struct { 115 pthread_t thrd; // pthread handle to io poller thread 116 void * stack; // pthread stack for io poller thread 117 int epollfd; // file descriptor to the epoll instance 118 volatile bool run; // Whether or not to continue 119 volatile bool stopped; // Whether the poller has finished running 120 volatile uint64_t epoch; // Epoch used for memory reclamation 121 } iopoll; 122 123 void __kernel_io_startup(void) { 124 __cfadbg_print_safe(io_core, "Kernel : Creating EPOLL instance\n" ); 125 126 iopoll.epollfd = epoll_create1(0); 127 if (iopoll.epollfd == -1) { 128 abort( "internal error, epoll_create1\n"); 129 } 130 131 __cfadbg_print_safe(io_core, "Kernel : Starting io poller thread\n" ); 132 133 iopoll.stack = __create_pthread( &iopoll.thrd, iopoll_loop, 0p ); 134 iopoll.run = true; 135 iopoll.stopped = false; 136 iopoll.epoch = 0; 137 } 138 139 void __kernel_io_shutdown(void) { 140 // Notify the io poller thread of the shutdown 141 iopoll.run = false; 142 sigval val = { 1 }; 143 pthread_sigqueue( iopoll.thrd, SIGUSR1, val ); 144 145 // Wait for the io poller thread to finish 146 147 __destroy_pthread( iopoll.thrd, iopoll.stack, 0p ); 148 149 int ret = close(iopoll.epollfd); 150 if (ret == -1) { 151 abort( "internal error, close epoll\n"); 152 } 153 154 // Io polling is now fully stopped 155 156 __cfadbg_print_safe(io_core, "Kernel : IO poller stopped\n" ); 157 } 158 159 static void * iopoll_loop( __attribute__((unused)) void * args ) { 160 __processor_id_t id; 161 id.full_proc = false; 162 id.id = doregister(&id); 163 __cfaabi_tls.this_proc_id = &id; 164 __cfadbg_print_safe(io_core, "Kernel : IO poller thread starting\n" ); 165 166 // Block signals to control when they arrive 167 sigset_t mask; 168 sigfillset(&mask); 169 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 170 abort( "internal error, pthread_sigmask" ); 171 } 172 173 sigdelset( &mask, SIGUSR1 ); 174 175 // Create sufficient events 176 struct epoll_event events[10]; 177 // Main loop 178 while( iopoll.run ) { 179 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : waiting on io_uring contexts\n"); 180 181 // increment the epoch to notify any deleters we are starting a new cycle 182 __atomic_fetch_add(&iopoll.epoch, 1, __ATOMIC_SEQ_CST); 183 184 // Wait for events 185 int nfds = epoll_pwait( iopoll.epollfd, events, 10, -1, &mask ); 186 187 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : %d io contexts events, waking up\n", nfds); 188 189 // Check if an error occured 190 if (nfds == -1) { 191 if( errno == EINTR ) continue; 192 abort( "internal error, pthread_sigmask" ); 193 } 194 195 for(i; nfds) { 196 $io_ctx_thread * io_ctx = ($io_ctx_thread *)(uintptr_t)events[i].data.u64; 197 /* paranoid */ verify( io_ctx ); 198 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Unparking io poller %d (%p)\n", io_ctx->ring->fd, io_ctx); 199 #if !defined( __CFA_NO_STATISTICS__ ) 200 __cfaabi_tls.this_stats = io_ctx->self.curr_cluster->stats; 201 #endif 202 203 eventfd_t v; 204 eventfd_read(io_ctx->ring->efd, &v); 205 206 post( io_ctx->sem ); 207 } 208 } 209 210 __atomic_store_n(&iopoll.stopped, true, __ATOMIC_SEQ_CST); 211 212 __cfadbg_print_safe(io_core, "Kernel : IO poller thread stopping\n" ); 213 unregister(&id); 214 return 0p; 215 } 216 217 //============================================================================================= 95 218 // I/O Context Constrution/Destruction 96 219 //============================================================================================= 97 220 98 99 100 static void __io_uring_setup ( $io_context & this, const io_context_params & params_in, int procfd ); 101 static void __io_uring_teardown( $io_context & this ); 102 static void __epoll_register($io_context & ctx); 103 static void __epoll_unregister($io_context & ctx); 104 void __ioarbiter_register( $io_arbiter & mutex, $io_context & ctx ); 105 void __ioarbiter_unregister( $io_arbiter & mutex, $io_context & ctx ); 106 107 void ?{}($io_context & this, processor * proc, struct cluster & cl) { 108 /* paranoid */ verify( cl.io.arbiter ); 109 this.proc = proc; 110 this.arbiter = cl.io.arbiter; 111 this.ext_sq.empty = true; 112 (this.ext_sq.queue){}; 113 __io_uring_setup( this, cl.io.params, proc->idle ); 114 __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this); 115 } 116 117 void ^?{}($io_context & this) { 118 __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %u\n", this.fd); 119 120 __io_uring_teardown( this ); 121 __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %u\n", this.fd); 221 void ?{}($io_ctx_thread & this, struct cluster & cl) { (this.self){ "IO Poller", cl }; } 222 void main( $io_ctx_thread & this ); 223 static inline $thread * get_thread( $io_ctx_thread & this ) { return &this.self; } 224 void ^?{}( $io_ctx_thread & mutex this ) {} 225 226 static void __io_create ( __io_data & this, const io_context_params & params_in ); 227 static void __io_destroy( __io_data & this ); 228 229 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) { 230 (this.thrd){ cl }; 231 this.thrd.ring = malloc(); 232 __cfadbg_print_safe(io_core, "Kernel I/O : Creating ring for io_context %p\n", &this); 233 __io_create( *this.thrd.ring, params ); 234 235 __cfadbg_print_safe(io_core, "Kernel I/O : Starting poller thread for io_context %p\n", &this); 236 this.thrd.done = false; 237 __thrd_start( this.thrd, main ); 238 239 __cfadbg_print_safe(io_core, "Kernel I/O : io_context %p ready\n", &this); 240 } 241 242 void ?{}(io_context & this, struct cluster & cl) { 243 io_context_params params; 244 (this){ cl, params }; 245 } 246 247 void ^?{}(io_context & this, bool cluster_context) { 248 __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %p\n", &this); 249 250 // Notify the thread of the shutdown 251 __atomic_store_n(&this.thrd.done, true, __ATOMIC_SEQ_CST); 252 253 // If this is an io_context within a cluster, things get trickier 254 $thread & thrd = this.thrd.self; 255 if( cluster_context ) { 256 // We are about to do weird things with the threads 257 // we don't need interrupts to complicate everything 258 disable_interrupts(); 259 260 // Get cluster info 261 cluster & cltr = *thrd.curr_cluster; 262 /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster ); 263 /* paranoid */ verify( !ready_mutate_islocked() ); 264 265 // We need to adjust the clean-up based on where the thread is 266 if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) { 267 // This is the tricky case 268 // The thread was preempted or ready to run and now it is on the ready queue 269 // but the cluster is shutting down, so there aren't any processors to run the ready queue 270 // the solution is to steal the thread from the ready-queue and pretend it was blocked all along 271 272 ready_schedule_lock(); 273 // The thread should on the list 274 /* paranoid */ verify( thrd.link.next != 0p ); 275 276 // Remove the thread from the ready queue of this cluster 277 // The thread should be the last on the list 278 __attribute__((unused)) bool removed = remove_head( &cltr, &thrd ); 279 /* paranoid */ verify( removed ); 280 thrd.link.next = 0p; 281 thrd.link.prev = 0p; 282 283 // Fixup the thread state 284 thrd.state = Blocked; 285 thrd.ticket = TICKET_BLOCKED; 286 thrd.preempted = __NO_PREEMPTION; 287 288 ready_schedule_unlock(); 289 290 // Pretend like the thread was blocked all along 291 } 292 // !!! This is not an else if !!! 293 // Ok, now the thread is blocked (whether we cheated to get here or not) 294 if( thrd.state == Blocked ) { 295 // This is the "easy case" 296 // The thread is parked and can easily be moved to active cluster 297 verify( thrd.curr_cluster != active_cluster() || thrd.curr_cluster == mainCluster ); 298 thrd.curr_cluster = active_cluster(); 299 300 // unpark the fast io_poller 301 unpark( &thrd ); 302 } 303 else { 304 // The thread is in a weird state 305 // I don't know what to do here 306 abort("io_context poller thread is in unexpected state, cannot clean-up correctly\n"); 307 } 308 309 // The weird thread kidnapping stuff is over, restore interrupts. 310 enable_interrupts( __cfaabi_dbg_ctx ); 311 } else { 312 post( this.thrd.sem ); 313 } 314 315 ^(this.thrd){}; 316 __cfadbg_print_safe(io_core, "Kernel I/O : Stopped poller thread for io_context %p\n", &this); 317 318 __io_destroy( *this.thrd.ring ); 319 __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %p\n", &this); 320 321 free(this.thrd.ring); 322 } 323 324 void ^?{}(io_context & this) { 325 ^(this){ false }; 122 326 } 123 327 … … 125 329 extern void __enable_interrupts_hard(); 126 330 127 static void __io_ uring_setup( $io_context & this, const io_context_params & params_in, int procfd) {331 static void __io_create( __io_data & this, const io_context_params & params_in ) { 128 332 // Step 1 : call to setup 129 333 struct io_uring_params params; 130 334 memset(¶ms, 0, sizeof(params)); 131 //if( params_in.poll_submit ) params.flags |= IORING_SETUP_SQPOLL;132 //if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;335 if( params_in.poll_submit ) params.flags |= IORING_SETUP_SQPOLL; 336 if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL; 133 337 134 338 __u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256; … … 136 340 abort("ERROR: I/O setup 'num_entries' must be a power of 2\n"); 137 341 } 342 if( params_in.poller_submits && params_in.eager_submits ) { 343 abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n"); 344 } 138 345 139 346 int fd = syscall(__NR_io_uring_setup, nentries, ¶ms ); … … 143 350 144 351 // Step 2 : mmap result 145 struct __sub_ring_t & sq = this.sq; 146 struct __cmp_ring_t & cq = this.cq; 352 memset( &this, 0, sizeof(struct __io_data) ); 353 struct __submition_data & sq = this.submit_q; 354 struct __completion_data & cq = this.completion_q; 147 355 148 356 // calculate the right ring size … … 193 401 // Get the pointers from the kernel to fill the structure 194 402 // submit queue 195 sq.kring.head = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head); 196 sq.kring.tail = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail); 197 sq.kring.array = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 198 sq.mask = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask); 199 sq.num = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries); 200 sq.flags = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags); 201 sq.dropped = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 202 203 sq.kring.released = 0; 204 205 sq.free_ring.head = 0; 206 sq.free_ring.tail = *sq.num; 207 sq.free_ring.array = alloc( *sq.num, 128`align ); 208 for(i; (__u32)*sq.num) { 209 sq.free_ring.array[i] = i; 210 } 211 212 sq.to_submit = 0; 403 sq.head = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head); 404 sq.tail = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail); 405 sq.mask = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask); 406 sq.num = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries); 407 sq.flags = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags); 408 sq.dropped = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 409 sq.array = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 410 sq.prev_head = *sq.head; 411 412 { 413 const __u32 num = *sq.num; 414 for( i; num ) { 415 __sqe_clean( &sq.sqes[i] ); 416 } 417 } 418 419 (sq.submit_lock){}; 420 (sq.release_lock){}; 421 422 if( params_in.poller_submits || params_in.eager_submits ) { 423 /* paranoid */ verify( is_pow2( params_in.num_ready ) || (params_in.num_ready < 8) ); 424 sq.ready_cnt = max( params_in.num_ready, 8 ); 425 sq.ready = alloc( sq.ready_cnt, 64`align ); 426 for(i; sq.ready_cnt) { 427 sq.ready[i] = -1ul32; 428 } 429 sq.prev_ready = 0; 430 } 431 else { 432 sq.ready_cnt = 0; 433 sq.ready = 0p; 434 sq.prev_ready = 0; 435 } 213 436 214 437 // completion queue … … 223 446 // io_uring_register is so f*cking slow on some machine that it 224 447 // will never succeed if preemption isn't hard blocked 225 __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd);226 227 448 __disable_interrupts_hard(); 228 449 229 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1); 450 int efd = eventfd(0, 0); 451 if (efd < 0) { 452 abort("KERNEL ERROR: IO_URING EVENTFD - %s\n", strerror(errno)); 453 } 454 455 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &efd, 1); 230 456 if (ret < 0) { 231 457 abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno)); … … 233 459 234 460 __enable_interrupts_hard(); 235 236 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd);237 461 238 462 // some paranoid checks … … 244 468 /* paranoid */ verifyf( (*sq.mask) == ((*sq.num) - 1ul32), "IO_URING Expected mask to be %u (%u entries), was %u", (*sq.num) - 1ul32, *sq.num, *sq.mask ); 245 469 /* paranoid */ verifyf( (*sq.num) >= nentries, "IO_URING Expected %u entries, got %u", nentries, *sq.num ); 246 /* paranoid */ verifyf( (*sq. kring.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.kring.head );247 /* paranoid */ verifyf( (*sq. kring.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.kring.tail );470 /* paranoid */ verifyf( (*sq.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.head ); 471 /* paranoid */ verifyf( (*sq.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.tail ); 248 472 249 473 // Update the global ring info 250 this.ring_flags = 0;474 this.ring_flags = params.flags; 251 475 this.fd = fd; 252 } 253 254 static void __io_uring_teardown( $io_context & this ) { 476 this.efd = efd; 477 this.eager_submits = params_in.eager_submits; 478 this.poller_submits = params_in.poller_submits; 479 } 480 481 static void __io_destroy( __io_data & this ) { 255 482 // Shutdown the io rings 256 struct __sub _ring_t & sq = this.sq;257 struct __c mp_ring_t & cq = this.cq;483 struct __submition_data & sq = this.submit_q; 484 struct __completion_data & cq = this.completion_q; 258 485 259 486 // unmap the submit queue entries … … 270 497 // close the file descriptor 271 498 close(this.fd); 272 273 free( this.sq.free_ring.array ); // Maybe null, doesn't matter 274 } 275 276 void __cfa_io_start( processor * proc ) { 277 proc->io.ctx = alloc(); 278 (*proc->io.ctx){proc, *proc->cltr}; 279 } 280 void __cfa_io_stop ( processor * proc ) { 281 ^(*proc->io.ctx){}; 282 free(proc->io.ctx); 499 close(this.efd); 500 501 free( this.submit_q.ready ); // Maybe null, doesn't matter 283 502 } 284 503 … … 286 505 // I/O Context Sleep 287 506 //============================================================================================= 288 // static inline void __epoll_ctl($io_context & ctx, int op, const char * error) { 289 // struct epoll_event ev; 290 // ev.events = EPOLLIN | EPOLLONESHOT; 291 // ev.data.u64 = (__u64)&ctx; 292 // int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev); 293 // if (ret < 0) { 294 // abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) ); 295 // } 296 // } 297 298 // static void __epoll_register($io_context & ctx) { 299 // __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD"); 300 // } 301 302 // static void __epoll_unregister($io_context & ctx) { 303 // // Read the current epoch so we know when to stop 304 // size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST); 305 306 // // Remove the fd from the iopoller 307 // __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE"); 308 309 // // Notify the io poller thread of the shutdown 310 // iopoll.run = false; 311 // sigval val = { 1 }; 312 // pthread_sigqueue( iopoll.thrd, SIGUSR1, val ); 313 314 // // Make sure all this is done 315 // __atomic_thread_fence(__ATOMIC_SEQ_CST); 316 317 // // Wait for the next epoch 318 // while(curr == iopoll.epoch && !iopoll.stopped) Pause(); 319 // } 320 321 // void __ioctx_prepare_block($io_context & ctx) { 322 // __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx); 323 // __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM"); 324 // } 325 507 static inline void __ioctx_epoll_ctl($io_ctx_thread & ctx, int op, const char * error) { 508 struct epoll_event ev; 509 ev.events = EPOLLIN | EPOLLONESHOT; 510 ev.data.u64 = (__u64)&ctx; 511 int ret = epoll_ctl(iopoll.epollfd, op, ctx.ring->efd, &ev); 512 if (ret < 0) { 513 abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) ); 514 } 515 } 516 517 void __ioctx_register($io_ctx_thread & ctx) { 518 __ioctx_epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD"); 519 } 520 521 void __ioctx_prepare_block($io_ctx_thread & ctx) { 522 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.ring->fd, &ctx); 523 __ioctx_epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM"); 524 } 525 526 void __ioctx_unregister($io_ctx_thread & ctx) { 527 // Read the current epoch so we know when to stop 528 size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST); 529 530 // Remove the fd from the iopoller 531 __ioctx_epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE"); 532 533 // Notify the io poller thread of the shutdown 534 iopoll.run = false; 535 sigval val = { 1 }; 536 pthread_sigqueue( iopoll.thrd, SIGUSR1, val ); 537 538 // Make sure all this is done 539 __atomic_thread_fence(__ATOMIC_SEQ_CST); 540 541 // Wait for the next epoch 542 while(curr == iopoll.epoch && !iopoll.stopped) Pause(); 543 } 326 544 327 545 //============================================================================================= 328 546 // I/O Context Misc Setup 329 547 //============================================================================================= 330 void ?{}( $io_arbiter & this ) { 331 this.pending.empty = true; 332 } 333 334 void ^?{}( $io_arbiter & this ) {} 335 336 $io_arbiter * create(void) { 337 return new(); 338 } 339 void destroy($io_arbiter * arbiter) { 340 delete(arbiter); 341 } 342 343 //============================================================================================= 344 // I/O Context Misc Setup 345 //============================================================================================= 346 548 void register_fixed_files( io_context & ctx, int * files, unsigned count ) { 549 int ret = syscall( __NR_io_uring_register, ctx.thrd.ring->fd, IORING_REGISTER_FILES, files, count ); 550 if( ret < 0 ) { 551 abort( "KERNEL ERROR: IO_URING REGISTER - (%d) %s\n", (int)errno, strerror(errno) ); 552 } 553 554 __cfadbg_print_safe( io_core, "Kernel I/O : Performed io_register for %p, returned %d\n", active_thread(), ret ); 555 } 556 557 void register_fixed_files( cluster & cltr, int * files, unsigned count ) { 558 for(i; cltr.io.cnt) { 559 register_fixed_files( cltr.io.ctxs[i], files, count ); 560 } 561 } 347 562 #endif -
libcfa/src/concurrency/io/types.hfa
r5407cdc rfeacef9 22 22 23 23 #include "bits/locks.hfa" 24 #include "bits/queue.hfa"25 24 #include "kernel/fwd.hfa" 26 25 27 26 #if defined(CFA_HAVE_LINUX_IO_URING_H) 28 #include "bits/sequence.hfa" 29 #include "monitor.hfa" 27 #define LEADER_LOCK 28 struct __leaderlock_t { 29 struct $thread * volatile value; // ($thread) next_leader | (bool:1) is_locked 30 }; 30 31 31 struct processor; 32 monitor $io_arbiter; 32 static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; } 33 33 34 34 //----------------------------------------------------------------------- 35 35 // Ring Data structure 36 struct __sub_ring_t { 37 struct { 38 // Head and tail of the ring (associated with array) 39 volatile __u32 * head; // one passed last index consumed by the kernel 40 volatile __u32 * tail; // one passed last index visible to the kernel 41 volatile __u32 released; // one passed last index released back to the free list 36 struct __submition_data { 37 // Head and tail of the ring (associated with array) 38 volatile __u32 * head; 39 volatile __u32 * tail; 40 volatile __u32 prev_head; 42 41 43 // The actual kernel ring which uses head/tail 44 // indexes into the sqes arrays 45 __u32 * array; 46 } kring; 47 48 struct { 49 volatile __u32 head; 50 volatile __u32 tail; 51 // The ring which contains free allocations 52 // indexes into the sqes arrays 53 __u32 * array; 54 } free_ring; 55 56 // number of sqes to submit on next system call. 57 __u32 to_submit; 42 // The actual kernel ring which uses head/tail 43 // indexes into the sqes arrays 44 __u32 * array; 58 45 59 46 // number of entries and mask to go with it … … 61 48 const __u32 * mask; 62 49 63 // Submission flags , currently only IORING_SETUP_SQPOLL50 // Submission flags (Not sure what for) 64 51 __u32 * flags; 65 52 66 // number of sqes not submitted 67 // From documentation : [dropped] is incremented for each invalid submission queue entry encountered in the ring buffer. 53 // number of sqes not submitted (whatever that means) 68 54 __u32 * dropped; 69 55 56 // Like head/tail but not seen by the kernel 57 volatile __u32 * ready; 58 __u32 ready_cnt; 59 __u32 prev_ready; 60 61 #if defined(LEADER_LOCK) 62 __leaderlock_t submit_lock; 63 #else 64 __spinlock_t submit_lock; 65 #endif 66 __spinlock_t release_lock; 67 70 68 // A buffer of sqes (not the actual ring) 71 struct io_uring_sqe * sqes;69 volatile struct io_uring_sqe * sqes; 72 70 73 71 // The location and size of the mmaped area … … 76 74 }; 77 75 78 struct __c mp_ring_t{76 struct __completion_data { 79 77 // Head and tail of the ring 80 78 volatile __u32 * head; … … 85 83 const __u32 * num; 86 84 87 // I don't know what this value is for85 // number of cqes not submitted (whatever that means) 88 86 __u32 * overflow; 89 87 … … 96 94 }; 97 95 98 struct __outstanding_io { 99 inline Colable; 100 single_sem sem; 101 }; 102 static inline __outstanding_io *& Next( __outstanding_io * n ) { return (__outstanding_io *)Next( (Colable *)n ); } 103 104 struct __outstanding_io_queue { 105 __spinlock_t lock; 106 Queue(__outstanding_io) queue; 107 volatile bool empty; 108 }; 109 110 struct __external_io { 111 inline __outstanding_io; 112 __u32 * idxs; 113 __u32 have; 114 bool lazy; 115 }; 116 117 118 struct __attribute__((aligned(128))) $io_context { 119 $io_arbiter * arbiter; 120 processor * proc; 121 122 __outstanding_io_queue ext_sq; 123 124 struct __sub_ring_t sq; 125 struct __cmp_ring_t cq; 96 struct __io_data { 97 struct __submition_data submit_q; 98 struct __completion_data completion_q; 126 99 __u32 ring_flags; 127 100 int fd; 128 }; 129 130 struct __pending_alloc { 131 inline __outstanding_io; 132 __u32 * idxs; 133 __u32 want; 134 $io_context * ctx; 135 }; 136 137 struct __attribute__((aligned(128))) $io_arbiter { 138 __outstanding_io_queue pending; 101 int efd; 102 bool eager_submits:1; 103 bool poller_submits:1; 139 104 }; 140 105 … … 168 133 #endif 169 134 170 // void __ioctx_prepare_block($io_context & ctx); 135 struct $io_ctx_thread; 136 void __ioctx_register($io_ctx_thread & ctx); 137 void __ioctx_unregister($io_ctx_thread & ctx); 138 void __ioctx_prepare_block($io_ctx_thread & ctx); 139 void __sqe_clean( volatile struct io_uring_sqe * sqe ); 171 140 #endif 172 141 … … 179 148 180 149 static inline { 181 $thread * fulfil( io_future_t & this, __s32 result, bool do_unpark = true) {150 bool fulfil( io_future_t & this, __s32 result ) { 182 151 this.result = result; 183 return fulfil(this.self , do_unpark);152 return fulfil(this.self); 184 153 } 185 154 -
libcfa/src/concurrency/iofwd.hfa
r5407cdc rfeacef9 18 18 #include <unistd.h> 19 19 extern "C" { 20 #include < asm/types.h>20 #include <sys/types.h> 21 21 #if CFA_HAVE_LINUX_IO_URING_H 22 22 #include <linux/io_uring.h> … … 48 48 struct cluster; 49 49 struct io_future_t; 50 struct $io_context; 50 struct io_context; 51 struct io_cancellation; 51 52 52 53 struct iovec; … … 54 55 struct sockaddr; 55 56 struct statx; 56 struct epoll_event;57 58 struct io_uring_sqe;59 60 //----------61 // underlying calls62 extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want) __attribute__((nonnull (1,2)));63 extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2)));64 57 65 58 //---------- 66 59 // synchronous calls 67 60 #if defined(CFA_HAVE_PREADV2) 68 extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);61 extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 69 62 #endif 70 63 #if defined(CFA_HAVE_PWRITEV2) 71 extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);64 extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 72 65 #endif 73 extern int cfa_fsync(int fd, __u64 submit_flags);74 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);75 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);76 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);77 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);78 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);79 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);80 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);81 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);82 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags);83 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags);84 extern int cfa_madvise(void *addr, size_t length, int advice, __u64 submit_flags);85 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);66 extern int cfa_fsync(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 67 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 68 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 69 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 70 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 71 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 72 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 73 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 74 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 75 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 76 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 77 extern int cfa_madvise(void *addr, size_t length, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 78 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 86 79 #if defined(CFA_HAVE_OPENAT2) 87 extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);80 extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 88 81 #endif 89 extern int cfa_close(int fd, __u64 submit_flags);82 extern int cfa_close(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 90 83 #if defined(CFA_HAVE_STATX) 91 extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);84 extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 92 85 #endif 93 extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags);94 extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags);95 extern ssize_t cfa_splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);96 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);86 extern ssize_t cfa_read(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 87 extern ssize_t cfa_write(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 88 extern ssize_t cfa_splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 89 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context); 97 90 98 91 //---------- 99 92 // asynchronous calls 100 93 #if defined(CFA_HAVE_PREADV2) 101 extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);94 extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 102 95 #endif 103 96 #if defined(CFA_HAVE_PWRITEV2) 104 extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);97 extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 105 98 #endif 106 extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags);107 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);108 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);109 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);110 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);111 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);112 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);113 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);114 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);115 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags);116 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags);117 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, __u64 submit_flags);118 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);99 extern void async_fsync(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context); 100 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, int submit_flags, io_cancellation * cancellation, io_context * context); 101 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 102 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 103 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 104 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 105 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 106 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 107 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, io_cancellation * cancellation, io_context * context); 108 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, int submit_flags, io_cancellation * cancellation, io_context * context); 109 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, int submit_flags, io_cancellation * cancellation, io_context * context); 110 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, int submit_flags, io_cancellation * cancellation, io_context * context); 111 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, io_cancellation * cancellation, io_context * context); 119 112 #if defined(CFA_HAVE_OPENAT2) 120 extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);113 extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, io_cancellation * cancellation, io_context * context); 121 114 #endif 122 extern void async_close(io_future_t & future, int fd, __u64 submit_flags);115 extern void async_close(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context); 123 116 #if defined(CFA_HAVE_STATX) 124 extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);117 extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, io_cancellation * cancellation, io_context * context); 125 118 #endif 126 void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);127 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);128 extern void async_splice(io_future_t & future, int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);129 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);119 void async_read(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context); 120 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context); 121 extern void async_splice(io_future_t & future, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 122 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context); 130 123 131 124 … … 133 126 // Check if a function is blocks a only the user thread 134 127 bool has_user_level_blocking( fptr_t func ); 128 129 //----------------------------------------------------------------------------- 130 void register_fixed_files( io_context & ctx , int * files, unsigned count ); 131 void register_fixed_files( cluster & cltr, int * files, unsigned count ); -
libcfa/src/concurrency/kernel.cfa
r5407cdc rfeacef9 22 22 #include <signal.h> 23 23 #include <unistd.h> 24 extern "C" {25 #include <sys/eventfd.h>26 }27 24 28 25 //CFA Includes … … 34 31 #include "invoke.h" 35 32 36 #if !defined(__CFA_NO_STATISTICS__)37 #define __STATS( ...) __VA_ARGS__38 #else39 #define __STATS( ...)40 #endif41 33 42 34 //----------------------------------------------------------------------------- … … 115 107 static $thread * __next_thread(cluster * this); 116 108 static $thread * __next_thread_slow(cluster * this); 117 static inline bool __must_unpark( $thread * thrd ) __attribute((nonnull(1)));118 109 static void __run_thread(processor * this, $thread * dst); 119 110 static void __wake_one(cluster * cltr); 120 111 121 static void mark_idle (__cluster_proc_list & idles, processor & proc); 122 static void mark_awake(__cluster_proc_list & idles, processor & proc); 123 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles ); 124 125 extern void __cfa_io_start( processor * ); 126 extern bool __cfa_io_drain( processor * ); 127 extern void __cfa_io_flush( processor * ); 128 extern void __cfa_io_stop ( processor * ); 129 static inline bool __maybe_io_drain( processor * ); 130 131 extern void __disable_interrupts_hard(); 132 extern void __enable_interrupts_hard(); 133 134 static inline void __disable_interrupts_checked() { 135 /* paranoid */ verify( __preemption_enabled() ); 136 disable_interrupts(); 137 /* paranoid */ verify( ! __preemption_enabled() ); 138 } 139 140 static inline void __enable_interrupts_checked( bool poll = true ) { 141 /* paranoid */ verify( ! __preemption_enabled() ); 142 enable_interrupts( poll ); 143 /* paranoid */ verify( __preemption_enabled() ); 144 } 112 static void push (__cluster_idles & idles, processor & proc); 113 static void remove(__cluster_idles & idles, processor & proc); 114 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles ); 115 145 116 146 117 //============================================================================================= … … 158 129 verify(this); 159 130 160 __cfa_io_start( this );161 162 131 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 163 132 #if !defined(__CFA_NO_STATISTICS__) … … 171 140 preemption_scope scope = { this }; 172 141 173 __STATS( unsigned long long last_tally = rdtscl(); ) 174 175 // if we need to run some special setup, now is the time to do it. 176 if(this->init.thrd) { 177 this->init.thrd->curr_cluster = this->cltr; 178 __run_thread(this, this->init.thrd); 179 } 142 #if !defined(__CFA_NO_STATISTICS__) 143 unsigned long long last_tally = rdtscl(); 144 #endif 145 180 146 181 147 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this); … … 184 150 MAIN_LOOP: 185 151 for() { 186 // Check if there is pending io187 __maybe_io_drain( this );188 189 152 // Try to get the next thread 190 153 readyThread = __next_thread( this->cltr ); 191 154 192 155 if( !readyThread ) { 193 __cfa_io_flush( this );194 156 readyThread = __next_thread_slow( this->cltr ); 195 157 } … … 205 167 206 168 // Push self to idle stack 207 mark_idle(this->cltr->procs, * this);169 push(this->cltr->idles, * this); 208 170 209 171 // Confirm the ready-queue is empty … … 211 173 if( readyThread ) { 212 174 // A thread was found, cancel the halt 213 mark_awake(this->cltr->procs, * this);175 remove(this->cltr->idles, * this); 214 176 215 177 #if !defined(__CFA_NO_STATISTICS__) … … 227 189 #endif 228 190 229 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 230 231 __disable_interrupts_hard(); 232 eventfd_t val; 233 eventfd_read( this->idle, &val ); 234 __enable_interrupts_hard(); 191 wait( this->idle ); 235 192 236 193 #if !defined(__CFA_NO_STATISTICS__) … … 241 198 242 199 // We were woken up, remove self from idle 243 mark_awake(this->cltr->procs, * this);200 remove(this->cltr->idles, * this); 244 201 245 202 // DON'T just proceed, start looking again … … 248 205 249 206 /* paranoid */ verify( readyThread ); 250 251 // Reset io dirty bit252 this->io.dirty = false;253 207 254 208 // We found a thread run it … … 265 219 } 266 220 #endif 267 268 if(this->io.pending && !this->io.dirty) {269 __cfa_io_flush( this );270 }271 272 // SEARCH: {273 // /* paranoid */ verify( ! __preemption_enabled() );274 // /* paranoid */ verify( kernelTLS().this_proc_id );275 276 // // First, lock the scheduler since we are searching for a thread277 278 // // Try to get the next thread279 // ready_schedule_lock();280 // readyThread = pop_fast( this->cltr );281 // ready_schedule_unlock();282 // if(readyThread) { break SEARCH; }283 284 // // If we can't find a thread, might as well flush any outstanding I/O285 // if(this->io.pending) { __cfa_io_flush( this ); }286 287 // // Spin a little on I/O, just in case288 // for(25) {289 // __maybe_io_drain( this );290 // ready_schedule_lock();291 // readyThread = pop_fast( this->cltr );292 // ready_schedule_unlock();293 // if(readyThread) { break SEARCH; }294 // }295 296 // // no luck, try stealing a few times297 // for(25) {298 // if( __maybe_io_drain( this ) ) {299 // ready_schedule_lock();300 // readyThread = pop_fast( this->cltr );301 // } else {302 // ready_schedule_lock();303 // readyThread = pop_slow( this->cltr );304 // }305 // ready_schedule_unlock();306 // if(readyThread) { break SEARCH; }307 // }308 309 // // still no luck, search for a thread310 // ready_schedule_lock();311 // readyThread = pop_search( this->cltr );312 // ready_schedule_unlock();313 // if(readyThread) { break SEARCH; }314 315 // // Don't block if we are done316 // if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;317 318 // __STATS( __tls_stats()->ready.sleep.halts++; )319 320 // // Push self to idle stack321 // mark_idle(this->cltr->procs, * this);322 323 // // Confirm the ready-queue is empty324 // __maybe_io_drain( this );325 // ready_schedule_lock();326 // readyThread = pop_search( this->cltr );327 // ready_schedule_unlock();328 329 // if( readyThread ) {330 // // A thread was found, cancel the halt331 // mark_awake(this->cltr->procs, * this);332 333 // __STATS( __tls_stats()->ready.sleep.cancels++; )334 335 // // continue the main loop336 // break SEARCH;337 // }338 339 // __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); )340 // __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);341 342 // // __disable_interrupts_hard();343 // eventfd_t val;344 // eventfd_read( this->idle, &val );345 // // __enable_interrupts_hard();346 347 // __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); )348 349 // // We were woken up, remove self from idle350 // mark_awake(this->cltr->procs, * this);351 352 // // DON'T just proceed, start looking again353 // continue MAIN_LOOP;354 // }355 356 // RUN_THREAD:357 // /* paranoid */ verify( kernelTLS().this_proc_id );358 // /* paranoid */ verify( ! __preemption_enabled() );359 // /* paranoid */ verify( readyThread );360 361 // // Reset io dirty bit362 // this->io.dirty = false;363 364 // // We found a thread run it365 // __run_thread(this, readyThread);366 367 // // Are we done?368 // if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;369 370 // #if !defined(__CFA_NO_STATISTICS__)371 // unsigned long long curr = rdtscl();372 // if(curr > (last_tally + 500000000)) {373 // __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats);374 // last_tally = curr;375 // }376 // #endif377 378 // if(this->io.pending && !this->io.dirty) {379 // __cfa_io_flush( this );380 // }381 382 // // Check if there is pending io383 // __maybe_io_drain( this );384 221 } 385 222 … … 387 224 } 388 225 389 __cfa_io_stop( this );390 391 226 post( this->terminated ); 392 393 227 394 228 if(this == mainProcessor) { … … 413 247 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 414 248 __builtin_prefetch( thrd_dst->context.SP ); 415 416 __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name);417 249 418 250 $coroutine * proc_cor = get_coroutine(this->runner); … … 465 297 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 466 298 // The thread was preempted, reschedule it and reset the flag 467 schedule_thread$( thrd_dst );299 __schedule_thread( thrd_dst ); 468 300 break RUNNING; 469 301 } … … 486 318 break RUNNING; 487 319 case TICKET_UNBLOCK: 488 #if !defined(__CFA_NO_STATISTICS__)489 __tls_stats()->ready.threads.threads++;490 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );491 #endif492 320 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 493 321 // In this case, just run it again. … … 502 330 proc_cor->state = Active; 503 331 504 __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst);505 506 #if !defined(__CFA_NO_STATISTICS__)507 __tls_stats()->ready.threads.threads--;508 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );509 #endif510 511 332 /* paranoid */ verify( ! __preemption_enabled() ); 512 333 } … … 518 339 $thread * thrd_src = kernelTLS().this_thread; 519 340 520 __STATS( thrd_src->last_proc = kernelTLS().this_processor; ) 341 #if !defined(__CFA_NO_STATISTICS__) 342 struct processor * last_proc = kernelTLS().this_processor; 343 #endif 521 344 522 345 // Run the thread on this processor … … 537 360 538 361 #if !defined(__CFA_NO_STATISTICS__) 539 /* paranoid */ verify( thrd_src->last_proc != 0p ); 540 if(thrd_src->last_proc != kernelTLS().this_processor) { 362 if(last_proc != kernelTLS().this_processor) { 541 363 __tls_stats()->ready.threads.migration++; 542 364 } … … 551 373 // Scheduler routines 552 374 // KERNEL ONLY 553 staticvoid __schedule_thread( $thread * thrd ) {375 void __schedule_thread( $thread * thrd ) { 554 376 /* paranoid */ verify( ! __preemption_enabled() ); 555 377 /* paranoid */ verify( kernelTLS().this_proc_id ); 556 /* paranoid */ verify( ready_schedule_islocked());557 378 /* paranoid */ verify( thrd ); 558 379 /* paranoid */ verify( thrd->state != Halted ); … … 570 391 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 571 392 572 // Dereference the thread now because once we push it, there is not guaranteed it's still valid.573 struct cluster * cl = thrd->curr_cluster;574 __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )575 576 // push the thread to the cluster ready-queue577 push( cl, thrd );578 579 // variable thrd is no longer safe to use580 thrd = 0xdeaddeaddeaddeadp;581 582 // wake the cluster using the save variable.583 __wake_one( cl );584 585 #if !defined(__CFA_NO_STATISTICS__)586 if( kernelTLS().this_stats ) {587 __tls_stats()->ready.threads.threads++;588 if(outside) {589 __tls_stats()->ready.threads.extunpark++;590 }591 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor );592 }593 else {594 __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED);595 __atomic_fetch_add(&cl->stats->ready.threads.extunpark, 1, __ATOMIC_RELAXED);596 __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl );597 }598 #endif599 600 /* paranoid */ verify( ready_schedule_islocked());601 /* paranoid */ verify( ! __preemption_enabled() );602 }603 604 void schedule_thread$( $thread * thrd ) {605 393 ready_schedule_lock(); 606 __schedule_thread( thrd ); 394 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 395 struct cluster * cl = thrd->curr_cluster; 396 397 // push the thread to the cluster ready-queue 398 push( cl, thrd ); 399 400 // variable thrd is no longer safe to use 401 402 // wake the cluster using the save variable. 403 __wake_one( cl ); 607 404 ready_schedule_unlock(); 405 406 /* paranoid */ verify( ! __preemption_enabled() ); 608 407 } 609 408 … … 614 413 615 414 ready_schedule_lock(); 616 $thread * thrd = pop _fast( this );415 $thread * thrd = pop( this ); 617 416 ready_schedule_unlock(); 618 417 … … 628 427 629 428 ready_schedule_lock(); 630 $thread * thrd; 631 for(25) { 632 thrd = pop_slow( this ); 633 if(thrd) goto RET; 634 } 635 thrd = pop_search( this ); 636 637 RET: 429 $thread * thrd = pop_slow( this ); 638 430 ready_schedule_unlock(); 639 431 … … 643 435 } 644 436 645 static inline bool __must_unpark( $thread * thrd ) { 437 void unpark( $thread * thrd ) { 438 if( !thrd ) return; 439 646 440 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 647 441 switch(old_ticket) { 648 442 case TICKET_RUNNING: 649 443 // Wake won the race, the thread will reschedule/rerun itself 650 return false;444 break; 651 445 case TICKET_BLOCKED: 652 446 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 653 447 /* paranoid */ verify( thrd->state == Blocked ); 654 return true; 448 449 { 450 /* paranoid */ verify( publicTLS_get(this_proc_id) ); 451 bool full = publicTLS_get(this_proc_id)->full_proc; 452 if(full) disable_interrupts(); 453 454 /* paranoid */ verify( ! __preemption_enabled() ); 455 456 // Wake lost the race, 457 __schedule_thread( thrd ); 458 459 /* paranoid */ verify( ! __preemption_enabled() ); 460 461 if(full) enable_interrupts( __cfaabi_dbg_ctx ); 462 /* paranoid */ verify( publicTLS_get(this_proc_id) ); 463 } 464 465 break; 655 466 default: 656 467 // This makes no sense, something is wrong abort … … 659 470 } 660 471 661 void __kernel_unpark( $thread * thrd ) {662 /* paranoid */ verify( ! __preemption_enabled() );663 /* paranoid */ verify( ready_schedule_islocked());664 665 if( !thrd ) return;666 667 if(__must_unpark(thrd)) {668 // Wake lost the race,669 __schedule_thread( thrd );670 }671 672 /* paranoid */ verify( ready_schedule_islocked());673 /* paranoid */ verify( ! __preemption_enabled() );674 }675 676 void unpark( $thread * thrd ) {677 if( !thrd ) return;678 679 if(__must_unpark(thrd)) {680 disable_interrupts();681 // Wake lost the race,682 schedule_thread$( thrd );683 enable_interrupts(false);684 }685 }686 687 472 void park( void ) { 688 __disable_interrupts_checked(); 689 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION ); 690 returnToKernel(); 691 __enable_interrupts_checked(); 473 /* paranoid */ verify( __preemption_enabled() ); 474 disable_interrupts(); 475 /* paranoid */ verify( ! __preemption_enabled() ); 476 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION ); 477 478 returnToKernel(); 479 480 /* paranoid */ verify( ! __preemption_enabled() ); 481 enable_interrupts( __cfaabi_dbg_ctx ); 482 /* paranoid */ verify( __preemption_enabled() ); 692 483 693 484 } … … 729 520 // KERNEL ONLY 730 521 bool force_yield( __Preemption_Reason reason ) { 731 __disable_interrupts_checked(); 732 $thread * thrd = kernelTLS().this_thread; 733 /* paranoid */ verify(thrd->state == Active); 734 735 // SKULLDUGGERY: It is possible that we are preempting this thread just before 736 // it was going to park itself. If that is the case and it is already using the 737 // intrusive fields then we can't use them to preempt the thread 738 // If that is the case, abandon the preemption. 739 bool preempted = false; 740 if(thrd->link.next == 0p) { 741 preempted = true; 742 thrd->preempted = reason; 743 returnToKernel(); 744 } 745 __enable_interrupts_checked( false ); 522 /* paranoid */ verify( __preemption_enabled() ); 523 disable_interrupts(); 524 /* paranoid */ verify( ! __preemption_enabled() ); 525 526 $thread * thrd = kernelTLS().this_thread; 527 /* paranoid */ verify(thrd->state == Active); 528 529 // SKULLDUGGERY: It is possible that we are preempting this thread just before 530 // it was going to park itself. If that is the case and it is already using the 531 // intrusive fields then we can't use them to preempt the thread 532 // If that is the case, abandon the preemption. 533 bool preempted = false; 534 if(thrd->link.next == 0p) { 535 preempted = true; 536 thrd->preempted = reason; 537 returnToKernel(); 538 } 539 540 /* paranoid */ verify( ! __preemption_enabled() ); 541 enable_interrupts_noPoll(); 542 /* paranoid */ verify( __preemption_enabled() ); 543 746 544 return preempted; 747 545 } … … 759 557 unsigned idle; 760 558 unsigned total; 761 [idle, total, p] = query _idles(this->procs);559 [idle, total, p] = query(this->idles); 762 560 763 561 // If no one is sleeping, we are done … … 765 563 766 564 // We found a processor, wake it up 767 eventfd_t val; 768 val = 1; 769 eventfd_write( p->idle, val ); 565 post( p->idle ); 770 566 771 567 #if !defined(__CFA_NO_STATISTICS__) 772 if( kernelTLS().this_stats ) { 773 __tls_stats()->ready.sleep.wakes++; 774 } 775 else { 776 __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED); 777 } 568 __tls_stats()->ready.sleep.wakes++; 778 569 #endif 779 570 … … 788 579 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 789 580 790 __disable_interrupts_checked();581 disable_interrupts(); 791 582 /* paranoid */ verify( ! __preemption_enabled() ); 792 eventfd_t val; 793 val = 1; 794 eventfd_write( this->idle, val ); 795 __enable_interrupts_checked(); 796 } 797 798 static void mark_idle(__cluster_proc_list & this, processor & proc) { 583 post( this->idle ); 584 enable_interrupts( __cfaabi_dbg_ctx ); 585 } 586 587 static void push (__cluster_idles & this, processor & proc) { 799 588 /* paranoid */ verify( ! __preemption_enabled() ); 800 589 lock( this ); 801 590 this.idle++; 802 591 /* paranoid */ verify( this.idle <= this.total ); 803 remove(proc); 804 insert_first(this. idles, proc);592 593 insert_first(this.list, proc); 805 594 unlock( this ); 806 595 /* paranoid */ verify( ! __preemption_enabled() ); 807 596 } 808 597 809 static void mark_awake(__cluster_proc_list& this, processor & proc) {598 static void remove(__cluster_idles & this, processor & proc) { 810 599 /* paranoid */ verify( ! __preemption_enabled() ); 811 600 lock( this ); 812 601 this.idle--; 813 602 /* paranoid */ verify( this.idle >= 0 ); 603 814 604 remove(proc); 815 insert_last(this.actives, proc);816 605 unlock( this ); 817 606 /* paranoid */ verify( ! __preemption_enabled() ); 818 607 } 819 608 820 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) { 821 /* paranoid */ verify( ! __preemption_enabled() ); 822 /* paranoid */ verify( ready_schedule_islocked() ); 823 609 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) { 824 610 for() { 825 611 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST); … … 827 613 unsigned idle = this.idle; 828 614 unsigned total = this.total; 829 processor * proc = &this. idles`first;615 processor * proc = &this.list`first; 830 616 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it 831 617 asm volatile("": : :"memory"); … … 833 619 return [idle, total, proc]; 834 620 } 835 836 /* paranoid */ verify( ready_schedule_islocked() );837 /* paranoid */ verify( ! __preemption_enabled() );838 621 } 839 622 … … 881 664 // Kernel Utilities 882 665 //============================================================================================= 883 #if defined(CFA_HAVE_LINUX_IO_URING_H)884 #include "io/types.hfa"885 #endif886 887 static inline bool __maybe_io_drain( processor * proc ) {888 bool ret = false;889 #if defined(CFA_HAVE_LINUX_IO_URING_H)890 __cfadbg_print_safe(runtime_core, "Kernel : core %p checking io for ring %d\n", proc, proc->io.ctx->fd);891 892 // Check if we should drain the queue893 $io_context * ctx = proc->io.ctx;894 unsigned head = *ctx->cq.head;895 unsigned tail = *ctx->cq.tail;896 if(head == tail) return false;897 ready_schedule_lock();898 ret = __cfa_io_drain( proc );899 ready_schedule_unlock();900 #endif901 return ret;902 }903 904 666 //----------------------------------------------------------------------------- 905 667 // Debug … … 929 691 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 930 692 } 693 694 extern int __print_alarm_stats; 695 void print_alarm_stats() { 696 __print_alarm_stats = -1; 697 } 931 698 #endif 932 699 // Local Variables: // -
libcfa/src/concurrency/kernel.hfa
r5407cdc rfeacef9 28 28 } 29 29 30 //----------------------------------------------------------------------------- 31 // Underlying Locks 30 32 #ifdef __CFA_WITH_VERIFY__ 31 33 extern bool __cfaabi_dbg_in_kernel(); 32 34 #endif 33 35 34 //----------------------------------------------------------------------------- 35 // I/O 36 struct cluster; 37 struct $io_context; 38 struct $io_arbiter; 39 40 struct io_context_params { 41 int num_entries; 42 }; 43 44 void ?{}(io_context_params & this); 36 extern "C" { 37 char * strerror(int); 38 } 39 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); } 40 41 struct __bin_sem_t { 42 pthread_mutex_t lock; 43 pthread_cond_t cond; 44 int val; 45 }; 46 47 static inline void ?{}(__bin_sem_t & this) with( this ) { 48 // Create the mutex with error checking 49 pthread_mutexattr_t mattr; 50 pthread_mutexattr_init( &mattr ); 51 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP); 52 pthread_mutex_init(&lock, &mattr); 53 54 pthread_cond_init (&cond, (const pthread_condattr_t *)0p); // workaround trac#208: cast should not be required 55 val = 0; 56 } 57 58 static inline void ^?{}(__bin_sem_t & this) with( this ) { 59 CHECKED( pthread_mutex_destroy(&lock) ); 60 CHECKED( pthread_cond_destroy (&cond) ); 61 } 62 63 static inline void wait(__bin_sem_t & this) with( this ) { 64 verify(__cfaabi_dbg_in_kernel()); 65 CHECKED( pthread_mutex_lock(&lock) ); 66 while(val < 1) { 67 pthread_cond_wait(&cond, &lock); 68 } 69 val -= 1; 70 CHECKED( pthread_mutex_unlock(&lock) ); 71 } 72 73 static inline bool post(__bin_sem_t & this) with( this ) { 74 bool needs_signal = false; 75 76 CHECKED( pthread_mutex_lock(&lock) ); 77 if(val < 1) { 78 val += 1; 79 pthread_cond_signal(&cond); 80 needs_signal = true; 81 } 82 CHECKED( pthread_mutex_unlock(&lock) ); 83 84 return needs_signal; 85 } 86 87 #undef CHECKED 88 45 89 46 90 //----------------------------------------------------------------------------- … … 51 95 struct __processor_id_t { 52 96 unsigned id:24; 97 bool full_proc:1; 53 98 54 99 #if !defined(__CFA_NO_STATISTICS__) … … 69 114 struct cluster * cltr; 70 115 71 // Ready Queue state per processor72 struct {73 unsigned short its;74 unsigned short itr;75 unsigned id;76 unsigned target;77 unsigned long long int cutoff;78 } rdq;79 80 116 // Set to true to notify the processor should terminate 81 117 volatile bool do_terminate; … … 89 125 // Handle to pthreads 90 126 pthread_t kernel_thread; 91 92 struct {93 $io_context * ctx;94 bool pending;95 bool dirty;96 } io;97 127 98 128 // Preemption data … … 104 134 105 135 // Idle lock (kernel semaphore) 106 int idle;136 __bin_sem_t idle; 107 137 108 138 // Termination synchronisation (user semaphore) … … 114 144 // Link lists fields 115 145 DLISTED_MGD_IMPL_IN(processor) 116 117 // special init fields118 // This is needed for memcached integration119 // once memcached experiments are done this should probably be removed120 // it is not a particularly safe scheme as it can make processors less homogeneous121 struct {122 $thread * thrd;123 } init;124 146 125 147 #if !defined(__CFA_NO_STATISTICS__) … … 137 159 void ^?{}(processor & this); 138 160 139 static inline void ?{}(processor & this) { this{ "Anonymous Processor", *mainCluster}; }140 static inline void ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; }141 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster}; }161 static inline void ?{}(processor & this) { this{ "Anonymous Processor", *mainCluster}; } 162 static inline void ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; } 163 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster }; } 142 164 143 165 DLISTED_MGD_IMPL_OUT(processor) 144 166 145 167 //----------------------------------------------------------------------------- 168 // I/O 169 struct __io_data; 170 171 // IO poller user-thread 172 // Not using the "thread" keyword because we want to control 173 // more carefully when to start/stop it 174 struct $io_ctx_thread { 175 struct __io_data * ring; 176 single_sem sem; 177 volatile bool done; 178 $thread self; 179 }; 180 181 182 struct io_context { 183 $io_ctx_thread thrd; 184 }; 185 186 struct io_context_params { 187 int num_entries; 188 int num_ready; 189 int submit_aff; 190 bool eager_submits:1; 191 bool poller_submits:1; 192 bool poll_submit:1; 193 bool poll_complete:1; 194 }; 195 196 void ?{}(io_context_params & this); 197 198 void ?{}(io_context & this, struct cluster & cl); 199 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params); 200 void ^?{}(io_context & this); 201 202 struct io_cancellation { 203 __u64 target; 204 }; 205 206 static inline void ?{}(io_cancellation & this) { this.target = -1u; } 207 static inline void ^?{}(io_cancellation &) {} 208 bool cancel(io_cancellation & this); 209 210 //----------------------------------------------------------------------------- 146 211 // Cluster Tools 147 212 148 // Intrusives lanes which are used by the re ady queue213 // Intrusives lanes which are used by the relaxed ready queue 149 214 struct __attribute__((aligned(128))) __intrusive_lane_t; 150 215 void ?{}(__intrusive_lane_t & this); 151 216 void ^?{}(__intrusive_lane_t & this); 152 217 153 // Aligned timestamps which are used by the relaxed ready queue 154 struct __attribute__((aligned(128))) __timestamp_t; 155 void ?{}(__timestamp_t & this); 156 void ^?{}(__timestamp_t & this); 218 // Counter used for wether or not the lanes are all empty 219 struct __attribute__((aligned(128))) __snzi_node_t; 220 struct __snzi_t { 221 unsigned mask; 222 int root; 223 __snzi_node_t * nodes; 224 }; 225 226 void ?{}( __snzi_t & this, unsigned depth ); 227 void ^?{}( __snzi_t & this ); 157 228 158 229 //TODO adjust cache size to ARCHITECTURE 159 230 // Structure holding the relaxed ready queue 160 231 struct __ready_queue_t { 232 // Data tracking how many/which lanes are used 233 // Aligned to 128 for cache locality 234 __snzi_t snzi; 235 161 236 // Data tracking the actual lanes 162 237 // On a seperate cacheline from the used struct since … … 167 242 __intrusive_lane_t * volatile data; 168 243 169 // Array of times170 __timestamp_t * volatile tscs;171 172 244 // Number of lanes (empty or not) 173 245 volatile size_t count; … … 179 251 180 252 // Idle Sleep 181 struct __cluster_ proc_list{253 struct __cluster_idles { 182 254 // Spin lock protecting the queue 183 255 volatile uint64_t lock; … … 190 262 191 263 // List of idle processors 192 dlist(processor, processor) idles; 193 194 // List of active processors 195 dlist(processor, processor) actives; 264 dlist(processor, processor) list; 196 265 }; 197 266 … … 209 278 210 279 // List of idle processors 211 __cluster_ proc_list procs;280 __cluster_idles idles; 212 281 213 282 // List of threads … … 223 292 224 293 struct { 225 $io_arbiter * arbiter;226 io_context_params params;294 io_context * ctxs; 295 unsigned cnt; 227 296 } io; 228 297 -
libcfa/src/concurrency/kernel/fwd.hfa
r5407cdc rfeacef9 108 108 109 109 extern void disable_interrupts(); 110 extern void enable_interrupts( bool poll = false ); 110 extern void enable_interrupts_noPoll(); 111 extern void enable_interrupts( __cfaabi_dbg_ctx_param ); 111 112 112 113 extern "Cforall" { … … 219 220 // Mark as fulfilled, wake thread if needed 220 221 // return true if a thread was unparked 221 $thread * post(oneshot & this, bool do_unpark = true) {222 bool post(oneshot & this) { 222 223 struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST); 223 if( got == 0p ) return 0p;224 if(do_unpark)unpark( got );225 return got;224 if( got == 0p ) return false; 225 unpark( got ); 226 return true; 226 227 } 227 228 } … … 335 336 // from the server side, mark the future as fulfilled 336 337 // delete it if needed 337 $thread * fulfil( future_t & this, bool do_unpark = true) {338 bool fulfil( future_t & this ) { 338 339 for() { 339 340 struct oneshot * expected = this.ptr; … … 343 344 #pragma GCC diagnostic ignored "-Wfree-nonheap-object" 344 345 #endif 345 if( expected == 3p ) { free( &this ); return 0p; }346 if( expected == 3p ) { free( &this ); return false; } 346 347 #if defined(__GNUC__) && __GNUC__ >= 7 347 348 #pragma GCC diagnostic pop … … 355 356 struct oneshot * want = expected == 0p ? 1p : 2p; 356 357 if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 357 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return 0p; }358 $thread * ret = post( *expected, do_unpark);358 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; } 359 bool ret = post( *expected ); 359 360 __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST); 360 361 return ret; … … 402 403 __VA_ARGS__ \ 403 404 } \ 404 if( !(in_kernel) ) enable_interrupts( ); \405 if( !(in_kernel) ) enable_interrupts( __cfaabi_dbg_ctx ); \ 405 406 } 406 407 #else -
libcfa/src/concurrency/kernel/startup.cfa
r5407cdc rfeacef9 22 22 extern "C" { 23 23 #include <limits.h> // PTHREAD_STACK_MIN 24 #include <sys/eventfd.h> // eventfd25 24 #include <sys/mman.h> // mprotect 26 25 #include <sys/resource.h> // getrlimit … … 73 72 static void __kernel_first_resume( processor * this ); 74 73 static void __kernel_last_resume ( processor * this ); 75 static void init(processor & this, const char name[], cluster & _cltr , $thread * initT);74 static void init(processor & this, const char name[], cluster & _cltr); 76 75 static void deinit(processor & this); 77 76 static void doregister( struct cluster & cltr ); … … 90 89 extern void __kernel_alarm_startup(void); 91 90 extern void __kernel_alarm_shutdown(void); 91 extern void __kernel_io_startup (void); 92 extern void __kernel_io_shutdown(void); 92 93 93 94 //----------------------------------------------------------------------------- … … 101 102 KERNEL_STORAGE($thread, mainThread); 102 103 KERNEL_STORAGE(__stack_t, mainThreadCtx); 104 KERNEL_STORAGE(io_context, mainPollerThread); 103 105 KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock); 104 106 #if !defined(__CFA_NO_STATISTICS__) … … 196 198 197 199 void ?{}(processor & this) with( this ) { 200 ( this.idle ){}; 198 201 ( this.terminated ){}; 199 202 ( this.runner ){}; 200 init( this, "Main Processor", *mainCluster , 0p);203 init( this, "Main Processor", *mainCluster ); 201 204 kernel_thread = pthread_self(); 202 205 … … 223 226 __kernel_alarm_startup(); 224 227 228 // Start IO 229 __kernel_io_startup(); 230 225 231 // Add the main thread to the ready queue 226 232 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 227 schedule_thread$(mainThread);233 __schedule_thread(mainThread); 228 234 229 235 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX … … 235 241 // THE SYSTEM IS NOW COMPLETELY RUNNING 236 242 243 244 // SKULLDUGGERY: The constructor for the mainCluster will call alloc with a dimension of 0 245 // malloc *can* return a non-null value, we should free it if that is the case 246 free( mainCluster->io.ctxs ); 247 248 // Now that the system is up, finish creating systems that need threading 249 mainCluster->io.ctxs = (io_context *)&storage_mainPollerThread; 250 mainCluster->io.cnt = 1; 251 (*mainCluster->io.ctxs){ *mainCluster }; 252 237 253 __cfadbg_print_safe(runtime_core, "Kernel : Started\n--------------------------------------------------\n\n"); 238 254 239 255 /* paranoid */ verify( ! __preemption_enabled() ); 240 enable_interrupts( );256 enable_interrupts( __cfaabi_dbg_ctx ); 241 257 /* paranoid */ verify( __preemption_enabled() ); 242 258 … … 244 260 245 261 static void __kernel_shutdown(void) { 262 //Before we start shutting things down, wait for systems that need threading to shutdown 263 ^(*mainCluster->io.ctxs){}; 264 mainCluster->io.cnt = 0; 265 mainCluster->io.ctxs = 0p; 266 246 267 /* paranoid */ verify( __preemption_enabled() ); 247 268 disable_interrupts(); … … 262 283 __kernel_alarm_shutdown(); 263 284 264 #if !defined( __CFA_NO_STATISTICS__ ) 265 __stats_t * st = (__stats_t *)& storage_mainProcStats; 266 __tally_stats(mainCluster->stats, st); 267 if( 0 != mainProcessor->print_stats ) { 268 __print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor ); 269 } 270 #if defined(CFA_STATS_ARRAY) 271 __flush_stat( st, "Processor", mainProcessor ); 272 #endif 273 #endif 285 // Stop IO 286 __kernel_io_shutdown(); 274 287 275 288 // Destroy the main processor and its context in reverse order of construction … … 351 364 __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc ); 352 365 } 353 #if defined(CFA_STATS_ARRAY)354 __flush_stat( &local_stats, "Processor", proc );355 #endif356 366 #endif 357 367 … … 447 457 link.next = 0p; 448 458 link.prev = 0p; 449 link.preferred = -1u;450 last_proc = 0p;451 459 #if defined( __CFA_WITH_VERIFY__ ) 452 460 canary = 0x0D15EA5E0D15EA5Ep; … … 468 476 } 469 477 470 static void init(processor & this, const char name[], cluster & _cltr , $thread * initT) with( this ) {478 static void init(processor & this, const char name[], cluster & _cltr) with( this ) { 471 479 this.name = name; 472 480 this.cltr = &_cltr; 473 this.rdq.its = 0; 474 this.rdq.itr = 0; 475 this.rdq.id = -1u; 476 this.rdq.target = -1u; 477 this.rdq.cutoff = -1ull; 481 full_proc = true; 478 482 do_terminate = false; 479 483 preemption_alarm = 0p; 480 484 pending_preemption = false; 481 485 482 this.io.ctx = 0p;483 this.io.pending = false;484 this.io.dirty = false;485 486 this.init.thrd = initT;487 488 this.idle = eventfd(0, 0);489 if (idle < 0) {490 abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno));491 }492 493 486 #if !defined(__CFA_NO_STATISTICS__) 494 487 print_stats = 0; … … 496 489 #endif 497 490 498 // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue 499 uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this); 500 this.cltr->procs.total += 1u; 501 insert_last(this.cltr->procs.actives, this); 491 lock( this.cltr->idles ); 492 int target = this.cltr->idles.total += 1u; 493 unlock( this.cltr->idles ); 494 495 id = doregister((__processor_id_t*)&this); 496 497 // Lock the RWlock so no-one pushes/pops while we are changing the queue 498 uint_fast32_t last_size = ready_mutate_lock(); 502 499 503 500 // Adjust the ready queue size 504 ready_queue_grow( cltr );501 ready_queue_grow( cltr, target ); 505 502 506 503 // Unlock the RWlock … … 512 509 // Not a ctor, it just preps the destruction but should not destroy members 513 510 static void deinit(processor & this) { 511 lock( this.cltr->idles ); 512 int target = this.cltr->idles.total -= 1u; 513 unlock( this.cltr->idles ); 514 514 515 // Lock the RWlock so no-one pushes/pops while we are changing the queue 515 516 uint_fast32_t last_size = ready_mutate_lock(); 516 this.cltr->procs.total -= 1u;517 remove(this);518 517 519 518 // Adjust the ready queue size 520 ready_queue_shrink( this.cltr ); 521 522 // Unlock the RWlock and unregister: we don't need the read_lock any more 523 ready_mutate_unregister((__processor_id_t*)&this, last_size ); 524 525 close(this.idle); 526 } 527 528 void ?{}(processor & this, const char name[], cluster & _cltr, $thread * initT) { 519 ready_queue_shrink( this.cltr, target ); 520 521 // Unlock the RWlock 522 ready_mutate_unlock( last_size ); 523 524 // Finally we don't need the read_lock any more 525 unregister((__processor_id_t*)&this); 526 } 527 528 void ?{}(processor & this, const char name[], cluster & _cltr) { 529 ( this.idle ){}; 529 530 ( this.terminated ){}; 530 531 ( this.runner ){}; 531 532 532 533 disable_interrupts(); 533 init( this, name, _cltr , initT);534 enable_interrupts( );534 init( this, name, _cltr ); 535 enable_interrupts( __cfaabi_dbg_ctx ); 535 536 536 537 __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this); 537 538 538 539 this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this ); 539 } 540 541 void ?{}(processor & this, const char name[], cluster & _cltr) { 542 (this){name, _cltr, 0p}; 540 543 541 } 544 542 … … 559 557 disable_interrupts(); 560 558 deinit( this ); 561 enable_interrupts( );559 enable_interrupts( __cfaabi_dbg_ctx ); 562 560 } 563 561 564 562 //----------------------------------------------------------------------------- 565 563 // Cluster 566 static void ?{}(__cluster_ proc_list& this) {564 static void ?{}(__cluster_idles & this) { 567 565 this.lock = 0; 568 566 this.idle = 0; 569 567 this.total = 0; 568 (this.list){}; 570 569 } 571 570 … … 583 582 threads{ __get }; 584 583 585 io.arbiter = create();586 io.params = io_params;587 588 584 doregister(this); 589 585 … … 593 589 594 590 // Adjust the ready queue size 595 ready_queue_grow( &this );591 ready_queue_grow( &this, 0 ); 596 592 597 593 // Unlock the RWlock 598 594 ready_mutate_unlock( last_size ); 599 enable_interrupts( false ); // Don't poll, could be in main cluster 595 enable_interrupts_noPoll(); // Don't poll, could be in main cluster 596 597 598 this.io.cnt = num_io; 599 this.io.ctxs = aalloc(num_io); 600 for(i; this.io.cnt) { 601 (this.io.ctxs[i]){ this, io_params }; 602 } 600 603 } 601 604 602 605 void ^?{}(cluster & this) { 603 destroy(this.io.arbiter); 606 for(i; this.io.cnt) { 607 ^(this.io.ctxs[i]){ true }; 608 } 609 free(this.io.ctxs); 604 610 605 611 // Lock the RWlock so no-one pushes/pops while we are changing the queue … … 608 614 609 615 // Adjust the ready queue size 610 ready_queue_shrink( &this );616 ready_queue_shrink( &this, 0 ); 611 617 612 618 // Unlock the RWlock 613 619 ready_mutate_unlock( last_size ); 614 enable_interrupts ( false); // Don't poll, could be in main cluster620 enable_interrupts_noPoll(); // Don't poll, could be in main cluster 615 621 616 622 #if !defined(__CFA_NO_STATISTICS__) … … 618 624 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 619 625 } 620 #if defined(CFA_STATS_ARRAY)621 __flush_stat( this.stats, "Cluster", &this );622 #endif623 626 free( this.stats ); 624 627 #endif … … 733 736 } 734 737 738 735 739 #if defined(__CFA_WITH_VERIFY__) 736 740 static bool verify_fwd_bck_rng(void) { -
libcfa/src/concurrency/kernel_private.hfa
r5407cdc rfeacef9 29 29 extern "C" { 30 30 void disable_interrupts() OPTIONAL_THREAD; 31 void enable_interrupts( bool poll = true ); 32 } 33 34 void schedule_thread$( $thread * ) __attribute__((nonnull (1))); 31 void enable_interrupts_noPoll(); 32 void enable_interrupts( __cfaabi_dbg_ctx_param ); 33 } 34 35 void __schedule_thread( $thread * ) 36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__)) 37 __attribute__((nonnull (1))) 38 #endif 39 ; 35 40 36 41 extern bool __preemption_enabled(); … … 72 77 //----------------------------------------------------------------------------- 73 78 // I/O 74 $io_arbiter * create(void); 75 void destroy($io_arbiter *); 79 void ^?{}(io_context & this, bool ); 76 80 77 81 //======================================================================= 78 82 // Cluster lock API 79 83 //======================================================================= 84 // Cells use by the reader writer lock 85 // while not generic it only relies on a opaque pointer 86 struct __attribute__((aligned(128))) __scheduler_lock_id_t { 87 // Spin lock used as the underlying lock 88 volatile bool lock; 89 90 // Handle pointing to the proc owning this cell 91 // Used for allocating cells and debugging 92 __processor_id_t * volatile handle; 93 94 #ifdef __CFA_WITH_VERIFY__ 95 // Debug, check if this is owned for reading 96 bool owned; 97 #endif 98 }; 99 100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t)); 101 80 102 // Lock-Free registering/unregistering of threads 81 103 // Register a processor to a given cluster and get its unique id in return 82 void register_proc_id( struct __processor_id_t *);104 unsigned doregister( struct __processor_id_t * proc ); 83 105 84 106 // Unregister a processor from a given cluster using its id, getting back the original pointer 85 void unregister_proc_id( struct __processor_id_t * proc ); 107 void unregister( struct __processor_id_t * proc ); 108 109 //----------------------------------------------------------------------- 110 // Cluster idle lock/unlock 111 static inline void lock(__cluster_idles & this) { 112 for() { 113 uint64_t l = this.lock; 114 if( 115 (0 == (l % 2)) 116 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 117 ) return; 118 Pause(); 119 } 120 } 121 122 static inline void unlock(__cluster_idles & this) { 123 /* paranoid */ verify( 1 == (this.lock % 2) ); 124 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 125 } 86 126 87 127 //======================================================================= … … 111 151 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 112 152 } 113 114 // Cells use by the reader writer lock115 // while not generic it only relies on a opaque pointer116 struct __attribute__((aligned(128))) __scheduler_lock_id_t {117 // Spin lock used as the underlying lock118 volatile bool lock;119 120 // Handle pointing to the proc owning this cell121 // Used for allocating cells and debugging122 __processor_id_t * volatile handle;123 124 #ifdef __CFA_WITH_VERIFY__125 // Debug, check if this is owned for reading126 bool owned;127 #endif128 };129 130 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));131 153 132 154 //----------------------------------------------------------------------- … … 224 246 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ ); 225 247 226 //-----------------------------------------------------------------------227 // Lock-Free registering/unregistering of threads228 // Register a processor to a given cluster and get its unique id in return229 // For convenience, also acquires the lock230 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {231 register_proc_id( proc );232 return ready_mutate_lock();233 }234 235 // Unregister a processor from a given cluster using its id, getting back the original pointer236 // assumes the lock is acquired237 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {238 ready_mutate_unlock( last_s );239 unregister_proc_id( proc );240 }241 242 //-----------------------------------------------------------------------243 // Cluster idle lock/unlock244 static inline void lock(__cluster_proc_list & this) {245 /* paranoid */ verify( ! __preemption_enabled() );246 247 // Start by locking the global RWlock so that we know no-one is248 // adding/removing processors while we mess with the idle lock249 ready_schedule_lock();250 251 // Simple counting lock, acquired, acquired by incrementing the counter252 // to an odd number253 for() {254 uint64_t l = this.lock;255 if(256 (0 == (l % 2))257 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)258 ) return;259 Pause();260 }261 262 /* paranoid */ verify( ! __preemption_enabled() );263 }264 265 static inline void unlock(__cluster_proc_list & this) {266 /* paranoid */ verify( ! __preemption_enabled() );267 268 /* paranoid */ verify( 1 == (this.lock % 2) );269 // Simple couting lock, release by incrementing to an even number270 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );271 272 // Release the global lock, which we acquired when locking273 ready_schedule_unlock();274 275 /* paranoid */ verify( ! __preemption_enabled() );276 }277 278 248 //======================================================================= 279 249 // Ready-Queue API 250 //----------------------------------------------------------------------- 251 // pop thread from the ready queue of a cluster 252 // returns 0p if empty 253 __attribute__((hot)) bool query(struct cluster * cltr); 254 280 255 //----------------------------------------------------------------------- 281 256 // push thread onto a ready queue for a cluster 282 257 // returns true if the list was previously empty, false otherwise 283 __attribute__((hot)) voidpush(struct cluster * cltr, struct $thread * thrd);284 285 //----------------------------------------------------------------------- 286 // pop thread from the local queuesof a cluster258 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd); 259 260 //----------------------------------------------------------------------- 261 // pop thread from the ready queue of a cluster 287 262 // returns 0p if empty 288 263 // May return 0p spuriously 289 __attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr); 290 291 //----------------------------------------------------------------------- 292 // pop thread from any ready queue of a cluster 293 // returns 0p if empty 294 // May return 0p spuriously 295 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 296 297 //----------------------------------------------------------------------- 298 // search all ready queues of a cluster for any thread 264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr); 265 266 //----------------------------------------------------------------------- 267 // pop thread from the ready queue of a cluster 299 268 // returns 0p if empty 300 269 // guaranteed to find any threads added before this call 301 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr); 270 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 271 272 //----------------------------------------------------------------------- 273 // remove thread from the ready queue of a cluster 274 // returns bool if it wasn't found 275 bool remove_head(struct cluster * cltr, struct $thread * thrd); 302 276 303 277 //----------------------------------------------------------------------- 304 278 // Increase the width of the ready queue (number of lanes) by 4 305 void ready_queue_grow (struct cluster * cltr );279 void ready_queue_grow (struct cluster * cltr, int target); 306 280 307 281 //----------------------------------------------------------------------- 308 282 // Decrease the width of the ready queue (number of lanes) by 4 309 void ready_queue_shrink(struct cluster * cltr );283 void ready_queue_shrink(struct cluster * cltr, int target); 310 284 311 285 -
libcfa/src/concurrency/locks.cfa
r5407cdc rfeacef9 134 134 lock( lock __cfaabi_dbg_ctx2 ); 135 135 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 136 /* paranoid */ verifyf( owner == active_thread() || !strict_owner , "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 137 /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to release owner lock %p which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count ); 136 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 138 137 139 138 // if recursion count is zero release lock and set new owner if one is waiting … … 147 146 size_t wait_count( blocking_lock & this ) with( this ) { 148 147 return wait_count; 148 } 149 150 void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) { 151 recursion_count = recursion; 152 } 153 154 size_t get_recursion_count( blocking_lock & this ) with( this ) { 155 return recursion_count; 149 156 } 150 157 … … 166 173 } 167 174 168 size_ton_wait( blocking_lock & this ) with( this ) {175 void on_wait( blocking_lock & this ) with( this ) { 169 176 lock( lock __cfaabi_dbg_ctx2 ); 170 177 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 171 178 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 172 179 173 size_t ret = recursion_count;174 175 180 pop_and_set_new_owner( this ); 176 181 unlock( lock ); 177 return ret;178 }179 180 void on_wakeup( blocking_lock & this, size_t recursion ) with( this ) {181 recursion_count = recursion;182 182 } 183 183 … … 274 274 } 275 275 276 bool empty( condition_variable(L) & this ) with(this) { 277 lock( lock __cfaabi_dbg_ctx2 ); 278 bool ret = empty(blocked_threads); 279 unlock( lock ); 280 return ret; 281 } 276 bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); } 282 277 283 278 int counter( condition_variable(L) & this ) with(this) { return count; } … … 290 285 if (i->lock) { 291 286 // if lock was passed get recursion count to reset to after waking thread 292 recursion_count = on_wait( *i->lock ); 287 recursion_count = get_recursion_count(*i->lock); 288 on_wait( *i->lock ); 293 289 } 294 290 return recursion_count; … … 305 301 306 302 // resets recursion count here after waking 307 if (i.lock) on_wakeup(*i.lock, recursion_count);303 if (i.lock) set_recursion_count(*i.lock, recursion_count); 308 304 } 309 305 … … 327 323 328 324 // resets recursion count here after waking 329 if (info.lock) on_wakeup(*info.lock, recursion_count);325 if (info.lock) set_recursion_count(*info.lock, recursion_count); 330 326 } 331 327 … … 377 373 } 378 374 379 $thread * V (semaphore & this, const bool doUnpark) with( this ) {375 bool V(semaphore & this) with( this ) { 380 376 $thread * thrd = 0p; 381 377 lock( lock __cfaabi_dbg_ctx2 ); … … 389 385 390 386 // make new owner 391 if( doUnpark ) unpark( thrd ); 392 393 return thrd; 394 } 395 396 bool V(semaphore & this) with( this ) { 397 $thread * thrd = V(this, true); 387 unpark( thrd ); 388 398 389 return thrd != 0p; 399 390 } -
libcfa/src/concurrency/locks.hfa
r5407cdc rfeacef9 20 20 21 21 #include "bits/weakso_locks.hfa" 22 #include "containers/queueLockFree.hfa"23 24 #include "thread.hfa"25 22 26 23 #include "time_t.hfa" 27 24 #include "time.hfa" 28 29 //-----------------------------------------------------------------------------30 // Semaphores31 32 // '0-nary' semaphore33 // Similar to a counting semaphore except the value of one is never reached34 // as a consequence, a V() that would bring the value to 1 *spins* until35 // a P consumes it36 struct Semaphore0nary {37 __spinlock_t lock; // needed to protect38 mpsc_queue($thread) queue;39 };40 41 static inline bool P(Semaphore0nary & this, $thread * thrd) {42 /* paranoid */ verify(!(thrd->seqable.next));43 /* paranoid */ verify(!(thrd`next));44 45 push(this.queue, thrd);46 return true;47 }48 49 static inline bool P(Semaphore0nary & this) {50 $thread * thrd = active_thread();51 P(this, thrd);52 park();53 return true;54 }55 56 static inline $thread * V(Semaphore0nary & this, bool doUnpark = true) {57 $thread * next;58 lock(this.lock __cfaabi_dbg_ctx2);59 for (;;) {60 next = pop(this.queue);61 if (next) break;62 Pause();63 }64 unlock(this.lock);65 66 if (doUnpark) unpark(next);67 return next;68 }69 70 // Wrapper used on top of any sempahore to avoid potential locking71 struct BinaryBenaphore {72 volatile ssize_t counter;73 };74 75 static inline {76 void ?{}(BinaryBenaphore & this) { this.counter = 0; }77 void ?{}(BinaryBenaphore & this, zero_t) { this.counter = 0; }78 void ?{}(BinaryBenaphore & this, one_t ) { this.counter = 1; }79 80 // returns true if no blocking needed81 bool P(BinaryBenaphore & this) {82 return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0;83 }84 85 bool tryP(BinaryBenaphore & this) {86 ssize_t c = this.counter;87 return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);88 }89 90 // returns true if notify needed91 bool V(BinaryBenaphore & this) {92 ssize_t c = 0;93 for () {94 if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {95 if (c == 0) return true;96 /* paranoid */ verify(c < 0);97 return false;98 } else {99 if (c == 1) return true;100 /* paranoid */ verify(c < 1);101 Pause();102 }103 }104 }105 }106 107 // Binary Semaphore based on the BinaryBenaphore on top of the 0-nary Semaphore108 struct ThreadBenaphore {109 BinaryBenaphore ben;110 Semaphore0nary sem;111 };112 113 static inline void ?{}(ThreadBenaphore & this) {}114 static inline void ?{}(ThreadBenaphore & this, zero_t) { (this.ben){ 0 }; }115 static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; }116 117 static inline bool P(ThreadBenaphore & this) { return P(this.ben) ? false : P(this.sem); }118 static inline bool tryP(ThreadBenaphore & this) { return tryP(this.ben); }119 static inline bool P(ThreadBenaphore & this, bool wait) { return wait ? P(this) : tryP(this); }120 121 static inline $thread * V(ThreadBenaphore & this, bool doUnpark = true) {122 if (V(this.ben)) return 0p;123 return V(this.sem, doUnpark);124 }125 126 //-----------------------------------------------------------------------------127 // Semaphore128 struct semaphore {129 __spinlock_t lock;130 int count;131 __queue_t($thread) waiting;132 };133 134 void ?{}(semaphore & this, int count = 1);135 void ^?{}(semaphore & this);136 bool P (semaphore & this);137 bool V (semaphore & this);138 bool V (semaphore & this, unsigned count);139 $thread * V (semaphore & this, bool );140 25 141 26 //---------- … … 146 31 static inline void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };} 147 32 static inline void ^?{}( single_acquisition_lock & this ) {} 148 static inline void lock ( single_acquisition_lock & this ) { lock( (blocking_lock &)this ); }149 static inline bool try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }150 static inline void unlock ( single_acquisition_lock & this ) { unlock( (blocking_lock &)this ); }151 static inline size_t on_wait ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this); }152 static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v); }153 static inline void on_notify( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t); }33 static inline void lock ( single_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 34 static inline void unlock ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 35 static inline void on_wait ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); } 36 static inline void on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 37 static inline void set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); } 38 static inline size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 154 39 155 40 //---------- … … 160 45 static inline void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };} 161 46 static inline void ^?{}( owner_lock & this ) {} 162 static inline void lock ( owner_lock & this ) { lock ( (blocking_lock &)this ); } 163 static inline bool try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); } 164 static inline void unlock ( owner_lock & this ) { unlock ( (blocking_lock &)this ); } 165 static inline size_t on_wait ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); } 166 static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 47 static inline void lock ( owner_lock & this ) { lock ( (blocking_lock &)this ); } 48 static inline void unlock ( owner_lock & this ) { unlock ( (blocking_lock &)this ); } 49 static inline void on_wait ( owner_lock & this ) { on_wait( (blocking_lock &)this ); } 167 50 static inline void on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 168 169 struct fast_lock { 170 $thread * volatile owner; 171 ThreadBenaphore sem; 172 }; 173 174 static inline bool $try_lock(fast_lock & this, $thread * thrd) { 175 $thread * exp = 0p; 176 return __atomic_compare_exchange_n(&this.owner, &exp, thrd, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); 177 } 178 179 static inline void lock( fast_lock & this ) __attribute__((artificial)); 180 static inline void lock( fast_lock & this ) { 181 $thread * thrd = active_thread(); 182 /* paranoid */verify(thrd != this.owner); 183 184 for (;;) { 185 if ($try_lock(this, thrd)) return; 186 P(this.sem); 187 } 188 } 189 190 static inline bool try_lock( fast_lock & this ) __attribute__((artificial)); 191 static inline bool try_lock ( fast_lock & this ) { 192 $thread * thrd = active_thread(); 193 /* paranoid */ verify(thrd != this.owner); 194 return $try_lock(this, thrd); 195 } 196 197 static inline $thread * unlock( fast_lock & this ) __attribute__((artificial)); 198 static inline $thread * unlock( fast_lock & this ) { 199 /* paranoid */ verify(active_thread() == this.owner); 200 201 // open 'owner' before unlocking anyone 202 // so new and unlocked threads don't park incorrectly. 203 // This may require additional fencing on ARM. 204 this.owner = 0p; 205 206 return V(this.sem); 207 } 208 209 static inline size_t on_wait( fast_lock & this ) { unlock(this); return 0; } 210 static inline void on_wakeup( fast_lock & this, size_t ) { lock(this); } 211 static inline void on_notify( fast_lock &, struct $thread * t ) { unpark(t); } 212 213 struct mcs_node { 214 mcs_node * volatile next; 215 single_sem sem; 216 }; 217 218 static inline void ?{}(mcs_node & this) { this.next = 0p; } 219 220 static inline mcs_node * volatile & ?`next ( mcs_node * node ) { 221 return node->next; 222 } 223 224 struct mcs_lock { 225 mcs_queue(mcs_node) queue; 226 }; 227 228 static inline void lock(mcs_lock & l, mcs_node & n) { 229 if(push(l.queue, &n)) 230 wait(n.sem); 231 } 232 233 static inline void unlock(mcs_lock & l, mcs_node & n) { 234 mcs_node * next = advance(l.queue, &n); 235 if(next) post(next->sem); 236 } 51 static inline void set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); } 52 static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 237 53 238 54 //----------------------------------------------------------------------------- … … 243 59 244 60 // For synchronization locks to use when releasing 245 size_t on_wait( L & ); 61 void on_wait( L & ); 62 63 // to get recursion count for cond lock to reset after waking 64 size_t get_recursion_count( L & ); 246 65 247 66 // to set recursion count after getting signalled; 248 void on_wakeup( L &, size_t recursion );67 void set_recursion_count( L &, size_t recursion ); 249 68 }; 250 69 … … 300 119 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ); 301 120 } 121 122 //----------------------------------------------------------------------------- 123 // Semaphore 124 struct semaphore { 125 __spinlock_t lock; 126 int count; 127 __queue_t($thread) waiting; 128 }; 129 130 void ?{}(semaphore & this, int count = 1); 131 void ^?{}(semaphore & this); 132 bool P (semaphore & this); 133 bool V (semaphore & this); 134 bool V (semaphore & this, unsigned count); -
libcfa/src/concurrency/monitor.hfa
r5407cdc rfeacef9 61 61 static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } ) 62 62 void delete( T * th ) { 63 if(th)^(*th){};63 ^(*th){}; 64 64 free( th ); 65 65 } -
libcfa/src/concurrency/preemption.cfa
r5407cdc rfeacef9 15 15 16 16 #define __cforall_thread__ 17 // #define __CFA_DEBUG_PRINT_PREEMPTION__18 17 19 18 #include "preemption.hfa" … … 29 28 #include "kernel_private.hfa" 30 29 31 32 30 #if !defined(__CFA_DEFAULT_PREEMPTION__) 33 31 #define __CFA_DEFAULT_PREEMPTION__ 10`ms 34 32 #endif 35 33 36 __attribute__((weak)) Duration default_preemption() { 37 const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION"); 38 if(!preempt_rate_s) { 39 __cfadbg_print_safe(preemption, "No CFA_DEFAULT_PREEMPTION in ENV\n"); 40 return __CFA_DEFAULT_PREEMPTION__; 41 } 42 43 char * endptr = 0p; 44 long int preempt_rate_l = strtol(preempt_rate_s, &endptr, 10); 45 if(preempt_rate_l < 0 || preempt_rate_l > 65535) { 46 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION out of range : %ld\n", preempt_rate_l); 47 return __CFA_DEFAULT_PREEMPTION__; 48 } 49 if('\0' != *endptr) { 50 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION not a decimal number : %s\n", preempt_rate_s); 51 return __CFA_DEFAULT_PREEMPTION__; 52 } 53 54 return preempt_rate_l`ms; 34 Duration default_preemption() __attribute__((weak)) { 35 return __CFA_DEFAULT_PREEMPTION__; 55 36 } 56 37 … … 117 98 //Loop throught every thing expired 118 99 while( node = get_expired( alarms, currtime ) ) { 119 __cfadbg_print_buffer_decl( preemption, " KERNEL: preemption tick %lu\n", currtime.tn);100 // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" ); 120 101 Duration period = node->period; 121 102 if( period == 0) { … … 123 104 } 124 105 125 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm ticking node %p.\n", node );126 127 128 106 // Check if this is a kernel 129 107 if( node->type == Kernel ) { … … 131 109 } 132 110 else if( node->type == User ) { 133 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm unparking %p.\n", node->thrd );134 111 timeout( node->thrd ); 135 112 } … … 140 117 // Check if this is a periodic alarm 141 118 if( period > 0 ) { 142 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns);119 // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv ); 143 120 node->alarm = currtime + period; // Alarm is periodic, add currtime to it (used cached current time) 144 121 insert( alarms, node ); // Reinsert the node for the next time it triggers … … 148 125 // If there are still alarms pending, reset the timer 149 126 if( & (*alarms)`first ) { 127 __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv); 150 128 Duration delta = (*alarms)`first.alarm - currtime; 151 129 Duration capped = max(delta, 50`us); 130 // itimerval tim = { caped }; 131 // __cfaabi_dbg_print_buffer_local( " Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec); 132 152 133 __kernel_set_timer( capped ); 153 134 } … … 315 296 // Enable interrupts by decrementing the counter 316 297 // If counter reaches 0, execute any pending __cfactx_switch 317 void enable_interrupts( bool poll) {298 void enable_interrupts( __cfaabi_dbg_ctx_param ) { 318 299 // Cache the processor now since interrupts can start happening after the atomic store 319 300 processor * proc = __cfaabi_tls.this_processor; 320 /* paranoid */ verify( !poll ||proc );301 /* paranoid */ verify( proc ); 321 302 322 303 with( __cfaabi_tls.preemption_state ){ … … 340 321 // Signal the compiler that a fence is needed but only for signal handlers 341 322 __atomic_signal_fence(__ATOMIC_RELEASE); 342 if( p oll && proc->pending_preemption ) {323 if( proc->pending_preemption ) { 343 324 proc->pending_preemption = false; 344 325 force_yield( __POLL_PREEMPTION ); 345 326 } 346 327 } 328 } 329 330 // For debugging purposes : keep track of the last person to enable the interrupts 331 __cfaabi_dbg_debug_do( proc->last_enable = caller; ) 332 } 333 334 // Disable interrupts by incrementint the counter 335 // Don't execute any pending __cfactx_switch even if counter reaches 0 336 void enable_interrupts_noPoll() { 337 unsigned short prev = __cfaabi_tls.preemption_state.disable_count; 338 __cfaabi_tls.preemption_state.disable_count -= 1; 339 // If this triggers someone is enabled already enabled interrupts 340 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev ); 341 if( prev == 1 ) { 342 #if GCC_VERSION > 50000 343 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free"); 344 #endif 345 // Set enabled flag to true 346 // should be atomic to avoid preemption in the middle of the operation. 347 // use memory order RELAXED since there is no inter-thread on this variable requirements 348 __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED); 349 350 // Signal the compiler that a fence is needed but only for signal handlers 351 __atomic_signal_fence(__ATOMIC_RELEASE); 347 352 } 348 353 } … … 580 585 581 586 // Setup proper signal handlers 582 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); // __cfactx_switch handler583 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO ); // debug handler587 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler 588 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO | SA_RESTART ); // debug handler 584 589 585 590 signal_block( SIGALRM ); … … 684 689 } 685 690 691 #if !defined(__CFA_NO_STATISTICS__) 692 int __print_alarm_stats = 0; 693 #endif 694 686 695 // Main of the alarm thread 687 696 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 688 697 static void * alarm_loop( __attribute__((unused)) void * args ) { 689 698 __processor_id_t id; 690 register_proc_id(&id); 699 id.full_proc = false; 700 id.id = doregister(&id); 691 701 __cfaabi_tls.this_proc_id = &id; 692 702 703 #if !defined(__CFA_NO_STATISTICS__) 704 struct __stats_t local_stats; 705 __cfaabi_tls.this_stats = &local_stats; 706 __init_stats( &local_stats ); 707 #endif 693 708 694 709 // Block sigalrms to control when they arrive … … 749 764 EXIT: 750 765 __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" ); 751 register_proc_id(&id); 752 766 unregister(&id); 767 768 #if !defined(__CFA_NO_STATISTICS__) 769 if( 0 != __print_alarm_stats ) { 770 __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p ); 771 } 772 #endif 753 773 return 0p; 754 774 } -
libcfa/src/concurrency/ready_queue.cfa
r5407cdc rfeacef9 17 17 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ 18 18 19 // #define USE_MPSC 20 21 #define USE_RELAXED_FIFO 22 // #define USE_WORK_STEALING 19 // #define USE_SNZI 23 20 24 21 #include "bits/defs.hfa" … … 31 28 #include <unistd.h> 32 29 30 #include "snzi.hfa" 33 31 #include "ready_subqueue.hfa" 34 32 35 33 static const size_t cache_line_size = 64; 36 37 #if !defined(__CFA_NO_STATISTICS__)38 #define __STATS(...) __VA_ARGS__39 #else40 #define __STATS(...)41 #endif42 34 43 35 // No overriden function, no environment variable, no define … … 47 39 #endif 48 40 49 #if defined(USE_RELAXED_FIFO) 50 #define BIAS 4 51 #define READYQ_SHARD_FACTOR 4 52 #define SEQUENTIAL_SHARD 1 53 #elif defined(USE_WORK_STEALING) 54 #define READYQ_SHARD_FACTOR 2 55 #define SEQUENTIAL_SHARD 2 56 #else 57 #error no scheduling strategy selected 58 #endif 59 60 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)); 61 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)); 62 static inline struct $thread * search(struct cluster * cltr); 63 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred); 64 41 #define BIAS 16 65 42 66 43 // returns the maximum number of processors the RWLock support … … 116 93 //======================================================================= 117 94 // Lock-Free registering/unregistering of threads 118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {95 unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) { 119 96 __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc); 120 97 … … 130 107 /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size)); 131 108 /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0); 132 proc->id =i;109 return i; 133 110 } 134 111 } … … 157 134 /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size)); 158 135 /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0); 159 proc->id =n;160 } 161 162 void unregister _proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {136 return n; 137 } 138 139 void unregister( struct __processor_id_t * proc ) with(*__scheduler_lock) { 163 140 unsigned id = proc->id; 164 141 /*paranoid*/ verify(id < ready); … … 215 192 216 193 //======================================================================= 217 // Cforall Re ady Queue used for scheduling194 // Cforall Reqdy Queue used for scheduling 218 195 //======================================================================= 219 196 void ?{}(__ready_queue_t & this) with (this) { 220 197 lanes.data = 0p; 221 lanes.tscs = 0p;222 198 lanes.count = 0; 223 199 } 224 200 225 201 void ^?{}(__ready_queue_t & this) with (this) { 226 verify( SEQUENTIAL_SHARD == lanes.count ); 202 verify( 1 == lanes.count ); 203 #ifdef USE_SNZI 204 verify( !query( snzi ) ); 205 #endif 227 206 free(lanes.data); 228 free(lanes.tscs);229 207 } 230 208 231 209 //----------------------------------------------------------------------- 232 #if defined(USE_RELAXED_FIFO) 233 //----------------------------------------------------------------------- 234 // get index from random number with or without bias towards queues 235 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) { 236 unsigned i; 237 bool local; 210 __attribute__((hot)) bool query(struct cluster * cltr) { 211 #ifdef USE_SNZI 212 return query(cltr->ready_queue.snzi); 213 #endif 214 return true; 215 } 216 217 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) { 218 unsigned i; 219 bool local; 220 #if defined(BIAS) 238 221 unsigned rlow = r % BIAS; 239 222 unsigned rhigh = r / BIAS; … … 241 224 // (BIAS - 1) out of BIAS chances 242 225 // Use perferred queues 243 i = preferred + (rhigh % READYQ_SHARD_FACTOR);226 i = preferred + (rhigh % 4); 244 227 local = true; 245 228 } … … 250 233 local = false; 251 234 } 252 return [i, local]; 253 } 254 255 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 256 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 257 258 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 259 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 260 261 // write timestamp 262 thrd->link.ts = rdtscl(); 263 264 bool local; 265 int preferred = external ? -1 : kernelTLS().this_processor->rdq.id; 266 267 // Try to pick a lane and lock it 268 unsigned i; 269 do { 270 // Pick the index of a lane 271 unsigned r = __tls_rand_fwd(); 272 [i, local] = idx_from_r(r, preferred); 273 274 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 275 276 #if !defined(__CFA_NO_STATISTICS__) 277 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED); 278 else if(local) __tls_stats()->ready.push.local.attempt++; 279 else __tls_stats()->ready.push.share.attempt++; 235 #else 236 i = r; 237 local = false; 238 #endif 239 return [i, local]; 240 } 241 242 //----------------------------------------------------------------------- 243 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 244 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 245 246 // write timestamp 247 thrd->link.ts = rdtscl(); 248 249 __attribute__((unused)) bool local; 250 __attribute__((unused)) int preferred; 251 #if defined(BIAS) 252 preferred = 253 //* 254 kernelTLS().this_processor ? kernelTLS().this_processor->id * 4 : -1; 255 /*/ 256 thrd->link.preferred * 4; 257 //*/ 258 #endif 259 260 // Try to pick a lane and lock it 261 unsigned i; 262 do { 263 // Pick the index of a lane 264 // unsigned r = __tls_rand(); 265 unsigned r = __tls_rand_fwd(); 266 [i, local] = idx_from_r(r, preferred); 267 268 #if !defined(__CFA_NO_STATISTICS__) 269 if(local) { 270 __tls_stats()->ready.pick.push.local++; 271 } 272 #endif 273 274 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 275 276 #if !defined(__CFA_NO_STATISTICS__) 277 __tls_stats()->ready.pick.push.attempt++; 278 #endif 279 280 // If we can't lock it retry 281 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 282 283 bool first = false; 284 285 // Actually push it 286 #ifdef USE_SNZI 287 bool lane_first = 288 #endif 289 290 push(lanes.data[i], thrd); 291 292 #ifdef USE_SNZI 293 // If this lane used to be empty we need to do more 294 if(lane_first) { 295 // Check if the entire queue used to be empty 296 first = !query(snzi); 297 298 // Update the snzi 299 arrive( snzi, i ); 300 } 301 #endif 302 303 __tls_rand_advance_bck(); 304 305 // Unlock and return 306 __atomic_unlock( &lanes.data[i].lock ); 307 308 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 309 310 // Update statistics 311 #if !defined(__CFA_NO_STATISTICS__) 312 #if defined(BIAS) 313 if( local ) __tls_stats()->ready.pick.push.lsuccess++; 314 #endif 315 __tls_stats()->ready.pick.push.success++; 316 #endif 317 318 // return whether or not the list was empty before this push 319 return first; 320 } 321 322 static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j); 323 static struct $thread * try_pop(struct cluster * cltr, unsigned i); 324 325 // Pop from the ready queue from a given cluster 326 __attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) { 327 /* paranoid */ verify( lanes.count > 0 ); 328 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 329 int preferred; 330 #if defined(BIAS) 331 // Don't bother trying locally too much 332 int local_tries = 8; 333 preferred = kernelTLS().this_processor->id * 4; 334 #endif 335 336 337 // As long as the list is not empty, try finding a lane that isn't empty and pop from it 338 #ifdef USE_SNZI 339 while( query(snzi) ) { 340 #else 341 for(25) { 342 #endif 343 // Pick two lists at random 344 // unsigned ri = __tls_rand(); 345 // unsigned rj = __tls_rand(); 346 unsigned ri = __tls_rand_bck(); 347 unsigned rj = __tls_rand_bck(); 348 349 unsigned i, j; 350 __attribute__((unused)) bool locali, localj; 351 [i, locali] = idx_from_r(ri, preferred); 352 [j, localj] = idx_from_r(rj, preferred); 353 354 #if !defined(__CFA_NO_STATISTICS__) 355 if(locali) { 356 __tls_stats()->ready.pick.pop.local++; 357 } 358 if(localj) { 359 __tls_stats()->ready.pick.pop.local++; 360 } 361 #endif 362 363 i %= count; 364 j %= count; 365 366 // try popping from the 2 picked lists 367 struct $thread * thrd = try_pop(cltr, i, j); 368 if(thrd) { 369 #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__) 370 if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++; 280 371 #endif 281 282 #if defined(USE_MPSC) 283 // mpsc always succeeds 284 } while( false ); 285 #else 286 // If we can't lock it retry 287 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 288 #endif 289 290 // Actually push it 291 push(lanes.data[i], thrd); 292 293 #if !defined(USE_MPSC) 294 // Unlock and return 295 __atomic_unlock( &lanes.data[i].lock ); 296 #endif 297 298 // Mark the current index in the tls rng instance as having an item 299 __tls_rand_advance_bck(); 300 301 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 302 303 // Update statistics 304 #if !defined(__CFA_NO_STATISTICS__) 305 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED); 306 else if(local) __tls_stats()->ready.push.local.success++; 307 else __tls_stats()->ready.push.share.success++; 308 #endif 309 } 310 311 // Pop from the ready queue from a given cluster 312 __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) { 313 /* paranoid */ verify( lanes.count > 0 ); 314 /* paranoid */ verify( kernelTLS().this_processor ); 315 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count ); 316 317 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 318 int preferred = kernelTLS().this_processor->rdq.id; 319 320 321 // As long as the list is not empty, try finding a lane that isn't empty and pop from it 322 for(25) { 323 // Pick two lists at random 324 unsigned ri = __tls_rand_bck(); 325 unsigned rj = __tls_rand_bck(); 326 327 unsigned i, j; 328 __attribute__((unused)) bool locali, localj; 329 [i, locali] = idx_from_r(ri, preferred); 330 [j, localj] = idx_from_r(rj, preferred); 331 332 i %= count; 333 j %= count; 334 335 // try popping from the 2 picked lists 336 struct $thread * thrd = try_pop(cltr, i, j __STATS(, *(locali || localj ? &__tls_stats()->ready.pop.local : &__tls_stats()->ready.pop.help))); 337 if(thrd) { 338 return thrd; 339 } 340 } 341 342 // All lanes where empty return 0p 343 return 0p; 344 } 345 346 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) { return pop_fast(cltr); } 347 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) { 348 return search(cltr); 349 } 350 #endif 351 #if defined(USE_WORK_STEALING) 352 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 353 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 354 355 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 356 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 357 358 // write timestamp 359 thrd->link.ts = rdtscl(); 360 361 // Try to pick a lane and lock it 362 unsigned i; 363 do { 364 #if !defined(__CFA_NO_STATISTICS__) 365 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED); 366 else __tls_stats()->ready.push.local.attempt++; 367 #endif 368 369 if(unlikely(external)) { 370 i = __tls_rand() % lanes.count; 371 } 372 else { 373 processor * proc = kernelTLS().this_processor; 374 unsigned r = proc->rdq.its++; 375 i = proc->rdq.id + (r % READYQ_SHARD_FACTOR); 376 } 377 378 379 #if defined(USE_MPSC) 380 // mpsc always succeeds 381 } while( false ); 382 #else 383 // If we can't lock it retry 384 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 385 #endif 386 387 // Actually push it 388 push(lanes.data[i], thrd); 389 390 #if !defined(USE_MPSC) 391 // Unlock and return 392 __atomic_unlock( &lanes.data[i].lock ); 393 #endif 394 395 #if !defined(__CFA_NO_STATISTICS__) 396 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED); 397 else __tls_stats()->ready.push.local.success++; 398 #endif 399 400 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 401 } 402 403 // Pop from the ready queue from a given cluster 404 __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) { 405 /* paranoid */ verify( lanes.count > 0 ); 406 /* paranoid */ verify( kernelTLS().this_processor ); 407 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count ); 408 409 processor * proc = kernelTLS().this_processor; 410 411 if(proc->rdq.target == -1u) { 412 proc->rdq.target = __tls_rand() % lanes.count; 413 unsigned it1 = proc->rdq.itr; 414 unsigned it2 = proc->rdq.itr + 1; 415 unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR); 416 unsigned idx2 = proc->rdq.id + (it2 % READYQ_SHARD_FACTOR); 417 unsigned long long tsc1 = ts(lanes.data[idx1]); 418 unsigned long long tsc2 = ts(lanes.data[idx2]); 419 proc->rdq.cutoff = min(tsc1, tsc2); 420 if(proc->rdq.cutoff == 0) proc->rdq.cutoff = -1ull; 421 } 422 else { 423 unsigned target = proc->rdq.target; 424 proc->rdq.target = -1u; 425 if(lanes.tscs[target].tv < proc->rdq.cutoff) { 426 $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help)); 427 if(t) return t; 428 } 429 } 430 431 for(READYQ_SHARD_FACTOR) { 432 unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR); 433 if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t; 434 } 435 return 0p; 436 } 437 438 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) { 439 unsigned i = __tls_rand() % lanes.count; 440 return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal)); 441 } 442 443 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) with (cltr->ready_queue) { 444 return search(cltr); 445 } 446 #endif 447 448 //======================================================================= 449 // Various Ready Queue utilities 450 //======================================================================= 451 // these function work the same or almost the same 452 // whether they are using work-stealing or relaxed fifo scheduling 453 454 //----------------------------------------------------------------------- 455 // try to pop from a lane given by index w 456 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) { 457 __STATS( stats.attempt++; ) 458 459 // Get relevant elements locally 460 __intrusive_lane_t & lane = lanes.data[w]; 461 462 // If list looks empty retry 463 if( is_empty(lane) ) { 464 __STATS( stats.espec++; ) 465 return 0p; 466 } 467 468 // If we can't get the lock retry 469 if( !__atomic_try_acquire(&lane.lock) ) { 470 __STATS( stats.elock++; ) 471 return 0p; 472 } 473 474 // If list is empty, unlock and retry 475 if( is_empty(lane) ) { 476 __atomic_unlock(&lane.lock); 477 __STATS( stats.eempty++; ) 478 return 0p; 479 } 480 481 // Actually pop the list 482 struct $thread * thrd; 483 thrd = pop(lane); 484 485 /* paranoid */ verify(thrd); 486 /* paranoid */ verify(lane.lock); 487 488 // Unlock and return 489 __atomic_unlock(&lane.lock); 490 491 // Update statistics 492 __STATS( stats.success++; ) 493 494 #if defined(USE_WORK_STEALING) 495 lanes.tscs[w].tv = thrd->link.ts; 496 #endif 497 498 // return the popped thread 499 return thrd; 500 } 501 502 //----------------------------------------------------------------------- 503 // try to pop from any lanes making sure you don't miss any threads push 504 // before the start of the function 505 static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) { 372 return thrd; 373 } 374 } 375 376 // All lanes where empty return 0p 377 return 0p; 378 } 379 380 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) { 506 381 /* paranoid */ verify( lanes.count > 0 ); 507 382 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); … … 509 384 for(i; count) { 510 385 unsigned idx = (offset + i) % count; 511 struct $thread * thrd = try_pop(cltr, idx __STATS(, __tls_stats()->ready.pop.search));386 struct $thread * thrd = try_pop(cltr, idx); 512 387 if(thrd) { 513 388 return thrd; … … 519 394 } 520 395 396 521 397 //----------------------------------------------------------------------- 522 // Check that all the intrusive queues in the data structure are still consistent 398 // Given 2 indexes, pick the list with the oldest push an try to pop from it 399 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) { 400 #if !defined(__CFA_NO_STATISTICS__) 401 __tls_stats()->ready.pick.pop.attempt++; 402 #endif 403 404 // Pick the bet list 405 int w = i; 406 if( __builtin_expect(!is_empty(lanes.data[j]), true) ) { 407 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j; 408 } 409 410 return try_pop(cltr, w); 411 } 412 413 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) { 414 // Get relevant elements locally 415 __intrusive_lane_t & lane = lanes.data[w]; 416 417 // If list looks empty retry 418 if( is_empty(lane) ) return 0p; 419 420 // If we can't get the lock retry 421 if( !__atomic_try_acquire(&lane.lock) ) return 0p; 422 423 424 // If list is empty, unlock and retry 425 if( is_empty(lane) ) { 426 __atomic_unlock(&lane.lock); 427 return 0p; 428 } 429 430 // Actually pop the list 431 struct $thread * thrd; 432 thrd = pop(lane); 433 434 /* paranoid */ verify(thrd); 435 /* paranoid */ verify(lane.lock); 436 437 #ifdef USE_SNZI 438 // If this was the last element in the lane 439 if(emptied) { 440 depart( snzi, w ); 441 } 442 #endif 443 444 // Unlock and return 445 __atomic_unlock(&lane.lock); 446 447 // Update statistics 448 #if !defined(__CFA_NO_STATISTICS__) 449 __tls_stats()->ready.pick.pop.success++; 450 #endif 451 452 // Update the thread bias 453 thrd->link.preferred = w / 4; 454 455 // return the popped thread 456 return thrd; 457 } 458 //----------------------------------------------------------------------- 459 460 bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 461 for(i; lanes.count) { 462 __intrusive_lane_t & lane = lanes.data[i]; 463 464 bool removed = false; 465 466 __atomic_acquire(&lane.lock); 467 if(head(lane)->link.next == thrd) { 468 $thread * pthrd; 469 pthrd = pop(lane); 470 471 /* paranoid */ verify( pthrd == thrd ); 472 473 removed = true; 474 #ifdef USE_SNZI 475 if(emptied) { 476 depart( snzi, i ); 477 } 478 #endif 479 } 480 __atomic_unlock(&lane.lock); 481 482 if( removed ) return true; 483 } 484 return false; 485 } 486 487 //----------------------------------------------------------------------- 488 523 489 static void check( __ready_queue_t & q ) with (q) { 524 #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)490 #if defined(__CFA_WITH_VERIFY__) 525 491 { 526 492 for( idx ; lanes.count ) { … … 533 499 assert(tail(sl)->link.prev->link.next == tail(sl) ); 534 500 535 if( is_empty(sl)) {501 if(sl.before.link.ts == 0l) { 536 502 assert(tail(sl)->link.prev == head(sl)); 537 503 assert(head(sl)->link.next == tail(sl)); … … 545 511 } 546 512 547 //-----------------------------------------------------------------------548 // Given 2 indexes, pick the list with the oldest push an try to pop from it549 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {550 // Pick the bet list551 int w = i;552 if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {553 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;554 }555 556 return try_pop(cltr, w __STATS(, stats));557 }558 559 513 // Call this function of the intrusive list was moved using memcpy 560 514 // fixes the list so that the pointers back to anchors aren't left dangling 561 515 static inline void fix(__intrusive_lane_t & ll) { 562 #if !defined(USE_MPSC) 563 // if the list is not empty then follow he pointer and fix its reverse 564 if(!is_empty(ll)) { 565 head(ll)->link.next->link.prev = head(ll); 566 tail(ll)->link.prev->link.next = tail(ll); 567 } 568 // Otherwise just reset the list 569 else { 570 verify(tail(ll)->link.next == 0p); 571 tail(ll)->link.prev = head(ll); 572 head(ll)->link.next = tail(ll); 573 verify(head(ll)->link.prev == 0p); 574 } 575 #endif 576 } 577 578 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) { 579 processor * it = &list`first; 580 for(unsigned i = 0; i < count; i++) { 581 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count); 582 it->rdq.id = value; 583 it->rdq.target = -1u; 584 value += READYQ_SHARD_FACTOR; 585 it = &(*it)`next; 586 } 587 } 588 589 static void reassign_cltr_id(struct cluster * cltr) { 590 unsigned preferred = 0; 591 assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle); 592 assign_list(preferred, cltr->procs.idles , cltr->procs.idle ); 593 } 594 595 static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) { 596 #if defined(USE_WORK_STEALING) 597 lanes.tscs = alloc(lanes.count, lanes.tscs`realloc); 598 for(i; lanes.count) { 599 lanes.tscs[i].tv = ts(lanes.data[i]); 600 } 601 #endif 516 // if the list is not empty then follow he pointer and fix its reverse 517 if(!is_empty(ll)) { 518 head(ll)->link.next->link.prev = head(ll); 519 tail(ll)->link.prev->link.next = tail(ll); 520 } 521 // Otherwise just reset the list 522 else { 523 verify(tail(ll)->link.next == 0p); 524 tail(ll)->link.prev = head(ll); 525 head(ll)->link.next = tail(ll); 526 verify(head(ll)->link.prev == 0p); 527 } 602 528 } 603 529 604 530 // Grow the ready queue 605 void ready_queue_grow(struct cluster * cltr) { 606 size_t ncount; 607 int target = cltr->procs.total; 608 531 void ready_queue_grow (struct cluster * cltr, int target) { 609 532 /* paranoid */ verify( ready_mutate_islocked() ); 610 533 __cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue\n"); … … 615 538 // grow the ready queue 616 539 with( cltr->ready_queue ) { 540 #ifdef USE_SNZI 541 ^(snzi){}; 542 #endif 543 617 544 // Find new count 618 545 // Make sure we always have atleast 1 list 619 if(target >= 2) { 620 ncount = target * READYQ_SHARD_FACTOR; 621 } else { 622 ncount = SEQUENTIAL_SHARD; 623 } 546 size_t ncount = target >= 2 ? target * 4: 1; 624 547 625 548 // Allocate new array (uses realloc and memcpies the data) … … 638 561 // Update original 639 562 lanes.count = ncount; 640 } 641 642 fix_times(cltr); 643 644 reassign_cltr_id(cltr); 563 564 #ifdef USE_SNZI 565 // Re-create the snzi 566 snzi{ log2( lanes.count / 8 ) }; 567 for( idx; (size_t)lanes.count ) { 568 if( !is_empty(lanes.data[idx]) ) { 569 arrive(snzi, idx); 570 } 571 } 572 #endif 573 } 645 574 646 575 // Make sure that everything is consistent … … 653 582 654 583 // Shrink the ready queue 655 void ready_queue_shrink(struct cluster * cltr ) {584 void ready_queue_shrink(struct cluster * cltr, int target) { 656 585 /* paranoid */ verify( ready_mutate_islocked() ); 657 586 __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n"); … … 660 589 /* paranoid */ check( cltr->ready_queue ); 661 590 662 int target = cltr->procs.total;663 664 591 with( cltr->ready_queue ) { 592 #ifdef USE_SNZI 593 ^(snzi){}; 594 #endif 595 665 596 // Remember old count 666 597 size_t ocount = lanes.count; … … 668 599 // Find new count 669 600 // Make sure we always have atleast 1 list 670 lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;601 lanes.count = target >= 2 ? target * 4: 1; 671 602 /* paranoid */ verify( ocount >= lanes.count ); 672 /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR|| target < 2 );603 /* paranoid */ verify( lanes.count == target * 4 || target < 2 ); 673 604 674 605 // for printing count the number of displaced threads … … 713 644 fix(lanes.data[idx]); 714 645 } 715 } 716 717 fix_times(cltr); 718 719 reassign_cltr_id(cltr); 646 647 #ifdef USE_SNZI 648 // Re-create the snzi 649 snzi{ log2( lanes.count / 8 ) }; 650 for( idx; (size_t)lanes.count ) { 651 if( !is_empty(lanes.data[idx]) ) { 652 arrive(snzi, idx); 653 } 654 } 655 #endif 656 } 720 657 721 658 // Make sure that everything is consistent -
libcfa/src/concurrency/ready_subqueue.hfa
r5407cdc rfeacef9 2 2 3 3 #define __CFA_NO_SCHED_STATS__ 4 5 #include "containers/queueLockFree.hfa"6 4 7 5 // Intrusives lanes which are used by the relaxed ready queue 8 6 struct __attribute__((aligned(128))) __intrusive_lane_t { 9 7 10 #if defined(USE_MPSC) 11 mpsc_queue($thread) queue; 12 __attribute__((aligned(128))) 13 #else 14 // anchor for the head and the tail of the queue 15 __attribute__((aligned(128))) struct __sentinel_t { 16 // Link lists fields 17 // instrusive link field for threads 18 // must be exactly as in $thread 19 __thread_desc_link link; 20 } before, after; 21 #endif 8 // anchor for the head and the tail of the queue 9 __attribute__((aligned(128))) struct __sentinel_t { 10 // Link lists fields 11 // instrusive link field for threads 12 // must be exactly as in $thread 13 __thread_desc_link link; 14 } before, after; 22 15 23 16 // spin lock protecting the queue … … 42 35 // Get the head pointer (one before the first element) from the anchor 43 36 static inline $thread * head(const __intrusive_lane_t & this) { 44 #if defined(USE_MPSC) 45 return this.queue.head; 46 #else 47 $thread * rhead = ($thread *)( 48 (uintptr_t)( &this.before ) - offsetof( $thread, link ) 49 ); 50 /* paranoid */ verify(rhead); 51 return rhead; 52 #endif 37 $thread * rhead = ($thread *)( 38 (uintptr_t)( &this.before ) - offsetof( $thread, link ) 39 ); 40 /* paranoid */ verify(rhead); 41 return rhead; 53 42 } 54 43 55 44 // Get the tail pointer (one after the last element) from the anchor 56 45 static inline $thread * tail(const __intrusive_lane_t & this) { 57 #if defined(USE_MPSC) 58 return this.queue.tail; 59 #else 60 $thread * rtail = ($thread *)( 61 (uintptr_t)( &this.after ) - offsetof( $thread, link ) 62 ); 63 /* paranoid */ verify(rtail); 64 return rtail; 65 #endif 46 $thread * rtail = ($thread *)( 47 (uintptr_t)( &this.after ) - offsetof( $thread, link ) 48 ); 49 /* paranoid */ verify(rtail); 50 return rtail; 66 51 } 67 52 … … 70 55 this.lock = false; 71 56 72 #if !defined(USE_MPSC) 73 this.before.link.prev = 0p; 74 this.before.link.next = tail(this); 75 this.before.link.ts = 0; 76 77 this.after .link.prev = head(this); 78 this.after .link.next = 0p; 79 this.after .link.ts = 0; 80 81 #if !defined(__CFA_NO_SCHED_STATS__) 82 this.stat.diff = 0; 83 this.stat.push = 0; 84 this.stat.pop = 0; 85 #endif 86 87 // We add a boat-load of assertions here because the anchor code is very fragile 88 /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before)); 89 /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after )); 90 /* paranoid */ verify(head(this)->link.prev == 0p ); 91 /* paranoid */ verify(head(this)->link.next == tail(this) ); 92 /* paranoid */ verify(tail(this)->link.next == 0p ); 93 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 94 /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev ); 95 /* paranoid */ verify(&head(this)->link.next == &this.before.link.next ); 96 /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev ); 97 /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next ); 98 /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128); 99 /* paranoid */ verify(__alignof__(this) == 128); 100 /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128)); 101 #endif 57 this.before.link.prev = 0p; 58 this.before.link.next = tail(this); 59 this.before.link.ts = 0; 60 61 this.after .link.prev = head(this); 62 this.after .link.next = 0p; 63 this.after .link.ts = 0; 64 65 #if !defined(__CFA_NO_SCHED_STATS__) 66 this.stat.diff = 0; 67 this.stat.push = 0; 68 this.stat.pop = 0; 69 #endif 70 71 // We add a boat-load of assertions here because the anchor code is very fragile 72 /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before)); 73 /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after )); 74 /* paranoid */ verify(head(this)->link.prev == 0p ); 75 /* paranoid */ verify(head(this)->link.next == tail(this) ); 76 /* paranoid */ verify(tail(this)->link.next == 0p ); 77 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 78 /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev ); 79 /* paranoid */ verify(&head(this)->link.next == &this.before.link.next ); 80 /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev ); 81 /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next ); 82 /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128); 83 /* paranoid */ verify(__alignof__(this) == 128); 84 /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128)); 102 85 } 103 86 104 87 // Dtor is trivial 105 88 void ^?{}( __intrusive_lane_t & this ) { 106 #if !defined(USE_MPSC) 107 // Make sure the list is empty 108 /* paranoid */ verify(head(this)->link.prev == 0p ); 109 /* paranoid */ verify(head(this)->link.next == tail(this) ); 110 /* paranoid */ verify(tail(this)->link.next == 0p ); 111 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 112 #endif 89 // Make sure the list is empty 90 /* paranoid */ verify(head(this)->link.prev == 0p ); 91 /* paranoid */ verify(head(this)->link.next == tail(this) ); 92 /* paranoid */ verify(tail(this)->link.next == 0p ); 93 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 113 94 } 114 95 … … 116 97 // returns true of lane was empty before push, false otherwise 117 98 bool push(__intrusive_lane_t & this, $thread * node) { 118 #if defined(USE_MPSC) 119 inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) { 120 return this->link.next; 99 #if defined(__CFA_WITH_VERIFY__) 100 /* paranoid */ verify(this.lock); 101 /* paranoid */ verify(node->link.ts != 0); 102 /* paranoid */ verify(node->link.next == 0p); 103 /* paranoid */ verify(node->link.prev == 0p); 104 /* paranoid */ verify(tail(this)->link.next == 0p); 105 /* paranoid */ verify(head(this)->link.prev == 0p); 106 107 if(this.before.link.ts == 0l) { 108 /* paranoid */ verify(tail(this)->link.prev == head(this)); 109 /* paranoid */ verify(head(this)->link.next == tail(this)); 110 } else { 111 /* paranoid */ verify(tail(this)->link.prev != head(this)); 112 /* paranoid */ verify(head(this)->link.next != tail(this)); 121 113 } 122 push(this.queue, node); 123 #else 124 #if defined(__CFA_WITH_VERIFY__) 125 /* paranoid */ verify(this.lock); 126 /* paranoid */ verify(node->link.ts != 0); 127 /* paranoid */ verify(node->link.next == 0p); 128 /* paranoid */ verify(node->link.prev == 0p); 129 /* paranoid */ verify(tail(this)->link.next == 0p); 130 /* paranoid */ verify(head(this)->link.prev == 0p); 131 132 if(this.before.link.ts == 0l) { 133 /* paranoid */ verify(tail(this)->link.prev == head(this)); 134 /* paranoid */ verify(head(this)->link.next == tail(this)); 135 } else { 136 /* paranoid */ verify(tail(this)->link.prev != head(this)); 137 /* paranoid */ verify(head(this)->link.next != tail(this)); 138 } 139 #endif 140 141 // Get the relevant nodes locally 142 $thread * tail = tail(this); 143 $thread * prev = tail->link.prev; 144 145 // Do the push 146 node->link.next = tail; 147 node->link.prev = prev; 148 prev->link.next = node; 149 tail->link.prev = node; 150 151 // Update stats 152 #if !defined(__CFA_NO_SCHED_STATS__) 153 this.stat.diff++; 154 this.stat.push++; 155 #endif 156 157 verify(node->link.next == tail(this)); 158 159 // Check if the queue used to be empty 160 if(this.before.link.ts == 0l) { 161 this.before.link.ts = node->link.ts; 162 /* paranoid */ verify(node->link.prev == head(this)); 163 return true; 164 } 165 return false; 166 #endif 114 #endif 115 116 // Get the relevant nodes locally 117 $thread * tail = tail(this); 118 $thread * prev = tail->link.prev; 119 120 // Do the push 121 node->link.next = tail; 122 node->link.prev = prev; 123 prev->link.next = node; 124 tail->link.prev = node; 125 126 // Update stats 127 #if !defined(__CFA_NO_SCHED_STATS__) 128 this.stat.diff++; 129 this.stat.push++; 130 #endif 131 132 verify(node->link.next == tail(this)); 133 134 // Check if the queue used to be empty 135 if(this.before.link.ts == 0l) { 136 this.before.link.ts = node->link.ts; 137 /* paranoid */ verify(node->link.prev == head(this)); 138 return true; 139 } 140 return false; 167 141 } 168 142 … … 172 146 $thread * pop(__intrusive_lane_t & this) { 173 147 /* paranoid */ verify(this.lock); 174 #if defined(USE_MPSC) 175 inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) { 176 return this->link.next; 177 } 178 return pop(this.queue); 179 #else 180 /* paranoid */ verify(this.before.link.ts != 0ul); 181 182 // Get anchors locally 183 $thread * head = head(this); 184 $thread * tail = tail(this); 185 186 // Get the relevant nodes locally 187 $thread * node = head->link.next; 188 $thread * next = node->link.next; 189 190 /* paranoid */ verify(node != tail); 191 /* paranoid */ verify(node); 192 193 // Do the pop 194 head->link.next = next; 195 next->link.prev = head; 196 node->link.next = 0p; 197 node->link.prev = 0p; 198 199 // Update head time stamp 200 this.before.link.ts = next->link.ts; 201 202 // Update stats 203 #ifndef __CFA_NO_SCHED_STATS__ 204 this.stat.diff--; 205 this.stat.pop ++; 206 #endif 207 208 // Check if we emptied list and return accordingly 209 /* paranoid */ verify(tail(this)->link.next == 0p); 210 /* paranoid */ verify(head(this)->link.prev == 0p); 211 if(next == tail) { 212 /* paranoid */ verify(this.before.link.ts == 0); 213 /* paranoid */ verify(tail(this)->link.prev == head(this)); 214 /* paranoid */ verify(head(this)->link.next == tail(this)); 215 return node; 216 } 217 else { 218 /* paranoid */ verify(next->link.ts != 0); 219 /* paranoid */ verify(tail(this)->link.prev != head(this)); 220 /* paranoid */ verify(head(this)->link.next != tail(this)); 221 /* paranoid */ verify(this.before.link.ts != 0); 222 return node; 223 } 224 #endif 148 /* paranoid */ verify(this.before.link.ts != 0ul); 149 150 // Get anchors locally 151 $thread * head = head(this); 152 $thread * tail = tail(this); 153 154 // Get the relevant nodes locally 155 $thread * node = head->link.next; 156 $thread * next = node->link.next; 157 158 /* paranoid */ verify(node != tail); 159 /* paranoid */ verify(node); 160 161 // Do the pop 162 head->link.next = next; 163 next->link.prev = head; 164 node->link.next = 0p; 165 node->link.prev = 0p; 166 167 // Update head time stamp 168 this.before.link.ts = next->link.ts; 169 170 // Update stats 171 #ifndef __CFA_NO_SCHED_STATS__ 172 this.stat.diff--; 173 this.stat.pop ++; 174 #endif 175 176 // Check if we emptied list and return accordingly 177 /* paranoid */ verify(tail(this)->link.next == 0p); 178 /* paranoid */ verify(head(this)->link.prev == 0p); 179 if(next == tail) { 180 /* paranoid */ verify(this.before.link.ts == 0); 181 /* paranoid */ verify(tail(this)->link.prev == head(this)); 182 /* paranoid */ verify(head(this)->link.next == tail(this)); 183 return node; 184 } 185 else { 186 /* paranoid */ verify(next->link.ts != 0); 187 /* paranoid */ verify(tail(this)->link.prev != head(this)); 188 /* paranoid */ verify(head(this)->link.next != tail(this)); 189 /* paranoid */ verify(this.before.link.ts != 0); 190 return node; 191 } 225 192 } 226 193 227 194 // Check whether or not list is empty 228 195 static inline bool is_empty(__intrusive_lane_t & this) { 229 #if defined(USE_MPSC) 230 return this.queue.head == 0p; 231 #else 232 // Cannot verify here since it may not be locked 233 return this.before.link.ts == 0; 234 #endif 196 // Cannot verify here since it may not be locked 197 return this.before.link.ts == 0; 235 198 } 236 199 237 200 // Return the timestamp 238 201 static inline unsigned long long ts(__intrusive_lane_t & this) { 239 #if defined(USE_MPSC) 240 $thread * tl = this.queue.head; 241 if(!tl) return -1ull; 242 return tl->link.ts; 243 #else 244 // Cannot verify here since it may not be locked 245 return this.before.link.ts; 246 #endif 247 } 248 249 // Aligned timestamps which are used by the relaxed ready queue 250 struct __attribute__((aligned(128))) __timestamp_t { 251 volatile unsigned long long tv; 252 }; 253 254 void ?{}(__timestamp_t & this) { this.tv = 0; } 255 void ^?{}(__timestamp_t & this) {} 202 // Cannot verify here since it may not be locked 203 return this.before.link.ts; 204 } -
libcfa/src/concurrency/stats.cfa
r5407cdc rfeacef9 5 5 #include <inttypes.h> 6 6 #include "bits/debug.hfa" 7 #include "bits/locks.hfa"8 7 #include "stats.hfa" 9 #include "strstream.hfa"10 8 11 9 #if !defined(__CFA_NO_STATISTICS__) 12 10 void __init_stats( struct __stats_t * stats ) { 13 stats->ready.push.local.attempt = 0; 14 stats->ready.push.local.success = 0; 15 stats->ready.push.share.attempt = 0; 16 stats->ready.push.share.success = 0; 17 stats->ready.push.extrn.attempt = 0; 18 stats->ready.push.extrn.success = 0; 19 stats->ready.pop.local .attempt = 0; 20 stats->ready.pop.local .success = 0; 21 stats->ready.pop.local .elock = 0; 22 stats->ready.pop.local .eempty = 0; 23 stats->ready.pop.local .espec = 0; 24 stats->ready.pop.help .attempt = 0; 25 stats->ready.pop.help .success = 0; 26 stats->ready.pop.help .elock = 0; 27 stats->ready.pop.help .eempty = 0; 28 stats->ready.pop.help .espec = 0; 29 stats->ready.pop.steal .attempt = 0; 30 stats->ready.pop.steal .success = 0; 31 stats->ready.pop.steal .elock = 0; 32 stats->ready.pop.steal .eempty = 0; 33 stats->ready.pop.steal .espec = 0; 34 stats->ready.pop.search.attempt = 0; 35 stats->ready.pop.search.success = 0; 36 stats->ready.pop.search.elock = 0; 37 stats->ready.pop.search.eempty = 0; 38 stats->ready.pop.search.espec = 0; 11 stats->ready.pick.push.attempt = 0; 12 stats->ready.pick.push.success = 0; 13 stats->ready.pick.push.local = 0; 14 stats->ready.pick.push.lsuccess = 0; 15 stats->ready.pick.pop .probe = 0; 16 stats->ready.pick.pop .attempt = 0; 17 stats->ready.pick.pop .success = 0; 18 stats->ready.pick.pop .local = 0; 19 stats->ready.pick.pop .lsuccess = 0; 39 20 stats->ready.threads.migration = 0; 40 stats->ready.threads.extunpark = 0;41 stats->ready.threads.threads = 0;42 21 stats->ready.sleep.halts = 0; 43 22 stats->ready.sleep.cancels = 0; … … 46 25 47 26 #if defined(CFA_HAVE_LINUX_IO_URING_H) 48 stats->io.alloc.fast = 0; 49 stats->io.alloc.slow = 0; 50 stats->io.alloc.fail = 0; 51 stats->io.alloc.revoke = 0; 52 stats->io.alloc.block = 0; 53 stats->io.submit.fast = 0; 54 stats->io.submit.slow = 0; 55 stats->io.flush.external = 0; 56 stats->io.calls.flush = 0; 57 stats->io.calls.submitted = 0; 58 stats->io.calls.drain = 0; 59 stats->io.calls.completed = 0; 60 stats->io.calls.errors.busy = 0; 61 stats->io.poller.sleeps = 0; 62 #endif 63 64 #if defined(CFA_STATS_ARRAY) 65 stats->array.values = alloc(CFA_STATS_ARRAY); 66 stats->array.cnt = 0; 27 stats->io.submit_q.submit_avg.rdy = 0; 28 stats->io.submit_q.submit_avg.csm = 0; 29 stats->io.submit_q.submit_avg.cnt = 0; 30 stats->io.submit_q.look_avg.val = 0; 31 stats->io.submit_q.look_avg.cnt = 0; 32 stats->io.submit_q.look_avg.block = 0; 33 stats->io.submit_q.alloc_avg.val = 0; 34 stats->io.submit_q.alloc_avg.cnt = 0; 35 stats->io.submit_q.alloc_avg.block = 0; 36 stats->io.submit_q.helped = 0; 37 stats->io.submit_q.leader = 0; 38 stats->io.submit_q.busy = 0; 39 stats->io.complete_q.completed_avg.val = 0; 40 stats->io.complete_q.completed_avg.cnt = 0; 41 stats->io.complete_q.blocks = 0; 67 42 #endif 68 43 } 69 44 70 45 void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) { 71 __atomic_fetch_add( &cltr->ready.push.local.attempt, proc->ready.push.local.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.local.attempt = 0; 72 __atomic_fetch_add( &cltr->ready.push.local.success, proc->ready.push.local.success, __ATOMIC_SEQ_CST ); proc->ready.push.local.success = 0; 73 __atomic_fetch_add( &cltr->ready.push.share.attempt, proc->ready.push.share.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.share.attempt = 0; 74 __atomic_fetch_add( &cltr->ready.push.share.success, proc->ready.push.share.success, __ATOMIC_SEQ_CST ); proc->ready.push.share.success = 0; 75 __atomic_fetch_add( &cltr->ready.push.extrn.attempt, proc->ready.push.extrn.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.attempt = 0; 76 __atomic_fetch_add( &cltr->ready.push.extrn.success, proc->ready.push.extrn.success, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.success = 0; 77 __atomic_fetch_add( &cltr->ready.pop.local .attempt, proc->ready.pop.local .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.local .attempt = 0; 78 __atomic_fetch_add( &cltr->ready.pop.local .success, proc->ready.pop.local .success, __ATOMIC_SEQ_CST ); proc->ready.pop.local .success = 0; 79 __atomic_fetch_add( &cltr->ready.pop.local .elock , proc->ready.pop.local .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.local .elock = 0; 80 __atomic_fetch_add( &cltr->ready.pop.local .eempty , proc->ready.pop.local .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.local .eempty = 0; 81 __atomic_fetch_add( &cltr->ready.pop.local .espec , proc->ready.pop.local .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.local .espec = 0; 82 __atomic_fetch_add( &cltr->ready.pop.help .attempt, proc->ready.pop.help .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.help .attempt = 0; 83 __atomic_fetch_add( &cltr->ready.pop.help .success, proc->ready.pop.help .success, __ATOMIC_SEQ_CST ); proc->ready.pop.help .success = 0; 84 __atomic_fetch_add( &cltr->ready.pop.help .elock , proc->ready.pop.help .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.help .elock = 0; 85 __atomic_fetch_add( &cltr->ready.pop.help .eempty , proc->ready.pop.help .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.help .eempty = 0; 86 __atomic_fetch_add( &cltr->ready.pop.help .espec , proc->ready.pop.help .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.help .espec = 0; 87 __atomic_fetch_add( &cltr->ready.pop.steal .attempt, proc->ready.pop.steal .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .attempt = 0; 88 __atomic_fetch_add( &cltr->ready.pop.steal .success, proc->ready.pop.steal .success, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .success = 0; 89 __atomic_fetch_add( &cltr->ready.pop.steal .elock , proc->ready.pop.steal .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .elock = 0; 90 __atomic_fetch_add( &cltr->ready.pop.steal .eempty , proc->ready.pop.steal .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .eempty = 0; 91 __atomic_fetch_add( &cltr->ready.pop.steal .espec , proc->ready.pop.steal .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .espec = 0; 92 __atomic_fetch_add( &cltr->ready.pop.search.attempt, proc->ready.pop.search.attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.search.attempt = 0; 93 __atomic_fetch_add( &cltr->ready.pop.search.success, proc->ready.pop.search.success, __ATOMIC_SEQ_CST ); proc->ready.pop.search.success = 0; 94 __atomic_fetch_add( &cltr->ready.pop.search.elock , proc->ready.pop.search.elock , __ATOMIC_SEQ_CST ); proc->ready.pop.search.elock = 0; 95 __atomic_fetch_add( &cltr->ready.pop.search.eempty , proc->ready.pop.search.eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.search.eempty = 0; 96 __atomic_fetch_add( &cltr->ready.pop.search.espec , proc->ready.pop.search.espec , __ATOMIC_SEQ_CST ); proc->ready.pop.search.espec = 0; 46 __atomic_fetch_add( &cltr->ready.pick.push.attempt , proc->ready.pick.push.attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.push.attempt = 0; 47 __atomic_fetch_add( &cltr->ready.pick.push.success , proc->ready.pick.push.success , __ATOMIC_SEQ_CST ); proc->ready.pick.push.success = 0; 48 __atomic_fetch_add( &cltr->ready.pick.push.local , proc->ready.pick.push.local , __ATOMIC_SEQ_CST ); proc->ready.pick.push.local = 0; 49 __atomic_fetch_add( &cltr->ready.pick.push.lsuccess, proc->ready.pick.push.lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.push.lsuccess = 0; 50 __atomic_fetch_add( &cltr->ready.pick.pop .probe , proc->ready.pick.pop .probe , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .probe = 0; 51 __atomic_fetch_add( &cltr->ready.pick.pop .attempt , proc->ready.pick.pop .attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .attempt = 0; 52 __atomic_fetch_add( &cltr->ready.pick.pop .success , proc->ready.pick.pop .success , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .success = 0; 53 __atomic_fetch_add( &cltr->ready.pick.pop .local , proc->ready.pick.pop .local , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .local = 0; 54 __atomic_fetch_add( &cltr->ready.pick.pop .lsuccess, proc->ready.pick.pop .lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.pop .lsuccess = 0; 97 55 __atomic_fetch_add( &cltr->ready.threads.migration , proc->ready.threads.migration , __ATOMIC_SEQ_CST ); proc->ready.threads.migration = 0; 98 __atomic_fetch_add( &cltr->ready.threads.extunpark , proc->ready.threads.extunpark , __ATOMIC_SEQ_CST ); proc->ready.threads.extunpark = 0;99 __atomic_fetch_add( &cltr->ready.threads.threads , proc->ready.threads.threads , __ATOMIC_SEQ_CST ); proc->ready.threads.threads = 0;100 56 __atomic_fetch_add( &cltr->ready.sleep.halts , proc->ready.sleep.halts , __ATOMIC_SEQ_CST ); proc->ready.sleep.halts = 0; 101 57 __atomic_fetch_add( &cltr->ready.sleep.cancels , proc->ready.sleep.cancels , __ATOMIC_SEQ_CST ); proc->ready.sleep.cancels = 0; … … 104 60 105 61 #if defined(CFA_HAVE_LINUX_IO_URING_H) 106 __atomic_fetch_add( &cltr->io.alloc.fast , proc->io.alloc.fast , __ATOMIC_SEQ_CST ); proc->io.alloc.fast = 0; 107 __atomic_fetch_add( &cltr->io.alloc.slow , proc->io.alloc.slow , __ATOMIC_SEQ_CST ); proc->io.alloc.slow = 0; 108 __atomic_fetch_add( &cltr->io.alloc.fail , proc->io.alloc.fail , __ATOMIC_SEQ_CST ); proc->io.alloc.fail = 0; 109 __atomic_fetch_add( &cltr->io.alloc.revoke , proc->io.alloc.revoke , __ATOMIC_SEQ_CST ); proc->io.alloc.revoke = 0; 110 __atomic_fetch_add( &cltr->io.alloc.block , proc->io.alloc.block , __ATOMIC_SEQ_CST ); proc->io.alloc.block = 0; 111 __atomic_fetch_add( &cltr->io.submit.fast , proc->io.submit.fast , __ATOMIC_SEQ_CST ); proc->io.submit.fast = 0; 112 __atomic_fetch_add( &cltr->io.submit.slow , proc->io.submit.slow , __ATOMIC_SEQ_CST ); proc->io.submit.slow = 0; 113 __atomic_fetch_add( &cltr->io.flush.external , proc->io.flush.external , __ATOMIC_SEQ_CST ); proc->io.flush.external = 0; 114 __atomic_fetch_add( &cltr->io.calls.flush , proc->io.calls.flush , __ATOMIC_SEQ_CST ); proc->io.calls.flush = 0; 115 __atomic_fetch_add( &cltr->io.calls.submitted , proc->io.calls.submitted , __ATOMIC_SEQ_CST ); proc->io.calls.submitted = 0; 116 __atomic_fetch_add( &cltr->io.calls.drain , proc->io.calls.drain , __ATOMIC_SEQ_CST ); proc->io.calls.drain = 0; 117 __atomic_fetch_add( &cltr->io.calls.completed , proc->io.calls.completed , __ATOMIC_SEQ_CST ); proc->io.calls.completed = 0; 118 __atomic_fetch_add( &cltr->io.calls.errors.busy, proc->io.calls.errors.busy, __ATOMIC_SEQ_CST ); proc->io.calls.errors.busy = 0; 119 __atomic_fetch_add( &cltr->io.poller.sleeps , proc->io.poller.sleeps , __ATOMIC_SEQ_CST ); proc->io.poller.sleeps = 0; 62 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy , proc->io.submit_q.submit_avg.rdy , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.rdy = 0; 63 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm , proc->io.submit_q.submit_avg.csm , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.csm = 0; 64 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl , proc->io.submit_q.submit_avg.avl , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.avl = 0; 65 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt , proc->io.submit_q.submit_avg.cnt , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.cnt = 0; 66 __atomic_fetch_add( &cltr->io.submit_q.look_avg.val , proc->io.submit_q.look_avg.val , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.val = 0; 67 __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt , proc->io.submit_q.look_avg.cnt , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.cnt = 0; 68 __atomic_fetch_add( &cltr->io.submit_q.look_avg.block , proc->io.submit_q.look_avg.block , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.block = 0; 69 __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val , proc->io.submit_q.alloc_avg.val , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.val = 0; 70 __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt , proc->io.submit_q.alloc_avg.cnt , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.cnt = 0; 71 __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block , proc->io.submit_q.alloc_avg.block , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.block = 0; 72 __atomic_fetch_add( &cltr->io.submit_q.helped , proc->io.submit_q.helped , __ATOMIC_SEQ_CST ); proc->io.submit_q.helped = 0; 73 __atomic_fetch_add( &cltr->io.submit_q.leader , proc->io.submit_q.leader , __ATOMIC_SEQ_CST ); proc->io.submit_q.leader = 0; 74 __atomic_fetch_add( &cltr->io.submit_q.busy , proc->io.submit_q.busy , __ATOMIC_SEQ_CST ); proc->io.submit_q.busy = 0; 75 __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.val = 0; 76 __atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.cnt = 0; 77 __atomic_fetch_add( &cltr->io.complete_q.blocks , proc->io.complete_q.blocks , __ATOMIC_SEQ_CST ); proc->io.complete_q.blocks = 0; 120 78 #endif 121 79 } 122 80 123 #define eng3(X) (ws(3, 3, unit(eng( X ))))124 125 81 void __print_stats( struct __stats_t * stats, int flags, const char * type, const char * name, void * id ) with( *stats ) { 126 82 127 char buf[1024]; 128 ostrstream sstr = { buf, 1024 }; 83 if( flags & CFA_STATS_READY_Q ) { 84 double push_sur = (100.0 * ((double)ready.pick.push.success) / ready.pick.push.attempt); 85 double pop_sur = (100.0 * ((double)ready.pick.pop .success) / ready.pick.pop .attempt); 129 86 130 if( flags & CFA_STATS_READY_Q ) { 87 double push_len = ((double)ready.pick.push.attempt) / ready.pick.push.success; 88 double pop_len = ((double)ready.pick.pop .attempt) / ready.pick.pop .success; 131 89 132 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----"; 90 double lpush_sur = (100.0 * ((double)ready.pick.push.lsuccess) / ready.pick.push.local); 91 double lpop_sur = (100.0 * ((double)ready.pick.pop .lsuccess) / ready.pick.pop .local); 133 92 134 uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success; 135 uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success; 136 sstr | "- totals : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk)"; 93 double lpush_len = ((double)ready.pick.push.local) / ready.pick.push.lsuccess; 94 double lpop_len = ((double)ready.pick.pop .local) / ready.pick.pop .lsuccess; 137 95 138 double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS; 139 double sLcl_len = ready.push.local.success ? ((double)ready.push.local.attempt) / ready.push.local.success : 0; 140 double sOth_len = ready.push.share.success ? ((double)ready.push.share.attempt) / ready.push.share.success : 0; 141 double sExt_len = ready.push.extrn.success ? ((double)ready.push.extrn.attempt) / ready.push.extrn.success : 0; 142 sstr | "- push avg : " | ws(3, 3, push_len) 143 | "- l: " | eng3(ready.push.local.attempt) | " (" | ws(3, 3, sLcl_len) | ")" 144 | ", s: " | eng3(ready.push.share.attempt) | " (" | ws(3, 3, sOth_len) | ")" 145 | ", e: " | eng3(ready.push.extrn.attempt) | " (" | ws(3, 3, sExt_len) | ")"; 146 147 double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR; 148 sstr | "- local : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%' 149 | " (" | eng3(ready.pop.local .attempt) | " try," | eng3(ready.pop.local .espec) | " spc," | eng3(ready.pop.local .elock) | " lck," | eng3(ready.pop.local .eempty) | " ept)"; 150 double rHlp_pc = (100.0 * (double)ready.pop.help .success) / totalR; 151 sstr | "- help : " | eng3(ready.pop.help .success) | "-"| ws(3, 3, rHlp_pc) | '%' 152 | " (" | eng3(ready.pop.help .attempt) | " try," | eng3(ready.pop.help .espec) | " spc," | eng3(ready.pop.help .elock) | " lck," | eng3(ready.pop.help .eempty) | " ept)"; 153 double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR; 154 sstr | "- steal : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%' 155 | " (" | eng3(ready.pop.steal .attempt) | " try," | eng3(ready.pop.steal .espec) | " spc," | eng3(ready.pop.steal .elock) | " lck," | eng3(ready.pop.steal .eempty) | " ept)"; 156 double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR; 157 sstr | "- search : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%' 158 | " (" | eng3(ready.pop.search.attempt) | " try," | eng3(ready.pop.search.espec) | " spc," | eng3(ready.pop.search.elock) | " lck," | eng3(ready.pop.search.eempty) | " ept)"; 159 160 sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit"; 161 sstr | nl; 96 __cfaabi_bits_print_safe( STDOUT_FILENO, 97 "----- %s \"%s\" (%p) - Ready Q Stats -----\n" 98 "- total threads run : %'15" PRIu64 "\n" 99 "- total threads scheduled: %'15" PRIu64 "\n" 100 "- push average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 101 "- pop average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 102 "- local push avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 103 "- local pop avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 104 "- thread migrations : %'15" PRIu64 "\n" 105 "- Idle Sleep -\n" 106 "-- halts : %'15" PRIu64 "\n" 107 "-- cancelled halts : %'15" PRIu64 "\n" 108 "-- schedule wake : %'15" PRIu64 "\n" 109 "-- wake on exit : %'15" PRIu64 "\n" 110 "\n" 111 , type, name, id 112 , ready.pick.pop.success 113 , ready.pick.push.success 114 , push_len, push_sur, ready.pick.push.attempt 115 , pop_len , pop_sur , ready.pick.pop .attempt 116 , lpush_len, lpush_sur, ready.pick.push.local 117 , lpop_len , lpop_sur , ready.pick.pop .local 118 , ready.threads.migration 119 , ready.sleep.halts, ready.sleep.cancels, ready.sleep.wakes, ready.sleep.exits 120 ); 162 121 } 163 122 164 123 #if defined(CFA_HAVE_LINUX_IO_URING_H) 165 124 if( flags & CFA_STATS_IO ) { 166 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----"; 125 double avgrdy = ((double)io.submit_q.submit_avg.rdy) / io.submit_q.submit_avg.cnt; 126 double avgcsm = ((double)io.submit_q.submit_avg.csm) / io.submit_q.submit_avg.cnt; 167 127 168 uint64_t total_allocs = io.alloc.fast + io.alloc.slow; 169 double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs; 170 sstr | "- total allocations : " | eng3(io.alloc.fast) | "fast," | eng3(io.alloc.slow) | "slow (" | ws(3, 3, avgfasta) | "%)"; 171 sstr | "- failures : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk"; 128 double lavgv = 0; 129 double lavgb = 0; 130 if(io.submit_q.look_avg.cnt != 0) { 131 lavgv = ((double)io.submit_q.look_avg.val ) / io.submit_q.look_avg.cnt; 132 lavgb = ((double)io.submit_q.look_avg.block) / io.submit_q.look_avg.cnt; 133 } 172 134 173 uint64_t total_submits = io.submit.fast + io.submit.slow; 174 double avgfasts = (100.0 * (double)io.submit.fast) / total_submits; 175 sstr | "- total submits : " | eng3(io.submit.fast) | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)"; 176 sstr | "- flush external : " | eng3(io.flush.external); 135 double aavgv = 0; 136 double aavgb = 0; 137 if(io.submit_q.alloc_avg.cnt != 0) { 138 aavgv = ((double)io.submit_q.alloc_avg.val ) / io.submit_q.alloc_avg.cnt; 139 aavgb = ((double)io.submit_q.alloc_avg.block) / io.submit_q.alloc_avg.cnt; 140 } 177 141 178 sstr | "- io_uring_enter : " | eng3(io.calls.flush) | " (" | eng3(io.calls.drain) | ", " | eng3(io.calls.errors.busy) | " EBUSY)"; 179 180 double avgsubs = ((double)io.calls.submitted) / io.calls.flush; 181 double avgcomp = ((double)io.calls.completed) / io.calls.drain; 182 sstr | "- submits : " | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"; 183 sstr | "- completes : " | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"; 184 185 sstr | "- poller sleeping : " | eng3(io.poller.sleeps); 186 sstr | nl; 142 __cfaabi_bits_print_safe( STDOUT_FILENO, 143 "----- %s \"%s\" (%p) - I/O Stats -----\n" 144 "- total submit calls : %'15" PRIu64 "\n" 145 "- avg ready entries : %'18.2lf\n" 146 "- avg submitted entries : %'18.2lf\n" 147 "- total helped entries : %'15" PRIu64 "\n" 148 "- total leader entries : %'15" PRIu64 "\n" 149 "- total busy submit : %'15" PRIu64 "\n" 150 "- total ready search : %'15" PRIu64 "\n" 151 "- avg ready search len : %'18.2lf\n" 152 "- avg ready search block : %'18.2lf\n" 153 "- total alloc search : %'15" PRIu64 "\n" 154 "- avg alloc search len : %'18.2lf\n" 155 "- avg alloc search block : %'18.2lf\n" 156 "- total wait calls : %'15" PRIu64 "\n" 157 "- avg completion/wait : %'18.2lf\n" 158 "- total completion blocks: %'15" PRIu64 "\n" 159 "\n" 160 , type, name, id 161 , io.submit_q.submit_avg.cnt 162 , avgrdy, avgcsm 163 , io.submit_q.helped, io.submit_q.leader, io.submit_q.busy 164 , io.submit_q.look_avg.cnt 165 , lavgv, lavgb 166 , io.submit_q.alloc_avg.cnt 167 , aavgv, aavgb 168 , io.complete_q.completed_avg.cnt 169 , ((double)io.complete_q.completed_avg.val) / io.complete_q.completed_avg.cnt 170 , io.complete_q.blocks 171 ); 187 172 } 188 173 #endif 189 190 if(flags) write( sstr, stdout );191 174 } 192 193 #if defined(CFA_STATS_ARRAY)194 extern "C" {195 #include <stdio.h>196 #include <errno.h>197 #include <sys/stat.h>198 #include <fcntl.h>199 }200 201 void __flush_stat( struct __stats_t * this, const char * name, void * handle) {202 int ret = mkdir(".cfadata", 0755);203 if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno);204 205 char filename[100];206 snprintf(filename, 100, ".cfadata/%s%p.data", name, handle);207 208 int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644);209 if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno);210 211 for(i; this->array.cnt) {212 char line[100];213 size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value);214 write(fd, line, n);215 }216 217 this->array.cnt = 0;218 close(fd);219 }220 221 static __spinlock_t stats_lock;222 223 void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) {224 if(external) lock(stats_lock __cfaabi_dbg_ctx2);225 226 if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle );227 228 size_t idx = this->array.cnt;229 this->array.cnt++;230 231 if(external) unlock(stats_lock);232 233 this->array.values[idx].ts = rdtscl();234 this->array.values[idx].value = value;235 }236 #endif237 175 #endif -
libcfa/src/concurrency/stats.hfa
r5407cdc rfeacef9 1 1 #pragma once 2 3 // #define CFA_STATS_ARRAY 100004 2 5 3 #include <stdint.h> … … 16 14 static inline void __print_stats( struct __stats_t *, int, const char *, const char *, void * ) {} 17 15 #else 18 struct __stats_readyQ_pop_t {19 // number of attemps at poping something20 volatile uint64_t attempt;21 16 22 // number of successes at poping 23 volatile uint64_t success; 24 25 // number of attempts failed due to the lock being held 26 volatile uint64_t elock; 27 28 // number of attempts failed due to the queue being empty (lock held) 29 volatile uint64_t eempty; 30 31 // number of attempts failed due to the queue looking empty (lock not held) 32 volatile uint64_t espec; 33 }; 34 35 struct __attribute__((aligned(64))) __stats_readyQ_t { 36 // Push statistic 17 struct __attribute__((aligned(64))) __stats_readQ_t { 37 18 struct { 19 // Push statistic 38 20 struct { 39 // number of attemps at pushing something to preferred queues21 // number of attemps at pushing something 40 22 volatile uint64_t attempt; 41 23 24 // number of successes at pushing 25 volatile uint64_t success; 26 27 // number of attemps at pushing something to preferred queues 28 volatile uint64_t local; 29 42 30 // number of successes at pushing to preferred queues 31 volatile uint64_t lsuccess; 32 } push; 33 34 // Pop statistic 35 struct { 36 // number of reads of the mask 37 // picking an empty __cfa_readyQ_mask_t counts here 38 // but not as an attempt 39 volatile uint64_t probe; 40 41 // number of attemps at poping something 42 volatile uint64_t attempt; 43 44 // number of successes at poping 43 45 volatile uint64_t success; 44 }45 // Stats for local queue within cluster46 local,47 46 48 // Stats for non-local queues within cluster49 share,47 // number of attemps at poping something to preferred queues 48 volatile uint64_t local; 50 49 51 // Stats from outside cluster 52 extrn; 53 } push; 54 55 // Pop statistic 56 struct { 57 // pop from local queue 58 __stats_readyQ_pop_t local; 59 60 // pop before looking at local queue 61 __stats_readyQ_pop_t help; 62 63 // pop from some other queue 64 __stats_readyQ_pop_t steal; 65 66 // pop when searching queues sequentially 67 __stats_readyQ_pop_t search; 68 } pop; 69 50 // number of successes at poping to preferred queues 51 volatile uint64_t lsuccess; 52 } pop; 53 } pick; 70 54 struct { 71 55 volatile uint64_t migration; 72 volatile uint64_t extunpark;73 volatile int64_t threads; // number of threads in the system, includes only local change74 56 } threads; 75 57 struct { … … 84 66 struct __attribute__((aligned(64))) __stats_io_t{ 85 67 struct { 86 volatile uint64_t fast; 87 volatile uint64_t slow; 88 volatile uint64_t fail; 89 volatile uint64_t revoke; 90 volatile uint64_t block; 91 } alloc; 68 struct { 69 volatile uint64_t rdy; 70 volatile uint64_t csm; 71 volatile uint64_t avl; 72 volatile uint64_t cnt; 73 } submit_avg; 74 struct { 75 volatile uint64_t val; 76 volatile uint64_t cnt; 77 volatile uint64_t block; 78 } look_avg; 79 struct { 80 volatile uint64_t val; 81 volatile uint64_t cnt; 82 volatile uint64_t block; 83 } alloc_avg; 84 volatile uint64_t helped; 85 volatile uint64_t leader; 86 volatile uint64_t busy; 87 } submit_q; 92 88 struct { 93 volatile uint64_t fast;94 volatile uint64_t slow;95 } submit;96 struct {97 volatile uint64_t external;98 } flush;99 struct {100 volatile uint64_t drain;101 volatile uint64_t completed;102 volatile uint64_t flush;103 volatile uint64_t submitted;104 89 struct { 105 volatile uint64_t busy; 106 } errors; 107 } calls; 108 struct { 109 volatile uint64_t sleeps; 110 } poller; 111 }; 112 #endif 113 114 #if defined(CFA_STATS_ARRAY) 115 struct __stats_elem_t { 116 long long int ts; 117 int64_t value; 90 volatile uint64_t val; 91 volatile uint64_t cnt; 92 } completed_avg; 93 volatile uint64_t blocks; 94 } complete_q; 118 95 }; 119 96 #endif 120 97 121 98 struct __attribute__((aligned(128))) __stats_t { 122 __stats_read yQ_t ready;99 __stats_readQ_t ready; 123 100 #if defined(CFA_HAVE_LINUX_IO_URING_H) 124 101 __stats_io_t io; 125 102 #endif 126 127 #if defined(CFA_STATS_ARRAY)128 struct {129 __stats_elem_t * values;130 volatile size_t cnt;131 } array;132 #endif133 134 103 }; 135 104 … … 137 106 void __tally_stats( struct __stats_t *, struct __stats_t * ); 138 107 void __print_stats( struct __stats_t *, int, const char *, const char *, void * ); 139 #if defined(CFA_STATS_ARRAY)140 void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle);141 void __flush_stat( struct __stats_t *, const char *, void * );142 #else143 static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {}144 static inline void __flush_stat( struct __stats_t *, const char *, void * ) {}145 #endif146 108 #endif 147 109 -
libcfa/src/concurrency/thread.cfa
r5407cdc rfeacef9 39 39 link.next = 0p; 40 40 link.prev = 0p; 41 link.preferred = -1u; 42 last_proc = 0p; 41 link.preferred = -1; 43 42 #if defined( __CFA_WITH_VERIFY__ ) 44 43 canary = 0x0D15EA5E0D15EA5Ep; … … 63 62 } 64 63 64 FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t)) 65 65 66 forall(T &) 66 67 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) { … … 72 73 forall(T &) 73 74 const char * msg(ThreadCancelled(T) *) { 74 return "ThreadCancelled (...)";75 return "ThreadCancelled"; 75 76 } 76 77 77 78 forall(T &) 78 79 static void default_thread_cancel_handler(ThreadCancelled(T) & ) { 79 // Improve this error message, can I do formatting?80 80 abort( "Unhandled thread cancellation.\n" ); 81 81 } 82 82 83 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) 84 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 83 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))) 85 84 void ?{}( thread_dtor_guard_t & this, 86 85 T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) { 87 $monitor * m = get_monitor(thrd);86 $monitor * m = get_monitor(thrd); 88 87 $thread * desc = get_thread(thrd); 89 88 … … 104 103 } 105 104 desc->state = Cancelled; 106 void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 105 void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 107 106 join ? cancelHandler : default_thread_cancel_handler; 108 107 108 ThreadCancelled(T) except; 109 109 // TODO: Remove explitate vtable set once trac#186 is fixed. 110 ThreadCancelled(T) except; 111 except.virtual_table = &_default_vtable; 110 except.virtual_table = &get_exception_vtable(&except); 112 111 except.the_thread = &thrd; 113 112 except.the_exception = __cfaehm_cancellation_exception( cancellation ); 114 // Why is this cast required? 115 throwResume (ThreadCancelled(T) &)except; 113 throwResume except; 116 114 117 115 except.the_exception->virtual_table->free( except.the_exception ); … … 136 134 /* paranoid */ verify( this_thrd->context.SP ); 137 135 138 schedule_thread$( this_thrd );139 enable_interrupts( );136 __schedule_thread( this_thrd ); 137 enable_interrupts( __cfaabi_dbg_ctx ); 140 138 } 141 139 … … 160 158 161 159 //----------------------------------------------------------------------------- 162 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) 163 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 160 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))) 164 161 T & join( T & this ) { 165 162 thread_dtor_guard_t guard = { this, defaultResumptionHandler }; … … 170 167 disable_interrupts(); 171 168 uint64_t ret = __tls_rand(); 172 enable_interrupts( );169 enable_interrupts( __cfaabi_dbg_ctx ); 173 170 return ret; 174 171 } -
libcfa/src/concurrency/thread.hfa
r5407cdc rfeacef9 32 32 }; 33 33 34 EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (34 FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) ( 35 35 thread_t * the_thread; 36 36 exception_t * the_exception; … … 42 42 forall(T &) 43 43 const char * msg(ThreadCancelled(T) *); 44 45 // define that satisfies the trait without using the thread keyword 46 #define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this) 44 47 45 48 // Inline getters for threads/coroutines/monitors … … 79 82 }; 80 83 81 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) 82 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 84 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) ) 83 85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) ); 84 86 void ^?{}( thread_dtor_guard_t & this ); … … 126 128 //---------- 127 129 // join 128 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) 129 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 130 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) ) 130 131 T & join( T & this ); 131 132 -
libcfa/src/containers/list.hfa
r5407cdc rfeacef9 83 83 (this.is_terminator){ 1 }; 84 84 } 85 static inline void ?=?( $mgd_link(tE) &this, tE* elem ) { 86 this.elem = elem ; 87 this.terminator = 0p; 88 this.is_terminator = 0; 89 } 90 static inline void ?=?( $mgd_link(tE) &this, void * terminator ) { 91 this.elem = 0p; 92 this.terminator = terminator; 93 this.is_terminator = 1; 85 forall ( tInit | { void ?{}( $mgd_link(tE) &, tInit); } ) 86 static inline void ?=?( $mgd_link(tE) &this, tInit i ) { 87 ^?{}( this ); 88 ?{}( this, i ); 94 89 } 95 90 struct $dlinks { … … 186 181 187 182 static inline void insert_after(Tnode &list_pos, Telem &to_insert) { 188 verify(&list_pos != 0p);189 verify(&to_insert != 0p);183 assert (&list_pos != 0p); 184 assert (&to_insert != 0p); 190 185 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 191 verify($prev_link(singleton_to_insert).elem == 0p);192 verify($next_link(singleton_to_insert).elem == 0p);186 assert($prev_link(singleton_to_insert).elem == 0p); 187 assert($next_link(singleton_to_insert).elem == 0p); 193 188 $prev_link(singleton_to_insert) = & $tempcv_n2e(list_pos); 194 189 $next_link(singleton_to_insert) = $next_link(list_pos); … … 209 204 210 205 static inline void insert_before(Tnode &list_pos, Telem &to_insert) { 211 verify(&list_pos != 0p);212 verify(&to_insert != 0p);206 assert (&list_pos != 0p); 207 assert (&to_insert != 0p); 213 208 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 214 verify($prev_link(singleton_to_insert).elem == 0p);215 verify($next_link(singleton_to_insert).elem == 0p);209 assert($prev_link(singleton_to_insert).elem == 0p); 210 assert($next_link(singleton_to_insert).elem == 0p); 216 211 $next_link(singleton_to_insert) = & $tempcv_n2e(list_pos); 217 212 $prev_link(singleton_to_insert) = $prev_link(list_pos); … … 232 227 233 228 static inline void insert_first(dlist(Tnode, Telem) &list, Telem &to_insert) { 234 verify(&list != 0p);235 verify(&to_insert != 0p);229 assert (&list != 0p); 230 assert (&to_insert != 0p); 236 231 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 237 verify($prev_link(singleton_to_insert).elem == 0p);238 verify($next_link(singleton_to_insert).elem == 0p);232 assert($prev_link(singleton_to_insert).elem == 0p); 233 assert($next_link(singleton_to_insert).elem == 0p); 239 234 240 235 $prev_link(singleton_to_insert) = (void*) &list; … … 254 249 255 250 static inline void insert_last(dlist(Tnode, Telem) &list, Telem &to_insert) { 256 verify(&list != 0p);257 verify(&to_insert != 0p);251 assert (&list != 0p); 252 assert (&to_insert != 0p); 258 253 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 259 verify($next_link(singleton_to_insert).elem == 0p);260 verify($prev_link(singleton_to_insert).elem == 0p);254 assert($next_link(singleton_to_insert).elem == 0p); 255 assert($prev_link(singleton_to_insert).elem == 0p); 261 256 262 257 $next_link(singleton_to_insert) = (void*) &list; … … 276 271 277 272 static inline void remove(Tnode &list_pos) { 278 verify( &list_pos != 0p );273 assert( &list_pos != 0p ); 279 274 280 275 $mgd_link(Telem) &incoming_from_prev = *0p; … … 313 308 314 309 static inline bool ?`is_empty(dlist(Tnode, Telem) &list) { 315 verify( &list != 0p );310 assert( &list != 0p ); 316 311 $dlinks(Telem) *listLinks = & list.$links; 317 312 if (listLinks->next.is_terminator) { 318 verify(listLinks->prev.is_terminator);319 verify(listLinks->next.terminator);320 verify(listLinks->prev.terminator);313 assert(listLinks->prev.is_terminator); 314 assert(listLinks->next.terminator); 315 assert(listLinks->prev.terminator); 321 316 return true; 322 317 } else { 323 verify(!listLinks->prev.is_terminator);324 verify(listLinks->next.elem);325 verify(listLinks->prev.elem);318 assert(!listLinks->prev.is_terminator); 319 assert(listLinks->next.elem); 320 assert(listLinks->prev.elem); 326 321 return false; 327 322 } … … 329 324 330 325 static inline Telem & pop_first(dlist(Tnode, Telem) &list) { 331 verify( &list != 0p );332 verify( !list`is_empty );326 assert( &list != 0p ); 327 assert( !list`is_empty ); 333 328 $dlinks(Telem) *listLinks = & list.$links; 334 329 Telem & first = *listLinks->next.elem; … … 339 334 340 335 static inline Telem & pop_last(dlist(Tnode, Telem) &list) { 341 verify( &list != 0p );342 verify( !list`is_empty );336 assert( &list != 0p ); 337 assert( !list`is_empty ); 343 338 $dlinks(Telem) *listLinks = & list.$links; 344 339 Telem & last = *listLinks->prev.elem; -
libcfa/src/exception.c
r5407cdc rfeacef9 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Feb 24 13:40:00 202113 // Update Count : 3 612 // Last Modified On : Tue Oct 27 16:27:00 2020 13 // Update Count : 35 14 14 // 15 15 … … 26 26 #include "concurrency/invoke.h" 27 27 #include "stdhdr/assert.h" 28 #include "virtual.h"29 28 30 29 #if defined( __ARM_ARCH ) … … 47 46 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643; 48 47 49 // Base Exception type id: 50 struct __cfa__parent_vtable __cfatid_exception_t = { 51 NULL, 48 // Base exception vtable is abstract, you should not have base exceptions. 49 struct __cfaehm_base_exception_t_vtable 50 ___cfaehm_base_exception_t_vtable_instance = { 51 .parent = NULL, 52 .size = 0, 53 .copy = NULL, 54 .free = NULL, 55 .msg = NULL 52 56 }; 53 57 -
libcfa/src/exception.h
r5407cdc rfeacef9 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hr Apr 8 15:20:00 202113 // Update Count : 1 212 // Last Modified On : Tue Oct 27 14:45:00 2020 13 // Update Count : 11 14 14 // 15 15 … … 29 29 struct __cfaehm_base_exception_t; 30 30 typedef struct __cfaehm_base_exception_t exception_t; 31 struct __cfa__parent_vtable;32 31 struct __cfaehm_base_exception_t_vtable { 33 const struct __cfa __parent_vtable * __cfavir_typeid;32 const struct __cfaehm_base_exception_t_vtable * parent; 34 33 size_t size; 35 34 void (*copy)(struct __cfaehm_base_exception_t *this, … … 41 40 struct __cfaehm_base_exception_t_vtable const * virtual_table; 42 41 }; 43 extern struct __cfa__parent_vtable __cfatid_exception_t; 42 extern struct __cfaehm_base_exception_t_vtable 43 ___cfaehm_base_exception_t_vtable_instance; 44 44 45 45 … … 104 104 /* The first field must be a pointer to a virtual table. 105 105 * That virtual table must be a decendent of the base exception virtual table. 106 * The virtual table must point at the prober type-id.107 * None of these can be enforced in an assertion.108 106 */ 107 virtualT const & get_exception_vtable(exceptT *); 108 // Always returns the virtual table for this type (associated types hack). 109 109 }; 110 110 -
libcfa/src/exception.hfa
r5407cdc rfeacef9 10 10 // Created On : Thu Apr 7 10:25:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hr Apr 8 15:16:00 202113 // Update Count : 412 // Last Modified On : Tue Aug 4 16:22:00 2020 13 // Update Count : 3 14 14 // 15 15 … … 18 18 // ----------------------------------------------------------------------------------------------- 19 19 20 // EHM_EXCEPTION(exception_name)(fields...); 21 // Create an exception (a virtual structure that inherits from exception_t) 22 // with the given name and fields. 23 #define EHM_EXCEPTION(exception_name) \ 24 _EHM_TYPE_ID_STRUCT(exception_name, ); \ 25 _EHM_TYPE_ID_VALUE(exception_name, ); \ 26 _EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \ 27 _EHM_EXCEPTION_STRUCT(exception_name, , ) 28 29 // EHM_EXTERN_VTABLE(exception_name, table_name); 30 // Forward declare a virtual table called table_name for exception_name type. 31 #define EHM_EXTERN_VTABLE(exception_name, table_name) \ 32 _EHM_EXTERN_VTABLE(exception_name, , table_name) 33 34 // EHM_VIRTUAL_TABLE(exception_name, table_name); 35 // Define a virtual table called table_name for exception_name type. 36 #define EHM_VIRTUAL_TABLE(exception_name, table_name) \ 37 _EHM_DEFINE_COPY(exception_name, ) \ 38 _EHM_DEFINE_MSG(exception_name, ) \ 39 _EHM_VIRTUAL_TABLE(exception_name, , table_name) 40 41 // EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...); 42 // As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones. 43 // The assertions list should include all polymorphic parameters and 44 // assertions inside a parentisized list. Parameters should include all the 45 // polymorphic parameter names inside a parentisized list (same order). 46 #define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \ 47 _EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \ 48 _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \ 49 _EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters) 50 51 // EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name); 52 // As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones. 53 // Arguments should be the parentisized list of polymorphic arguments. 54 #define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \ 55 _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) 56 57 // EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name); 58 // As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones. 59 // Arguments should be the parentisized list of polymorphic arguments. 60 #define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \ 61 _EHM_TYPE_ID_VALUE(exception_name, arguments); \ 62 _EHM_DEFINE_COPY(exception_name, arguments) \ 63 _EHM_DEFINE_MSG(exception_name, arguments) \ 64 _EHM_VIRTUAL_TABLE(exception_name, arguments, table_name) 65 66 // EHM_DEFAULT_VTABLE(exception_name, (arguments)) 67 // Create a declaration for a (possibly polymorphic) default vtable. 68 #define EHM_DEFAULT_VTABLE(exception_name, arguments) \ 69 _EHM_VTABLE_TYPE(exception_name) arguments & const _default_vtable 20 // TRIVIAL_EXCEPTION_DECLARATION(exception_name); 21 // Declare a trivial exception, one that adds no fields or features. 22 // This will make the exception visible and may go in a .hfa or .cfa file. 23 #define TRIVIAL_EXCEPTION_DECLARATION(...) \ 24 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__) 25 26 // TRIVIAL_EXCEPTION_INSTANCE(exception_name); 27 // Create the trival exception. This must be used exactly once and should be used in a .cfa file, 28 // as it creates the unique instance of the virtual table. 29 #define TRIVIAL_EXCEPTION_INSTANCE(...) _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__) 30 31 // TRIVIAL_EXCEPTION(exception_name[, parent_name]); 32 // Does both of the above, a short hand if the exception is only used in one .cfa file. 33 // For legacy reasons this is the only one that official supports having a parent other than the 34 // base exception. This feature may be removed or changed. 35 #define TRIVIAL_EXCEPTION(...) \ 36 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__); \ 37 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__) 38 39 // FORALL_TRIVIAL_EXCEPTION(exception_name, (assertions...), (parameters...)); 40 // Forward declare a polymorphic but otherwise trivial exception type. You must provide the entire 41 // assertion list (exactly what would go in the forall clause) and parameters list (only the 42 // parameter names from the assertion list, same order and comma seperated). This should be 43 // visible where ever use the exception. This just generates the polymorphic framework, see 44 // POLY_VTABLE_DECLARATION to allow instantiations. 45 #define FORALL_TRIVIAL_EXCEPTION(exception_name, assertions, parameters) \ 46 _FORALL_TRIVIAL_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 47 48 // FORALL_TRIVIAL_INSTANCE(exception_name, (assertions...), (parameters...)) 49 // Create the forall trivial exception. The assertion list and parameters must match. 50 // There must be exactly one use of this in a program for each exception type. This just 51 // generates the polymorphic framework, see POLY_VTABLE_INSTANCE to allow instantiations. 52 #define FORALL_TRIVIAL_INSTANCE(exception_name, assertions, parameters) \ 53 _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) 54 55 // DATA_EXCEPTION(exception_name)(fields...); 56 // Forward declare an exception that adds fields but no features. The added fields go in the 57 // second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE). 58 #define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__) 59 60 // FORALL_DATA_EXCEPTION(exception_name, (assertions...), (parameters...))(fields...); 61 // Define a polymorphic exception that adds fields but no additional features. The assertion list 62 // and matching parameters must match. Then you can give the list of fields. This should be 63 // visible where ever you use the exception. This just generates the polymorphic framework, see 64 // POLY_VTABLE_DECLARATION to allow instantiations. 65 #define FORALL_DATA_EXCEPTION(exception_name, assertions, parameters) \ 66 _FORALL_DATA_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 67 68 // FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...)) 69 // Create a polymorphic data exception. The assertion list and parameters must match. This should 70 // appear once in each program. This just generates the polymorphic framework, see 71 // POLY_VTABLE_INSTANCE to allow instantiations. 72 #define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \ 73 _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) 74 75 // VTABLE_DECLARATION(exception_name)([new_features...]); 76 // Declare a virtual table type for an exception with exception_name. You may also add features 77 // (fields on the virtual table) by including them in the second list. 78 #define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__) 79 80 // VTABLE_INSTANCE(exception_name)(msg [, others...]); 81 // Create the instance of the virtual table. There must be exactly one instance of a virtual table 82 // for each exception type. This fills in most of the fields of the virtual table (uses ?=? and 83 // ^?{}) but you must provide the message function and any other fields added in the declaration. 84 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) 85 86 // FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]); 87 // Declare a polymorphic virtual table type for an exception with exception_name, the given 88 // assertions and parameters. You may also add features (fields on the virtual table). This just 89 // generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations. 90 #define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \ 91 _FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 92 93 // POLY_VTABLE_DECLARATION(exception_name, types...); 94 // Declares that an instantiation for this exception exists for the given types. This should be 95 // visible anywhere you use the instantiation of the exception is used. 96 #define POLY_VTABLE_DECLARATION(exception_name, ...) \ 97 VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \ 98 extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) 99 100 // POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]); 101 // Creates an instantiation for the given exception for the given types. This should occur only 102 // once in the entire program. You must fill in all features, message and any others given in the 103 // initial declaration. 104 #define POLY_VTABLE_INSTANCE(exception_name, ...) \ 105 _POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__) 106 107 // VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name) 108 // Get the name of the vtable type or the name of the vtable instance for an exception type. 109 #define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable) 110 #define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance) 111 112 // VTABLE_FIELD(exception_name); 113 // FORALL_VTABLE_FIELD(exception_name, (parameters-or-types)); 114 // The declaration of the virtual table field. Should be the first declaration in a virtual type. 115 #define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table 116 #define FORALL_VTABLE_FIELD(exception_name, parameters) \ 117 VTABLE_TYPE(exception_name) parameters const * virtual_table 118 119 // VTABLE_INIT(object_reference, exception_name); 120 // Sets a virtual table field on an object to the virtual table instance for the type. 121 #define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name) 122 123 // VTABLE_ASSERTION(exception_name, (parameters...)) 124 // The assertion that there is an instantiation of the vtable for the exception and types. 125 #define VTABLE_ASSERTION(exception_name, parameters) \ 126 { VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); } 70 127 71 128 // IS_EXCEPTION(exception_name [, (...parameters)]) … … 78 135 #define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~) 79 136 80 // Macros starting with a leading underscore are internal. 81 82 // Create an exception type definition. must be tailing, can be polymorphic. 83 #define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \ 84 forall_clause struct exception_name { \ 85 _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \ 86 _CLOSE 87 88 // Create a (possibly polymorphic) virtual table forward declaration. 89 #define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \ 90 extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name 91 92 // Create a (possibly polymorphic) virtual table definition. 93 #define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \ 94 const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \ 95 .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \ 96 .size : sizeof(struct exception_type arguments), \ 97 .copy : copy, \ 98 .^?{} : ^?{}, \ 99 .msg : msg, \ 137 // All internal helper macros begin with an underscore. 138 #define _CLOSE(...) __VA_ARGS__ } 139 #define _GLUE2(left, right) left##right 140 #define _GLUE3(left, middle, right) left##middle##right 141 #define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,) 142 #define _UNPACK(...) __VA_ARGS__ 143 144 #define _TRIVIAL_EXCEPTION_DECLARATION(exception_name, parent_name, ...) \ 145 _VTABLE_DECLARATION(exception_name, parent_name)(); \ 146 struct exception_name { \ 147 VTABLE_FIELD(exception_name); \ 148 }; \ 149 void ?{}(exception_name & this); \ 150 const char * _GLUE2(exception_name,_msg)(exception_name * this) 151 152 #define _TRIVIAL_EXCEPTION_INSTANCE(exception_name, parent_name, ...) \ 153 void ?{}(exception_name & this) { \ 154 VTABLE_INIT(this, exception_name); \ 155 } \ 156 const char * _GLUE2(exception_name,_msg)(exception_name * this) { \ 157 return #exception_name; \ 158 } \ 159 _VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg)) 160 161 #define _FORALL_TRIVIAL_EXCEPTION(exception_name, parent_name, assertions, \ 162 parameters, parent_parameters) \ 163 _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \ 164 parameters, parent_parameters)(); \ 165 forall assertions struct exception_name { \ 166 FORALL_VTABLE_FIELD(exception_name, parameters); \ 167 }; \ 168 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) 169 170 #define _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) \ 171 forall(_UNPACK assertions | \ 172 is_exception(exception_name parameters, VTABLE_TYPE(exception_name) parameters)) \ 173 void ?{}(exception_name parameters & this) 174 175 #define _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) \ 176 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) { \ 177 (this).virtual_table = &get_exception_vtable(&this); \ 100 178 } 101 179 102 // Create a (possibly polymorphic) copy function from an assignment operator. 103 #define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \ 104 forall_clause void copy(exception_name parameters * this, \ 105 exception_name parameters * that) { \ 106 *this = *that; \ 107 } 108 109 #define _EHM_DEFINE_COPY(exception_name, arguments) \ 110 void copy(exception_name arguments * this, exception_name arguments * that) { \ 111 *this = *that; \ 112 } 113 114 // Create a (possibly polymorphic) msg function 115 #define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \ 116 forall_clause const char * msg(exception_name parameters * this) { \ 117 return #exception_name #parameters; \ 118 } 119 120 #define _EHM_DEFINE_MSG(exception_name, arguments) \ 121 const char * msg(exception_name arguments * this) { \ 122 return #exception_name #arguments; \ 123 } 124 125 // Produces the C compatable name of the virtual table type for a virtual type. 126 #define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable) 127 128 // Create the vtable type for exception name. 129 #define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \ 130 forall_clause struct exception_name; \ 131 forall_clause _EHM_VTABLE_TYPE(exception_name) { \ 132 _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \ 180 #define _DATA_EXCEPTION(exception_name, parent_name, ...) \ 181 _VTABLE_DECLARATION(exception_name, parent_name)(); \ 182 struct exception_name { \ 183 VTABLE_FIELD(exception_name); \ 184 _CLOSE 185 186 #define _FORALL_DATA_EXCEPTION(exception_name, parent_name, \ 187 assertions, parameters, parent_parameters) \ 188 _FORALL_VTABLE_DECLARATION(exception_name, parent_name, \ 189 assertions, parameters, parent_parameters)(); \ 190 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters); \ 191 forall assertions struct exception_name { \ 192 FORALL_VTABLE_FIELD(exception_name, parameters); \ 193 _CLOSE 194 195 #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ 196 struct exception_name; \ 197 VTABLE_TYPE(exception_name); \ 198 VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *); \ 199 extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ 200 VTABLE_TYPE(exception_name) { \ 201 VTABLE_TYPE(parent_name) const * parent; \ 202 size_t size; \ 203 void (*copy)(exception_name * this, exception_name * other); \ 204 void (*^?{})(exception_name & this); \ 205 const char * (*msg)(exception_name * this); \ 206 _CLOSE 207 208 #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ 209 VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *) { \ 210 return VTABLE_NAME(exception_name); \ 211 } \ 212 void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ 213 *this = *other; \ 214 } \ 215 VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \ 216 &VTABLE_NAME(parent_name), sizeof(exception_name), \ 217 _GLUE2(exception_name,_copy), ^?{}, \ 218 _CLOSE 219 220 #define _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \ 221 parameters, parent_parameters) \ 222 forall assertions struct exception_name; \ 223 forall assertions VTABLE_TYPE(exception_name) { \ 224 VTABLE_TYPE(parent_name) parent_parameters const * parent; \ 133 225 size_t size; \ 134 226 void (*copy)(exception_name parameters * this, exception_name parameters * other); \ 135 227 void (*^?{})(exception_name parameters & this); \ 136 228 const char * (*msg)(exception_name parameters * this); \ 137 } 138 139 // Define the function required to satify the trait for exceptions. 140 #define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \ 141 forall_clause inline void mark_exception( \ 142 exception_name parameters const &, \ 143 _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \ 144 145 #define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \ 146 forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \ 147 get_exception_vtable(exception_name parameters const & this) { \ 148 /* This comes before the structure definition, but we know the offset. */ \ 149 /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \ 150 assert(false); \ 151 } 152 153 // Generates a new type-id structure. This is used to mangle the name of the 154 // type-id instance so it also includes polymorphic information. Must be the 155 // direct decendent of exception_t. 156 // The second field is used to recover type information about the exception. 157 #define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \ 158 forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \ 159 __cfa__parent_vtable const * parent; \ 160 } 161 162 // Generate a new type-id value. 163 #define _EHM_TYPE_ID_VALUE(exception_name, arguments) \ 164 __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \ 165 _EHM_TYPE_ID_TYPE(exception_name) arguments const \ 166 _EHM_TYPE_ID_NAME(exception_name) = { \ 167 &__cfatid_exception_t, \ 168 } 169 170 // _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to 171 // be updated to extend the hierarchy if we are still using macros when that 172 // is added. 173 174 // Produce the C compatable name of the type-id type for an exception type. 175 #define _EHM_TYPE_ID_TYPE(exception_name) \ 176 struct _GLUE2(__cfatid_struct_, exception_name) 177 178 // Produce the name of the instance of the type-id for an exception type. 179 #define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name) 229 _CLOSE 230 231 #define _POLY_VTABLE_INSTANCE(exception_name, parent_name, ...) \ 232 extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name); \ 233 VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable( \ 234 exception_name(__VA_ARGS__) *) { \ 235 return VTABLE_NAME(exception_name); \ 236 } \ 237 void _GLUE2(exception_name,_copy)( \ 238 exception_name(__VA_ARGS__) * this, exception_name(__VA_ARGS__) * other) { \ 239 *this = *other; \ 240 } \ 241 VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) @= { \ 242 &VTABLE_NAME(parent_name), sizeof(exception_name(__VA_ARGS__)), \ 243 _GLUE2(exception_name,_copy), ^?{}, \ 244 _CLOSE 180 245 181 246 #define _IS_EXCEPTION(kind, exception_name, parameters, ...) \ 182 kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters) 183 184 // Internal helper macros: 185 #define _CLOSE(...) __VA_ARGS__ } 186 #define _GLUE2(left, right) left##right 247 kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters) -
libcfa/src/fstream.cfa
r5407cdc rfeacef9 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 22:08:57 202113 // Update Count : 44214 // 15 16 #include "fstream.hfa" // also includes iostream.hfa12 // Last Modified On : Fri Jun 19 16:24:54 2020 13 // Update Count : 384 14 // 15 16 #include "fstream.hfa" 17 17 18 18 #include <stdio.h> // vfprintf, vfscanf 19 19 #include <stdlib.h> // exit 20 20 #include <stdarg.h> // varargs 21 #include <string.h> // strncpy, strerror 21 #include <string.h> // strlen 22 #include <float.h> // DBL_DIG, LDBL_DIG 23 #include <complex.h> // creal, cimag 22 24 #include <assert.h> 23 25 #include <errno.h> // errno 24 26 27 25 28 // *********************************** ofstream *********************************** 26 29 … … 29 32 30 33 void ?{}( ofstream & os, void * file ) { 31 os.file$ = file; 32 os.sepDefault$ = true; 33 os.sepOnOff$ = false; 34 os.nlOnOff$ = true; 35 os.prt$ = false; 36 os.sawNL$ = false; 37 os.acquired$ = false; 38 sepSetCur$( os, sepGet( os ) ); 34 os.$file = file; 35 os.$sepDefault = true; 36 os.$sepOnOff = false; 37 os.$nlOnOff = true; 38 os.$prt = false; 39 os.$sawNL = false; 40 $sepSetCur( os, sepGet( os ) ); 39 41 sepSet( os, " " ); 40 42 sepSetTuple( os, ", " ); … … 42 44 43 45 // private 44 bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }45 void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }46 void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }47 const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }48 void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$= sepCur; }49 bool getNL$( ofstream & os ) { return os.sawNL$; }50 void setNL$( ofstream & os, bool state ) { os.sawNL$= state; }51 bool getANL$( ofstream & os ) { return os.nlOnOff$; }52 bool getPrt$( ofstream & os ) { return os.prt$; }53 void setPrt$( ofstream & os, bool state ) { os.prt$= state; }46 bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; } 47 void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; } 48 void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; } 49 const char * $sepGetCur( ofstream & os ) { return os.$sepCur; } 50 void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur = sepCur; } 51 bool $getNL( ofstream & os ) { return os.$sawNL; } 52 void $setNL( ofstream & os, bool state ) { os.$sawNL = state; } 53 bool $getANL( ofstream & os ) { return os.$nlOnOff; } 54 bool $getPrt( ofstream & os ) { return os.$prt; } 55 void $setPrt( ofstream & os, bool state ) { os.$prt = state; } 54 56 55 57 // public 56 void ?{}( ofstream & os ) { os. file$= 0p; }58 void ?{}( ofstream & os ) { os.$file = 0p; } 57 59 58 60 void ?{}( ofstream & os, const char name[], const char mode[] ) { … … 68 70 } // ^?{} 69 71 70 void sepOn( ofstream & os ) { os. sepOnOff$ = ! getNL$( os ); }71 void sepOff( ofstream & os ) { os. sepOnOff$= false; }72 void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); } 73 void sepOff( ofstream & os ) { os.$sepOnOff = false; } 72 74 73 75 bool sepDisable( ofstream & os ) { 74 bool temp = os. sepDefault$;75 os. sepDefault$= false;76 sepReset$( os );76 bool temp = os.$sepDefault; 77 os.$sepDefault = false; 78 $sepReset( os ); 77 79 return temp; 78 80 } // sepDisable 79 81 80 82 bool sepEnable( ofstream & os ) { 81 bool temp = os. sepDefault$;82 os. sepDefault$= true;83 if ( os. sepOnOff$ ) sepReset$( os ); // start of line ?83 bool temp = os.$sepDefault; 84 os.$sepDefault = true; 85 if ( os.$sepOnOff ) $sepReset( os ); // start of line ? 84 86 return temp; 85 87 } // sepEnable 86 88 87 void nlOn( ofstream & os ) { os. nlOnOff$= true; }88 void nlOff( ofstream & os ) { os. nlOnOff$= false; }89 90 const char * sepGet( ofstream & os ) { return os. separator$; }89 void nlOn( ofstream & os ) { os.$nlOnOff = true; } 90 void nlOff( ofstream & os ) { os.$nlOnOff = false; } 91 92 const char * sepGet( ofstream & os ) { return os.$separator; } 91 93 void sepSet( ofstream & os, const char s[] ) { 92 94 assert( s ); 93 strncpy( os. separator$, s, ofstream_sepSize - 1 );94 os. separator$[ofstream_sepSize - 1] = '\0';95 strncpy( os.$separator, s, sepSize - 1 ); 96 os.$separator[sepSize - 1] = '\0'; 95 97 } // sepSet 96 98 97 const char * sepGetTuple( ofstream & os ) { return os. tupleSeparator$; }99 const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; } 98 100 void sepSetTuple( ofstream & os, const char s[] ) { 99 101 assert( s ); 100 strncpy( os. tupleSeparator$, s, ofstream_sepSize - 1 );101 os. tupleSeparator$[ofstream_sepSize - 1] = '\0';102 strncpy( os.$tupleSeparator, s, sepSize - 1 ); 103 os.$tupleSeparator[sepSize - 1] = '\0'; 102 104 } // sepSet 103 105 104 106 void ends( ofstream & os ) { 105 if ( getANL$( os ) ) nl( os );106 else setPrt$( os, false ); // turn off107 if ( $getANL( os ) ) nl( os ); 108 else $setPrt( os, false ); // turn off 107 109 if ( &os == &exit ) exit( EXIT_FAILURE ); 108 110 if ( &os == &abort ) abort(); 109 if ( os.acquired$ ) { os.acquired$ = false; release( os ); }110 111 } // ends 111 112 112 boolfail( ofstream & os ) {113 return os. file$ == 0 || ferror( (FILE *)(os.file$) );113 int fail( ofstream & os ) { 114 return os.$file == 0 || ferror( (FILE *)(os.$file) ); 114 115 } // fail 115 116 116 117 int flush( ofstream & os ) { 117 return fflush( (FILE *)(os. file$) );118 return fflush( (FILE *)(os.$file) ); 118 119 } // flush 119 120 … … 134 135 135 136 void close( ofstream & os ) { 136 if ( (FILE *)(os. file$) == 0p ) return;137 if ( (FILE *)(os. file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return;138 139 if ( fclose( (FILE *)(os. file$) ) == EOF ) {137 if ( (FILE *)(os.$file) == 0p ) return; 138 if ( (FILE *)(os.$file) == (FILE *)stdout || (FILE *)(os.$file) == (FILE *)stderr ) return; 139 140 if ( fclose( (FILE *)(os.$file) ) == EOF ) { 140 141 abort | IO_MSG "close output" | nl | strerror( errno ); 141 142 } // if 142 os. file$= 0p;143 os.$file = 0p; 143 144 } // close 144 145 … … 148 149 } // if 149 150 150 if ( fwrite( data, 1, size, (FILE *)(os. file$) ) != size ) {151 if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) { 151 152 abort | IO_MSG "write" | nl | strerror( errno ); 152 153 } // if … … 157 158 va_list args; 158 159 va_start( args, format ); 159 int len = vfprintf( (FILE *)(os. file$), format, args );160 int len = vfprintf( (FILE *)(os.$file), format, args ); 160 161 if ( len == EOF ) { 161 if ( ferror( (FILE *)(os. file$) ) ) {162 if ( ferror( (FILE *)(os.$file) ) ) { 162 163 abort | IO_MSG "invalid write"; 163 164 } // if … … 165 166 va_end( args ); 166 167 167 setPrt$( os, true ); // called in output cascade168 sepReset$( os ); // reset separator168 $setPrt( os, true ); // called in output cascade 169 $sepReset( os ); // reset separator 169 170 return len; 170 171 } // fmt 171 172 inline void acquire( ofstream & os ) {173 lock( os.lock$ );174 if ( ! os.acquired$ ) os.acquired$ = true;175 else unlock( os.lock$ );176 } // acquire177 178 inline void release( ofstream & os ) {179 unlock( os.lock$ );180 } // release181 182 void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); }183 void ^?{}( osacquire & acq ) { release( acq.os ); }184 172 185 173 static ofstream soutFile = { (FILE *)stdout }; … … 188 176 ofstream & serr = serrFile, & stderr = serrFile; 189 177 190 static ofstream lsoutFile = { (FILE *)stdout };191 ofstream & lsout = lsoutFile;192 193 178 static ofstream exitFile = { (FILE *)stdout }; 194 179 ofstream & exit = exitFile; … … 196 181 ofstream & abort = abortFile; 197 182 198 ofstream & nl( ofstream & os ) {199 nl$( os ); // call basic_ostream nl200 flush( os );201 return os;202 // (ofstream &)(os | '\n');203 // setPrt$( os, false ); // turn off204 // setNL$( os, true );205 // flush( os );206 // return sepOff( os ); // prepare for next line207 } // nl208 183 209 184 // *********************************** ifstream *********************************** … … 212 187 // private 213 188 void ?{}( ifstream & is, void * file ) { 214 is.file$ = file; 215 is.nlOnOff$ = false; 216 is.acquired$ = false; 189 is.$file = file; 190 is.$nlOnOff = false; 217 191 } // ?{} 218 192 219 193 // public 220 void ?{}( ifstream & is ) { is. file$= 0p; }194 void ?{}( ifstream & is ) { is.$file = 0p; } 221 195 222 196 void ?{}( ifstream & is, const char name[], const char mode[] ) { … … 232 206 } // ^?{} 233 207 234 void nlOn( ifstream & os ) { os. nlOnOff$= true; }235 void nlOff( ifstream & os ) { os. nlOnOff$= false; }236 bool getANL( ifstream & os ) { return os. nlOnOff$; }237 238 boolfail( ifstream & is ) {239 return is. file$ == 0p || ferror( (FILE *)(is.file$) );208 void nlOn( ifstream & os ) { os.$nlOnOff = true; } 209 void nlOff( ifstream & os ) { os.$nlOnOff = false; } 210 bool getANL( ifstream & os ) { return os.$nlOnOff; } 211 212 int fail( ifstream & is ) { 213 return is.$file == 0p || ferror( (FILE *)(is.$file) ); 240 214 } // fail 241 215 242 void ends( ifstream & is ) {243 if ( is.acquired$ ) { is.acquired$ = false; release( is ); }244 } // ends245 246 216 int eof( ifstream & is ) { 247 return feof( (FILE *)(is. file$) );217 return feof( (FILE *)(is.$file) ); 248 218 } // eof 249 219 … … 256 226 } // if 257 227 #endif // __CFA_DEBUG__ 258 is. file$= file;228 is.$file = file; 259 229 } // open 260 230 … … 264 234 265 235 void close( ifstream & is ) { 266 if ( (FILE *)(is. file$) == 0p ) return;267 if ( (FILE *)(is. file$) == (FILE *)stdin ) return;268 269 if ( fclose( (FILE *)(is. file$) ) == EOF ) {236 if ( (FILE *)(is.$file) == 0p ) return; 237 if ( (FILE *)(is.$file) == (FILE *)stdin ) return; 238 239 if ( fclose( (FILE *)(is.$file) ) == EOF ) { 270 240 abort | IO_MSG "close input" | nl | strerror( errno ); 271 241 } // if 272 is. file$= 0p;242 is.$file = 0p; 273 243 } // close 274 244 … … 278 248 } // if 279 249 280 if ( fread( data, size, 1, (FILE *)(is. file$) ) == 0 ) {250 if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) { 281 251 abort | IO_MSG "read" | nl | strerror( errno ); 282 252 } // if … … 289 259 } // if 290 260 291 if ( ungetc( c, (FILE *)(is. file$) ) == EOF ) {261 if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) { 292 262 abort | IO_MSG "ungetc" | nl | strerror( errno ); 293 263 } // if … … 299 269 300 270 va_start( args, format ); 301 int len = vfscanf( (FILE *)(is. file$), format, args );271 int len = vfscanf( (FILE *)(is.$file), format, args ); 302 272 if ( len == EOF ) { 303 if ( ferror( (FILE *)(is. file$) ) ) {273 if ( ferror( (FILE *)(is.$file) ) ) { 304 274 abort | IO_MSG "invalid read"; 305 275 } // if … … 309 279 } // fmt 310 280 311 inline void acquire( ifstream & is ) {312 lock( is.lock$ );313 if ( ! is.acquired$ ) is.acquired$ = true;314 else unlock( is.lock$ );315 } // acquire316 317 inline void release( ifstream & is ) {318 unlock( is.lock$ );319 } // release320 321 void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); }322 void ^?{}( isacquire & acq ) { release( acq.is ); }323 324 281 static ifstream sinFile = { (FILE *)stdin }; 325 282 ifstream & sin = sinFile, & stdin = sinFile; … … 329 286 330 287 331 EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table);332 288 void ?{}( Open_Failure & this, ofstream & ostream ) { 333 this.virtual_table = &Open_Failure_main_table;289 VTABLE_INIT(this, Open_Failure); 334 290 this.ostream = &ostream; 335 291 this.tag = 1; 336 292 } 337 293 void ?{}( Open_Failure & this, ifstream & istream ) { 338 this.virtual_table = &Open_Failure_main_table;294 VTABLE_INIT(this, Open_Failure); 339 295 this.istream = &istream; 340 296 this.tag = 0; 341 297 } 298 const char * Open_Failure_msg(Open_Failure * this) { 299 return "Open_Failure"; 300 } 301 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg); 342 302 void throwOpen_Failure( ofstream & ostream ) { 343 303 Open_Failure exc = { ostream }; -
libcfa/src/fstream.hfa
r5407cdc rfeacef9 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 22:00:30 202113 // Update Count : 22612 // Last Modified On : Fri Jun 19 16:29:17 2020 13 // Update Count : 189 14 14 // 15 15 16 16 #pragma once 17 17 18 #include "bits/weakso_locks.hfa" // mutex_lock18 #include "bits/weakso_locks.hfa" 19 19 #include "iostream.hfa" 20 20 #include <exception.hfa> … … 24 24 25 25 26 enum { ofstream_sepSize = 16 };26 enum { sepSize = 16 }; 27 27 struct ofstream { 28 void * file$; 29 bool sepDefault$; 30 bool sepOnOff$; 31 bool nlOnOff$; 32 bool prt$; // print text 33 bool sawNL$; 34 const char * sepCur$; 35 char separator$[ofstream_sepSize]; 36 char tupleSeparator$[ofstream_sepSize]; 37 multiple_acquisition_lock lock$; 38 bool acquired$; 28 void * $file; 29 bool $sepDefault; 30 bool $sepOnOff; 31 bool $nlOnOff; 32 bool $prt; // print text 33 bool $sawNL; 34 const char * $sepCur; 35 char $separator[sepSize]; 36 char $tupleSeparator[sepSize]; 37 // multiple_acquisition_lock lock; 39 38 }; // ofstream 40 39 41 // Satisfies ostream42 43 40 // private 44 bool sepPrt$( ofstream & );45 void sepReset$( ofstream & );46 void sepReset$( ofstream &, bool );47 const char * sepGetCur$( ofstream & );48 void sepSetCur$( ofstream &, const char [] );49 bool getNL$( ofstream & );50 void setNL$( ofstream &, bool );51 bool getANL$( ofstream & );52 bool getPrt$( ofstream & );53 void setPrt$( ofstream &, bool );41 bool $sepPrt( ofstream & ); 42 void $sepReset( ofstream & ); 43 void $sepReset( ofstream &, bool ); 44 const char * $sepGetCur( ofstream & ); 45 void $sepSetCur( ofstream &, const char [] ); 46 bool $getNL( ofstream & ); 47 void $setNL( ofstream &, bool ); 48 bool $getANL( ofstream & ); 49 bool $getPrt( ofstream & ); 50 void $setPrt( ofstream &, bool ); 54 51 55 52 // public … … 66 63 void sepSetTuple( ofstream &, const char [] ); 67 64 68 void ends( ofstream & ); 69 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 70 71 bool fail( ofstream & ); 65 void ends( ofstream & os ); 66 int fail( ofstream & ); 72 67 int flush( ofstream & ); 73 void open( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w"68 void open( ofstream &, const char name[], const char mode[] ); 74 69 void open( ofstream &, const char name[] ); 75 70 void close( ofstream & ); 76 71 ofstream & write( ofstream &, const char data[], size_t size ); 72 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 77 73 78 void acquire( ofstream & ); 79 void release( ofstream & ); 80 81 struct osacquire { 82 ofstream & os; 83 }; 84 void ?{}( osacquire & acq, ofstream & ); 85 void ^?{}( osacquire & acq ); 86 87 void ?{}( ofstream & ); 88 void ?{}( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w" 89 void ?{}( ofstream &, const char name[] ); 90 void ^?{}( ofstream & ); 91 92 // private 93 static inline ofstream & nl$( ofstream & os ) { return nl( os ); } // remember basic_ostream nl 94 // public 95 ofstream & nl( ofstream & os ); // override basic_ostream nl 74 void ?{}( ofstream & os ); 75 void ?{}( ofstream & os, const char name[], const char mode[] ); 76 void ?{}( ofstream & os, const char name[] ); 77 void ^?{}( ofstream & os ); 96 78 97 79 extern ofstream & sout, & stdout, & serr, & stderr; // aliases … … 103 85 104 86 struct ifstream { 105 void * file$; 106 bool nlOnOff$; 107 multiple_acquisition_lock lock$; 108 bool acquired$; 87 void * $file; 88 bool $nlOnOff; 109 89 }; // ifstream 110 111 // Satisfies istream112 90 113 91 // public … … 115 93 void nlOff( ifstream & ); 116 94 bool getANL( ifstream & ); 117 void ends( ifstream & ); 118 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 119 120 bool fail( ifstream & is ); 95 int fail( ifstream & is ); 121 96 int eof( ifstream & is ); 122 void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"97 void open( ifstream & is, const char name[], const char mode[] ); 123 98 void open( ifstream & is, const char name[] ); 124 99 void close( ifstream & is ); 125 100 ifstream & read( ifstream & is, char * data, size_t size ); 126 101 ifstream & ungetc( ifstream & is, char c ); 127 128 void acquire( ifstream & is ); 129 void release( ifstream & is ); 130 131 struct isacquire { 132 ifstream & is; 133 }; 134 void ?{}( isacquire & acq, ifstream & is ); 135 void ^?{}( isacquire & acq ); 102 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 136 103 137 104 void ?{}( ifstream & is ); 138 void ?{}( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"105 void ?{}( ifstream & is, const char name[], const char mode[] ); 139 106 void ?{}( ifstream & is, const char name[] ); 140 107 void ^?{}( ifstream & is ); … … 146 113 147 114 148 EHM_EXCEPTION(Open_Failure)(115 DATA_EXCEPTION(Open_Failure)( 149 116 union { 150 117 ofstream * ostream; … … 155 122 ); 156 123 157 void ?{}( Open_Failure & this, ofstream & );158 void ?{}( Open_Failure & this, ifstream & );124 void ?{}( Open_Failure & this, ofstream & ostream ); 125 void ?{}( Open_Failure & this, ifstream & istream ); 159 126 160 127 // Local Variables: // -
libcfa/src/gmp.hfa
r5407cdc rfeacef9 10 10 // Created On : Tue Apr 19 08:43:43 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 20 20:59:21 202113 // Update Count : 3 212 // Last Modified On : Sun Feb 9 09:56:54 2020 13 // Update Count : 31 14 14 // 15 15 … … 263 263 forall( ostype & | ostream( ostype ) ) { 264 264 ostype & ?|?( ostype & os, Int mp ) { 265 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );265 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 266 266 gmp_printf( "%Zd", mp.mpz ); 267 267 sepOn( os ); -
libcfa/src/heap.cfa
r5407cdc rfeacef9 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 20 21:20:48202113 // Update Count : 103 312 // Last Modified On : Sun Jan 10 11:20:49 2021 13 // Update Count : 1031 14 14 // 15 15 … … 52 52 static bool prtFree = false; 53 53 54 bool prtFree() {54 inline bool prtFree() { 55 55 return prtFree; 56 56 } // prtFree … … 1128 1128 1129 1129 // Set the alignment for an the allocation and return previous alignment or 0 if no alignment. 1130 size_t malloc_alignment_set$( void * addr, size_t alignment ) {1130 size_t $malloc_alignment_set( void * addr, size_t alignment ) { 1131 1131 if ( unlikely( addr == 0p ) ) return libAlign(); // minimum alignment 1132 1132 size_t ret; … … 1139 1139 } // if 1140 1140 return ret; 1141 } // malloc_alignment_set$1141 } // $malloc_alignment_set 1142 1142 1143 1143 … … 1153 1153 1154 1154 // Set allocation is zero filled and return previous zero filled. 1155 bool malloc_zero_fill_set$( void * addr ) {1155 bool $malloc_zero_fill_set( void * addr ) { 1156 1156 if ( unlikely( addr == 0p ) ) return false; // null allocation is not zero fill 1157 1157 HeapManager.Storage.Header * header = headerAddr( addr ); … … 1162 1162 header->kind.real.blockSize |= 2; // mark as zero filled 1163 1163 return ret; 1164 } // malloc_zero_fill_set$1164 } // $malloc_zero_fill_set 1165 1165 1166 1166 … … 1176 1176 1177 1177 // Set allocation size and return previous size. 1178 size_t malloc_size_set$( void * addr, size_t size ) {1178 size_t $malloc_size_set( void * addr, size_t size ) { 1179 1179 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size 1180 1180 HeapManager.Storage.Header * header = headerAddr( addr ); … … 1185 1185 header->kind.real.size = size; 1186 1186 return ret; 1187 } // malloc_size_set$1187 } // $malloc_size_set 1188 1188 1189 1189 -
libcfa/src/iostream.cfa
r5407cdc rfeacef9 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 18:01:03 202113 // Update Count : 1 33012 // Last Modified On : Mon Aug 24 08:31:35 2020 13 // Update Count : 1130 14 14 // 15 15 … … 36 36 37 37 38 forall( ostype & | basic_ostream( ostype ) ) {38 forall( ostype & | ostream( ostype ) ) { 39 39 ostype & ?|?( ostype & os, bool b ) { 40 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );40 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 41 41 fmt( os, "%s", b ? "true" : "false" ); 42 42 return os; … … 48 48 ostype & ?|?( ostype & os, char c ) { 49 49 fmt( os, "%c", c ); 50 if ( c == '\n' ) setNL$( os, true );50 if ( c == '\n' ) $setNL( os, true ); 51 51 return sepOff( os ); 52 52 } // ?|? … … 56 56 57 57 ostype & ?|?( ostype & os, signed char sc ) { 58 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );58 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 59 59 fmt( os, "%hhd", sc ); 60 60 return os; … … 65 65 66 66 ostype & ?|?( ostype & os, unsigned char usc ) { 67 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );67 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 68 68 fmt( os, "%hhu", usc ); 69 69 return os; … … 74 74 75 75 ostype & ?|?( ostype & os, short int si ) { 76 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );76 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 77 77 fmt( os, "%hd", si ); 78 78 return os; … … 83 83 84 84 ostype & ?|?( ostype & os, unsigned short int usi ) { 85 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );85 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 86 86 fmt( os, "%hu", usi ); 87 87 return os; … … 92 92 93 93 ostype & ?|?( ostype & os, int i ) { 94 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );94 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 95 95 fmt( os, "%d", i ); 96 96 return os; … … 101 101 102 102 ostype & ?|?( ostype & os, unsigned int ui ) { 103 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );103 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 104 104 fmt( os, "%u", ui ); 105 105 return os; … … 110 110 111 111 ostype & ?|?( ostype & os, long int li ) { 112 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );112 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 113 113 fmt( os, "%ld", li ); 114 114 return os; … … 119 119 120 120 ostype & ?|?( ostype & os, unsigned long int uli ) { 121 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );121 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 122 122 fmt( os, "%lu", uli ); 123 123 return os; … … 128 128 129 129 ostype & ?|?( ostype & os, long long int lli ) { 130 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );130 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 131 131 fmt( os, "%lld", lli ); 132 132 return os; … … 137 137 138 138 ostype & ?|?( ostype & os, unsigned long long int ulli ) { 139 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );139 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 140 140 fmt( os, "%llu", ulli ); 141 141 return os; … … 145 145 } // ?|? 146 146 147 #if defined( __SIZEOF_INT128__ )147 #if defined( __SIZEOF_INT128__ ) 148 148 // UINT64_MAX 18_446_744_073_709_551_615_ULL 149 149 #define P10_UINT64 10_000_000_000_000_000_000_ULL // 19 zeroes 150 150 151 151 static inline void base10_128( ostype & os, unsigned int128 val ) { 152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0)// gcc version >= 7152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0) // gcc version >= 7 153 153 if ( val > P10_UINT64 ) { 154 #else154 #else 155 155 if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug 156 #endif // __GNUC_PREREQ(7,0)156 #endif // __GNUC_PREREQ(7,0) 157 157 base10_128( os, val / P10_UINT64 ); // recursive 158 158 fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) ); … … 171 171 172 172 ostype & ?|?( ostype & os, int128 llli ) { 173 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );173 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 174 174 base10_128( os, llli ); 175 175 return os; … … 180 180 181 181 ostype & ?|?( ostype & os, unsigned int128 ullli ) { 182 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );182 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 183 183 base10_128( os, ullli ); 184 184 return os; … … 187 187 (ostype &)(os | ullli); ends( os ); 188 188 } // ?|? 189 #endif // __SIZEOF_INT128__189 #endif // __SIZEOF_INT128__ 190 190 191 191 #define PrintWithDP( os, format, val, ... ) \ … … 195 195 int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \ 196 196 fmt( os, "%s", buf ); \ 197 if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \197 if ( isfinite( val ) ) { /* if number, always print decimal point */ \ 198 198 for ( int i = 0;; i += 1 ) { \ 199 199 if ( i == len ) { fmt( os, "." ); break; } \ 200 if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' ) break; /* decimal point or scientific ? */\200 if ( buf[i] == '.' ) break; \ 201 201 } /* for */ \ 202 202 } /* if */ \ … … 204 204 205 205 ostype & ?|?( ostype & os, float f ) { 206 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );206 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 207 207 PrintWithDP( os, "%g", f ); 208 208 return os; … … 213 213 214 214 ostype & ?|?( ostype & os, double d ) { 215 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );215 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 216 216 PrintWithDP( os, "%.*lg", d, DBL_DIG ); 217 217 return os; … … 222 222 223 223 ostype & ?|?( ostype & os, long double ld ) { 224 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );224 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 225 225 PrintWithDP( os, "%.*Lg", ld, LDBL_DIG ); 226 226 return os; … … 231 231 232 232 ostype & ?|?( ostype & os, float _Complex fc ) { 233 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );233 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 234 234 // os | crealf( fc ) | nonl; 235 235 PrintWithDP( os, "%g", crealf( fc ) ); … … 243 243 244 244 ostype & ?|?( ostype & os, double _Complex dc ) { 245 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );245 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 246 246 // os | creal( dc ) | nonl; 247 247 PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG ); … … 255 255 256 256 ostype & ?|?( ostype & os, long double _Complex ldc ) { 257 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );257 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 258 258 // os | creall( ldc ) || nonl; 259 259 PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG ); … … 266 266 } // ?|? 267 267 268 ostype & ?|?( ostype & os, const char s [] ) {268 ostype & ?|?( ostype & os, const char str[] ) { 269 269 enum { Open = 1, Close, OpenClose }; 270 270 static const unsigned char mask[256] @= { … … 282 282 }; // mask 283 283 284 if ( s [0] == '\0' ) { sepOff( os ); return os; } // null string => no separator284 if ( str[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator 285 285 286 286 // first character IS NOT spacing or closing punctuation => add left separator 287 unsigned char ch = s [0]; // must make unsigned288 if ( sepPrt$( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {289 fmt( os, "%s", sepGetCur$( os ) );287 unsigned char ch = str[0]; // must make unsigned 288 if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) { 289 fmt( os, "%s", $sepGetCur( os ) ); 290 290 } // if 291 291 292 292 // if string starts line, must reset to determine open state because separator is off 293 sepReset$( os ); // reset separator293 $sepReset( os ); // reset separator 294 294 295 295 // last character IS spacing or opening punctuation => turn off separator for next item 296 int len = strlen( s ); 297 ch = s[len - 1]; // must make unsigned 298 fmt( os, "%s", s ); // fmt resets seperator, but reset it again 299 if ( sepPrt$( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 296 size_t len = strlen( str ); 297 ch = str[len - 1]; // must make unsigned 298 if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 300 299 sepOn( os ); 301 300 } else { 302 301 sepOff( os ); 303 302 } // if 304 if ( ch == '\n' ) setNL$( os, true ); // check *AFTER* sepPrt$call above as it resets NL flag305 return os;306 // return write( os, s, len ); 307 } // ?|? 308 void ?|?( ostype & os, const char s [] ) {309 (ostype &)(os | s ); ends( os );310 } // ?|? 311 312 // ostype & ?|?( ostype & os, const char16_t * s ) {313 // if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );314 // fmt( os, "%ls", s );303 if ( ch == '\n' ) $setNL( os, true ); // check *AFTER* $sepPrt call above as it resets NL flag 304 return write( os, str, len ); 305 } // ?|? 306 307 void ?|?( ostype & os, const char str[] ) { 308 (ostype &)(os | str); ends( os ); 309 } // ?|? 310 311 // ostype & ?|?( ostype & os, const char16_t * str ) { 312 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 313 // fmt( os, "%ls", str ); 315 314 // return os; 316 315 // } // ?|? 317 316 318 317 // #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 319 // ostype & ?|?( ostype & os, const char32_t * s ) {320 // if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );321 // fmt( os, "%ls", s );318 // ostype & ?|?( ostype & os, const char32_t * str ) { 319 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 320 // fmt( os, "%ls", str ); 322 321 // return os; 323 322 // } // ?|? 324 323 // #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 325 324 326 // ostype & ?|?( ostype & os, const wchar_t * s ) {327 // if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );328 // fmt( os, "%ls", s );325 // ostype & ?|?( ostype & os, const wchar_t * str ) { 326 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 327 // fmt( os, "%ls", str ); 329 328 // return os; 330 329 // } // ?|? 331 330 332 331 ostype & ?|?( ostype & os, const void * p ) { 333 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );332 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 334 333 fmt( os, "%p", p ); 335 334 return os; … … 341 340 // manipulators 342 341 ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) { 343 return manip( os ); 342 (ostype &)(manip( os )); 343 return os; 344 344 } // ?|? 345 345 void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) { 346 manip( os);347 if ( getPrt$( os ) ) ends( os ); // something printed ?348 setPrt$( os, false ); // turn off346 (ostype &)(manip( os )); 347 if ( $getPrt( os ) ) ends( os ); // something printed ? 348 $setPrt( os, false ); // turn off 349 349 } // ?|? 350 350 … … 359 359 ostype & nl( ostype & os ) { 360 360 (ostype &)(os | '\n'); 361 setPrt$( os, false ); // turn off 362 setNL$( os, true ); 361 $setPrt( os, false ); // turn off 362 $setNL( os, true ); 363 flush( os ); 363 364 return sepOff( os ); // prepare for next line 364 365 } // nl 365 366 366 367 ostype & nonl( ostype & os ) { 367 setPrt$( os, false ); // turn off368 $setPrt( os, false ); // turn off 368 369 return os; 369 370 } // nonl … … 398 399 return os; 399 400 } // nlOff 400 } // distribution401 402 forall( ostype & | ostream( ostype ) ) {403 ostype & acquire( ostype & os ) {404 acquire( os ); // call void returning405 return os;406 } // acquire407 401 } // distribution 408 402 … … 411 405 ostype & ?|?( ostype & os, T arg, Params rest ) { 412 406 (ostype &)(os | arg); // print first argument 413 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator407 $sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator 414 408 (ostype &)(os | rest); // print remaining arguments 415 sepSetCur$( os, sepGet( os ) ); // switch to regular separator409 $sepSetCur( os, sepGet( os ) ); // switch to regular separator 416 410 return os; 417 411 } // ?|? … … 419 413 // (ostype &)(?|?( os, arg, rest )); ends( os ); 420 414 (ostype &)(os | arg); // print first argument 421 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator415 $sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator 422 416 (ostype &)(os | rest); // print remaining arguments 423 sepSetCur$( os, sepGet( os ) ); // switch to regular separator417 $sepSetCur( os, sepGet( os ) ); // switch to regular separator 424 418 ends( os ); 425 419 } // ?|? … … 448 442 // Default prefix for non-decimal prints is 0b, 0, 0x. 449 443 #define IntegralFMTImpl( T, IFMTNP, IFMTP ) \ 450 forall( ostype & | basic_ostream( ostype ) ) { \444 forall( ostype & | ostream( ostype ) ) { \ 451 445 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 452 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \446 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 453 447 \ 454 448 if ( f.base == 'b' || f.base == 'B' ) { /* bespoke binary format */ \ … … 523 517 return os; \ 524 518 } /* ?|? */ \ 525 void ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 526 (ostype &)(os | f); ends( os ); \ 527 } /* ?|? */ \ 519 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 528 520 } // distribution 529 521 530 IntegralFMTImpl( signed char, " *hh ", "*.*hh " )531 IntegralFMTImpl( unsigned char, " *hh ", "*.*hh " )532 IntegralFMTImpl( signed short int, " *h ", "*.*h " )533 IntegralFMTImpl( unsigned short int, " *h ", "*.*h " )534 IntegralFMTImpl( signed int, " * ", "*.* " )535 IntegralFMTImpl( unsigned int, " * ", "*.* " )536 IntegralFMTImpl( signed long int, " *l ", "*.*l " )537 IntegralFMTImpl( unsigned long int, " *l ", "*.*l " )538 IntegralFMTImpl( signed long long int, " *ll ", "*.*ll " )539 IntegralFMTImpl( unsigned long long int, " *ll ", "*.*ll " )540 541 522 IntegralFMTImpl( signed char, "% *hh ", "% *.*hh " ) 523 IntegralFMTImpl( unsigned char, "% *hh ", "% *.*hh " ) 524 IntegralFMTImpl( signed short int, "% *h ", "% *.*h " ) 525 IntegralFMTImpl( unsigned short int, "% *h ", "% *.*h " ) 526 IntegralFMTImpl( signed int, "% * ", "% *.* " ) 527 IntegralFMTImpl( unsigned int, "% * ", "% *.* " ) 528 IntegralFMTImpl( signed long int, "% *l ", "% *.*l " ) 529 IntegralFMTImpl( unsigned long int, "% *l ", "% *.*l " ) 530 IntegralFMTImpl( signed long long int, "% *ll ", "% *.*ll " ) 531 IntegralFMTImpl( unsigned long long int, "% *ll ", "% *.*ll " ) 532 533 #if 0 542 534 #if defined( __SIZEOF_INT128__ ) 543 535 // Default prefix for non-decimal prints is 0b, 0, 0x. 544 forall( ostype & | basic_ostream( ostype ) ) 536 #define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \ 537 forall( ostype & | ostream( ostype ) ) \ 538 static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \ 539 if ( f.val > UINT64_MAX ) { \ 540 unsigned long long int lsig = f.val % P10_UINT64; \ 541 f.val /= P10_UINT64; /* msig */ \ 542 base10_128( os, f ); /* recursion */ \ 543 _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \ 544 fmt.flags.nobsdp = true; \ 545 /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \ 546 sepOff( os ); \ 547 (ostype &)(os | fmt); \ 548 } else { \ 549 /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \ 550 _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \ 551 (ostype &)(os | fmt); \ 552 } /* if */ \ 553 } /* base10_128 */ \ 554 forall( ostype & | ostream( ostype ) ) { \ 555 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 556 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 557 \ 558 if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \ 559 unsigned long long int msig = (unsigned long long int)(f.val >> 64); \ 560 unsigned long long int lsig = (unsigned long long int)(f.val); \ 561 _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \ 562 _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \ 563 if ( msig == 0 ) { \ 564 fmt.val = lsig; \ 565 (ostype &)(os | fmt); \ 566 } else { \ 567 fmt2.flags.pad0 = fmt2.flags.nobsdp = true; \ 568 if ( f.base == 'b' | f.base == 'B' ) { \ 569 if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \ 570 if ( fmt.flags.left ) { \ 571 fmt.flags.left = false; \ 572 fmt.wd = 0; \ 573 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 574 fmt2.flags.left = true; \ 575 int msigd = high1( msig ); \ 576 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 577 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \ 578 if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \ 579 fmt2.flags.pc = true; fmt2.pc = 64; \ 580 } else { \ 581 if ( fmt.wd > 64 ) fmt.wd -= 64; \ 582 else fmt.wd = 1; \ 583 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 584 fmt2.wd = 64; \ 585 } /* if */ \ 586 /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 587 (ostype &)(os | fmt | "" | fmt2); \ 588 } else if ( f.base == 'o' ) { \ 589 if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \ 590 fmt.val = (unsigned long long int)fmt.val >> 2; \ 591 fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \ 592 if ( fmt.flags.left ) { \ 593 fmt.flags.left = false; \ 594 fmt.wd = 0; \ 595 /* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 596 (ostype &)(os | fmt | "" | fmt2); \ 597 sepOff( os ); \ 598 fmt2.flags.left = true; \ 599 int msigd = ceiling_div( high1( fmt.val ), 3 ); \ 600 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 601 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \ 602 if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \ 603 fmt2.flags.pc = true; fmt2.pc = 21; \ 604 } else { \ 605 if ( fmt.wd > 22 ) fmt.wd -= 22; \ 606 else fmt.wd = 1; \ 607 /* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 608 (ostype &)(os | fmt | "" | fmt2); \ 609 sepOff( os ); \ 610 fmt2.wd = 21; \ 611 } /* if */ \ 612 fmt2.val = lsig & 0x7fffffffffffffffU; \ 613 /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 614 (ostype &)(os | fmt2); \ 615 } else { /* f.base == 'x' | f.base == 'X' */ \ 616 if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \ 617 if ( fmt.flags.left ) { \ 618 fmt.flags.left = false; \ 619 fmt.wd = 0; \ 620 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 621 fmt2.flags.left = true; \ 622 int msigd = high1( msig ); \ 623 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 624 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \ 625 if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \ 626 fmt2.flags.pc = true; fmt2.pc = 16; \ 627 } else { \ 628 if ( fmt.wd > 16 ) fmt.wd -= 16; \ 629 else fmt.wd = 1; \ 630 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 631 fmt2.wd = 16; \ 632 } /* if */ \ 633 /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 634 (ostype &)(os | fmt | "" | fmt2); \ 635 } /* if */ \ 636 } /* if */ \ 637 } else { \ 638 if ( CODE == 'd' ) { \ 639 if ( f.val < 0 ) { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \ 640 } /* if */ \ 641 base10_128( os, f ); \ 642 } /* if */ \ 643 return os; \ 644 } /* ?|? */ \ 645 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 646 } // distribution 647 648 IntegralFMTImpl128( int128, signed, 'd', "% *ll ", "% *.*ll " ) 649 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "% *ll ", "% *.*ll " ) 650 #endif // __SIZEOF_INT128__ 651 #endif // 0 652 653 #if 1 654 #if defined( __SIZEOF_INT128__ ) 655 // Default prefix for non-decimal prints is 0b, 0, 0x. 656 forall( ostype & | ostream( ostype ) ) 545 657 static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) { 546 658 int wd = 1; // f.wd is never 0 because 0 implies left-pad … … 607 719 608 720 #define IntegralFMTImpl128( T ) \ 609 forall( ostype & | basic_ostream( ostype ) ) { \721 forall( ostype & | ostream( ostype ) ) { \ 610 722 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 611 723 _Ostream_Manip(uint64_t) fmt; \ … … 629 741 IntegralFMTImpl128( unsigned int128 ) 630 742 #endif // __SIZEOF_INT128__ 743 #endif // 0 631 744 632 745 // *********************************** floating point *********************************** 633 746 634 static const char *suffixes[] = { 635 "y", "z", "a", "f", "p", "n", "u", "m", "", 636 "K", "M", "G", "T", "P", "E", "Z", "Y" 637 }; 638 #define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */ 639 #define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3)) 640 641 #define PrintWithDP2( os, format, ... ) \ 747 #define PrintWithDP2( os, format, val, ... ) \ 642 748 { \ 643 if ( ! f.flags.eng ) {\644 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \645 if ( isfinite( f.val ) && ( f.pc != 0 || ! f.flags.nobsdp ) ) { /* if number, print decimal point when no fraction or exponent */\646 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ?*/ \647 if ( i == len ) {\648 if ( ! f.flags.left) { \649 buf[i] = '.'; buf[i + 1] = '\0';\650 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */\651 } else {\652 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */\653 buf[i] = '.';\654 if ( i == len ) buf[i + 1] = '\0'; \655 } /* if */\749 enum { size = 48 }; \ 750 char buf[size]; \ 751 int bufbeg = 0, i, len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \ 752 if ( isfinite( val ) && (f.base != 'g' || f.pc != 0) ) { /* if number, print decimal point */ \ 753 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \ 754 if ( i == len && ! f.flags.nobsdp ) { \ 755 if ( ! f.flags.left ) { \ 756 buf[i] = '.'; buf[i + 1] = '\0'; \ 757 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \ 758 } else { \ 759 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \ 760 buf[i] = '.'; \ 761 if ( i == len ) buf[i + 1] = '\0'; \ 656 762 } /* if */ \ 657 763 } /* if */ \ 658 } else { \659 int exp10, len2; \660 eng( f.val, f.pc, exp10 ); /* changes arguments */ \661 if ( ! f.flags.left && f.wd > 1 ) { \662 /* Exponent size (number of digits, 'e', optional minus sign) */ \663 f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \664 if ( f.wd < 1 ) f.wd = 1; \665 } /* if */ \666 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \667 if ( f.flags.left ) { \668 for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \669 len += 1; \670 } /* if */ \671 if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \672 len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \673 } else { \674 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \675 } /* if */ \676 if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \677 764 } /* if */ \ 678 765 fmt( os, "%s", &buf[bufbeg] ); \ … … 680 767 681 768 #define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \ 682 forall( ostype & | basic_ostream( ostype ) ) { \ 683 static void eng( T &value, int & pc, int & exp10 ) { \ 684 exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \ 685 if ( exp10 < 0 ) exp10 -= 2; \ 686 exp10 = floor( exp10, 3 ); \ 687 value *= pow( 10.0, -exp10 ); \ 688 if ( pc <= 3 ) pc = 3; \ 689 } /* eng */ \ 690 \ 769 forall( ostype & | ostream( ostype ) ) { \ 691 770 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 692 enum { size = 48 }; \ 693 char buf[size]; \ 694 int bufbeg = 0, i, len; \ 695 \ 696 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \ 697 char fmtstr[sizeof(DFMTP) + 8]; /* sizeof includes '\0' */ \ 771 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 772 char fmtstr[sizeof(DFMTP)]; /* sizeof includes '\0' */ \ 698 773 if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \ 699 774 else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \ … … 709 784 fmtstr[sizeof(DFMTNP)-2] = f.base; /* sizeof includes '\0' */ \ 710 785 /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \ 711 PrintWithDP2( os, &fmtstr[star], f. wd, f.val) \786 PrintWithDP2( os, &fmtstr[star], f.val, f.wd ) \ 712 787 } else { /* precision */ \ 713 788 fmtstr[sizeof(DFMTP)-2] = f.base; /* sizeof includes '\0' */ \ 714 789 /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \ 715 PrintWithDP2( os, &fmtstr[star], f. wd, f.pc, f.val) \790 PrintWithDP2( os, &fmtstr[star], f.val, f.wd, f.pc ) \ 716 791 } /* if */ \ 717 792 return os; \ … … 721 796 } // distribution 722 797 723 FloatingPointFMTImpl( double, " * ", "*.* " )724 FloatingPointFMTImpl( long double, " *L ", "*.*L " )798 FloatingPointFMTImpl( double, "% * ", "% *.* " ) 799 FloatingPointFMTImpl( long double, "% *L ", "% *.*L " ) 725 800 726 801 // *********************************** character *********************************** 727 802 728 forall( ostype & | basic_ostream( ostype ) ) {803 forall( ostype & | ostream( ostype ) ) { 729 804 ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) { 730 805 if ( f.base != 'c' ) { // bespoke binary/octal/hex format … … 737 812 } // if 738 813 739 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );814 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 740 815 741 816 #define CFMTNP "% * " … … 759 834 // *********************************** C string *********************************** 760 835 761 forall( ostype & | basic_ostream( ostype ) ) {836 forall( ostype & | ostream( ostype ) ) { 762 837 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) { 763 838 if ( ! f.val ) return os; // null pointer ? … … 775 850 } // if 776 851 777 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );852 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 778 853 779 854 #define SFMTNP "% * " … … 807 882 808 883 809 forall( istype & | basic_istream( istype ) ) {884 forall( istype & | istream( istype ) ) { 810 885 istype & ?|?( istype & is, bool & b ) { 811 886 char val[6]; … … 819 894 return is; 820 895 } // ?|? 821 void ?|?( istype & is, bool & b ) {822 (istype &)(is | b); ends( is );823 } // ?|?824 896 825 897 istype & ?|?( istype & is, char & c ) { … … 833 905 return is; 834 906 } // ?|? 835 void ?|?( istype & is, char & c ) {836 (istype &)(is | c); ends( is );837 } // ?|?838 907 839 908 istype & ?|?( istype & is, signed char & sc ) { … … 841 910 return is; 842 911 } // ?|? 843 void ?|?( istype & is, signed char & sc ) {844 (istype &)(is | sc); ends( is );845 } // ?|?846 912 847 913 istype & ?|?( istype & is, unsigned char & usc ) { … … 849 915 return is; 850 916 } // ?|? 851 void ?|?( istype & is, unsigned char & usc ) {852 (istype &)(is | usc); ends( is );853 } // ?|?854 917 855 918 istype & ?|?( istype & is, short int & si ) { … … 857 920 return is; 858 921 } // ?|? 859 void ?|?( istype & is, short int & si ) {860 (istype &)(is | si); ends( is );861 } // ?|?862 922 863 923 istype & ?|?( istype & is, unsigned short int & usi ) { … … 865 925 return is; 866 926 } // ?|? 867 void ?|?( istype & is, unsigned short int & usi ) {868 (istype &)(is | usi); ends( is );869 } // ?|?870 927 871 928 istype & ?|?( istype & is, int & i ) { … … 873 930 return is; 874 931 } // ?|? 875 void ?|?( istype & is, int & i ) {876 (istype &)(is | i); ends( is );877 } // ?|?878 932 879 933 istype & ?|?( istype & is, unsigned int & ui ) { … … 881 935 return is; 882 936 } // ?|? 883 void ?|?( istype & is, unsigned int & ui ) {884 (istype &)(is | ui); ends( is );885 } // ?|?886 937 887 938 istype & ?|?( istype & is, long int & li ) { … … 889 940 return is; 890 941 } // ?|? 891 void ?|?( istype & is, long int & li ) {892 (istype &)(is | li); ends( is );893 } // ?|?894 942 895 943 istype & ?|?( istype & is, unsigned long int & ulli ) { … … 897 945 return is; 898 946 } // ?|? 899 void ?|?( istype & is, unsigned long int & ulli ) {900 (istype &)(is | ulli); ends( is );901 } // ?|?902 947 903 948 istype & ?|?( istype & is, long long int & lli ) { … … 905 950 return is; 906 951 } // ?|? 907 void ?|?( istype & is, long long int & lli ) {908 (istype &)(is | lli); ends( is );909 } // ?|?910 952 911 953 istype & ?|?( istype & is, unsigned long long int & ulli ) { … … 913 955 return is; 914 956 } // ?|? 915 void & ?|?( istype & is, unsigned long long int & ulli ) { 916 (istype &)(is | ulli); ends( is ); 917 } // ?|? 918 919 #if defined( __SIZEOF_INT128__ ) 920 istype & ?|?( istype & is, int128 & llli ) { 921 return (istype &)(is | (unsigned int128 &)llli); 922 } // ?|? 923 void ?|?( istype & is, int128 & llli ) { 924 (istype &)(is | llli); ends( is ); 925 } // ?|? 926 927 istype & ?|?( istype & is, unsigned int128 & ullli ) { 957 958 #if defined( __SIZEOF_INT128__ ) 959 istype & ?|?( istype & is, int128 & i128 ) { 960 return (istype &)(is | (unsigned int128 &)i128); 961 } // ?|? 962 963 istype & ?|?( istype & is, unsigned int128 & ui128 ) { 928 964 char s[40]; 929 965 bool sign = false; … … 932 968 // If the input is too large, the value returned is undefined. If there is no input, no value is returned 933 969 if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) { // take first 39 characters, ignore remaining 934 u llli= 0;970 ui128 = 0; 935 971 for ( unsigned int i = 0; s[i] != '\0'; i += 1 ) { 936 u llli = ullli* 10 + s[i] - '0';972 ui128 = ui128 * 10 + s[i] - '0'; 937 973 } // for 938 if ( sign ) u llli = -ullli;974 if ( sign ) ui128 = -ui128; 939 975 } else if ( sign ) ungetc( is, '-' ); // return minus when no digits 940 976 return is; 941 977 } // ?|? 942 void ?|?( istype & is, unsigned int128 & ullli ) { 943 (istype &)(is | ullli); ends( is ); 944 } // ?|? 945 #endif // __SIZEOF_INT128__ 978 #endif // __SIZEOF_INT128__ 946 979 947 980 istype & ?|?( istype & is, float & f ) { … … 949 982 return is; 950 983 } // ?|? 951 void ?|?( istype & is, float & f ) {952 (istype &)(is | f); ends( is );953 } // ?|?954 984 955 985 istype & ?|?( istype & is, double & d ) { … … 957 987 return is; 958 988 } // ?|? 959 void ?|?( istype & is, double & d ) {960 (istype &)(is | d); ends( is );961 } // ?|?962 989 963 990 istype & ?|?( istype & is, long double & ld ) { … … 965 992 return is; 966 993 } // ?|? 967 void ?|?( istype & is, long double & ld ) { 968 (istype &)(is | ld); ends( is ); 969 } // ?|? 994 970 995 971 996 istype & ?|?( istype & is, float _Complex & fc ) { … … 975 1000 return is; 976 1001 } // ?|? 977 void ?|?( istype & is, float _Complex & fc ) {978 (istype &)(is | fc); ends( is );979 } // ?|?980 1002 981 1003 istype & ?|?( istype & is, double _Complex & dc ) { … … 985 1007 return is; 986 1008 } // ?|? 987 void ?|?( istype & is, double _Complex & dc ) {988 (istype &)(is | dc); ends( is );989 } // ?|?990 1009 991 1010 istype & ?|?( istype & is, long double _Complex & ldc ) { … … 995 1014 return is; 996 1015 } // ?|? 997 void ?|?( istype & is, long double _Complex & ldc ) {998 (istype &)(is | ldc); ends( is );999 } // ?|?1000 1016 1001 1017 // istype & ?|?( istype & is, const char fmt[] ) { … … 1004 1020 // } // ?|? 1005 1021 1006 istype & ?|?( istype & is, char s[]) {1022 istype & ?|?( istype & is, char * s ) { 1007 1023 fmt( is, "%s", s ); 1008 1024 return is; 1009 } // ?|?1010 void ?|?( istype & is, char s[] ) {1011 (istype &)(is | s); ends( is );1012 1025 } // ?|? 1013 1026 … … 1016 1029 return manip( is ); 1017 1030 } // ?|? 1018 void ?|?( istype & is, istype & (* manip)( istype & ) ) {1019 manip( is ); ends( is );1020 } // ?|?1021 1031 1022 1032 istype & nl( istype & is ) { … … 1036 1046 } // distribution 1037 1047 1038 forall( istype & | istream( istype ) ) {1039 istype & acquire( istype & is ) {1040 acquire( is ); // call void returning1041 return is;1042 } // acquire1043 } // distribution1044 1045 1048 // *********************************** manipulators *********************************** 1046 1049 1047 forall( istype & | basic_istream( istype ) ) { 1048 istype & ?|?( istype & is, _Istream_Cstr f ) { 1049 // skip xxx 1050 if ( ! f.s ) { 1051 // printf( "skip %s %d\n", f.scanset, f.wd ); 1052 if ( f.wd == -1 ) fmt( is, f.scanset, "" ); // no input arguments 1053 else for ( f.wd ) fmt( is, "%*c" ); 1054 return is; 1055 } // if 1056 size_t len = 0; 1057 if ( f.scanset ) len = strlen( f.scanset ); 1058 char fmtstr[len + 16]; 1059 int start = 1; 1060 fmtstr[0] = '%'; 1061 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; } 1062 if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); } 1063 // cstr %s, %*s, %ws, %*ws 1064 if ( ! f.scanset ) { 1065 fmtstr[start] = 's'; fmtstr[start + 1] = '\0'; 1066 // printf( "cstr %s\n", fmtstr ); 1067 fmt( is, fmtstr, f.s ); 1068 return is; 1069 } // if 1070 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1071 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1072 fmtstr[start] = '['; start += 1; 1073 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; } 1074 strcpy( &fmtstr[start], f.scanset ); // copy includes '\0' 1075 len += start; 1076 fmtstr[len] = ']'; fmtstr[len + 1] = '\0'; 1077 // printf( "incl/excl %s\n", fmtstr ); 1050 forall( istype & | istream( istype ) ) 1051 istype & ?|?( istype & is, _Istream_Cstr f ) { 1052 // skip xxx 1053 if ( ! f.s ) { 1054 // printf( "skip %s %d\n", f.scanset, f.wd ); 1055 if ( f.wd == -1 ) fmt( is, f.scanset, "" ); // no input arguments 1056 else for ( f.wd ) fmt( is, "%*c" ); 1057 return is; 1058 } // if 1059 size_t len = 0; 1060 if ( f.scanset ) len = strlen( f.scanset ); 1061 char fmtstr[len + 16]; 1062 int start = 1; 1063 fmtstr[0] = '%'; 1064 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; } 1065 if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); } 1066 // cstr %s, %*s, %ws, %*ws 1067 if ( ! f.scanset ) { 1068 fmtstr[start] = 's'; fmtstr[start + 1] = '\0'; 1069 // printf( "cstr %s\n", fmtstr ); 1078 1070 fmt( is, fmtstr, f.s ); 1079 1071 return is; 1080 } // ?|? 1081 void ?|?( istype & is, _Istream_Cstr f ) { 1082 (istype &)(is | f); ends( is ); 1083 } // ?|? 1084 1085 istype & ?|?( istype & is, _Istream_Char f ) { 1086 fmt( is, "%*c" ); // argument variable unused 1087 return is; 1088 } // ?|? 1089 void ?|?( istype & is, _Istream_Char f ) { 1090 (istype &)(is | f); ends( is ); 1091 } // ?|? 1092 } // distribution 1072 } // if 1073 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1074 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1075 fmtstr[start] = '['; start += 1; 1076 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; } 1077 strcpy( &fmtstr[start], f.scanset ); // copy includes '\0' 1078 len += start; 1079 fmtstr[len] = ']'; fmtstr[len + 1] = '\0'; 1080 // printf( "incl/excl %s\n", fmtstr ); 1081 fmt( is, fmtstr, f.s ); 1082 return is; 1083 } // ?|? 1084 1085 forall( istype & | istream( istype ) ) 1086 istype & ?|?( istype & is, _Istream_Char f ) { 1087 fmt( is, "%*c" ); // argument variable unused 1088 return is; 1089 } // ?|? 1093 1090 1094 1091 #define InputFMTImpl( T, CODE ) \ 1095 forall( istype & | basic_istream( istype ) ) { \ 1096 istype & ?|?( istype & is, _Istream_Manip(T) f ) { \ 1097 enum { size = 16 }; \ 1098 char fmtstr[size]; \ 1099 if ( f.wd == -1 ) { \ 1100 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \ 1101 } else { \ 1102 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \ 1103 } /* if */ \ 1104 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \ 1105 fmt( is, fmtstr, &f.val ); \ 1106 return is; \ 1107 } /* ?|? */ \ 1108 void ?|?( istype & is, _Istream_Manip(T) f ) { \ 1109 (istype &)(is | f); ends( is ); \ 1110 } /* ?|? */ \ 1111 } // distribution 1092 forall( istype & | istream( istype ) ) \ 1093 istype & ?|?( istype & is, _Istream_Manip(T) f ) { \ 1094 enum { size = 16 }; \ 1095 char fmtstr[size]; \ 1096 if ( f.wd == -1 ) { \ 1097 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \ 1098 } else { \ 1099 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \ 1100 } /* if */ \ 1101 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \ 1102 fmt( is, fmtstr, &f.val ); \ 1103 return is; \ 1104 } // ?|? 1112 1105 1113 1106 InputFMTImpl( signed char, "hhi" ) … … 1126 1119 InputFMTImpl( long double, "Lf" ) 1127 1120 1128 forall( istype & | basic_istream( istype ) ) { 1129 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) { 1130 float re, im; 1131 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore }; 1132 is | fmtuc; 1133 &fmtuc.val = &im; 1134 is | fmtuc; 1135 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1136 return is; 1137 } // ?|? 1138 void ?|?( istype & is, _Istream_Manip(float _Complex) fc ) { 1139 (istype &)(is | fc); ends( is ); 1140 } // ?|? 1141 1142 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { 1143 double re, im; 1144 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore }; 1145 is | fmtuc; 1146 &fmtuc.val = &im; 1147 is | fmtuc; 1148 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1149 return is; 1150 } // ?|? 1151 void ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { 1152 (istype &)(is | dc); ends( is ); 1153 } // ?|? 1154 1155 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { 1156 long double re, im; 1157 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore }; 1158 is | fmtuc; 1159 &fmtuc.val = &im; 1160 is | fmtuc; 1161 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1162 return is; 1163 } // ?|? 1164 void ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { 1165 (istype &)(is | ldc); ends( is ); 1166 } // ?|? 1167 } // distribution 1121 forall( istype & | istream( istype ) ) 1122 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) { 1123 float re, im; 1124 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore }; 1125 is | fmtuc; 1126 &fmtuc.val = &im; 1127 is | fmtuc; 1128 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1129 return is; 1130 } // ?|? 1131 1132 forall( istype & | istream( istype ) ) 1133 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { 1134 double re, im; 1135 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore }; 1136 is | fmtuc; 1137 &fmtuc.val = &im; 1138 is | fmtuc; 1139 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1140 return is; 1141 } // ?|? 1142 1143 forall( istype & | istream( istype ) ) 1144 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { 1145 long double re, im; 1146 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore }; 1147 is | fmtuc; 1148 &fmtuc.val = &im; 1149 is | fmtuc; 1150 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1151 return is; 1152 } // ?|? 1168 1153 1169 1154 // Local Variables: // -
libcfa/src/iostream.hfa
r5407cdc rfeacef9 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue A pr 27 17:59:21 202113 // Update Count : 3 9812 // Last Modified On : Tue Aug 11 22:16:14 2020 13 // Update Count : 350 14 14 // 15 15 … … 22 22 23 23 24 trait basic_ostream( ostype & ) {24 trait ostream( ostype & ) { 25 25 // private 26 bool sepPrt$( ostype & ); // get separator state (on/off)27 void sepReset$( ostype & ); // set separator state to default state28 void sepReset$( ostype &, bool ); // set separator and default state29 const char * sepGetCur$( ostype & ); // get current separator string30 void sepSetCur$( ostype &, const char [] ); // set current separator string31 bool getNL$( ostype & ); // check newline32 void setNL$( ostype &, bool ); // saw newline33 bool getANL$( ostype & ); // get auto newline (on/off)34 bool getPrt$( ostype & ); // get fmt called in output cascade35 void setPrt$( ostype &, bool ); // set fmt called in output cascade26 bool $sepPrt( ostype & ); // get separator state (on/off) 27 void $sepReset( ostype & ); // set separator state to default state 28 void $sepReset( ostype &, bool ); // set separator and default state 29 const char * $sepGetCur( ostype & ); // get current separator string 30 void $sepSetCur( ostype &, const char [] ); // set current separator string 31 bool $getNL( ostype & ); // check newline 32 void $setNL( ostype &, bool ); // saw newline 33 bool $getANL( ostype & ); // get auto newline (on/off) 34 bool $getPrt( ostype & ); // get fmt called in output cascade 35 void $setPrt( ostype &, bool ); // set fmt called in output cascade 36 36 // public 37 37 void sepOn( ostype & ); // turn separator state on … … 47 47 void sepSetTuple( ostype &, const char [] ); // set tuple separator to string (15 character maximum) 48 48 49 void ends( ostype & ); // end of output statement 49 void ends( ostype & os ); // end of output statement 50 int fail( ostype & ); 51 int flush( ostype & ); 52 void open( ostype & os, const char name[], const char mode[] ); 53 void close( ostype & os ); 54 ostype & write( ostype &, const char [], size_t ); 50 55 int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 51 }; // basic_ostream52 53 trait ostream( ostype & | basic_ostream( ostype ) ) {54 int flush( ostype & );55 bool fail( ostype & ); // operation failed?56 void open( ostype &, const char name[], const char mode[] );57 void close( ostype & );58 ostype & write( ostype &, const char [], size_t );59 void acquire( ostype & ); // concurrent access60 56 }; // ostream 61 57 … … 70 66 // implement writable for intrinsic types 71 67 72 forall( ostype & | basic_ostream( ostype ) ) {68 forall( ostype & | ostream( ostype ) ) { 73 69 ostype & ?|?( ostype &, bool ); 74 70 void ?|?( ostype &, bool ); … … 97 93 ostype & ?|?( ostype &, unsigned long long int ); 98 94 void ?|?( ostype &, unsigned long long int ); 99 #if defined( __SIZEOF_INT128__ )95 #if defined( __SIZEOF_INT128__ ) 100 96 ostype & ?|?( ostype &, int128 ); 101 97 void ?|?( ostype &, int128 ); 102 98 ostype & ?|?( ostype &, unsigned int128 ); 103 99 void ?|?( ostype &, unsigned int128 ); 104 #endif // __SIZEOF_INT128__100 #endif // __SIZEOF_INT128__ 105 101 106 102 ostype & ?|?( ostype &, float ); … … 121 117 void ?|?( ostype &, const char [] ); 122 118 // ostype & ?|?( ostype &, const char16_t * ); 123 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous119 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 124 120 // ostype & ?|?( ostype &, const char32_t * ); 125 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )121 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 126 122 // ostype & ?|?( ostype &, const wchar_t * ); 127 123 ostype & ?|?( ostype &, const void * ); … … 143 139 } // distribution 144 140 145 forall( ostype & | ostream( ostype ) ) {146 ostype & acquire( ostype & );147 } // distribution148 149 141 // tuples 150 142 forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) { … … 164 156 struct _Ostream_Manip { 165 157 T val; // polymorphic base-type 166 int wd, pc; // width, precision: signed for computations158 unsigned int wd, pc; // width, precision 167 159 char base; // numeric base / floating-point style 168 160 union { 169 161 unsigned char all; 170 162 struct { 171 unsigned char eng:1; // engineering notation172 163 unsigned char neg:1; // val is negative 173 164 unsigned char pc:1; // precision specified … … 192 183 _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'x', { .all : 0 } }; } \ 193 184 _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \ 194 _Ostream_Manip(T) wd( unsigned int w, unsigned intpc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \185 _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \ 195 186 _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \ 196 _Ostream_Manip(T) & wd( unsigned int w, unsigned intpc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \187 _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 197 188 _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \ 198 189 _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \ … … 202 193 _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \ 203 194 } /* distribution */ \ 204 forall( ostype & | basic_ostream( ostype ) ) { \195 forall( ostype & | ostream( ostype ) ) { \ 205 196 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \ 206 197 void ?|?( ostype & os, _Ostream_Manip(T) f ); \ … … 229 220 _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \ 230 221 _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \ 231 _Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \ 232 _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \ 233 _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \ 234 _Ostream_Manip(T) ws( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \ 235 _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; return fmt; } \ 236 _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 237 _Ostream_Manip(T) & ws( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 222 _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \ 223 _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \ 224 _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \ 225 _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \ 226 _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 238 227 _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \ 239 228 _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \ … … 244 233 _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \ 245 234 _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \ 246 _Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \247 _Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \248 235 } /* distribution */ \ 249 forall( ostype & | basic_ostream( ostype ) ) { \236 forall( ostype & | ostream( ostype ) ) { \ 250 237 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \ 251 238 void ?|?( ostype & os, _Ostream_Manip(T) f ); \ … … 267 254 _Ostream_Manip(char) & nobase( _Ostream_Manip(char) & fmt ) { fmt.flags.nobsdp = true; return fmt; } 268 255 } // distribution 269 forall( ostype & | basic_ostream( ostype ) ) {256 forall( ostype & | ostream( ostype ) ) { 270 257 ostype & ?|?( ostype & os, _Ostream_Manip(char) f ); 271 258 void ?|?( ostype & os, _Ostream_Manip(char) f ); … … 279 266 _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; } 280 267 _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; } 281 _Ostream_Manip(const char *) wd( unsigned int w, unsigned intpc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }268 _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; } 282 269 _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; } 283 _Ostream_Manip(const char *) & wd( unsigned int w, unsigned intpc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }270 _Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } 284 271 _Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; } 285 272 _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; } 286 273 } // distribution 287 forall( ostype & | basic_ostream( ostype ) ) {274 forall( ostype & | ostream( ostype ) ) { 288 275 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ); 289 276 void ?|?( ostype & os, _Ostream_Manip(const char *) f ); … … 294 281 295 282 296 trait basic_istream( istype & ) { 297 bool getANL( istype & ); // get scan newline (on/off) 283 trait istream( istype & ) { 298 284 void nlOn( istype & ); // read newline 299 285 void nlOff( istype & ); // scan newline 300 301 void ends( istype & os ); // end of output statement 302 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 303 istype & ungetc( istype &, char ); 286 bool getANL( istype & ); // get scan newline (on/off) 287 int fail( istype & ); 304 288 int eof( istype & ); 305 }; // basic_istream306 307 trait istream( istype & | basic_istream( istype ) ) {308 bool fail( istype & );309 289 void open( istype & is, const char name[] ); 310 290 void close( istype & is ); 311 291 istype & read( istype &, char *, size_t ); 312 void acquire( istype & ); // concurrent access 292 istype & ungetc( istype &, char ); 293 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 313 294 }; // istream 314 295 … … 317 298 }; // readable 318 299 319 forall( istype & | basic_istream( istype ) ) {300 forall( istype & | istream( istype ) ) { 320 301 istype & ?|?( istype &, bool & ); 321 void ?|?( istype &, bool & );322 302 323 303 istype & ?|?( istype &, char & ); 324 void ?|?( istype &, char & );325 304 istype & ?|?( istype &, signed char & ); 326 void ?|?( istype &, signed char & );327 305 istype & ?|?( istype &, unsigned char & ); 328 void ?|?( istype &, unsigned char & );329 306 330 307 istype & ?|?( istype &, short int & ); 331 void ?|?( istype &, short int & );332 308 istype & ?|?( istype &, unsigned short int & ); 333 void ?|?( istype &, unsigned short int & );334 309 istype & ?|?( istype &, int & ); 335 void ?|?( istype &, int & );336 310 istype & ?|?( istype &, unsigned int & ); 337 void ?|?( istype &, unsigned int & );338 311 istype & ?|?( istype &, long int & ); 339 void ?|?( istype &, long int & );340 312 istype & ?|?( istype &, unsigned long int & ); 341 void ?|?( istype &, unsigned long int & );342 313 istype & ?|?( istype &, long long int & ); 343 void ?|?( istype &, long long int & );344 314 istype & ?|?( istype &, unsigned long long int & ); 345 void ?|?( istype &, unsigned long long int & ); 346 #if defined( __SIZEOF_INT128__ ) 315 #if defined( __SIZEOF_INT128__ ) 347 316 istype & ?|?( istype &, int128 & ); 348 void ?|?( istype &, int128 & );349 317 istype & ?|?( istype &, unsigned int128 & ); 350 void ?|?( istype &, unsigned int128 & ); 351 #endif // __SIZEOF_INT128__ 318 #endif // __SIZEOF_INT128__ 352 319 353 320 istype & ?|?( istype &, float & ); 354 void ?|?( istype &, float & );355 321 istype & ?|?( istype &, double & ); 356 void ?|?( istype &, double & );357 322 istype & ?|?( istype &, long double & ); 358 void ?|?( istype &, long double & );359 323 360 324 istype & ?|?( istype &, float _Complex & ); 361 void ?|?( istype &, float _Complex & );362 325 istype & ?|?( istype &, double _Complex & ); 363 void ?|?( istype &, double _Complex & );364 326 istype & ?|?( istype &, long double _Complex & ); 365 void ?|?( istype &, long double _Complex & );366 327 367 328 // istype & ?|?( istype &, const char [] ); 368 istype & ?|?( istype &, char [] ); 369 void ?|?( istype &, char [] ); 329 istype & ?|?( istype &, char * ); 370 330 371 331 // manipulators 372 332 istype & ?|?( istype &, istype & (*)( istype & ) ); 373 void ?|?( istype &, istype & (*)( istype & ) );374 333 istype & nl( istype & is ); 375 334 istype & nlOn( istype & ); 376 335 istype & nlOff( istype & ); 377 } // distribution378 379 forall( istype & | istream( istype ) ) {380 istype & acquire( istype & );381 336 } // distribution 382 337 … … 397 352 398 353 static inline { 354 _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; } 399 355 _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; } 400 _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }401 356 _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; } 402 357 _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; } … … 408 363 _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; } 409 364 } // distribution 410 forall( istype & | basic_istream( istype ) ) { 411 istype & ?|?( istype & is, _Istream_Cstr f ); 412 void ?|?( istype & is, _Istream_Cstr f ); 413 } 365 forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f ); 414 366 415 367 struct _Istream_Char { … … 421 373 _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; } 422 374 } // distribution 423 forall( istype & | basic_istream( istype ) ) { 424 istype & ?|?( istype & is, _Istream_Char f ); 425 void ?|?( istype & is, _Istream_Char f ); 426 } 375 forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f ); 427 376 428 377 forall( T & | sized( T ) ) … … 440 389 _Istream_Manip(T) & wdi( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \ 441 390 } /* distribution */ \ 442 forall( istype & | basic_istream( istype ) ) { \391 forall( istype & | istream( istype ) ) { \ 443 392 istype & ?|?( istype & is, _Istream_Manip(T) f ); \ 444 void ?|?( istype & is, _Istream_Manip(T) f ); \445 393 } // ?|? 446 394 -
libcfa/src/math.hfa
r5407cdc rfeacef9 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // math .hfa--7 // math -- 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Mon Apr 18 23:37:04 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 15 11:47:56 202113 // Update Count : 1 3212 // Last Modified On : Mon Aug 24 08:56:20 2020 13 // Update Count : 126 14 14 // 15 15 … … 100 100 long double _Complex log( long double _Complex x ) { return clogl( x ); } 101 101 102 // O(1) polymorphic integer log2, using clz, which returns the number of leading 0-bits, starting at the most103 // significant bit (single instruction on x86)104 int log2( unsigned int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clz( n ); }105 long int log2( unsigned long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzl( n ); }106 long long int log2( unsigned long long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzll( n ); }107 102 float log2( float x ) { return log2f( x ); } 108 103 // extern "C" { double log2( double ); } -
libcfa/src/startup.cfa
r5407cdc rfeacef9 39 39 40 40 void disable_interrupts() __attribute__(( weak )) {} 41 void enable_interrupts () __attribute__(( weak )) {}41 void enable_interrupts_noPoll() __attribute__(( weak )) {} 42 42 } // extern "C" 43 43 -
libcfa/src/stdlib.hfa
r5407cdc rfeacef9 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Apr 20 21:20:03 202113 // Update Count : 57 512 // Last Modified On : Thu Jan 21 22:02:13 2021 13 // Update Count : 574 14 14 // 15 15 … … 44 44 45 45 // Macro because of returns 46 #define ARRAY_ALLOC$( allocation, alignment, dim ) \46 #define $ARRAY_ALLOC( allocation, alignment, dim ) \ 47 47 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)allocation( dim, (size_t)sizeof(T) ); /* C allocation */ \ 48 48 else return (T *)alignment( _Alignof(T), dim, sizeof(T) ) … … 57 57 58 58 T * aalloc( size_t dim ) { 59 ARRAY_ALLOC$( aalloc, amemalign, dim );59 $ARRAY_ALLOC( aalloc, amemalign, dim ); 60 60 } // aalloc 61 61 62 62 T * calloc( size_t dim ) { 63 ARRAY_ALLOC$( calloc, cmemalign, dim );63 $ARRAY_ALLOC( calloc, cmemalign, dim ); 64 64 } // calloc 65 65 … … 119 119 S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; } 120 120 121 3. Replace the alloc_internal$function which is outside ttype forall-block with following function:122 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {121 3. Replace the $alloc_internal function which is outside ttype forall-block with following function: 122 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) { 123 123 T * ptr = NULL; 124 124 size_t size = sizeof(T); … … 145 145 146 146 return ptr; 147 } // alloc_internal$147 } // $alloc_internal 148 148 */ 149 149 … … 175 175 S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; } 176 176 177 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {177 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) { 178 178 T * ptr = NULL; 179 179 size_t size = sizeof(T); … … 206 206 207 207 return ptr; 208 } // alloc_internal$209 210 forall( TT... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {211 212 T * alloc_internal$( void * , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {213 return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest);214 } 215 216 T * alloc_internal$( void * Resize, T * , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {217 return alloc_internal$( (void*)0p, Realloc, Align, Dim, Fill, rest);218 } 219 220 T * alloc_internal$( void * Resize, T * Realloc, size_t , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {221 return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);222 } 223 224 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) , S_fill(T) Fill, TT rest) {225 return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);208 } // $alloc_internal 209 210 forall( TT... | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) { 211 212 T * $alloc_internal( void * , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) { 213 return $alloc_internal( Resize, (T*)0p, Align, Dim, Fill, rest); 214 } 215 216 T * $alloc_internal( void * Resize, T * , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) { 217 return $alloc_internal( (void*)0p, Realloc, Align, Dim, Fill, rest); 218 } 219 220 T * $alloc_internal( void * Resize, T * Realloc, size_t , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) { 221 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest); 222 } 223 224 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) , S_fill(T) Fill, TT rest) { 225 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest); 226 226 } 227 227 228 228 T * alloc( TT all ) { 229 return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);229 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all); 230 230 } 231 231 232 232 T * alloc( size_t dim, TT all ) { 233 return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);233 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all); 234 234 } 235 235 -
libcfa/src/time.hfa
r5407cdc rfeacef9 10 10 // Created On : Wed Mar 14 23:18:57 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 21 06:32:31 202113 // Update Count : 66 712 // Last Modified On : Wed Jun 17 16:13:00 2020 13 // Update Count : 663 14 14 // 15 15 … … 28 28 29 29 static inline { 30 void ?{}( Duration & dur, timeval t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }31 void ?{}( Duration & dur, timespec t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }32 33 30 Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; } 34 Duration ?=?( Duration & dur, timeval t ) with( dur ) {35 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);36 return dur;37 } // ?=?38 Duration ?=?( Duration & dur, timespec t ) with( dur ) {39 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;40 return dur;41 } // ?=?42 31 43 32 Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; } … … 60 49 Duration ?%?( Duration lhs, Duration rhs ) { return (Duration)@{ lhs.tn % rhs.tn }; } 61 50 Duration ?%=?( Duration & lhs, Duration rhs ) { lhs = lhs % rhs; return lhs; } 51 52 bool ?==?( Duration lhs, Duration rhs ) { return lhs.tn == rhs.tn; } 53 bool ?!=?( Duration lhs, Duration rhs ) { return lhs.tn != rhs.tn; } 54 bool ?<? ( Duration lhs, Duration rhs ) { return lhs.tn < rhs.tn; } 55 bool ?<=?( Duration lhs, Duration rhs ) { return lhs.tn <= rhs.tn; } 56 bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn > rhs.tn; } 57 bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; } 62 58 63 59 bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; } … … 67 63 bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn > 0; } 68 64 bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; } 69 70 bool ?==?( Duration lhs, Duration rhs ) { return lhs.tn == rhs.tn; }71 bool ?!=?( Duration lhs, Duration rhs ) { return lhs.tn != rhs.tn; }72 bool ?<? ( Duration lhs, Duration rhs ) { return lhs.tn < rhs.tn; }73 bool ?<=?( Duration lhs, Duration rhs ) { return lhs.tn <= rhs.tn; }74 bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn > rhs.tn; }75 bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; }76 65 77 66 Duration abs( Duration rhs ) { return rhs.tn >= 0 ? rhs : -rhs; } … … 163 152 void ?{}( Time & time, int year, int month = 1, int day = 1, int hour = 0, int min = 0, int sec = 0, int64_t nsec = 0 ); 164 153 static inline { 154 Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; } 155 165 156 void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; } 166 void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }167 168 Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }169 157 Time ?=?( Time & time, timeval t ) with( time ) { 170 158 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL); 171 159 return time; 172 160 } // ?=? 161 162 void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; } 173 163 Time ?=?( Time & time, timespec t ) with( time ) { 174 164 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; -
libcfa/src/virtual.c
r5407cdc rfeacef9 15 15 16 16 #include "virtual.h" 17 #include "assert.h"18 17 19 18 int __cfa__is_parent( struct __cfa__parent_vtable const * parent, 20 19 struct __cfa__parent_vtable const * child ) { 21 assert( child );22 20 do { 23 21 if ( parent == child ) … … 30 28 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 31 29 struct __cfa__parent_vtable const * const * child ) { 32 assert( child );33 30 return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0; 34 31 } -
src/AST/Convert.cpp
r5407cdc rfeacef9 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 09 15::37::05 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 12 18:43:51 202113 // Update Count : 3 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Nov 12 10:07:00 2020 13 // Update Count : 34 14 14 // 15 15 … … 327 327 const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final { 328 328 auto decl = new AsmDecl( get<AsmStmt>().accept1( node->stmt ) ); 329 declPostamble( decl, node );330 return nullptr;331 }332 333 const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final {334 auto decl = new DirectiveDecl( get<DirectiveStmt>().accept1( node->stmt ) );335 329 declPostamble( decl, node ); 336 330 return nullptr; … … 1775 1769 } 1776 1770 1777 virtual void visit( const DirectiveDecl * old ) override final {1778 auto decl = new ast::DirectiveDecl{1779 old->location,1780 GET_ACCEPT_1(stmt, DirectiveStmt)1781 };1782 decl->extension = old->extension;1783 decl->uniqueId = old->uniqueId;1784 decl->storage = { old->storageClasses.val };1785 1786 this->node = decl;1787 }1788 1789 1771 virtual void visit( const StaticAssertDecl * old ) override final { 1790 1772 auto decl = new ast::StaticAssertDecl{ -
src/AST/Decl.hpp
r5407cdc rfeacef9 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:25:05202113 // Update Count : 3 212 // Last Modified On : Mon Jan 11 20:48:38 2021 13 // Update Count : 30 14 14 // 15 15 … … 365 365 }; 366 366 367 /// C-preprocessor directive `#...`368 class DirectiveDecl : public Decl {369 public:370 ptr<DirectiveStmt> stmt;371 372 DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt )373 : Decl( loc, "", {}, {} ), stmt(stmt) {}374 375 const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); }376 private:377 DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); }378 MUTATE_FRIEND379 };380 381 367 class StaticAssertDecl : public Decl { 382 368 public: -
src/AST/Expr.cpp
r5407cdc rfeacef9 260 260 } 261 261 262 ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) {263 const Type * charType = new BasicType( BasicType::Char );264 // Adjust the length of the string for the terminator.265 const Expr * strSize = from_ulong( loc, str.size() + 1 );266 const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim );267 const std::string strValue = "\"" + str + "\"";268 return new ConstantExpr( loc, strType, strValue, std::nullopt );269 }270 271 262 ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) { 272 263 return new ConstantExpr{ -
src/AST/Expr.hpp
r5407cdc rfeacef9 438 438 long long int intValue() const; 439 439 440 /// Generates a boolean constant of the given bool.440 /// generates a boolean constant of the given bool 441 441 static ConstantExpr * from_bool( const CodeLocation & loc, bool b ); 442 /// Generates an integer constant of the given int.442 /// generates an integer constant of the given int 443 443 static ConstantExpr * from_int( const CodeLocation & loc, int i ); 444 /// Generates an integer constant of the given unsigned long int.444 /// generates an integer constant of the given unsigned long int 445 445 static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i ); 446 /// Generates a string constant from the given string (char type, unquoted string). 447 static ConstantExpr * from_string( const CodeLocation & loc, const std::string & string ); 448 /// Generates a null pointer value for the given type. void * if omitted. 446 /// generates a null pointer value for the given type. void * if omitted. 449 447 static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr ); 450 448 -
src/AST/Fwd.hpp
r5407cdc rfeacef9 9 9 // Author : Andrew Beach 10 10 // Created On : Wed May 8 16:05:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 12 18:37:39 202113 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Jul 23 14:15:00 2020 13 // Update Count : 2 14 14 // 15 15 … … 35 35 class TypedefDecl; 36 36 class AsmDecl; 37 class DirectiveDecl;38 37 class StaticAssertDecl; 39 38 -
src/AST/Node.cpp
r5407cdc rfeacef9 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 16 14:16:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 12 18:25:06 202113 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jun 5 10:21:00 2020 13 // Update Count : 1 14 14 // 15 15 … … 130 130 template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::weak >; 131 131 template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::strong >; 132 template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::weak >;133 template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::strong >;134 132 template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::weak >; 135 133 template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::strong >; -
src/AST/Pass.hpp
r5407cdc rfeacef9 139 139 const ast::Decl * visit( const ast::TypedefDecl * ) override final; 140 140 const ast::AsmDecl * visit( const ast::AsmDecl * ) override final; 141 const ast::DirectiveDecl * visit( const ast::DirectiveDecl * ) override final;142 141 const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * ) override final; 143 142 const ast::CompoundStmt * visit( const ast::CompoundStmt * ) override final; -
src/AST/Pass.impl.hpp
r5407cdc rfeacef9 646 646 647 647 //-------------------------------------------------------------------------- 648 // DirectiveDecl649 template< typename core_t >650 const ast::DirectiveDecl * ast::Pass< core_t >::visit( const ast::DirectiveDecl * node ) {651 VISIT_START( node );652 653 VISIT(654 maybe_accept( node, &DirectiveDecl::stmt );655 )656 657 VISIT_END( DirectiveDecl, node );658 }659 660 //--------------------------------------------------------------------------661 648 // StaticAssertDecl 662 649 template< typename core_t > -
src/AST/Print.cpp
r5407cdc rfeacef9 387 387 388 388 virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final { 389 safe_print( node->stmt );390 return node;391 }392 393 virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final {394 389 safe_print( node->stmt ); 395 390 return node; -
src/AST/Type.cpp
r5407cdc rfeacef9 105 105 } 106 106 107 // --- BaseInstType108 109 107 std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const { 110 108 assertf( aggr(), "Must have aggregate to perform lookup" ); … … 121 119 template<typename decl_t> 122 120 SueInstType<decl_t>::SueInstType( 123 const base_type* b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )124 : BaseInstType( b->name, q, std::move(as) ), base( b ) {}121 const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 122 : BaseInstType( b->name, q, move(as) ), base( b ) {} 125 123 126 124 template<typename decl_t> … … 144 142 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 145 143 : BaseInstType( b->name, q, move(as) ), base( b ) {} 146 147 // --- TypeInstType148 144 149 145 void TypeInstType::set_base( const TypeDecl * b ) { -
src/AST/Visitor.hpp
r5407cdc rfeacef9 9 9 // Author : Andrew Beach 10 10 // Created On : Thr May 9 15:28:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 12 18:25:07 202113 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr May 9 15:33:00 2019 13 // Update Count : 0 14 14 // 15 15 … … 31 31 virtual const ast::Decl * visit( const ast::TypedefDecl * ) = 0; 32 32 virtual const ast::AsmDecl * visit( const ast::AsmDecl * ) = 0; 33 virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * ) = 0;34 33 virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * ) = 0; 35 34 virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * ) = 0; -
src/CodeGen/CodeGenerator.cc
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 19:00:42 202113 // Update Count : 53 612 // Last Modified On : Sun Feb 16 08:32:48 2020 13 // Update Count : 532 14 14 // 15 15 #include "CodeGenerator.h" … … 935 935 if ( asmStmt->get_instruction() ) asmStmt->get_instruction()->accept( *visitor ); 936 936 output << " )"; 937 }938 939 void CodeGenerator::postvisit( DirectiveDecl * directiveDecl ) {940 output << endl << directiveDecl->get_stmt()->directive; // endl prevents spaces before directive941 937 } 942 938 -
src/CodeGen/CodeGenerator.h
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:35:38 202113 // Update Count : 6 312 // Last Modified On : Sun Feb 16 03:58:31 2020 13 // Update Count : 62 14 14 // 15 15 … … 105 105 void postvisit( DirectiveStmt * ); 106 106 void postvisit( AsmDecl * ); // special: statement in declaration context 107 void postvisit( DirectiveDecl * ); // special: statement in declaration context108 107 void postvisit( IfStmt * ); 109 108 void postvisit( SwitchStmt * ); -
src/Common/CodeLocationTools.cpp
r5407cdc rfeacef9 9 9 // Author : Andrew Beach 10 10 // Created On : Fri Dec 4 15:42:00 2020 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 12 18:35:37 202113 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Dec 9 9:42:00 2020 13 // Update Count : 1 14 14 // 15 15 … … 102 102 macro(TypedefDecl, Decl) \ 103 103 macro(AsmDecl, AsmDecl) \ 104 macro(DirectiveDecl, DirectiveDecl) \105 104 macro(StaticAssertDecl, StaticAssertDecl) \ 106 105 macro(CompoundStmt, CompoundStmt) \ -
src/Common/PassVisitor.h
r5407cdc rfeacef9 77 77 virtual void visit( AsmDecl * asmDecl ) override final; 78 78 virtual void visit( const AsmDecl * asmDecl ) override final; 79 virtual void visit( DirectiveDecl * directiveDecl ) override final;80 virtual void visit( const DirectiveDecl * directiveDecl ) override final;81 79 virtual void visit( StaticAssertDecl * assertDecl ) override final; 82 80 virtual void visit( const StaticAssertDecl * assertDecl ) override final; … … 263 261 virtual Declaration * mutate( TypedefDecl * typeDecl ) override final; 264 262 virtual AsmDecl * mutate( AsmDecl * asmDecl ) override final; 265 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final;266 263 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final; 267 264 -
src/Common/PassVisitor.impl.h
r5407cdc rfeacef9 973 973 974 974 //-------------------------------------------------------------------------- 975 // DirectiveDecl976 template< typename pass_type >977 void PassVisitor< pass_type >::visit( DirectiveDecl * node ) {978 VISIT_START( node );979 980 maybeAccept_impl( node->stmt, *this );981 982 VISIT_END( node );983 }984 985 template< typename pass_type >986 void PassVisitor< pass_type >::visit( const DirectiveDecl * node ) {987 VISIT_START( node );988 989 maybeAccept_impl( node->stmt, *this );990 991 VISIT_END( node );992 }993 994 template< typename pass_type >995 DirectiveDecl * PassVisitor< pass_type >::mutate( DirectiveDecl * node ) {996 MUTATE_START( node );997 998 maybeMutate_impl( node->stmt, *this );999 1000 MUTATE_END( DirectiveDecl, node );1001 }1002 1003 //--------------------------------------------------------------------------1004 975 // StaticAssertDecl 1005 976 template< typename pass_type > -
src/Concurrency/Keywords.cc
r5407cdc rfeacef9 42 42 43 43 namespace Concurrency { 44 inline static std::string getTypeIdName( std::string const & exception_name ) {45 return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name );46 }47 44 inline static std::string getVTableName( std::string const & exception_name ) { 48 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name);45 return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name); 49 46 } 50 47 … … 78 75 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), 79 76 context_error( context_error ), exception_name( exception_name ), 80 typeid_name( getTypeIdName( exception_name ) ),81 77 vtable_name( getVTableName( exception_name ) ), 82 78 needs_main( needs_main ), cast_target( cast_target ) {} … … 88 84 89 85 void handle( StructDecl * ); 90 void addTypeId( StructDecl * );91 86 void addVtableForward( StructDecl * ); 92 87 FunctionDecl * forwardDeclare( StructDecl * ); … … 104 99 const std::string context_error; 105 100 const std::string exception_name; 106 const std::string typeid_name;107 101 const std::string vtable_name; 108 102 bool needs_main; … … 112 106 FunctionDecl * dtor_decl = nullptr; 113 107 StructDecl * except_decl = nullptr; 114 StructDecl * typeid_decl = nullptr;115 108 StructDecl * vtable_decl = nullptr; 116 109 }; … … 400 393 except_decl = decl; 401 394 } 402 else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {403 typeid_decl = decl;404 }405 395 else if ( !vtable_decl && vtable_name == decl->name && decl->body ) { 406 396 vtable_decl = decl; … … 414 404 if ( type_decl && isDestructorFor( decl, type_decl ) ) 415 405 dtor_decl = decl; 416 else if ( vtable_name.empty() || !decl->has_body() ) 406 else if ( vtable_name.empty() ) 407 ; 408 else if( !decl->has_body() ) 417 409 ; 418 410 else if ( auto param = isMainFor( decl, cast_target ) ) { … … 426 418 std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) }; 427 419 ObjectDecl * vtable_object = Virtual::makeVtableInstance( 428 "_default_vtable_object_declaration",429 420 vtable_decl->makeInst( poly_args ), struct_type, nullptr ); 430 421 declsToAddAfter.push_back( vtable_object ); 431 declsToAddAfter.push_back(432 new ObjectDecl(433 Virtual::concurrentDefaultVTableName(),434 Type::Const,435 LinkageSpec::Cforall,436 /* bitfieldWidth */ nullptr,437 new ReferenceType( Type::Const, vtable_object->type->clone() ),438 new SingleInit( new VariableExpr( vtable_object ) )439 )440 );441 422 declsToAddAfter.push_back( Virtual::makeGetExceptionFunction( 442 423 vtable_object, except_decl->makeInst( std::move( poly_args ) ) … … 467 448 if( !dtor_decl ) SemanticError( decl, context_error ); 468 449 469 if ( !exception_name.empty() ) { 470 if( !typeid_decl ) SemanticError( decl, context_error ); 471 if( !vtable_decl ) SemanticError( decl, context_error ); 472 473 addTypeId( decl ); 474 addVtableForward( decl ); 475 } 450 addVtableForward( decl ); 476 451 FunctionDecl * func = forwardDeclare( decl ); 477 452 ObjectDecl * field = addField( decl ); … … 479 454 } 480 455 481 void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) { 482 assert( typeid_decl ); 483 StructInstType typeid_type( Type::Const, typeid_decl ); 484 typeid_type.parameters.push_back( new TypeExpr( 485 new StructInstType( noQualifiers, decl ) 456 void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) { 457 if ( vtable_decl ) { 458 std::list< Expression * > poly_args = { 459 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 460 }; 461 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 462 vtable_decl->makeInst( poly_args ), 463 except_decl->makeInst( poly_args ) 486 464 ) ); 487 declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) ); 488 } 489 490 void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) { 491 assert( vtable_decl ); 492 std::list< Expression * > poly_args = { 493 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 494 }; 495 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 496 vtable_decl->makeInst( poly_args ), 497 except_decl->makeInst( poly_args ) 498 ) ); 499 ObjectDecl * vtable_object = Virtual::makeVtableForward( 500 "_default_vtable_object_declaration", 501 vtable_decl->makeInst( move( poly_args ) ) ); 502 declsToAddBefore.push_back( vtable_object ); 503 declsToAddBefore.push_back( 504 new ObjectDecl( 505 Virtual::concurrentDefaultVTableName(), 506 Type::Const, 507 LinkageSpec::Cforall, 508 /* bitfieldWidth */ nullptr, 509 new ReferenceType( Type::Const, vtable_object->type->clone() ), 510 /* init */ nullptr 511 ) 512 ); 465 declsToAddBefore.push_back( Virtual::makeVtableForward( 466 vtable_decl->makeInst( move( poly_args ) ) ) ); 467 // Its only an error if we want a vtable and don't have one. 468 } else if ( ! vtable_name.empty() ) { 469 SemanticError( decl, context_error ); 470 } 513 471 } 514 472 -
src/Parser/DeclarationNode.cc
r5407cdc rfeacef9 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 23 08:44:08202113 // Update Count : 11 4912 // Last Modified On : Mon Jan 11 20:58:07 2021 13 // Update Count : 1137 14 14 // 15 15 … … 167 167 } 168 168 169 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) { 170 DeclarationNode * newnode = new DeclarationNode; 171 newnode->name = name; 172 newnode->type = new TypeData( TypeData::Function ); 173 newnode->type->function.params = param; 174 newnode->type->function.body = body; 175 176 if ( ret ) { 177 newnode->type->base = ret->type; 178 ret->type = nullptr; 179 delete ret; 180 } // if 181 182 return newnode; 183 } // DeclarationNode::newFunction 184 185 169 186 DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) { 170 187 DeclarationNode * newnode = new DeclarationNode; … … 220 237 return newnode; 221 238 } // DeclarationNode::newForall 239 240 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) { 241 DeclarationNode * newnode = new DeclarationNode; 242 newnode->type = new TypeData( TypeData::SymbolicInst ); 243 newnode->type->symbolic.name = name; 244 newnode->type->symbolic.isTypedef = true; 245 newnode->type->symbolic.params = nullptr; 246 return newnode; 247 } // DeclarationNode::newFromTypedef 222 248 223 249 DeclarationNode * DeclarationNode::newFromGlobalScope() { … … 263 289 } // DeclarationNode::newEnum 264 290 291 DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) { 292 DeclarationNode * newnode = new DeclarationNode; 293 newnode->name = name; 294 newnode->enumeratorValue.reset( constant ); 295 return newnode; 296 } // DeclarationNode::newEnumConstant 297 265 298 DeclarationNode * DeclarationNode::newName( const string * name ) { 266 299 DeclarationNode * newnode = new DeclarationNode; 267 assert( ! newnode->name );268 300 newnode->name = name; 269 301 return newnode; 270 302 } // DeclarationNode::newName 271 272 DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) {273 DeclarationNode * newnode = newName( name );274 newnode->enumeratorValue.reset( constant );275 return newnode;276 } // DeclarationNode::newEnumConstant277 278 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {279 DeclarationNode * newnode = new DeclarationNode;280 newnode->type = new TypeData( TypeData::SymbolicInst );281 newnode->type->symbolic.name = name;282 newnode->type->symbolic.isTypedef = true;283 newnode->type->symbolic.params = nullptr;284 return newnode;285 } // DeclarationNode::newFromTypedef286 303 287 304 DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) { … … 295 312 296 313 DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) { 297 DeclarationNode * newnode = new Name( name );314 DeclarationNode * newnode = new DeclarationNode; 298 315 newnode->type = nullptr; 316 assert( ! newnode->name ); 317 // newnode->variable.name = name; 318 newnode->name = name; 299 319 newnode->variable.tyClass = tc; 300 320 newnode->variable.assertions = nullptr; … … 323 343 324 344 DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) { 325 DeclarationNode * newnode = newName( name ); 345 DeclarationNode * newnode = new DeclarationNode; 346 newnode->name = name; 326 347 newnode->type = new TypeData( TypeData::Symbolic ); 327 348 newnode->type->symbolic.isTypedef = false; … … 396 417 } // DeclarationNode::newBuiltinType 397 418 398 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {399 DeclarationNode * newnode = newName( name );400 newnode->type = new TypeData( TypeData::Function );401 newnode->type->function.params = param;402 newnode->type->function.body = body;403 404 if ( ret ) {405 newnode->type->base = ret->type;406 ret->type = nullptr;407 delete ret;408 } // if409 410 return newnode;411 } // DeclarationNode::newFunction412 413 419 DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) { 414 420 DeclarationNode * newnode = new DeclarationNode; … … 418 424 newnode->attributes.push_back( new Attribute( *name, exprs ) ); 419 425 delete name; 420 return newnode;421 }422 423 DeclarationNode * DeclarationNode::newDirectiveStmt( StatementNode * stmt ) {424 DeclarationNode * newnode = new DeclarationNode;425 newnode->directiveStmt = stmt;426 426 return newnode; 427 427 } … … 879 879 } 880 880 881 DeclarationNode * DeclarationNode::cloneType( string * n ame ) {882 DeclarationNode * newnode = new Name( name );881 DeclarationNode * DeclarationNode::cloneType( string * newName ) { 882 DeclarationNode * newnode = new DeclarationNode; 883 883 newnode->type = maybeClone( type ); 884 884 newnode->copySpecifiers( this ); 885 assert( newName ); 886 newnode->name = newName; 885 887 return newnode; 886 888 } … … 1070 1072 return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) ); 1071 1073 } // if 1072 if ( directiveStmt ) {1073 return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) );1074 } // if1075 1074 1076 1075 if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) { -
src/Parser/ParseNode.h
r5407cdc rfeacef9 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 15:19:04202113 // Update Count : 89 712 // Last Modified On : Sun Jan 3 18:23:01 2021 13 // Update Count : 896 14 14 // 15 15 … … 249 249 static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false ); 250 250 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 251 static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement252 251 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement 253 252 static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message ); … … 346 345 std::string error; 347 346 StatementNode * asmStmt = nullptr; 348 StatementNode * directiveStmt = nullptr;349 347 350 348 static UniqueName anonymous; -
src/Parser/TypeData.h
r5407cdc rfeacef9 7 7 // TypeData.h -- 8 8 // 9 // Author : Peter A. Buhr9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 15:18:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Mar 27 09:05:35 202113 // Update Count : 20012 // Last Modified On : Fri Dec 13 23:42:35 2019 13 // Update Count : 199 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <iosfwd> // for ostream19 #include <list> // for list20 #include <string> // for string18 #include <iosfwd> // for ostream 19 #include <list> // for list 20 #include <string> // for string 21 21 22 #include "ParseNode.h" // for DeclarationNode, DeclarationNode::Ag...23 #include "SynTree/LinkageSpec.h" // for Spec24 #include "SynTree/Type.h" // for Type, ReferenceToType (ptr only)25 #include "SynTree/SynTree.h" // for Visitor Nodes22 #include "ParseNode.h" // for DeclarationNode, DeclarationNode::Ag... 23 #include "SynTree/LinkageSpec.h" // for Spec 24 #include "SynTree/Type.h" // for Type, ReferenceToType (ptr only) 25 #include "SynTree/SynTree.h" // for Visitor Nodes 26 26 27 27 struct TypeData { … … 33 33 const std::string * name = nullptr; 34 34 DeclarationNode * params = nullptr; 35 ExpressionNode * actuals = nullptr; // holds actual parameters later applied to AggInst35 ExpressionNode * actuals = nullptr; // holds actual parameters later applied to AggInst 36 36 DeclarationNode * fields = nullptr; 37 37 bool body; … … 62 62 63 63 struct Function_t { 64 mutable DeclarationNode * params = nullptr; // mutables modified in buildKRFunction65 mutable DeclarationNode * idList = nullptr; // old-style64 mutable DeclarationNode * params = nullptr; // mutables modified in buildKRFunction 65 mutable DeclarationNode * idList = nullptr; // old-style 66 66 mutable DeclarationNode * oldDeclList = nullptr; 67 67 StatementNode * body = nullptr; 68 ExpressionNode * withExprs = nullptr; // expressions from function's with_clause68 ExpressionNode * withExprs = nullptr; // expressions from function's with_clause 69 69 }; 70 70 -
src/Parser/TypedefTable.cc
r5407cdc rfeacef9 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 15 20:56:47 202113 // Update Count : 2 6012 // Last Modified On : Sat Feb 15 08:06:36 2020 13 // Update Count : 259 14 14 // 15 15 … … 89 89 debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl ); 90 90 auto ret = kindTable.insertAt( scope, identifier, kind ); 91 if ( ! ret.second ) ret.first->second = kind; // exists => update91 if ( ! ret.second ) ret.first->second = kind; // exists => update 92 92 } // TypedefTable::addToEnclosingScope 93 93 -
src/Parser/lex.ll
r5407cdc rfeacef9 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : T hu Apr 1 13:22:31 202113 * Update Count : 7 5412 * Last Modified On : Tue Oct 6 18:15:41 2020 13 * Update Count : 743 14 14 */ 15 15 … … 221 221 break { KEYWORD_RETURN(BREAK); } 222 222 case { KEYWORD_RETURN(CASE); } 223 catch { QKEYWORD_RETURN(CATCH); } // CFA224 catchResume { QKEYWORD_RETURN(CATCHRESUME); } // CFA223 catch { KEYWORD_RETURN(CATCH); } // CFA 224 catchResume { KEYWORD_RETURN(CATCHRESUME); } // CFA 225 225 char { KEYWORD_RETURN(CHAR); } 226 226 choose { KEYWORD_RETURN(CHOOSE); } // CFA … … 247 247 fallthrough { KEYWORD_RETURN(FALLTHROUGH); } // CFA 248 248 fallthru { KEYWORD_RETURN(FALLTHRU); } // CFA 249 finally { QKEYWORD_RETURN(FINALLY); } // CFA 250 fixup { QKEYWORD_RETURN(FIXUP); } // CFA 249 finally { KEYWORD_RETURN(FINALLY); } // CFA 251 250 float { KEYWORD_RETURN(FLOAT); } 252 251 __float80 { KEYWORD_RETURN(uuFLOAT80); } // GCC … … 288 287 or { QKEYWORD_RETURN(WOR); } // CFA 289 288 otype { KEYWORD_RETURN(OTYPE); } // CFA 290 recover { QKEYWORD_RETURN(RECOVER); } // CFA291 289 register { KEYWORD_RETURN(REGISTER); } 292 report { KEYWORD_RETURN(THROWRESUME); } // CFA293 290 restrict { KEYWORD_RETURN(RESTRICT); } // C99 294 291 __restrict { KEYWORD_RETURN(RESTRICT); } // GCC … … 318 315 __typeof { KEYWORD_RETURN(TYPEOF); } // GCC 319 316 __typeof__ { KEYWORD_RETURN(TYPEOF); } // GCC 320 typeid { KEYWORD_RETURN(TYPEID); } // GCC321 317 union { KEYWORD_RETURN(UNION); } 322 318 __uint128_t { KEYWORD_RETURN(UINT128); } // GCC … … 328 324 __volatile { KEYWORD_RETURN(VOLATILE); } // GCC 329 325 __volatile__ { KEYWORD_RETURN(VOLATILE); } // GCC 330 vtable { KEYWORD_RETURN(VTABLE); } // CFA 331 waitfor { KEYWORD_RETURN(WAITFOR); } // CFA 332 when { KEYWORD_RETURN(WHEN); } // CFA 326 waitfor { KEYWORD_RETURN(WAITFOR); } 327 when { KEYWORD_RETURN(WHEN); } 333 328 while { KEYWORD_RETURN(WHILE); } 334 329 with { KEYWORD_RETURN(WITH); } // CFA -
src/Parser/parser.yy
r5407cdc rfeacef9 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 26 18:41:54202113 // Update Count : 4 99012 // Last Modified On : Wed Feb 3 18:30:12 2021 13 // Update Count : 4700 14 14 // 15 15 … … 32 32 // 33 33 // 1. designation with and without '=' (use ':' instead) 34 34 // 2. attributes not allowed in parenthesis of declarator 35 35 // 36 36 // All of the syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall … … 211 211 } // forCtrl 212 212 213 bool forall = false ;// aggregate have one or more forall qualifiers ?213 bool forall = false, yyy = false; // aggregate have one or more forall qualifiers ? 214 214 215 215 // https://www.gnu.org/software/bison/manual/bison.html#Location-Type … … 264 264 %token RESTRICT // C99 265 265 %token ATOMIC // C11 266 %token FORALL MUTEX VIRTUAL VTABLE COERCE// CFA266 %token FORALL MUTEX VIRTUAL COERCE // CFA 267 267 %token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED 268 268 %token BOOL COMPLEX IMAGINARY // C99 … … 270 270 %token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC 271 271 %token ZERO_T ONE_T // CFA 272 %token SIZEOF TYPEOF VALIST AUTO_TYPE // GCC 273 %token OFFSETOF BASETYPEOF TYPEID // CFA 272 %token VALIST // GCC 273 %token AUTO_TYPE // GCC 274 %token TYPEOF BASETYPEOF LABEL // GCC 274 275 %token ENUM STRUCT UNION 275 276 %token EXCEPTION // CFA 276 277 %token GENERATOR COROUTINE MONITOR THREAD // CFA 277 278 %token OTYPE FTYPE DTYPE TTYPE TRAIT // CFA 279 %token SIZEOF OFFSETOF 278 280 // %token RESUME // CFA 279 %token LABEL // GCC280 281 %token SUSPEND // CFA 281 282 %token ATTRIBUTE EXTENSION // GCC 282 283 %token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN 283 %token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR // CFA 284 %token DISABLE ENABLE TRY THROW THROWRESUME AT // CFA 284 %token CHOOSE DISABLE ENABLE FALLTHRU FALLTHROUGH TRY CATCH CATCHRESUME FINALLY THROW THROWRESUME AT WITH WHEN WAITFOR // CFA 285 285 %token ASM // C99, extension ISO/IEC 9899:1999 Section J.5.10(1) 286 286 %token ALIGNAS ALIGNOF GENERIC STATICASSERT // C11 287 287 288 288 // names and constants: lexer differentiates between identifier and typedef names 289 %token<tok> IDENTIFIER QUOTED_IDENTIFIER TYPEDEFnameTYPEGENname290 %token<tok> TIMEOUT WOR CATCH RECOVER CATCHRESUME FIXUP FINALLY // CFA291 %token<tok> INTEGERconstant CHARACTERconstantSTRINGliteral289 %token<tok> IDENTIFIER QUOTED_IDENTIFIER TYPEDEFname TYPEGENname 290 %token<tok> TIMEOUT WOR 291 %token<tok> INTEGERconstant CHARACTERconstant STRINGliteral 292 292 %token<tok> DIRECTIVE 293 293 // Floating point constant is broken into three kinds of tokens because of the ambiguity with tuple indexing and … … 321 321 %type<en> constant 322 322 %type<en> tuple tuple_expression_list 323 %type<op> ptrref_operator unary_operator assignment_operator simple_assignment_operator compound_assignment_operator323 %type<op> ptrref_operator unary_operator assignment_operator 324 324 %type<en> primary_expression postfix_expression unary_expression 325 325 %type<en> cast_expression_list cast_expression exponential_expression multiplicative_expression additive_expression … … 373 373 374 374 %type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type 375 %type<decl> vtable vtable_opt default_opt376 375 377 376 %type<decl> trait_declaration trait_declaration_list trait_declaring_list trait_specifier … … 429 428 430 429 %type<decl> type_declaration_specifier type_type_specifier type_name typegen_name 431 %type<decl> typedef _nametypedef_declaration typedef_expression430 %type<decl> typedef typedef_declaration typedef_expression 432 431 433 432 %type<decl> variable_type_redeclarator type_ptr type_array type_function … … 441 440 442 441 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list 443 %type<decl> type_specifier type_specifier_nobody 442 %type<decl> type_specifier type_specifier_nobody enum_specifier_nobody 444 443 445 444 %type<decl> variable_declarator variable_ptr variable_array variable_function 446 445 %type<decl> variable_abstract_declarator variable_abstract_ptr variable_abstract_array variable_abstract_function 447 446 448 %type<decl> attribute_list_opt attribute_list attribute attribute_name_list attribute_name447 %type<decl> attribute_list_opt attribute_list attribute_opt attribute attribute_name_list attribute_name 449 448 450 449 // initializers … … 463 462 // Order of these lines matters (low-to-high precedence). THEN is left associative over WOR/TIMEOUT/ELSE, WOR is left 464 463 // associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE. 465 %precedence THEN // rule precedence for IF/WAITFOR statement 466 %precedence WOR // token precedence for start of WOR in WAITFOR statement 467 %precedence TIMEOUT // token precedence for start of TIMEOUT in WAITFOR statement 468 %precedence CATCH // token precedence for start of TIMEOUT in WAITFOR statement 469 %precedence RECOVER // token precedence for start of TIMEOUT in WAITFOR statement 470 %precedence CATCHRESUME // token precedence for start of TIMEOUT in WAITFOR statement 471 %precedence FIXUP // token precedence for start of TIMEOUT in WAITFOR statement 472 %precedence FINALLY // token precedence for start of TIMEOUT in WAITFOR statement 473 %precedence ELSE // token precedence for start of else clause in IF/WAITFOR statement 474 464 %precedence THEN // rule precedence for IF/WAITFOR statement 465 %precedence WOR // token precedence for start of WOR in WAITFOR statement 466 %precedence TIMEOUT // token precedence for start of TIMEOUT in WAITFOR statement 467 %precedence ELSE // token precedence for start of else clause in IF/WAITFOR statement 475 468 476 469 // Handle shift/reduce conflict for generic type by shifting the '(' token. For example, this string is ambiguous: … … 551 544 TIMEOUT 552 545 | WOR 553 | CATCH554 | RECOVER555 | CATCHRESUME556 | FIXUP557 | FINALLY558 546 ; 559 547 … … 786 774 | OFFSETOF '(' type_no_function ',' identifier ')' 787 775 { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); } 788 | TYPEID '(' type_no_function ')'789 {790 SemanticError( yylloc, "typeid name is currently unimplemented." ); $$ = nullptr;791 // $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) );792 }793 776 ; 794 777 … … 812 795 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 813 796 | '(' aggregate_control '&' ')' cast_expression // CFA 814 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }815 | '(' aggregate_control '*' ')' cast_expression // CFA816 797 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); } 817 798 | '(' VIRTUAL ')' cast_expression // CFA … … 958 939 959 940 assignment_operator: 960 simple_assignment_operator961 | compound_assignment_operator962 ;963 964 simple_assignment_operator:965 941 '=' { $$ = OperKinds::Assign; } 966 | ATassign { $$ = OperKinds::AtAssn; } // CFA 967 ; 968 969 compound_assignment_operator: 970 EXPassign { $$ = OperKinds::ExpAssn; } 942 | ATassign { $$ = OperKinds::AtAssn; } 943 | EXPassign { $$ = OperKinds::ExpAssn; } 971 944 | MULTassign { $$ = OperKinds::MulAssn; } 972 945 | DIVassign { $$ = OperKinds::DivAssn; } … … 1046 1019 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); } 1047 1020 | '{' push 1048 local_label_declaration_opt // GCC, local labels appear at start of block1021 local_label_declaration_opt // GCC, local labels 1049 1022 statement_decl_list // C99, intermix declarations and statements 1050 1023 pop '}' … … 1244 1217 | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA 1245 1218 { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); } 1246 1247 | comma_expression ';' TYPEDEFname // CFA, array type1248 {1249 SemanticError( yylloc, "Array interator is currently unimplemented." ); $$ = nullptr;1250 $$ = forCtrl( new ExpressionNode( build_varref( $3 ) ), $1, nullptr, OperKinds::Range, nullptr, nullptr );1251 }1252 1219 1253 1220 // There is a S/R conflicit if ~ and -~ are factored out. … … 1399 1366 1400 1367 exception_statement: 1401 TRY compound_statement handler_clause %prec THEN1368 TRY compound_statement handler_clause 1402 1369 { $$ = new StatementNode( build_try( $2, $3, 0 ) ); } 1403 1370 | TRY compound_statement finally_clause … … 1422 1389 handler_key: 1423 1390 CATCH { $$ = CatchStmt::Terminate; } 1424 | RECOVER { $$ = CatchStmt::Terminate; }1425 1391 | CATCHRESUME { $$ = CatchStmt::Resume; } 1426 | FIXUP { $$ = CatchStmt::Resume; }1427 1392 ; 1428 1393 … … 1776 1741 ; 1777 1742 1743 enum_specifier_nobody: // type specifier - {...} 1744 // Preclude SUE declarations in restricted scopes (see type_specifier_nobody) 1745 basic_type_specifier 1746 | sue_type_specifier_nobody 1747 ; 1748 1778 1749 type_qualifier_list_opt: // GCC, used in asm_statement 1779 1750 // empty … … 1795 1766 type_qualifier: 1796 1767 type_qualifier_name 1797 | attribute // trick handles most atrribute locations1768 | attribute 1798 1769 ; 1799 1770 … … 1903 1874 | AUTO_TYPE 1904 1875 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); } 1905 | vtable1906 ;1907 1908 vtable_opt:1909 // empty1910 { $$ = nullptr; }1911 | vtable;1912 ;1913 1914 vtable:1915 VTABLE '(' type_list ')' default_opt1916 { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; }1917 ;1918 1919 default_opt:1920 // empty1921 { $$ = nullptr; }1922 | DEFAULT1923 { SemanticError( yylloc, "vtable default is currently unimplemented." ); $$ = nullptr; }1924 1876 ; 1925 1877 … … 2073 2025 '{' field_declaration_list_opt '}' type_parameters_opt 2074 2026 { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); } 2075 | aggregate_key attribute_list_opt TYPEDEFname // unqualified type name 2076 { 2077 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef 2027 | aggregate_key attribute_list_opt type_name 2028 { 2029 // for type_name can be a qualified type name S.T, in which case only the last name in the chain needs a typedef (other names in the chain should already have one) 2030 typedefTable.makeTypedef( *$3->type->leafName(), forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef 2078 2031 forall = false; // reset 2079 2032 } 2080 2033 '{' field_declaration_list_opt '}' type_parameters_opt 2081 { 2082 DeclarationNode::newFromTypedef( $3 ); 2083 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2084 } 2085 | aggregate_key attribute_list_opt TYPEGENname // unqualified type name 2086 { 2087 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef 2088 forall = false; // reset 2089 } 2090 '{' field_declaration_list_opt '}' type_parameters_opt 2091 { 2092 DeclarationNode::newFromTypeGen( $3, nullptr ); 2093 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2094 } 2034 { $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $8, $6, true )->addQualifiers( $2 ); } 2095 2035 | aggregate_type_nobody 2096 2036 ; … … 2129 2069 2130 2070 aggregate_data: 2131 STRUCT vtable_opt2132 { $$ = AggregateDecl::Struct; }2071 STRUCT 2072 { yyy = true; $$ = AggregateDecl::Struct; } 2133 2073 | UNION 2134 { $$ = AggregateDecl::Union; }2074 { yyy = true; $$ = AggregateDecl::Union; } 2135 2075 | EXCEPTION // CFA 2136 {$$ = AggregateDecl::Exception; }2137 //{ SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }2076 // { yyy = true; $$ = AggregateDecl::Exception; } 2077 { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2138 2078 ; 2139 2079 2140 2080 aggregate_control: // CFA 2141 2081 MONITOR 2142 { $$ = AggregateDecl::Monitor; }2082 { yyy = true; $$ = AggregateDecl::Monitor; } 2143 2083 | MUTEX STRUCT 2144 { $$ = AggregateDecl::Monitor; }2084 { yyy = true; $$ = AggregateDecl::Monitor; } 2145 2085 | GENERATOR 2146 { $$ = AggregateDecl::Generator; }2086 { yyy = true; $$ = AggregateDecl::Generator; } 2147 2087 | MUTEX GENERATOR 2148 2088 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2149 2089 | COROUTINE 2150 { $$ = AggregateDecl::Coroutine; }2090 { yyy = true; $$ = AggregateDecl::Coroutine; } 2151 2091 | MUTEX COROUTINE 2152 2092 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2153 2093 | THREAD 2154 { $$ = AggregateDecl::Thread; }2094 { yyy = true; $$ = AggregateDecl::Thread; } 2155 2095 | MUTEX THREAD 2156 2096 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } … … 2248 2188 ; 2249 2189 2190 // Cannot use attribute_list_opt because of ambiguity with enum_specifier_nobody, which already parses attribute. 2191 // Hence, only a single attribute is allowed after the "ENUM". 2250 2192 enum_type: // enum 2251 ENUM attribute_ list_opt '{' enumerator_list comma_opt '}'2193 ENUM attribute_opt '{' enumerator_list comma_opt '}' 2252 2194 { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); } 2253 | ENUM attribute_ list_opt identifier2195 | ENUM attribute_opt identifier 2254 2196 { typedefTable.makeTypedef( *$3 ); } 2255 2197 '{' enumerator_list comma_opt '}' 2256 2198 { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); } 2257 | ENUM attribute_ list_opt typedef_name // unqualified type name2199 | ENUM attribute_opt typedef // enum cannot be generic 2258 2200 '{' enumerator_list comma_opt '}' 2259 2201 { $$ = DeclarationNode::newEnum( $3->name, $5, true )->addQualifiers( $2 ); } 2260 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}' 2261 { 2262 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2263 SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; 2264 } 2265 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2266 { 2267 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2268 typedefTable.makeTypedef( *$6 ); 2269 } 2270 '{' enumerator_list comma_opt '}' 2271 { 2272 SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; 2273 } 2274 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}' 2275 { 2276 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2277 typedefTable.makeTypedef( *$6->name ); 2278 SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; 2279 } 2202 | ENUM enum_specifier_nobody '{' enumerator_list comma_opt '}' 2203 // { $$ = DeclarationNode::newEnum( nullptr, $4, true ); } 2204 { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; } 2205 | ENUM enum_specifier_nobody declarator '{' enumerator_list comma_opt '}' 2206 // { 2207 // typedefTable.makeTypedef( *$3->name ); 2208 // $$ = DeclarationNode::newEnum( nullptr, $5, true ); 2209 // } 2210 { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; } 2280 2211 | enum_type_nobody 2281 2212 ; 2282 2213 2283 2214 enum_type_nobody: // enum - {...} 2284 ENUM attribute_list_opt identifier 2285 { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); } 2286 | ENUM attribute_list_opt type_name // qualified type name 2287 { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); } 2215 ENUM attribute_opt identifier 2216 { 2217 typedefTable.makeTypedef( *$3 ); 2218 $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); 2219 } 2220 | ENUM attribute_opt type_name // enum cannot be generic 2221 { 2222 typedefTable.makeTypedef( *$3->type->symbolic.name ); 2223 $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); 2224 } 2288 2225 ; 2289 2226 … … 2291 2228 identifier_or_type_name enumerator_value_opt 2292 2229 { $$ = DeclarationNode::newEnumConstant( $1, $2 ); } 2293 | INLINE type_name2294 { $$ = DeclarationNode::newEnumConstant( new string("inline"), nullptr ); }2295 2230 | enumerator_list ',' identifier_or_type_name enumerator_value_opt 2296 2231 { $$ = $1->appendList( DeclarationNode::newEnumConstant( $3, $4 ) ); } 2297 | enumerator_list ',' INLINE type_name enumerator_value_opt2298 { $$ = $1->appendList( DeclarationNode::newEnumConstant( new string("inline"), nullptr ) ); }2299 2232 ; 2300 2233 … … 2304 2237 // | '=' constant_expression 2305 2238 // { $$ = $2; } 2306 | simple_assignment_operatorinitializer2239 | '=' initializer 2307 2240 { $$ = $2->get_expression(); } // FIX ME: enum only deals with constant_expression 2308 2241 ; … … 2432 2365 // empty 2433 2366 { $$ = nullptr; } 2434 | simple_assignment_operator initializer { $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); } 2435 | '=' VOID { $$ = new InitializerNode( true ); } 2367 | '=' initializer 2368 { $$ = $2; } 2369 | '=' VOID 2370 { $$ = new InitializerNode( true ); } 2371 | ATassign initializer 2372 { $$ = $2->set_maybeConstructed( false ); } 2436 2373 ; 2437 2374 … … 2689 2626 2690 2627 external_definition: 2691 DIRECTIVE 2692 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); } 2693 | declaration 2628 declaration 2694 2629 | external_function_definition 2695 2630 | EXTENSION external_definition // GCC, multiple __extension__ allowed, meaning unknown … … 2699 2634 } 2700 2635 | ASM '(' string_literal ')' ';' // GCC, global assembler statement 2701 { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); } 2636 { 2637 $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); 2638 } 2702 2639 | EXTERN STRINGliteral // C++-style linkage specifier 2703 2640 { … … 2845 2782 ; 2846 2783 2784 attribute_opt: 2785 // empty 2786 { $$ = nullptr; } 2787 | attribute 2788 ; 2789 2847 2790 attribute: // GCC 2848 2791 ATTRIBUTE '(' '(' attribute_name_list ')' ')' … … 2906 2849 // declaring an array of functions versus a pointer to an array of functions. 2907 2850 2908 paren_identifier:2909 identifier2910 { $$ = DeclarationNode::newName( $1 ); }2911 | '(' paren_identifier ')' // redundant parenthesis2912 { $$ = $2; }2913 ;2914 2915 2851 variable_declarator: 2916 2852 paren_identifier attribute_list_opt … … 2923 2859 ; 2924 2860 2861 paren_identifier: 2862 identifier 2863 { $$ = DeclarationNode::newName( $1 ); } 2864 | '(' paren_identifier ')' // redundant parenthesis 2865 { $$ = $2; } 2866 ; 2867 2925 2868 variable_ptr: 2926 2869 ptrref_operator variable_declarator … … 2928 2871 | ptrref_operator type_qualifier_list variable_declarator 2929 2872 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 2930 | '(' variable_ptr ')' attribute_list_opt // redundant parenthesis 2931 { $$ = $2->addQualifiers( $4 ); } 2932 | '(' attribute_list variable_ptr ')' attribute_list_opt // redundant parenthesis 2933 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 2873 | '(' variable_ptr ')' attribute_list_opt 2874 { $$ = $2->addQualifiers( $4 ); } // redundant parenthesis 2934 2875 ; 2935 2876 … … 2939 2880 | '(' variable_ptr ')' array_dimension 2940 2881 { $$ = $2->addArray( $4 ); } 2941 | '(' attribute_list variable_ptr ')' array_dimension 2942 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2943 | '(' variable_array ')' multi_array_dimension // redundant parenthesis 2882 | '(' variable_array ')' multi_array_dimension // redundant parenthesis 2944 2883 { $$ = $2->addArray( $4 ); } 2945 | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis2946 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }2947 2884 | '(' variable_array ')' // redundant parenthesis 2948 2885 { $$ = $2; } 2949 | '(' attribute_list variable_array ')' // redundant parenthesis2950 { $$ = $3->addQualifiers( $2 ); }2951 2886 ; 2952 2887 … … 2954 2889 '(' variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 2955 2890 { $$ = $2->addParamList( $6 ); } 2956 | '(' attribute_list variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)2957 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }2958 2891 | '(' variable_function ')' // redundant parenthesis 2959 2892 { $$ = $2; } 2960 | '(' attribute_list variable_function ')' // redundant parenthesis2961 { $$ = $3->addQualifiers( $2 ); }2962 2893 ; 2963 2894 … … 2979 2910 | '(' function_ptr ')' '(' push parameter_type_list_opt pop ')' 2980 2911 { $$ = $2->addParamList( $6 ); } 2981 | '(' attribute_list function_ptr ')' '(' push parameter_type_list_opt pop ')'2982 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }2983 2912 | '(' function_no_ptr ')' // redundant parenthesis 2984 2913 { $$ = $2; } 2985 | '(' attribute_list function_no_ptr ')' // redundant parenthesis2986 { $$ = $3->addQualifiers( $2 ); }2987 2914 ; 2988 2915 … … 2992 2919 | ptrref_operator type_qualifier_list function_declarator 2993 2920 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 2994 | '(' function_ptr ')' attribute_list_opt 2995 { $$ = $2->addQualifiers( $4 ); } 2996 | '(' attribute_list function_ptr ')' attribute_list_opt 2997 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 2921 | '(' function_ptr ')' 2922 { $$ = $2; } 2998 2923 ; 2999 2924 … … 3001 2926 '(' function_ptr ')' array_dimension 3002 2927 { $$ = $2->addArray( $4 ); } 3003 | '(' attribute_list function_ptr ')' array_dimension3004 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }3005 2928 | '(' function_array ')' multi_array_dimension // redundant parenthesis 3006 2929 { $$ = $2->addArray( $4 ); } 3007 | '(' attribute_list function_array ')' multi_array_dimension // redundant parenthesis3008 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }3009 2930 | '(' function_array ')' // redundant parenthesis 3010 2931 { $$ = $2; } 3011 | '(' attribute_list function_array ')' // redundant parenthesis3012 { $$ = $3->addQualifiers( $2 ); }3013 2932 ; 3014 2933 … … 3031 2950 | '(' KR_function_ptr ')' '(' push parameter_type_list_opt pop ')' 3032 2951 { $$ = $2->addParamList( $6 ); } 3033 | '(' attribute_list KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'3034 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }3035 2952 | '(' KR_function_no_ptr ')' // redundant parenthesis 3036 2953 { $$ = $2; } 3037 | '(' attribute_list KR_function_no_ptr ')' // redundant parenthesis3038 { $$ = $3->addQualifiers( $2 ); }3039 2954 ; 3040 2955 … … 3046 2961 | '(' KR_function_ptr ')' 3047 2962 { $$ = $2; } 3048 | '(' attribute_list KR_function_ptr ')'3049 { $$ = $3->addQualifiers( $2 ); }3050 2963 ; 3051 2964 … … 3053 2966 '(' KR_function_ptr ')' array_dimension 3054 2967 { $$ = $2->addArray( $4 ); } 3055 | '(' attribute_list KR_function_ptr ')' array_dimension3056 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }3057 2968 | '(' KR_function_array ')' multi_array_dimension // redundant parenthesis 3058 2969 { $$ = $2->addArray( $4 ); } 3059 | '(' attribute_list KR_function_array ')' multi_array_dimension // redundant parenthesis3060 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }3061 2970 | '(' KR_function_array ')' // redundant parenthesis 3062 2971 { $$ = $2; } 3063 | '(' attribute_list KR_function_array ')' // redundant parenthesis3064 { $$ = $3->addQualifiers( $2 ); }3065 2972 ; 3066 2973 … … 3074 2981 // The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays 3075 2982 // and functions versus pointers to arrays and functions. 3076 3077 paren_type:3078 typedef_name3079 {3080 // hide type name in enclosing scope by variable name3081 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );3082 }3083 | '(' paren_type ')'3084 { $$ = $2; }3085 ;3086 2983 3087 2984 variable_type_redeclarator: … … 3095 2992 ; 3096 2993 2994 paren_type: 2995 typedef 2996 // hide type name in enclosing scope by variable name 2997 { 2998 // if ( ! typedefTable.existsCurr( *$1->name ) ) { 2999 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" ); 3000 // } else { 3001 // SemanticError( yylloc, string("'") + *$1->name + "' redeclared as different kind of symbol." ); $$ = nullptr; 3002 // } // if 3003 } 3004 | '(' paren_type ')' 3005 { $$ = $2; } 3006 ; 3007 3097 3008 type_ptr: 3098 3009 ptrref_operator variable_type_redeclarator … … 3100 3011 | ptrref_operator type_qualifier_list variable_type_redeclarator 3101 3012 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3102 | '(' type_ptr ')' attribute_list_opt // redundant parenthesis 3103 { $$ = $2->addQualifiers( $4 ); } 3104 | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis 3105 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 3013 | '(' type_ptr ')' attribute_list_opt 3014 { $$ = $2->addQualifiers( $4 ); } // redundant parenthesis 3106 3015 ; 3107 3016 … … 3111 3020 | '(' type_ptr ')' array_dimension 3112 3021 { $$ = $2->addArray( $4 ); } 3113 | '(' attribute_list type_ptr ')' array_dimension3114 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }3115 3022 | '(' type_array ')' multi_array_dimension // redundant parenthesis 3116 3023 { $$ = $2->addArray( $4 ); } 3117 | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis3118 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }3119 3024 | '(' type_array ')' // redundant parenthesis 3120 3025 { $$ = $2; } 3121 | '(' attribute_list type_array ')' // redundant parenthesis3122 { $$ = $3->addQualifiers( $2 ); }3123 3026 ; 3124 3027 … … 3128 3031 | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3129 3032 { $$ = $2->addParamList( $6 ); } 3130 | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)3131 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }3132 3033 | '(' type_function ')' // redundant parenthesis 3133 3034 { $$ = $2; } 3134 | '(' attribute_list type_function ')' // redundant parenthesis3135 { $$ = $3->addQualifiers( $2 ); }3136 3035 ; 3137 3036 … … 3158 3057 | ptrref_operator type_qualifier_list identifier_parameter_declarator 3159 3058 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3160 | '(' identifier_parameter_ptr ')' attribute_list_opt // redundant parenthesis3059 | '(' identifier_parameter_ptr ')' attribute_list_opt 3161 3060 { $$ = $2->addQualifiers( $4 ); } 3162 3061 ; … … 3192 3091 3193 3092 type_parameter_redeclarator: 3194 typedef _nameattribute_list_opt3093 typedef attribute_list_opt 3195 3094 { $$ = $1->addQualifiers( $2 ); } 3196 | '&' MUTEX typedef _nameattribute_list_opt3095 | '&' MUTEX typedef attribute_list_opt 3197 3096 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3198 3097 | type_parameter_ptr … … 3203 3102 ; 3204 3103 3205 typedef _name:3104 typedef: 3206 3105 TYPEDEFname 3207 3106 { $$ = DeclarationNode::newName( $1 ); } … … 3215 3114 | ptrref_operator type_qualifier_list type_parameter_redeclarator 3216 3115 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3217 | '(' type_parameter_ptr ')' attribute_list_opt // redundant parenthesis3116 | '(' type_parameter_ptr ')' attribute_list_opt 3218 3117 { $$ = $2->addQualifiers( $4 ); } 3219 3118 ; 3220 3119 3221 3120 type_parameter_array: 3222 typedef _namearray_parameter_dimension3121 typedef array_parameter_dimension 3223 3122 { $$ = $1->addArray( $2 ); } 3224 3123 | '(' type_parameter_ptr ')' array_parameter_dimension … … 3227 3126 3228 3127 type_parameter_function: 3229 typedef _name '(' push parameter_type_list_opt pop ')'// empty parameter list OBSOLESCENT (see 3)3128 typedef '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3230 3129 { $$ = $1->addParamList( $4 ); } 3231 3130 | '(' type_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) … … 3356 3255 | ptrref_operator type_qualifier_list abstract_parameter_declarator 3357 3256 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3358 | '(' abstract_parameter_ptr ')' attribute_list_opt // redundant parenthesis3257 | '(' abstract_parameter_ptr ')' attribute_list_opt 3359 3258 { $$ = $2->addQualifiers( $4 ); } 3360 3259 ; … … 3435 3334 | ptrref_operator type_qualifier_list variable_abstract_declarator 3436 3335 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3437 | '(' variable_abstract_ptr ')' attribute_list_opt // redundant parenthesis3336 | '(' variable_abstract_ptr ')' attribute_list_opt 3438 3337 { $$ = $2->addQualifiers( $4 ); } 3439 3338 ; -
src/ResolvExpr/CurrentObject.cc
r5407cdc rfeacef9 925 925 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) { 926 926 if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) { 927 assert( sit->base );928 927 return new StructIterator{ loc, sit }; 929 928 } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) { 930 assert( uit->base );931 929 return new UnionIterator{ loc, uit }; 932 930 } else { -
src/SynTree/Constant.cc
r5407cdc rfeacef9 42 42 } 43 43 44 Constant Constant::from_string( const std::string & str ) {45 Type * charType = new BasicType( noQualifiers, BasicType::Char );46 // Adjust the length of the string for the terminator.47 Expression * strSize = new ConstantExpr( Constant::from_ulong( str.size() + 1 ) );48 Type * strType = new ArrayType( noQualifiers, charType, strSize, false, false );49 const std::string strValue = "\"" + str + "\"";50 return Constant( strType, strValue, std::nullopt );51 }52 53 44 Constant Constant::null( Type * ptrtype ) { 54 45 if ( nullptr == ptrtype ) { -
src/SynTree/Constant.h
r5407cdc rfeacef9 47 47 /// generates an integer constant of the given unsigned long int 48 48 static Constant from_ulong( unsigned long i ); 49 /// generates a string constant from the given string (char type, unquoted string)50 static Constant from_string( const std::string & string );51 49 52 50 /// generates a null pointer value for the given type. void * if omitted. -
src/SynTree/Declaration.cc
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:35:39 202113 // Update Count : 3 712 // Last Modified On : Wed Dec 11 16:39:56 2019 13 // Update Count : 36 14 14 // 15 15 … … 66 66 67 67 68 DirectiveDecl::DirectiveDecl( DirectiveStmt *stmt ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), stmt( stmt ) {69 }70 71 DirectiveDecl::DirectiveDecl( const DirectiveDecl &other ) : Declaration( other ), stmt( maybeClone( other.stmt ) ) {72 }73 74 DirectiveDecl::~DirectiveDecl() {75 delete stmt;76 }77 78 void DirectiveDecl::print( std::ostream &os, Indenter indent ) const {79 stmt->print( os, indent );80 }81 82 void DirectiveDecl::printShort( std::ostream &os, Indenter indent ) const {83 stmt->print( os, indent );84 }85 86 87 68 StaticAssertDecl::StaticAssertDecl( Expression * condition, ConstantExpr * message ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), condition( condition ), message( message ) { 88 69 } -
src/SynTree/Declaration.h
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:35:36202113 // Update Count : 15 912 // Last Modified On : Mon Jan 11 20:48:39 2021 13 // Update Count : 158 14 14 // 15 15 … … 400 400 }; 401 401 402 class DirectiveDecl : public Declaration {403 public:404 DirectiveStmt * stmt;405 406 DirectiveDecl( DirectiveStmt * stmt );407 DirectiveDecl( const DirectiveDecl & other );408 virtual ~DirectiveDecl();409 410 DirectiveStmt * get_stmt() { return stmt; }411 void set_stmt( DirectiveStmt * newValue ) { stmt = newValue; }412 413 virtual DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); }414 virtual void accept( Visitor & v ) override { v.visit( this ); }415 virtual void accept( Visitor & v ) const override { v.visit( this ); }416 virtual DirectiveDecl * acceptMutator( Mutator & m ) override { return m.mutate( this ); }417 virtual void print( std::ostream & os, Indenter indent = {} ) const override;418 virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;419 };420 421 402 class StaticAssertDecl : public Declaration { 422 403 public: -
src/SynTree/Mutator.h
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:35:36 202113 // Update Count : 1 812 // Last Modified On : Thu Jul 25 22:37:46 2019 13 // Update Count : 17 14 14 // 15 15 #pragma once … … 34 34 virtual Declaration * mutate( TypedefDecl * typeDecl ) = 0; 35 35 virtual AsmDecl * mutate( AsmDecl * asmDecl ) = 0; 36 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0;37 36 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0; 38 37 -
src/SynTree/SynTree.h
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:56:44 202113 // Update Count : 1 312 // Last Modified On : Thu Jul 25 22:37:45 2019 13 // Update Count : 12 14 14 // 15 15 … … 36 36 class TypedefDecl; 37 37 class AsmDecl; 38 class DirectiveDecl;39 38 class StaticAssertDecl; 40 39 -
src/SynTree/Visitor.h
r5407cdc rfeacef9 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:35:35 202113 // Update Count : 1 512 // Last Modified On : Thu Jul 25 22:21:49 2019 13 // Update Count : 14 14 14 // 15 15 … … 45 45 virtual void visit( AsmDecl * node ) { visit( const_cast<const AsmDecl *>(node) ); } 46 46 virtual void visit( const AsmDecl * asmDecl ) = 0; 47 virtual void visit( DirectiveDecl * node ) { visit( const_cast<const DirectiveDecl *>(node) ); }48 virtual void visit( const DirectiveDecl * directiveDecl ) = 0;49 47 virtual void visit( StaticAssertDecl * node ) { visit( const_cast<const StaticAssertDecl *>(node) ); } 50 48 virtual void visit( const StaticAssertDecl * assertDecl ) = 0; -
src/Virtual/ExpandCasts.cc
r5407cdc rfeacef9 32 32 namespace Virtual { 33 33 34 static bool is_prefix( const std::string & prefix, const std::string& entire ) {35 size_t const p_size = prefix.size();36 return (p_size < entire.size() && prefix == entire.substr(0, p_size));37 }38 39 static bool is_type_id_object( const ObjectDecl * objectDecl ) {40 const std::string & objectName = objectDecl->name;41 return is_prefix( "__cfatid_", objectName );42 }43 44 34 // Indented until the new ast code gets added. 45 35 … … 76 66 }; 77 67 68 /* Currently virtual depends on the rather brittle name matching between 69 * a (strict/explicate) virtual type, its vtable type and the vtable 70 * instance. 71 * A stronger implementation, would probably keep track of those triads 72 * and use that information to create better error messages. 73 */ 74 75 namespace { 76 77 std::string get_vtable_name( std::string const & name ) { 78 return name + "_vtable"; 79 } 80 81 std::string get_vtable_inst_name( std::string const & name ) { 82 return std::string("_") + get_vtable_name( name ) + "_instance"; 83 } 84 85 std::string get_vtable_name_root( std::string const & name ) { 86 return name.substr(0, name.size() - 7 ); 87 } 88 89 std::string get_vtable_inst_name_root( std::string const & name ) { 90 return get_vtable_name_root( name.substr(1, name.size() - 10 ) ); 91 } 92 93 bool is_vtable_inst_name( std::string const & name ) { 94 return 17 < name.size() && 95 name == get_vtable_inst_name( get_vtable_inst_name_root( name ) ); 96 } 97 98 } // namespace 99 78 100 class VirtualCastCore { 79 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection) {101 Type * pointer_to_pvt(int level_of_indirection) { 80 102 Type * type = new StructInstType( 81 103 Type::Qualifiers( Type::Const ), pvt_decl ); … … 83 105 type = new PointerType( noQualifiers, type ); 84 106 } 85 return new CastExpr( expr, type );107 return type; 86 108 } 87 109 … … 119 141 120 142 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { 121 if ( is_type_id_object( objectDecl ) ) { 122 // Multiple definitions should be fine because of linkonce. 123 indexer.insert( objectDecl ); 143 if ( is_vtable_inst_name( objectDecl->get_name() ) ) { 144 if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) { 145 std::string msg = "Repeated instance of virtual table, original found at: "; 146 msg += existing->location.filename; 147 msg += ":" + toString( existing->location.first_line ); 148 SemanticError( objectDecl->location, msg ); 149 } 124 150 } 125 151 } … … 144 170 } 145 171 146 /// Get the base type from a pointer or reference. 147 const Type * getBaseType( const Type * type ) { 148 if ( auto target = dynamic_cast<const PointerType *>( type ) ) { 149 return target->base; 150 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) { 151 return target->base; 172 /// Get the virtual table type used in a virtual cast. 173 Type * getVirtualTableType( const VirtualCastExpr * castExpr ) { 174 const Type * objectType; 175 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) { 176 objectType = target->base; 177 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) { 178 objectType = target->base; 152 179 } else { 153 return nullptr; 154 } 155 } 156 157 /* Attempt to follow the "head" field of the structure to get the... 158 * Returns nullptr on error, otherwise owner must free returned node. 159 */ 160 StructInstType * followHeadPointerType( 161 const StructInstType * oldType, 162 const std::string& fieldName, 163 const CodeLocation& errorLocation ) { 164 165 // First section of the function is all about trying to fill this variable in. 166 StructInstType * newType = nullptr; 167 { 168 const StructDecl * oldDecl = oldType->baseStruct; 169 assert( oldDecl ); 170 171 // Helper function for throwing semantic errors. 172 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) { 173 const std::string& context = "While following head pointer of " + 174 oldDecl->name + " named '" + fieldName + "': "; 175 SemanticError( errorLocation, context + message ); 176 }; 177 178 if ( oldDecl->members.empty() ) { 179 throwError( "Type has no fields." ); 180 } 181 const Declaration * memberDecl = oldDecl->members.front(); 180 castError( castExpr, "Virtual cast type must be a pointer or reference type." ); 181 } 182 assert( objectType ); 183 184 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType ); 185 if ( nullptr == structType ) { 186 castError( castExpr, "Virtual cast type must refer to a structure type." ); 187 } 188 const StructDecl * structDecl = structType->baseStruct; 189 assert( structDecl ); 190 191 const ObjectDecl * fieldDecl = nullptr; 192 if ( 0 < structDecl->members.size() ) { 193 const Declaration * memberDecl = structDecl->members.front(); 182 194 assert( memberDecl ); 183 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 184 assert( fieldDecl ); 185 if ( fieldName != fieldDecl->name ) { 186 throwError( "Head field did not have expected name." ); 187 } 188 189 const Type * fieldType = fieldDecl->type; 190 if ( nullptr == fieldType ) { 191 throwError( "Could not get head field." ); 192 } 193 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType ); 194 if ( nullptr == ptrType ) { 195 throwError( "First field is not a pointer type." ); 196 } 197 assert( ptrType->base ); 198 newType = dynamic_cast<StructInstType *>( ptrType->base ); 199 if ( nullptr == newType ) { 200 throwError( "First field does not point to a structure type." ); 201 } 202 } 203 204 // Now we can look into copying it. 205 newType = newType->clone(); 206 if ( ! oldType->parameters.empty() ) { 207 deleteAll( newType->parameters ); 208 newType->parameters.clear(); 209 cloneAll( oldType->parameters, newType->parameters ); 210 } 211 return newType; 212 } 213 214 /// Get the type-id type from a virtual type. 215 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) { 216 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type ); 217 if ( nullptr == typeInst ) { 218 return nullptr; 219 } 220 StructInstType * tableInst = 221 followHeadPointerType( typeInst, "virtual_table", errorLocation ); 222 if ( nullptr == tableInst ) { 223 return nullptr; 224 } 225 StructInstType * typeIdInst = 226 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation ); 227 delete tableInst; 228 return typeIdInst; 195 fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 196 if ( fieldDecl && fieldDecl->name != "virtual_table" ) { 197 fieldDecl = nullptr; 198 } 199 } 200 if ( nullptr == fieldDecl ) { 201 castError( castExpr, "Virtual cast type must have a leading virtual_table field." ); 202 } 203 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type ); 204 if ( nullptr == fieldType ) { 205 castError( castExpr, "Virtual cast type virtual_table field is not a pointer." ); 206 } 207 assert( fieldType->base ); 208 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base ); 209 assert( virtualStructType ); 210 211 // Here is the type, but if it is polymorphic it will have lost information. 212 // (Always a clone so that it may always be deleted.) 213 StructInstType * virtualType = virtualStructType->clone(); 214 if ( ! structType->parameters.empty() ) { 215 deleteAll( virtualType->parameters ); 216 virtualType->parameters.clear(); 217 cloneAll( structType->parameters, virtualType->parameters ); 218 } 219 return virtualType; 229 220 } 230 221 … … 237 228 assert( pvt_decl ); 238 229 239 const Type * base_type = getBaseType( castExpr->result ); 240 if ( nullptr == base_type ) { 241 castError( castExpr, "Virtual cast target must be a pointer or reference type." ); 242 } 243 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) ); 244 if ( nullptr == type_id_type ) { 245 castError( castExpr, "Ill formed virtual cast target type." ); 246 } 247 ObjectDecl * type_id = indexer.lookup( type_id_type ); 248 delete type_id_type; 249 if ( nullptr == type_id ) { 250 castError( castExpr, "Virtual cast does not target a virtual type." ); 230 const Type * vtable_type = getVirtualTableType( castExpr ); 231 ObjectDecl * table = indexer.lookup( vtable_type ); 232 if ( nullptr == table ) { 233 SemanticError( castLocation( castExpr ), 234 "Could not find virtual table instance." ); 251 235 } 252 236 253 237 Expression * result = new CastExpr( 254 238 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { 255 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ), 256 cast_to_type_id( castExpr->get_arg(), 2 ), 239 new CastExpr( 240 new AddressExpr( new VariableExpr( table ) ), 241 pointer_to_pvt(1) 242 ), 243 new CastExpr( 244 castExpr->get_arg(), 245 pointer_to_pvt(2) 246 ) 257 247 } ), 258 248 castExpr->get_result()->clone() … … 262 252 castExpr->set_result( nullptr ); 263 253 delete castExpr; 254 delete vtable_type; 264 255 return result; 265 256 } -
src/Virtual/Tables.cc
r5407cdc rfeacef9 10 10 // Created On : Mon Aug 31 11:11:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 21 15:36:00 202113 // Update Count : 212 // Last Modified On : Tue Sep 3 14:56:00 2020 13 // Update Count : 0 14 14 // 15 15 … … 22 22 namespace Virtual { 23 23 24 std::string typeIdType( std::string const & type_name ) {25 return "__cfatid_struct_" + type_name;26 }27 28 std::string typeIdName( std::string const & type_name ) {29 return "__cfatid_" + type_name;30 }31 32 static std::string typeIdTypeToInstance( std::string const & type_name ) {33 return typeIdName(type_name.substr(16));34 }35 36 24 std::string vtableTypeName( std::string const & name ) { 37 25 return name + "_vtable"; 38 }39 40 std::string baseTypeName( std::string const & vtable_type_name ) {41 return vtable_type_name.substr(0, vtable_type_name.size() - 7);42 26 } 43 27 … … 50 34 } 51 35 52 std::string concurrentDefaultVTableName() {53 return "_default_vtable";54 }55 56 36 bool isVTableInstanceName( std::string const & name ) { 57 37 // There are some delicate length calculations here. … … 61 41 62 42 static ObjectDecl * makeVtableDeclaration( 63 std::string const & name,64 43 StructInstType * type, Initializer * init ) { 44 std::string const & name = instanceName( type->name ); 65 45 Type::StorageClasses storage = noStorageClasses; 66 46 if ( nullptr == init ) { … … 77 57 } 78 58 79 ObjectDecl * makeVtableForward( std::string const & name,StructInstType * type ) {59 ObjectDecl * makeVtableForward( StructInstType * type ) { 80 60 assert( type ); 81 return makeVtableDeclaration( name,type, nullptr );61 return makeVtableDeclaration( type, nullptr ); 82 62 } 83 63 84 64 ObjectDecl * makeVtableInstance( 85 std::string const & name, StructInstType * vtableType, 86 Type * objectType, Initializer * init ) { 65 StructInstType * vtableType, Type * objectType, Initializer * init ) { 87 66 assert( vtableType ); 88 67 assert( objectType ); … … 102 81 inits.push_back( 103 82 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) ); 104 } else if ( std::string( "__cfavir_typeid" ) == field->name ) {105 std::string const & baseType = baseTypeName( vtableType->name );106 std::string const & typeId = typeIdName( baseType );107 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );108 83 } else if ( std::string( "size" ) == field->name ) { 109 84 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) ); … … 120 95 assert(false); 121 96 } 122 return makeVtableDeclaration( name,vtableType, init );97 return makeVtableDeclaration( vtableType, init ); 123 98 } 124 99 … … 172 147 } 173 148 174 Attribute * linkonce( const std::string & subsection ) {175 const std::string section = ".gnu.linkonce." + subsection;176 return new Attribute( "section", {177 new ConstantExpr( Constant::from_string( section ) ),178 } );179 149 } 180 181 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {182 assert( typeIdType );183 StructInstType * type = typeIdType->clone();184 type->tq.is_const = true;185 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );186 return new ObjectDecl(187 typeid_name,188 noStorageClasses,189 LinkageSpec::Cforall,190 /* bitfieldWidth */ nullptr,191 type,192 new ListInit( { new SingleInit(193 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )194 ) } ),195 { linkonce( typeid_name ) },196 noFuncSpecifiers197 );198 }199 200 } -
src/Virtual/Tables.h
r5407cdc rfeacef9 10 10 // Created On : Mon Aug 31 11:07:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 21 10:30:00 202113 // Update Count : 212 // Last Modified On : Tue Sep 1 14:29:00 2020 13 // Update Count : 0 14 14 // 15 15 … … 22 22 namespace Virtual { 23 23 24 std::string typeIdType( std::string const & type_name );25 std::string typeIdName( std::string const & type_name );26 24 std::string vtableTypeName( std::string const & type_name ); 27 25 std::string instanceName( std::string const & vtable_name ); 28 26 std::string vtableInstanceName( std::string const & type_name ); 29 std::string concurrentDefaultVTableName();30 27 bool isVTableInstanceName( std::string const & name ); 31 28 32 ObjectDecl * makeVtableForward( 33 std::string const & name, StructInstType * vtableType ); 29 ObjectDecl * makeVtableForward( StructInstType * vtableType ); 34 30 /* Create a forward declaration of a vtable of the given type. 35 31 * vtableType node is consumed. 36 32 */ 37 33 38 ObjectDecl * makeVtableInstance( 39 std::string const & name, 40 StructInstType * vtableType, Type * objectType, 34 ObjectDecl * makeVtableInstance( StructInstType * vtableType, Type * objectType, 41 35 Initializer * init = nullptr ); 42 36 /* Create an initialized definition of a vtable. … … 56 50 */ 57 51 58 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );59 /* Build an instance of the type-id from the type of the type-id.60 * TODO: Should take the parent type. Currently locked to the exception_t.61 */62 63 52 } -
src/main.cc
r5407cdc rfeacef9 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Mar 6 15:49:00202113 // Update Count : 6 5612 // Last Modified On : Mon Feb 8 21:10:16 2021 13 // Update Count : 642 14 14 // 15 15 … … 101 101 static string PreludeDirector = ""; 102 102 103 static void parse_cmdline( int argc, char * argv[] );103 static void parse_cmdline( int argc, char *argv[] ); 104 104 static void parse( FILE * input, LinkageSpec::Spec linkage, bool shouldExit = false ); 105 105 static void dump( list< Declaration * > & translationUnit, ostream & out = cout ); 106 static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );107 106 108 107 static void backtrace( int start ) { // skip first N stack frames … … 159 158 #define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused )) 160 159 161 static void Signal( int sig, void (* handler)(SIGPARMS), int flags ) {160 static void Signal( int sig, void (*handler)(SIGPARMS), int flags ) { 162 161 struct sigaction act; 163 162 … … 166 165 167 166 if ( sigaction( sig, &act, nullptr ) == -1 ) { 168 cerr << "* cfa-cpp compilationerror* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;167 cerr << "*CFA runtime error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl; 169 168 _exit( EXIT_FAILURE ); 170 169 } // if … … 350 349 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 351 350 if ( exprp ) { 352 dump( move( transUnit ) ); 351 translationUnit = convert( move( transUnit ) ); 352 dump( translationUnit ); 353 353 return EXIT_SUCCESS; 354 354 } // if … … 421 421 delete output; 422 422 } // if 423 } catch ( SemanticErrorException & e ) {423 } catch ( SemanticErrorException &e ) { 424 424 if ( errorp ) { 425 425 cerr << "---AST at error:---" << endl; … … 432 432 } // if 433 433 return EXIT_FAILURE; 434 } catch ( UnimplementedError & e ) {434 } catch ( UnimplementedError &e ) { 435 435 cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl; 436 436 if ( output != &cout ) { … … 438 438 } // if 439 439 return EXIT_FAILURE; 440 } catch ( CompilerError & e ) {440 } catch ( CompilerError &e ) { 441 441 cerr << "Compiler Error: " << e.get_what() << endl; 442 442 cerr << "(please report bugs to [REDACTED])" << endl; … … 445 445 } // if 446 446 return EXIT_FAILURE; 447 } catch ( std::bad_alloc & ) {448 cerr << "*cfa-cpp compilation error* std::bad_alloc" << endl;449 backtrace( 1 );450 abort();451 447 } catch ( ... ) { 452 448 exception_ptr eptr = current_exception(); … … 455 451 rethrow_exception(eptr); 456 452 } else { 457 cerr << " *cfa-cpp compilation error* exception uncaught and unknown" << endl;458 } // if 459 } catch( const exception & e) {460 cerr << " *cfa-cpp compilation error* uncaught exception \"" << e.what() << "\"\n";453 cerr << "Exception Uncaught and Unknown" << endl; 454 } // if 455 } catch(const exception& e) { 456 cerr << "Uncaught Exception \"" << e.what() << "\"\n"; 461 457 } // try 462 458 return EXIT_FAILURE; … … 548 544 enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) }; 549 545 550 static void usage( char * argv[] ) {546 static void usage( char *argv[] ) { 551 547 cout << "Usage: " << argv[0] << " [options] [input-file (default stdin)] [output-file (default stdout)], where options are:" << endl; 552 548 int i = 0, j = 1; // j skips starting colon … … 736 732 } // dump 737 733 738 static void dump( ast::TranslationUnit && transUnit, ostream & out ) {739 std::list< Declaration * > translationUnit = convert( move( transUnit ) );740 dump( translationUnit, out );741 }742 743 734 // Local Variables: // 744 735 // tab-width: 4 // -
tests/.expect/KRfunctions.nast.arm64.txt
r5407cdc rfeacef9 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 6)(signed int __param_0, signed int __param_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));106 signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4))); 108 108 } 109 109 -
tests/.expect/KRfunctions.nast.x64.txt
r5407cdc rfeacef9 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 6)(signed int __param_0, signed int __param_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));106 signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4))); 108 108 } 109 109 -
tests/.expect/KRfunctions.nast.x86.txt
r5407cdc rfeacef9 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 6)(signed int __param_0, signed int __param_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));106 signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4))); 108 108 } 109 109 -
tests/.expect/KRfunctions.oast.x64.txt
r5407cdc rfeacef9 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 6)(signed int _X1xi_1, signed int _X1yi_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));106 signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4))); 108 108 } 109 109 -
tests/.expect/attributes.nast.arm64.txt
r5407cdc rfeacef9 6 6 7 7 } 8 struct __a nonymous0 {8 struct __attribute__ ((unused)) __anonymous0 { 9 9 }; 10 10 static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1); … … 26 26 return _X4_retS12__anonymous0_1; 27 27 } 28 __attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;29 28 struct __attribute__ ((unused)) Agn1; 30 29 struct __attribute__ ((unused)) Agn2 { … … 104 103 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 104 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 105 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 112 106 }; 113 107 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 123 117 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 124 118 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 119 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 131 120 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 132 121 { … … 166 155 } 167 156 168 {169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);170 }171 172 {173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);174 }175 176 {177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);178 }179 180 {181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);182 }183 184 {185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);186 }187 188 157 } 189 158 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 224 193 } 225 194 226 {227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);228 }229 230 {231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);232 }233 234 {235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);236 }237 238 {239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);240 }241 242 {243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);244 }245 246 195 } 247 196 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 {249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);250 }251 252 {253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);254 }255 256 {257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);258 }259 260 {261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);262 }263 264 {265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);266 }267 268 197 { 269 198 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 342 271 343 272 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));345 }346 347 {348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));349 }350 351 {352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));353 }354 355 {356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));357 }358 359 {360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));361 }362 363 {364 273 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 365 274 } … … 404 313 } 405 314 406 {407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);408 }409 410 {411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);412 }413 414 {415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);416 }417 418 {419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);420 }421 422 {423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);424 }425 426 315 } 427 316 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 462 351 } 463 352 464 {465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);466 }467 468 {469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);470 }471 472 {473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);474 }475 476 {477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);478 }479 480 {481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);482 }483 484 353 } 485 354 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 520 389 } 521 390 522 {523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);524 }525 526 {527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);528 }529 530 {531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);532 }533 534 {535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);536 }537 538 {539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);540 }541 542 391 } 543 392 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 578 427 } 579 428 580 {581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);582 }583 584 {585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);586 }587 588 {589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);590 }591 592 {593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);594 }595 596 {597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);598 }599 600 429 } 601 430 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 636 465 } 637 466 638 {639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);640 }641 642 {643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);644 }645 646 {647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);648 }649 650 {651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);652 }653 654 {655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);656 }657 658 467 } 659 468 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 694 503 } 695 504 696 {697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);698 }699 700 {701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);702 }703 704 {705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);706 }707 708 {709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);710 }711 712 {713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);714 }715 716 505 } 717 506 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 752 541 } 753 542 754 {755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);756 }757 758 {759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);760 }761 762 {763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);764 }765 766 {767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);768 }769 770 {771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);772 }773 774 543 } 775 544 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 810 579 } 811 580 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 581 } 582 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 834 583 { 835 584 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 866 615 { 867 616 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 }869 870 {871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);872 }873 874 {875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);876 }877 878 {879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);880 }881 882 {883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);884 }885 886 {887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);888 }889 890 }891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){892 {893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);894 }895 896 {897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);898 }899 900 {901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);902 }903 904 {905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);906 }907 908 {909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);910 }911 912 {913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);914 }915 916 {917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);918 }919 920 {921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);922 }923 924 {925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);926 }927 928 {929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);930 }931 932 {933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);934 }935 936 {937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);938 }939 940 {941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);942 }943 944 {945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);946 }947 948 }949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){950 {951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);952 }953 954 {955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);956 }957 958 {959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);960 }961 962 {963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);964 }965 966 {967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);968 }969 970 {971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);972 }973 974 {975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);976 }977 978 {979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);980 }981 982 {983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);984 }985 986 {987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);988 }989 990 {991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);992 }993 994 {995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);996 }997 998 {999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1000 }1001 1002 {1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1004 }1005 1006 }1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){1008 {1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1010 }1011 1012 {1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1014 }1015 1016 {1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1018 }1019 1020 {1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1022 }1023 1024 {1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1026 }1027 1028 {1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1030 }1031 1032 {1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1034 }1035 1036 {1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1038 }1039 1040 {1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1042 }1043 1044 {1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1046 }1047 1048 {1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1050 }1051 1052 {1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1054 }1055 1056 {1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1058 }1059 1060 {1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1062 }1063 1064 }1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){1066 {1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1068 }1069 1070 {1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1072 }1073 1074 {1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1076 }1077 1078 {1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1080 }1081 1082 {1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1084 }1085 1086 {1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1088 }1089 1090 {1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1092 }1093 1094 {1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1096 }1097 1098 {1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1100 }1101 1102 {1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1104 }1105 1106 {1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1108 }1109 1110 {1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1112 }1113 1114 {1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1116 }1117 1118 {1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1120 }1121 1122 }1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){1124 {1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1126 }1127 1128 {1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1130 }1131 1132 {1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1134 }1135 1136 {1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1138 }1139 1140 {1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1142 }1143 1144 {1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1146 }1147 1148 {1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1150 }1151 1152 {1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1154 }1155 1156 {1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1158 }1159 1160 {1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1162 }1163 1164 {1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1166 }1167 1168 {1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1170 }1171 1172 {1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1174 }1175 1176 {1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);1178 617 } 1179 618 … … 1188 627 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 1189 628 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();1192 629 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 1193 630 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 1199 636 } 1200 637 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0); 638 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 639 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 640 } 641 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0); 642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){ 643 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0); 1217 644 } 1218 645 signed int _X3vtrFi___1(){ … … 1222 649 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)]; 1223 650 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)]; 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 651 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1226 652 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 1227 653 } … … 1245 671 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 1246 672 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 2)(signed int __param_0[((unsigned long int )5)]));673 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)])); 1248 674 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1249 675 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 3)(signed int (*__param_0)(signed int __param_0)));676 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0))); 1251 677 signed int _X2adFi___1(){ 1252 678 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 1350 776 1351 777 } 1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object 6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 2)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 4)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 6)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));778 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4); 779 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6); 780 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8); 781 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)()); 782 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0)); 783 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)()); 784 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0)); 1359 785 struct Vad { 1360 786 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.nast.x64.txt
r5407cdc rfeacef9 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 112 107 }; 113 108 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 123 118 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 124 119 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 131 121 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 132 122 { … … 166 156 } 167 157 168 {169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);170 }171 172 {173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);174 }175 176 {177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);178 }179 180 {181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);182 }183 184 {185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);186 }187 188 158 } 189 159 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 224 194 } 225 195 226 {227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);228 }229 230 {231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);232 }233 234 {235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);236 }237 238 {239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);240 }241 242 {243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);244 }245 246 196 } 247 197 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 {249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);250 }251 252 {253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);254 }255 256 {257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);258 }259 260 {261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);262 }263 264 {265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);266 }267 268 198 { 269 199 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 342 272 343 273 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));345 }346 347 {348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));349 }350 351 {352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));353 }354 355 {356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));357 }358 359 {360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));361 }362 363 {364 274 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 365 275 } … … 404 314 } 405 315 406 {407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);408 }409 410 {411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);412 }413 414 {415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);416 }417 418 {419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);420 }421 422 {423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);424 }425 426 316 } 427 317 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 462 352 } 463 353 464 {465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);466 }467 468 {469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);470 }471 472 {473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);474 }475 476 {477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);478 }479 480 {481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);482 }483 484 354 } 485 355 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 520 390 } 521 391 522 {523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);524 }525 526 {527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);528 }529 530 {531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);532 }533 534 {535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);536 }537 538 {539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);540 }541 542 392 } 543 393 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 578 428 } 579 429 580 {581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);582 }583 584 {585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);586 }587 588 {589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);590 }591 592 {593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);594 }595 596 {597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);598 }599 600 430 } 601 431 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 636 466 } 637 467 638 {639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);640 }641 642 {643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);644 }645 646 {647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);648 }649 650 {651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);652 }653 654 {655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);656 }657 658 468 } 659 469 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 694 504 } 695 505 696 {697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);698 }699 700 {701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);702 }703 704 {705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);706 }707 708 {709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);710 }711 712 {713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);714 }715 716 506 } 717 507 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 752 542 } 753 543 754 {755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);756 }757 758 {759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);760 }761 762 {763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);764 }765 766 {767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);768 }769 770 {771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);772 }773 774 544 } 775 545 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 810 580 } 811 581 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 834 584 { 835 585 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 866 616 { 867 617 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 }869 870 {871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);872 }873 874 {875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);876 }877 878 {879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);880 }881 882 {883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);884 }885 886 {887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);888 }889 890 }891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){892 {893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);894 }895 896 {897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);898 }899 900 {901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);902 }903 904 {905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);906 }907 908 {909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);910 }911 912 {913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);914 }915 916 {917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);918 }919 920 {921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);922 }923 924 {925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);926 }927 928 {929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);930 }931 932 {933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);934 }935 936 {937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);938 }939 940 {941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);942 }943 944 {945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);946 }947 948 }949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){950 {951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);952 }953 954 {955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);956 }957 958 {959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);960 }961 962 {963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);964 }965 966 {967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);968 }969 970 {971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);972 }973 974 {975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);976 }977 978 {979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);980 }981 982 {983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);984 }985 986 {987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);988 }989 990 {991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);992 }993 994 {995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);996 }997 998 {999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1000 }1001 1002 {1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1004 }1005 1006 }1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){1008 {1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1010 }1011 1012 {1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1014 }1015 1016 {1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1018 }1019 1020 {1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1022 }1023 1024 {1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1026 }1027 1028 {1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1030 }1031 1032 {1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1034 }1035 1036 {1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1038 }1039 1040 {1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1042 }1043 1044 {1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1046 }1047 1048 {1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1050 }1051 1052 {1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1054 }1055 1056 {1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1058 }1059 1060 {1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1062 }1063 1064 }1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){1066 {1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1068 }1069 1070 {1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1072 }1073 1074 {1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1076 }1077 1078 {1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1080 }1081 1082 {1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1084 }1085 1086 {1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1088 }1089 1090 {1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1092 }1093 1094 {1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1096 }1097 1098 {1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1100 }1101 1102 {1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1104 }1105 1106 {1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1108 }1109 1110 {1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1112 }1113 1114 {1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1116 }1117 1118 {1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1120 }1121 1122 }1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){1124 {1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1126 }1127 1128 {1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1130 }1131 1132 {1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1134 }1135 1136 {1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1138 }1139 1140 {1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1142 }1143 1144 {1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1146 }1147 1148 {1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1150 }1151 1152 {1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1154 }1155 1156 {1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1158 }1159 1160 {1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1162 }1163 1164 {1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1166 }1167 1168 {1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1170 }1171 1172 {1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1174 }1175 1176 {1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);1178 618 } 1179 619 … … 1188 628 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 1189 629 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();1192 630 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 1193 631 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 1199 637 } 1200 638 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0); 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0); 1217 645 } 1218 646 signed int _X3vtrFi___1(){ … … 1222 650 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)]; 1223 651 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)]; 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1226 653 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 1227 654 } … … 1245 672 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 1246 673 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 2)(signed int __param_0[((unsigned long int )5)]));674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)])); 1248 675 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1249 676 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 3)(signed int (*__param_0)(signed int __param_0)));677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0))); 1251 678 signed int _X2adFi___1(){ 1252 679 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 1350 777 1351 778 } 1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object 6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 2)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 4)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 6)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4); 780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6); 781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8); 782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)()); 783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0)); 784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)()); 785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0)); 1359 786 struct Vad { 1360 787 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.nast.x86.txt
r5407cdc rfeacef9 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 112 107 }; 113 108 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 123 118 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 124 119 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 131 121 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 132 122 { … … 166 156 } 167 157 168 {169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);170 }171 172 {173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);174 }175 176 {177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);178 }179 180 {181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);182 }183 184 {185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);186 }187 188 158 } 189 159 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 224 194 } 225 195 226 {227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);228 }229 230 {231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);232 }233 234 {235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);236 }237 238 {239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);240 }241 242 {243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);244 }245 246 196 } 247 197 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 {249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);250 }251 252 {253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);254 }255 256 {257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);258 }259 260 {261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);262 }263 264 {265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);266 }267 268 198 { 269 199 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 342 272 343 273 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));345 }346 347 {348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));349 }350 351 {352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));353 }354 355 {356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));357 }358 359 {360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));361 }362 363 {364 274 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 365 275 } … … 404 314 } 405 315 406 {407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);408 }409 410 {411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);412 }413 414 {415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);416 }417 418 {419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);420 }421 422 {423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);424 }425 426 316 } 427 317 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 462 352 } 463 353 464 {465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);466 }467 468 {469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);470 }471 472 {473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);474 }475 476 {477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);478 }479 480 {481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);482 }483 484 354 } 485 355 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 520 390 } 521 391 522 {523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);524 }525 526 {527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);528 }529 530 {531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);532 }533 534 {535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);536 }537 538 {539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);540 }541 542 392 } 543 393 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 578 428 } 579 429 580 {581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);582 }583 584 {585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);586 }587 588 {589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);590 }591 592 {593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);594 }595 596 {597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);598 }599 600 430 } 601 431 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 636 466 } 637 467 638 {639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);640 }641 642 {643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);644 }645 646 {647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);648 }649 650 {651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);652 }653 654 {655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);656 }657 658 468 } 659 469 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 694 504 } 695 505 696 {697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);698 }699 700 {701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);702 }703 704 {705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);706 }707 708 {709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);710 }711 712 {713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);714 }715 716 506 } 717 507 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 752 542 } 753 543 754 {755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);756 }757 758 {759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);760 }761 762 {763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);764 }765 766 {767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);768 }769 770 {771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);772 }773 774 544 } 775 545 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 810 580 } 811 581 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 834 584 { 835 585 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 866 616 { 867 617 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 }869 870 {871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);872 }873 874 {875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);876 }877 878 {879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);880 }881 882 {883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);884 }885 886 {887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);888 }889 890 }891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){892 {893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);894 }895 896 {897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);898 }899 900 {901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);902 }903 904 {905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);906 }907 908 {909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);910 }911 912 {913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);914 }915 916 {917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);918 }919 920 {921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);922 }923 924 {925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);926 }927 928 {929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);930 }931 932 {933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);934 }935 936 {937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);938 }939 940 {941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);942 }943 944 {945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);946 }947 948 }949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){950 {951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);952 }953 954 {955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);956 }957 958 {959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);960 }961 962 {963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);964 }965 966 {967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);968 }969 970 {971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);972 }973 974 {975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);976 }977 978 {979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);980 }981 982 {983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);984 }985 986 {987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);988 }989 990 {991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);992 }993 994 {995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);996 }997 998 {999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1000 }1001 1002 {1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1004 }1005 1006 }1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){1008 {1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1010 }1011 1012 {1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1014 }1015 1016 {1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1018 }1019 1020 {1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1022 }1023 1024 {1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1026 }1027 1028 {1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1030 }1031 1032 {1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1034 }1035 1036 {1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1038 }1039 1040 {1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1042 }1043 1044 {1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1046 }1047 1048 {1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1050 }1051 1052 {1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1054 }1055 1056 {1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1058 }1059 1060 {1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1062 }1063 1064 }1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){1066 {1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1068 }1069 1070 {1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1072 }1073 1074 {1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1076 }1077 1078 {1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1080 }1081 1082 {1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1084 }1085 1086 {1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1088 }1089 1090 {1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1092 }1093 1094 {1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1096 }1097 1098 {1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1100 }1101 1102 {1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1104 }1105 1106 {1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1108 }1109 1110 {1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1112 }1113 1114 {1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1116 }1117 1118 {1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1120 }1121 1122 }1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){1124 {1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1126 }1127 1128 {1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1130 }1131 1132 {1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1134 }1135 1136 {1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1138 }1139 1140 {1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1142 }1143 1144 {1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1146 }1147 1148 {1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1150 }1151 1152 {1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1154 }1155 1156 {1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1158 }1159 1160 {1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1162 }1163 1164 {1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1166 }1167 1168 {1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1170 }1171 1172 {1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1174 }1175 1176 {1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);1178 618 } 1179 619 … … 1188 628 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 1189 629 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();1192 630 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 1193 631 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 1199 637 } 1200 638 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0); 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0); 1217 645 } 1218 646 signed int _X3vtrFi___1(){ … … 1222 650 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)]; 1223 651 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)]; 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1226 653 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 1227 654 } … … 1245 672 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 1246 673 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 2)(signed int __param_0[((unsigned int )5)]));674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned int )5)])); 1248 675 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1249 676 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 3)(signed int (*__param_0)(signed int __param_0)));677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0))); 1251 678 signed int _X2adFi___1(){ 1252 679 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 1350 777 1351 778 } 1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object 6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 2)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 4)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 6)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4); 780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6); 781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8); 782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)()); 783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0)); 784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)()); 785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0)); 1359 786 struct Vad { 1360 787 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.oast.x64.txt
r5407cdc rfeacef9 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 112 107 }; 113 108 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 123 118 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 124 119 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 131 121 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 132 122 { … … 166 156 } 167 157 168 {169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);170 }171 172 {173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);174 }175 176 {177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);178 }179 180 {181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);182 }183 184 {185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);186 }187 188 158 } 189 159 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 224 194 } 225 195 226 {227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);228 }229 230 {231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);232 }233 234 {235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);236 }237 238 {239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);240 }241 242 {243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);244 }245 246 196 } 247 197 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 {249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);250 }251 252 {253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);254 }255 256 {257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);258 }259 260 {261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);262 }263 264 {265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);266 }267 268 198 { 269 199 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 342 272 343 273 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));345 }346 347 {348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));349 }350 351 {352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));353 }354 355 {356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));357 }358 359 {360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));361 }362 363 {364 274 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 365 275 } … … 404 314 } 405 315 406 {407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);408 }409 410 {411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);412 }413 414 {415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);416 }417 418 {419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);420 }421 422 {423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);424 }425 426 316 } 427 317 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 462 352 } 463 353 464 {465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);466 }467 468 {469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);470 }471 472 {473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);474 }475 476 {477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);478 }479 480 {481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);482 }483 484 354 } 485 355 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 520 390 } 521 391 522 {523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);524 }525 526 {527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);528 }529 530 {531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);532 }533 534 {535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);536 }537 538 {539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);540 }541 542 392 } 543 393 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 578 428 } 579 429 580 {581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);582 }583 584 {585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);586 }587 588 {589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);590 }591 592 {593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);594 }595 596 {597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);598 }599 600 430 } 601 431 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 636 466 } 637 467 638 {639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);640 }641 642 {643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);644 }645 646 {647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);648 }649 650 {651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);652 }653 654 {655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);656 }657 658 468 } 659 469 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 694 504 } 695 505 696 {697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);698 }699 700 {701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);702 }703 704 {705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);706 }707 708 {709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);710 }711 712 {713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);714 }715 716 506 } 717 507 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 752 542 } 753 543 754 {755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);756 }757 758 {759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);760 }761 762 {763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);764 }765 766 {767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);768 }769 770 {771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);772 }773 774 544 } 775 545 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 810 580 } 811 581 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 834 584 { 835 585 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 866 616 { 867 617 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 }869 870 {871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);872 }873 874 {875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);876 }877 878 {879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);880 }881 882 {883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);884 }885 886 {887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);888 }889 890 }891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){892 {893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);894 }895 896 {897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);898 }899 900 {901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);902 }903 904 {905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);906 }907 908 {909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);910 }911 912 {913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);914 }915 916 {917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);918 }919 920 {921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);922 }923 924 {925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);926 }927 928 {929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);930 }931 932 {933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);934 }935 936 {937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);938 }939 940 {941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);942 }943 944 {945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);946 }947 948 }949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){950 {951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);952 }953 954 {955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);956 }957 958 {959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);960 }961 962 {963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);964 }965 966 {967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);968 }969 970 {971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);972 }973 974 {975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);976 }977 978 {979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);980 }981 982 {983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);984 }985 986 {987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);988 }989 990 {991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);992 }993 994 {995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);996 }997 998 {999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1000 }1001 1002 {1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1004 }1005 1006 }1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){1008 {1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1010 }1011 1012 {1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1014 }1015 1016 {1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1018 }1019 1020 {1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1022 }1023 1024 {1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1026 }1027 1028 {1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1030 }1031 1032 {1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1034 }1035 1036 {1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1038 }1039 1040 {1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1042 }1043 1044 {1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1046 }1047 1048 {1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1050 }1051 1052 {1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1054 }1055 1056 {1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1058 }1059 1060 {1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1062 }1063 1064 }1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){1066 {1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1068 }1069 1070 {1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1072 }1073 1074 {1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1076 }1077 1078 {1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1080 }1081 1082 {1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1084 }1085 1086 {1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1088 }1089 1090 {1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1092 }1093 1094 {1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1096 }1097 1098 {1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1100 }1101 1102 {1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1104 }1105 1106 {1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1108 }1109 1110 {1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1112 }1113 1114 {1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1116 }1117 1118 {1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1120 }1121 1122 }1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){1124 {1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1126 }1127 1128 {1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1130 }1131 1132 {1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1134 }1135 1136 {1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1138 }1139 1140 {1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1142 }1143 1144 {1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1146 }1147 1148 {1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1150 }1151 1152 {1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1154 }1155 1156 {1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1158 }1159 1160 {1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1162 }1163 1164 {1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1166 }1167 1168 {1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1170 }1171 1172 {1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1174 }1175 1176 {1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);1178 618 } 1179 619 … … 1188 628 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 1189 629 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();1192 630 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 1193 631 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 1199 637 } 1200 638 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8); 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3); 1217 645 } 1218 646 signed int _X3vtrFi___1(){ … … 1222 650 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)]; 1223 651 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)]; 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1226 653 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 1227 654 } … … 1245 672 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 1246 673 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned long int )5)]));674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned long int )5)])); 1248 675 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1249 676 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13)));677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8))); 1251 678 signed int _X2adFi___1(){ 1252 679 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 1350 777 1351 778 } 1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15);1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object1 6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17);1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object1 8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19);1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)());1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25));1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 6)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)());1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 8)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31));779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10); 780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object11, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12); 781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object13, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14); 782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)()); 783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20)); 784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)()); 785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object23)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26)); 1359 786 struct Vad { 1360 787 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.oast.x86.txt
r5407cdc rfeacef9 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 112 107 }; 113 108 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 123 118 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 124 119 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 131 121 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 132 122 { … … 166 156 } 167 157 168 {169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);170 }171 172 {173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);174 }175 176 {177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);178 }179 180 {181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);182 }183 184 {185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);186 }187 188 158 } 189 159 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 224 194 } 225 195 226 {227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);228 }229 230 {231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);232 }233 234 {235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);236 }237 238 {239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);240 }241 242 {243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);244 }245 246 196 } 247 197 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 {249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);250 }251 252 {253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);254 }255 256 {257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);258 }259 260 {261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);262 }263 264 {265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);266 }267 268 198 { 269 199 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 342 272 343 273 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));345 }346 347 {348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));349 }350 351 {352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));353 }354 355 {356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));357 }358 359 {360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));361 }362 363 {364 274 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 365 275 } … … 404 314 } 405 315 406 {407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);408 }409 410 {411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);412 }413 414 {415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);416 }417 418 {419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);420 }421 422 {423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);424 }425 426 316 } 427 317 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 462 352 } 463 353 464 {465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);466 }467 468 {469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);470 }471 472 {473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);474 }475 476 {477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);478 }479 480 {481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);482 }483 484 354 } 485 355 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 520 390 } 521 391 522 {523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);524 }525 526 {527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);528 }529 530 {531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);532 }533 534 {535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);536 }537 538 {539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);540 }541 542 392 } 543 393 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 578 428 } 579 429 580 {581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);582 }583 584 {585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);586 }587 588 {589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);590 }591 592 {593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);594 }595 596 {597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);598 }599 600 430 } 601 431 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 636 466 } 637 467 638 {639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);640 }641 642 {643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);644 }645 646 {647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);648 }649 650 {651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);652 }653 654 {655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);656 }657 658 468 } 659 469 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 694 504 } 695 505 696 {697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);698 }699 700 {701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);702 }703 704 {705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);706 }707 708 {709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);710 }711 712 {713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);714 }715 716 506 } 717 507 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 752 542 } 753 543 754 {755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);756 }757 758 {759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);760 }761 762 {763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);764 }765 766 {767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);768 }769 770 {771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);772 }773 774 544 } 775 545 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 810 580 } 811 581 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 834 584 { 835 585 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 866 616 { 867 617 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 }869 870 {871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);872 }873 874 {875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);876 }877 878 {879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);880 }881 882 {883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);884 }885 886 {887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);888 }889 890 }891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){892 {893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);894 }895 896 {897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);898 }899 900 {901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);902 }903 904 {905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);906 }907 908 {909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);910 }911 912 {913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);914 }915 916 {917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);918 }919 920 {921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);922 }923 924 {925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);926 }927 928 {929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);930 }931 932 {933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);934 }935 936 {937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);938 }939 940 {941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);942 }943 944 {945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);946 }947 948 }949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){950 {951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);952 }953 954 {955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);956 }957 958 {959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);960 }961 962 {963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);964 }965 966 {967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);968 }969 970 {971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);972 }973 974 {975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);976 }977 978 {979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);980 }981 982 {983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);984 }985 986 {987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);988 }989 990 {991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);992 }993 994 {995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);996 }997 998 {999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1000 }1001 1002 {1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1004 }1005 1006 }1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){1008 {1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1010 }1011 1012 {1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1014 }1015 1016 {1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1018 }1019 1020 {1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1022 }1023 1024 {1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1026 }1027 1028 {1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1030 }1031 1032 {1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1034 }1035 1036 {1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1038 }1039 1040 {1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1042 }1043 1044 {1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1046 }1047 1048 {1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1050 }1051 1052 {1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1054 }1055 1056 {1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);1058 }1059 1060 {1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1062 }1063 1064 }1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){1066 {1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1068 }1069 1070 {1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1072 }1073 1074 {1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1076 }1077 1078 {1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1080 }1081 1082 {1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1084 }1085 1086 {1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1088 }1089 1090 {1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1092 }1093 1094 {1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1096 }1097 1098 {1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1100 }1101 1102 {1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1104 }1105 1106 {1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1108 }1109 1110 {1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1112 }1113 1114 {1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1116 }1117 1118 {1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);1120 }1121 1122 }1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){1124 {1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);1126 }1127 1128 {1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);1130 }1131 1132 {1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);1134 }1135 1136 {1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);1138 }1139 1140 {1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);1142 }1143 1144 {1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);1146 }1147 1148 {1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);1150 }1151 1152 {1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);1154 }1155 1156 {1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);1158 }1159 1160 {1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);1162 }1163 1164 {1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);1166 }1167 1168 {1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);1170 }1171 1172 {1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);1174 }1175 1176 {1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);1178 618 } 1179 619 … … 1188 628 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 1189 629 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();1192 630 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 1193 631 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 1199 637 } 1200 638 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8); 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3); 1217 645 } 1218 646 signed int _X3vtrFi___1(){ … … 1222 650 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)]; 1223 651 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)]; 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1226 653 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 1227 654 } … … 1245 672 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 1246 673 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned int )5)]));674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned int )5)])); 1248 675 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1249 676 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13)));677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8))); 1251 678 signed int _X2adFi___1(){ 1252 679 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 1350 777 1351 778 } 1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15);1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object1 6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17);1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object1 8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19);1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)());1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25));1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 6)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)());1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 8)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31));779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10); 780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object11, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12); 781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object13, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14); 782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)()); 783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20)); 784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)()); 785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object23)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26)); 1359 786 struct Vad { 1360 787 __attribute__ ((unused)) signed int :4; -
tests/.expect/declarationSpecifier.arm64.txt
r5407cdc rfeacef9 1147 1147 1148 1148 { 1149 signed int _tmp_cp_ret 6;1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);1149 signed int _tmp_cp_ret4; 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 1151 1151 } 1152 1152 -
tests/.expect/declarationSpecifier.x64.txt
r5407cdc rfeacef9 1147 1147 1148 1148 { 1149 signed int _tmp_cp_ret 6;1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);1149 signed int _tmp_cp_ret4; 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 1151 1151 } 1152 1152 -
tests/.expect/declarationSpecifier.x86.txt
r5407cdc rfeacef9 1147 1147 1148 1148 { 1149 signed int _tmp_cp_ret 6;1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);1149 signed int _tmp_cp_ret4; 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 1151 1151 } 1152 1152 -
tests/.expect/extension.arm64.txt
r5407cdc rfeacef9 457 457 458 458 { 459 signed int _tmp_cp_ret 6;460 ((void)(((void)(_tmp_cp_ret 6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 461 461 } 462 462 -
tests/.expect/extension.x64.txt
r5407cdc rfeacef9 457 457 458 458 { 459 signed int _tmp_cp_ret 6;460 ((void)(((void)(_tmp_cp_ret 6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 461 461 } 462 462 -
tests/.expect/extension.x86.txt
r5407cdc rfeacef9 457 457 458 458 { 459 signed int _tmp_cp_ret 6;460 ((void)(((void)(_tmp_cp_ret 6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));459 signed int _tmp_cp_ret4; 460 ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4)); 461 461 } 462 462 -
tests/.expect/gccExtensions.arm64.txt
r5407cdc rfeacef9 339 339 340 340 { 341 signed int _tmp_cp_ret 6;342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);341 signed int _tmp_cp_ret4; 342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 343 343 } 344 344 -
tests/.expect/gccExtensions.x64.txt
r5407cdc rfeacef9 339 339 340 340 { 341 signed int _tmp_cp_ret 6;342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);341 signed int _tmp_cp_ret4; 342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 343 343 } 344 344 -
tests/.expect/gccExtensions.x86.txt
r5407cdc rfeacef9 317 317 318 318 { 319 signed int _tmp_cp_ret 6;320 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);319 signed int _tmp_cp_ret4; 320 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); 321 321 } 322 322 -
tests/Makefile.am
r5407cdc rfeacef9 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Tue Mar 2 21:39:01 202114 ## Update Count : 9013 ## Last Modified On : Fri Oct 9 23:13:07 2020 14 ## Update Count : 86 15 15 ############################################################################### 16 16 … … 26 26 archiveerrors= 27 27 28 DEBUG_FLAGS=-debug - g -O028 DEBUG_FLAGS=-debug -O0 29 29 30 30 quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes … … 44 44 -Wall \ 45 45 -Wno-unused-function \ 46 - Wno-psabi\47 - quiet @CFA_FLAGS@46 -quiet @CFA_FLAGS@ \ 47 -DIN_DIR="${abs_srcdir}/.in/" 48 48 49 49 AM_CFAFLAGS = -XCFA --deterministic-out … … 75 75 pybin/tools.py \ 76 76 long_tests.hfa \ 77 io/.in/io.data \ 78 io/.in/many_read.data \ 77 .in/io.data \ 79 78 avltree/avl.h \ 80 79 avltree/avl-private.h \ 81 80 concurrent/clib.c \ 82 concurrent/clib_tls.c \83 81 exceptions/with-threads.hfa \ 84 82 exceptions/except-io.hfa … … 144 142 # don't use distcc to do the linking because distcc doesn't do linking 145 143 % : %.cfa $(CFACCBIN) 146 $(CFACOMPILETEST) -c -o $(abspath ${@}).o -DIN_DIR="$(abspath $(dir ${<}))/.in/"144 $(CFACOMPILETEST) -c -o $(abspath ${@}).o 147 145 $(CFACCLINK) ${@}.o -o $(abspath ${@}) 148 146 rm $(abspath ${@}).o … … 172 170 173 171 SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator forall \ 174 init1 limits nested-types stdincludes cast labelledExit array quasiKeyword include/includesbuiltins/sync warnings/self-assignment172 init1 limits nested-types stdincludes cast labelledExit array builtins/sync warnings/self-assignment 175 173 $(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN) 176 174 $(CFACOMPILE_SYNTAX) -
tests/attributes.cfa
r5407cdc rfeacef9 10 10 // Created On : Mon Feb 6 16:07:02 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 15 13:53:31 202113 // Update Count : 3812 // Last Modified On : Mon Jan 25 21:26:41 2021 13 // Update Count : 20 14 14 // 15 15 … … 42 42 __attribute__(( unused )) int f5 __attribute__(( unused )); 43 43 __attribute__(( used )) int f6 __attribute__(( packed )), f7 __attribute__(( unused )) __attribute__(( unused )), __attribute__(( used )) f8 __attribute__(( unused )); 44 int * f9 __attribute__(( unused )); 45 __attribute__(( used )) int __attribute__(( unused )) * f10; 46 int ( ( * f11 __attribute__(( unused )) ) __attribute__(( unused )) ); 47 int ( ( __attribute__(( unused )) * f12 __attribute__(( unused )) ) __attribute__(( unused )) ); 48 int ( ( __attribute__(( unused )) * (f13) __attribute__(( unused )) ) __attribute__(( unused )) ); 49 int ( ( ( __attribute__(( unused )) * (f14) ) __attribute__(( unused )) ) __attribute__(( unused )) ); 44 int ( ( * (f9) __attribute__(( unused )) ) __attribute__(( unused )) ); 50 45 }; 51 46 … … 60 55 const __attribute__(( used )) int __attribute__(( used )) vd5[5] __attribute__(( used )), __attribute__(( unused )) ((vd6)[5]) __attribute__(( used )); 61 56 const __attribute__(( used )) int __attribute__(( used )) (* __attribute__(( used )) vd7)() __attribute__(( used )), __attribute__(( unused )) ((* __attribute__(( used )) vd8)()) __attribute__(( used )); 62 const __attribute__(( used )) int __attribute__(( used )) ( __attribute__(( used )) * vd9)() __attribute__(( used )), __attribute__(( unused )) (( __attribute__(( used )) * vd10)()) __attribute__(( used )); 57 63 58 64 59 // function_declarator … … 68 63 __attribute__(( unused )) int * __attribute__(( unused )) * const __attribute__(( unused )) f2() {} 69 64 __attribute__(( unused )) int (* __attribute__(( unused )) f3(int))[] __attribute__(( used )); 70 __attribute__(( unused )) int ( __attribute__(( unused )) * __attribute__(( unused )) f4(int))[] __attribute__(( used )); 71 __attribute__(( unused )) int (* __attribute__(( unused )) f5(int p))[] {} 72 __attribute__(( unused )) int ( __attribute__(( unused )) * (f6)(int p))[] {} 73 __attribute__(( unused )) int (* __attribute__(( unused )) f7())(int) __attribute__(( used )); 74 __attribute__(( unused )) int (* __attribute__(( unused )) f8())(int) {} 75 __attribute__(( unused )) int ( __attribute__(( unused )) * f9())(int) {} 76 __attribute__(( unused )) int ( __attribute__(( unused )) * (f10)())(int) {} 65 __attribute__(( unused )) int (* __attribute__(( unused )) f3(int p))[] {} 66 __attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) __attribute__(( used )); 67 __attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) {} 77 68 78 69 … … 85 76 __attribute__(( unused )) int __attribute__(( unused )) t3[5] __attribute__(( unused )); 86 77 __attribute__(( unused )) int __attribute__(( unused )) (* (* __attribute__(( unused )) t4[5]) __attribute__(( unused )) ) __attribute__(( unused )); 87 __attribute__(( unused )) int __attribute__(( unused )) ( __attribute__(( unused )) * ( __attribute__(( unused )) * t5[5]) __attribute__(( unused )) ) __attribute__(( unused )); 88 __attribute__(( unused )) int __attribute__(( unused )) t6() __attribute__(( unused )); 78 __attribute__(( unused )) int __attribute__(( unused )) t5() __attribute__(( unused )); 89 79 __attribute__(( unused )) int __attribute__(( unused )) * __attribute__(( unused )) ((t6))() __attribute__(( unused )); 90 80 } -
tests/concurrent/clib.c
r5407cdc rfeacef9 1 #include <clib/cfathread.h> 2 1 3 #include <stdio.h> 2 4 #include <stdlib.h> 3 #include <clib/cfathread.h>4 #include <bits/defs.hfa>5 6 extern "C" {7 void _exit(int status);8 }9 5 10 6 thread_local struct drand48_data buffer = { 0 }; … … 19 15 cfathread_t volatile blocked[blocked_size]; 20 16 21 void * Worker( void *) {17 void Worker( cfathread_t this ) { 22 18 for(int i = 0; i < 1000; i++) { 23 19 int idx = myrand() % blocked_size; … … 26 22 cfathread_unpark( thrd ); 27 23 } else { 28 cfathread_t thrd = __atomic_exchange_n(&blocked[idx], cfathread_self(), __ATOMIC_SEQ_CST);24 cfathread_t thrd = __atomic_exchange_n(&blocked[idx], this, __ATOMIC_SEQ_CST); 29 25 cfathread_unpark( thrd ); 30 26 cfathread_park(); … … 32 28 } 33 29 printf("Done\n"); 34 return NULL;35 30 } 36 31 37 32 volatile bool stop; 38 void * Unparker( void *) {33 void Unparker( cfathread_t this ) { 39 34 while(!stop) { 40 35 int idx = myrand() % blocked_size; … … 47 42 } 48 43 printf("Done Unparker\n"); 49 return NULL;50 44 } 51 45 … … 57 51 } 58 52 59 cfathread_cluster_t cl = cfathread_cluster_self(); 60 61 cfathread_cluster_add_worker( cl, NULL, NULL, NULL ); 62 cfathread_cluster_add_worker( cl, NULL, NULL, NULL ); 63 cfathread_cluster_add_worker( cl, NULL, NULL, NULL ); 64 65 cfathread_attr_t attr; 66 cfathread_attr_init(&attr); 67 cfathread_attr_setcluster(&attr, cl); 68 69 cfathread_t u; 70 cfathread_create( &u, &attr, Unparker, NULL ); 53 cfathread_setproccnt( 4 ); 54 cfathread_t u = cfathread_create( Unparker ); 71 55 { 72 56 cfathread_t t[20]; 73 57 for(int i = 0; i < 20; i++) { 74 cfathread_create( &t[i], &attr, Worker, NULL);58 t[i] = cfathread_create( Worker ); 75 59 } 76 60 for(int i = 0; i < 20; i++) { 77 cfathread_join( t[i] , NULL);61 cfathread_join( t[i] ); 78 62 } 79 63 } 80 64 stop = true; 81 cfathread_join(u, NULL); 82 cfathread_attr_destroy(&attr); 83 fflush(stdout); 84 _exit(0); 65 cfathread_join(u); 66 cfathread_setproccnt( 1 ); 85 67 } -
tests/concurrent/coroutineYield.cfa
r5407cdc rfeacef9 38 38 39 39 40 Coroutine c;41 40 int main(int argc, char* argv[]) { 41 Coroutine c; 42 42 for(int i = 0; TEST(i < N); i++) { 43 43 #if !defined(TEST_FOREVER) -
tests/concurrent/futures/multi.cfa
r5407cdc rfeacef9 5 5 6 6 thread Server { 7 int pending, done, iteration;7 int cnt, iteration; 8 8 multi_future(int) * request; 9 9 }; 10 10 11 11 void ?{}( Server & this ) { 12 ((thread&)this){"Server Thread"}; 13 this.pending = 0; 14 this.done = 0; 12 this.cnt = 0; 15 13 this.iteration = 0; 16 14 this.request = 0p; … … 18 16 19 17 void ^?{}( Server & mutex this ) { 20 assert(this. pending== 0);21 this.request = 0p;18 assert(this.cnt == 0); 19 this.request = 0p; 22 20 } 23 21 … … 26 24 } 27 25 28 void call( Server & mutex this ) { 29 this.pending++; 26 void process( Server & mutex this ) { 27 fulfil( *this.request, this.iteration ); 28 this.iteration++; 30 29 } 31 30 32 void finish( Server & mutex this ) {33 this. done++;31 void call( Server & mutex this ) { 32 this.cnt++; 34 33 } 35 34 35 void finish( Server & mutex this ) { } 36 36 37 void main( Server & this ) { 37 MAIN_LOOP:38 38 for() { 39 39 waitfor( ^?{} : this ) { 40 40 break; 41 41 } 42 or waitfor( call: this ) { 43 if (this.pending != NFUTURES) { continue MAIN_LOOP; } 44 45 this.pending = 0; 46 fulfil( *this.request, this.iteration ); 47 this.iteration++; 48 49 for(NFUTURES) { 50 waitfor( finish: this ); 42 or when( this.cnt < NFUTURES ) waitfor( call: this ) { 43 if (this.cnt == NFUTURES) { 44 process(this); 51 45 } 52 53 reset( *this.request ); 54 this.done = 0; 46 } 47 or waitfor( finish: this ) { 48 if (this.cnt == NFUTURES) { 49 reset( *this.request ); 50 this.cnt = 0; 51 } 55 52 } 56 53 } … … 60 57 Server * the_server; 61 58 thread Worker {}; 62 void ?{}(Worker & this) {63 ((thread&)this){"Worker Thread"};64 }65 66 59 multi_future(int) * shared_future; 67 60 -
tests/errors/.expect/completeType.nast.arm64.txt
r5407cdc rfeacef9 12 12 Application of 13 13 Variable Expression: *?: forall 14 instance of type DT (not function type)14 DT: data type 15 15 function 16 16 ... with parameters … … 21 21 ... with resolved type: 22 22 pointer to forall 23 instance of type [unbound] (not function type) 23 [unbound]:data type 24 function 25 ... with parameters 26 pointer to instance of type [unbound] (not function type) 27 ... returning 28 reference to instance of type [unbound] (not function type) 29 30 ... to arguments 31 Variable Expression: x: pointer to instance of struct B with body 32 ... with resolved type: 33 pointer to instance of struct B with body 34 35 ... with resolved type: 36 reference to instance of struct B with body 37 ... to: nothing 38 ... with resolved type: 39 void 40 (types: 41 void 42 ) 43 Environment:([unbound]) -> instance of struct B with body (no widening) 44 45 46 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 47 Application of 48 Variable Expression: *?: forall 49 DT: data type 50 function 51 ... with parameters 52 pointer to instance of type DT (not function type) 53 ... returning 54 reference to instance of type DT (not function type) 55 56 ... with resolved type: 57 pointer to forall 58 [unbound]:data type 24 59 function 25 60 ... with parameters … … 41 76 void 42 77 ) 43 Environment:([unbound]DT) -> instance of struct A without body (no widening) 44 45 46 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 47 Application of 48 Variable Expression: *?: forall 49 instance of type DT (not function type) 50 function 51 ... with parameters 52 pointer to instance of type DT (not function type) 53 ... returning 54 reference to instance of type DT (not function type) 55 56 ... with resolved type: 57 pointer to forall 58 instance of type [unbound] (not function type) 59 function 60 ... with parameters 61 pointer to instance of type [unbound] (not function type) 62 ... returning 63 reference to instance of type [unbound] (not function type) 64 65 ... to arguments 66 Variable Expression: x: pointer to instance of struct B with body 67 ... with resolved type: 68 pointer to instance of struct B with body 69 70 ... with resolved type: 71 reference to instance of struct B with body 72 ... to: nothing 73 ... with resolved type: 74 void 75 (types: 76 void 77 ) 78 Environment:([unbound]DT) -> instance of struct B with body (no widening) 78 Environment:([unbound]) -> instance of struct A without body (no widening) 79 79 80 80 … … 113 113 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of 114 114 Variable Expression: baz: forall 115 instance of type T (not function type) 116 with assertions 117 Variable Expression: ?=?: pointer to function 118 ... with parameters 119 reference to instance of type T (not function type) 120 instance of type T (not function type) 121 ... returning 122 instance of type T (not function type) 123 124 ... with resolved type: 125 pointer to function 115 T: sized data type 116 ... with assertions 117 ?=?: pointer to function 126 118 ... with parameters 127 119 reference to instance of type T (not function type) … … 130 122 instance of type T (not function type) 131 123 132 Variable Expression: ?{}: pointer to function 133 ... with parameters 134 reference to instance of type T (not function type) 135 ... returning nothing 136 137 ... with resolved type: 138 pointer to function 124 ?{}: pointer to function 139 125 ... with parameters 140 126 reference to instance of type T (not function type) 141 127 ... returning nothing 142 128 143 Variable Expression: ?{}: pointer to function 144 ... with parameters 145 reference to instance of type T (not function type) 146 instance of type T (not function type) 147 ... returning nothing 148 149 ... with resolved type: 150 pointer to function 129 ?{}: pointer to function 151 130 ... with parameters 152 131 reference to instance of type T (not function type) … … 154 133 ... returning nothing 155 134 156 Variable Expression: ^?{}: pointer to function 157 ... with parameters 158 reference to instance of type T (not function type) 159 ... returning nothing 160 161 ... with resolved type: 162 pointer to function 135 ^?{}: pointer to function 163 136 ... with parameters 164 137 reference to instance of type T (not function type) 165 138 ... returning nothing 139 166 140 167 141 function … … 172 146 ... with resolved type: 173 147 pointer to forall 174 instance of type [unbound] (not function type) 175 with assertions 176 Variable Expression: ?=?: pointer to function 177 ... with parameters 178 reference to instance of type T (not function type) 179 instance of type T (not function type) 180 ... returning 181 instance of type T (not function type) 182 183 ... with resolved type: 184 pointer to function 148 [unbound]:sized data type 149 ... with assertions 150 ?=?: pointer to function 185 151 ... with parameters 186 152 reference to instance of type [unbound] (not function type) … … 189 155 instance of type [unbound] (not function type) 190 156 191 Variable Expression: ?{}: pointer to function 192 ... with parameters 193 reference to instance of type T (not function type) 194 ... returning nothing 195 196 ... with resolved type: 197 pointer to function 157 ?{}: pointer to function 198 158 ... with parameters 199 159 reference to instance of type [unbound] (not function type) 200 160 ... returning nothing 201 161 202 Variable Expression: ?{}: pointer to function 203 ... with parameters 204 reference to instance of type T (not function type) 205 instance of type T (not function type) 206 ... returning nothing 207 208 ... with resolved type: 209 pointer to function 162 ?{}: pointer to function 210 163 ... with parameters 211 164 reference to instance of type [unbound] (not function type) … … 213 166 ... returning nothing 214 167 215 Variable Expression: ^?{}: pointer to function 216 ... with parameters 217 reference to instance of type T (not function type) 218 ... returning nothing 219 220 ... with resolved type: 221 pointer to function 168 ^?{}: pointer to function 222 169 ... with parameters 223 170 reference to instance of type [unbound] (not function type) 224 171 ... returning nothing 172 225 173 226 174 function … … 240 188 void 241 189 ) 242 Environment:([unbound] T) -> instance of type T (not function type) (no widening)190 Environment:([unbound]) -> instance of type T (not function type) (no widening) 243 191 244 192 Could not satisfy assertion: 245 Variable Expression:?=?: pointer to function193 ?=?: pointer to function 246 194 ... with parameters 247 reference to instance of type T(not function type)248 instance of type T(not function type)195 reference to instance of type [unbound] (not function type) 196 instance of type [unbound] (not function type) 249 197 ... returning 250 instance of type T(not function type)198 instance of type [unbound] (not function type) 251 199 252 ... with resolved type:253 pointer to function254 ... with parameters255 reference to instance of type [unbound] (not function type)256 instance of type [unbound] (not function type)257 ... returning258 instance of type [unbound] (not function type)259 -
tests/exceptions/.expect/resume-threads.txt
r5407cdc rfeacef9 6 6 7 7 catch-all 8 9 throwing child exception 10 inner parent match 8 11 9 12 caught yin as yin -
tests/exceptions/.expect/resume.txt
r5407cdc rfeacef9 6 6 7 7 catch-all 8 9 throwing child exception 10 inner parent match 8 11 9 12 caught yin as yin -
tests/exceptions/.expect/terminate-threads.txt
r5407cdc rfeacef9 5 5 6 6 catch-all 7 8 throwing child exception 9 inner parent match 7 10 8 11 caught yin as yin -
tests/exceptions/.expect/terminate.txt
r5407cdc rfeacef9 5 5 6 6 catch-all 7 8 throwing child exception 9 inner parent match 7 10 8 11 caught yin as yin -
tests/exceptions/cancel/coroutine.cfa
r5407cdc rfeacef9 4 4 #include <exception.hfa> 5 5 6 EHM_EXCEPTION(internal_error)(); 7 EHM_VIRTUAL_TABLE(internal_error, internal_vt); 6 TRIVIAL_EXCEPTION(internal_error); 8 7 9 8 coroutine WillCancel {}; … … 15 14 void main(WillCancel & wc) { 16 15 printf("1"); 17 cancel_stack((internal_error){ &internal_vt});16 cancel_stack((internal_error){}); 18 17 printf("!"); 19 18 } -
tests/exceptions/cancel/thread.cfa
r5407cdc rfeacef9 4 4 #include <exception.hfa> 5 5 6 EHM_EXCEPTION(internal_error)(); 7 EHM_VIRTUAL_TABLE(internal_error, internal_vt); 6 TRIVIAL_EXCEPTION(internal_error); 8 7 9 8 thread WillCancel {}; … … 15 14 void main(WillCancel &) { 16 15 printf("1"); 17 cancel_stack((internal_error){ &internal_vt});16 cancel_stack((internal_error){}); 18 17 printf("!"); 19 18 } -
tests/exceptions/conditional.cfa
r5407cdc rfeacef9 6 6 #include <exception.hfa> 7 7 8 EHM_EXCEPTION(num_error)(9 int num;8 VTABLE_DECLARATION(num_error)( 9 int (*code)(num_error *this); 10 10 ); 11 11 12 EHM_VIRTUAL_TABLE(num_error, num_error_vt); 12 struct num_error { 13 VTABLE_FIELD(num_error); 14 char * msg; 15 int num; 16 }; 17 18 const char * num_error_msg(num_error * this) { 19 if ( ! this->msg ) { 20 static const char * base = "Num Error with code: X"; 21 this->msg = (char *)malloc(22); 22 for (int i = 0 ; (this->msg[i] = base[i]) ; ++i); 23 } 24 this->msg[21] = '0' + this->num; 25 return this->msg; 26 } 27 void ?{}(num_error & this, int num) { 28 VTABLE_INIT(this, num_error); 29 this.msg = 0; 30 this.num = num; 31 } 32 void ?{}(num_error & this, num_error & other) { 33 this.virtual_table = other.virtual_table; 34 this.msg = 0; 35 this.num = other.num; 36 } 37 void ^?{}(num_error & this) { 38 if( this.msg ) free( this.msg ); 39 } 40 int num_error_code( num_error * this ) { 41 return this->num; 42 } 43 44 VTABLE_INSTANCE(num_error)( 45 num_error_msg, 46 num_error_code, 47 ); 13 48 14 49 void caught_num_error(int expect, num_error * actual) { … … 17 52 18 53 int main(int argc, char * argv[]) { 19 num_error exc = {&num_error_vt, 2};54 num_error exc = 2; 20 55 21 56 try { 22 57 throw exc; 23 } catch (num_error * error ; 3 == error-> num) {58 } catch (num_error * error ; 3 == error->virtual_table->code( error )) { 24 59 caught_num_error(3, error); 25 } catch (num_error * error ; 2 == error-> num) {60 } catch (num_error * error ; 2 == error->virtual_table->code( error )) { 26 61 caught_num_error(2, error); 27 62 } … … 29 64 try { 30 65 throwResume exc; 31 } catchResume (num_error * error ; 3 == error-> num) {66 } catchResume (num_error * error ; 3 == error->virtual_table->code( error )) { 32 67 caught_num_error(3, error); 33 } catchResume (num_error * error ; 2 == error-> num) {68 } catchResume (num_error * error ; 2 == error->virtual_table->code( error )) { 34 69 caught_num_error(2, error); 35 70 } -
tests/exceptions/data-except.cfa
r5407cdc rfeacef9 3 3 #include <exception.hfa> 4 4 5 EHM_EXCEPTION(paired)(5 DATA_EXCEPTION(paired)( 6 6 int first; 7 7 int second; 8 8 ); 9 9 10 EHM_VIRTUAL_TABLE(paired, paired_vt); 10 void ?{}(paired & this, int first, int second) { 11 VTABLE_INIT(this, paired); 12 this.first = first; 13 this.second = second; 14 } 11 15 12 const char * virtual_msg(paired * this) { 13 return this->virtual_table->msg(this); 16 const char * paired_msg(paired * this) { 17 return "paired"; 18 } 19 20 VTABLE_INSTANCE(paired)(paired_msg); 21 22 void throwPaired(int first, int second) { 23 paired exc = {first, second}; 14 24 } 15 25 16 26 int main(int argc, char * argv[]) { 17 paired except = { &paired_vt,3, 13};27 paired except = {3, 13}; 18 28 19 29 try { 20 30 throw except; 21 31 } catch (paired * exc) { 22 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);32 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second); 23 33 ++exc->first; 24 34 } 25 35 26 printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);36 printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second); 27 37 28 38 try { 29 39 throwResume except; 30 40 } catchResume (paired * exc) { 31 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);41 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second); 32 42 ++exc->first; 33 43 } 34 44 35 printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);45 printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second); 36 46 } -
tests/exceptions/defaults.cfa
r5407cdc rfeacef9 4 4 #include <exception.hfa> 5 5 6 EHM_EXCEPTION(log_message)(6 DATA_EXCEPTION(log_message)( 7 7 char * msg; 8 8 ); 9 9 10 _EHM_DEFINE_COPY(log_message, ) 11 const char * msg(log_message * this) { 10 void ?{}(log_message & this, char * msg) { 11 VTABLE_INIT(this, log_message); 12 this.msg = msg; 13 } 14 15 const char * get_log_message(log_message * this) { 12 16 return this->msg; 13 17 } 14 _EHM_VIRTUAL_TABLE(log_message, , log_vt); 18 19 VTABLE_INSTANCE(log_message)(get_log_message); 15 20 16 21 // Logging messages don't have to be handled. … … 23 28 // We can catch log: 24 29 try { 25 throwResume (log_message){ &log_vt,"Should be printed.\n"};30 throwResume (log_message){"Should be printed.\n"}; 26 31 } catchResume (log_message * this) { 27 32 printf("%s", this->virtual_table->msg(this)); 28 33 } 29 34 // But we don't have to: 30 throwResume (log_message){ &log_vt,"Should not be printed.\n"};35 throwResume (log_message){"Should not be printed.\n"}; 31 36 } 32 37 33 38 // I don't have a good use case for doing the same with termination. 34 EHM_EXCEPTION(jump)();39 TRIVIAL_EXCEPTION(jump); 35 40 void defaultTerminationHandler(jump &) { 36 41 printf("jump default handler.\n"); 37 42 } 38 43 39 EHM_VIRTUAL_TABLE(jump, jump_vt);40 41 44 void jump_test(void) { 42 45 try { 43 throw (jump){ &jump_vt};46 throw (jump){}; 44 47 } catch (jump * this) { 45 48 printf("jump catch handler.\n"); 46 49 } 47 throw (jump){ &jump_vt};50 throw (jump){}; 48 51 } 49 52 50 EHM_EXCEPTION(first)(); 51 EHM_VIRTUAL_TABLE(first, first_vt); 52 53 EHM_EXCEPTION(unhandled_exception)(); 54 EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt); 53 TRIVIAL_EXCEPTION(first); 54 TRIVIAL_EXCEPTION(unhandled_exception); 55 55 56 56 void unhandled_test(void) { 57 57 forall(T &, V & | is_exception(T, V)) 58 58 void defaultTerminationHandler(T &) { 59 throw (unhandled_exception){ &unhandled_vt};59 throw (unhandled_exception){}; 60 60 } 61 61 void defaultTerminationHandler(unhandled_exception &) { … … 63 63 } 64 64 try { 65 throw (first){ &first_vt};65 throw (first){}; 66 66 } catch (unhandled_exception * t) { 67 67 printf("Catch unhandled_exception.\n"); … … 69 69 } 70 70 71 EHM_EXCEPTION(second)(); 72 EHM_VIRTUAL_TABLE(second, second_vt); 71 TRIVIAL_EXCEPTION(second); 73 72 74 73 void cross_test(void) { 75 74 void defaultTerminationHandler(first &) { 76 75 printf("cross terminate default\n"); 77 throw (second){ &second_vt};76 throw (second){}; 78 77 } 79 78 void defaultResumptionHandler(first &) { 80 79 printf("cross resume default\n"); 81 throwResume (second){ &second_vt};80 throwResume (second){}; 82 81 } 83 82 try { 84 83 printf("cross terminate throw\n"); 85 throw (first){ &first_vt};84 throw (first){}; 86 85 } catch (second *) { 87 86 printf("cross terminate catch\n"); … … 89 88 try { 90 89 printf("cross resume throw\n"); 91 throwResume (first){ &first_vt};90 throwResume (first){}; 92 91 } catchResume (second *) { 93 92 printf("cross resume catch\n"); -
tests/exceptions/finally.cfa
r5407cdc rfeacef9 4 4 #include "except-io.hfa" 5 5 6 EHM_EXCEPTION(myth)(); 7 8 EHM_VIRTUAL_TABLE(myth, myth_vt); 6 TRIVIAL_EXCEPTION(myth); 9 7 10 8 int main(int argc, char * argv[]) { 11 myth exc = {&myth_vt};9 myth exc; 12 10 13 11 try { -
tests/exceptions/interact.cfa
r5407cdc rfeacef9 4 4 #include "except-io.hfa" 5 5 6 EHM_EXCEPTION(star)(); 7 EHM_EXCEPTION(moon)(); 8 9 EHM_VIRTUAL_TABLE(star, star_vt); 10 EHM_VIRTUAL_TABLE(moon, moon_vt); 6 TRIVIAL_EXCEPTION(star); 7 TRIVIAL_EXCEPTION(moon); 11 8 12 9 int main(int argc, char * argv[]) { 13 10 // Resume falls back to terminate. 14 11 try { 15 throwResume (star){ &star_vt};12 throwResume (star){}; 16 13 } catch (star *) { 17 14 printf("caught as termination\n"); … … 20 17 try { 21 18 loud_region a = "try block with resume throw"; 22 throwResume (star){ &star_vt};19 throwResume (star){}; 23 20 } catch (star *) { 24 21 printf("caught as termination\n"); … … 32 29 try { 33 30 try { 34 throw (star){ &star_vt};31 throw (star){}; 35 32 } catchResume (star *) { 36 33 printf("resume catch on terminate\n"); … … 46 43 try { 47 44 try { 48 throwResume (star){ &star_vt};45 throwResume (star){}; 49 46 } catch (star *) { 50 47 printf("terminate catch on resume\n"); … … 61 58 try { 62 59 try { 63 throw (star){ &star_vt};60 throw (star){}; 64 61 } catchResume (star *) { 65 62 printf("inner resume catch (error)\n"); … … 78 75 try { 79 76 try { 80 throwResume (star){ &star_vt};77 throwResume (star){}; 81 78 } catch (star *) { 82 79 printf("inner termination catch\n"); … … 97 94 try { 98 95 printf("throwing resume moon\n"); 99 throwResume (moon){ &moon_vt};96 throwResume (moon){}; 100 97 } catch (star *) { 101 98 printf("termination catch\n"); 102 99 } 103 100 printf("throwing resume star\n"); 104 throwResume (star){ &star_vt};101 throwResume (star){}; 105 102 } catchResume (star *) { 106 103 printf("resumption star catch\n"); … … 108 105 } catchResume (moon *) { 109 106 printf("resumption moon catch, will terminate\n"); 110 throw (star){ &star_vt};107 throw (star){}; 111 108 } 112 109 } catchResume (star *) { -
tests/exceptions/polymorphic.cfa
r5407cdc rfeacef9 3 3 #include <exception.hfa> 4 4 5 EHM_FORALL_EXCEPTION(proxy, (T&), (T))(); 5 FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T)); 6 FORALL_TRIVIAL_INSTANCE(proxy, (U), (U)) 6 7 7 EHM_FORALL_VIRTUAL_TABLE(proxy, (int), proxy_int); 8 EHM_FORALL_VIRTUAL_TABLE(proxy, (char), proxy_char); 8 const char * msg(proxy(int) * this) { return "proxy(int)"; } 9 const char * msg(proxy(char) * this) { return "proxy(char)"; } 10 POLY_VTABLE_INSTANCE(proxy, int)(msg); 11 POLY_VTABLE_INSTANCE(proxy, char)(msg); 9 12 10 13 void proxy_test(void) { 11 proxy(int) an_int = {&proxy_int};12 proxy(char) a_char = {&proxy_char};13 14 14 try { 15 throw an_int;15 throw (proxy(int)){}; 16 16 } catch (proxy(int) *) { 17 17 printf("terminate catch\n"); … … 19 19 20 20 try { 21 throwResume a_char;21 throwResume (proxy(char)){}; 22 22 } catchResume (proxy(char) *) { 23 23 printf("resume catch\n"); … … 25 25 26 26 try { 27 throw a_char;27 throw (proxy(char)){}; 28 28 } catch (proxy(int) *) { 29 29 printf("caught proxy(int)\n"); … … 33 33 } 34 34 35 EHM_FORALL_EXCEPTION(cell, (T), (T))(35 FORALL_DATA_EXCEPTION(cell, (T), (T))( 36 36 T data; 37 37 ); 38 38 39 EHM_FORALL_VIRTUAL_TABLE(cell, (int), int_cell); 40 EHM_FORALL_VIRTUAL_TABLE(cell, (char), char_cell); 41 EHM_FORALL_VIRTUAL_TABLE(cell, (bool), bool_cell); 39 FORALL_DATA_INSTANCE(cell, (T), (T)) 40 41 const char * msg(cell(int) * this) { return "cell(int)"; } 42 const char * msg(cell(char) * this) { return "cell(char)"; } 43 const char * msg(cell(bool) * this) { return "cell(bool)"; } 44 POLY_VTABLE_INSTANCE(cell, int)(msg); 45 POLY_VTABLE_INSTANCE(cell, char)(msg); 46 POLY_VTABLE_INSTANCE(cell, bool)(msg); 42 47 43 48 void cell_test(void) { 44 49 try { 45 cell(int) except = {&int_cell, -7}; 50 cell(int) except; 51 except.data = -7; 46 52 throw except; 47 53 } catch (cell(int) * error) { … … 50 56 51 57 try { 52 cell(bool) ball = {&bool_cell, false}; 58 cell(bool) ball; 59 ball.data = false; 53 60 throwResume ball; 54 61 printf("%i\n", ball.data); -
tests/exceptions/resume.cfa
r5407cdc rfeacef9 4 4 #include "except-io.hfa" 5 5 6 EHM_EXCEPTION(yin)(); 7 EHM_EXCEPTION(yang)(); 8 EHM_EXCEPTION(zen)(); 9 10 EHM_VIRTUAL_TABLE(yin, yin_vt); 11 EHM_VIRTUAL_TABLE(yang, yang_vt); 12 EHM_VIRTUAL_TABLE(zen, zen_vt); 6 TRIVIAL_EXCEPTION(yin); 7 TRIVIAL_EXCEPTION(yang); 8 TRIVIAL_EXCEPTION(zen); 9 TRIVIAL_EXCEPTION(moment_of, zen); 13 10 14 11 void in_void(void); 15 12 16 13 int main(int argc, char * argv[]) { 17 yin a_yin = {&yin_vt};18 yang a_yang = {&yang_vt};19 zen a_zen = {&zen_vt};20 21 14 // The simple throw catchResume test. 22 15 try { 23 16 loud_exit a = "simple try clause"; 24 17 printf("simple throw\n"); 25 throwResume a_zen;18 throwResume (zen){}; 26 19 printf("end of try clause\n"); 27 20 } catchResume (zen * error) { … … 33 26 // Throw catch-all test. 34 27 try { 35 throwResume a_zen;28 throwResume (zen){}; 36 29 } catchResume (exception_t * error) { 37 30 printf("catch-all\n"); 31 } 32 printf("\n"); 33 34 // Catch a parent of the given exception. 35 try { 36 printf("throwing child exception\n"); 37 throwResume (moment_of){}; 38 } catchResume (zen *) { 39 printf("inner parent match\n"); 40 } catchResume (moment_of *) { 41 printf("outer exact match\n"); 38 42 } 39 43 printf("\n"); … … 42 46 try { 43 47 try { 44 throwResume a_yin;48 throwResume (yin){}; 45 49 } catchResume (zen *) { 46 50 printf("caught yin as zen\n"); … … 58 62 loud_exit a = "rethrow inner try"; 59 63 printf("rethrow inner try\n"); 60 throwResume a_zen;64 throwResume (zen){}; 61 65 } catchResume (zen *) { 62 66 loud_exit a = "rethrowing catch clause"; … … 73 77 try { 74 78 try { 75 throwResume a_yin;79 throwResume (yin){}; 76 80 } catchResume (yin *) { 77 81 printf("caught yin, will throw yang\n"); 78 throwResume a_yang;82 throwResume (yang){}; 79 83 } catchResume (yang *) { 80 84 printf("caught exception from same try\n"); … … 89 93 try { 90 94 printf("throwing first exception\n"); 91 throwResume a_yin;95 throwResume (yin){}; 92 96 } catchResume (yin *) { 93 97 printf("caught first exception\n"); 94 98 try { 95 99 printf("throwing second exception\n"); 96 throwResume a_yang;100 throwResume (yang){}; 97 101 } catchResume (yang *) { 98 102 printf("caught second exception\n"); … … 110 114 try { 111 115 try { 112 throwResume a_zen;113 throwResume a_zen;116 throwResume (zen){}; 117 throwResume (zen){}; 114 118 } catchResume (zen *) { 115 119 printf("inner catch\n"); 116 120 } 117 throwResume a_zen;121 throwResume (zen){}; 118 122 } catchResume (zen *) { 119 123 printf("outer catch\n"); … … 126 130 // Do a throw and rethrow in a void function. 127 131 void in_void(void) { 128 zen a_zen = {&zen_vt};129 132 try { 130 133 try { 131 134 printf("throw\n"); 132 throwResume a_zen;135 throwResume (zen){}; 133 136 } catchResume (zen *) { 134 137 printf("rethrow\n"); -
tests/exceptions/terminate.cfa
r5407cdc rfeacef9 4 4 #include "except-io.hfa" 5 5 6 EHM_EXCEPTION(yin)(); 7 EHM_EXCEPTION(yang)(); 8 EHM_EXCEPTION(zen)(); 9 10 EHM_VIRTUAL_TABLE(yin, yin_vt); 11 EHM_VIRTUAL_TABLE(yang, yang_vt); 12 EHM_VIRTUAL_TABLE(zen, zen_vt); 6 TRIVIAL_EXCEPTION(yin); 7 TRIVIAL_EXCEPTION(yang); 8 TRIVIAL_EXCEPTION(zen); 9 TRIVIAL_EXCEPTION(moment_of, zen); 13 10 14 11 void in_void(void); 15 12 16 13 int main(int argc, char * argv[]) { 17 yin a_yin = {&yin_vt};18 yang a_yang = {&yang_vt};19 zen a_zen = {&zen_vt};20 21 14 // The simple throw catch test. 22 15 try { 23 16 loud_exit a = "simple try clause"; 24 17 printf("simple throw\n"); 25 throw a_zen;18 throw (zen){}; 26 19 printf("end of try clause\n"); 27 20 } catch (zen * error) { … … 33 26 // Throw catch-all test. 34 27 try { 35 throw a_zen;28 throw (zen){}; 36 29 } catch (exception_t * error) { 37 30 printf("catch-all\n"); 31 } 32 printf("\n"); 33 34 // Catch a parent of the given exception. 35 try { 36 printf("throwing child exception\n"); 37 throw (moment_of){}; 38 } catch (zen *) { 39 printf("inner parent match\n"); 40 } catch (moment_of *) { 41 printf("outer exact match\n"); 38 42 } 39 43 printf("\n"); … … 42 46 try { 43 47 try { 44 throw a_yin;48 throw (yin){}; 45 49 } catch (zen *) { 46 50 printf("caught yin as zen\n"); … … 58 62 loud_exit a = "rethrow inner try"; 59 63 printf("rethrow inner try\n"); 60 throw a_zen;64 throw (zen){}; 61 65 } catch (zen *) { 62 66 loud_exit a = "rethrowing catch clause"; … … 73 77 try { 74 78 try { 75 throw a_yin;79 throw (yin){}; 76 80 } catch (yin *) { 77 81 printf("caught yin, will throw yang\n"); 78 throw a_yang;82 throw (yang){}; 79 83 } catch (yang *) { 80 84 printf("caught exception from same try\n"); … … 89 93 try { 90 94 printf("throwing first exception\n"); 91 throw a_yin;95 throw (yin){}; 92 96 } catch (yin *) { 93 97 printf("caught first exception\n"); 94 98 try { 95 99 printf("throwing second exception\n"); 96 throw a_yang;100 throw (yang){}; 97 101 } catch (yang *) { 98 102 printf("caught second exception\n"); … … 110 114 try { 111 115 try { 112 throw a_zen;113 throw a_zen;116 throw (zen){}; 117 throw (zen){}; 114 118 } catch (zen *) { 115 119 printf("inner catch\n"); 116 120 } 117 throw a_zen;121 throw (zen){}; 118 122 } catch (zen *) { 119 123 printf("outer catch\n"); … … 126 130 // Do a throw and rethrow in a void function. 127 131 void in_void(void) { 128 zen a_zen = {&zen_vt};129 132 try { 130 133 try { 131 134 printf("throw\n"); 132 throw a_zen;135 throw (zen){}; 133 136 } catch (zen *) { 134 137 printf("rethrow\n"); -
tests/exceptions/trash.cfa
r5407cdc rfeacef9 3 3 #include <exception.hfa> 4 4 5 EHM_EXCEPTION(yin)(); 6 EHM_EXCEPTION(yang)(); 7 8 EHM_VIRTUAL_TABLE(yin, yin_vt); 9 EHM_VIRTUAL_TABLE(yang, yang_vt); 5 TRIVIAL_EXCEPTION(yin); 6 TRIVIAL_EXCEPTION(yang); 10 7 11 8 int main(int argc, char * argv[]) { 12 9 try { 13 10 try { 14 throw (yin){ &yin_vt};11 throw (yin){}; 15 12 } finally { 16 13 try { 17 throw (yang){ &yang_vt};14 throw (yang){}; 18 15 } catch (yin *) { 19 16 printf("inner yin\n"); -
tests/exceptions/type-check.cfa
r5407cdc rfeacef9 3 3 #include <exception.hfa> 4 4 5 EHM_EXCEPTION(truth)();5 TRIVIAL_EXCEPTION(truth); 6 6 7 7 int main(int argc, char * argv[]) { -
tests/exceptions/virtual-cast.cfa
r5407cdc rfeacef9 12 12 #include <assert.h> 13 13 14 15 16 // Hand defined alpha virtual type:17 struct __cfatid_struct_alpha {18 __cfa__parent_vtable const * parent;19 };20 21 __attribute__(( section(".gnu.linkonce.__cfatid_alpha") ))22 struct __cfatid_struct_alpha __cfatid_alpha = {23 (__cfa__parent_vtable *)0,24 };25 26 14 struct alpha_vtable { 27 struct __cfatid_struct_alpha const * const __cfavir_typeid;15 alpha_vtable const * const parent; 28 16 char (*code)(void); 29 17 }; … … 39 27 40 28 41 // Hand defined beta virtual type:42 struct __cfatid_struct_beta {43 __cfatid_struct_alpha const * parent;44 };45 46 __attribute__(( section(".gnu.linkonce.__cfatid_beta") ))47 struct __cfatid_struct_beta __cfatid_beta = {48 &__cfatid_alpha,49 };50 51 29 struct beta_vtable { 52 struct __cfatid_struct_beta const * const __cfavir_typeid;30 alpha_vtable const * const parent; 53 31 char (*code)(void); 54 32 }; … … 64 42 65 43 66 // Hand defined gamma virtual type:67 struct __cfatid_struct_gamma {68 __cfatid_struct_beta const * parent;69 };70 71 __attribute__(( section(".gnu.linkonce.__cfatid_gamma") ))72 struct __cfatid_struct_gamma __cfatid_gamma = {73 &__cfatid_beta,74 };75 76 44 struct gamma_vtable { 77 struct __cfatid_struct_gamma const * const __cfavir_typeid;45 beta_vtable const * const parent; 78 46 char (*code)(void); 79 47 }; … … 89 57 90 58 extern "C" { 91 alpha_vtable _alpha_vtable_instance = { &__cfatid_alpha, ret_a };92 beta_vtable _beta_vtable_instance = { &_ _cfatid_beta, ret_b };93 gamma_vtable _gamma_vtable_instance = { &_ _cfatid_gamma, ret_g };59 alpha_vtable _alpha_vtable_instance = { 0, ret_a }; 60 beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b }; 61 gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g }; 94 62 } 95 63 -
tests/exceptions/virtual-poly.cfa
r5407cdc rfeacef9 8 8 #include <assert.h> 9 9 10 11 struct __cfatid_struct_mono_base {12 __cfa__parent_vtable const * parent;13 };14 15 __attribute__(( section(".gnu.linkonce.__cfatid_mono_base") ))16 struct __cfatid_struct_mono_base __cfatid_mono_base = {17 (__cfa__parent_vtable *)0,18 };19 20 10 struct mono_base_vtable { 21 __cfatid_struct_mono_base const * const __cfavir_typeid;11 mono_base_vtable const * const parent; 22 12 }; 23 13 … … 27 17 28 18 forall(T) 29 struct __cfatid_struct_mono_child {30 __cfatid_struct_mono_base const * parent;31 };32 33 forall(T)34 19 struct mono_child_vtable { 35 __cfatid_struct_mono_child(T) const * const __cfavir_typeid;20 mono_base_vtable const * const parent; 36 21 }; 37 22 … … 41 26 }; 42 27 43 __cfatid_struct_mono_child(int) __cfatid_mono_child @= { 44 &__cfatid_mono_base, 45 }; 46 28 mono_base_vtable _mono_base_vtable_instance @= { 0 }; 47 29 mono_child_vtable(int) _mono_child_vtable_instance @= { 48 &_ _cfatid_mono_child,30 &_mono_base_vtable_instance 49 31 }; 50 32 … … 55 37 } 56 38 57 58 forall(U)59 struct __cfatid_struct_poly_base {60 __cfa__parent_vtable const * parent;61 };62 63 39 forall(U) 64 40 struct poly_base_vtable { 65 __cfatid_struct_poly_base(U) const * const __cfavir_typeid;41 poly_base_vtable(U) const * const parent; 66 42 }; 67 43 … … 72 48 73 49 forall(V) 74 struct __cfatid_struct_poly_child {75 __cfatid_struct_poly_base(V) const * parent;76 };77 78 forall(V)79 50 struct poly_child_vtable { 80 __cfatid_struct_poly_child(V) const * const __cfavir_typeid;51 poly_base_vtable(V) const * const parent; 81 52 }; 82 53 … … 86 57 }; 87 58 88 __cfatid_struct_poly_base(int) __cfatid_poly_base @= { 89 (__cfa__parent_vtable *)0, 59 poly_base_vtable(int) _poly_base_vtable_instance @= { 0 }; 60 poly_child_vtable(int) _poly_child_vtable_instance @= { 61 &_poly_base_vtable_instance 90 62 }; 91 __cfatid_struct_poly_child(int) __cfatid_poly_child = { 92 &__cfatid_poly_base, 63 /* Resolver bug keeps me from adding these. 64 poly_base_vtable(char) _poly_base_vtable_instance @= { 0 }; 65 poly_child_vtable(char) _poly_child_vtable_instance @= { 66 &_poly_base_vtable_instance 93 67 }; 94 poly_child_vtable(int) _poly_child_vtable_instance @= { 95 &__cfatid_poly_child, 96 }; 68 */ 97 69 98 70 void poly_poly_test() { … … 105 77 mono_poly_test(); 106 78 poly_poly_test(); 107 printf( "done\n" ); 79 printf( "done\n" ); // non-empty .expect file 108 80 } -
tests/linking/exception-nothreads.cfa
r5407cdc rfeacef9 17 17 #include <exception.hfa> 18 18 19 EHM_EXCEPTION(ping)(); 20 EHM_VIRTUAL_TABLE(ping, ping_vt); 19 TRIVIAL_EXCEPTION(ping); 21 20 22 21 int main(void) { 23 22 try { 24 throwResume (ping){ &ping_vt};23 throwResume (ping){}; 25 24 } catchResume (ping *) { 26 25 printf("%s threads\n", threading_enabled() ? "with" : "no"); -
tests/linking/exception-withthreads.cfa
r5407cdc rfeacef9 18 18 #include "../exceptions/with-threads.hfa" 19 19 20 EHM_EXCEPTION(ping)(); 21 EHM_VIRTUAL_TABLE(ping, ping_vt); 20 TRIVIAL_EXCEPTION(ping); 22 21 23 22 int main(void) { 24 23 try { 25 throwResume (ping){ &ping_vt};24 throwResume (ping){}; 26 25 } catchResume (ping *) { 27 26 printf("%s threads\n", threading_enabled() ? "with" : "no"); -
tests/linking/weakso_nothd.cfa
r5407cdc rfeacef9 6 6 // 7 7 // weakso_nothd.cfa -- 8 // test whether or not usin ga weakso locks pulls in threads8 // test whether or not usind a weakso locks pulls in threads 9 9 // 10 10 // Author : Thierry Delisle -
tests/meta/.expect/archVast.nast.arm64.txt
r5407cdc rfeacef9 7 7 char Alternatives are: 8 8 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 9 Variable Expression: FA64: double9 Variable Expression: FA64: signed int 10 10 ... with resolved type: 11 double11 signed int 12 12 ... to: 13 13 char … … 39 39 40 40 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 41 Variable Expression: FA64: signed int41 Variable Expression: FA64: double 42 42 ... with resolved type: 43 signed int43 double 44 44 ... to: 45 45 char -
tests/time.cfa
r5407cdc rfeacef9 10 10 // Created On : Tue Mar 27 17:24:56 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 16 14:59:53 202113 // Update Count : 3 812 // Last Modified On : Thu Jun 18 18:14:49 2020 13 // Update Count : 37 14 14 // 15 15 … … 53 53 // | "Newfoundland" | getTime( Newfoundland ) 54 54 // | "local" | getTime() 55 // | "local nsec" | timeHiRes()55 // | "local nsec" | getTimeNsec() 56 56 // | "PST" | PST(); // getTime short form 57 57 // sout | nl; -
tests/unified_locking/.expect/locks.txt
r5407cdc rfeacef9 11 11 Start Test 6: owner lock and condition variable 3 wait/notify all 12 12 Done Test 6 13 Start Test 7: fast lock and condition variable singlewait/notify13 Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify 14 14 Done Test 7 15 Start Test 8: fast lock and condition variable 3 wait/notify all15 Start Test 8: owner lock and condition variable multiple acquire and wait/notify 16 16 Done Test 8 17 Start Test 9: multi acquisiton lock and condition variable multiple acquire andwait/notify17 Start Test 9: no lock condition variable wait/notify 18 18 Done Test 9 19 Start Test 10: owner lock and condition variable multiple acquire and wait/notify19 Start Test 10: locked condition variable wait/notify with front() 20 20 Done Test 10 21 Start Test 11: no lock condition variable wait/notify22 Done Test 1123 Start Test 12: locked condition variable wait/notify with front()24 Done Test 12 -
tests/unified_locking/locks.cfa
r5407cdc rfeacef9 15 15 condition_variable( owner_lock ) c_o; 16 16 17 fast_lock f;18 condition_variable( fast_lock ) c_f;19 20 17 thread T_C_M_WS1 {}; 21 18 … … 71 68 } 72 69 unlock(s); 73 }74 }75 76 thread T_C_F_WS1 {};77 78 void main( T_C_F_WS1 & this ) {79 for (unsigned int i = 0; i < num_times; i++) {80 lock(f);81 if(empty(c_f) && i != num_times - 1) {82 wait(c_f,f);83 }else{84 notify_one(c_f);85 }86 unlock(f);87 }88 }89 90 thread T_C_F_WB1 {};91 92 void main( T_C_F_WB1 & this ) {93 for (unsigned int i = 0; i < num_times; i++) {94 lock(f);95 if(counter(c_f) == 3 || i == num_times - 1) {96 notify_all(c_f);97 }else{98 wait(c_f,f);99 }100 unlock(f);101 70 } 102 71 } … … 286 255 printf("Done Test 6\n"); 287 256 288 printf("Start Test 7: fast lock and condition variable singlewait/notify\n");289 { 290 T_C_ F_WS1t1[2];257 printf("Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 258 { 259 T_C_M_WS2 t1[2]; 291 260 } 292 261 printf("Done Test 7\n"); 293 262 294 printf("Start Test 8: fast lock and condition variable 3 wait/notify all\n");295 { 296 T_C_ F_WB1 t1[4];263 printf("Start Test 8: owner lock and condition variable multiple acquire and wait/notify\n"); 264 { 265 T_C_O_WS2 t1[2]; 297 266 } 298 267 printf("Done Test 8\n"); 299 268 300 printf("Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 301 { 302 T_C_M_WS2 t1[2]; 303 } 304 printf("Done Test 9\n"); 305 306 printf("Start Test 10: owner lock and condition variable multiple acquire and wait/notify\n"); 307 { 308 T_C_O_WS2 t1[2]; 309 } 310 printf("Done Test 10\n"); 311 312 printf("Start Test 11: no lock condition variable wait/notify\n"); 269 printf("Start Test 9: no lock condition variable wait/notify\n"); 313 270 { 314 271 T_C_NLW t1; 315 272 T_C_NLS t2; 316 273 } 317 printf("Done Test 11\n");318 319 printf("Start Test 1 2: locked condition variable wait/notify with front()\n");274 printf("Done Test 9\n"); 275 276 printf("Start Test 10: locked condition variable wait/notify with front()\n"); 320 277 { 321 278 T_C_S_WNF t1[2]; 322 279 } 323 printf("Done Test 1 2\n");280 printf("Done Test 10\n"); 324 281 325 282 // removed to limit test duration. Full test is in long run tests -
tests/vector_math/.expect/vec4_float.txt
r5407cdc rfeacef9 6 6 zero-assign:<0.,0.,0.,0.> 7 7 fill-ctor:<1.23,1.23,1.23,1.23> 8 ?-?:<0.02,0.43,-0.999998,-1e-06 >9 ?-=?:<0.02,0.43,-0.999998,-1e-06 >10 -?:<-0.02,-0.43,0.999998,1e-06 >8 ?-?:<0.02,0.43,-0.999998,-1e-06.> 9 ?-=?:<0.02,0.43,-0.999998,-1e-06.> 10 -?:<-0.02,-0.43,0.999998,1e-06.> 11 11 ?+?:<2.3,2.45,-9.2,-12.5> 12 12 ?+=?:<2.3,2.45,-9.2,-12.5> -
tools/gdb/utils-gdb.py
r5407cdc rfeacef9 23 23 gdb.execute('handle SIGUSR1 nostop noprint pass') 24 24 25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state yield_state')25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state') 26 26 27 27 class ThreadInfo: … … 52 52 # GDB types for various structures/types in CFA 53 53 return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(), 54 processor_ptr = gdb.lookup_type('struct processor').pointer(), 55 thread_ptr = gdb.lookup_type('struct $thread').pointer(), 56 int_ptr = gdb.lookup_type('int').pointer(), 57 thread_state = gdb.lookup_type('enum __Coroutine_State'), 58 yield_state = gdb.lookup_type('enum __Preemption_Reason')) 54 processor_ptr = gdb.lookup_type('struct processor').pointer(), 55 thread_ptr = gdb.lookup_type('struct $thread').pointer(), 56 int_ptr = gdb.lookup_type('int').pointer(), 57 thread_state = gdb.lookup_type('enum __Coroutine_State')) 59 58 60 59 def get_addr(addr): … … 372 371 def print_thread(self, thread, tid, marked): 373 372 cfa_t = get_cfa_types() 374 ys = str(thread['preempted'].cast(cfa_t.yield_state)) 375 if ys == '_X15__NO_PREEMPTIONKM19__Preemption_Reason_1': 376 state = str(thread['state'].cast(cfa_t.thread_state)) 377 elif ys == '_X18__ALARM_PREEMPTIONKM19__Preemption_Reason_1': 378 state = 'preempted' 379 elif ys == '_X19__MANUAL_PREEMPTIONKM19__Preemption_Reason_1': 380 state = 'yield' 381 elif ys == '_X17__POLL_PREEMPTIONKM19__Preemption_Reason_1': 382 state = 'poll' 383 else: 384 print("error: thread {} in undefined preemption state {}".format(thread, ys)) 385 state = 'error' 386 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), state, str(thread)) 373 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread)) 387 374 388 375 def print_threads_by_cluster(self, cluster, print_system = False): … … 493 480 context = thread['context'] 494 481 495 482 # lookup for sp,fp and uSwitch 483 xsp = context['SP'] + 48 484 xfp = context['FP'] 485 486 # convert string so we can strip out the address 487 try: 488 xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28) 489 except: 490 print("here") 491 return 496 492 497 493 # must be at frame 0 to set pc register 498 494 gdb.execute('select-frame 0') 499 if gdb.selected_frame().architecture().name() != 'i386:x86-64':500 print('gdb debugging only supported for i386:x86-64 for now')501 return502 503 # gdb seems to handle things much better if we pretend we just entered the context switch504 # pretend the pc is __cfactx_switch and adjust the sp, base pointer doesn't need to change505 # lookup for sp,fp and uSwitch506 xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific507 xfp = context['FP']508 509 # convert string so we can strip out the address510 try:511 xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address)512 except:513 print("here")514 return515 495 516 496 # push sp, fp, pc into a global stack … … 523 503 524 504 # update registers for new task 525 # print('switching to {} ({}) : [{}, {}, {}]'.format(thread['self_cor']['name'].string(), str(thread), str(xsp), str(xfp), str(xpc))) 526 print('switching to thread {} ({})'.format(str(thread), thread['self_cor']['name'].string())) 505 print('switching to ') 527 506 gdb.execute('set $rsp={}'.format(xsp)) 528 507 gdb.execute('set $rbp={}'.format(xfp)) … … 573 552 574 553 argv = parse(arg) 554 print(argv) 575 555 if argv[0].isdigit(): 576 556 cname = " ".join(argv[1:]) if len(argv) > 1 else None
Note:
See TracChangeset
for help on using the changeset viewer.