Changes in / [7030dab:71d6bd8]


Ignore:
Files:
35 added
151 deleted
291 edited

Legend:

Unmodified
Added
Removed
  • Jenkinsfile_disabled

    r7030dab r71d6bd8  
    126126                        }
    127127
    128                         sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} --quiet --prefix=${BuildDir}"
     128                        sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
    129129
    130130                        // Configure libcfa
     
    155155                dir (BuildDir) {
    156156                        sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
    157                 }
    158         }
    159 
    160         build_stage('Build : install', true) {
    161                 // Build outside of the src tree to ease cleaning
    162                 dir (BuildDir) {
    163                         sh "make -j 8 --no-print-directory install"
    164157                }
    165158        }
     
    186179                echo "Archiving core dumps"
    187180                dir (BuildDir) {
    188                         archiveArtifacts artifacts: "tests/crashes/**/*,lib/**/lib*.so*", fingerprint: true
     181                        archiveArtifacts artifacts: "tests/crashes/**/*", fingerprint: true
    189182                }
    190183                throw err
     
    222215
    223216                //Then publish the results
    224                 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'        , groupCompile    , false, 'Compilation')
    225                 do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff'   , groupCompile    , true , 'Compilation (relative)')
    226                 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch'      , groupConcurrency, false, 'Context Switching')
    227                 do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff' , groupConcurrency, true , 'Context Switching (relative)')
    228                 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'          , groupConcurrency, false, 'Mutual Exclusion')
    229                 do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff'     , groupConcurrency, true , 'Mutual Exclusion (relative)')
    230                 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling'     , groupConcurrency, false, 'Internal and External Scheduling')
    231                 do_plot(Settings.RunBenchmark && Settings.Publish, 'scheduling.diff', groupConcurrency, true , 'Internal and External Scheduling (relative)')
     217                do_plot(Settings.RunBenchmark && Settings.Publish, 'compile'       , groupCompile    , false, 'Compilation')
     218                do_plot(Settings.RunBenchmark && Settings.Publish, 'compile.diff'  , groupCompile    , true , 'Compilation (relative)')
     219                do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch'     , groupConcurrency, false, 'Context Switching')
     220                do_plot(Settings.RunBenchmark && Settings.Publish, 'ctxswitch.diff', groupConcurrency, true , 'Context Switching (relative)')
     221                do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex'         , groupConcurrency, false, 'Mutual Exclusion')
     222                do_plot(Settings.RunBenchmark && Settings.Publish, 'mutex.diff'    , groupConcurrency, true , 'Mutual Exclusion (relative)')
     223                do_plot(Settings.RunBenchmark && Settings.Publish, 'signal'        , groupConcurrency, false, 'Internal and External Scheduling')
     224                do_plot(Settings.RunBenchmark && Settings.Publish, 'signal.diff'   , groupConcurrency, true , 'Internal and External Scheduling (relative)')
    232225        }
    233226}
     
    332325        public String CXX
    333326        public String CC
    334         public String lto
    335 
    336         CC_Desc(String name, String CXX, String CC, String lto) {
     327
     328        CC_Desc(String name, String CXX, String CC) {
    337329                this.name = name
    338330                this.CXX = CXX
    339                 this.CC  = CC
    340                 this.lto = lto
     331                this.CC = CC
    341332        }
    342333}
     
    373364                switch( param.Compiler ) {
    374365                        case 'gcc-9':
    375                                 this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9', '-flto=auto')
     366                                this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9')
    376367                        break
    377368                        case 'gcc-8':
    378                                 this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8', '-flto=auto')
     369                                this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8')
    379370                        break
    380371                        case 'gcc-7':
    381                                 this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
     372                                this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7')
    382373                        break
    383374                        case 'gcc-6':
    384                                 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
     375                                this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
    385376                        break
    386377                        case 'gcc-5':
    387                                 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
     378                                this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
    388379                        break
    389380                        case 'gcc-4.9':
    390                                 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
     381                                this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
    391382                        break
    392383                        case 'clang':
    393                                 this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6', '-flto=thin -flto-jobs=0')
     384                                this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6')
    394385                        break
    395386                        default :
     
    448439        // prepare the properties
    449440        properties ([                                                                                                   \
    450                 buildDiscarder(logRotator(                                                                              \
    451                         artifactDaysToKeepStr: '',                                                                      \
    452                         artifactNumToKeepStr: '',                                                                       \
    453                         daysToKeepStr: '730',                                                                           \
    454                         numToKeepStr: '1000'                                                                            \
    455                 )),                                                                                                             \
    456441                [$class: 'ParametersDefinitionProperty',                                                                \
    457442                        parameterDefinitions: [                                                                         \
  • benchmark/Makefile.am

    r7030dab r71d6bd8  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Mar 10 11:41:18 2020
    14 ## Update Count     : 258
     13## Last Modified On : Mon Jul 29 18:02:19 2019
     14## Update Count     : 54
    1515###############################################################################
    1616
     
    2828BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
    2929BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
     30BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
     31BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    3032BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    31 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
    32 BENCH_V_PY = $(__bench_v_PY_$(__quiet))
    33 BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
    34 BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
    35 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    3633
    3734__quiet = verbose
     
    3936__bench_v_CFA_quiet = @
    4037__bench_v_CXX_quiet = @
     38__bench_v_GOC_quiet = @
     39__bench_v_JAVAC_quiet = @
    4140__bench_v_UPP_quiet = @
    42 __bench_v_GOC_quiet = @
    43 __bench_v_RUSTC_quiet = @
    44 __bench_v_JAVAC_quiet = @
    4541__bench_v_CC_verbose = $(AM_V_CC)
    4642__bench_v_CFA_verbose = $(AM_V_CFA)
    4743__bench_v_CXX_verbose = $(AM_V_CXX)
     44__bench_v_GOC_verbose = $(AM_V_GOC)
     45__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    4846__bench_v_UPP_verbose = $(AM_V_UPP)
    49 __bench_v_GOC_verbose = $(AM_V_GOC)
    50 __bench_v_PY_verbose = $(AM_V_PY)
    51 __bench_v_RUSTC_verbose = $(AM_V_RUST)
    52 __bench_v_NODEJS_verbose = $(AM_V_NODEJS)
    53 __bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    5447
    5548
     
    5851STATS    = ${abs_top_srcdir}/tools/stat.py
    5952# NEED AT LEAST 4 DATA VALUES FOR BENCHMARKS BECAUSE THE MAX AND MIN VALUES ARE REMOVED
    60 repeats  = 13 # 31 for benchmarks
     53repeats  = 5 # 31 for benchmarks
    6154arch     = x64
    6255skipcompile = no
     
    6962
    7063dummyC.c:
    71         echo "int main() { return 0; }" > ${@}
     64        @echo "int main() { return 0; }" > ${@}
    7265
    7366dummyCXX.cpp:
    74         echo "int main() { return 0; }" > ${@}
    75 
    76 .SILENT:                # do not print recipe
     67        @echo "int main() { return 0; }" > ${@}
     68
    7769.NOTPARALLEL:
    78 .PHONY: jenkins cleancsv
    79 
    80 ## =========================================================================================================
    81 
    82 all : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
    83 
    84 basic_loop_DURATION = 15000000000
    85 basic_function_DURATION = 10000000000
    86 basic_tls_fetch_add_DURATION = 10000000000
    87 basic_DURATION = 250000000
    88 
    89 ctxswitch_pthread_DURATION = 25000000
    90 ctxswitch_rust_thread_DURATION = $(ctxswitch_pthread_DURATION)
    91 ctxswitch_cfa_generator_DURATION = 5000000000
    92 ctxswitch_nodejs_await_DURATION = 5000000
    93 ctxswitch_DURATION = 100000000
    94 
    95 #mutex_java_DURATION = 10000000
    96 mutex_DURATION = 50000000
    97 
    98 schedint_pthread_DURATION = 1000000
    99 schedint_java_DURATION = $(schedint_pthread_DURATION)
    100 schedint_rust_DURATION = $(schedint_pthread_DURATION)
    101 schedint_DURATION = 10000000
    102 
    103 schedext_DURATION = 10000000
    104 
    105 creation_pthread_DURATION = 250000
    106 creation_rust_thread_DURATION = ${creation_pthread_DURATION}
    107 creation_java_thread_DURATION = ${creation_pthread_DURATION}
    108 creation_cfa_coroutine_DURATION = 100000000
    109 creation_cfa_coroutine_eager_DURATION = 10000000
    110 creation_cfa_generator_DURATION = 1000000000
    111 creation_upp_coroutine_DURATION = ${creation_cfa_coroutine_eager_DURATION}
    112 creation_cfa_thread_DURATION = 10000000
    113 creation_upp_thread_DURATION = ${creation_cfa_thread_DURATION}
    114 creation_DURATION = 10000000
     70.PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
     71
     72## =========================================================================================================
     73all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
    11574
    11675%.run : %$(EXEEXT) ${REPEAT}
    117         rm -f .result.log
    118         echo "------------------------------------------------------"
    119         echo $<
    120         ${REPEAT} ${repeats} -- ./a.out\
    121                 $(if ${$(subst -,_,$(basename $@))_DURATION},\
    122                         ${$(subst -,_,$(basename $@))_DURATION},\
    123                         ${$(firstword $(subst -, ,$(basename $@)))_DURATION}) | tee -a .result.log
    124         ${STATS} .result.log
    125         echo "------------------------------------------------------"
    126         rm -f a.out .result.log *.class
    127 
    128 #       ${REPEAT} ${repeats} -- /usr/bin/time -f "%Uu %Ss %Er %Mkb" ./a.out
     76        @rm -f .result.log
     77        @echo "------------------------------------------------------"
     78        @echo $<
     79        @${REPEAT} ${repeats} ./a.out | tee -a .result.log
     80        @${STATS} .result.log
     81        @echo "------------------------------------------------------"
     82        @rm -f a.out .result.log *.class
    12983
    13084%.runquiet :
    131         +make $(basename $@) CFLAGS="-w" __quiet=quiet
    132         taskset -c 1 ./a.out
    133         rm -f a.out
     85        @+make $(basename $@) CFLAGS="-w" __quiet=quiet
     86        @taskset -c 1 ./a.out
     87        @rm -f a.out
    13488
    13589%.make :
    136         printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
    137         +/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
     90        @printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
     91        @+/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
    13892
    13993${REPEAT} :
    140         +make -C ${abs_top_builddir}/tools repeat
     94        @+make -C ${abs_top_builddir}/tools repeat
    14195
    14296## =========================================================================================================
     
    14498FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    14599
    146 cleancsv:
    147         rm -f compile.csv basic.csv ctxswitch.csv mutex.csv scheduling.csv
    148 
    149 jenkins$(EXEEXT): cleancsv
     100jenkins$(EXEEXT):
    150101@DOifskipcompile@
    151         +make compile.csv
    152         -+make compile.diff.csv
     102        @+make compile.csv
     103        @-+make compile.diff.csv
    153104@DOendif@
    154         +make ctxswitch.csv
    155         -+make ctxswitch.diff.csv
    156         +make mutex.csv
    157         -+make mutex.diff.csv
    158         +make scheduling.csv
    159         -+make scheduling.diff.csv
     105        @+make ctxswitch.csv
     106        @-+make ctxswitch.diff.csv
     107        @+make mutex.csv
     108        @-+make mutex.diff.csv
     109        @+make signal.csv
     110        @-+make signal.diff.csv
    160111@DOifskipcompile@
    161112        cat compile.csv
     
    166117        cat mutex.csv
    167118        -cat mutex.diff.csv
    168         cat scheduling.csv
    169         -cat scheduling.diff.csv
     119        cat signal.csv
     120        -cat signal.diff.csv
    170121
    171122compile.csv:
    172         echo "building $@"
    173         echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
    174         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
    175         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@
    176         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@
    177         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@
    178         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@
    179         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@
    180         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@
    181         +make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@
    182         $(srcdir)/fixcsv.sh $@
     123        @echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
     124        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
     125        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@
     126        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@
     127        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@
     128        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@
     129        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@
     130        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@
     131        @+make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@
     132        @$(srcdir)/fixcsv.sh $@
    183133
    184134ctxswitch.csv:
    185         echo "building $@"
    186         echo "generator,coroutine,thread" > $@
    187         +make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
    188         +make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
    189         +make ctxswitch-cfa_thread.runquiet >> $@
    190         $(srcdir)/fixcsv.sh $@
     135        @echo "generator,coroutine,thread" > $@
     136        @+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
     137        @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
     138        @+make ctxswitch-cfa_thread.runquiet >> $@
     139        @$(srcdir)/fixcsv.sh $@
    191140
    192141mutex.csv:
    193         echo "building $@"
    194         echo "1-monitor,2-monitor" > $@
    195         +make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
    196         +make mutex-cfa2.runquiet >> $@
    197         $(srcdir)/fixcsv.sh $@
    198 
    199 scheduling.csv:
    200         echo "building $@"
    201         echo "schedint-1,schedint-2,schedext-1,schedext-2" > $@
    202         +make schedint-cfa1.runquiet >> $@ && echo -n ',' >> $@
    203         +make schedint-cfa2.runquiet >> $@ && echo -n ',' >> $@
    204         +make schedext-cfa1.runquiet >> $@ && echo -n ',' >> $@
    205         +make schedext-cfa2.runquiet >> $@
    206         $(srcdir)/fixcsv.sh $@
     142        @echo "1-monitor,2-monitor" > $@
     143        @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
     144        @+make mutex-cfa2.runquiet >> $@
     145        @$(srcdir)/fixcsv.sh $@
     146
     147signal.csv:
     148        @echo "signal-1,signal-2,waitfor-1,waitfor-2" > $@
     149        @+make signal-cfa1.runquiet >> $@ && echo -n ',' >> $@
     150        @+make signal-cfa2.runquiet >> $@ && echo -n ',' >> $@
     151        @+make waitfor-cfa1.runquiet >> $@ && echo -n ',' >> $@
     152        @+make waitfor-cfa2.runquiet >> $@
     153        @$(srcdir)/fixcsv.sh $@
    207154
    208155%.diff.csv: %.csv
    209         test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
    210         $(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
    211 
    212 ## =========================================================================================================
    213 
    214 BASIC_DEPEND  =                                 \
    215         basic-loop.run                          \
    216         basic-function.run                      \
    217         basic-fetch_add.run                     \
    218         basic-ttst_lock.run                     \
    219         basic-tls-fetch_add.run
    220 
    221 basic-loop$(EXEEXT):
    222         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/loop.c
    223 
    224 basic-function$(EXEEXT):
    225         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/function.c
    226 
    227 basic-fetch_add$(EXEEXT):
    228         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/fetch_add.c
    229 
    230 basic-ttst_lock$(EXEEXT):
    231         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/ttst_lock.c
    232 
    233 basic-tls-fetch_add$(EXEEXT):
    234         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/tls_fetch_add.c
    235 
    236 basic$(EXEEXT): $(BASIC_DEPEND)
    237 
    238 ## =========================================================================================================
    239 
    240 CTXSWITCH_DEPEND  =                     \
     156        @test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
     157        @$(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
     158
     159
     160## =========================================================================================================
     161loop$(EXEEXT):
     162        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
     163
     164function$(EXEEXT):
     165        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
     166
     167fetch_add$(EXEEXT):
     168        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
     169
     170ttst_lock$(EXEEXT):
     171        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/ttst_lock.c
     172
     173tls-fetch_add$(EXEEXT):
     174        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     175
     176## =========================================================================================================
     177CTXSWITCH_DEPEND  =                 \
     178        loop.run                                \
     179        function.run                    \
     180        fetch_add.run                   \
     181        ttst_lock.run                   \
     182        tls-fetch_add.run                       \
     183        ctxswitch-pthread.run           \
    241184        ctxswitch-cfa_generator.run     \
    242185        ctxswitch-cfa_coroutine.run     \
     
    245188        ctxswitch-upp_coroutine.run     \
    246189        ctxswitch-upp_thread.run        \
    247         ctxswitch-python_coroutine.run  \
    248         ctxswitch-nodejs_coroutine.run  \
    249         ctxswitch-nodejs_await.run      \
    250         ctxswitch-goroutine_thread.run  \
    251         ctxswitch-rust_thread.run       \
    252         ctxswitch-nodejs_coroutine.run  \
    253         ctxswitch-java_thread.run       \
    254         ctxswitch-pthread.run
     190        ctxswitch-goroutine.run         \
     191        ctxswitch-java_thread.run
     192
    255193
    256194if WITH_LIBFIBRE
    257 CTXSWITCH_DEPEND  +=                    \
    258         ctxswitch-kos_fibre.run         \
     195CTXSWITCH_DEPEND  +=           \
     196        ctxswitch-kos_fibre.run  \
    259197        ctxswitch-kos_fibre2.run
     198
    260199
    261200ctxswitch-kos_fibre$(EXEEXT):
     
    268207ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND)
    269208
     209ctxswitch-pthread$(EXEEXT):
     210        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     211
    270212ctxswitch-cfa_generator$(EXEEXT):
    271         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_gen.cfa
     213        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa
    272214
    273215ctxswitch-cfa_coroutine$(EXEEXT):
    274         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_cor.cfa
     216        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
    275217
    276218ctxswitch-cfa_thread$(EXEEXT):
    277         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd.cfa
     219        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
    278220
    279221ctxswitch-cfa_thread2$(EXEEXT):
    280         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd2.cfa
     222        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
    281223
    282224ctxswitch-upp_coroutine$(EXEEXT):
    283         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_cor.cc
     225        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
    284226
    285227ctxswitch-upp_thread$(EXEEXT):
    286         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_thrd.cc
    287 
    288 ctxswitch-python_coroutine$(EXEEXT):
    289         $(BENCH_V_PY)echo "#!/bin/sh" > a.out
    290         echo "python3.7 $(srcdir)/ctxswitch/python_cor.py" >> a.out
    291         chmod a+x a.out
    292 
    293 ctxswitch-nodejs_coroutine$(EXEEXT):
    294         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    295         echo "nodejs $(srcdir)/ctxswitch/node_cor.js" >> a.out
    296         chmod a+x a.out
    297 
    298 ctxswitch-nodejs_await$(EXEEXT):
    299         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    300         echo "nodejs $(srcdir)/ctxswitch/node_await.js" >> a.out
    301         chmod a+x a.out
    302 
    303 ctxswitch-goroutine_thread$(EXEEXT):
     228        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
     229
     230ctxswitch-goroutine$(EXEEXT):
    304231        $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
    305 
    306 ctxswitch-rust_thread$(EXEEXT):
    307         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/ctxswitch/rust_thrd.rs
    308232
    309233ctxswitch-java_thread$(EXEEXT):
    310234        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    311         echo "#!/bin/sh" > a.out
    312         echo "java JavaThread" >> a.out
    313         chmod a+x a.out
    314 
    315 ctxswitch-pthread$(EXEEXT):
    316         $(BENCH_V_CC)$(COMPILE) $(srcdir)/ctxswitch/pthreads.c
    317 
    318 ## =========================================================================================================
    319 
    320 mutex$(EXEEXT) :                \
     235        @echo "#!/bin/sh" > a.out
     236        @echo "java JavaThread" >> a.out
     237        @chmod a+x a.out
     238
     239## =========================================================================================================
     240mutex$(EXEEXT) :\
     241        loop.run                        \
     242        function.run            \
     243        fetch_add.run           \
     244        mutex-pthread_lock.run  \
     245        mutex-upp.run           \
    321246        mutex-cfa1.run          \
    322247        mutex-cfa2.run          \
    323248        mutex-cfa4.run          \
    324         mutex-upp.run           \
    325         mutex-go.run            \
    326         mutex-rust.run          \
    327         mutex-java.run          \
    328         mutex-pthread.run
    329 
    330 mutex-pthread$(EXEEXT):
    331         $(BENCH_V_CC)$(COMPILE) $(srcdir)/mutex/pthreads.c
     249        mutex-java_thread.run
     250
     251mutex-pthread_lock$(EXEEXT):
     252        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     253
     254mutex-upp$(EXEEXT):
     255        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    332256
    333257mutex-cfa1$(EXEEXT):
    334         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa1.cfa
     258        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    335259
    336260mutex-cfa2$(EXEEXT):
    337         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa2.cfa
     261        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    338262
    339263mutex-cfa4$(EXEEXT):
    340         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa4.cfa
    341 
    342 mutex-upp$(EXEEXT):
    343         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/mutex/upp.cc
    344 
    345 mutex-go$(EXEEXT):
    346         $(BENCH_V_GOC)go build -o a.out $(srcdir)/mutex/goroutine.go
    347 
    348 mutex-rust$(EXEEXT):
    349         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/mutex/rust.rs
    350 
    351 mutex-java$(EXEEXT):
     264        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
     265
     266mutex-java_thread$(EXEEXT):
    352267        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    353         echo "#!/bin/sh" > a.out
    354         echo "java JavaThread" >> a.out
    355         chmod a+x a.out
    356 
    357 ## =========================================================================================================
    358 
    359 schedint$(EXEEXT) :             \
    360         schedint-cfa1.run       \
    361         schedint-cfa2.run       \
    362         schedint-cfa4.run       \
    363         schedint-upp.run        \
    364         schedint-rust.run       \
    365         schedint-java.run       \
    366         schedint-pthread.run
    367 
    368 schedint-cfa1$(EXEEXT):
    369         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa1.cfa
    370 
    371 schedint-cfa2$(EXEEXT):
    372         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa2.cfa
    373 
    374 schedint-cfa4$(EXEEXT):
    375         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa4.cfa
    376 
    377 schedint-upp$(EXEEXT):
    378         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedint/upp.cc
    379 
    380 schedint-rust$(EXEEXT):
    381         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/schedint/rust.rs
    382 
    383 schedint-java$(EXEEXT):
     268        @echo "#!/bin/sh" > a.out
     269        @echo "java JavaThread" >> a.out
     270        @chmod a+x a.out
     271
     272## =========================================================================================================
     273signal$(EXEEXT) :\
     274        signal-pthread_cond.run \
     275        signal-upp.run          \
     276        signal-cfa1.run         \
     277        signal-cfa2.run         \
     278        signal-cfa4.run         \
     279        signal-java_thread.run
     280
     281signal-pthread_cond$(EXEEXT):
     282        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
     283
     284signal-upp$(EXEEXT):
     285        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
     286
     287signal-cfa1$(EXEEXT):
     288        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
     289
     290signal-cfa2$(EXEEXT):
     291        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
     292
     293signal-cfa4$(EXEEXT):
     294        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
     295
     296signal-java_thread$(EXEEXT):
    384297        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    385         echo "#!/bin/sh" > a.out
    386         echo "java JavaThread" >> a.out
    387         chmod a+x a.out
    388 
    389 schedint-pthread$(EXEEXT):
    390         $(BENCH_V_CC)$(COMPILE) $(srcdir)/schedint/pthreads.c
    391 
    392 ## =========================================================================================================
    393 
    394 schedext$(EXEEXT) :             \
    395         schedext-cfa1.run       \
    396         schedext-cfa2.run       \
    397         schedext-cfa4.run       \
    398         schedext-upp.run        \
    399         schedext-goroutine.run
    400 
    401 schedext-cfa1$(EXEEXT):
    402         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa1.cfa
    403 
    404 schedext-cfa2$(EXEEXT):
    405         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa2.cfa
    406 
    407 schedext-cfa4$(EXEEXT):
    408         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa4.cfa
    409 
    410 schedext-upp$(EXEEXT):
    411         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedext/upp.cc
    412 
    413 schedext-goroutine$(EXEEXT):
    414         $(BENCH_V_GOC)go build -o a.out $(srcdir)/schedext/goroutine.go
    415 
    416 
    417 ## =========================================================================================================
    418 
    419 creation$(EXEEXT) :                             \
    420         creation-cfa_generator.run              \
     298        @echo "#!/bin/sh" > a.out
     299        @echo "java JavaThread" >> a.out
     300        @chmod a+x a.out
     301
     302
     303## =========================================================================================================
     304waitfor$(EXEEXT) :\
     305        waitfor-upp.run         \
     306        waitfor-cfa1.run                \
     307        waitfor-cfa2.run                \
     308        waitfor-cfa4.run
     309
     310waitfor-upp$(EXEEXT):
     311        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
     312
     313waitfor-cfa1$(EXEEXT):
     314        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
     315
     316waitfor-cfa2$(EXEEXT):
     317        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
     318
     319waitfor-cfa4$(EXEEXT):
     320        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
     321
     322## =========================================================================================================
     323creation$(EXEEXT) :\
     324        creation-pthread.run                    \
    421325        creation-cfa_coroutine.run              \
    422326        creation-cfa_coroutine_eager.run        \
     
    424328        creation-upp_coroutine.run              \
    425329        creation-upp_thread.run                 \
    426         creation-python_coroutine.run           \
    427         creation-nodejs_coroutine.run           \
    428         creation-goroutine_thread.run           \
    429         creation-rust_thread.run                \
    430         creation-java_thread.run                \
    431         creation-pthread.run
    432 
    433 creation-cfa_generator$(EXEEXT):
    434         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_gen.cfa
     330        creation-goroutine.run                  \
     331        creation-java_thread.run
    435332
    436333creation-cfa_coroutine$(EXEEXT):
    437         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa
     334        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
    438335
    439336creation-cfa_coroutine_eager$(EXEEXT):
    440         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     337        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    441338
    442339creation-cfa_thread$(EXEEXT):
    443         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_thrd.cfa
     340        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
    444341
    445342creation-upp_coroutine$(EXEEXT):
    446         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_cor.cc
     343        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
    447344
    448345creation-upp_thread$(EXEEXT):
    449         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_thrd.cc
    450 
    451 creation-python_coroutine$(EXEEXT):
    452         $(BENCH_V_PY)echo "#!/bin/sh" > a.out
    453         echo "python3.7 $(srcdir)/creation/python_cor.py" >> a.out
    454         chmod a+x a.out
    455 
    456 creation-nodejs_coroutine$(EXEEXT):
    457         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    458         echo "nodejs $(srcdir)/creation/node_cor.js" >> a.out
    459         chmod a+x a.out
    460 
    461 creation-goroutine_thread$(EXEEXT):
     346        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
     347
     348creation-pthread$(EXEEXT):
     349        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
     350
     351creation-goroutine$(EXEEXT):
    462352        $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
    463 
    464 creation-rust_thread$(EXEEXT):
    465         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/creation/rust_thrd.rs
    466353
    467354creation-java_thread$(EXEEXT):
    468355        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    469         echo "#!/bin/sh" > a.out
    470         echo "java JavaThread" >> a.out
    471         chmod a+x a.out
    472 
    473 creation-pthread$(EXEEXT):
    474         $(BENCH_V_CC)$(COMPILE) $(srcdir)/creation/pthreads.c
    475 
    476 ## =========================================================================================================
    477 
    478 compile$(EXEEXT) :              \
     356        @echo "#!/bin/sh" > a.out
     357        @echo "java JavaThread" >> a.out
     358        @chmod a+x a.out
     359
     360## =========================================================================================================
     361
     362compile$(EXEEXT) :\
    479363        compile-array.make      \
    480364        compile-attributes.make \
     
    486370        compile-typeof.make
    487371
     372
    488373testdir = $(top_srcdir)/tests
    489374
    490375compile-array$(EXEEXT):
    491         $(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     376        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    492377
    493378compile-attributes$(EXEEXT):
    494         $(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     379        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    495380
    496381compile-empty$(EXEEXT):
    497         $(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     382        @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    498383
    499384compile-expression$(EXEEXT):
    500         $(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     385        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    501386
    502387compile-io$(EXEEXT):
    503         $(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     388        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    504389
    505390compile-monitor$(EXEEXT):
    506         $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     391        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    507392
    508393compile-operators$(EXEEXT):
    509         $(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     394        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    510395
    511396compile-thread$(EXEEXT):
    512         $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     397        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    513398
    514399compile-typeof$(EXEEXT):
    515         $(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    516 
    517 ## =========================================================================================================
    518 
    519 size$(EXEEXT) : size-cfa.runquiet
    520 
    521 size-cfa$(EXEEXT):
    522         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/size/size.cfa
     400        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
  • benchmark/Makefile.in

    r7030dab r71d6bd8  
    9393EXTRA_PROGRAMS = dummy$(EXEEXT)
    9494@WITH_LIBFIBRE_TRUE@am__append_1 = \
    95 @WITH_LIBFIBRE_TRUE@    ctxswitch-kos_fibre.run         \
     95@WITH_LIBFIBRE_TRUE@    ctxswitch-kos_fibre.run  \
    9696@WITH_LIBFIBRE_TRUE@    ctxswitch-kos_fibre2.run
    9797
     
    352352LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    353353        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
    354         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
     354        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
     355        $(AM_CFLAGS) $(CFLAGS)
    355356
    356357AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    358359am__v_CFA_0 = @echo "  CFA     " $@;
    359360am__v_CFA_1 =
     361AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     362am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     363am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     364am__v_JAVAC_1 =
     365AM_V_GOC = $(am__v_GOC_@AM_V@)
     366am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     367am__v_GOC_0 = @echo "  GOC     " $@;
     368am__v_GOC_1 =
    360369UPPCC = u++
    361370UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    364373am__v_UPP_0 = @echo "  UPP     " $@;
    365374am__v_UPP_1 =
    366 AM_V_GOC = $(am__v_GOC_@AM_V@)
    367 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    368 am__v_GOC_0 = @echo "  GOC     " $@;
    369 am__v_GOC_1 =
    370 AM_V_PY = $(am__v_PY_@AM_V@)
    371 am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
    372 am__v_PY_0 = @echo "  PYTHON  " $@;
    373 am__v_PY_1 =
    374 AM_V_RUST = $(am__v_RUST_@AM_V@)
    375 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
    376 am__v_RUST_0 = @echo "  RUST    " $@;
    377 am__v_RUST_1 =
    378 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
    379 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
    380 am__v_NODEJS_0 = @echo "  NODEJS  " $@;
    381 am__v_NODEJS_1 =
    382 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    383 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    384 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    385 am__v_JAVAC_1 =
    386375
    387376# applies to both programs
     
    392381BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
    393382BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
     383BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
     384BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    394385BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    395 BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
    396 BENCH_V_PY = $(__bench_v_PY_$(__quiet))
    397 BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
    398 BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
    399 BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    400386__quiet = verbose
    401387__bench_v_CC_quiet = @
    402388__bench_v_CFA_quiet = @
    403389__bench_v_CXX_quiet = @
     390__bench_v_GOC_quiet = @
     391__bench_v_JAVAC_quiet = @
    404392__bench_v_UPP_quiet = @
    405 __bench_v_GOC_quiet = @
    406 __bench_v_RUSTC_quiet = @
    407 __bench_v_JAVAC_quiet = @
    408393__bench_v_CC_verbose = $(AM_V_CC)
    409394__bench_v_CFA_verbose = $(AM_V_CFA)
    410395__bench_v_CXX_verbose = $(AM_V_CXX)
     396__bench_v_GOC_verbose = $(AM_V_GOC)
     397__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    411398__bench_v_UPP_verbose = $(AM_V_UPP)
    412 __bench_v_GOC_verbose = $(AM_V_GOC)
    413 __bench_v_PY_verbose = $(AM_V_PY)
    414 __bench_v_RUSTC_verbose = $(AM_V_RUST)
    415 __bench_v_NODEJS_verbose = $(AM_V_NODEJS)
    416 __bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    417399TOOLSDIR = ${abs_top_builddir}/tools/
    418400REPEAT = ${abs_top_builddir}/tools/repeat
    419401STATS = ${abs_top_srcdir}/tools/stat.py
    420402# NEED AT LEAST 4 DATA VALUES FOR BENCHMARKS BECAUSE THE MAX AND MIN VALUES ARE REMOVED
    421 repeats = 13 # 31 for benchmarks
     403repeats = 5 # 31 for benchmarks
    422404arch = x64
    423405skipcompile = no
     
    425407PRINT_FORMAT = %20s: #Comments needed for spacing
    426408dummy_SOURCES = dummyC.c dummyCXX.cpp
    427 basic_loop_DURATION = 15000000000
    428 basic_function_DURATION = 10000000000
    429 basic_tls_fetch_add_DURATION = 10000000000
    430 basic_DURATION = 250000000
    431 ctxswitch_pthread_DURATION = 25000000
    432 ctxswitch_rust_thread_DURATION = $(ctxswitch_pthread_DURATION)
    433 ctxswitch_cfa_generator_DURATION = 5000000000
    434 ctxswitch_nodejs_await_DURATION = 5000000
    435 ctxswitch_DURATION = 100000000
    436 
    437 #mutex_java_DURATION = 10000000
    438 mutex_DURATION = 50000000
    439 schedint_pthread_DURATION = 1000000
    440 schedint_java_DURATION = $(schedint_pthread_DURATION)
    441 schedint_rust_DURATION = $(schedint_pthread_DURATION)
    442 schedint_DURATION = 10000000
    443 schedext_DURATION = 10000000
    444 creation_pthread_DURATION = 250000
    445 creation_rust_thread_DURATION = ${creation_pthread_DURATION}
    446 creation_java_thread_DURATION = ${creation_pthread_DURATION}
    447 creation_cfa_coroutine_DURATION = 100000000
    448 creation_cfa_coroutine_eager_DURATION = 10000000
    449 creation_cfa_generator_DURATION = 1000000000
    450 creation_upp_coroutine_DURATION = ${creation_cfa_coroutine_eager_DURATION}
    451 creation_cfa_thread_DURATION = 10000000
    452 creation_upp_thread_DURATION = ${creation_cfa_thread_DURATION}
    453 creation_DURATION = 10000000
    454409FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    455 BASIC_DEPEND = \
    456         basic-loop.run                          \
    457         basic-function.run                      \
    458         basic-fetch_add.run                     \
    459         basic-ttst_lock.run                     \
    460         basic-tls-fetch_add.run
    461 
    462 CTXSWITCH_DEPEND = ctxswitch-cfa_generator.run \
    463         ctxswitch-cfa_coroutine.run ctxswitch-cfa_thread.run \
    464         ctxswitch-cfa_thread2.run ctxswitch-upp_coroutine.run \
    465         ctxswitch-upp_thread.run ctxswitch-python_coroutine.run \
    466         ctxswitch-nodejs_coroutine.run ctxswitch-nodejs_await.run \
    467         ctxswitch-goroutine_thread.run ctxswitch-rust_thread.run \
    468         ctxswitch-nodejs_coroutine.run ctxswitch-java_thread.run \
    469         ctxswitch-pthread.run $(am__append_1)
     410CTXSWITCH_DEPEND = loop.run function.run fetch_add.run ttst_lock.run \
     411        tls-fetch_add.run ctxswitch-pthread.run \
     412        ctxswitch-cfa_generator.run ctxswitch-cfa_coroutine.run \
     413        ctxswitch-cfa_thread.run ctxswitch-cfa_thread2.run \
     414        ctxswitch-upp_coroutine.run ctxswitch-upp_thread.run \
     415        ctxswitch-goroutine.run ctxswitch-java_thread.run \
     416        $(am__append_1)
    470417testdir = $(top_srcdir)/tests
    471418all: all-am
     
    786733
    787734dummyC.c:
    788         echo "int main() { return 0; }" > ${@}
     735        @echo "int main() { return 0; }" > ${@}
    789736
    790737dummyCXX.cpp:
    791         echo "int main() { return 0; }" > ${@}
    792 
    793 .SILENT:                # do not print recipe
     738        @echo "int main() { return 0; }" > ${@}
     739
    794740.NOTPARALLEL:
    795 .PHONY: jenkins cleancsv
    796 
    797 all : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
     741.PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
     742
     743all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
    798744
    799745%.run : %$(EXEEXT) ${REPEAT}
    800         rm -f .result.log
    801         echo "------------------------------------------------------"
    802         echo $<
    803         ${REPEAT} ${repeats} -- ./a.out\
    804                 $(if ${$(subst -,_,$(basename $@))_DURATION},\
    805                         ${$(subst -,_,$(basename $@))_DURATION},\
    806                         ${$(firstword $(subst -, ,$(basename $@)))_DURATION}) | tee -a .result.log
    807         ${STATS} .result.log
    808         echo "------------------------------------------------------"
    809         rm -f a.out .result.log *.class
    810 
    811 #       ${REPEAT} ${repeats} -- /usr/bin/time -f "%Uu %Ss %Er %Mkb" ./a.out
     746        @rm -f .result.log
     747        @echo "------------------------------------------------------"
     748        @echo $<
     749        @${REPEAT} ${repeats} ./a.out | tee -a .result.log
     750        @${STATS} .result.log
     751        @echo "------------------------------------------------------"
     752        @rm -f a.out .result.log *.class
    812753
    813754%.runquiet :
    814         +make $(basename $@) CFLAGS="-w" __quiet=quiet
    815         taskset -c 1 ./a.out
    816         rm -f a.out
     755        @+make $(basename $@) CFLAGS="-w" __quiet=quiet
     756        @taskset -c 1 ./a.out
     757        @rm -f a.out
    817758
    818759%.make :
    819         printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
    820         +/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
     760        @printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
     761        @+/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
    821762
    822763${REPEAT} :
    823         +make -C ${abs_top_builddir}/tools repeat
    824 
    825 cleancsv:
    826         rm -f compile.csv basic.csv ctxswitch.csv mutex.csv scheduling.csv
    827 
    828 jenkins$(EXEEXT): cleancsv
     764        @+make -C ${abs_top_builddir}/tools repeat
     765
     766jenkins$(EXEEXT):
    829767@DOifskipcompile@
    830         +make compile.csv
    831         -+make compile.diff.csv
     768        @+make compile.csv
     769        @-+make compile.diff.csv
    832770@DOendif@
    833         +make ctxswitch.csv
    834         -+make ctxswitch.diff.csv
    835         +make mutex.csv
    836         -+make mutex.diff.csv
    837         +make scheduling.csv
    838         -+make scheduling.diff.csv
     771        @+make ctxswitch.csv
     772        @-+make ctxswitch.diff.csv
     773        @+make mutex.csv
     774        @-+make mutex.diff.csv
     775        @+make signal.csv
     776        @-+make signal.diff.csv
    839777@DOifskipcompile@
    840778        cat compile.csv
     
    845783        cat mutex.csv
    846784        -cat mutex.diff.csv
    847         cat scheduling.csv
    848         -cat scheduling.diff.csv
     785        cat signal.csv
     786        -cat signal.diff.csv
    849787
    850788compile.csv:
    851         echo "building $@"
    852         echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
    853         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
    854         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@
    855         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@
    856         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@
    857         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@
    858         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@
    859         +make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@
    860         +make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@
    861         $(srcdir)/fixcsv.sh $@
     789        @echo "array,attributes,empty,expression,io,monitor,operators,typeof" > $@
     790        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-array.make >> $@
     791        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-attributes.make >> $@
     792        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-empty.make >> $@
     793        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-expression.make >> $@
     794        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-io.make >> $@
     795        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-monitor.make >> $@
     796        @+make TIME_FORMAT='%e,' PRINT_FORMAT='' compile-operators.make >> $@
     797        @+make TIME_FORMAT='%e' PRINT_FORMAT='' compile-typeof.make >> $@
     798        @$(srcdir)/fixcsv.sh $@
    862799
    863800ctxswitch.csv:
    864         echo "building $@"
    865         echo "generator,coroutine,thread" > $@
    866         +make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
    867         +make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
    868         +make ctxswitch-cfa_thread.runquiet >> $@
    869         $(srcdir)/fixcsv.sh $@
     801        @echo "generator,coroutine,thread" > $@
     802        @+make ctxswitch-cfa_generator.runquiet >> $@ && echo -n ',' >> $@
     803        @+make ctxswitch-cfa_coroutine.runquiet >> $@ && echo -n ',' >> $@
     804        @+make ctxswitch-cfa_thread.runquiet >> $@
     805        @$(srcdir)/fixcsv.sh $@
    870806
    871807mutex.csv:
    872         echo "building $@"
    873         echo "1-monitor,2-monitor" > $@
    874         +make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
    875         +make mutex-cfa2.runquiet >> $@
    876         $(srcdir)/fixcsv.sh $@
    877 
    878 scheduling.csv:
    879         echo "building $@"
    880         echo "schedint-1,schedint-2,schedext-1,schedext-2" > $@
    881         +make schedint-cfa1.runquiet >> $@ && echo -n ',' >> $@
    882         +make schedint-cfa2.runquiet >> $@ && echo -n ',' >> $@
    883         +make schedext-cfa1.runquiet >> $@ && echo -n ',' >> $@
    884         +make schedext-cfa2.runquiet >> $@
    885         $(srcdir)/fixcsv.sh $@
     808        @echo "1-monitor,2-monitor" > $@
     809        @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
     810        @+make mutex-cfa2.runquiet >> $@
     811        @$(srcdir)/fixcsv.sh $@
     812
     813signal.csv:
     814        @echo "signal-1,signal-2,waitfor-1,waitfor-2" > $@
     815        @+make signal-cfa1.runquiet >> $@ && echo -n ',' >> $@
     816        @+make signal-cfa2.runquiet >> $@ && echo -n ',' >> $@
     817        @+make waitfor-cfa1.runquiet >> $@ && echo -n ',' >> $@
     818        @+make waitfor-cfa2.runquiet >> $@
     819        @$(srcdir)/fixcsv.sh $@
    886820
    887821%.diff.csv: %.csv
    888         test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
    889         $(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
    890 
    891 basic-loop$(EXEEXT):
    892         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/loop.c
    893 
    894 basic-function$(EXEEXT):
    895         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/function.c
    896 
    897 basic-fetch_add$(EXEEXT):
    898         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/fetch_add.c
    899 
    900 basic-ttst_lock$(EXEEXT):
    901         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/ttst_lock.c
    902 
    903 basic-tls-fetch_add$(EXEEXT):
    904         $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/tls_fetch_add.c
    905 
    906 basic$(EXEEXT): $(BASIC_DEPEND)
     822        @test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
     823        @$(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
     824
     825loop$(EXEEXT):
     826        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
     827
     828function$(EXEEXT):
     829        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
     830
     831fetch_add$(EXEEXT):
     832        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
     833
     834ttst_lock$(EXEEXT):
     835        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/ttst_lock.c
     836
     837tls-fetch_add$(EXEEXT):
     838        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
    907839
    908840@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT):
     
    914846ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND)
    915847
     848ctxswitch-pthread$(EXEEXT):
     849        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
     850
    916851ctxswitch-cfa_generator$(EXEEXT):
    917         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_gen.cfa
     852        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa
    918853
    919854ctxswitch-cfa_coroutine$(EXEEXT):
    920         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_cor.cfa
     855        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
    921856
    922857ctxswitch-cfa_thread$(EXEEXT):
    923         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd.cfa
     858        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
    924859
    925860ctxswitch-cfa_thread2$(EXEEXT):
    926         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd2.cfa
     861        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
    927862
    928863ctxswitch-upp_coroutine$(EXEEXT):
    929         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_cor.cc
     864        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
    930865
    931866ctxswitch-upp_thread$(EXEEXT):
    932         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_thrd.cc
    933 
    934 ctxswitch-python_coroutine$(EXEEXT):
    935         $(BENCH_V_PY)echo "#!/bin/sh" > a.out
    936         echo "python3.7 $(srcdir)/ctxswitch/python_cor.py" >> a.out
    937         chmod a+x a.out
    938 
    939 ctxswitch-nodejs_coroutine$(EXEEXT):
    940         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    941         echo "nodejs $(srcdir)/ctxswitch/node_cor.js" >> a.out
    942         chmod a+x a.out
    943 
    944 ctxswitch-nodejs_await$(EXEEXT):
    945         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    946         echo "nodejs $(srcdir)/ctxswitch/node_await.js" >> a.out
    947         chmod a+x a.out
    948 
    949 ctxswitch-goroutine_thread$(EXEEXT):
     867        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
     868
     869ctxswitch-goroutine$(EXEEXT):
    950870        $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
    951 
    952 ctxswitch-rust_thread$(EXEEXT):
    953         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/ctxswitch/rust_thrd.rs
    954871
    955872ctxswitch-java_thread$(EXEEXT):
    956873        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    957         echo "#!/bin/sh" > a.out
    958         echo "java JavaThread" >> a.out
    959         chmod a+x a.out
    960 
    961 ctxswitch-pthread$(EXEEXT):
    962         $(BENCH_V_CC)$(COMPILE) $(srcdir)/ctxswitch/pthreads.c
    963 
    964 mutex$(EXEEXT) :                \
     874        @echo "#!/bin/sh" > a.out
     875        @echo "java JavaThread" >> a.out
     876        @chmod a+x a.out
     877
     878mutex$(EXEEXT) :\
     879        loop.run                        \
     880        function.run            \
     881        fetch_add.run           \
     882        mutex-pthread_lock.run  \
     883        mutex-upp.run           \
    965884        mutex-cfa1.run          \
    966885        mutex-cfa2.run          \
    967886        mutex-cfa4.run          \
    968         mutex-upp.run           \
    969         mutex-go.run            \
    970         mutex-rust.run          \
    971         mutex-java.run          \
    972         mutex-pthread.run
    973 
    974 mutex-pthread$(EXEEXT):
    975         $(BENCH_V_CC)$(COMPILE) $(srcdir)/mutex/pthreads.c
     887        mutex-java_thread.run
     888
     889mutex-pthread_lock$(EXEEXT):
     890        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     891
     892mutex-upp$(EXEEXT):
     893        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    976894
    977895mutex-cfa1$(EXEEXT):
    978         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa1.cfa
     896        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    979897
    980898mutex-cfa2$(EXEEXT):
    981         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa2.cfa
     899        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    982900
    983901mutex-cfa4$(EXEEXT):
    984         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa4.cfa
    985 
    986 mutex-upp$(EXEEXT):
    987         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/mutex/upp.cc
    988 
    989 mutex-go$(EXEEXT):
    990         $(BENCH_V_GOC)go build -o a.out $(srcdir)/mutex/goroutine.go
    991 
    992 mutex-rust$(EXEEXT):
    993         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/mutex/rust.rs
    994 
    995 mutex-java$(EXEEXT):
     902        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
     903
     904mutex-java_thread$(EXEEXT):
    996905        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    997         echo "#!/bin/sh" > a.out
    998         echo "java JavaThread" >> a.out
    999         chmod a+x a.out
    1000 
    1001 schedint$(EXEEXT) :             \
    1002         schedint-cfa1.run       \
    1003         schedint-cfa2.run       \
    1004         schedint-cfa4.run       \
    1005         schedint-upp.run        \
    1006         schedint-rust.run       \
    1007         schedint-java.run       \
    1008         schedint-pthread.run
    1009 
    1010 schedint-cfa1$(EXEEXT):
    1011         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa1.cfa
    1012 
    1013 schedint-cfa2$(EXEEXT):
    1014         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa2.cfa
    1015 
    1016 schedint-cfa4$(EXEEXT):
    1017         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa4.cfa
    1018 
    1019 schedint-upp$(EXEEXT):
    1020         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedint/upp.cc
    1021 
    1022 schedint-rust$(EXEEXT):
    1023         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/schedint/rust.rs
    1024 
    1025 schedint-java$(EXEEXT):
     906        @echo "#!/bin/sh" > a.out
     907        @echo "java JavaThread" >> a.out
     908        @chmod a+x a.out
     909
     910signal$(EXEEXT) :\
     911        signal-pthread_cond.run \
     912        signal-upp.run          \
     913        signal-cfa1.run         \
     914        signal-cfa2.run         \
     915        signal-cfa4.run         \
     916        signal-java_thread.run
     917
     918signal-pthread_cond$(EXEEXT):
     919        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
     920
     921signal-upp$(EXEEXT):
     922        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
     923
     924signal-cfa1$(EXEEXT):
     925        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
     926
     927signal-cfa2$(EXEEXT):
     928        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
     929
     930signal-cfa4$(EXEEXT):
     931        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
     932
     933signal-java_thread$(EXEEXT):
    1026934        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    1027         echo "#!/bin/sh" > a.out
    1028         echo "java JavaThread" >> a.out
    1029         chmod a+x a.out
    1030 
    1031 schedint-pthread$(EXEEXT):
    1032         $(BENCH_V_CC)$(COMPILE) $(srcdir)/schedint/pthreads.c
    1033 
    1034 schedext$(EXEEXT) :             \
    1035         schedext-cfa1.run       \
    1036         schedext-cfa2.run       \
    1037         schedext-cfa4.run       \
    1038         schedext-upp.run        \
    1039         schedext-goroutine.run
    1040 
    1041 schedext-cfa1$(EXEEXT):
    1042         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa1.cfa
    1043 
    1044 schedext-cfa2$(EXEEXT):
    1045         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa2.cfa
    1046 
    1047 schedext-cfa4$(EXEEXT):
    1048         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa4.cfa
    1049 
    1050 schedext-upp$(EXEEXT):
    1051         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedext/upp.cc
    1052 
    1053 schedext-goroutine$(EXEEXT):
    1054         $(BENCH_V_GOC)go build -o a.out $(srcdir)/schedext/goroutine.go
    1055 
    1056 creation$(EXEEXT) :                             \
    1057         creation-cfa_generator.run              \
     935        @echo "#!/bin/sh" > a.out
     936        @echo "java JavaThread" >> a.out
     937        @chmod a+x a.out
     938
     939waitfor$(EXEEXT) :\
     940        waitfor-upp.run         \
     941        waitfor-cfa1.run                \
     942        waitfor-cfa2.run                \
     943        waitfor-cfa4.run
     944
     945waitfor-upp$(EXEEXT):
     946        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
     947
     948waitfor-cfa1$(EXEEXT):
     949        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
     950
     951waitfor-cfa2$(EXEEXT):
     952        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
     953
     954waitfor-cfa4$(EXEEXT):
     955        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
     956
     957creation$(EXEEXT) :\
     958        creation-pthread.run                    \
    1058959        creation-cfa_coroutine.run              \
    1059960        creation-cfa_coroutine_eager.run        \
     
    1061962        creation-upp_coroutine.run              \
    1062963        creation-upp_thread.run                 \
    1063         creation-python_coroutine.run           \
    1064         creation-nodejs_coroutine.run           \
    1065         creation-goroutine_thread.run           \
    1066         creation-rust_thread.run                \
    1067         creation-java_thread.run                \
    1068         creation-pthread.run
    1069 
    1070 creation-cfa_generator$(EXEEXT):
    1071         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_gen.cfa
     964        creation-goroutine.run                  \
     965        creation-java_thread.run
    1072966
    1073967creation-cfa_coroutine$(EXEEXT):
    1074         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa
     968        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
    1075969
    1076970creation-cfa_coroutine_eager$(EXEEXT):
    1077         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     971        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    1078972
    1079973creation-cfa_thread$(EXEEXT):
    1080         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_thrd.cfa
     974        $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
    1081975
    1082976creation-upp_coroutine$(EXEEXT):
    1083         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_cor.cc
     977        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
    1084978
    1085979creation-upp_thread$(EXEEXT):
    1086         $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_thrd.cc
    1087 
    1088 creation-python_coroutine$(EXEEXT):
    1089         $(BENCH_V_PY)echo "#!/bin/sh" > a.out
    1090         echo "python3.7 $(srcdir)/creation/python_cor.py" >> a.out
    1091         chmod a+x a.out
    1092 
    1093 creation-nodejs_coroutine$(EXEEXT):
    1094         $(BENCH_V_NODEJS)echo "#!/bin/sh" > a.out
    1095         echo "nodejs $(srcdir)/creation/node_cor.js" >> a.out
    1096         chmod a+x a.out
    1097 
    1098 creation-goroutine_thread$(EXEEXT):
     980        $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
     981
     982creation-pthread$(EXEEXT):
     983        $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
     984
     985creation-goroutine$(EXEEXT):
    1099986        $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
    1100 
    1101 creation-rust_thread$(EXEEXT):
    1102         $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/creation/rust_thrd.rs
    1103987
    1104988creation-java_thread$(EXEEXT):
    1105989        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    1106         echo "#!/bin/sh" > a.out
    1107         echo "java JavaThread" >> a.out
    1108         chmod a+x a.out
    1109 
    1110 creation-pthread$(EXEEXT):
    1111         $(BENCH_V_CC)$(COMPILE) $(srcdir)/creation/pthreads.c
    1112 
    1113 compile$(EXEEXT) :              \
     990        @echo "#!/bin/sh" > a.out
     991        @echo "java JavaThread" >> a.out
     992        @chmod a+x a.out
     993
     994compile$(EXEEXT) :\
    1114995        compile-array.make      \
    1115996        compile-attributes.make \
     
    11221003
    11231004compile-array$(EXEEXT):
    1124         $(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     1005        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    11251006
    11261007compile-attributes$(EXEEXT):
    1127         $(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     1008        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    11281009
    11291010compile-empty$(EXEEXT):
    1130         $(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     1011        @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    11311012
    11321013compile-expression$(EXEEXT):
    1133         $(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     1014        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    11341015
    11351016compile-io$(EXEEXT):
    1136         $(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     1017        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    11371018
    11381019compile-monitor$(EXEEXT):
    1139         $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     1020        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    11401021
    11411022compile-operators$(EXEEXT):
    1142         $(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     1023        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    11431024
    11441025compile-thread$(EXEEXT):
    1145         $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     1026        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    11461027
    11471028compile-typeof$(EXEEXT):
    1148         $(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    1149 
    1150 size$(EXEEXT) : size-cfa.runquiet
    1151 
    1152 size-cfa$(EXEEXT):
    1153         $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/size/size.cfa
     1029        @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
    11541030
    11551031# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • benchmark/bench.h

    r7030dab r71d6bd8  
    55#endif
    66        #include <stdlib.h>
    7         #include <stdint.h>                             // uint64_t
    8         #include <unistd.h>                             // sysconf
     7        #include <unistd.h>                                     // sysconf
    98#if ! defined(__cforall)
    109        #include <time.h>
     
    1615
    1716
    18 static inline uint64_t bench_time() {
    19         struct timespec ts;
    20         clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
    21         return 1000000000LL * ts.tv_sec + ts.tv_nsec;
    22 } // bench_time
     17static inline unsigned long long int bench_time() {
     18    struct timespec ts;
     19    clock_gettime(
     20#if defined( __linux__ )
     21         CLOCK_THREAD_CPUTIME_ID,
     22#elif defined( __freebsd__ )
     23         CLOCK_PROF,
     24#elif defined( __solaris__ )
     25         CLOCK_HIGHRES,
     26#else
     27    #error uC++ : internal error, unsupported architecture
     28#endif
     29         &ts );
     30    return 1000000000LL * ts.tv_sec + ts.tv_nsec;
     31} // Time
    2332
    2433#ifndef BENCH_N
    25 #define BENCH_N 10000000
     34#define BENCH_N 500 //10000000
    2635#endif
    2736
    28 size_t times = BENCH_N;
    29 
    30 #define BENCH_START()                           \
    31         if ( argc > 2 ) exit( EXIT_FAILURE );   \
    32         if ( argc == 2 ) {                      \
    33                 times = atoi( argv[1] );        \
    34         }
    35 
    3637#define BENCH(statement, output)                \
    37         uint64_t StartTime, EndTime;            \
     38        size_t n = BENCH_N;                     \
     39        if( argc > 2 ) return 1;                \
     40        if( argc == 2 ) {                               \
     41                n = atoi(argv[1]);              \
     42        }                                               \
     43        long long int StartTime, EndTime;       \
    3844        StartTime = bench_time();               \
    39         statement;                              \
     45        statement;                                      \
    4046        EndTime = bench_time();                 \
    41         double output = (double)( EndTime - StartTime ) / times;
    42 
     47        double output =         \
     48            (double)( EndTime - StartTime ) / n;
    4349
    4450#if defined(__cforall)
     
    4753}
    4854#endif
    49 #if defined(__U_CPLUSPLUS__)
    50 unsigned int uDefaultPreemption() {
    51         return 0;
    52 }
    53 #endif
  • benchmark/creation/JavaThread.java

    r7030dab r71d6bd8  
    2626        static int x = 2;
    2727
    28         static private int times = Integer.parseInt("10000") ;
     28        static private final int NoOfTimes = Integer.parseInt("10000") ;
    2929
    3030        public static class MyThread extends Thread {
     
    3333        }
    3434        public static void helper() throws InterruptedException {
    35                 for(int i = 1; i <= times; i += 1) {
     35                for(int i = 1; i <= NoOfTimes; i += 1) {
    3636                        MyThread m = new MyThread();
    3737                        x = nextRandom( x );
     
    4444                helper();
    4545                long end = System.nanoTime();
    46                 System.out.println( (end - start) / times );
     46                System.out.println( (end - start) / NoOfTimes );
    4747        }
    4848        public static void main(String[] args) throws InterruptedException {
    49                 if ( args.length > 2 ) System.exit( 1 );
    50                 if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    51 
    52                 for (int i = Integer.parseInt("5"); --i >= 0 ; ) {
     49                for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
    5350                        InnerMain();
    54                         Thread.sleep(2000);             // 2 seconds
     51                        Thread.sleep(2000);     // 2 seconds
    5552                        x = nextRandom(x);
    5653                }
     
    5855        }
    5956}
    60 
    61 // Local Variables: //
    62 // tab-width: 4 //
    63 // End: //
  • benchmark/creation/cfa_cor.cfa

    r7030dab r71d6bd8  
    55
    66coroutine MyCoroutine {};
    7 void ?{}( MyCoroutine & this ) {
     7void ?{} (MyCoroutine & this) {
    88#ifdef EAGER
    9         resume( this );
     9        resume(this);
    1010#endif
    1111}
    12 void main( MyCoroutine & ) {}
     12void main(MyCoroutine &) {}
    1313
    14 int main( int argc, char * argv[] ) {
    15         BENCH_START()
     14int main(int argc, char* argv[]) {
    1615        BENCH(
    17                 for ( times ) {
    18                         MyCoroutine c;
     16                for ( i; n ) {
     17                        MyCoroutine m;
    1918                },
    2019                result
    2120        )
    22         printf( "%g\n", result );
     21
     22        printf("%g\n", result);
    2323}
    24 
    25 // Local Variables: //
    26 // tab-width: 4 //
    27 // End: //
  • benchmark/creation/cfa_thrd.cfa

    r7030dab r71d6bd8  
    77void main(MyThread &) {}
    88
    9 int main( int argc, char * argv[] ) {
    10         BENCH_START()
     9int main(int argc, char* argv[]) {
    1110        BENCH(
    12                 for ( times ) {
     11                for ( i; n ) {
    1312                        MyThread m;
    1413                },
    1514                result
    1615        )
    17         printf( "%g\n", result );
     16
     17        printf("%g\n", result);
    1818}
    19 
    20 // Local Variables: //
    21 // tab-width: 4 //
    22 // End: //
  • benchmark/creation/goroutine.go

    r7030dab r71d6bd8  
    22
    33import (
    4         "fmt"
    5         "time"
    6         "os"
    7         "strconv"
     4    "fmt"
     5    "time"
    86)
    97
     
    1917
    2018func main() {
    21         var times int = 10000000
    22         if len( os.Args ) > 2 { os.Exit( 1 ) }
    23         if len( os.Args ) == 2 { times, _ = strconv.Atoi(os.Args[1]) }
    24 
     19        const NoOfTimes = 500000
    2520        start := time.Now()
    26         for i := 1; i <= times; i += 1 {
     21        for i := 1; i <= NoOfTimes; i += 1 {
    2722                go noop()               // creation
    28                 <- shake                // wait for completion
    2923        }
    3024        end := time.Now()
    31         fmt.Printf( "%d\n", end.Sub(start) / time.Duration(times) )
     25        fmt.Printf("%d\n", end.Sub(start) / time.Duration(NoOfTimes))
     26        <- shake
    3227}
    33 
    34 // Local Variables: //
    35 // tab-width: 4 //
    36 // End: //
  • benchmark/creation/pthreads.c

    r7030dab r71d6bd8  
    44#include "bench.h"
    55
    6 static void * foo(void *arg) {
     6static void *foo(void *arg) {
    77    return arg;
    88}
    99
    10 int main( int argc, char * argv[] ) {
    11         BENCH_START()
     10int main(int argc, char* argv[]) {
    1211        BENCH(
    13                 for (size_t i = 0; i < times; i++) {
     12                for (size_t i = 0; i < n; i++) {
    1413                        pthread_t thread;
    1514                        if (pthread_create(&thread, NULL, foo, NULL) < 0) {
     
    1716                                return 1;
    1817                        }
     18
    1919                        if (pthread_join( thread, NULL) < 0) {
    2020                                perror( "failure" );
     
    2424                result
    2525        )
    26         printf( "%g\n", result );
     26
     27        printf("%g\n", result);
    2728}
    28 
    29 // Local Variables: //
    30 // tab-width: 4 //
    31 // End: //
  • benchmark/creation/upp_cor.cc

    r7030dab r71d6bd8  
    55_Coroutine MyCor {
    66        void main() {}
    7   public:
    8         MyCor() { resume(); }
    97};
    108
    11 int main( int argc, char * argv[] ) {
    12         BENCH_START()
     9int main(int argc, char* argv[]) {
    1310        BENCH(
    14                 for (size_t i = 0; i < times; i++) {
     11                for (size_t i = 0; i < n; i++) {
    1512                        MyCor m;
    1613                },
    1714                result
    1815        )
    19         printf( "%g\n", result );
     16
     17        printf("%g\n", result);
    2018}
    21 
    22 // Local Variables: //
    23 // tab-width: 4 //
    24 // End: //
  • benchmark/creation/upp_thrd.cc

    r7030dab r71d6bd8  
    77};
    88
    9 int main( int argc, char * argv[] ) {
    10         BENCH_START()
     9int main(int argc, char* argv[]) {
    1110        BENCH(
    12                 for (size_t i = 0; i < times; i++) {
     11                for (size_t i = 0; i < n; i++) {
    1312                        MyThread m;
    1413                },
    1514                result
    1615        )
    17         printf( "%g\n", result );
     16
     17        printf("%g\n", result);
    1818}
    19 
    20 // Local Variables: //
    21 // tab-width: 4 //
    22 // End: //
  • benchmark/ctxswitch/JavaThread.java

    r7030dab r71d6bd8  
    2626        static int x = 2;
    2727
    28         static private int times = Integer.parseInt("100000");
     28        static private final int NoOfTimes = Integer.parseInt("1000000") ;
    2929
    3030        public static void helper() {
    31                 for(int i = 1; i <= times; i += 1) {
     31                for(int i = 1; i <= NoOfTimes; i += 1) {
    3232                        Thread.yield();
    3333                }
     
    3737                helper();
    3838                long end = System.nanoTime();
    39                 System.out.println( (end - start) / times );
     39                System.out.println( (end - start) / NoOfTimes );
    4040        }
    4141        public static void main(String[] args) throws InterruptedException {
    42                 if ( args.length > 2 ) System.exit( 1 );
    43                 if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    44 
    45                 for (int i = Integer.parseInt("5"); --i >= 0 ; ) {
     42                for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
    4643                        InnerMain();
    47                         Thread.sleep(2000);     // 2 seconds
     44                        Thread.sleep(2000);     // 2 seconds
    4845                        x = nextRandom(x);
    4946                }
     
    5148        }
    5249}
    53 
    54 // Local Variables: //
    55 // tab-width: 4 //
    56 // End: //
  • benchmark/ctxswitch/cfa_cor.cfa

    r7030dab r71d6bd8  
    22#include <thread.hfa>
    33
    4 #include "../bench.h"
     4#include "bench.h"
    55
    6 coroutine C {};
    7 void main( __attribute__((unused)) C & ) {
    8         for () {
    9                 suspend;
     6coroutine GreatSuspender {};
     7
     8void ?{}( GreatSuspender & this ) {
     9        prime(this);
     10}
     11
     12void main( __attribute__((unused)) GreatSuspender & this ) {
     13        while( true ) {
     14                suspend();
    1015        }
    1116}
    12 int main( int argc, char * argv[] ) {
    13         C c;
    14         BENCH_START()
     17
     18int main(int argc, char* argv[]) {
     19        GreatSuspender s;
     20
    1521        BENCH(
    16                 for ( times ) {
    17                         resume( c );
     22                for ( i; n ) {
     23                        resume( s );
    1824                },
    1925                result
    2026        )
    21         printf( "%g\n", result );
     27
     28        printf("%g\n", result);
    2229}
    23 
    24 // Local Variables: //
    25 // tab-width: 4 //
    26 // End: //
  • benchmark/ctxswitch/cfa_cor_then.cfa

    r7030dab r71d6bd8  
    66void noOp(void) {}
    77
    8 coroutine C {} c;
     8coroutine GreatSuspender {};
    99
    10 void ?{}( C & this ) {
     10void ?{}( GreatSuspender & this ) {
    1111        prime(this);
    1212}
    1313
    14 void main( __attribute__((unused)) C & this ) {
    15         while () {
     14void main( __attribute__((unused)) GreatSuspender & this ) {
     15        while( true ) {
    1616                suspend_then(noOp);
    1717        }
    1818}
    1919
    20 int main( int argc, char * argv[] ) {
    21         BENCH_START()
     20int main(int argc, char* argv[]) {
     21        GreatSuspender s;
     22
    2223        BENCH(
    23                 for ( times ) {
    24                         resume( c );
     24                for ( i; n ) {
     25                        resume( s );
    2526                },
    2627                result
    2728        )
    28         printf( "%g\n", result );
     29
     30        printf("%g\n", result);
    2931}
    30 
    31 // Local Variables: //
    32 // tab-width: 4 //
    33 // End: //
  • benchmark/ctxswitch/cfa_gen.cfa

    r7030dab r71d6bd8  
    11#include "../bench.h"
    22
    3 generator G {};
    4 void main( G & ) {
     3typedef struct {
     4        void * next;
     5} GreatSuspender;
     6
     7void comain( GreatSuspender * this ) {
     8    if ( __builtin_expect(this->next != 0, 1) ) goto *(this->next);
     9    this->next = &&s1;
    510        for () {
    6                 suspend;
     11            return;
     12          s1: ;
    713        }
    814}
    915
    10 int main( int argc, char * argv[] ) {
    11         G g;
    12         BENCH_START()
     16int main(int argc, char* argv[]) {
     17    GreatSuspender s = { 0 };
     18
    1319        BENCH(
    14                 for ( times ) {
    15                         resume( g );
     20                for ( i; n ) {
     21                        comain( &s );
    1622                },
    1723                result
    1824        )
    19         printf( "%g\n", result );
     25
     26        printf("%g\n", result);
    2027}
    21 
    22 // Local Variables: //
    23 // tab-width: 4 //
    24 // End: //
  • benchmark/ctxswitch/cfa_thrd.cfa

    r7030dab r71d6bd8  
    33#include "bench.h"
    44
    5 int main( int argc, char * argv[] ) {
    6         BENCH_START()
     5int main(int argc, char* argv[]) {
    76        BENCH(
    8                 for ( times ) {
     7                for ( i; n ) {
    98                        yield();
    109                },
    1110                result
    1211        )
    13         printf( "%g\n", result );
     12
     13        printf("%g\n", result);
    1414}
    15 
    16 // Local Variables: //
    17 // tab-width: 4 //
    18 // End: //
  • benchmark/ctxswitch/cfa_thrd2.cfa

    r7030dab r71d6bd8  
    88
    99void main(__attribute__((unused)) Fibre & this) {
    10         while ( ! done ) {
     10        while(!done) {
    1111                yield();
    1212        }
    1313}
    1414
    15 int main( int argc, char * argv[] ) {
    16         BENCH_START()
     15int main(int argc, char* argv[]) {
    1716        Fibre f1;
    1817        BENCH(
    19                 for ( times ) {
     18                for ( i; n ) {
    2019                        yield();
    2120                },
    2221                result
    2322        )
    24         printf( "%g\n", result );
     23
     24        printf("%g\n", result);
    2525        done = true;
     26        return 0;
    2627}
    27 
    28 // Local Variables: //
    29 // tab-width: 4 //
    30 // End: //
  • benchmark/ctxswitch/goroutine.go

    r7030dab r71d6bd8  
    22
    33import (
    4         "fmt"
    5         "time"
    6         "os"
    7         "strconv"
    8         "runtime"
     4    "fmt"
     5    "runtime"
     6    "time"
    97)
    108
     
    3028
    3129func main() {
    32         var times int = 10000000
    33         if len( os.Args ) > 2 { os.Exit( 1 ) }
    34         if len( os.Args ) == 2 { times, _ = strconv.Atoi(os.Args[1]) }
    35         go ContextSwitch( times )               // context switch
     30        const NoOfTimes = 10000000
     31        go ContextSwitch( NoOfTimes )           // context switch
    3632        <- shake
    3733}
    38 
    39 // Local Variables: //
    40 // tab-width: 4 //
    41 // End: //
  • benchmark/ctxswitch/kos_fibre.cpp

    r7030dab r71d6bd8  
    33#include "bench.h"
    44
    5 int main( int argc, char * argv[] ) {
    6         BENCH_START()
     5int main(int argc, char* argv[]) {
    76        BENCH(
    8                 for (size_t i = 0; i < times; i++) {
     7                for (size_t i = 0; i < n; i++) {
    98                        Fibre::yield();
    109                },
    1110                result
    1211        )
    13         printf( "%g\n", result );
     12        printf("%g\n", result);
     13        return 0;
    1414}
    15 
    16 // Local Variables: //
    17 // tab-width: 4 //
    18 // End: //
  • benchmark/ctxswitch/kos_fibre2.cpp

    r7030dab r71d6bd8  
    1111}
    1212
    13 int main( int argc, char * argv[] ) {
    14         BENCH_START()
     13int main(int argc, char* argv[]) {
    1514        Fibre* f1 = (new Fibre)->run(f1main);
    1615        BENCH(
    17                 for (size_t i = 0; i < times; i++) {
     16                for (size_t i = 0; i < n; i++) {
    1817                        Fibre::yield();
    1918                },
    2019                result
    2120        )
    22         printf( "%g\n", result );
     21        printf("%g\n", result);
    2322        done = true;
    2423        Fibre::yield();
    2524        f1->join();
     25        return 0;
    2626}
    27 
    28 // Local Variables: //
    29 // tab-width: 4 //
    30 // End: //
  • benchmark/ctxswitch/pthreads.c

    r7030dab r71d6bd8  
    66#include "bench.h"
    77
    8 int main( int argc, char * argv[] ) {
    9         BENCH_START()
     8int main(int argc, char* argv[]) {
    109        BENCH(
    11                 for (size_t i = 0; i < times; i++) {
     10                for (size_t i = 0; i < n; i++) {
    1211                        sched_yield();
    1312                },
    1413                result
    1514        )
    16         printf( "%g\n", result );
     15
     16        printf("%g\n", result);
    1717}
  • benchmark/ctxswitch/upp_cor.cc

    r7030dab r71d6bd8  
    33#include "bench.h"
    44
    5 _Coroutine C {
     5_Coroutine GreatSuspender {
     6public:
     7        GreatSuspender() {
     8                resume();
     9        }
     10
     11        void do_resume() {
     12                resume();
     13        }
     14private:
    615        void main() {
    716                while( true ) {
     
    918                }
    1019        }
    11   public:
    12         void do_resume() {
    13                 resume();
    14         }
    15 } c;
    16 int main( int argc, char * argv[] ) {
    17         BENCH_START()
     20};
     21
     22int main(int argc, char* argv[]) {
     23        GreatSuspender s;
     24
    1825        BENCH(
    19                 for (size_t i = 0; i < times; i++) {
    20                         c.do_resume();
     26                for (size_t i = 0; i < n; i++) {
     27                        s.do_resume();
    2128                },
    2229                result
    2330        )
    24         printf( "%g\n", result );
     31
     32        printf("%g\n", result);
    2533}
    26 
    27 // Local Variables: //
    28 // tab-width: 4 //
    29 // End: //
  • benchmark/ctxswitch/upp_thrd.cc

    r7030dab r71d6bd8  
    33#include "bench.h"
    44
    5 int main( int argc, char * argv[] ) {
    6         BENCH_START()
     5int main(int argc, char* argv[]) {
    76        BENCH(
    8                 for (size_t i = 0; i < times; i++) {
     7                for (size_t i = 0; i < n; i++) {
    98                        uThisTask().yield();
    109                },
    1110                result
    1211        )
    13         printf( "%g\n", result );
     12
     13        printf("%g\n", result);
    1414}
    15 
    16 // Local Variables: //
    17 // tab-width: 4 //
    18 // End: //
  • benchmark/mutex/JavaThread.java

    r7030dab r71d6bd8  
    2626        static int x = 2;
    2727
    28         static private int times = Integer.parseInt("100000000");
     28        static private final int NoOfTimes = Integer.parseInt("100000000") ;
    2929
    3030        public synchronized void noop() {
     
    3535                // Inhibit biased locking ...
    3636                x = (j.hashCode() ^ System.identityHashCode(j)) | 1 ;     
    37                 for(int i = 1; i <= times; i += 1) {
     37                for(int i = 1; i <= NoOfTimes; i += 1) {
    3838                        x = nextRandom(x);
    3939                        j.noop();
     
    4444                helper();
    4545                long end = System.nanoTime();
    46                 System.out.println( (end - start) / times );
     46                System.out.println( (end - start) / NoOfTimes );
    4747        }
    4848        public static void main(String[] args) throws InterruptedException {
    49                 if ( args.length > 2 ) System.exit( 1 );
    50                 if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    51 
    5249                for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
    5350                        InnerMain();
     
    5855        }
    5956}
    60 
    61 // Local Variables: //
    62 // tab-width: 4 //
    63 // End: //
  • benchmark/mutex/cfa1.cfa

    r7030dab r71d6bd8  
    44#include "bench.h"
    55
    6 monitor M {} m1;
    7 void __attribute__((noinline)) call( M & mutex p1 ) {}
     6monitor M {};
     7void __attribute__((noinline)) call( M & mutex m ) {}
    88
    9 int main( int argc, char * argv[] ) {
    10         BENCH_START()
     9int main(int argc, char* argv[]) {
     10        M m;
    1111        BENCH(
    12                 for ( times ) {
    13                         call( m1 );
     12                for ( i; n ) {
     13                        call(m);
    1414                },
    1515                result
    1616        )
    17         printf( "%g\n", result );
     17
     18        printf("%g\n", result);
    1819}
    19 
    20 // Local Variables: //
    21 // tab-width: 4 //
    22 // End: //
  • benchmark/mutex/cfa2.cfa

    r7030dab r71d6bd8  
    44#include "bench.h"
    55
    6 monitor M {} m1, m2;
     6monitor M {};
     7void __attribute__((noinline)) call( M & mutex m1, M & mutex m2 ) {}
    78
    8 void __attribute__((noinline)) call( M & mutex p1, M & mutex p2 ) {}
    9 
    10 int main( int argc, char * argv[] ) {
    11         BENCH_START()
     9int main(int argc, char* argv[]) {
     10        M m1, m2;
    1211        BENCH(
    13                 for ( times ) {
    14                         call( m1, m2 );
     12                for ( i; n ) {
     13                        call(m1, m2);
    1514                },
    1615                result
    1716        )
    18         printf( "%g\n", result );
     17
     18        printf("%g\n", result);
    1919}
    20 
    21 // Local Variables: //
    22 // tab-width: 4 //
    23 // End: //
  • benchmark/mutex/cfa4.cfa

    r7030dab r71d6bd8  
    55
    66
    7 monitor M {} m1, m2, m3, m4;
    8 void __attribute__((noinline)) call( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {}
     7monitor M {};
     8void __attribute__((noinline)) call( M & mutex m1, M & mutex m2, M & mutex m3, M & mutex m4 ) {}
    99
    10 int main( int argc, char * argv[] ) {
    11         BENCH_START()
     10int main(int argc, char* argv[]) {
     11        M m1, m2, m3, m4;
    1212        BENCH(
    13                 for ( times ) {
    14                         call( m1, m2, m3, m4 );
     13                for ( i; n ) {
     14                        call(m1, m2, m3, m4);
    1515                },
    1616                result
    1717        )
    18         printf( "%g\n", result );
     18
     19        printf("%g\n", result);
    1920}
    20 
    21 // Local Variables: //
    22 // tab-width: 4 //
    23 // End: //
  • benchmark/mutex/pthreads.c

    r7030dab r71d6bd8  
    77
    88void __attribute__((noinline)) call() {
    9          pthread_mutex_lock( &mutex );
    10          pthread_mutex_unlock( &mutex );
     9         pthread_mutex_lock  (&mutex);
     10         pthread_mutex_unlock(&mutex);
    1111}
    12 int main( int argc, char * argv[] ) {
    13         BENCH_START()
     12
     13int main(int argc, char* argv[]) {
    1414        BENCH(
    15                 for ( size_t i = 0; i < times; i++ ) {
     15                for (size_t i = 0; i < n; i++) {
    1616                        call();
    1717                },
    1818                result
    1919        )
    20         printf( "%g\n", result );
     20
     21        printf("%g\n", result);
    2122}
    22 
    23 // Local Variables: //
    24 // tab-width: 4 //
    25 // End: //
  • benchmark/mutex/upp.cc

    r7030dab r71d6bd8  
    88};
    99
    10 int main( int argc, char * argv[] ) {
    11         BENCH_START()
     10int main(int argc, char* argv[]) {
    1211        MyMonitor m;
    1312        BENCH(
    14                 for ( size_t i = 0; i < times; i++ ) {
     13                for (size_t i = 0; i < n; i++) {
    1514                        m.call();
    1615                },
    1716                result
    1817        )
    19         printf( "%g\n", result );
     18
     19        printf("%g\n", result);
    2020}
    21 
    22 // Local Variables: //
    23 // tab-width: 4 //
    24 // End: //
  • benchmark/schedext/cfa1.cfa

    r7030dab r71d6bd8  
    44#include <stdio.h>
    55
    6 #include "../bench.h"
     6#include "bench.h"
    77
    8 monitor M {} m1;
     8int argc;
     9char** argv;
     10volatile int go = 0;
    911
    10 void __attribute__((noinline)) call( M & mutex p1 ) {}
    11 void __attribute__((noinline)) wait( M & mutex p1 ) {
    12         for ( times ) {
    13                 waitfor( call : p1 );
    14         }
     12monitor M {};
     13M m1;
     14
     15void __attribute__((noinline)) call( M & mutex a1 ) {}
     16
     17int  __attribute__((noinline)) wait( M & mutex a1 ) {
     18        go = 1;
     19        BENCH(
     20                for ( i; n ) {
     21                        waitfor(call, a1);
     22                },
     23                result
     24        )
     25
     26        printf("%g\n", result);
     27        go = 0;
     28        return 0;
    1529}
    1630
    1731thread T {};
     32void ^?{}( T & mutex this ) {}
    1833void main( T & ) {
    19         BENCH(
    20                 for ( times ) { call( m1 ); },
    21                 result
    22         )
    23         printf( "%g\n", result );
     34        while(go == 0) { yield(); }
     35        while(go == 1) { call(m1); }
     36
    2437}
    2538
    26 int main( int argc, char * argv[] ) {
    27         BENCH_START()
     39int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    2840        T t;
    29         wait( m1 );
     41        return wait(m1);
    3042}
    31 
    32 // Local Variables: //
    33 // tab-width: 4 //
    34 // End: //
  • benchmark/schedext/cfa2.cfa

    r7030dab r71d6bd8  
    44#include <stdio.h>
    55
    6 #include "../bench.h"
     6#include "bench.h"
    77
    8 monitor M {} m1, m2;
     8int argc;
     9char** argv;
     10volatile int go = 0;
    911
    10 void __attribute__((noinline)) call( M & mutex p1, M & mutex p2 ) {}
    11 void __attribute__((noinline)) wait( M & mutex p1, M & mutex p2 ) {
    12         for ( times ) {
    13                 waitfor( call : p1, p2 );
    14         }
    15 }
    16 thread T {};
    17 void main( T & ) {
     12monitor M {};
     13M m1, m2;
     14
     15void __attribute__((noinline)) call( M & mutex a1, M & mutex a2 ) {}
     16
     17int  __attribute__((noinline)) wait( M & mutex a1, M & mutex a2 ) {
     18        go = 1;
    1819        BENCH(
    19                 for ( times ) {
    20                         call( m1, m2 );
     20                for ( i; n ) {
     21                        waitfor(call, a1, a2);
    2122                },
    2223                result
    2324        )
    24         printf( "%g\n", result );
     25
     26        printf("%g\n", result);
     27        go = 0;
     28        return 0;
    2529}
    2630
    27 int main( int argc, char * argv[] ) {
    28         BENCH_START()
    29         T t;
    30         wait( m1, m2 );
     31thread T {};
     32void ^?{}( T & mutex this ) {}
     33void main( T & ) {
     34        while(go == 0) { yield(); }
     35        while(go == 1) { call(m1, m2); }
     36
    3137}
    3238
    33 // Local Variables: //
    34 // tab-width: 4 //
    35 // End: //
     39int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     40        T t;
     41        return wait(m1, m2);
     42}
  • benchmark/schedext/cfa4.cfa

    r7030dab r71d6bd8  
    44#include <stdio.h>
    55
    6 #include "../bench.h"
     6#include "bench.h"
    77
    8 monitor M {} m1, m2, m3, m4;
     8int argc;
     9char** argv;
     10volatile int go = 0;
    911
    10 void __attribute__((noinline)) call( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {}
    11 void __attribute__((noinline)) wait( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {
    12         for ( times ) {
    13                 waitfor( call : p1, p2, p3, p4 );
    14         }
    15 }
    16 thread T {};
    17 void main( T & ) {
     12monitor M {};
     13M m1, m2, m3, m4;
     14
     15void __attribute__((noinline)) call( M & mutex a1, M & mutex a2, M & mutex a3, M & mutex a4 ) {}
     16
     17int  __attribute__((noinline)) wait( M & mutex a1, M & mutex a2, M & mutex a3, M & mutex a4 ) {
     18        go = 1;
    1819        BENCH(
    19                 for ( times ) {
    20                         call( m1, m2, m3, m4 );
     20                for ( i; n ) {
     21                        waitfor(call, a1, a2, a3, a4);
    2122                },
    2223                result
    2324        )
    24         printf( "%g\n", result );
     25
     26        printf("%g\n", result);
     27        go = 0;
     28        return 0;
    2529}
    2630
    27 int main( int argc, char * argv[] ) {
    28         BENCH_START()
    29         T t;
    30         wait( m1, m2, m3, m4 );
     31thread T {};
     32void ^?{}( T & mutex this ) {}
     33void main( T & ) {
     34        while(go == 0) { yield(); }
     35        while(go == 1) { call(m1, m2, m3, m4); }
     36
    3137}
    3238
    33 // Local Variables: //
    34 // tab-width: 4 //
    35 // End: //
     39int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     40        T t;
     41        return wait(m1, m2, m3, m4);
     42}
  • benchmark/schedext/upp.cc

    r7030dab r71d6bd8  
    33#include "bench.h"
    44
     5int argc;
     6char** argv;
     7volatile int go = 0;
     8
    59_Monitor M {
    610public:
    711        void __attribute__((noinline)) call() {}
    8         void __attribute__((noinline)) wait() {
    9                 for ( size_t i = 0; i < times; i++ ) {
    10                         _Accept(call);
    11                 }
     12
     13        int __attribute__((noinline)) wait() {
     14                go = 1;
     15                BENCH(
     16                        for (size_t i = 0; i < n; i++) {
     17                                _Accept(call);
     18                        },
     19                        result
     20                )
     21
     22                printf("%g\n", result);
     23                go = 0;
     24                return 0;
    1225        }
    13 } m;
     26};
     27
     28M m;
    1429
    1530_Task T {
    1631        void main() {
    17                 BENCH(
    18                         for ( size_t i = 0; i < times; i++ ) {
    19                                 m.call();
    20                         },
    21                         result
    22                 )
    23                 printf( "%g\n", result );
     32                while(go == 0) { yield(); }
     33                while(go == 1) { m.call(); }
     34
    2435        }
    2536};
    2637
    27 int main( int argc, char * argv[] ) {
    28         BENCH_START()
     38int main(int margc, char* margv[]) {
     39        argc = margc;
     40        argv = margv;
    2941        T t;
    30         m.wait();
     42        return m.wait();
    3143}
    32 
    33 // Local Variables: //
    34 // tab-width: 4 //
    35 // End: //
  • benchmark/schedint/JavaThread.java

    r7030dab r71d6bd8  
    4949        static int x = 2;
    5050
    51         static private int times = Integer.parseInt("1000000");
     51        static private final int NoOfTimes = Integer.parseInt("1000000") ;
    5252
    5353        public static void helper( Monitor m ) throws InterruptedException {
    54                 for(int i = 1; i <= times; i += 1) {
     54                for(int i = 1; i <= NoOfTimes; i += 1) {
    5555                        m.wait();               // relase monitor lock
    5656                        m.next = true;
     
    6363                synchronized(m) {
    6464                        s.start();
    65                         while( ! Monitor.go ) { // waiter must start first
     65                        while( !Monitor.go ) {
    6666                                Thread.yield();
    6767                        }
     
    7272                Monitor.go = false;
    7373                s.join();
    74                 System.out.println( (end - start) / times);
     74                System.out.println( (end - start) / NoOfTimes);
    7575        }
    7676        public static void main(String[] args) throws InterruptedException {
    77                 if ( args.length > 2 ) System.exit( 1 );
    78                 if ( args.length == 2 ) { times = Integer.parseInt(args[1]); }
    79 
    8077                for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
    8178                        InnerMain();
     
    8683        }
    8784}
    88 
    89 // Local Variables: //
    90 // tab-width: 4 //
    91 // End: //
  • benchmark/schedint/cfa1.cfa

    r7030dab r71d6bd8  
    44#include <stdio.h>
    55
    6 #include "../bench.h"
     6#include "bench.h"
    77
     8int argc;
     9char** argv;
    810volatile int go = 0;
    911
    1012condition c;
    11 monitor M {} m1;
     13monitor M {};
     14M m1;
    1215
    13 void __attribute__((noinline)) call( M & mutex p1 ) {
    14         signal( c );
     16void __attribute__((noinline)) call( M & mutex a1 ) {
     17        signal(c);
    1518}
    16 void __attribute__((noinline)) wait( M & mutex p1 ) {
     19
     20int  __attribute__((noinline)) wait( M & mutex a1 ) {
    1721        go = 1;
    18         for ( times ) {
    19                 wait( c );
    20         }
     22        BENCH(
     23                for ( i; n ) {
     24                        wait(c);
     25                },
     26                result
     27        )
     28
     29        printf("%g\n", result);
     30        go = 0;
     31        return 0;
    2132}
    2233
    2334thread T {};
     35void ^?{}( T & mutex ) {}
    2436void main( T & ) {
    25         while ( go == 0 ) { yield(); } // waiter must start first
    26         BENCH(
    27                 for ( times ) { call( m1 ); },
    28                 result
    29         )
    30         printf( "%g\n", result );
     37        while(go == 0) { yield(); }
     38        while(go == 1) { call(m1); }
     39
    3140}
    3241
    33 int main( int argc, char * argv[] ) {
    34         BENCH_START()
     42int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    3543        T t;
    36         wait( m1 );
     44        return wait(m1);
    3745}
    38 
    39 // Local Variables: //
    40 // tab-width: 4 //
    41 // End: //
  • benchmark/schedint/cfa2.cfa

    r7030dab r71d6bd8  
    44#include <stdio.h>
    55
    6 #include "../bench.h"
     6#include "bench.h"
    77
     8int argc;
     9char** argv;
    810volatile int go = 0;
    911
    1012condition c;
    11 monitor M {} m1, m2;
     13monitor M {};
     14M m1, m2;
    1215
    13 void __attribute__((noinline)) call( M & mutex p1, M & mutex p2 ) {
    14         signal( c );
     16void __attribute__((noinline)) call( M & mutex a1, M & mutex a2 ) {
     17        signal(c);
    1518}
    16 void __attribute__((noinline)) wait( M & mutex p1, M & mutex p2 ) {
     19
     20int  __attribute__((noinline)) wait( M & mutex a1, M & mutex a2 ) {
    1721        go = 1;
    18         for ( times ) {
    19                 wait( c );
    20         }
     22        BENCH(
     23                for ( i; n ) {
     24                        wait(c);
     25                },
     26                result
     27        )
     28
     29        printf("%g\n", result);
     30        go = 0;
     31        return 0;
    2132}
    2233
    2334thread T {};
     35void ^?{}( T & mutex this ) {}
    2436void main( T & ) {
    25         while ( go == 0 ) { yield(); } // waiter must start first
    26         BENCH(
    27                 for ( times ) { call( m1, m2 ); },
    28                 result
    29         )
    30         printf( "%g\n", result );
     37        while(go == 0) { yield(); }
     38        while(go == 1) { call(m1, m2); }
     39
    3140}
    3241
    33 int main( int argc, char * argv[] ) {
    34         BENCH_START()
     42int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    3543        T t;
    36         wait( m1, m2 );
     44        return wait(m1, m2);
    3745}
    38 
    39 // Local Variables: //
    40 // tab-width: 4 //
    41 // End: //
  • benchmark/schedint/cfa4.cfa

    r7030dab r71d6bd8  
    44#include <stdio.h>
    55
    6 #include "../bench.h"
     6#include "bench.h"
    77
     8int argc;
     9char** argv;
    810volatile int go = 0;
    911
    1012condition c;
    11 monitor M {} m1, m2, m3, m4;
     13monitor M {};
     14M m1, m2, m3, m4;
    1215
    13 void __attribute__((noinline)) call( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {
    14         signal( c );
     16void __attribute__((noinline)) call( M & mutex a1, M & mutex a2, M & mutex a3, M & mutex a4 ) {
     17        signal(c);
    1518}
    16 void __attribute__((noinline)) wait( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {
     19
     20int  __attribute__((noinline)) wait( M & mutex a1, M & mutex a2, M & mutex a3, M & mutex a4 ) {
    1721        go = 1;
    18         for ( times ) {
    19                 wait( c );
    20         }
     22        BENCH(
     23                for ( i; n ) {
     24                        wait(c);
     25                },
     26                result
     27        )
     28
     29        printf("%g\n", result);
     30        go = 0;
     31        return 0;
    2132}
    2233
    2334thread T {};
     35void ^?{}( T & mutex this ) {}
    2436void main( T & ) {
    25         while ( go == 0 ) { yield(); } // waiter must start first
    26         BENCH(
    27                 for ( times ) { call( m1, m2, m3, m4 ); },
    28                 result
    29         )
    30         printf( "%g\n", result );
     37        while(go == 0) { yield(); }
     38        while(go == 1) { call(m1, m2, m3, m4); }
     39
    3140}
    3241
    33 int main( int argc, char * argv[] ) {
    34         BENCH_START()
     42int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    3543        T t;
    36         wait( m1, m2, m3, m4 );
     44        return wait(m1, m2, m3, m4);
    3745}
    38 
    39 // Local Variables: //
    40 // tab-width: 4 //
    41 // End: //
  • benchmark/schedint/pthreads.c

    r7030dab r71d6bd8  
    44#include "bench.h"
    55
     6int argc;
     7char** argv;
    68volatile int go = 0;
    79
     10pthread_cond_t c;
    811pthread_mutex_t m;
    9 pthread_cond_t c;
    1012
    1113void __attribute__((noinline)) call() {
    12         pthread_mutex_lock( &m );
    13         pthread_cond_signal( &c );
    14         pthread_mutex_unlock( &m );
     14        pthread_mutex_lock(&m);
     15        pthread_cond_signal(&c);
     16        pthread_mutex_unlock(&m);
    1517}
    1618
    17 void __attribute__((noinline)) wait() {
     19int __attribute__((noinline)) wait() {
    1820        pthread_mutex_lock(&m);
    1921        go = 1;
    20         for ( size_t i = 0; i < times; i++ ) {
    21                 pthread_cond_wait( &c, &m );
    22         }
     22        BENCH(
     23                for (size_t i = 0; i < n; i++) {
     24                        pthread_cond_wait(&c, &m);
     25                },
     26                result
     27        )
     28
     29        printf("%g\n", result);
    2330        go = 0;
    24         pthread_mutex_unlock( &m );
     31        pthread_mutex_unlock(&m);
     32        return 0;
    2533}
    2634
    27 void * thread_main( __attribute__((unused)) void * arg ) {
    28         while ( go == 0 ) { sched_yield(); } // waiter must start first
    29         // barging for lock acquire => may not execute N times
    30         BENCH(
    31                 while ( go == 1 ) { call(); },
    32                 result
    33         )
    34         printf( "%g\n", result );
     35void* thread_main(__attribute__((unused)) void * arg ) {
     36        while(go == 0) { sched_yield(); }
     37        while(go == 1) { call(); }
    3538        return NULL;
    3639}
    3740
    38 int main( int argc, char * argv[] ) {
    39         BENCH_START()
     41int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    4042        pthread_t thread;
    41         if ( pthread_create( &thread, NULL, thread_main, NULL ) < 0 ) {
     43        if (pthread_create(&thread, NULL, thread_main, NULL) < 0) {
    4244                perror( "failure" );
    4345                return 1;
    4446        }
    4547        wait();
    46         if ( pthread_join( thread, NULL ) < 0 ) {
     48        if (pthread_join( thread, NULL) < 0) {
    4749                perror( "failure" );
    4850                return 1;
    4951        }
     52        return 0;
    5053}
    51 
    52 // Local Variables: //
    53 // tab-width: 4 //
    54 // End: //
  • benchmark/schedint/upp.cc

    r7030dab r71d6bd8  
    33#include "bench.h"
    44
     5int argc;
     6char** argv;
    57volatile int go = 0;
    68
     
    1113                cond.signal();
    1214        }
    13         void __attribute__((noinline)) wait() {
     15
     16        int __attribute__((noinline)) wait() {
    1417                go = 1;
    15                 for ( size_t i = 0; i < times; i++ ) {
    16                         cond.wait();
    17                 }
     18                BENCH(
     19                        for (size_t i = 0; i < n; i++) {
     20                                cond.wait();
     21                        },
     22                        result
     23                )
     24
     25                printf("%g\n", result);
     26                go = 0;
     27                return 0;
    1828        }
    19 } m;
     29};
     30
     31M m;
    2032
    2133_Task T {
    2234        void main() {
    23                 while ( go == 0 ) { yield(); } // waiter must start first
    24                 BENCH(
    25                         for ( size_t i = 0; i < times; i++ ) {
    26                                 m.call();
    27                         },
    28                         result
    29                 )
    30                 printf( "%g\n", result );
     35                while(go == 0) { yield(); }
     36                while(go == 1) { m.call(); }
     37
    3138        }
    3239};
    3340
    34 int main( int argc, char * argv[] ) {
    35         BENCH_START()
     41int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    3642        T t;
    37         m.wait();
     43        return m.wait();
    3844}
    39 
    40 // Local Variables: //
    41 // tab-width: 4 //
    42 // End: //
  • configure

    r7030dab r71d6bd8  
    25572557# don't use the default CFLAGS as they unconditonnaly add -O2
    25582558: ${CFLAGS=""}
    2559 : ${CXXFLAGS=""}
    25602559
    25612560am__api_version='1.15'
  • configure.ac

    r7030dab r71d6bd8  
    1414# don't use the default CFLAGS as they unconditonnaly add -O2
    1515: ${CFLAGS=""}
    16 : ${CXXFLAGS=""}
    1716
    1817AM_INIT_AUTOMAKE([subdir-objects])
  • doc/bibliography/pl.bib

    r7030dab r71d6bd8  
    99%    Predefined journal names:
    1010%  acmcs: Computing Surveys             acta: Acta Infomatica
     11@string{acta="Acta Infomatica"}
    1112%  cacm: Communications of the ACM
    1213%  ibmjrd: IBM J. Research & Development ibmsj: IBM Systems Journal
     
    2122%  tcs: Theoretical Computer Science
    2223
    23 @string{acta="Acta Infomatica"}
    2424string{ieeepds="IEEE Transactions on Parallel and Distributed Systems"}
    2525@string{ieeepds="IEEE Trans. Parallel Distrib. Syst."}
     
    124124    series      = {ACM Distinguished Dissertations},
    125125    year        = 1983,
    126 }
    127 
    128 @article{Zhang19,
    129     keywords    = {Algebraic effects, dynamic scoping, exceptions, parametricity, type systems},
    130     author      = {Zhang, Yizhou and Myers, Andrew C.},
    131     title       = {Abstraction-safe Effect Handlers via Tunneling},
    132     journal     = {Proc. ACM Program. Lang.},
    133     issue_date  = {January 2019},
    134     volume      = {3},
    135     number      = {POPL},
    136     month       = jan,
    137     year        = {2019},
    138     issn        = {2475-1421},
    139     pages       = {5:1--5:29},
    140     articleno   = {5},
    141     publisher   = {ACM},
    142     address     = {New York, NY, USA},
    143 }
    144 
    145 @inproceedings{Zhang16,
    146     keywords    = {Exception tunneling, Genus, exception handling},
    147     author      = {Zhang, Yizhou and Salvaneschi, Guido and Beightol, Quinn and Liskov, Barbara and Myers, Andrew C.},
    148     title       = {Accepting Blame for Safe Tunneled Exceptions},
    149     booktitle   = {Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation},
    150     series      = {PLDI'16},
    151     year        = {2016},
    152     location    = {Santa Barbara, CA, USA},
    153     pages       = {281--295},
    154     publisher   = {ACM},
    155     address     = {New York, NY, USA},
    156126}
    157127
     
    428398    journal     = sigplan,
    429399    year        = 1981,
    430     month       = feb,
    431     volume      = 16,
    432     number      = 2,
    433     pages       = {48-52},
     400    month       = feb, volume = 16, number = 2, pages = {48-52},
    434401    comment     = {
    435402        A one-pass, top-down algorithm for overload resolution.  Input is a
     
    510477    title       = {An Alternative to Subclassing},
    511478    journal     = sigplan,
    512     volume      = {21},
    513     number      = {11},
     479    volume      = {21},    number = {11},
    514480    pages       = {424-428},
    515     month       = nov,
    516     year        = 1986,
     481    month       = nov, year = 1986,
    517482    comment     = {
    518483        The Smalltalk class hierarchy has three uses: factoring out code;
     
    568533    isbn        = {3-540-66538-2},
    569534    location    = {Toulouse, France},
     535    doi         = {http://doi.acm.org/10.1145/318773.319251},
    570536    publisher   = {Springer},
    571537    address     = {London, UK},
     
    665631    year        = 2010,
    666632    pages       = {39--50},
     633    numpages    = {12},
    667634    publisher   = {IEEE Computer Society},
    668635    address     = {Washington, DC, USA},
     
    955922}
    956923
    957 @manual{C99,
    958     keywords    = {ISO/IEC C 9899},
    959     contributer = {pabuhr@plg},
    960     key         = {C99},
    961     title       = {C Programming Language {ISO/IEC} 9899:1999(E)},
    962     edition     = {2nd},
    963     publisher   = {International Standard Organization},
    964     address     = {\href{https://webstore.ansi.org/Standards/INCITS/INCITSISOIEC98991999R2005}{https://webstore.ansi.org/\-Standards/\-INCITS/\-INCITSISOIEC98991999R2005}},
    965     year        = 1999,
    966 }
    967 
    968924@manual{C11,
    969925    keywords    = {ISO/IEC C 11},
     
    13491305    location    = {London, United Kingdom},
    13501306    pages       = {41--53},
     1307    numpages    = {13},
     1308    url         = {http://doi.acm.org/10.1145/360204.360207},
     1309    doi         = {10.1145/360204.360207},
     1310    acmid       = {360207},
    13511311    publisher   = {ACM},
    13521312    address     = {New York, NY, USA},
     
    24482408    year        = 1993,
    24492409    pages       = {201--208},
     2410    url         = {http://doi.acm.org/10.1145/155360.155580},
    24502411    publisher   = {ACM},
    24512412    address     = {New York, NY, USA},
     
    26452606    location    = {Boulder, Colorado, USA},
    26462607    pages       = {91--97},
     2608    numpages    = {7},
    26472609    publisher   = {ACM},
    26482610    address     = {New York, NY, USA},
     
    26752637    issn        = {0004-5411},
    26762638    pages       = {215--225},
     2639    numpages    = {11},
     2640    url         = {http://doi.acm.org/10.1145/321879.321884},
     2641    doi         = {10.1145/321879.321884},
     2642    acmid       = {321884},
    26772643    publisher   = {ACM},
    26782644    address     = {New York, NY, USA},
     
    27422708}
    27432709
    2744 @misc{Drepper13,
    2745     keywords    = {thread-local storage},
    2746     contributer = {pabuhr@plg},
    2747     author      = {Ulrich Drepper},
    2748     title       = {{ELF} Handling For Thread-Local Storage},
    2749     year        = 2013,
    2750     month       = aug,
    2751     note        = {WikipediA},
    2752     howpublished= {\href{http://www.akkadia.org/drepper/tls.pdf}
    2753                   {http://\-www.akkadia.org/\-drepper/\-tls.pdf}},
    2754 }
    2755 
    27562710@misc{Turley99,
    27572711    keywords    = {embedded system, micrprocessor},
     
    27642718    howpublished= {\href{https://www.eetimes.com/author.asp?sectionid=36&doc_id=1287712}
    27652719                  {https://\-www.eetimes.com/\-author.asp?sectionid=\-36&doc_id=1287712}},
    2766 }
    2767 
    2768 @article{Xiao19,
    2769     keywords    = {bug classification, fault trigger, Linux operating system, regression bug},
    2770     contributer = {pabuhr@plg},
    2771     author      = {Guanping Xiao and Zheng Zheng and Beibei Yin and Kishor S. Trivedi and Xiaoting Du and Kai-Yuan Cai},
    2772     title       = {An Empirical Study of Fault Triggers in the Linux Operating System: An Evolutionary Perspective},
    2773     journal     = {IEEE Transactions on Reliability},
    2774     month       = dec,
    2775     year        = 2019,
    2776     volume      = 68,
    2777     number      = 4,
    2778     pages       = {1356-1383},
    27792720}
    27802721
     
    31963137}
    31973138
    3198 @inproceedings{Palix11,
    3199     keywords    = {Linux, fault-finding tools},
    3200     contributer = {pabuhr@plg},
    3201     author      = {Nicolas Palix and Ga\"el Thomas and Suman Saha and Christophe Calv\`es and Julia Lawall and Gilles Muller},
    3202     title       = {Faults in Linux: Ten Years Later},
    3203     booktitle   = {Proc. of the 16 International Conf. on Arch. Support for Prog. Lang. and Oper. Sys.},
    3204     series      = {ASPLOS'11},
    3205     month       = mar,
    3206     year        = 2011,
    3207     location    = {Newport Beach, California, USA},
    3208     pages       = {305-318},
    3209     publisher   = {ACM},
    3210     address     = {New York, NY, USA},
    3211 }
    3212 
    32133139@article{Lamport87,
    32143140    keywords    = {software solutions, mutual exclusion, fast},
     
    33323258    issn        = {0001-0782},
    33333259    pages       = {107--115},
     3260    numpages    = {9},
     3261    url         = {http://doi.acm.org/10.1145/1538788.1538814},
     3262    doi         = {10.1145/1538788.1538814},
     3263    acmid       = {1538814},
    33343264    publisher   = {ACM},
    33353265    address     = {New York, NY, USA},
     
    37343664}
    37353665
    3736 @mastersthesis{Radhakrishnan19,
    3737     author      = {Srihari Radhakrishnan},
    3738     title       = {High Performance Web Servers: A Study In Concurrent Programming Models},
    3739     school      = {School of Computer Sc., University of Waterloo},
    3740     year        = 2019,
    3741     optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    3742     note        = {\href{https://uwspace.uwaterloo.ca/handle/10012/14706}{https://\-uwspace.uwaterloo.ca/\-handle/\-10012/\-14706}},
    3743 }
    3744 
    37453666@article{katzenelson83b,
    37463667    contributer = {gjditchfield@plg},
     
    37763697    pages       = {115-138},
    37773698    year        = 1971,
    3778 }
    3779 
    3780 @inproceedings{Hagersten03,
    3781     keywords    = {cache storage, parallel architectures, performance evaluation, shared memory systems},
    3782     author      = {Zoran Radovi\'{c} and Erik Hagersten},
    3783     title       = {Hierarchical backoff locks for nonuniform communication architectures},
    3784     booktitle   = {Proceedings of the Ninth International Symposium on High-Performance Computer Architecture},
    3785     year        = {2003},
    3786     location    = {Anaheim, CA, USA},
    3787     pages       = {241-252},
    3788     publisher   = {IEEE},
    37893699}
    37903700
     
    44554365}
    44564366
    4457 @misc{gccValueLabels,
    4458     keywords    = {gcc extension, value labels},
    4459     contributer = {pabuhr@plg},
    4460     key         = {Labels as Values},
    4461     author      = {{gcc Extension}},
    4462     title       = {Labels as Values},
    4463     year        = {since gcc-3},
    4464     howpublished= {\href{https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html}
    4465                   {https:\-//gcc.gnu.org/\-onlinedocs/\-gcc/\-Labels-as-Values.html}},
    4466 }
    4467 
    44684367@mastersthesis{Clarke90,
    44694368    keywords    = {concurrency, postponing requests},
     
    45584457
    45594458@article{Pierce00,
    4560     keywords    = {Scala, polymorphism, subtyping, type inference},
     4459    keywords    = {Scala},
    45614460    contributer = {a3moss@uwaterloo.ca},
    45624461    author      = {Pierce, Benjamin C. and Turner, David N.},
     
    45704469    issn        = {0164-0925},
    45714470    pages       = {1--44},
     4471    numpages    = {44},
     4472    url         = {http://doi.acm.org/10.1145/345099.345100},
     4473    doi         = {10.1145/345099.345100},
     4474    acmid       = {345100},
    45724475    publisher   = {ACM},
    45734476    address     = {New York, NY, USA},
     4477    keywords    = {polymorphism, subtyping, type inference},
    45744478}
    4575 
    4576 @article{Dice15,
    4577     keywords    = {Concurrency, NUMA, hierarchical locks, locks, multicore, mutex, mutual exclusion, spin locks},
    4578     author      = {Dice, David and Marathe, Virendra J. and Shavit, Nir},
    4579     title       = {Lock Cohorting: A General Technique for Designing NUMA Locks},
    4580     journal     = {ACM Trans. Parallel Comput.},
    4581     issue_date  = {January 2015},
    4582     volume      = 1,
    4583     number      = 2,
    4584     month       = feb,
    4585     year        = 2015,
    4586     pages       = {13:1--13:42},
    4587     publisher   = {ACM},
    4588     address     = {New York, NY, USA},
    4589 }
    45904479
    45914480@article{Sundell08,
     
    46654554    journal     = sigplan,
    46664555    year        = 1989,
    4667     month       = jun,
    4668     volume      = 24,
    4669     number      = 6,
    4670     pages       = {37-48},
     4556    month       = jun, volume = 24, number = 6, pages = {37-48},
    46714557    abstract    = {
    46724558        This paper describes a scheme we have used to manage a large
     
    51094995    year        = 1986,
    51104996    pages       = {313--326},
     4997    numpages    = {14},
    51114998    publisher   = {ACM},
    51124999    address     = {New York, NY, USA},
     
    51245011    year        = 1986,
    51255012    pages       = {327--348},
     5013    numpages    = {22},
    51265014    publisher   = {ACM},
    51275015    address     = {New York, NY, USA},
     
    53205208    year        = 2005,
    53215209    pages       = {146-196},
     5210    numpages    = {51},
    53225211    publisher   = {ACM},
    53235212    address     = {New York, NY, USA},
     
    54655354    year        = 2000,
    54665355    pages       = {29-46},
    5467     note        = {OOPSLA'00, Oct. 15--19, 2000, Minneapolis, Minn., U.S.A.},
     5356    note        = {OOPSLA'00, Oct. 15--19, 2000, Minneapolis, Minnesota, U.S.A.},
    54685357}
    54695358
     
    55795468    location    = {San Diego, California, USA},
    55805469    pages       = {101--112},
     5470    numpages    = {12},
     5471    url         = {http://doi.acm.org/10.1145/2535838.2535878},
     5472    doi         = {10.1145/2535838.2535878},
     5473    acmid       = {2535878},
    55815474    publisher   = {ACM},
    55825475    address     = {New York, NY, USA},
     
    56825575    issn        = {0362-1340},
    56835576    pages       = {30--42},
     5577    numpages    = {13},
     5578    url         = {http://doi.acm.org/10.1145/947586.947589},
     5579    doi         = {10.1145/947586.947589},
    56845580    publisher   = {ACM},
    56855581    address     = {New York, NY, USA}
     
    62166112    month       = 9,
    62176113    year        = 2005,
    6218 }
    6219 
    6220 @article{Bauer15,
    6221     keywords    = {resumption exceptions, theory},
    6222     contributer = {pabuhr@plg},
    6223     author      = {Andrej Bauer and Matija Pretnar},
    6224     title       = {Programming with Algebraic Effects and Handlers},
    6225     journal     = {Journal of Logical and Algebraic Methods in Programming},
    6226     publisher   = {Elsevier BV},
    6227     volume      = 84,
    6228     number      = 1,
    6229     month       = jan,
    6230     year        = 2015,
    6231     pages       = {108-123},
    62326114}
    62336115
     
    66176499    issn        = {0164-0925},
    66186500    pages       = {429-475},
     6501    url         = {http://doi.acm.org/10.1145/1133651.1133653},
     6502    doi         = {10.1145/1133651.1133653},
     6503    acmid       = {1133653},
    66196504    publisher   = {ACM},
    66206505    address     = {New York, NY, USA},
     
    69946879    issn        = {0001-0782},
    69956880    pages       = {565--569},
     6881    numpages    = {5},
     6882    url         = {http://doi.acm.org/10.1145/359545.359566},
     6883    doi         = {10.1145/359545.359566},
     6884    acmid       = {359566},
    69966885    publisher   = {ACM},
    69976886    address     = {New York, NY, USA}
     
    70116900    issn        = {0362-1340},
    70126901    pages       = {145--147},
     6902    numpages    = {3},
     6903    url         = {http://doi.acm.org/10.1145/122598.122614},
     6904    doi         = {10.1145/122598.122614},
     6905    acmid       = {122614},
    70136906    publisher   = {ACM},
    70146907    address     = {New York, NY, USA},
     
    71137006    issn        = {0362-1340},
    71147007    pages       = {82--87},
     7008    numpages    = {6},
     7009    url         = {http://doi.acm.org/10.1145/947680.947688},
     7010    doi         = {10.1145/947680.947688},
    71157011    publisher   = {ACM},
    71167012    address     = {New York, NY, USA},
     
    72577153}
    72587154
    7259 @article{Cascaval08,
    7260     author      = {Cascaval, Calin and Blundell, Colin and Michael, Maged and Cain, Harold W. and Wu, Peng and Chiras, Stefanie and Chatterjee, Siddhartha},
    7261     title       = {Software Transactional Memory: Why Is It Only a Research Toy?},
    7262     journal     = {Queue},
    7263     volume      = {6},
    7264     number      = {5},
    7265     month       = sep,
    7266     year        = {2008},
    7267     pages       = {40:46--40:58},
    7268     publisher   = {ACM},
    7269     address     = {New York, NY, USA},
    7270 }
    7271 
    72727155@article{Dijkstra65a,
    72737156    keywords    = {N-thread software-solution mutual exclusion},
     
    74807363    year        = 1974,
    74817364    pages       = {261-301},
     7365    issn        = {0360-0300},
     7366    doi         = {http://doi.acm.org/10.1145/356635.356640},
    74827367    publisher   = {ACM},
    74837368    address     = {New York, NY, USA},
     
    75697454    publisher   = {ACM Press},
    75707455    address     = {New York, NY, USA},
     7456    doi         = {http://doi.acm.org/10.1145/356586.356588},
    75717457}
    75727458
     
    78697755    howpublished= {\href{https://projects.eclipse.org/proposals/trace-compass}{https://\-projects.eclipse.org/\-proposals/\-trace-compass}},
    78707756}
    7871 
    7872 @inproceedings{Boehm09,
    7873     author      = {Boehm, Hans-J.},
    7874     title       = {Transactional Memory Should Be an Implementation Technique, Not a Programming Interface},
    7875     booktitle   = {Proceedings of the First USENIX Conference on Hot Topics in Parallelism},
    7876     series      = {HotPar'09},
    7877     year        = {2009},
    7878     location    = {Berkeley, California},
    7879     publisher   = {USENIX Association},
    7880     address     = {Berkeley, CA, USA},
    7881 }
    7882 
     7757 
    78837758@article{Leroy00,
    78847759    keywords    = {type-systems, exceptions},
     
    79307805    number      = {2},
    79317806    pages       = {204-214},
    7932     month       = apr,
    7933     year        = 1988,
     7807    month       = apr, year = 1988,
    79347808    comment     = {
    79357809        Extended record types add fields to their base record.  Assignment
     
    82368110    issn        = {0004-5411},
    82378111    pages       = {245--281},
     8112    numpages    = {37},
     8113    url         = {http://doi.acm.org/10.1145/62.2160},
     8114    doi         = {10.1145/62.2160},
     8115    acmid       = {2160},
    82388116    publisher   = {ACM},
    82398117    address     = {New York, NY, USA},
     
    82488126    contributer = {pabuhr@plg},
    82498127    author      = {Boehm, Hans-J. and Adve, Sarita V.},
    8250     title       = {You Don't Know Jack About Shared Variables or Memory Models},
     8128    title       = {You Don'T Know Jack About Shared Variables or Memory Models},
    82518129    journal     = cacm,
    82528130    volume      = 55,
  • doc/papers/concurrency/Paper.tex

    r7030dab r71d6bd8  
    6161\newcommand{\CCseventeen}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}17\xspace} % C++17 symbolic name
    6262\newcommand{\CCtwenty}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}20\xspace} % C++20 symbolic name
    63 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\large$^\sharp$}\xspace} % C# symbolic name
     63\newcommand{\Csharp}{C\raisebox{-0.7ex}{\Large$^\sharp$}\xspace} % C# symbolic name
    6464
    6565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    127127\newcommand*{\etc}{%
    128128        \@ifnextchar{.}{\ETC}%
    129                 {\ETC.\xspace}%
     129        {\ETC.\xspace}%
    130130}}{}%
    131131\@ifundefined{etal}{
    132132\newcommand{\ETAL}{\abbrevFont{et}~\abbrevFont{al}}
    133133\newcommand*{\etal}{%
    134         \@ifnextchar{.}{\ETAL}%
    135                 {\ETAL.\xspace}%
     134        \@ifnextchar{.}{\protect\ETAL}%
     135                {\protect\ETAL.\xspace}%
    136136}}{}%
    137137\@ifundefined{viz}{
     
    163163                __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    164164                inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    165                 otype, restrict, resume, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,
     165                otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, thread,
    166166                _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    167167                virtual, __volatile, __volatile__, waitfor, when, with, zero_t},
    168168        moredirectives={defined,include_next},
    169169        % replace/adjust listing characters that look bad in sanserif
    170         literate={-}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
     170        literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
    171171                {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1
    172172                {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1
     
    197197                _Else, _Enable, _Event, _Finally, _Monitor, _Mutex, _Nomutex, _PeriodicTask, _RealTimeTask,
    198198                _Resume, _Select, _SporadicTask, _Task, _Timeout, _When, _With, _Throw},
     199}
     200\lstdefinelanguage{Golang}{
     201        morekeywords=[1]{package,import,func,type,struct,return,defer,panic,recover,select,var,const,iota,},
     202        morekeywords=[2]{string,uint,uint8,uint16,uint32,uint64,int,int8,int16,int32,int64,
     203                bool,float32,float64,complex64,complex128,byte,rune,uintptr, error,interface},
     204        morekeywords=[3]{map,slice,make,new,nil,len,cap,copy,close,true,false,delete,append,real,imag,complex,chan,},
     205        morekeywords=[4]{for,break,continue,range,goto,switch,case,fallthrough,if,else,default,},
     206        morekeywords=[5]{Println,Printf,Error,},
     207        sensitive=true,
     208        morecomment=[l]{//},
     209        morecomment=[s]{/*}{*/},
     210        morestring=[b]',
     211        morestring=[b]",
     212        morestring=[s]{`}{`},
    199213}
    200214
     
    227241{}
    228242\lstnewenvironment{uC++}[1][]
    229 {\lstset{language=uC++,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
     243{\lstset{#1}}
    230244{}
    231245\lstnewenvironment{Go}[1][]
     
    248262}
    249263
    250 \newsavebox{\myboxA}
    251 \newsavebox{\myboxB}
    252 \newsavebox{\myboxC}
    253 \newsavebox{\myboxD}
     264\newbox\myboxA
     265\newbox\myboxB
     266\newbox\myboxC
     267\newbox\myboxD
    254268
    255269\title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
     
    268282\CFA is a polymorphic, non-object-oriented, concurrent, backwards-compatible extension of the C programming language.
    269283This paper discusses the design philosophy and implementation of its advanced control-flow and concurrent/parallel features, along with the supporting runtime written in \CFA.
    270 These features are created from scratch as ISO C has only low-level and/or unimplemented concurrency, so C programmers continue to rely on library approaches like pthreads.
     284These features are created from scratch as ISO C has only low-level and/or unimplemented concurrency, so C programmers continue to rely on library features like pthreads.
    271285\CFA introduces modern language-level control-flow mechanisms, like generators, coroutines, user-level threading, and monitors for mutual exclusion and synchronization.
    272286% Library extension for executors, futures, and actors are built on these basic mechanisms.
     
    281295
    282296\begin{document}
    283 \linenumbers                            % comment out to turn off line numbering
     297\linenumbers                                            % comment out to turn off line numbering
    284298
    285299\maketitle
     
    288302\section{Introduction}
    289303
    290 \CFA~\cite{Moss18,Cforall} is a modern, polymorphic, non-object-oriented\footnote{
    291 \CFA has object-oriented features, such as constructors, destructors, virtuals and simple trait/interface inheritance.
    292 % Go interfaces, Rust traits, Swift Protocols, Haskell Type Classes and Java Interfaces.
    293 % "Trait inheritance" works for me. "Interface inheritance" might also be a good choice, and distinguish clearly from implementation inheritance.
    294 % You'll want to be a little bit careful with terms like "structural" and "nominal" inheritance as well. CFA has structural inheritance (I think Go as well) -- it's inferred based on the structure of the code. Java, Rust, and Haskell (not sure about Swift) have nominal inheritance, where there needs to be a specific statement that "this type inherits from this type".
     304This paper discusses the design philosophy and implementation of advanced language-level control-flow and concurrent/parallel features in \CFA~\cite{Moss18,Cforall} and its runtime, which is written entirely in \CFA.
     305\CFA is a modern, polymorphic, non-object-oriented\footnote{
     306\CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
    295307However, functions \emph{cannot} be nested in structures, so there is no lexical binding between a structure and set of functions (member/method) implemented by an implicit \lstinline@this@ (receiver) parameter.},
    296308backwards-compatible extension of the C programming language.
    297 In many ways, \CFA is to C as Scala~\cite{Scala} is to Java, providing a \emph{research vehicle} for new typing and control-flow capabilities on top of a highly popular programming language\footnote{
    298 The TIOBE index~\cite{TIOBE} for December 2019 ranks the top five \emph{popular} programming languages as Java 17\%, C 16\%, Python 10\%, and \CC 6\%, \Csharp 5\% = 54\%, and over the past 30 years, C has always ranked either first or second in popularity.}
    299 allowing immediate dissemination.
    300 This paper discusses the design philosophy and implementation of advanced language-level control-flow and concurrent/parallel features in \CFA and its runtime, which is written entirely in \CFA.
    301 The \CFA control-flow framework extends ISO \Celeven~\cite{C11} with new call/return and concurrent/parallel control-flow.
    302 
    303 % The call/return extensions retain state between callee and caller versus losing the callee's state on return;
    304 % the concurrency extensions allow high-level management of threads.
    305 
    306 Call/return control-flow with argument/parameter passing appeared in the first programming languages.
    307 Over the past 50 years, call/return has been augmented with features like static/dynamic call, exceptions (multi-level return) and generators/coroutines (retain state between calls).
    308 While \CFA has mechanisms for dynamic call (algebraic effects) and exceptions\footnote{
    309 \CFA exception handling will be presented in a separate paper.
    310 The key feature that dovetails with this paper is nonlocal exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}}, this work only discusses retaining state between calls via generators/coroutines.
    311 \newterm{Coroutining} was introduced by Conway~\cite{Conway63} (1963), discussed by Knuth~\cite[\S~1.4.2]{Knuth73V1}, implemented in Simula67~\cite{Simula67}, formalized by Marlin~\cite{Marlin80}, and is now popular and appears in old and new programming languages: CLU~\cite{CLU}, \Csharp~\cite{Csharp}, Ruby~\cite{Ruby}, Python~\cite{Python}, JavaScript~\cite{JavaScript}, Lua~\cite{Lua}, \CCtwenty~\cite{C++20Coroutine19}.
    312 Coroutining is sequential execution requiring direct handoff among coroutines, \ie only the programmer is controlling execution order.
    313 If coroutines transfer to an internal event-engine for scheduling the next coroutines, the program transitions into the realm of concurrency~\cite[\S~3]{Buhr05a}.
    314 Coroutines are only a stepping stone towards concurrency where the commonality is that coroutines and threads retain state between calls.
    315 
    316 \Celeven/\CCeleven define concurrency~\cite[\S~7.26]{C11}, but it is largely wrappers for a subset of the pthreads library~\cite{Pthreads}.\footnote{Pthreads concurrency is based on simple thread fork/join in a function and mutex/condition locks, which is low-level and error-prone}
    317 Interestingly, almost a decade after the \Celeven standard, neither gcc-9, clang-9 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating no interest in the C11 concurrency approach (possibly because of the recent effort to add concurrency to \CC).
    318 While the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}, as for \CC.
     309In many ways, \CFA is to C as Scala~\cite{Scala} is to Java, providing a \emph{research vehicle} for new typing and control-flow capabilities on top of a highly popular programming language allowing immediate dissemination.
     310Within the \CFA framework, new control-flow features are created from scratch because ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
     311However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}, and \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and mutex/condition locks, which is low-level and error-prone;
     312no high-level language concurrency features are defined.
     313Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-9 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach (possibly because the effort to add concurrency to \CC).
     314Finally, while the \Celeven standard does not state a threading model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}.
     315
    319316In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
    320317As multi-core hardware became available in the 1980/90s, both user and kernel threading were examined.
    321318Kernel threading was chosen, largely because of its simplicity and fit with the simpler operating systems and hardware architectures at the time, which gave it a performance advantage~\cite{Drepper03}.
    322319Libraries like pthreads were developed for C, and the Solaris operating-system switched from user (JDK 1.1~\cite{JDK1.1}) to kernel threads.
    323 As a result, many current languages implementations adopt the 1:1 kernel-threading model, like Java (Scala), Objective-C~\cite{obj-c-book}, \CCeleven~\cite{C11}, C\#~\cite{Csharp} and Rust~\cite{Rust}, with a variety of presentation mechanisms.
    324 From 2000 onwards, several language implementations have championed the M:N user-threading model, like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book}, including putting green threads back into Java~\cite{Quasar}, and many user-threading libraries have appeared~\cite{Qthreads,MPC,Marcel}.
    325 The main argument for user-level threading is that it is lighter weight than kernel threading (locking and context switching do not cross the kernel boundary), so there is less restriction on programming styles that encourages large numbers of threads performing medium-sized work to facilitate load balancing by the runtime~\cite{Verch12}.
     320As a result, languages like Java, Scala, Objective-C~\cite{obj-c-book}, \CCeleven~\cite{C11}, and C\#~\cite{Csharp} adopt the 1:1 kernel-threading model, with a variety of presentation mechanisms.
     321From 2000 onwards, languages like Go~\cite{Go}, Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, D~\cite{D}, and \uC~\cite{uC++,uC++book} have championed the M:N user-threading model, and many user-threading libraries have appeared~\cite{Qthreads,MPC,Marcel}, including putting green threads back into Java~\cite{Quasar}.
     322The main argument for user-level threading is that it is lighter weight than kernel threading (locking and context switching do not cross the kernel boundary), so there is less restriction on programming styles that encourage large numbers of threads performing medium work units to facilitate load balancing by the runtime~\cite{Verch12}.
    326323As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{Adya02,vonBehren03}.
    327324Finally, performant user-threading implementations (both time and space) meet or exceed direct kernel-threading implementations, while achieving the programming advantages of high concurrency levels and safety.
    328325
    329 A further effort over the past two decades is the development of language memory models to deal with the conflict between language features and compiler/hardware optimizations, \eg some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}.
     326A further effort over the past two decades is the development of language memory models to deal with the conflict between language features and compiler/hardware optimizations, \ie some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}.
    330327The consequence is that a language must provide sufficient tools to program around safety issues, as inline and library code is all sequential to the compiler.
    331328One solution is low-level qualifiers and functions (\eg @volatile@ and atomics) allowing \emph{programmers} to explicitly write safe (race-free~\cite{Boehm12}) programs.
    332 A safer solution is high-level language constructs so the \emph{compiler} knows the concurrency boundaries (where mutual exclusion and synchronization are acquired/released) and provide implicit safety at and across these boundaries.
    333 While the optimization problem is best known with respect to concurrency, it applies to other complex control-flow, like exceptions and coroutines.
    334 As well, language solutions allow matching the language paradigm with the approach, \eg matching the functional paradigm with data-flow programming or the imperative paradigm with thread programming.
    335 
    336 Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety (unsafe code) for performance when necessary.
    337 Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~9]{Buhr05a}) and \emph{barging}\footnote{
    338 Barging is competitive succession instead of direct handoff, \ie after a lock is released both arriving and preexisting waiter threads compete to acquire the lock.
    339 Hence, an arriving thread can temporally \emph{barge} ahead of threads already waiting for an event, which can repeat indefinitely leading to starvation of waiter threads.
     329A safer solution is high-level language constructs so the \emph{compiler} knows the optimization boundaries, and hence, provides implicit safety.
     330This problem is best known with respect to concurrency, but applies to other complex control-flow, like exceptions\footnote{
     331\CFA exception handling will be presented in a separate paper.
     332The key feature that dovetails with this paper is nonlocal exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}
     333} and coroutines.
     334Finally, language solutions allow matching constructs with language paradigm, \ie imperative and functional languages often have different presentations of the same concept to fit their programming model.
     335
     336Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary.
     337Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~8]{Buhr05a}) and \emph{barging}\footnote{
     338The notion of competitive succession instead of direct handoff, \ie a lock owner releases the lock and an arriving thread acquires it ahead of preexisting waiter threads.
    340339} (signals-as-hints~\cite[\S~8]{Buhr05a}), where one is a consequence of the other, \ie once there is spurious wakeup, signals-as-hints follow.
    341 (Author experience teaching concurrency is that students are confused by these semantics.)
    342 However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~9]{Buhr05a};
    343 it is a performance design choice.
    344 We argue removing spurious wakeup and signals-as-hints make concurrent programming simpler and safer as there is less local non-determinism to manage.
    345 If barging acquisition is allowed, its specialized performance advantage should be available as an option not the default.
    346 
    347 \CFA embraces language extensions for advanced control-flow, user-level threading, and safety as the default.
    348 We present comparative examples to support our argument that the \CFA control-flow extensions are as expressive and safe as those in other concurrent imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
     340However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~8]{Buhr05a}, it is a performance design choice.
     341Similarly, signals-as-hints are often a performance decision.
     342We argue removing spurious wakeup and signals-as-hints make concurrent programming significantly safer because it removes local non-determinism and matches with programmer expectation.
     343(Author experience teaching concurrency is that students are highly confused by these semantics.)
     344Clawing back performance, when local non-determinism is unimportant, should be an option not the default.
     345
     346\begin{comment}
     347Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory.
     348As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
     349While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (\eg objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC.
     350Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base.
     351\CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems.
     352\end{comment}
     353
     354\CFA embraces user-level threading, language extensions for advanced control-flow, and safety as the default.
     355We present comparative examples so the reader can judge if the \CFA control-flow extensions are better and safer than those in other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
    349356The main contributions of this work are:
    350 \begin{itemize}[topsep=3pt,itemsep=0pt]
     357\begin{itemize}[topsep=3pt,itemsep=1pt]
    351358\item
    352 a set of fundamental execution properties that dictate which language-level control-flow features need to be supported,
    353 
     359language-level generators, coroutines and user-level threading, which respect the expectations of C programmers.
    354360\item
    355 integration of these language-level control-flow features, while respecting the style and expectations of C programmers,
    356 
     361monitor synchronization without barging, and the ability to safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating these capabilities with all monitor synchronization mechanisms.
    357362\item
    358 monitor synchronization without barging, and the ability to safely acquiring multiple monitors \emph{simultaneously} (deadlock free), while seamlessly integrating these capabilities with all monitor synchronization mechanisms,
    359 
    360 \item
    361 providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features,
    362 
     363providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features.
    363364% \item
    364365% library extensions for executors, futures, and actors built on the basic mechanisms.
    365 
    366366\item
    367 a runtime system without spurious wake-up and no performance loss,
    368 
     367a runtime system with no spurious wakeup.
    369368\item
    370 a dynamic partitioning mechanism to segregate groups of executing user and kernel threads performing specialized work (\eg web-server or compute engine) or requiring different scheduling (\eg NUMA or real-time).
    371 
     369a dynamic partitioning mechanism to segregate the execution environment for specialized requirements.
    372370% \item
    373371% a non-blocking I/O library
    374 
    375372\item
    376 experimental results showing comparable performance of the \CFA features with similar mechanisms in other languages.
     373experimental results showing comparable performance of the new features with similar mechanisms in other programming languages.
    377374\end{itemize}
    378375
    379 Section~\ref{s:FundamentalExecutionProperties} presents the compositional hierarchy of execution properties directing the design of control-flow features in \CFA.
    380 Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls producing constructs @generator@ and @coroutine@.
    381 Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread producing the @thread@ construct.
     376Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls, which produces constructs @generator@ and @coroutine@.
     377Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread, which produces the @thread@ construct.
    382378Section~\ref{s:MutualExclusionSynchronization} discusses the two mechanisms to restricted nondeterminism when controlling shared access to resources (mutual exclusion) and timing relationships among threads (synchronization).
    383379Section~\ref{s:Monitor} shows how both mutual exclusion and synchronization are safely embedded in the @monitor@ and @thread@ constructs.
    384380Section~\ref{s:CFARuntimeStructure} describes the large-scale mechanism to structure (cluster) threads and virtual processors (kernel threads).
    385 Section~\ref{s:Performance} uses a series of microbenchmarks to compare \CFA threading with pthreads, Java 11.0.6, Go 1.12.6, Rust 1.37.0, Python 3.7.6, Node.js 12.14.1, and \uC 7.0.0.
    386 
    387 
    388 \section{Fundamental Execution Properties}
    389 \label{s:FundamentalExecutionProperties}
    390 
    391 The features in a programming language should be composed from a set of fundamental properties rather than an ad hoc collection chosen by the designers.
    392 To this end, the control-flow features created for \CFA are based on the fundamental properties of any language with function-stack control-flow (see also \uC~\cite[pp.~140-142]{uC++}).
    393 The fundamental properties are execution state, thread, and mutual-exclusion/synchronization (MES).
    394 These independent properties can be used alone, in pairs, or in triplets to compose different language features, forming a compositional hierarchy where the most advanced feature has all the properties (state/thread/MES).
    395 While it is possible for a language to only support the most advanced feature~\cite{Hermes90}, this unnecessarily complicates and makes inefficient solutions to certain classes of problems.
    396 As is shown, each of the (non-rejected) composed features solves a particular set of problems, and hence, has a defensible position in a programming language.
    397 If a compositional feature is missing, a programmer has too few/many fundamental properties resulting in a complex and/or is inefficient solution.
    398 
    399 In detail, the fundamental properties are:
    400 \begin{description}[leftmargin=\parindent,topsep=3pt,parsep=0pt]
    401 \item[\newterm{execution state}:]
    402 is the state information needed by a control-flow feature to initialize, manage compute data and execution location(s), and de-initialize.
    403 State is retained in fixed-sized aggregate structures and dynamic-sized stack(s), often allocated in the heap(s) managed by the runtime system.
    404 The lifetime of the state varies with the control-flow feature, where longer life-time and dynamic size provide greater power but also increase usage complexity and cost.
    405 Control-flow transfers among execution states occurs in multiple ways, such as function call, context switch, asynchronous await, etc.
    406 Because the programming language determines what constitutes an execution state, implicitly manages this state, and defines movement mechanisms among states, execution state is an elementary property of the semantics of a programming language.
    407 % An execution-state is related to the notion of a process continuation \cite{Hieb90}.
    408 
    409 \item[\newterm{threading}:]
    410 is execution of code that occurs independently of other execution, \ie the execution resulting from a thread is sequential.
    411 Multiple threads provide \emph{concurrent execution};
    412 concurrent execution becomes parallel when run on multiple processing units (hyper-threading, cores, sockets).
    413 There must be language mechanisms to create, block/unblock, and join with a thread.
    414 
    415 \item[\newterm{MES}:]
    416 is the concurrency mechanisms to perform an action without interruption and establish timing relationships among multiple threads.
    417 These two properties are independent, \ie mutual exclusion cannot provide synchronization and vice versa without introducing additional threads~\cite[\S~4]{Buhr05a}.
    418 Limiting MES, \eg no access to shared data, results in contrived solutions and inefficiency on multi-core von Neumann computers where shared memory is a foundational aspect of its design.
    419 \end{description}
    420 These properties are fundamental because they cannot be built from existing language features, \eg a basic programming language like C99~\cite{C99} cannot create new control-flow features, concurrency, or provide MES using atomic hardware mechanisms.
    421 
    422 
    423 \subsection{Execution Properties}
    424 
    425 Table~\ref{t:ExecutionPropertyComposition} shows how the three fundamental execution properties: state, thread, and mutual exclusion compose a hierarchy of control-flow features needed in a programming language.
    426 (When doing case analysis, not all combinations are meaningful.)
    427 Note, basic von Neumann execution requires at least one thread and an execution state providing some form of call stack.
    428 For table entries missing these minimal components, the property is borrowed from the invoker (caller).
    429 
    430 Case 1 is a function that borrows storage for its state (stack frame/activation) and a thread from its invoker and retains this state across \emph{callees}, \ie function local-variables are retained on the stack across calls.
    431 Case 2 is case 1 with access to shared state so callers are restricted during update (mutual exclusion) and scheduling for other threads (synchronization).
    432 Case 3 is a stateful function supporting resume/suspend along with call/return to retain state across \emph{callers}, but has some restrictions because the function's state is stackless.
    433 Note, stackless functions still borrow the caller's stack and thread, where the stack is used to preserve state across its callees.
    434 Case 4 is cases 2 and 3 with protection to shared state for stackless functions.
    435 Cases 5 and 6 are the same as 3 and 4 but only the thread is borrowed as the function state is stackful, so resume/suspend is a context switch from the caller's to the function's stack.
    436 Cases 7 and 8 are rejected because a function that is given a new thread must have its own stack where the thread begins and stack frames are stored for calls, \ie there is no stack to borrow.
    437 Cases 9 and 10 are rejected because a thread with a fixed state (no stack) cannot accept calls, make calls, block, or be preempted, all of which require an unknown amount of additional dynamic state.
    438 Hence, once started, this kind of thread must execute to completion, \ie computation only, which severely restricts runtime management.
    439 Cases 11 and 12 have a stackful thread with and without safe access to shared state.
    440 Execution properties increase the cost of creation and execution along with complexity of usage.
    441 
    442 \begin{table}
    443 \caption{Execution property composition}
    444 \centering
    445 \label{t:ExecutionPropertyComposition}
    446 \renewcommand{\arraystretch}{1.25}
    447 %\setlength{\tabcolsep}{5pt}
    448 \begin{tabular}{c|c||l|l}
    449 \multicolumn{2}{c||}{execution properties} & \multicolumn{2}{c}{mutual exclusion / synchronization} \\
    450 \hline
    451 stateful                        & thread        & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\
    452 \hline   
    453 \hline   
    454 No                                      & No            & \textbf{1}\ \ \ function                              & \textbf{2}\ \ \ @monitor@ function    \\
    455 \hline   
    456 Yes (stackless)         & No            & \textbf{3}\ \ \ @generator@                   & \textbf{4}\ \ \ @monitor@ @generator@ \\
    457 \hline   
    458 Yes (stackful)          & No            & \textbf{5}\ \ \ @coroutine@                   & \textbf{6}\ \ \ @monitor@ @coroutine@ \\
    459 \hline   
    460 No                                      & Yes           & \textbf{7}\ \ \ {\color{red}rejected} & \textbf{8}\ \ \ {\color{red}rejected} \\
    461 \hline   
    462 Yes (stackless)         & Yes           & \textbf{9}\ \ \ {\color{red}rejected} & \textbf{10}\ \ \ {\color{red}rejected} \\
    463 \hline   
    464 Yes (stackful)          & Yes           & \textbf{11}\ \ \ @thread@                             & \textbf{12}\ \ @monitor@ @thread@             \\
    465 \end{tabular}
    466 \end{table}
    467 
    468 Given the execution-properties taxonomy, programmers can now answer three basic questions: is state necessary across calls and how much, is a separate thread necessary, is access to shared state necessary.
    469 The answers define the optimal language feature need for implementing a programming problem.
    470 The next sections discusses how \CFA fills in the table with language features, while other programming languages may only provide a subset of the table.
    471 
    472 
    473 \subsection{Design Requirements}
    474 
    475 The following design requirements largely stem from building \CFA on top of C.
    476 \begin{itemize}[topsep=3pt,parsep=0pt]
    477 \item
    478 All communication must be statically type checkable for early detection of errors and efficient code generation.
    479 This requirement is consistent with the fact that C is a statically-typed programming-language.
    480 
    481 \item
    482 Direct interaction among language features must be possible allowing any feature to be selected without restricting comm\-unication.
    483 For example, many concurrent languages do not provide direct communication (calls) among threads, \ie threads only communicate indirectly through monitors, channels, messages, and/or futures.
    484 Indirect communication increases the number of objects, consuming more resources, and require additional synchronization and possibly data transfer.
    485 
    486 \item
    487 All communication is performed using function calls, \ie data is transmitted from argument to parameter and results are returned from function calls.
    488 Alternative forms of communication, such as call-backs, message passing, channels, or communication ports, step outside of C's normal form of communication.
    489 
    490 \item
    491 All stateful features must follow the same declaration scopes and lifetimes as other language data.
    492 For C that means at program startup, during block and function activation, and on demand using dynamic allocation.
    493 
    494 \item
    495 MES must be available implicitly in language constructs as well as explicitly for specialized requirements, because requiring programmers to build MES using low-level locks often leads to incorrect programs.
    496 Furthermore, reducing synchronization scope by encapsulating it within language constructs further reduces errors in concurrent programs.
    497 
    498 \item
    499 Both synchronous and asynchronous communication are needed.
    500 However, we believe the best way to provide asynchrony, such as call-buffering/chaining and/or returning futures~\cite{multilisp}, is building it from expressive synchronous features.
    501 
    502 \item
    503 Synchronization must be able to control the service order of requests including prioritizing selection from different kinds of outstanding requests, and postponing a request for an unspecified time while continuing to accept new requests.
    504 Otherwise, certain concurrency problems are difficult, e.g.\ web server, disk scheduling, and the amount of concurrency is inhibited~\cite{Gentleman81}.
    505 \end{itemize}
    506 We have satisfied these requirements in \CFA while maintaining backwards compatibility with the huge body of legacy C programs.
    507 % In contrast, other new programming languages must still access C programs (\eg operating-system service routines), but do so through fragile C interfaces.
    508 
    509 
    510 \subsection{Asynchronous Await / Call}
    511 
    512 Asynchronous await/call is a caller mechanism for structuring programs and/or increasing concurrency, where the caller (client) postpones an action into the future, which is subsequently executed by a callee (server).
    513 The caller detects the action's completion through a \newterm{future}/\newterm{promise}.
    514 The benefit is asynchronous caller execution with respect to the callee until future resolution.
    515 For single-threaded languages like JavaScript, an asynchronous call passes a callee action, which is queued in the event-engine, and continues execution with a promise.
    516 When the caller needs the promise to be fulfilled, it executes @await@.
    517 A promise-completion call-back can be part of the callee action or the caller is rescheduled;
    518 in either case, the call back is executed after the promise is fulfilled.
    519 While asynchronous calls generate new callee (server) events, we content this mechanism is insufficient for advanced control-flow mechanisms like generators or coroutines (which are discussed next).
    520 Specifically, control between caller and callee occurs indirectly through the event-engine precluding direct handoff and cycling among events, and requires complex resolution of a control promise and data.
    521 Note, @async-await@ is just syntactic-sugar over the event engine so it does not solve these deficiencies.
    522 For multi-threaded languages like Java, the asynchronous call queues a callee action with an executor (server), which subsequently executes the work by a thread in the executor thread-pool.
    523 The problem is when concurrent work-units need to interact and/or block as this effects the executor, \eg stops threads.
    524 While it is possible to extend this approach to support the necessary mechanisms, \eg message passing in Actors, we show monitors and threads provide an equally competitive approach that does not deviate from normal call communication and can be used to build asynchronous call, as is done in Java.
     381Section~\ref{s:Performance} uses a series of microbenchmarks to compare \CFA threading with pthreads, Java OpenJDK-9, Go 1.12.6 and \uC 7.0.0.
    525382
    526383
     
    528385\label{s:StatefulFunction}
    529386
    530 A \emph{stateful function} has the ability to remember state between calls, where state can be either data or execution, \eg plugin, device driver, finite-state machine (FSM).
    531 A simple technique to retain data state between calls is @static@ declarations within a function, which is often implemented by hoisting the declarations to the global scope but hiding the names within the function using name mangling.
    532 However, each call starts the function at the top making it difficult to determine the last point of execution in an algorithm, and requiring multiple flag variables and testing to reestablish the continuation point.
    533 Hence, the next step of generalizing function state is implicitly remembering the return point between calls and reentering the function at this point rather than the top, called \emph{generators}\,/\,\emph{iterators} or \emph{stackless coroutines}.
    534 For example, a Fibonacci generator retains data and execution state allowing it to remember prior values needed to generate the next value and the location in the algorithm to compute that value.
    535 The next step of generalization is instantiating the function to allow multiple named instances, \eg multiple Fibonacci generators, where each instance has its own state, and hence, can generate an independent sequence of values.
    536 Note, a subset of generator state is a function \emph{closure}, \ie the technique of capturing lexical references when returning a nested function.
    537 A further generalization is adding a stack to a generator's state, called a \emph{coroutine}, so it can suspend outside of itself, \eg call helper functions to arbitrary depth before suspending back to its resumer without unwinding these calls.
    538 For example, a coroutine iterator for a binary tree can stop the traversal at the visit point (pre, infix, post traversal), return the node value to the caller, and then continue the recursive traversal from the current node on the next call.
    539 
    540 There are two styles of activating a stateful function, \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
    541 These styles \emph{do not} cause incremental stack growth, \eg a million resume/suspend or resume/resume cycles do not remember each cycle just the last resumer for each cycle.
    542 Selecting between stackless/stackful semantics and asymmetric/symmetric style is a tradeoff between programming requirements, performance, and design, where stackless is faster and smaller (modified call/return between closures), stackful is more general but slower and larger (context switching between distinct stacks), and asymmetric is simpler control-flow than symmetric.
    543 Additionally, storage management for the closure/stack (especially in unmanaged languages, \ie no garbage collection) must be factored into design and performance.
    544 Note, creation cost (closure/stack) is amortized across usage, so activation cost (resume/suspend) is usually the dominant factor.
    545 
    546 % The stateful function is an old idea~\cite{Conway63,Marlin80} that is new again~\cite{C++20Coroutine19}, where execution is temporarily suspended and later resumed, \eg plugin, device driver, finite-state machine.
    547 % Hence, a stateful function may not end when it returns to its caller, allowing it to be restarted with the data and execution location present at the point of suspension.
    548 % If the closure is fixed size, we call it a \emph{generator} (or \emph{stackless}), and its control flow is restricted, \eg suspending outside the generator is prohibited.
    549 % If the closure is variable size, we call it a \emph{coroutine} (or \emph{stackful}), and as the names implies, often implemented with a separate stack with no programming restrictions.
    550 % Hence, refactoring a stackless coroutine may require changing it to stackful.
    551 % A foundational property of all \emph{stateful functions} is that resume/suspend \emph{do not} cause incremental stack growth, \ie resume/suspend operations are remembered through the closure not the stack.
    552 % As well, activating a stateful function is \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
    553 % A fixed closure activated by modified call/return is faster than a variable closure activated by context switching.
    554 % Additionally, any storage management for the closure (especially in unmanaged languages, \ie no garbage collection) must also be factored into design and performance.
    555 % Therefore, selecting between stackless and stackful semantics is a tradeoff between programming requirements and performance, where stackless is faster and stackful is more general.
    556 % nppNote, creation cost is amortized across usage, so activation cost is usually the dominant factor.
    557 
    558 For example, Python presents asymmetric generators as a function object, \uC presents symmetric coroutines as a \lstinline[language=C++]|class|-like object, and many languages present threading using function pointers, @pthreads@~\cite{Butenhof97}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}.
    559 \begin{center}
    560 \begin{tabular}{@{}l|l|l@{}}
    561 \multicolumn{1}{@{}c|}{Python asymmetric generator} & \multicolumn{1}{c|}{\uC symmetric coroutine} & \multicolumn{1}{c@{}}{Pthreads thread} \\
    562 \hline
    563 \begin{python}
    564 `def Gen():` $\LstCommentStyle{\color{red}// function}$
    565         ... yield val ...
    566 gen = Gen()
    567 for i in range( 10 ):
    568         print( next( gen ) )
    569 \end{python}
    570 &
    571 \begin{uC++}
    572 `_Coroutine Cycle {` $\LstCommentStyle{\color{red}// class}$
    573         Cycle * p;
    574         void main() { p->cycle(); }
    575         void cycle() { resume(); }  `};`
    576 Cycle c1, c2; c1.p=&c2; c2.p=&c1; c1.cycle();
    577 \end{uC++}
    578 &
    579 \begin{cfa}
    580 void * rtn( void * arg ) { ... }
    581 int i = 3, rc;
    582 pthread_t t; $\C{// thread id}$
    583 $\LstCommentStyle{\color{red}// function pointer}$
    584 rc=pthread_create(&t, `rtn`, (void *)i);
    585 \end{cfa}
    586 \end{tabular}
    587 \end{center}
    588 \CFA's preferred presentation model for generators/coroutines/threads is a hybrid of functions and classes, giving an object-oriented flavour.
    589 Essentially, the generator/coroutine/thread function is semantically coupled with a generator/coroutine/thread custom type via the type's name.
    590 The custom type solves several issues, while accessing the underlying mechanisms used by the custom types is still allowed for flexibility reasons.
    591 Each custom type is discussed in detail in the following sections.
    592 
    593 
    594 \subsection{Generator}
    595 
    596 Stackless generators (Table~\ref{t:ExecutionPropertyComposition} case 3) have the potential to be very small and fast, \ie as small and fast as function call/return for both creation and execution.
    597 The \CFA goal is to achieve this performance target, possibly at the cost of some semantic complexity.
    598 A series of different kinds of generators and their implementation demonstrate how this goal is accomplished.\footnote{
    599 The \CFA operator syntax uses \lstinline|?| to denote operands, which allows precise definitions for pre, post, and infix operators, \eg \lstinline|?++|, \lstinline|++?|, and \lstinline|?+?|, in addition \lstinline|?\{\}| denotes a constructor, as in \lstinline|foo `f` = `\{`...`\}`|, \lstinline|^?\{\}| denotes a destructor, and \lstinline|?()| is \CC function call \lstinline|operator()|.
    600 Operator \lstinline+|+ is overloaded for printing, like bit-shift \lstinline|<<| in \CC.
    601 The \CFA \lstinline|with| clause opens an aggregate scope making its fields directly accessible, like Pascal \lstinline|with|, but using parallel semantics;
    602 multiple aggregates may be opened.
    603 \CFA has rebindable references \lstinline|int i, & ip = i, j; `&ip = &j;`| and non-rebindable references \lstinline|int i, & `const` ip = i, j; `&ip = &j;` // disallowed|.
    604 }%
     387The stateful function is an old idea~\cite{Conway63,Marlin80} that is new again~\cite{C++20Coroutine19}, where execution is temporarily suspended and later resumed, \eg plugin, device driver, finite-state machine.
     388Hence, a stateful function may not end when it returns to its caller, allowing it to be restarted with the data and execution location present at the point of suspension.
     389This capability is accomplished by retaining a data/execution \emph{closure} between invocations.
     390If the closure is fixed size, we call it a \emph{generator} (or \emph{stackless}), and its control flow is restricted, \eg suspending outside the generator is prohibited.
     391If the closure is variable size, we call it a \emph{coroutine} (or \emph{stackful}), and as the names implies, often implemented with a separate stack with no programming restrictions.
     392Hence, refactoring a stackless coroutine may require changing it to stackful.
     393A foundational property of all \emph{stateful functions} is that resume/suspend \emph{do not} cause incremental stack growth, \ie resume/suspend operations are remembered through the closure not the stack.
     394As well, activating a stateful function is \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
     395A fixed closure activated by modified call/return is faster than a variable closure activated by context switching.
     396Additionally, any storage management for the closure (especially in unmanaged languages, \ie no garbage collection) must also be factored into design and performance.
     397Therefore, selecting between stackless and stackful semantics is a tradeoff between programming requirements and performance, where stackless is faster and stackful is more general.
     398Note, creation cost is amortized across usage, so activation cost is usually the dominant factor.
    605399
    606400\begin{figure}
     
    616410
    617411
    618 
    619 
    620412        int fn = f->fn; f->fn = f->fn1;
    621413                f->fn1 = f->fn + fn;
    622414        return fn;
     415
    623416}
    624417int main() {
     
    639432void `main(Fib & fib)` with(fib) {
    640433
    641 
    642434        [fn1, fn] = [1, 0];
    643435        for () {
     
    659451\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    660452typedef struct {
    661         int `restart`, fn1, fn;
     453        int fn1, fn;  void * `next`;
    662454} Fib;
    663 #define FibCtor { `0`, 1, 0 }
     455#define FibCtor { 1, 0, NULL }
    664456Fib * comain( Fib * f ) {
    665         `static void * states[] = {&&s0, &&s1};`
    666         `goto *states[f->restart];`
    667   s0: f->`restart` = 1;
     457        if ( f->next ) goto *f->next;
     458        f->next = &&s1;
    668459        for ( ;; ) {
    669460                return f;
    670461          s1:; int fn = f->fn + f->fn1;
    671                 f->fn1 = f->fn; f->fn = fn;
     462                        f->fn1 = f->fn; f->fn = fn;
    672463        }
    673464}
     
    681472\end{lrbox}
    682473
    683 \subfloat[C]{\label{f:CFibonacci}\usebox\myboxA}
     474\subfloat[C asymmetric generator]{\label{f:CFibonacci}\usebox\myboxA}
    684475\hspace{3pt}
    685476\vrule
    686477\hspace{3pt}
    687 \subfloat[\CFA]{\label{f:CFAFibonacciGen}\usebox\myboxB}
     478\subfloat[\CFA asymmetric generator]{\label{f:CFAFibonacciGen}\usebox\myboxB}
    688479\hspace{3pt}
    689480\vrule
    690481\hspace{3pt}
    691 \subfloat[C generated code for \CFA version]{\label{f:CFibonacciSim}\usebox\myboxC}
     482\subfloat[C generator implementation]{\label{f:CFibonacciSim}\usebox\myboxC}
    692483\caption{Fibonacci (output) asymmetric generator}
    693484\label{f:FibonacciAsymmetricGenerator}
     
    702493};
    703494void ?{}( Fmt & fmt ) { `resume(fmt);` } // constructor
    704 void ^?{}( Fmt & f ) with(f) { $\C[2.25in]{// destructor}$
     495void ^?{}( Fmt & f ) with(f) { $\C[1.75in]{// destructor}$
    705496        if ( g != 0 || b != 0 ) sout | nl; }
    706497void `main( Fmt & f )` with(f) {
     
    708499                for ( ; g < 5; g += 1 ) { $\C{// groups}$
    709500                        for ( ; b < 4; b += 1 ) { $\C{// blocks}$
    710                                 do { `suspend;` $\C{// wait for character}$
    711                                 while ( ch == '\n' ); // ignore newline
    712                                 sout | ch;                      $\C{// print character}$
    713                         } sout | " ";  $\C{// block separator}$
    714                 } sout | nl; $\C{// group separator}$
     501                                `suspend;` $\C{// wait for character}$
     502                                while ( ch == '\n' ) `suspend;` // ignore
     503                                sout | ch;                                              // newline
     504                        } sout | " ";  // block spacer
     505                } sout | nl; // group newline
    715506        }
    716507}
     
    730521\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    731522typedef struct {
    732         int `restart`, g, b;
     523        void * next;
    733524        char ch;
     525        int g, b;
    734526} Fmt;
    735527void comain( Fmt * f ) {
    736         `static void * states[] = {&&s0, &&s1};`
    737         `goto *states[f->restart];`
    738   s0: f->`restart` = 1;
     528        if ( f->next ) goto *f->next;
     529        f->next = &&s1;
    739530        for ( ;; ) {
    740531                for ( f->g = 0; f->g < 5; f->g += 1 ) {
    741532                        for ( f->b = 0; f->b < 4; f->b += 1 ) {
    742                                 do { return;  s1: ;
    743                                 } while ( f->ch == '\n' );
     533                                return;
     534                          s1:;  while ( f->ch == '\n' ) return;
    744535                                printf( "%c", f->ch );
    745536                        } printf( " " );
     
    748539}
    749540int main() {
    750         Fmt fmt = { `0` };  comain( &fmt ); // prime
     541        Fmt fmt = { NULL };  comain( &fmt ); // prime
    751542        for ( ;; ) {
    752543                scanf( "%c", &fmt.ch );
     
    759550\end{lrbox}
    760551
    761 \subfloat[\CFA]{\label{f:CFAFormatGen}\usebox\myboxA}
    762 \hspace{35pt}
     552\subfloat[\CFA asymmetric generator]{\label{f:CFAFormatGen}\usebox\myboxA}
     553\hspace{3pt}
    763554\vrule
    764555\hspace{3pt}
    765 \subfloat[C generated code for \CFA version]{\label{f:CFormatGenImpl}\usebox\myboxB}
     556\subfloat[C generator simulation]{\label{f:CFormatSim}\usebox\myboxB}
    766557\hspace{3pt}
    767558\caption{Formatter (input) asymmetric generator}
     
    769560\end{figure}
    770561
    771 Figure~\ref{f:FibonacciAsymmetricGenerator} shows an unbounded asymmetric generator for an infinite sequence of Fibonacci numbers written (left to right) in C, \CFA, and showing the underlying C implementation for the \CFA version.
     562Stateful functions appear as generators, coroutines, and threads, where presentations are based on function objects or pointers~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.
     563For example, Python presents generators as a function object:
     564\begin{python}
     565def Gen():
     566        ... `yield val` ...
     567gen = Gen()
     568for i in range( 10 ):
     569        print( next( gen ) )
     570\end{python}
     571Boost presents coroutines in terms of four functor object-types:
     572\begin{cfa}
     573asymmetric_coroutine<>::pull_type
     574asymmetric_coroutine<>::push_type
     575symmetric_coroutine<>::call_type
     576symmetric_coroutine<>::yield_type
     577\end{cfa}
     578and many languages present threading using function pointers, @pthreads@~\cite{Butenhof97}, \Csharp~\cite{Csharp}, Go~\cite{Go}, and Scala~\cite{Scala}, \eg pthreads:
     579\begin{cfa}
     580void * rtn( void * arg ) { ... }
     581int i = 3, rc;
     582pthread_t t; $\C{// thread id}$
     583`rc = pthread_create( &t, rtn, (void *)i );` $\C{// create and initialized task, type-unsafe input parameter}$
     584\end{cfa}
     585% void mycor( pthread_t cid, void * arg ) {
     586%       int * value = (int *)arg;                               $\C{// type unsafe, pointer-size only}$
     587%       // thread body
     588% }
     589% int main() {
     590%       int input = 0, output;
     591%       coroutine_t cid = coroutine_create( &mycor, (void *)&input ); $\C{// type unsafe, pointer-size only}$
     592%       coroutine_resume( cid, (void *)input, (void **)&output ); $\C{// type unsafe, pointer-size only}$
     593% }
     594\CFA's preferred presentation model for generators/coroutines/threads is a hybrid of objects and functions, with an object-oriented flavour.
     595Essentially, the generator/coroutine/thread function is semantically coupled with a generator/coroutine/thread custom type.
     596The custom type solves several issues, while accessing the underlying mechanisms used by the custom types is still allowed.
     597
     598
     599\subsection{Generator}
     600
     601Stackless generators have the potential to be very small and fast, \ie as small and fast as function call/return for both creation and execution.
     602The \CFA goal is to achieve this performance target, possibly at the cost of some semantic complexity.
     603A series of different kinds of generators and their implementation demonstrate how this goal is accomplished.
     604
     605Figure~\ref{f:FibonacciAsymmetricGenerator} shows an unbounded asymmetric generator for an infinite sequence of Fibonacci numbers written in C and \CFA, with a simple C implementation for the \CFA version.
    772606This generator is an \emph{output generator}, producing a new result on each resumption.
    773607To compute Fibonacci, the previous two values in the sequence are retained to generate the next value, \ie @fn1@ and @fn@, plus the execution location where control restarts when the generator is resumed, \ie top or middle.
     
    777611The C version only has the middle execution state because the top execution state is declaration initialization.
    778612Figure~\ref{f:CFAFibonacciGen} shows the \CFA approach, which also has a manual closure, but replaces the structure with a custom \CFA @generator@ type.
    779 Each generator type must have a function named \lstinline|main|,
    780 % \footnote{
    781 % The name \lstinline|main| has special meaning in C, specifically the function where a program starts execution.
    782 % Leveraging starting semantics to this name for generator/coroutine/thread is a logical extension.}
    783 called a \emph{generator main} (leveraging the starting semantics for program @main@ in C), which is connected to the generator type via its single reference parameter.
     613This generator type is then connected to a function that \emph{must be named \lstinline|main|},\footnote{
     614The name \lstinline|main| has special meaning in C, specifically the function where a program starts execution.
     615Hence, overloading this name for other starting points (generator/coroutine/thread) is a logical extension.}
     616called a \emph{generator main},which takes as its only parameter a reference to the generator type.
    784617The generator main contains @suspend@ statements that suspend execution without ending the generator versus @return@.
    785 For the Fibonacci generator-main,
     618For the Fibonacci generator-main,\footnote{
     619The \CFA \lstinline|with| opens an aggregate scope making its fields directly accessible, like Pascal \lstinline|with|, but using parallel semantics.
     620Multiple aggregates may be opened.}
    786621the top initialization state appears at the start and the middle execution state is denoted by statement @suspend@.
    787622Any local variables in @main@ \emph{are not retained} between calls;
     
    792627Resuming an ended (returned) generator is undefined.
    793628Function @resume@ returns its argument generator so it can be cascaded in an expression, in this case to print the next Fibonacci value @fn@ computed in the generator instance.
    794 Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA asymmetric generator.
    795 Only one execution-state field, @restart@, is needed to subscript the suspension points in the generator.
    796 At the start of the generator main, the @static@ declaration, @states@, is initialized to the N suspend points in the generator (where operator @&&@ dereferences/references a label~\cite{gccValueLabels}).
    797 Next, the computed @goto@ selects the last suspend point and branches to it.
    798 The  cost of setting @restart@ and branching via the computed @goto@ adds very little cost to the suspend/resume calls.
    799 
    800 An advantage of the \CFA explicit generator type is the ability to allow multiple type-safe interface functions taking and returning arbitrary types.
     629Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA generator only needs one additional field, @next@, to handle retention of execution state.
     630The computed @goto@ at the start of the generator main, which branches after the previous suspend, adds very little cost to the resume call.
     631Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types.\footnote{
     632The \CFA operator syntax uses \lstinline|?| to denote operands, which allows precise definitions for pre, post, and infix operators, \eg \lstinline|++?|, \lstinline|?++|, and \lstinline|?+?|, in addition \lstinline|?\{\}| denotes a constructor, as in \lstinline|foo `f` = `\{`...`\}`|, \lstinline|^?\{\}| denotes a destructor, and \lstinline|?()| is \CC function call \lstinline|operator()|.
     633}%
    801634\begin{cfa}
    802635int ?()( Fib & fib ) { return `resume( fib )`.fn; } $\C[3.9in]{// function-call interface}$
    803 int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// add parameter to skip N values}$
    804 double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}$
    805 Fib f;  int i;  double d;
    806 i = f();  i = f( 2 );  d = f();                                         $\C{// alternative interfaces}\CRT$
     636int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// use function-call interface to skip N values}$
     637double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}\CRT$
     638sout | (int)f1() | (double)f1() | f2( 2 ); // alternative interface, cast selects call based on return type, step 2 values
    807639\end{cfa}
    808640Now, the generator can be a separately compiled opaque-type only accessed through its interface functions.
    809641For contrast, Figure~\ref{f:PythonFibonacci} shows the equivalent Python Fibonacci generator, which does not use a generator type, and hence only has a single interface, but an implicit closure.
    810642
    811 \begin{figure}
    812 %\centering
    813 \newbox\myboxA
    814 \begin{lrbox}{\myboxA}
    815 \begin{python}[aboveskip=0pt,belowskip=0pt]
    816 def Fib():
    817         fn1, fn = 0, 1
    818         while True:
    819                 `yield fn1`
    820                 fn1, fn = fn, fn1 + fn
    821 f1 = Fib()
    822 f2 = Fib()
    823 for i in range( 10 ):
    824         print( next( f1 ), next( f2 ) )
    825 
    826 
    827 
    828 
    829 
    830 
    831 
    832 
    833 
    834 
    835 \end{python}
    836 \end{lrbox}
    837 
    838 \newbox\myboxB
    839 \begin{lrbox}{\myboxB}
    840 \begin{python}[aboveskip=0pt,belowskip=0pt]
    841 def Fmt():
    842         try:
    843                 while True:                                             $\C[2.5in]{\# until destructor call}$
    844                         for g in range( 5 ):            $\C{\# groups}$
    845                                 for b in range( 4 ):    $\C{\# blocks}$
    846                                         while True:
    847                                                 ch = (yield)    $\C{\# receive from send}$
    848                                                 if '\n' not in ch: $\C{\# ignore newline}$
    849                                                         break
    850                                         print( ch, end='' )     $\C{\# print character}$
    851                                 print( '  ', end='' )   $\C{\# block separator}$
    852                         print()                                         $\C{\# group separator}$
    853         except GeneratorExit:                           $\C{\# destructor}$
    854                 if g != 0 | b != 0:                             $\C{\# special case}$
    855                         print()
    856 fmt = Fmt()
    857 `next( fmt )`                                                   $\C{\# prime, next prewritten}$
    858 for i in range( 41 ):
    859         `fmt.send( 'a' );`                                      $\C{\# send to yield}$
    860 \end{python}
    861 \end{lrbox}
    862 
    863 \hspace{30pt}
    864 \subfloat[Fibonacci]{\label{f:PythonFibonacci}\usebox\myboxA}
    865 \hspace{3pt}
    866 \vrule
    867 \hspace{3pt}
    868 \subfloat[Formatter]{\label{f:PythonFormatter}\usebox\myboxB}
    869 \caption{Python generator}
    870 \label{f:PythonGenerator}
    871 \end{figure}
    872 
    873 Having to manually create the generator closure by moving local-state variables into the generator type is an additional programmer burden (removed by the coroutine in Section~\ref{s:Coroutine}).
    874 This manual requirement follows from the generality of allowing variable-size local-state, \eg local state with a variable-length array requires dynamic allocation as the array size is unknown at compile time.
     643Having to manually create the generator closure by moving local-state variables into the generator type is an additional programmer burden.
     644(This restriction is removed by the coroutine in Section~\ref{s:Coroutine}.)
     645This requirement follows from the generality of variable-size local-state, \eg local state with a variable-length array requires dynamic allocation because the array size is unknown at compile time.
    875646However, dynamic allocation significantly increases the cost of generator creation/destruction and is a showstopper for embedded real-time programming.
    876647But more importantly, the size of the generator type is tied to the local state in the generator main, which precludes separate compilation of the generator main, \ie a generator must be inlined or local state must be dynamically allocated.
    877 With respect to safety, we believe static analysis can discriminate persistent generator state from temporary generator-main state and raise a compile-time error for temporary usage spanning suspend points.
    878 Our experience using generators is that the problems have simple data state, including local state, but complex execution state, so the burden of creating the generator type is small.
     648With respect to safety, we believe static analysis can discriminate local state from temporary variables in a generator, \ie variable usage spanning @suspend@, and generate a compile-time error.
     649Finally, our current experience is that most generator problems have simple data state, including local state, but complex execution state, so the burden of creating the generator type is small.
    879650As well, C programmers are not afraid of this kind of semantic programming requirement, if it results in very small, fast generators.
    880651
     
    898669The example takes advantage of resuming a generator in the constructor to prime the loops so the first character sent for formatting appears inside the nested loops.
    899670The destructor provides a newline, if formatted text ends with a full line.
    900 Figure~\ref{f:CFormatGenImpl} shows the C implementation of the \CFA input generator with one additional field and the computed @goto@.
    901 For contrast, Figure~\ref{f:PythonFormatter} shows the equivalent Python format generator with the same properties as the format generator.
    902 
    903 % https://dl-acm-org.proxy.lib.uwaterloo.ca/
    904 
    905 Figure~\ref{f:DeviceDriverGen} shows an important application for an asymmetric generator, a device-driver, because device drivers are a significant source of operating-system errors: 85\% in Windows XP~\cite[p.~78]{Swift05} and 51.6\% in Linux~\cite[p.~1358,]{Xiao19}. %\cite{Palix11}
    906 Swift \etal~\cite[p.~86]{Swift05} restructure device drivers using the Extension Procedure Call (XPC) within the kernel via functions @nooks_driver_call@ and @nooks_kernel_call@, which have coroutine properties context switching to separate stacks with explicit hand-off calls;
    907 however, the calls do not retain execution state, and hence always start from the top.
    908 The alternative approach for implementing device drivers is using stack-ripping.
    909 However, Adya \etal~\cite{Adya02} argue against stack ripping in Section 3.2 and suggest a hybrid approach in Section 4 using cooperatively scheduled \emph{fibers}, which is coroutining.
    910 
    911 As an example, the following protocol:
     671Figure~\ref{f:CFormatSim} shows the C implementation of the \CFA input generator with one additional field and the computed @goto@.
     672For contrast, Figure~\ref{f:PythonFormatter} shows the equivalent Python format generator with the same properties as the Fibonacci generator.
     673
     674Figure~\ref{f:DeviceDriverGen} shows a \emph{killer} asymmetric generator, a device-driver, because device drivers caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
     675Device drives follow the pattern of simple data state but complex execution state, \ie finite state-machine (FSM) parsing a protocol.
     676For example, the following protocol:
    912677\begin{center}
    913678\ldots\, STX \ldots\, message \ldots\, ESC ETX \ldots\, message \ldots\, ETX 2-byte crc \ldots
    914679\end{center}
    915 is for a simple network message beginning with the control character STX, ending with an ETX, and followed by a 2-byte cyclic-redundancy check.
     680is a network message beginning with the control character STX, ending with an ETX, and followed by a 2-byte cyclic-redundancy check.
    916681Control characters may appear in a message if preceded by an ESC.
    917682When a message byte arrives, it triggers an interrupt, and the operating system services the interrupt by calling the device driver with the byte read from a hardware register.
    918 The device driver returns a status code of its current state, and when a complete message is obtained, the operating system read the message accumulated in the supplied buffer.
    919 Hence, the device driver is an input/output generator, where the cost of resuming the device-driver generator is the same as call/return, so performance in an operating-system kernel is excellent.
    920 The key benefits of using a generator are correctness, safety, and maintenance because the execution states are transcribed directly into the programming language rather than table lookup or stack ripping.
    921 The conclusion is that FSMs are complex and occur in important domains, so direct generator support is important in a system programming language.
     683The device driver returns a status code of its current state, and when a complete message is obtained, the operating system knows the message is in the message buffer.
     684Hence, the device driver is an input/output generator.
     685
     686Note, the cost of creating and resuming the device-driver generator, @Driver@, is virtually identical to call/return, so performance in an operating-system kernel is excellent.
     687As well, the data state is small, where variables @byte@ and @msg@ are communication variables for passing in message bytes and returning the message, and variables @lnth@, @crc@, and @sum@ are local variable that must be retained between calls and are manually hoisted into the generator type.
     688% Manually, detecting and hoisting local-state variables is easy when the number is small.
     689In contrast, the execution state is large, with one @resume@ and seven @suspend@s.
     690Hence, the key benefits of the generator are correctness, safety, and maintenance because the execution states are transcribed directly into the programming language rather than using a table-driven approach.
     691Because FSMs can be complex and frequently occur in important domains, direct generator support is important in a system programming language.
    922692
    923693\begin{figure}
    924694\centering
     695\newbox\myboxA
     696\begin{lrbox}{\myboxA}
     697\begin{python}[aboveskip=0pt,belowskip=0pt]
     698def Fib():
     699        fn1, fn = 0, 1
     700        while True:
     701                `yield fn1`
     702                fn1, fn = fn, fn1 + fn
     703f1 = Fib()
     704f2 = Fib()
     705for i in range( 10 ):
     706        print( next( f1 ), next( f2 ) )
     707
     708
     709
     710
     711
     712
     713\end{python}
     714\end{lrbox}
     715
     716\newbox\myboxB
     717\begin{lrbox}{\myboxB}
     718\begin{python}[aboveskip=0pt,belowskip=0pt]
     719def Fmt():
     720        try:
     721                while True:
     722                        for g in range( 5 ):
     723                                for b in range( 4 ):
     724                                        print( `(yield)`, end='' )
     725                                print( '  ', end='' )
     726                        print()
     727        except GeneratorExit:
     728                if g != 0 | b != 0:
     729                        print()
     730fmt = Fmt()
     731`next( fmt )`                    # prime, next prewritten
     732for i in range( 41 ):
     733        `fmt.send( 'a' );`      # send to yield
     734\end{python}
     735\end{lrbox}
     736\subfloat[Fibonacci]{\label{f:PythonFibonacci}\usebox\myboxA}
     737\hspace{3pt}
     738\vrule
     739\hspace{3pt}
     740\subfloat[Formatter]{\label{f:PythonFormatter}\usebox\myboxB}
     741\caption{Python generator}
     742\label{f:PythonGenerator}
     743
     744\bigskip
     745
    925746\begin{tabular}{@{}l|l@{}}
    926747\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     
    929750`generator` Driver {
    930751        Status status;
    931         char byte, * msg; // communication
    932         int lnth, sum;      // local state
    933         short int crc;
     752        unsigned char byte, * msg; // communication
     753        unsigned int lnth, sum;      // local state
     754        unsigned short int crc;
    934755};
    935756void ?{}( Driver & d, char * m ) { d.msg = m; }
     
    979800(The trivial cycle is a generator resuming itself.)
    980801This control flow is similar to recursion for functions but without stack growth.
    981 Figure~\ref{f:PingPongFullCoroutineSteps} shows the steps for symmetric control-flow are creating, executing, and terminating the cycle.
     802The steps for symmetric control-flow are creating, executing, and terminating the cycle.
    982803Constructing the cycle must deal with definition-before-use to close the cycle, \ie, the first generator must know about the last generator, which is not within scope.
    983804(This issue occurs for any cyclic data structure.)
    984 The example creates the generators, @ping@/@pong@, and then assigns the partners that form the cycle.
    985 % (Alternatively, the constructor can assign the partners as they are declared, except the first, and the first-generator partner is set after the last generator declaration to close the cycle.)
    986 Once the cycle is formed, the program main resumes one of the generators, @ping@, and the generators can then traverse an arbitrary cycle using @resume@ to activate partner generator(s).
     805% The example creates all the generators and then assigns the partners that form the cycle.
     806% Alternatively, the constructor can assign the partners as they are declared, except the first, and the first-generator partner is set after the last generator declaration to close the cycle.
     807Once the cycle is formed, the program main resumes one of the generators, and the generators can then traverse an arbitrary cycle using @resume@ to activate partner generator(s).
    987808Terminating the cycle is accomplished by @suspend@ or @return@, both of which go back to the stack frame that started the cycle (program main in the example).
    988 Note, the creator and starter may be different, \eg if the creator calls another function that starts the cycle.
    989809The starting stack-frame is below the last active generator because the resume/resume cycle does not grow the stack.
    990 Also, since local variables are not retained in the generator function, there are no objects with destructors to be called, so the cost is the same as a function return.
    991 Destructor cost occurs when the generator instance is deallocated by the creator.
     810Also, since local variables are not retained in the generator function, it does not contain any objects with destructors that must be called, so the  cost is the same as a function return.
     811Destructor cost occurs when the generator instance is deallocated, which is easily controlled by the programmer.
     812
     813Figure~\ref{f:CPingPongSim} shows the implementation of the symmetric generator, where the complexity is the @resume@, which needs an extension to the calling convention to perform a forward rather than backward jump.
     814This jump-starts at the top of the next generator main to re-execute the normal calling convention to make space on the stack for its local variables.
     815However, before the jump, the caller must reset its stack (and any registers) equivalent to a @return@, but subsequently jump forward.
     816This semantics is basically a tail-call optimization, which compilers already perform.
     817The example shows the assembly code to undo the generator's entry code before the direct jump.
     818This assembly code depends on what entry code is generated, specifically if there are local variables and the level of optimization.
     819To provide this new calling convention requires a mechanism built into the compiler, which is beyond the scope of \CFA at this time.
     820Nevertheless, it is possible to hand generate any symmetric generators for proof of concept and performance testing.
     821A compiler could also eliminate other artifacts in the generator simulation to further increase performance, \eg LLVM has various coroutine support~\cite{CoroutineTS}, and \CFA can leverage this support should it fork @clang@.
    992822
    993823\begin{figure}
     
    996826\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    997827`generator PingPong` {
    998         int N, i;                               // local state
    999828        const char * name;
     829        int N;
     830        int i;                          // local state
    1000831        PingPong & partner; // rebindable reference
    1001832};
    1002833
    1003834void `main( PingPong & pp )` with(pp) {
    1004 
    1005 
    1006835        for ( ; i < N; i += 1 ) {
    1007836                sout | name | i;
     
    1021850\begin{cfa}[escapechar={},aboveskip=0pt,belowskip=0pt]
    1022851typedef struct PingPong {
    1023         int restart, N, i;
    1024852        const char * name;
     853        int N, i;
    1025854        struct PingPong * partner;
     855        void * next;
    1026856} PingPong;
    1027 #define PPCtor(name, N) {0, N, 0, name, NULL}
     857#define PPCtor(name, N) {name,N,0,NULL,NULL}
    1028858void comain( PingPong * pp ) {
    1029         static void * states[] = {&&s0, &&s1};
    1030         goto *states[pp->restart];
    1031   s0: pp->restart = 1;
     859        if ( pp->next ) goto *pp->next;
     860        pp->next = &&cycle;
    1032861        for ( ; pp->i < pp->N; pp->i += 1 ) {
    1033862                printf( "%s %d\n", pp->name, pp->i );
    1034863                asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
    1035864                asm( "mov  %rdi,%rax" );
    1036                 asm( "add  $16, %rsp" );
    1037                 asm( "popq %rbp" );
     865                asm( "popq %rbx" );
    1038866                asm( "jmp  comain" );
    1039           s1: ;
     867          cycle: ;
    1040868        }
    1041869}
     
    1053881\end{figure}
    1054882
    1055 \begin{figure}
    1056 \centering
    1057 \input{FullCoroutinePhases.pstex_t}
    1058 \vspace*{-10pt}
    1059 \caption{Symmetric coroutine steps: Ping / Pong}
    1060 \label{f:PingPongFullCoroutineSteps}
    1061 \end{figure}
    1062 
    1063 Figure~\ref{f:CPingPongSim} shows the C implementation of the \CFA symmetric generator, where there is still only one additional field, @restart@, but @resume@ is more complex because it does a forward rather than backward jump.
    1064 Before the jump, the parameter for the next call @partner@ is placed into the register used for the first parameter, @rdi@, and the remaining registers are reset for a return.
    1065 The @jmp comain@ restarts the function but with a different parameter, so the new call's behaviour depends on the state of the coroutine type, i.e., branch to restart location with different data state.
    1066 While the semantics of call forward is a tail-call optimization, which compilers perform, the generator state is different on each call rather a common state for a tail-recursive function (i.e., the parameter to the function never changes during the forward calls.
    1067 However, this assembler code depends on what entry code is generated, specifically if there are local variables and the level of optimization.
    1068 Hence, internal compiler support is necessary for any forward call (or backwards return), \eg LLVM has various coroutine support~\cite{CoroutineTS}, and \CFA can leverage this support should it eventually fork @clang@.
    1069 For this reason, \CFA does not support general symmetric generators at this time, but, it is possible to hand generate any symmetric generators (as in Figure~\ref{f:CPingPongSim}) for proof of concept and performance testing.
    1070 
    1071 Finally, part of this generator work was inspired by the recent \CCtwenty coroutine proposal~\cite{C++20Coroutine19}, which uses the general term coroutine to mean generator.
     883Finally, part of this generator work was inspired by the recent \CCtwenty generator proposal~\cite{C++20Coroutine19} (which they call coroutines).
    1072884Our work provides the same high-performance asymmetric generators as \CCtwenty, and extends their work with symmetric generators.
    1073885An additional \CCtwenty generator feature allows @suspend@ and @resume@ to be followed by a restricted compound statement that is executed after the current generator has reset its stack but before calling the next generator, specified with \CFA syntax:
     
    1084896\label{s:Coroutine}
    1085897
    1086 Stackful coroutines (Table~\ref{t:ExecutionPropertyComposition} case 5) extend generator semantics, \ie there is an implicit closure and @suspend@ may appear in a helper function called from the coroutine main.
     898Stackful coroutines extend generator semantics, \ie there is an implicit closure and @suspend@ may appear in a helper function called from the coroutine main.
    1087899A coroutine is specified by replacing @generator@ with @coroutine@ for the type.
    1088 Coroutine generality results in higher cost for creation, due to dynamic stack allocation, for execution, due to context switching among stacks, and for terminating, due to possible stack unwinding and dynamic stack deallocation.
     900Coroutine generality results in higher cost for creation, due to dynamic stack allocation, execution, due to context switching among stacks, and terminating, due to possible stack unwinding and dynamic stack deallocation.
    1089901A series of different kinds of coroutines and their implementations demonstrate how coroutines extend generators.
    1090902
    1091903First, the previous generator examples are converted to their coroutine counterparts, allowing local-state variables to be moved from the generator type into the coroutine main.
    1092 \begin{center}
    1093 \begin{tabular}{@{}l|l|l|l@{}}
    1094 \multicolumn{1}{c|}{Fibonacci} & \multicolumn{1}{c|}{Formatter} & \multicolumn{1}{c|}{Device Driver} & \multicolumn{1}{c}{PingPong} \\
    1095 \hline
     904\begin{description}
     905\item[Fibonacci]
     906Move the declaration of @fn1@ to the start of coroutine main.
    1096907\begin{cfa}[xleftmargin=0pt]
    1097 void main( Fib & fib ) ...
     908void main( Fib & fib ) with(fib) {
    1098909        `int fn1;`
    1099 
    1100 
    1101 \end{cfa}
    1102 &
     910\end{cfa}
     911\item[Formatter]
     912Move the declaration of @g@ and @b@ to the for loops in the coroutine main.
    1103913\begin{cfa}[xleftmargin=0pt]
    1104914for ( `g`; 5 ) {
    1105915        for ( `b`; 4 ) {
    1106 
    1107 
    1108 \end{cfa}
    1109 &
     916\end{cfa}
     917\item[Device Driver]
     918Move the declaration of @lnth@ and @sum@ to their points of initialization.
    1110919\begin{cfa}[xleftmargin=0pt]
    1111 status = CONT;
    1112 `int lnth = 0, sum = 0;`
    1113 ...
    1114 `short int crc = byte << 8;`
    1115 \end{cfa}
    1116 &
     920        status = CONT;
     921        `unsigned int lnth = 0, sum = 0;`
     922        ...
     923        `unsigned short int crc = byte << 8;`
     924\end{cfa}
     925\item[PingPong]
     926Move the declaration of @i@ to the for loop in the coroutine main.
    1117927\begin{cfa}[xleftmargin=0pt]
    1118 void main( PingPong & pp ) ...
     928void main( PingPong & pp ) with(pp) {
    1119929        for ( `i`; N ) {
    1120 
    1121 
    1122 \end{cfa}
    1123 \end{tabular}
    1124 \end{center}
     930\end{cfa}
     931\end{description}
    1125932It is also possible to refactor code containing local-state and @suspend@ statements into a helper function, like the computation of the CRC for the device driver.
    1126933\begin{cfa}
    1127 int Crc() {
     934unsigned int Crc() {
    1128935        `suspend;`
    1129         short int crc = byte << 8;
     936        unsigned short int crc = byte << 8;
    1130937        `suspend;`
    1131938        status = (crc | byte) == sum ? MSG : ECRC;
     
    1138945
    1139946\begin{comment}
    1140 Figure~\ref{f:Coroutine3States} creates a @coroutine@ type, @`coroutine` Fib { int fn; }@, which provides communication, @fn@, for the \newterm{coroutine main}, @main@, which runs on the coroutine stack, and possibly multiple interface functions, \eg @restart@.
     947Figure~\ref{f:Coroutine3States} creates a @coroutine@ type, @`coroutine` Fib { int fn; }@, which provides communication, @fn@, for the \newterm{coroutine main}, @main@, which runs on the coroutine stack, and possibly multiple interface functions, \eg @next@.
    1141948Like the structure in Figure~\ref{f:ExternalState}, the coroutine type allows multiple instances, where instances of this type are passed to the (overloaded) coroutine main.
    1142949The coroutine main's stack holds the state for the next generation, @f1@ and @f2@, and the code represents the three states in the Fibonacci formula via the three suspend points, to context switch back to the caller's @resume@.
    1143 The interface function @restart@, takes a Fibonacci instance and context switches to it using @resume@;
     950The interface function @next@, takes a Fibonacci instance and context switches to it using @resume@;
    1144951on restart, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned.
    1145952The first @resume@ is special because it allocates the coroutine stack and cocalls its coroutine main on that stack;
     
    13071114\begin{figure}
    13081115\centering
     1116\lstset{language=CFA,escapechar={},moredelim=**[is][\protect\color{red}]{`}{`}}% allow $
    13091117\begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
    13101118\begin{cfa}
    13111119`coroutine` Prod {
    1312         Cons & c;                       $\C[1.5in]{// communication}$
     1120        Cons & c;                       // communication
    13131121        int N, money, receipt;
    13141122};
    13151123void main( Prod & prod ) with( prod ) {
    1316         for ( i; N ) {          $\C{// 1st resume}\CRT$
     1124        // 1st resume starts here
     1125        for ( i; N ) {
    13171126                int p1 = random( 100 ), p2 = random( 100 );
     1127                sout | p1 | " " | p2;
    13181128                int status = delivery( c, p1, p2 );
     1129                sout | " $" | money | nl | status;
    13191130                receipt += 1;
    13201131        }
    13211132        stop( c );
     1133        sout | "prod stops";
    13221134}
    13231135int payment( Prod & prod, int money ) {
     
    13401152\begin{cfa}
    13411153`coroutine` Cons {
    1342         Prod & p;                       $\C[1.5in]{// communication}$
     1154        Prod & p;                       // communication
    13431155        int p1, p2, status;
    13441156        bool done;
    13451157};
    13461158void ?{}( Cons & cons, Prod & p ) {
    1347         &cons.p = &p;           $\C{// reassignable reference}$
     1159        &cons.p = &p; // reassignable reference
    13481160        cons.[status, done ] = [0, false];
    13491161}
    13501162void main( Cons & cons ) with( cons ) {
    1351         int money = 1, receipt; $\C{// 1st resume}\CRT$
     1163        // 1st resume starts here
     1164        int money = 1, receipt;
    13521165        for ( ; ! done; ) {
     1166                sout | p1 | " " | p2 | nl | " $" | money;
    13531167                status += 1;
    13541168                receipt = payment( p, money );
     1169                sout | " #" | receipt;
    13551170                money += 1;
    13561171        }
     1172        sout | "cons stops";
    13571173}
    13581174int delivery( Cons & cons, int p1, int p2 ) {
     
    13751191This example is illustrative because both producer/consumer have two interface functions with @resume@s that suspend execution in these interface (helper) functions.
    13761192The program main creates the producer coroutine, passes it to the consumer coroutine in its initialization, and closes the cycle at the call to @start@ along with the number of items to be produced.
    1377 The call to @start@ is the first @resume@ of @prod@, which remembers the program main as the starter and creates @prod@'s stack with a frame for @prod@'s coroutine main at the top, and context switches to it.
    1378 @prod@'s coroutine main starts, creates local-state variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random values, calling the consumer's @deliver@ function to transfer the values, and printing the status returned from the consumer.
     1193The first @resume@ of @prod@ creates @prod@'s stack with a frame for @prod@'s coroutine main at the top, and context switches to it.
     1194@prod@'s coroutine main starts, creates local-state variables that are retained between coroutine activations, and executes $N$ iterations, each generating two random values, calling the consumer to deliver the values, and printing the status returned from the consumer.
     1195
    13791196The producer call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status.
    1380 Similarly on the first resume, @cons@'s stack is created and initialized, holding local-state variables retained between subsequent activations of the coroutine.
    1381 The symmetric coroutine cycle forms when the consumer calls the producer's @payment@ function, which resumes the producer in the consumer's delivery function.
    1382 When the producer calls @delivery@ again, it resumes the consumer in the @payment@ function.
    1383 Both interface function than return to the their corresponding coroutine-main functions for the next cycle.
     1197On the first resume, @cons@'s stack is created and initialized, holding local-state variables retained between subsequent activations of the coroutine.
     1198The consumer iterates until the @done@ flag is set, prints the values delivered by the producer, increments status, and calls back to the producer via @payment@, and on return from @payment@, prints the receipt from the producer and increments @money@ (inflation).
     1199The call from the consumer to @payment@ introduces the cycle between producer and consumer.
     1200When @payment@ is called, the consumer copies values into the producer's communication variable and a resume is executed.
     1201The context switch restarts the producer at the point where it last context switched, so it continues in @delivery@ after the resume.
     1202@delivery@ returns the status value in @prod@'s coroutine main, where the status is printed.
     1203The loop then repeats calling @delivery@, where each call resumes the consumer coroutine.
     1204The context switch to the consumer continues in @payment@.
     1205The consumer increments and returns the receipt to the call in @cons@'s coroutine main.
     1206The loop then repeats calling @payment@, where each call resumes the producer coroutine.
    13841207Figure~\ref{f:ProdConsRuntimeStacks} shows the runtime stacks of the program main, and the coroutine mains for @prod@ and @cons@ during the cycling.
    1385 As a consequence of a coroutine retaining its last resumer for suspending back, these reverse pointers allow @suspend@ to cycle \emph{backwards} around a symmetric coroutine cycle.
    13861208
    13871209\begin{figure}
     
    13921214\caption{Producer / consumer runtime stacks}
    13931215\label{f:ProdConsRuntimeStacks}
     1216
     1217\medskip
     1218
     1219\begin{center}
     1220\input{FullCoroutinePhases.pstex_t}
     1221\end{center}
     1222\vspace*{-10pt}
     1223\caption{Ping / Pong coroutine steps}
     1224\label{f:PingPongFullCoroutineSteps}
    13941225\end{figure}
    13951226
    13961227Terminating a coroutine cycle is more complex than a generator cycle, because it requires context switching to the program main's \emph{stack} to shutdown the program, whereas generators started by the program main run on its stack.
    1397 Furthermore, each deallocated coroutine must execute all destructors for object allocated in the coroutine type \emph{and} allocated on the coroutine's stack at the point of suspension, which can be arbitrarily deep.
    1398 In the example, termination begins with the producer's loop stopping after N iterations and calling the consumer's @stop@ function, which sets the @done@ flag, resumes the consumer in function @payment@, terminating the call, and the consumer's loop in its coroutine main.
    1399 % (Not shown is having @prod@ raise a nonlocal @stop@ exception at @cons@ after it finishes generating values and suspend back to @cons@, which catches the @stop@ exception to terminate its loop.)
    1400 When the consumer's main ends, its stack is already unwound so any stack allocated objects with destructors are finalized.
    1401 The question now is where does control continue?
    1402 
     1228Furthermore, each deallocated coroutine must guarantee all destructors are run for object allocated in the coroutine type \emph{and} allocated on the coroutine's stack at the point of suspension, which can be arbitrarily deep.
     1229When a coroutine's main ends, its stack is already unwound so any stack allocated objects with destructors have been finalized.
    14031230The na\"{i}ve semantics for coroutine-cycle termination is to context switch to the last resumer, like executing a @suspend@/@return@ in a generator.
    14041231However, for coroutines, the last resumer is \emph{not} implicitly below the current stack frame, as for generators, because each coroutine's stack is independent.
    14051232Unfortunately, it is impossible to determine statically if a coroutine is in a cycle and unrealistic to check dynamically (graph-cycle problem).
    14061233Hence, a compromise solution is necessary that works for asymmetric (acyclic) and symmetric (cyclic) coroutines.
    1407 Our solution is to retain a coroutine's starter (first resumer), and context switch back to the starter when the coroutine ends.
    1408 Hence, the consumer restarts its first resumer, @prod@, in @stop@, and when the producer ends, it restarts its first resumer, program main, in @start@ (see dashed lines from the end of the coroutine mains in Figure~\ref{f:ProdConsRuntimeStacks}).
     1234
     1235Our solution is to context switch back to the first resumer (starter) once the coroutine ends.
    14091236This semantics works well for the most common asymmetric and symmetric coroutine usage patterns.
    1410 For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer;
    1411 for symmetric coroutines, it is common for the cycle creator to persist for the lifetime of the cycle.
     1237For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer.
     1238All previous generators converted to coroutines have this property.
     1239For symmetric coroutines, it is common for the cycle creator to persist for the lifetime of the cycle.
     1240Hence, the starter coroutine is remembered on the first resume and ending the coroutine resumes the starter.
     1241Figure~\ref{f:ProdConsRuntimeStacks} shows this semantic by the dashed lines from the end of the coroutine mains: @prod@ starts @cons@ so @cons@ resumes @prod@ at the end, and the program main starts @prod@ so @prod@ resumes the program main at the end.
    14121242For other scenarios, it is always possible to devise a solution with additional programming effort, such as forcing the cycle forward (backward) to a safe point before starting termination.
    14131243
    1414 Note, the producer/consumer example does not illustrate the full power of the starter semantics because @cons@ always ends first.
    1415 Assume generator @PingPong@ in Figure~\ref{f:PingPongSymmetricGenerator} is converted to a coroutine.
    1416 Unlike generators, coroutines have a starter structure with multiple levels, where the program main starts @ping@ and @ping@ starts @pong@.
    1417 By adjusting $N$ for either @ping@/@pong@, it is possible to have either finish first.
    1418 If @pong@ ends first, it resumes its starter @ping@ in its coroutine main, then @ping@ ends and resumes its starter the program main on return;
    1419 if @ping@ ends first, it resumes its starter the program main on return.
    1420 Regardless of the cycle complexity, the starter structure always leads back to the program main, but the path can be entered at an arbitrary point.
    1421 Once back at the program main (creator), coroutines @ping@ and @pong@ are deallocated, runnning any destructors for objects within the coroutine and possibly deallocating any coroutine stacks for non-terminated coroutines, where stack deallocation implies stack unwinding to find destructors for allocated objects on the stack.
    1422 Hence, the \CFA termination semantics for the generator and coroutine ensure correct deallocation semnatics, regardless of the coroutine's state (terminated or active), like any other aggregate object.
     1244The producer/consumer example does not illustrate the full power of the starter semantics because @cons@ always ends first.
     1245Assume generator @PingPong@ is converted to a coroutine.
     1246Figure~\ref{f:PingPongFullCoroutineSteps} shows the creation, starter, and cyclic execution steps of the coroutine version.
     1247The program main creates (declares) coroutine instances @ping@ and @pong@.
     1248Next, program main resumes @ping@, making it @ping@'s starter, and @ping@'s main resumes @pong@'s main, making it @pong@'s starter.
     1249Execution forms a cycle when @pong@ resumes @ping@, and cycles $N$ times.
     1250By adjusting $N$ for either @ping@/@pong@, it is possible to have either one finish first, instead of @pong@ always ending first.
     1251If @pong@ ends first, it resumes its starter @ping@ in its coroutine main, then @ping@ ends and resumes its starter the program main in function @start@.
     1252If @ping@ ends first, it resumes its starter the program main in function @start@.
     1253Regardless of the cycle complexity, the starter stack always leads back to the program main, but the stack can be entered at an arbitrary point.
     1254Once back at the program main, coroutines @ping@ and @pong@ are deallocated.
     1255For generators, deallocation runs the destructors for all objects in the generator type.
     1256For coroutines, deallocation deals with objects in the coroutine type and must also run the destructors for any objects pending on the coroutine's stack for any unterminated coroutine.
     1257Hence, if a coroutine's destructor detects the coroutine is not ended, it implicitly raises a cancellation exception (uncatchable exception) at the coroutine and resumes it so the cancellation exception can propagate to the root of the coroutine's stack destroying all local variable on the stack.
     1258So the \CFA semantics for the generator and coroutine, ensure both can be safely deallocated at any time, regardless of their current state, like any other aggregate object.
     1259Explicitly raising normal exceptions at another coroutine can replace flag variables, like @stop@, \eg @prod@ raises a @stop@ exception at @cons@ after it finishes generating values and resumes @cons@, which catches the @stop@ exception to terminate its loop.
     1260
     1261Finally, there is an interesting effect for @suspend@ with symmetric coroutines.
     1262A coroutine must retain its last resumer to suspend back because the resumer is on a different stack.
     1263These reverse pointers allow @suspend@ to cycle \emph{backwards}, which may be useful in certain cases.
     1264However, there is an anomaly if a coroutine resumes itself, because it overwrites its last resumer with itself, losing the ability to resume the last external resumer.
     1265To prevent losing this information, a self-resume does not overwrite the last resumer.
    14231266
    14241267
     
    14511294Users wanting to extend custom types or build their own can only do so in ways offered by the language.
    14521295Furthermore, implementing custom types without language support may display the power of a programming language.
    1453 \CFA blends the two approaches, providing custom type for idiomatic \CFA code, while extending and building new custom types is still possible, similar to Java concurrency with builtin and library (@java.util.concurrent@) monitors.
     1296\CFA blends the two approaches, providing custom type for idiomatic \CFA code, while extending and building new custom types is still possible, similar to Java concurrency with builtin and library.
    14541297
    14551298Part of the mechanism to generalize custom types is the \CFA trait~\cite[\S~2.3]{Moss18}, \eg the definition for custom-type @coroutine@ is anything satisfying the trait @is_coroutine@, and this trait both enforces and restricts the coroutine-interface functions.
     
    14611304forall( `dtype` T | is_coroutine(T) ) void $suspend$( T & ), resume( T & );
    14621305\end{cfa}
    1463 Note, copying generators/coroutines/threads is undefined because muliple objects cannot execute on a shared stack and stack copying does not work in unmanaged languages (no garbage collection), like C, because the stack may contain pointers to objects within it that require updating for the copy.
     1306Note, copying generators/coroutines/threads is not meaningful.
     1307For example, both the resumer and suspender descriptors can have bidirectional pointers;
     1308copying these coroutines does not update the internal pointers so behaviour of both copies would be difficult to understand.
     1309Furthermore, two coroutines cannot logically execute on the same stack.
     1310A deep coroutine copy, which copies the stack, is also meaningless in an unmanaged language (no garbage collection), like C, because the stack may contain pointers to object within it that require updating for the copy.
    14641311The \CFA @dtype@ property provides no \emph{implicit} copying operations and the @is_coroutine@ trait provides no \emph{explicit} copying operations, so all coroutines must be passed by reference (pointer).
    14651312The function definitions ensure there is a statically typed @main@ function that is the starting point (first stack frame) of a coroutine, and a mechanism to get (read) the coroutine descriptor from its handle.
     
    15051352The combination of custom types and fundamental @trait@ description of these types allows a concise specification for programmers and tools, while more advanced programmers can have tighter control over memory layout and initialization.
    15061353
    1507 Figure~\ref{f:CoroutineMemoryLayout} shows different memory-layout options for a coroutine (where a thread is similar).
     1354Figure~\ref{f:CoroutineMemoryLayout} shows different memory-layout options for a coroutine (where a task is similar).
    15081355The coroutine handle is the @coroutine@ instance containing programmer specified type global/communication variables across interface functions.
    15091356The coroutine descriptor contains all implicit declarations needed by the runtime, \eg @suspend@/@resume@, and can be part of the coroutine handle or separate.
    15101357The coroutine stack can appear in a number of locations and be fixed or variable sized.
    1511 Hence, the coroutine's stack could be a variable-length structure (VLS)\footnote{
    1512 We are examining VLSs, where fields can be variable-sized structures or arrays.
     1358Hence, the coroutine's stack could be a VLS\footnote{
     1359We are examining variable-sized structures (VLS), where fields can be variable-sized structures or arrays.
    15131360Once allocated, a VLS is fixed sized.}
    15141361on the allocating stack, provided the allocating stack is large enough.
    15151362For a VLS stack allocation/deallocation is an inexpensive adjustment of the stack pointer, modulo any stack constructor costs (\eg initial frame setup).
    1516 For stack allocation in the heap, allocation/deallocation is an expensive allocation, where the heap can be a shared resource, modulo any stack constructor costs.
    1517 It is also possible to use a split (segmented) stack calling convention, available with gcc and clang, allowing a variable-sized stack via a set of connected blocks in the heap.
     1363For heap stack allocation, allocation/deallocation is an expensive heap allocation (where the heap can be a shared resource), modulo any stack constructor costs.
     1364With heap stack allocation, it is also possible to use a split (segmented) stack calling convention, available with gcc and clang, so the stack is variable sized.
    15181365Currently, \CFA supports stack/heap allocated descriptors but only fixed-sized heap allocated stacks.
    15191366In \CFA debug-mode, the fixed-sized stack is terminated with a write-only page, which catches most stack overflows.
    15201367Experience teaching concurrency with \uC~\cite{CS343} shows fixed-sized stacks are rarely an issue for students.
    1521 Split-stack allocation is under development but requires recompilation of legacy code, which is not always possible.
     1368Split-stack allocation is under development but requires recompilation of legacy code, which may be impossible.
    15221369
    15231370\begin{figure}
     
    15331380
    15341381Concurrency is nondeterministic scheduling of independent sequential execution paths (threads), where each thread has its own stack.
    1535 A single thread with multiple stacks, \ie coroutining, does \emph{not} imply concurrency~\cite[\S~3]{Buhr05a}.
    1536 Coroutining self-schedule the thread across stacks so execution is deterministic.
     1382A single thread with multiple call stacks, \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}.
     1383In coroutining, coroutines self-schedule the thread across stacks so execution is deterministic.
    15371384(It is \emph{impossible} to generate a concurrency error when coroutining.)
    1538 
    1539 The transition to concurrency, even for a single thread with multiple stacks, occurs when coroutines context switch to a \newterm{scheduling coroutine}, introducing non-determinism from the coroutine perspective~\cite[\S~3]{Buhr05a}.
     1385However, coroutines are a stepping stone towards concurrency.
     1386
     1387The transition to concurrency, even for a single thread with multiple stacks, occurs when coroutines context switch to a \newterm{scheduling coroutine}, introducing non-determinism from the coroutine perspective~\cite[\S~3,]{Buhr05a}.
    15401388Therefore, a minimal concurrency system requires coroutines \emph{in conjunction with a nondeterministic scheduler}.
    1541 The resulting execution system now follows a cooperative threading-model~\cite{Adya02,libdill} because context-switching points to the scheduler (blocking) are known, but the next unblocking point is unknown due to the scheduler.
    1542 Adding \newterm{preemption} introduces \newterm{non-cooperative} or \newterm{preemptive} scheduling, where context switching points to the scheduler are unknown as they can occur randomly between any two instructions often based on a timer interrupt.
     1389The resulting execution system now follows a cooperative threading model~\cite{Adya02,libdill}, called \newterm{non-preemptive scheduling}.
     1390Adding \newterm{preemption} introduces non-cooperative scheduling, where context switching occurs randomly between any two instructions often based on a timer interrupt, called \newterm{preemptive scheduling}.
     1391While a scheduler introduces uncertain execution among explicit context switches, preemption introduces uncertainty by introducing implicit context switches.
    15431392Uncertainty gives the illusion of parallelism on a single processor and provides a mechanism to access and increase performance on multiple processors.
    15441393The reason is that the scheduler/runtime have complete knowledge about resources and how to best utilized them.
    1545 However, the introduction of unrestricted nondeterminism results in the need for \newterm{mutual exclusion} and \newterm{synchronization}~\cite[\S~4]{Buhr05a}, which restrict nondeterminism for correctness;
     1394However, the introduction of unrestricted nondeterminism results in the need for \newterm{mutual exclusion} and \newterm{synchronization}, which restrict nondeterminism for correctness;
    15461395otherwise, it is impossible to write meaningful concurrent programs.
    15471396Optimal concurrent performance is often obtained by having as much nondeterminism as mutual exclusion and synchronization correctness allow.
    15481397
    1549 A scheduler can also be stackless or stackful.
     1398A scheduler can either be a stackless or stackful.
    15501399For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch.
    15511400For stackful, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches.
     
    15561405\label{s:threads}
    15571406
    1558 Threading (Table~\ref{t:ExecutionPropertyComposition} case 11) needs the ability to start a thread and wait for its completion.
     1407Threading needs the ability to start a thread and wait for its completion.
    15591408A common API for this ability is @fork@ and @join@.
    1560 \vspace{4pt}
    1561 \par\noindent
    1562 \begin{tabular}{@{}l|l|l@{}}
    1563 \multicolumn{1}{c|}{\textbf{Java}} & \multicolumn{1}{c|}{\textbf{\Celeven}} & \multicolumn{1}{c}{\textbf{pthreads}} \\
    1564 \hline
    1565 \begin{cfa}
    1566 class MyThread extends Thread {...}
    1567 mythread t = new MyThread(...);
     1409\begin{cquote}
     1410\begin{tabular}{@{}lll@{}}
     1411\multicolumn{1}{c}{\textbf{Java}} & \multicolumn{1}{c}{\textbf{\Celeven}} & \multicolumn{1}{c}{\textbf{pthreads}} \\
     1412\begin{cfa}
     1413class MyTask extends Thread {...}
     1414mytask t = new MyTask(...);
    15681415`t.start();` // start
    15691416// concurrency
     
    15721419&
    15731420\begin{cfa}
    1574 class MyThread { ... } // functor
    1575 MyThread mythread;
    1576 `thread t( mythread, ... );` // start
     1421class MyTask { ... } // functor
     1422MyTask mytask;
     1423`thread t( mytask, ... );` // start
    15771424// concurrency
    15781425`t.join();` // wait
     
    15871434\end{cfa}
    15881435\end{tabular}
    1589 \vspace{1pt}
    1590 \par\noindent
     1436\end{cquote}
    15911437\CFA has a simpler approach using a custom @thread@ type and leveraging declaration semantics (allocation/deallocation), where threads implicitly @fork@ after construction and @join@ before destruction.
    15921438\begin{cfa}
    1593 thread MyThread {};
    1594 void main( MyThread & this ) { ... }
     1439thread MyTask {};
     1440void main( MyTask & this ) { ... }
    15951441int main() {
    1596         MyThread team`[10]`; $\C[2.5in]{// allocate stack-based threads, implicit start after construction}$
     1442        MyTask team`[10]`; $\C[2.5in]{// allocate stack-based threads, implicit start after construction}$
    15971443        // concurrency
    15981444} $\C{// deallocate stack-based threads, implicit joins before destruction}$
     
    16021448Arbitrary topologies are possible using dynamic allocation, allowing threads to outlive their declaration scope, identical to normal dynamic allocation.
    16031449\begin{cfa}
    1604 MyThread * factory( int N ) { ... return `anew( N )`; } $\C{// allocate heap-based threads, implicit start after construction}$
     1450MyTask * factory( int N ) { ... return `anew( N )`; } $\C{// allocate heap-based threads, implicit start after construction}$
    16051451int main() {
    1606         MyThread * team = factory( 10 );
     1452        MyTask * team = factory( 10 );
    16071453        // concurrency
    16081454        `delete( team );` $\C{// deallocate heap-based threads, implicit joins before destruction}\CRT$
     
    16501496
    16511497Threads in \CFA are user level run by runtime kernel threads (see Section~\ref{s:CFARuntimeStructure}), where user threads provide concurrency and kernel threads provide parallelism.
    1652 Like coroutines, and for the same design reasons, \CFA provides a custom @thread@ type and a @trait@ to enforce and restrict the thread-interface functions.
     1498Like coroutines, and for the same design reasons, \CFA provides a custom @thread@ type and a @trait@ to enforce and restrict the task-interface functions.
    16531499\begin{cquote}
    16541500\begin{tabular}{@{}c@{\hspace{3\parindentlnth}}c@{}}
     
    16811527\label{s:MutualExclusionSynchronization}
    16821528
    1683 Unrestricted nondeterminism is meaningless as there is no way to know when a result is completed and safe to access.
     1529Unrestricted nondeterminism is meaningless as there is no way to know when the result is completed without synchronization.
    16841530To produce meaningful execution requires clawing back some determinism using mutual exclusion and synchronization, where mutual exclusion provides access control for threads using shared data, and synchronization is a timing relationship among threads~\cite[\S~4]{Buhr05a}.
    1685 The shared data protected by mutual exlusion is called a \newterm{critical section}~\cite{Dijkstra65}, and the protection can be simple (only 1 thread) or complex (only N kinds of threads, \eg group~\cite{Joung00} or readers/writer~\cite{Courtois71}).
    1686 Without synchronization control in a critical section, an arriving thread can barge ahead of preexisting waiter threads resulting in short/long-term starvation, staleness/freshness problems, and/or incorrect transfer of data.
    1687 Preventing or detecting barging is a challenge with low-level locks, but made easier through higher-level constructs.
    1688 This challenge is often split into two different approaches: barging \emph{avoidance} and \emph{prevention}.
    1689 Approaches that unconditionally releasing a lock for competing threads to acquire must use barging avoidance with flag/counter variable(s) to force barging threads to wait;
    1690 approaches that conditionally hold locks during synchronization, \eg baton-passing~\cite{Andrews89}, prevent barging completely.
    1691 
    1692 At the lowest level, concurrent control is provided by atomic operations, upon which different kinds of locking mechanisms are constructed, \eg spin locks, semaphores~\cite{Dijkstra68b}, barriers, and path expressions~\cite{Campbell74}.
    1693 However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}.
    1694 A significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
    1695 Easing composability is another feature higher-level mutual-exclusion mechanisms can offer.
    1696 Some concurrent systems eliminate mutable shared-state by switching to non-shared communication like message passing~\cite{Thoth,Harmony,V-Kernel,MPI} (Erlang, MPI), channels~\cite{CSP} (CSP,Go), actors~\cite{Akka} (Akka, Scala), or functional techniques (Haskell).
     1531Some concurrent systems eliminate mutable shared-state by switching to stateless communication like message passing~\cite{Thoth,Harmony,V-Kernel,MPI} (Erlang, MPI), channels~\cite{CSP} (CSP,Go), actors~\cite{Akka} (Akka, Scala), or functional techniques (Haskell).
    16971532However, these approaches introduce a new communication mechanism for concurrency different from the standard communication using function call/return.
    16981533Hence, a programmer must learn and manipulate two sets of design/programming patterns.
    16991534While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account.
    1700 In contrast, approaches based on shared-state models more closely resemble the standard call/return programming model, resulting in a single programming paradigm.
    1701 Finally, a newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}.
    1702 While this approach is pursued in hardware~\cite{Nakaike15} and system languages, like \CC~\cite{Cpp-Transactions}, the performance and feature set is still too restrictive~\cite{Cascaval08,Boehm09} to be the main concurrency paradigm for system languages.
     1535In contrast, approaches based on stateful models more closely resemble the standard call/return programming model, resulting in a single programming paradigm.
     1536
     1537At the lowest level, concurrent control is implemented by atomic operations, upon which different kinds of locking mechanisms are constructed, \eg semaphores~\cite{Dijkstra68b}, barriers, and path expressions~\cite{Campbell74}.
     1538However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}.
     1539A newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}.
     1540While this approach is pursued in hardware~\cite{Nakaike15} and system languages, like \CC~\cite{Cpp-Transactions}, the performance and feature set is still too restrictive to be the main concurrency paradigm for system languages, which is why it is rejected as the core paradigm for concurrency in \CFA.
     1541
     1542One of the most natural, elegant, and efficient mechanisms for mutual exclusion and synchronization for shared-memory systems is the \emph{monitor}.
     1543First proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}, many concurrent programming languages provide monitors as an explicit language construct: \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}.
     1544In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as mutex locks or semaphores to simulate monitors.
     1545For these reasons, \CFA selected monitors as the core high-level concurrency construct, upon which higher-level approaches can be easily constructed.
     1546
     1547
     1548\subsection{Mutual Exclusion}
     1549
     1550A group of instructions manipulating a specific instance of shared data that must be performed atomically is called a \newterm{critical section}~\cite{Dijkstra65}, which is enforced by \newterm{simple mutual-exclusion}.
     1551The generalization is called a \newterm{group critical-section}~\cite{Joung00}, where multiple tasks with the same session use the resource simultaneously and different sessions are segregated, which is enforced by \newterm{complex mutual-exclusion} providing the correct kind and number of threads using a group critical-section.
     1552The readers/writer problem~\cite{Courtois71} is an instance of a group critical-section, where readers share a session but writers have a unique session.
     1553
     1554However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use.
     1555Methods range from low-level locks, which are fast and flexible but require significant attention for correctness, to higher-level concurrency techniques, which sacrifice some performance to improve ease of use.
     1556Ease of use comes by either guaranteeing some problems cannot occur, \eg deadlock free, or by offering a more explicit coupling between shared data and critical section.
     1557For example, the \CC @std::atomic<T>@ offers an easy way to express mutual-exclusion on a restricted set of operations, \eg reading/writing, for numerical types.
     1558However, a significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
     1559Easing composability is another feature higher-level mutual-exclusion mechanisms can offer.
     1560
     1561
     1562\subsection{Synchronization}
     1563
     1564Synchronization enforces relative ordering of execution, and synchronization tools provide numerous mechanisms to establish these timing relationships.
     1565Low-level synchronization primitives offer good performance and flexibility at the cost of ease of use;
     1566higher-level mechanisms often simplify usage by adding better coupling between synchronization and data, \eg receive-specific versus receive-any thread in message passing or offering specialized solutions, \eg barrier lock.
     1567Often synchronization is used to order access to a critical section, \eg ensuring a waiting writer thread enters the critical section before a calling reader thread.
     1568If the calling reader is scheduled before the waiting writer, the reader has barged.
     1569Barging can result in staleness/freshness problems, where a reader barges ahead of a writer and reads temporally stale data, or a writer barges ahead of another writer overwriting data with a fresh value preventing the previous value from ever being read (lost computation).
     1570Preventing or detecting barging is an involved challenge with low-level locks, which is made easier through higher-level constructs.
     1571This challenge is often split into two different approaches: barging avoidance and prevention.
     1572Algorithms that unconditionally releasing a lock for competing threads to acquire use barging avoidance during synchronization to force a barging thread to wait;
     1573algorithms that conditionally hold locks during synchronization, \eg baton-passing~\cite{Andrews89}, prevent barging completely.
    17031574
    17041575
     
    17061577\label{s:Monitor}
    17071578
    1708 One of the most natural, elegant, efficient, high-level mechanisms for mutual exclusion and synchronization for shared-memory systems is the \emph{monitor} (Table~\ref{t:ExecutionPropertyComposition} case 2).
    1709 First proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}, many concurrent programming languages provide monitors as an explicit language construct: \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}.
    1710 In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as mutex locks or semaphores to manually implement a monitor.
    1711 For these reasons, \CFA selected monitors as the core high-level concurrency construct, upon which higher-level approaches can be easily constructed.
    1712 
    1713 Specifically, a \textbf{monitor} is a set of functions that ensure mutual exclusion when accessing shared state.
    1714 More precisely, a monitor is a programming technique that implicitly binds mutual exclusion to static function scope by call/return, as opposed to locks, where mutual-exclusion is defined by acquire/release calls, independent of lexical context (analogous to block and heap storage allocation).
     1579A \textbf{monitor} is a set of functions that ensure mutual exclusion when accessing shared state.
     1580More precisely, a monitor is a programming technique that implicitly binds mutual exclusion to static function scope, as opposed to locks, where mutual-exclusion is defined by acquire/release calls, independent of lexical context (analogous to block and heap storage allocation).
    17151581Restricting acquire/release points eases programming, comprehension, and maintenance, at a slight cost in flexibility and efficiency.
    17161582\CFA uses a custom @monitor@ type and leverages declaration semantics (deallocation) to protect active or waiting threads in a monitor.
    17171583
    17181584The following is a \CFA monitor implementation of an atomic counter.
    1719 \begin{cfa}
     1585\begin{cfa}[morekeywords=nomutex]
    17201586`monitor` Aint { int cnt; }; $\C[4.25in]{// atomic integer counter}$
    1721 int ++?( Aint & `mutex` this ) with( this ) { return ++cnt; } $\C{// increment}$
    1722 int ?=?( Aint & `mutex` lhs, int rhs ) with( lhs ) { cnt = rhs; } $\C{// conversions with int, mutex optional}\CRT$
    1723 int ?=?( int & lhs, Aint & `mutex` rhs ) with( rhs ) { lhs = cnt; }
    1724 \end{cfa}
    1725 The operators use the parameter-only declaration type-qualifier @mutex@ to mark which parameters require locking during function execution to protect from race conditions.
    1726 The assignment operators provide bidirectional conversion between an atomic and normal integer without accessing field @cnt@.
    1727 (These operations only need @mutex@, if reading/writing the implementation type is not atomic.)
    1728 The atomic counter is used without any explicit mutual-exclusion and provides thread-safe semantics.
     1587int ++?( Aint & `mutex`$\(_{opt}\)$ this ) with( this ) { return ++cnt; } $\C{// increment}$
     1588int ?=?( Aint & `mutex`$\(_{opt}\)$ lhs, int rhs ) with( lhs ) { cnt = rhs; } $\C{// conversions with int}\CRT$
     1589int ?=?( int & lhs, Aint & `mutex`$\(_{opt}\)$ rhs ) with( rhs ) { lhs = cnt; }
     1590\end{cfa}
     1591% The @Aint@ constructor, @?{}@, uses the \lstinline[morekeywords=nomutex]@nomutex@ qualifier indicating mutual exclusion is unnecessary during construction because an object is inaccessible (private) until after it is initialized.
     1592% (While a constructor may publish its address into a global variable, doing so generates a race-condition.)
     1593The prefix increment operation, @++?@, is normally @mutex@, indicating mutual exclusion is necessary during function execution, to protect the incrementing from race conditions, unless there is an atomic increment instruction for the implementation type.
     1594The assignment operators provide bidirectional conversion between an atomic and normal integer without accessing field @cnt@;
     1595these operations only need @mutex@, if reading/writing the implementation type is not atomic.
     1596The atomic counter is used without any explicit mutual-exclusion and provides thread-safe semantics, which is similar to the \CC template @std::atomic@.
    17291597\begin{cfa}
    17301598int i = 0, j = 0, k = 5;
     
    17341602i = x; j = y; k = z;
    17351603\end{cfa}
    1736 Note, like other concurrent programming languages, \CFA has specializations for the basic types using atomic instructions for performance and a general trait similar to the \CC template @std::atomic@.
    17371604
    17381605\CFA monitors have \newterm{multi-acquire} semantics so the thread in the monitor may acquire it multiple times without deadlock, allowing recursion and calling other interface functions.
    1739 \newpage
    17401606\begin{cfa}
    17411607monitor M { ... } m;
     
    17461612\end{cfa}
    17471613\CFA monitors also ensure the monitor lock is released regardless of how an acquiring function ends (normal or exceptional), and returning a shared variable is safe via copying before the lock is released.
    1748 Similar safety is offered by \emph{explicit} opt-in disciplines like \CC RAII versus the monitor \emph{implicit} language-enforced safety guarantee ensuring no programmer usage errors.
     1614Similar safety is offered by \emph{explicit} mechanisms like \CC RAII;
     1615monitor \emph{implicit} safety ensures no programmer usage errors.
    17491616Furthermore, RAII mechanisms cannot handle complex synchronization within a monitor, where the monitor lock may not be released on function exit because it is passed to an unblocking thread;
    17501617RAII is purely a mutual-exclusion mechanism (see Section~\ref{s:Scheduling}).
     
    17721639\end{cquote}
    17731640The @dtype@ property prevents \emph{implicit} copy operations and the @is_monitor@ trait provides no \emph{explicit} copy operations, so monitors must be passed by reference (pointer).
     1641% Copying a lock is insecure because it is possible to copy an open lock and then use the open copy when the original lock is closed to simultaneously access the shared data.
     1642% Copying a monitor is secure because both the lock and shared data are copies, but copying the shared data is meaningless because it no longer represents a unique entity.
    17741643Similarly, the function definitions ensures there is a mechanism to get (read) the monitor descriptor from its handle, and a special destructor to prevent deallocation if a thread using the shared data.
    17751644The custom monitor type also inserts any locks needed to implement the mutual exclusion semantics.
     
    17831652For example, a monitor may be passed through multiple helper functions before it is necessary to acquire the monitor's mutual exclusion.
    17841653
    1785 \CFA requires programmers to identify the kind of parameter with the @mutex@ keyword and uses no keyword to mean \lstinline[morekeywords=nomutex]@nomutex@, because @mutex@ parameters are rare and no keyword is the \emph{normal} parameter semantics.
    1786 Hence, @mutex@ parameters are documentation, at the function and its prototype, to both programmer and compiler, without other redundant keywords.
    1787 Furthermore, \CFA relies heavily on traits as an abstraction mechanism, so the @mutex@ qualifier prevents coincidentally matching of a monitor trait with a type that is not a monitor, similar to coincidental inheritance where a shape and playing card can both be drawable.
     1654The benefit of mandatory monitor qualifiers is self-documentation, but requiring both @mutex@ and \lstinline[morekeywords=nomutex]@nomutex@ for all monitor parameters is redundant.
     1655Instead, the semantics has one qualifier as the default and the other required.
     1656For example, make the safe @mutex@ qualifier the default because assuming \lstinline[morekeywords=nomutex]@nomutex@ may cause subtle errors.
     1657Alternatively, make the unsafe \lstinline[morekeywords=nomutex]@nomutex@ qualifier the default because it is the \emph{normal} parameter semantics while @mutex@ parameters are rare.
     1658Providing a default qualifier implies knowing whether a parameter is a monitor.
     1659Since \CFA relies heavily on traits as an abstraction mechanism, types can coincidentally match the monitor trait but not be a monitor, similar to inheritance where a shape and playing card can both be drawable.
     1660For this reason, \CFA requires programmers to identify the kind of parameter with the @mutex@ keyword and uses no keyword to mean \lstinline[morekeywords=nomutex]@nomutex@.
    17881661
    17891662The next semantic decision is establishing which parameter \emph{types} may be qualified with @mutex@.
     
    17991672Function @f3@ has a multiple object matrix, and @f4@ a multiple object data structure.
    18001673While shown shortly, multiple object acquisition is possible, but the number of objects must be statically known.
    1801 Therefore, \CFA only acquires one monitor per parameter with exactly one level of indirection, and exclude pointer types to unknown sized arrays.
     1674Therefore, \CFA only acquires one monitor per parameter with at most one level of indirection, excluding pointers as it is impossible to statically determine the size.
    18021675
    18031676For object-oriented monitors, \eg Java, calling a mutex member \emph{implicitly} acquires mutual exclusion of the receiver object, @`rec`.foo(...)@.
     
    18061679While object-oriented monitors can be extended with a mutex qualifier for multiple-monitor members, no prior example of this feature could be found.}
    18071680called \newterm{bulk acquire}.
    1808 \CFA guarantees bulk acquisition order is consistent across calls to @mutex@ functions using the same monitors as arguments, so acquiring multiple monitors in a bulk acquire is safe from deadlock.
     1681\CFA guarantees acquisition order is consistent across calls to @mutex@ functions using the same monitors as arguments, so acquiring multiple monitors is safe from deadlock.
    18091682Figure~\ref{f:BankTransfer} shows a trivial solution to the bank transfer problem~\cite{BankTransfer}, where two resources must be locked simultaneously, using \CFA monitors with implicit locking and \CC with explicit locking.
    18101683A \CFA programmer only has to manage when to acquire mutual exclusion;
     
    18261699void transfer( BankAccount & `mutex` my,
    18271700        BankAccount & `mutex` your, int me2you ) {
    1828         // bulk acquire
     1701
    18291702        deposit( my, -me2you ); // debit
    18301703        deposit( your, me2you ); // credit
     
    18561729void transfer( BankAccount & my,
    18571730                        BankAccount & your, int me2you ) {
    1858         `scoped_lock lock( my.m, your.m );` // bulk acquire
     1731        `scoped_lock lock( my.m, your.m );`
    18591732        deposit( my, -me2you ); // debit
    18601733        deposit( your, me2you ); // credit
     
    18841757\end{figure}
    18851758
    1886 Users can still force the acquiring order by using or not using @mutex@.
     1759Users can still force the acquiring order by using @mutex@/\lstinline[morekeywords=nomutex]@nomutex@.
    18871760\begin{cfa}
    18881761void foo( M & mutex m1, M & mutex m2 ); $\C{// acquire m1 and m2}$
    1889 void bar( M & mutex m1, M & m2 ) { $\C{// only acquire m1}$
     1762void bar( M & mutex m1, M & /* nomutex */ m2 ) { $\C{// acquire m1}$
    18901763        ... foo( m1, m2 ); ... $\C{// acquire m2}$
    18911764}
    1892 void baz( M & m1, M & mutex m2 ) { $\C{// only acquire m2}$
     1765void baz( M & /* nomutex */ m1, M & mutex m2 ) { $\C{// acquire m2}$
    18931766        ... foo( m1, m2 ); ... $\C{// acquire m1}$
    18941767}
     
    19331806% There are many aspects of scheduling in a concurrency system, all related to resource utilization by waiting threads, \ie which thread gets the resource next.
    19341807% Different forms of scheduling include access to processors by threads (see Section~\ref{s:RuntimeStructureCluster}), another is access to a shared resource by a lock or monitor.
    1935 This section discusses scheduling for waiting threads eligible for monitor entry, \ie which user thread gets the shared resource next. (See Section~\ref{s:RuntimeStructureCluster} for scheduling kernel threads on virtual processors.)
    1936 While monitor mutual-exclusion provides safe access to its shared data, the data may indicate a thread cannot proceed, \eg a bounded buffer may be full/\-empty so produce/consumer threads must block.
    1937 Leaving the monitor and retrying (busy waiting) is impractical for high-level programming.
    1938 
    1939 Monitors eliminate busy waiting by providing synchronization within the monitor critical-section to schedule threads needing access to the shared data, where threads block versus spin.
     1808This section discusses monitor scheduling for waiting threads eligible for entry, \ie which thread gets the shared resource next. (See Section~\ref{s:RuntimeStructureCluster} for scheduling threads on virtual processors.)
     1809While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer may be full/empty so produce/consumer threads must block.
     1810Leaving the monitor and trying again (busy waiting) is impractical for high-level programming.
     1811Monitors eliminate busy waiting by providing synchronization to schedule threads needing access to the shared data, where threads block versus spinning.
    19401812Synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling.
    1941 \newterm{Internal} (largely) schedules threads located \emph{inside} the monitor and is accomplished using condition variables with signal and wait.
    1942 \newterm{External} (largely) schedules threads located \emph{outside} the monitor and is accomplished with the @waitfor@ statement.
    1943 Note, internal scheduling has a small amount of external scheduling and vice versus, so the naming denotes where the majority of the block threads reside (inside or outside) for scheduling.
    1944 For complex scheduling, the approaches can be combined, so there can be an equal number of threads waiting inside and outside.
    1945 
    1946 \CFA monitors do not allow calling threads to barge ahead of signalled threads (via barging prevention), which simplifies synchronization among threads in the monitor and increases correctness.
    1947 A direct consequence of this semantics is that unblocked waiting threads are not required to recheck the waiting condition, \ie waits are not in a starvation-prone busy-loop as required by the signals-as-hints style with barging.
    1948 Preventing barging comes directly from Hoare's semantics in the seminal paper on monitors~\cite[p.~550]{Hoare74}.
     1813\newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and on behalf of other threads attempting entry.
     1814Finally, \CFA monitors do not allow calling threads to barge ahead of signalled threads, which simplifies synchronization among threads in the monitor and increases correctness.
     1815If barging is allowed, synchronization between a signaller and signallee is difficult, often requiring additional flags and multiple unblock/block cycles.
     1816In fact, signals-as-hints is completely opposite from that proposed by Hoare in the seminal paper on monitors~\cite[p.~550]{Hoare74}.
    19491817% \begin{cquote}
    19501818% However, we decree that a signal operation be followed immediately by resumption of a waiting program, without possibility of an intervening procedure call from yet a third program.
    19511819% It is only in this way that a waiting program has an absolute guarantee that it can acquire the resource just released by the signalling program without any danger that a third program will interpose a monitor entry and seize the resource instead.~\cite[p.~550]{Hoare74}
    19521820% \end{cquote}
    1953 Furthermore, \CFA concurrency has no spurious wakeup~\cite[\S~9]{Buhr05a}, which eliminates an implicit self barging.
    1954 
    1955 Monitor mutual-exclusion means signalling cannot have the signaller and signalled thread in the monitor simultaneously, so only the signaller or signallee can proceed.
    1956 Figure~\ref{f:MonitorScheduling} shows internal/external scheduling for the bounded-buffer examples in Figure~\ref{f:GenericBoundedBuffer}.
    1957 For internal scheduling in Figure~\ref{f:BBInt}, the @signal@ moves the signallee (front thread of the specified condition queue) to urgent and the signaller continues (solid line).
    1958 Multiple signals move multiple signallees to urgent until the condition queue is empty.
    1959 When the signaller exits or waits, a thread is implicitly unblocked from urgent (if available) before unblocking a calling thread to prevent barging.
     1821Furthermore, \CFA concurrency has no spurious wakeup~\cite[\S~9]{Buhr05a}, which eliminates an implicit form of self barging.
     1822Hence, a \CFA @wait@ statement is not enclosed in a @while@ loop retesting a blocking predicate, which can cause thread starvation due to barging.
     1823
     1824Figure~\ref{f:MonitorScheduling} shows general internal/external scheduling (for the bounded-buffer example in Figure~\ref{f:InternalExternalScheduling}).
     1825External calling threads block on the calling queue, if the monitor is occupied, otherwise they enter in FIFO order.
     1826Internal threads block on condition queues via @wait@ and reenter from the condition in FIFO order.
     1827Alternatively, internal threads block on urgent from the @signal_block@ or @waitfor@, and reenter implicitly when the monitor becomes empty, \ie, the thread in the monitor exits or waits.
     1828
     1829There are three signalling mechanisms to unblock waiting threads to enter the monitor.
     1830Note, signalling cannot have the signaller and signalled thread in the monitor simultaneously because of the mutual exclusion, so either the signaller or signallee can proceed.
     1831For internal scheduling, threads are unblocked from condition queues using @signal@, where the signallee is moved to urgent and the signaller continues (solid line).
     1832Multiple signals move multiple signallees to urgent until the condition is empty.
     1833When the signaller exits or waits, a thread blocked on urgent is processed before calling threads to prevent barging.
    19601834(Java conceptually moves the signalled thread to the calling queue, and hence, allows barging.)
    1961 Signal is used when the signaller is providing the cooperation needed by the signallee (\eg creating an empty slot in a buffer for a producer) and the signaller immediately exits the monitor to run concurrently (consume the buffer element) and passes control of the monitor to the signalled thread, which can immediately take advantage of the state change.
    1962 Specifically, the @wait@ function atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the function's parameter list.
    1963 Signalling is unconditional because signalling an empty condition queue does nothing.
    1964 It is common to declare condition queues as monitor fields to prevent shared access, hence no locking is required for access as the queues are protected by the monitor lock.
    1965 In \CFA, a condition queue can be created/stored independently.
     1835The alternative unblock is in the opposite order using @signal_block@, where the signaller is moved to urgent and the signallee continues (dashed line), and is implicitly unblocked from urgent when the signallee exits or waits.
     1836
     1837For external scheduling, the condition queues are not used;
     1838instead threads are unblocked directly from the calling queue using @waitfor@ based on function names requesting mutual exclusion.
     1839(The linear search through the calling queue to locate a particular call can be reduced to $O(1)$.)
     1840The @waitfor@ has the same semantics as @signal_block@, where the signalled thread executes before the signallee, which waits on urgent.
     1841Executing multiple @waitfor@s from different signalled functions causes the calling threads to move to urgent.
     1842External scheduling requires urgent to be a stack, because the signaller expects to execute immediately after the specified monitor call has exited or waited.
     1843Internal scheduling behaves the same for an urgent stack or queue, except for multiple signalling, where the threads unblock from urgent in reverse order from signalling.
     1844If the restart order is important, multiple signalling by a signal thread can be transformed into daisy-chain signalling among threads, where each thread signals the next thread.
     1845We tried both a stack for @waitfor@ and queue for signalling, but that resulted in complex semantics about which thread enters next.
     1846Hence, \CFA uses a single urgent stack to correctly handle @waitfor@ and adequately support both forms of signalling.
    19661847
    19671848\begin{figure}
     
    19811862\end{figure}
    19821863
     1864Figure~\ref{f:BBInt} shows a \CFA generic bounded-buffer with internal scheduling, where producers/consumers enter the monitor, detect the buffer is full/empty, and block on an appropriate condition variable, @full@/@empty@.
     1865The @wait@ function atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the function's parameter list.
     1866The appropriate condition variable is signalled to unblock an opposite kind of thread after an element is inserted/removed from the buffer.
     1867Signalling is unconditional, because signalling an empty condition variable does nothing.
     1868It is common to declare condition variables as monitor fields to prevent shared access, hence no locking is required for access as the conditions are protected by the monitor lock.
     1869In \CFA, a condition variable can be created/stored independently.
     1870% To still prevent expensive locking on access, a condition variable is tied to a \emph{group} of monitors on first use, called \newterm{branding}, resulting in a low-cost boolean test to detect sharing from other monitors.
     1871
     1872% Signalling semantics cannot have the signaller and signalled thread in the monitor simultaneously, which means:
     1873% \begin{enumerate}
     1874% \item
     1875% The signalling thread returns immediately and the signalled thread continues.
     1876% \item
     1877% The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait).
     1878% \item
     1879% The signalling thread blocks but is marked for urgent unblocking at the next scheduling point and the signalled thread continues.
     1880% \end{enumerate}
     1881% The first approach is too restrictive, as it precludes solving a reasonable class of problems, \eg dating service (see Figure~\ref{f:DatingService}).
     1882% \CFA supports the next two semantics as both are useful.
     1883
    19831884\begin{figure}
    19841885\centering
     
    19921893                T elements[10];
    19931894        };
    1994         void ?{}( Buffer(T) & buf ) with(buf) {
     1895        void ?{}( Buffer(T) & buffer ) with(buffer) {
    19951896                front = back = count = 0;
    19961897        }
    1997 
    1998         void insert(Buffer(T) & mutex buf, T elm) with(buf){
    1999                 if ( count == 10 ) `wait( empty )`; // full ?
    2000                 // insert elm into buf
     1898        void insert( Buffer(T) & mutex buffer, T elem )
     1899                                with(buffer) {
     1900                if ( count == 10 ) `wait( empty )`;
     1901                // insert elem into buffer
    20011902                `signal( full )`;
    20021903        }
    2003         T remove( Buffer(T) & mutex buf ) with(buf) {
    2004                 if ( count == 0 ) `wait( full )`; // empty ?
    2005                 // remove elm from buf
     1904        T remove( Buffer(T) & mutex buffer ) with(buffer) {
     1905                if ( count == 0 ) `wait( full )`;
     1906                // remove elem from buffer
    20061907                `signal( empty )`;
    2007                 return elm;
     1908                return elem;
    20081909        }
    20091910}
    20101911\end{cfa}
    20111912\end{lrbox}
     1913
     1914% \newbox\myboxB
     1915% \begin{lrbox}{\myboxB}
     1916% \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1917% forall( otype T ) { // distribute forall
     1918%       monitor Buffer {
     1919%
     1920%               int front, back, count;
     1921%               T elements[10];
     1922%       };
     1923%       void ?{}( Buffer(T) & buffer ) with(buffer) {
     1924%               [front, back, count] = 0;
     1925%       }
     1926%       T remove( Buffer(T) & mutex buffer ); // forward
     1927%       void insert( Buffer(T) & mutex buffer, T elem )
     1928%                               with(buffer) {
     1929%               if ( count == 10 ) `waitfor( remove, buffer )`;
     1930%               // insert elem into buffer
     1931%
     1932%       }
     1933%       T remove( Buffer(T) & mutex buffer ) with(buffer) {
     1934%               if ( count == 0 ) `waitfor( insert, buffer )`;
     1935%               // remove elem from buffer
     1936%
     1937%               return elem;
     1938%       }
     1939% }
     1940% \end{cfa}
     1941% \end{lrbox}
    20121942
    20131943\newbox\myboxB
    20141944\begin{lrbox}{\myboxB}
    20151945\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2016 forall( otype T ) { // distribute forall
    2017         monitor Buffer {
    2018 
    2019                 int front, back, count;
    2020                 T elements[10];
    2021         };
    2022         void ?{}( Buffer(T) & buf ) with(buf) {
    2023                 front = back = count = 0;
    2024         }
    2025         T remove( Buffer(T) & mutex buf ); // forward
    2026         void insert(Buffer(T) & mutex buf, T elm) with(buf){
    2027                 if ( count == 10 ) `waitfor( remove : buf )`;
    2028                 // insert elm into buf
    2029 
    2030         }
    2031         T remove( Buffer(T) & mutex buf ) with(buf) {
    2032                 if ( count == 0 ) `waitfor( insert : buf )`;
    2033                 // remove elm from buf
    2034 
    2035                 return elm;
    2036         }
    2037 }
    2038 \end{cfa}
    2039 \end{lrbox}
    2040 
    2041 \subfloat[Internal scheduling]{\label{f:BBInt}\usebox\myboxA}
    2042 \hspace{1pt}
    2043 \vrule
    2044 \hspace{3pt}
    2045 \subfloat[External scheduling]{\label{f:BBExt}\usebox\myboxB}
    2046 
    2047 \caption{Generic bounded buffer}
    2048 \label{f:GenericBoundedBuffer}
    2049 \end{figure}
    2050 
    2051 The @signal_block@ provides the opposite unblocking order, where the signaller is moved to urgent and the signallee continues and a thread is implicitly unblocked from urgent when the signallee exits or waits (dashed line).
    2052 Signal block is used when the signallee is providing the cooperation needed by the signaller (\eg if the buffer is removed and a producer hands off an item to a consumer, as in Figure~\ref{f:DatingSignalBlock}) so the signaller must wait until the signallee unblocks, provides the cooperation, exits the monitor to run concurrently, and passes control of the monitor to the signaller, which can immediately take advantage of the state change.
    2053 Using @signal@ or @signal_block@ can be a dynamic decision based on whether the thread providing the cooperation arrives before or after the thread needing the cooperation.
    2054 
    2055 External scheduling in Figure~\ref{f:BBExt} simplifies internal scheduling by eliminating condition queues and @signal@/@wait@ (cases where it cannot are discussed shortly), and has existed in the programming language Ada for almost 40 years with variants in other languages~\cite{SR,ConcurrentC++,uC++}.
    2056 While prior languages use external scheduling solely for thread interaction, \CFA generalizes it to both monitors and threads.
    2057 External scheduling allows waiting for events from other threads while restricting unrelated events, that would otherwise have to wait on condition queues in the monitor.
    2058 Scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the function calls that can next acquire mutual exclusion.
    2059 Specifically, a thread calling the monitor is unblocked directly from the calling queue based on function names that can fulfill the cooperation required by the signaller.
    2060 (The linear search through the calling queue to locate a particular call can be reduced to $O(1)$.)
    2061 Hence, the @waitfor@ has the same semantics as @signal_block@, where the signallee thread from the calling queue executes before the signaller, which waits on urgent.
    2062 Now when a producer/consumer detects a full/empty buffer, the necessary cooperation for continuation is specified by indicating the next function call that can occur.
    2063 For example, a producer detecting a full buffer must have cooperation from a consumer to remove an item so function @remove@ is accepted, which prevents producers from entering the monitor, and after a consumer calls @remove@, the producer waiting on urgent is \emph{implicitly} unblocked because it can now continue its insert operation.
    2064 Hence, this mechanism is done in terms of control flow, next call, versus in terms of data, channels, as in Go/Rust @select@.
    2065 While both mechanisms have strengths and weaknesses, \CFA uses the control-flow mechanism to be consistent with other language features.
    2066 
    2067 Figure~\ref{f:ReadersWriterLock} shows internal/external scheduling for a readers/writer lock with no barging and threads are serviced in FIFO order to eliminate staleness/freshness among the reader/writer threads.
    2068 For internal scheduling in Figure~\ref{f:RWInt}, the readers and writers wait on the same condition queue in FIFO order, making it impossible to tell if a waiting thread is a reader or writer.
    2069 To clawback the kind of thread, a \CFA condition can store user data in the node for a blocking thread at the @wait@, \ie whether the thread is a @READER@ or @WRITER@.
    2070 An unblocked reader thread checks if the thread at the front of the queue is a reader and unblock it, \ie the readers daisy-chain signal the next group of readers demarcated by the next writer or end of the queue.
    2071 For external scheduling in Figure~\ref{f:RWExt}, a waiting reader checks if a writer is using the resource, and if so, restricts further calls until the writer exits by calling @EndWrite@.
    2072 The writer does a similar action for each reader or writer using the resource.
    2073 Note, no new calls to @StartRead@/@StartWrite@ may occur when waiting for the call to @EndRead@/@EndWrite@.
    2074 
    2075 \begin{figure}
    2076 \centering
    2077 \newbox\myboxA
    2078 \begin{lrbox}{\myboxA}
    2079 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2080 enum RW { READER, WRITER };
    20811946monitor ReadersWriter {
    2082         int rcnt, wcnt; // readers/writer using resource
    2083         `condition RWers;`
     1947        int rcnt, wcnt; // readers/writer using resource
    20841948};
    20851949void ?{}( ReadersWriter & rw ) with(rw) {
     
    20881952void EndRead( ReadersWriter & mutex rw ) with(rw) {
    20891953        rcnt -= 1;
    2090         if ( rcnt == 0 ) `signal( RWers )`;
    20911954}
    20921955void EndWrite( ReadersWriter & mutex rw ) with(rw) {
    20931956        wcnt = 0;
    2094         `signal( RWers );`
    20951957}
    20961958void StartRead( ReadersWriter & mutex rw ) with(rw) {
    2097         if ( wcnt !=0 || ! empty( RWers ) )
    2098                 `wait( RWers, READER )`;
     1959        if ( wcnt > 0 ) `waitfor( EndWrite, rw );`
    20991960        rcnt += 1;
    2100         if ( ! empty(RWers) && `front(RWers) == READER` )
    2101                 `signal( RWers )`;  // daisy-chain signalling
    21021961}
    21031962void StartWrite( ReadersWriter & mutex rw ) with(rw) {
    2104         if ( wcnt != 0 || rcnt != 0 ) `wait( RWers, WRITER )`;
    2105 
     1963        if ( wcnt > 0 ) `waitfor( EndWrite, rw );`
     1964        else while ( rcnt > 0 ) `waitfor( EndRead, rw );`
    21061965        wcnt = 1;
    21071966}
     1967
    21081968\end{cfa}
    21091969\end{lrbox}
    21101970
    2111 \newbox\myboxB
    2112 \begin{lrbox}{\myboxB}
    2113 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2114 
    2115 monitor ReadersWriter {
    2116         int rcnt, wcnt; // readers/writer using resource
    2117 
    2118 };
    2119 void ?{}( ReadersWriter & rw ) with(rw) {
    2120         rcnt = wcnt = 0;
    2121 }
    2122 void EndRead( ReadersWriter & mutex rw ) with(rw) {
    2123         rcnt -= 1;
    2124 
    2125 }
    2126 void EndWrite( ReadersWriter & mutex rw ) with(rw) {
    2127         wcnt = 0;
    2128 
    2129 }
    2130 void StartRead( ReadersWriter & mutex rw ) with(rw) {
    2131         if ( wcnt > 0 ) `waitfor( EndWrite : rw );`
    2132 
    2133         rcnt += 1;
    2134 
    2135 
    2136 }
    2137 void StartWrite( ReadersWriter & mutex rw ) with(rw) {
    2138         if ( wcnt > 0 ) `waitfor( EndWrite : rw );`
    2139         else while ( rcnt > 0 ) `waitfor( EndRead : rw );`
    2140         wcnt = 1;
    2141 }
    2142 \end{cfa}
    2143 \end{lrbox}
    2144 
    2145 \subfloat[Internal scheduling]{\label{f:RWInt}\usebox\myboxA}
    2146 \hspace{1pt}
     1971\subfloat[Generic bounded buffer, internal scheduling]{\label{f:BBInt}\usebox\myboxA}
     1972\hspace{3pt}
    21471973\vrule
    21481974\hspace{3pt}
    2149 \subfloat[External scheduling]{\label{f:RWExt}\usebox\myboxB}
    2150 
    2151 \caption{Readers / writer lock}
    2152 \label{f:ReadersWriterLock}
     1975\subfloat[Readers / writer lock, external scheduling]{\label{f:RWExt}\usebox\myboxB}
     1976
     1977\caption{Internal / external scheduling}
     1978\label{f:InternalExternalScheduling}
    21531979\end{figure}
    21541980
    2155 Finally, external scheduling requires urgent to be a stack, because the signaller expects to execute immediately after the specified monitor call has exited or waited.
    2156 Internal schedulling performing multiple signalling results in unblocking from urgent in the reverse order from signalling.
    2157 It is rare for the unblocking order to be important as an unblocked thread can be time-sliced immediately after leaving the monitor.
    2158 If the unblocking order is important, multiple signalling can be restructured into daisy-chain signalling, where each thread signals the next thread.
    2159 Hence, \CFA uses a single urgent stack to correctly handle @waitfor@ and adequately support both forms of signalling.
    2160 (Advanced @waitfor@ features are discussed in Section~\ref{s:ExtendedWaitfor}.)
     1981Figure~\ref{f:BBInt} can be transformed into external scheduling by removing the condition variables and signals/waits, and adding the following lines at the locations of the current @wait@s in @insert@/@remove@, respectively.
     1982\begin{cfa}[aboveskip=2pt,belowskip=1pt]
     1983if ( count == 10 ) `waitfor( remove, buffer )`;       |      if ( count == 0 ) `waitfor( insert, buffer )`;
     1984\end{cfa}
     1985Here, the producers/consumers detects a full/\-empty buffer and prevents more producers/consumers from entering the monitor until there is a free/empty slot in the buffer.
     1986External scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the function calls that can next acquire mutual exclusion.
     1987If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer.
     1988Threads calling excluded functions block outside of (external to) the monitor on the calling queue, versus blocking on condition queues inside of (internal to) the monitor.
     1989Figure~\ref{f:RWExt} shows a readers/writer lock written using external scheduling, where a waiting reader detects a writer using the resource and restricts further calls until the writer exits by calling @EndWrite@.
     1990The writer does a similar action for each reader or writer using the resource.
     1991Note, no new calls to @StarRead@/@StartWrite@ may occur when waiting for the call to @EndRead@/@EndWrite@.
     1992External scheduling allows waiting for events from other threads while restricting unrelated events, that would otherwise have to wait on conditions in the monitor.
     1993The mechnaism can be done in terms of control flow, \eg Ada @accept@ or \uC @_Accept@, or in terms of data, \eg Go @select@ on channels.
     1994While both mechanisms have strengths and weaknesses, this project uses the control-flow mechanism to be consistent with other language features.
     1995% Two challenges specific to \CFA for external scheduling are loose object-definitions (see Section~\ref{s:LooseObjectDefinitions}) and multiple-monitor functions (see Section~\ref{s:Multi-MonitorScheduling}).
     1996
     1997Figure~\ref{f:DatingService} shows a dating service demonstrating non-blocking and blocking signalling.
     1998The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
     1999A thread blocks until an appropriate partner arrives.
     2000The complexity is exchanging phone numbers in the monitor because of the mutual-exclusion property.
     2001For signal scheduling, the @exchange@ condition is necessary to block the thread finding the match, while the matcher unblocks to take the opposite number, post its phone number, and unblock the partner.
     2002For signal-block scheduling, the implicit urgent-queue replaces the explict @exchange@-condition and @signal_block@ puts the finding thread on the urgent condition and unblocks the matcher.
     2003The dating service is an example of a monitor that cannot be written using external scheduling because it requires knowledge of calling parameters to make scheduling decisions, and parameters of waiting threads are unavailable;
     2004as well, an arriving thread may not find a partner and must wait, which requires a condition variable, and condition variables imply internal scheduling.
     2005Furthermore, barging corrupts the dating service during an exchange because a barger may also match and change the phone numbers, invalidating the previous exchange phone number.
     2006Putting loops around the @wait@s does not correct the problem;
     2007the simple solution must be restructured to account for barging.
    21612008
    21622009\begin{figure}
     
    21722019};
    21732020int girl( DS & mutex ds, int phNo, int ccode ) {
    2174         if ( empty( Boys[ccode] ) ) {
     2021        if ( is_empty( Boys[ccode] ) ) {
    21752022                wait( Girls[ccode] );
    21762023                GirlPhNo = phNo;
     
    21992046};
    22002047int girl( DS & mutex ds, int phNo, int ccode ) {
    2201         if ( empty( Boys[ccode] ) ) { // no compatible
     2048        if ( is_empty( Boys[ccode] ) ) { // no compatible
    22022049                wait( Girls[ccode] ); // wait for boy
    22032050                GirlPhNo = phNo; // make phone number available
     
    22192066\qquad
    22202067\subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB}
    2221 \caption{Dating service Monitor}
    2222 \label{f:DatingServiceMonitor}
     2068\caption{Dating service}
     2069\label{f:DatingService}
    22232070\end{figure}
    22242071
    2225 Figure~\ref{f:DatingServiceMonitor} shows a dating service demonstrating non-blocking and blocking signalling.
    2226 The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
    2227 A thread blocks until an appropriate partner arrives.
    2228 The complexity is exchanging phone numbers in the monitor because of the mutual-exclusion property.
    2229 For signal scheduling, the @exchange@ condition is necessary to block the thread finding the match, while the matcher unblocks to take the opposite number, post its phone number, and unblock the partner.
    2230 For signal-block scheduling, the implicit urgent-queue replaces the explicit @exchange@-condition and @signal_block@ puts the finding thread on the urgent stack and unblocks the matcher.
    2231 
    2232 The dating service is an important example of a monitor that cannot be written using external scheduling.
    2233 First, because scheduling requires knowledge of calling parameters to make matching decisions, and parameters of calling threads are unavailable within the monitor.
    2234 For example, a girl thread within the monitor cannot examine the @ccode@ of boy threads waiting on the calling queue to determine if there is a matching partner.
    2235 Second, because a scheduling decision may be delayed when there is no immediate match, which requires a condition queue for waiting, and condition queues imply internal scheduling.
    2236 For example, if a girl thread could determine there is no calling boy with the same @ccode@, it must wait until a matching boy arrives.
    2237 Finally, barging corrupts the dating service during an exchange because a barger may also match and change the phone numbers, invalidating the previous exchange phone number.
    2238 This situation shows rechecking the waiting condition and waiting again (signals-as-hints) fails, requiring significant restructured to account for barging.
     2072In summation, for internal scheduling, non-blocking signalling (as in the producer/consumer example) is used when the signaller is providing the cooperation for a waiting thread;
     2073the signaller enters the monitor and changes state, detects a waiting threads that can use the state, performs a non-blocking signal on the condition queue for the waiting thread, and exits the monitor to run concurrently.
     2074The waiter unblocks next from the urgent queue, uses/takes the state, and exits the monitor.
     2075Blocking signal is the reverse, where the waiter is providing the cooperation for the signalling thread;
     2076the signaller enters the monitor, detects a waiting thread providing the necessary state, performs a blocking signal to place it on the urgent queue and unblock the waiter.
     2077The waiter changes state and exits the monitor, and the signaller unblocks next from the urgent queue to use/take the state.
    22392078
    22402079Both internal and external scheduling extend to multiple monitors in a natural way.
    22412080\begin{cquote}
    2242 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
     2081\begin{tabular}{@{}l@{\hspace{3\parindentlnth}}l@{}}
    22432082\begin{cfa}
    22442083monitor M { `condition e`; ... };
     
    22512090&
    22522091\begin{cfa}
    2253 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 ); // overload rtn
     2092void rtn$\(_1\)$( M & mutex m1, M & mutex m2 );
    22542093void rtn$\(_2\)$( M & mutex m1 );
    22552094void bar( M & mutex m1, M & mutex m2 ) {
    2256         ... waitfor( `rtn`${\color{red}\(_1\)}$ ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\) : m1, m2 )}$
    2257         ... waitfor( `rtn${\color{red}\(_2\)}$ : m1` ); ...
     2095        ... waitfor( `rtn` ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\), m1, m2 )}$
     2096        ... waitfor( `rtn, m1` ); ... // $\LstCommentStyle{waitfor( rtn\(_2\), m1 )}$
    22582097}
    22592098\end{cfa}
     
    22622101For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex parameters, \ie @wait( e, m1, m2 )@.
    22632102To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
    2264 Wait cannot statically verify the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
    2265 While \CC supports bulk locking, @wait@ only accepts a single lock for a condition queue, so bulk locking with condition queues is asymmetric.
     2103Wait cannot statically verifies the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
     2104While \CC supports bulk locking, @wait@ only accepts a single lock for a condition variable, so bulk locking with condition variables is asymmetric.
    22662105Finally, a signaller,
    22672106\begin{cfa}
     
    22722111must have acquired at least the same locks as the waiting thread signalled from a condition queue to allow the locks to be passed, and hence, prevent barging.
    22732112
    2274 Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn : m1, m2 )@.
    2275 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn : m1 )@.
     2113Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn, m1, m2 )@.
     2114To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@.
    22762115@waitfor@ does statically verify the monitor types passed are the same as the acquired mutex-parameters of the given function or function pointer, hence the function (pointer) prototype must be accessible.
    22772116% When an overloaded function appears in an @waitfor@ statement, calls to any function with that name are accepted.
     
    22812120void rtn( M & mutex m );
    22822121`int` rtn( M & mutex m );
    2283 waitfor( (`int` (*)( M & mutex ))rtn : m );
    2284 \end{cfa}
    2285 
    2286 The ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock (see Section~\ref{s:MutexAcquisition}).
    2287 \newpage
     2122waitfor( (`int` (*)( M & mutex ))rtn, m );
     2123\end{cfa}
     2124
     2125The ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock.
    22882126\begin{cfa}
    22892127void foo( M & mutex m1, M & mutex m2 ) {
    2290         ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired}$
    2291 void bar( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2}$
     2128        ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired )}$
     2129void bar( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2 )}$
    22922130        ... signal( `e` ); ...
    22932131\end{cfa}
    22942132The @wait@ only releases @m1@ so the signalling thread cannot acquire @m1@ and @m2@ to enter @bar@ and @signal@ the condition.
    2295 While deadlock can occur with multiple/nesting acquisition, this is a consequence of locks, and by extension monitor locking is not perfectly composable.
     2133While deadlock can occur with multiple/nesting acquisition, this is a consequence of locks, and by extension monitors, not being perfectly composable.
     2134
    22962135
    22972136
    22982137\subsection{\texorpdfstring{Extended \protect\lstinline@waitfor@}{Extended waitfor}}
    2299 \label{s:ExtendedWaitfor}
    23002138
    23012139Figure~\ref{f:ExtendedWaitfor} shows the extended form of the @waitfor@ statement to conditionally accept one of a group of mutex functions, with an optional statement to be performed \emph{after} the mutex function finishes.
     
    23082146Hence, the terminating @else@ clause allows a conditional attempt to accept a call without blocking.
    23092147If both @timeout@ and @else@ clause are present, the @else@ must be conditional, or the @timeout@ is never triggered.
    2310 There is also a traditional future wait queue (not shown) (\eg Microsoft @WaitForMultipleObjects@), to wait for a specified number of future elements in the queue.
    2311 Finally, there is a shorthand for specifying multiple functions using the same set of monitors: @waitfor( f, g, h : m1, m2, m3 )@.
     2148There is also a traditional future wait queue (not shown) (\eg Microsoft (@WaitForMultipleObjects@)), to wait for a specified number of future elements in the queue.
    23122149
    23132150\begin{figure}
     
    23362173The right example accepts either @mem1@ or @mem2@ if @C1@ and @C2@ are true.
    23372174
    2338 An interesting use of @waitfor@ is accepting the @mutex@ destructor to know when an object is deallocated, \eg assume the bounded buffer is restructured from a monitor to a thread with the following @main@.
     2175An interesting use of @waitfor@ is accepting the @mutex@ destructor to know when an object is deallocated, \eg assume the bounded buffer is restructred from a monitor to a thread with the following @main@.
    23392176\begin{cfa}
    23402177void main( Buffer(T) & buffer ) with(buffer) {
    23412178        for () {
    2342                 `waitfor( ^?{} : buffer )` break;
    2343                 or when ( count != 20 ) waitfor( insert : buffer ) { ... }
    2344                 or when ( count != 0 ) waitfor( remove : buffer ) { ... }
     2179                `waitfor( ^?{}, buffer )` break;
     2180                or when ( count != 20 ) waitfor( insert, buffer ) { ... }
     2181                or when ( count != 0 ) waitfor( remove, buffer ) { ... }
    23452182        }
    23462183        // clean up
     
    24342271To support this efficient semantics (and prevent barging), the implementation maintains a list of monitors acquired for each blocked thread.
    24352272When a signaller exits or waits in a monitor function/statement, the front waiter on urgent is unblocked if all its monitors are released.
    2436 Implementing a fast subset check for the necessary released monitors is important and discussed in the following sections.
     2273Implementing a fast subset check for the necessary released monitors is important.
    24372274% The benefit is encapsulating complexity into only two actions: passing monitors to the next owner when they should be released and conditionally waking threads if all conditions are met.
    24382275
    24392276
    2440 \subsection{\texorpdfstring{\protect\lstinline@waitfor@ Implementation}{waitfor Implementation}}
    2441 \label{s:waitforImplementation}
    2442 
    2443 In a statically-typed object-oriented programming language, a class has an exhaustive list of members, even when members are added via static inheritance (see Figure~\ref{f:uCinheritance}).
    2444 Knowing all members at compilation (even separate compilation) allows uniquely numbered them so the accept-statement implementation can use a fast/compact bit mask with $O(1)$ compare.
    2445 
    2446 \begin{figure}
    2447 \centering
    2448 \begin{lrbox}{\myboxA}
    2449 \begin{uC++}[aboveskip=0pt,belowskip=0pt]
    2450 $\emph{translation unit 1}$
    2451 _Monitor B { // common type in .h file
    2452         _Mutex virtual void `f`( ... );
    2453         _Mutex virtual void `g`( ... );
    2454         _Mutex virtual void w1( ... ) { ... _Accept(`f`, `g`); ... }
    2455 };
    2456 $\emph{translation unit 2}$
    2457 // include B
    2458 _Monitor D : public B { // inherit
    2459         _Mutex void `h`( ... ); // add
    2460         _Mutex void w2( ... ) { ... _Accept(`f`, `h`); ... }
    2461 };
    2462 \end{uC++}
    2463 \end{lrbox}
    2464 
    2465 \begin{lrbox}{\myboxB}
    2466 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2467 $\emph{translation unit 1}$
    2468 monitor M { ... }; // common type in .h file
    2469 void `f`( M & mutex m, ... );
    2470 void `g`( M & mutex m, ... );
    2471 void w1( M & mutex m, ... ) { ... waitfor(`f`, `g` : m); ... }
    2472 
    2473 $\emph{translation unit 2}$
    2474 // include M
    2475 extern void `f`( M & mutex m, ... ); // import f but not g
    2476 void `h`( M & mutex m ); // add
    2477 void w2( M & mutex m, ... ) { ... waitfor(`f`, `h` : m); ... }
    2478 
    2479 \end{cfa}
    2480 \end{lrbox}
    2481 
    2482 \subfloat[\uC]{\label{f:uCinheritance}\usebox\myboxA}
    2483 \hspace{3pt}
    2484 \vrule
    2485 \hspace{3pt}
    2486 \subfloat[\CFA]{\label{f:CFinheritance}\usebox\myboxB}
    2487 \caption{Member / Function visibility}
    2488 \label{f:MemberFunctionVisibility}
    2489 \end{figure}
    2490 
    2491 However, the @waitfor@ statement in translation unit 2 (see Figure~\ref{f:CFinheritance}) cannot see function @g@ in translation unit 1 precluding a unique numbering for a bit-mask because the monitor type only carries the protected shared-data.
     2277\subsection{Loose Object Definitions}
     2278\label{s:LooseObjectDefinitions}
     2279
     2280In an object-oriented programming language, a class includes an exhaustive list of operations.
     2281A new class can add members via static inheritance but the subclass still has an exhaustive list of operations.
     2282(Dynamic member adding, \eg JavaScript~\cite{JavaScript}, is not considered.)
     2283In the object-oriented scenario, the type and all its operators are always present at compilation (even separate compilation), so it is possible to number the operations in a bit mask and use an $O(1)$ compare with a similar bit mask created for the operations specified in a @waitfor@.
     2284
     2285However, in \CFA, monitor functions can be statically added/removed in translation units, making a fast subset check difficult.
     2286\begin{cfa}
     2287        monitor M { ... }; // common type, included in .h file
     2288translation unit 1
     2289        void `f`( M & mutex m );
     2290        void g( M & mutex m ) { waitfor( `f`, m ); }
     2291translation unit 2
     2292        void `f`( M & mutex m ); $\C{// replacing f and g for type M in this translation unit}$
     2293        void `g`( M & mutex m );
     2294        void h( M & mutex m ) { waitfor( `f`, m ) or waitfor( `g`, m ); } $\C{// extending type M in this translation unit}$
     2295\end{cfa}
     2296The @waitfor@ statements in each translation unit cannot form a unique bit-mask because the monitor type does not carry that information.
     2297Hence, function pointers are used to identify the functions listed in the @waitfor@ statement, stored in a variable-sized array.
     2298Then, the same implementation approach used for the urgent stack is used for the calling queue.
     2299Each caller has a list of monitors acquired, and the @waitfor@ statement performs a (usually short) linear search matching functions in the @waitfor@ list with called functions, and then verifying the associated mutex locks can be transfers.
    24922300(A possible way to construct a dense mapping is at link or load-time.)
    2493 Hence, function pointers are used to identify the functions listed in the @waitfor@ statement, stored in a variable-sized array.
    2494 Then, the same implementation approach used for the urgent stack (see Section~\ref{s:Scheduling}) is used for the calling queue.
    2495 Each caller has a list of monitors acquired, and the @waitfor@ statement performs a (short) linear search matching functions in the @waitfor@ list with called functions, and then verifying the associated mutex locks can be transfers.
    24962301
    24972302
     
    25082313The solution is for the programmer to disambiguate:
    25092314\begin{cfa}
    2510 waitfor( f : `m2` ); $\C{// wait for call to f with argument m2}$
     2315waitfor( f, `m2` ); $\C{// wait for call to f with argument m2}$
    25112316\end{cfa}
    25122317Both locks are acquired by function @g@, so when function @f@ is called, the lock for monitor @m2@ is passed from @g@ to @f@, while @g@ still holds lock @m1@.
     
    25152320monitor M { ... };
    25162321void f( M & mutex m1, M & mutex m2 );
    2517 void g( M & mutex m1, M & mutex m2 ) { waitfor( f : `m1, m2` ); $\C{// wait for call to f with arguments m1 and m2}$
     2322void g( M & mutex m1, M & mutex m2 ) { waitfor( f, `m1, m2` ); $\C{// wait for call to f with arguments m1 and m2}$
    25182323\end{cfa}
    25192324Again, the set of monitors passed to the @waitfor@ statement must be entirely contained in the set of monitors already acquired by the accepting function.
    2520 % Also, the order of the monitors in a @waitfor@ statement must match the order of the mutex parameters.
    2521 
    2522 Figure~\ref{f:UnmatchedMutexSets} shows internal and external scheduling with multiple monitors that must match exactly with a signalling or accepting thread, \ie partial matching results in waiting.
    2523 In both cases, the set of monitors is disjoint so unblocking is impossible.
     2325Also, the order of the monitors in a @waitfor@ statement is unimportant.
     2326
     2327Figure~\ref{f:UnmatchedMutexSets} shows an example where, for internal and external scheduling with multiple monitors, a signalling or accepting thread must match exactly, \ie partial matching results in waiting.
     2328For both examples, the set of monitors is disjoint so unblocking is impossible.
    25242329
    25252330\begin{figure}
     
    25502355}
    25512356void g( M1 & mutex m1, M2 & mutex m2 ) {
    2552         waitfor( f : m1, m2 );
     2357        waitfor( f, m1, m2 );
    25532358}
    25542359g( `m11`, m2 ); // block on accept
     
    25652370\end{figure}
    25662371
     2372
     2373\subsection{\texorpdfstring{\protect\lstinline@mutex@ Threads}{mutex Threads}}
     2374
     2375Threads in \CFA can also be monitors to allow \emph{direct communication} among threads, \ie threads can have mutex functions that are called by other threads.
     2376Hence, all monitor features are available when using threads.
     2377Figure~\ref{f:DirectCommunication} shows a comparison of direct call communication in \CFA with direct channel communication in Go.
     2378(Ada provides a similar mechanism to the \CFA direct communication.)
     2379The program main in both programs communicates directly with the other thread versus indirect communication where two threads interact through a passive monitor.
     2380Both direct and indirection thread communication are valuable tools in structuring concurrent programs.
     2381
    25672382\begin{figure}
    25682383\centering
     
    25712386
    25722387struct Msg { int i, j; };
    2573 monitor thread GoRtn { int i;  float f;  Msg m; };
     2388thread GoRtn { int i;  float f;  Msg m; };
    25742389void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; }
    25752390void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; }
     
    25812396        for () {
    25822397
    2583                 `waitfor( mem1 : gortn )` sout | i;  // wait for calls
    2584                 or `waitfor( mem2 : gortn )` sout | f;
    2585                 or `waitfor( mem3 : gortn )` sout | m.i | m.j;
    2586                 or `waitfor( ^?{} : gortn )` break; // low priority
     2398                `waitfor( mem1, gortn )` sout | i;  // wait for calls
     2399                or `waitfor( mem2, gortn )` sout | f;
     2400                or `waitfor( mem3, gortn )` sout | m.i | m.j;
     2401                or `waitfor( ^?{}, gortn )` break;
    25872402
    25882403        }
     
    26382453\hspace{3pt}
    26392454\subfloat[Go]{\label{f:Gochannel}\usebox\myboxB}
    2640 \caption{Direct versus indirect communication}
    2641 \label{f:DirectCommunicationComparison}
    2642 
    2643 \medskip
    2644 
    2645 \begin{cfa}
    2646 monitor thread DatingService {
    2647         condition Girls[CompCodes], Boys[CompCodes];
    2648         int girlPhoneNo, boyPhoneNo, ccode;
    2649 };
    2650 int girl( DatingService & mutex ds, int phoneno, int code ) with( ds ) {
    2651         girlPhoneNo = phoneno;  ccode = code;
    2652         `wait( Girls[ccode] );`                                                         $\C{// wait for boy}$
    2653         girlPhoneNo = phoneno;  return boyPhoneNo;
    2654 }
    2655 int boy( DatingService & mutex ds, int phoneno, int code ) with( ds ) {
    2656         boyPhoneNo = phoneno;  ccode = code;
    2657         `wait( Boys[ccode] );`                                                          $\C{// wait for girl}$
    2658         boyPhoneNo = phoneno;  return girlPhoneNo;
    2659 }
    2660 void main( DatingService & ds ) with( ds ) {                    $\C{// thread starts, ds defaults to mutex}$
    2661         for () {
    2662                 waitfor( ^?{} ) break;                                                  $\C{// high priority}$
    2663                 or waitfor( girl )                                                              $\C{// girl called, compatible boy ? restart boy then girl}$
    2664                         if ( ! is_empty( Boys[ccode] ) ) { `signal_block( Boys[ccode] );  signal_block( Girls[ccode] );` }
    2665                 or waitfor( boy ) {                                                             $\C{// boy called, compatible girl ? restart girl then boy}$
    2666                         if ( ! is_empty( Girls[ccode] ) ) { `signal_block( Girls[ccode] );  signal_block( Boys[ccode] );` }
    2667         }
    2668 }
    2669 \end{cfa}
    2670 \caption{Direct communication dating service}
    2671 \label{f:DirectCommunicationDatingService}
     2455\caption{Direct communication}
     2456\label{f:DirectCommunication}
    26722457\end{figure}
    26732458
     
    26842469void main( Ping & pi ) {
    26852470        for ( 10 ) {
    2686                 `waitfor( ping : pi );`
     2471                `waitfor( ping, pi );`
    26872472                `pong( po );`
    26882473        }
     
    26972482        for ( 10 ) {
    26982483                `ping( pi );`
    2699                 `waitfor( pong : po );`
     2484                `waitfor( pong, po );`
    27002485        }
    27012486}
     
    27122497
    27132498
    2714 \subsection{\texorpdfstring{\protect\lstinline@monitor@ Generators / Coroutines / Threads}{monitor Generators / Coroutines / Threads}}
    2715 
    2716 \CFA generators, coroutines, and threads can also be monitors (Table~\ref{t:ExecutionPropertyComposition} cases 4, 6, 12) allowing safe \emph{direct communication} with threads, \ie the custom types can have mutex functions that are called by other threads.
    2717 All monitor features are available within these mutex functions.
    2718 For example, if the formatter generator (or coroutine equivalent) in Figure~\ref{f:CFAFormatGen} is extended with the monitor property and this interface function is used to communicate with the formatter:
    2719 \begin{cfa}
    2720 void fmt( Fmt & mutex fmt, char ch ) { fmt.ch = ch; resume( fmt ) }
    2721 \end{cfa}
    2722 multiple threads can safely pass characters for formatting.
    2723 
    2724 Figure~\ref{f:DirectCommunicationComparison} shows a comparison of direct call-communication in \CFA versus indirect channel-communication in Go.
    2725 (Ada has a similar mechanism to \CFA direct communication.)
    2726 The program thread in \CFA @main@ uses the call/return paradigm to directly communicate with the @GoRtn main@, whereas Go switches to the channel paradigm to indirectly communicate with the goroutine.
    2727 Communication by multiple threads is safe for the @gortn@ thread via mutex calls in \CFA or channel assignment in Go.
    2728 
    2729 Figure~\ref{f:DirectCommunicationDatingService} shows the dating-service problem in Figure~\ref{f:DatingServiceMonitor} extended from indirect monitor communication to direct thread communication.
    2730 When converting a monitor to a thread (server), the coding pattern is to move as much code as possible from the accepted members into the thread main so it does an much work as possible.
    2731 Notice, the dating server is postponing requests for an unspecified time while continuing to accept new requests.
    2732 For complex servers (web-servers), there can be hundreds of lines of code in the thread main and safe interaction with clients can be complex.
     2499\subsection{Execution Properties}
     2500
     2501Table~\ref{t:ObjectPropertyComposition} shows how the \CFA high-level constructs cover 3 fundamental execution properties: thread, stateful function, and mutual exclusion.
     2502Case 1 is a basic object, with none of the new execution properties.
     2503Case 2 allows @mutex@ calls to Case 1 to protect shared data.
     2504Case 3 allows stateful functions to suspend/resume but restricts operations because the state is stackless.
     2505Case 4 allows @mutex@ calls to Case 3 to protect shared data.
     2506Cases 5 and 6 are the same as 3 and 4 without restriction because the state is stackful.
     2507Cases 7 and 8 are rejected because a thread cannot execute without a stackful state in a preemptive environment when context switching from the signal handler.
     2508Cases 9 and 10 have a stackful thread without and with @mutex@ calls.
     2509For situations where threads do not require direct communication, case 9 provides faster creation/destruction by eliminating @mutex@ setup.
     2510
     2511\begin{table}
     2512\caption{Object property composition}
     2513\centering
     2514\label{t:ObjectPropertyComposition}
     2515\renewcommand{\arraystretch}{1.25}
     2516%\setlength{\tabcolsep}{5pt}
     2517\begin{tabular}{c|c||l|l}
     2518\multicolumn{2}{c||}{object properties} & \multicolumn{2}{c}{mutual exclusion} \\
     2519\hline
     2520thread  & stateful                              & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\
     2521\hline
     2522\hline
     2523No              & No                                    & \textbf{1}\ \ \ aggregate type                & \textbf{2}\ \ \ @monitor@ aggregate type \\
     2524\hline
     2525No              & Yes (stackless)               & \textbf{3}\ \ \ @generator@                   & \textbf{4}\ \ \ @monitor@ @generator@ \\
     2526\hline
     2527No              & Yes (stackful)                & \textbf{5}\ \ \ @coroutine@                   & \textbf{6}\ \ \ @monitor@ @coroutine@ \\
     2528\hline
     2529Yes             & No / Yes (stackless)  & \textbf{7}\ \ \ {\color{red}rejected} & \textbf{8}\ \ \ {\color{red}rejected} \\
     2530\hline
     2531Yes             & Yes (stackful)                & \textbf{9}\ \ \ @thread@                              & \textbf{10}\ \ @monitor@ @thread@ \\
     2532\end{tabular}
     2533\end{table}
    27332534
    27342535
     
    27362537
    27372538For completeness and efficiency, \CFA provides a standard set of low-level locks: recursive mutex, condition, semaphore, barrier, \etc, and atomic instructions: @fetchAssign@, @fetchAdd@, @testSet@, @compareSet@, \etc.
    2738 Some of these low-level mechanism are used to build the \CFA runtime, but we always advocate using high-level mechanisms whenever possible.
     2539Some of these low-level mechanism are used in the \CFA runtime, but we strongly advocate using high-level mechanisms whenever possible.
    27392540
    27402541
     
    27792580\begin{cfa}
    27802581struct Adder {
    2781         int * row, cols;
     2582    int * row, cols;
    27822583};
    27832584int operator()() {
     
    28382639\label{s:RuntimeStructureCluster}
    28392640
    2840 A \newterm{cluster} is a collection of user and kernel threads, where the kernel threads run the user threads from the cluster's ready queue, and the operating system runs the kernel threads on the processors from its ready queue.
    2841 The term \newterm{virtual processor} is introduced as a synonym for kernel thread to disambiguate between user and kernel thread.
    2842 From the language perspective, a virtual processor is an actual processor (core).
    2843 
     2641A \newterm{cluster} is a collection of threads and virtual processors (abstract kernel-thread) that execute the (user) threads from its own ready queue (like an OS executing kernel threads).
    28442642The purpose of a cluster is to control the amount of parallelism that is possible among threads, plus scheduling and other execution defaults.
    28452643The default cluster-scheduler is single-queue multi-server, which provides automatic load-balancing of threads on processors.
     
    28602658Programs may use more virtual processors than hardware processors.
    28612659On a multiprocessor, kernel threads are distributed across the hardware processors resulting in virtual processors executing in parallel.
    2862 (It is possible to use affinity to lock a virtual processor onto a particular hardware processor~\cite{affinityLinux,affinityWindows}, which is used when caching issues occur or for heterogeneous hardware processors.) %, affinityFreebsd, affinityNetbsd, affinityMacosx
     2660(It is possible to use affinity to lock a virtual processor onto a particular hardware processor~\cite{affinityLinux, affinityWindows, affinityFreebsd, affinityNetbsd, affinityMacosx}, which is used when caching issues occur or for heterogeneous hardware processors.)
    28632661The \CFA runtime attempts to block unused processors and unblock processors as the system load increases;
    2864 balancing the workload with processors is difficult because it requires future knowledge, \ie what will the application workload do next.
     2662balancing the workload with processors is difficult because it requires future knowledge, \ie what will the applicaton workload do next.
    28652663Preemption occurs on virtual processors rather than user threads, via operating-system interrupts.
    28662664Thus virtual processors execute user threads, where preemption frequency applies to a virtual processor, so preemption occurs randomly across the executed user threads.
     
    28972695Nondeterministic preemption provides fairness from long-running threads, and forces concurrent programmers to write more robust programs, rather than relying on code between cooperative scheduling to be atomic.
    28982696This atomic reliance can fail on multi-core machines, because execution across cores is nondeterministic.
    2899 A different reason for not supporting preemption is that it significantly complicates the runtime system, \eg Windows runtime does not support interrupts and on Linux systems, interrupts are complex (see below).
     2697A different reason for not supporting preemption is that it significantly complicates the runtime system, \eg Microsoft runtime does not support interrupts and on Linux systems, interrupts are complex (see below).
    29002698Preemption is normally handled by setting a countdown timer on each virtual processor.
    2901 When the timer expires, an interrupt is delivered, and its signal handler resets the countdown timer, and if the virtual processor is executing in user code, the signal handler performs a user-level context-switch, or if executing in the language runtime kernel, the preemption is ignored or rolled forward to the point where the runtime kernel context switches back to user code.
     2699When the timer expires, an interrupt is delivered, and the interrupt handler resets the countdown timer, and if the virtual processor is executing in user code, the signal handler performs a user-level context-switch, or if executing in the language runtime kernel, the preemption is ignored or rolled forward to the point where the runtime kernel context switches back to user code.
    29022700Multiple signal handlers may be pending.
    29032701When control eventually switches back to the signal handler, it returns normally, and execution continues in the interrupted user thread, even though the return from the signal handler may be on a different kernel thread than the one where the signal is delivered.
    29042702The only issue with this approach is that signal masks from one kernel thread may be restored on another as part of returning from the signal handler;
    29052703therefore, the same signal mask is required for all virtual processors in a cluster.
    2906 Because preemption interval is usually long (1 millisecond) performance cost is negligible.
    2907 
    2908 Linux switched a decade ago from specific to arbitrary virtual-processor signal-delivery for applications with multiple kernel threads.
    2909 In the new semantics, a virtual-processor directed signal may be delivered to any virtual processor created by the application that does not have the signal blocked.
     2704Because preemption frequency is usually long (1 millisecond) performance cost is negligible.
     2705
     2706Linux switched a decade ago from specific to arbitrary process signal-delivery for applications with multiple kernel threads.
     2707\begin{cquote}
     2708A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked.
     2709If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which it will deliver the signal.
     2710SIGNAL(7) - Linux Programmer's Manual
     2711\end{cquote}
    29102712Hence, the timer-expiry signal, which is generated \emph{externally} by the Linux kernel to an application, is delivered to any of its Linux subprocesses (kernel threads).
    29112713To ensure each virtual processor receives a preemption signal, a discrete-event simulation is run on a special virtual processor, and only it sets and receives timer events.
     
    29252727\label{s:Performance}
    29262728
    2927 To test the performance of the \CFA runtime, a series of microbenchmarks are used to compare \CFA with pthreads, Java 11.0.6, Go 1.12.6, Rust 1.37.0, Python 3.7.6, Node.js 12.14.1, and \uC 7.0.0.
     2729To verify the implementation of the \CFA runtime, a series of microbenchmarks are performed comparing \CFA with pthreads, Java OpenJDK-9, Go 1.12.6 and \uC 7.0.0.
    29282730For comparison, the package must be multi-processor (M:N), which excludes libdill/libmil~\cite{libdill} (M:1)), and use a shared-memory programming model, \eg not message passing.
    2929 The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04.6 LTS, and pthreads/\CFA/\uC are compiled with gcc 9.2.1.
     2731The benchmark computer is an AMD Opteron\texttrademark\ 6380 NUMA 64-core, 8 socket, 2.5 GHz processor, running Ubuntu 16.04.6 LTS, and \CFA/\uC are compiled with gcc 6.5.
    29302732
    29312733All benchmarks are run using the following harness. (The Java harness is augmented to circumvent JIT issues.)
    29322734\begin{cfa}
    2933 #define BENCH( `run` ) uint64_t start = cputime_ns();  `run;`  double result = (double)(cputime_ns() - start) / N;
    2934 \end{cfa}
    2935 where CPU time in nanoseconds is from the appropriate language clock.
    2936 Each benchmark is performed @N@ times, where @N@ is selected so the benchmark runs in the range of 2--20 seconds for the specific programming language.
    2937 The total time is divided by @N@ to obtain the average time for a benchmark.
    2938 Each benchmark experiment is run 13 times and the average appears in the table.
     2735unsigned int N = 10_000_000;
     2736#define BENCH( `run` ) Time before = getTimeNsec();  `run;`  Duration result = (getTimeNsec() - before) / N;
     2737\end{cfa}
     2738The method used to get time is @clock_gettime( CLOCK_REALTIME )@.
     2739Each benchmark is performed @N@ times, where @N@ varies depending on the benchmark;
     2740the total time is divided by @N@ to obtain the average time for a benchmark.
     2741Each benchmark experiment is run 31 times.
    29392742All omitted tests for other languages are functionally identical to the \CFA tests and available online~\cite{CforallBenchMarks}.
    2940 % tar --exclude-ignore=exclude -cvhf benchmark.tar benchmark
    2941 
    2942 \paragraph{Context Switching}
     2743% tar --exclude=.deps --exclude=Makefile --exclude=Makefile.in --exclude=c.c --exclude=cxx.cpp --exclude=fetch_add.c -cvhf benchmark.tar benchmark
     2744
     2745\paragraph{Object Creation}
     2746
     2747Object creation is measured by creating/deleting the specific kind of concurrent object.
     2748Figure~\ref{f:creation} shows the code for \CFA, with results in Table~\ref{tab:creation}.
     2749The only note here is that the call stacks of \CFA coroutines are lazily created, therefore without priming the coroutine to force stack creation, the creation cost is artificially low.
     2750
     2751\begin{multicols}{2}
     2752\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
     2753\begin{cfa}
     2754@thread@ MyThread {};
     2755void @main@( MyThread & ) {}
     2756int main() {
     2757        BENCH( for ( N ) { @MyThread m;@ } )
     2758        sout | result`ns;
     2759}
     2760\end{cfa}
     2761\captionof{figure}{\CFA object-creation benchmark}
     2762\label{f:creation}
     2763
     2764\columnbreak
     2765
     2766\vspace*{-16pt}
     2767\captionof{table}{Object creation comparison (nanoseconds)}
     2768\label{tab:creation}
     2769
     2770\begin{tabular}[t]{@{}r*{3}{D{.}{.}{5.2}}@{}}
     2771\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2772\CFA Coroutine Lazy             & 13.2          & 13.1          & 0.44          \\
     2773\CFA Coroutine Eager    & 531.3         & 536.0         & 26.54         \\
     2774\CFA Thread                             & 2074.9        & 2066.5        & 170.76        \\
     2775\uC Coroutine                   & 89.6          & 90.5          & 1.83          \\
     2776\uC Thread                              & 528.2         & 528.5         & 4.94          \\
     2777Goroutine                               & 4068.0        & 4113.1        & 414.55        \\
     2778Java Thread                             & 103848.5      & 104295.4      & 2637.57       \\
     2779Pthreads                                & 33112.6       & 33127.1       & 165.90
     2780\end{tabular}
     2781\end{multicols}
     2782
     2783
     2784\paragraph{Context-Switching}
    29432785
    29442786In procedural programming, the cost of a function call is important as modularization (refactoring) increases.
    2945 (In many cases, a compiler inlines function calls to increase the size and number of basic blocks for optimizing.)
    2946 Similarly, when modularization extends to coroutines/threads, the time for a context switch becomes a relevant factor.
     2787(In many cases, a compiler inlines function calls to eliminate this cost.)
     2788Similarly, when modularization extends to coroutines/tasks, the time for a context switch becomes a relevant factor.
    29472789The coroutine test is from resumer to suspender and from suspender to resumer, which is two context switches.
    2948 %For async-await systems, the test is scheduling and fulfilling @N@ empty promises, where all promises are allocated before versus interleaved with fulfillment to avoid garbage collection.
    2949 For async-await systems, the test measures the cost of the @await@ expression entering the event engine by awaiting @N@ promises, where each created promise is resolved by an immediate event in the engine (using Node.js @setImmediate@).
    29502790The thread test is using yield to enter and return from the runtime kernel, which is two context switches.
    29512791The difference in performance between coroutine and thread context-switch is the cost of scheduling for threads, whereas coroutines are self-scheduling.
    2952 Figure~\ref{f:ctx-switch} shows the \CFA code for a coroutine/thread with results in Table~\ref{t:ctx-switch}.
    2953 
    2954 % From: Gregor Richards <gregor.richards@uwaterloo.ca>
    2955 % To: "Peter A. Buhr" <pabuhr@plg2.cs.uwaterloo.ca>
    2956 % Date: Fri, 24 Jan 2020 13:49:18 -0500
    2957 %
    2958 % I can also verify that the previous version, which just tied a bunch of promises together, *does not* go back to the
    2959 % event loop at all in the current version of Node. Presumably they're taking advantage of the fact that the ordering of
    2960 % events is intentionally undefined to just jump right to the next 'then' in the chain, bypassing event queueing
    2961 % entirely. That's perfectly correct behavior insofar as its difference from the specified behavior isn't observable, but
    2962 % it isn't typical or representative of much anything useful, because most programs wouldn't have whole chains of eager
    2963 % promises. Also, it's not representative of *anything* you can do with async/await, as there's no way to encode such an
    2964 % eager chain that way.
     2792Figure~\ref{f:ctx-switch} only shows the \CFA code for coroutines/threads (other systems are similar) with all results in Table~\ref{tab:ctx-switch}.
    29652793
    29662794\begin{multicols}{2}
    29672795\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    29682796\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2969 @coroutine@ C {};
    2970 void main( C & ) { for () { @suspend;@ } }
     2797@coroutine@ C {} c;
     2798void main( C & ) { for ( ;; ) { @suspend;@ } }
    29712799int main() { // coroutine test
    2972         C c;
    29732800        BENCH( for ( N ) { @resume( c );@ } )
    2974         sout | result;
    2975 }
    2976 int main() { // thread test
     2801        sout | result`ns;
     2802}
     2803int main() { // task test
    29772804        BENCH( for ( N ) { @yield();@ } )
    2978         sout | result;
     2805        sout | result`ns;
    29792806}
    29802807\end{cfa}
     
    29862813\vspace*{-16pt}
    29872814\captionof{table}{Context switch comparison (nanoseconds)}
    2988 \label{t:ctx-switch}
     2815\label{tab:ctx-switch}
    29892816\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    29902817\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    2991 C function                      & 1.8           & 1.8           & 0.0   \\
    2992 \CFA generator          & 1.8           & 2.0           & 0.3   \\
    2993 \CFA coroutine          & 32.5          & 32.9          & 0.8   \\
    2994 \CFA thread                     & 93.8          & 93.6          & 2.2   \\
    2995 \uC coroutine           & 50.3          & 50.3          & 0.2   \\
    2996 \uC thread                      & 97.3          & 97.4          & 1.0   \\
    2997 Python generator        & 40.9          & 41.3          & 1.5   \\
    2998 Node.js generator       & 32.6          & 32.2          & 1.0   \\
    2999 Node.js await           & 1852.2        & 1854.7        & 16.4  \\
    3000 Goroutine thread        & 143.0         & 143.3         & 1.1   \\
    3001 Rust thread                     & 332.0         & 331.4         & 2.4   \\
    3002 Java thread                     & 405.0         & 415.0         & 17.6  \\
    3003 Pthreads thread         & 334.3         & 335.2         & 3.9
     2818C function              & 1.8   & 1.8   & 0.01  \\
     2819\CFA generator  & 2.4   & 2.2   & 0.25  \\
     2820\CFA Coroutine  & 36.2  & 36.2  & 0.25  \\
     2821\CFA Thread             & 93.2  & 93.5  & 2.09  \\
     2822\uC Coroutine   & 52.0  & 52.1  & 0.51  \\
     2823\uC Thread              & 96.2  & 96.3  & 0.58  \\
     2824Goroutine               & 141.0 & 141.3 & 3.39  \\
     2825Java Thread             & 374.0 & 375.8 & 10.38 \\
     2826Pthreads Thread & 361.0 & 365.3 & 13.19
    30042827\end{tabular}
    30052828\end{multicols}
    30062829
    3007 \paragraph{Internal Scheduling}
    3008 
    3009 Internal scheduling is measured using a cycle of two threads signalling and waiting.
    3010 Figure~\ref{f:schedint} shows the code for \CFA, with results in Table~\ref{t:schedint}.
     2830
     2831\paragraph{Mutual-Exclusion}
     2832
     2833Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section.
     2834For monitors, entering and leaving a monitor function is measured.
     2835To put the results in context, the cost of entering a non-inline function and the cost of acquiring and releasing a @pthread_mutex@ lock is also measured.
     2836Figure~\ref{f:mutex} shows the code for \CFA with all results in Table~\ref{tab:mutex}.
    30112837Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
    3012 Java scheduling is significantly greater because the benchmark explicitly creates multiple thread in order to prevent the JIT from making the program sequential, \ie removing all locking.
    30132838
    30142839\begin{multicols}{2}
    30152840\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    30162841\begin{cfa}
    3017 volatile int go = 0;
    3018 @condition c;@
    30192842@monitor@ M {} m1/*, m2, m3, m4*/;
    3020 void call( M & @mutex p1/*, p2, p3, p4*/@ ) {
    3021         @signal( c );@
    3022 }
    3023 void wait( M & @mutex p1/*, p2, p3, p4*/@ ) {
    3024         go = 1; // continue other thread
    3025         for ( N ) { @wait( c );@ } );
    3026 }
    3027 thread T {};
    3028 void main( T & ) {
    3029         while ( go == 0 ) { yield(); } // waiter must start first
    3030         BENCH( for ( N ) { call( m1/*, m2, m3, m4*/ ); } )
    3031         sout | result;
    3032 }
     2843void __attribute__((noinline))
     2844do_call( M & @mutex m/*, m2, m3, m4*/@ ) {}
    30332845int main() {
    3034         T t;
    3035         wait( m1/*, m2, m3, m4*/ );
    3036 }
    3037 \end{cfa}
    3038 \captionof{figure}{\CFA Internal-scheduling benchmark}
    3039 \label{f:schedint}
     2846        BENCH(
     2847                for( N ) do_call( m1/*, m2, m3, m4*/ );
     2848        )
     2849        sout | result`ns;
     2850}
     2851\end{cfa}
     2852\captionof{figure}{\CFA acquire/release mutex benchmark}
     2853\label{f:mutex}
    30402854
    30412855\columnbreak
    30422856
    30432857\vspace*{-16pt}
    3044 \captionof{table}{Internal-scheduling comparison (nanoseconds)}
    3045 \label{t:schedint}
    3046 \bigskip
    3047 
    3048 \begin{tabular}{@{}r*{3}{D{.}{.}{5.2}}@{}}
    3049 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3050 \CFA @signal@, 1 monitor        & 364.4         & 364.2         & 4.4           \\
    3051 \CFA @signal@, 2 monitor        & 484.4         & 483.9         & 8.8           \\
    3052 \CFA @signal@, 4 monitor        & 709.1         & 707.7         & 15.0          \\
    3053 \uC @signal@ monitor            & 328.3         & 327.4         & 2.4           \\
    3054 Rust cond. variable                     & 7514.0        & 7437.4        & 397.2         \\
    3055 Java @notify@ monitor           & 9623.0        & 9654.6        & 236.2         \\
    3056 Pthreads cond. variable         & 5553.7        & 5576.1        & 345.6
     2858\captionof{table}{Mutex comparison (nanoseconds)}
     2859\label{tab:mutex}
     2860\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
     2861\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2862test and test-and-test lock             & 19.1  & 18.9  & 0.40  \\
     2863\CFA @mutex@ function, 1 arg.   & 45.9  & 46.6  & 1.45  \\
     2864\CFA @mutex@ function, 2 arg.   & 105.0 & 104.7 & 3.08  \\
     2865\CFA @mutex@ function, 4 arg.   & 165.0 & 167.6 & 5.65  \\
     2866\uC @monitor@ member rtn.               & 54.0  & 53.7  & 0.82  \\
     2867Java synchronized method                & 31.0  & 31.1  & 0.50  \\
     2868Pthreads Mutex Lock                             & 33.6  & 32.6  & 1.14
    30572869\end{tabular}
    30582870\end{multicols}
     
    30622874
    30632875External scheduling is measured using a cycle of two threads calling and accepting the call using the @waitfor@ statement.
    3064 Figure~\ref{f:schedext} shows the code for \CFA with results in Table~\ref{t:schedext}.
     2876Figure~\ref{f:ext-sched} shows the code for \CFA, with results in Table~\ref{tab:ext-sched}.
    30652877Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
    30662878
     
    30692881\vspace*{-16pt}
    30702882\begin{cfa}
    3071 @monitor@ M {} m1/*, m2, m3, m4*/;
    3072 void call( M & @mutex p1/*, p2, p3, p4*/@ ) {}
    3073 void wait( M & @mutex p1/*, p2, p3, p4*/@ ) {
    3074         for ( N ) { @waitfor( call : p1/*, p2, p3, p4*/ );@ }
    3075 }
     2883volatile int go = 0;
     2884@monitor@ M {} m;
    30762885thread T {};
     2886void __attribute__((noinline))
     2887do_call( M & @mutex@ ) {}
    30772888void main( T & ) {
    3078         BENCH( for ( N ) { call( m1/*, m2, m3, m4*/ ); } )
    3079         sout | result;
     2889        while ( go == 0 ) { yield(); }
     2890        while ( go == 1 ) { do_call( m ); }
     2891}
     2892int __attribute__((noinline))
     2893do_wait( M & @mutex@ m ) {
     2894        go = 1; // continue other thread
     2895        BENCH( for ( N ) { @waitfor( do_call, m );@ } )
     2896        go = 0; // stop other thread
     2897        sout | result`ns;
    30802898}
    30812899int main() {
    30822900        T t;
    3083         wait( m1/*, m2, m3, m4*/ );
     2901        do_wait( m );
    30842902}
    30852903\end{cfa}
    30862904\captionof{figure}{\CFA external-scheduling benchmark}
    3087 \label{f:schedext}
     2905\label{f:ext-sched}
    30882906
    30892907\columnbreak
     
    30912909\vspace*{-16pt}
    30922910\captionof{table}{External-scheduling comparison (nanoseconds)}
    3093 \label{t:schedext}
     2911\label{tab:ext-sched}
    30942912\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    30952913\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3096 \CFA @waitfor@, 1 monitor       & 367.1 & 365.3 & 5.0   \\
    3097 \CFA @waitfor@, 2 monitor       & 463.0 & 464.6 & 7.1   \\
    3098 \CFA @waitfor@, 4 monitor       & 689.6 & 696.2 & 21.5  \\
    3099 \uC \lstinline[language=uC++]|_Accept| monitor  & 328.2 & 329.1 & 3.4   \\
    3100 Go \lstinline[language=Golang]|select| channel  & 365.0 & 365.5 & 1.2
     2914\CFA @waitfor@, 1 @monitor@     & 376.4 & 376.8 & 7.63  \\
     2915\CFA @waitfor@, 2 @monitor@     & 491.4 & 492.0 & 13.31 \\
     2916\CFA @waitfor@, 4 @monitor@     & 681.0 & 681.7 & 19.10 \\
     2917\uC @_Accept@                           & 331.1 & 331.4 & 2.66
    31012918\end{tabular}
    31022919\end{multicols}
    31032920
    3104 \paragraph{Mutual-Exclusion}
    3105 
    3106 Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section.
    3107 For monitors, entering and leaving a monitor function is measured, otherwise the language-appropriate mutex-lock is measured.
    3108 For comparison, a spinning (versus blocking) test-and-test-set lock is presented.
    3109 Figure~\ref{f:mutex} shows the code for \CFA with results in Table~\ref{t:mutex}.
    3110 Note the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
     2921
     2922\paragraph{Internal Scheduling}
     2923
     2924Internal scheduling is measured using a cycle of two threads signalling and waiting.
     2925Figure~\ref{f:int-sched} shows the code for \CFA, with results in Table~\ref{tab:int-sched}.
     2926Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
     2927Java scheduling is significantly greater because the benchmark explicitly creates multiple thread in order to prevent the JIT from making the program sequential, \ie removing all locking.
    31112928
    31122929\begin{multicols}{2}
    31132930\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    31142931\begin{cfa}
    3115 @monitor@ M {} m1/*, m2, m3, m4*/;
    3116 call( M & @mutex p1/*, p2, p3, p4*/@ ) {}
     2932volatile int go = 0;
     2933@monitor@ M { @condition c;@ } m;
     2934void __attribute__((noinline))
     2935do_call( M & @mutex@ a1 ) { @signal( c );@ }
     2936thread T {};
     2937void main( T & this ) {
     2938        while ( go == 0 ) { yield(); }
     2939        while ( go == 1 ) { do_call( m ); }
     2940}
     2941int  __attribute__((noinline))
     2942do_wait( M & mutex m ) with(m) {
     2943        go = 1; // continue other thread
     2944        BENCH( for ( N ) { @wait( c );@ } );
     2945        go = 0; // stop other thread
     2946        sout | result`ns;
     2947}
    31172948int main() {
    3118         BENCH( for( N ) call( m1/*, m2, m3, m4*/ ); )
    3119         sout | result;
    3120 }
    3121 \end{cfa}
    3122 \captionof{figure}{\CFA acquire/release mutex benchmark}
    3123 \label{f:mutex}
     2949        T t;
     2950        do_wait( m );
     2951}
     2952\end{cfa}
     2953\captionof{figure}{\CFA Internal-scheduling benchmark}
     2954\label{f:int-sched}
    31242955
    31252956\columnbreak
    31262957
    31272958\vspace*{-16pt}
    3128 \captionof{table}{Mutex comparison (nanoseconds)}
    3129 \label{t:mutex}
    3130 \begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    3131 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3132 test-and-test-set lock                  & 19.1  & 18.9  & 0.4   \\
    3133 \CFA @mutex@ function, 1 arg.   & 48.3  & 47.8  & 0.9   \\
    3134 \CFA @mutex@ function, 2 arg.   & 86.7  & 87.6  & 1.9   \\
    3135 \CFA @mutex@ function, 4 arg.   & 173.4 & 169.4 & 5.9   \\
    3136 \uC @monitor@ member rtn.               & 54.8  & 54.8  & 0.1   \\
    3137 Goroutine mutex lock                    & 34.0  & 34.0  & 0.0   \\
    3138 Rust mutex lock                                 & 33.0  & 33.2  & 0.8   \\
    3139 Java synchronized method                & 31.0  & 31.0  & 0.0   \\
    3140 Pthreads mutex Lock                             & 31.0  & 31.1  & 0.4
     2959\captionof{table}{Internal-scheduling comparison (nanoseconds)}
     2960\label{tab:int-sched}
     2961\bigskip
     2962
     2963\begin{tabular}{@{}r*{3}{D{.}{.}{5.2}}@{}}
     2964\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
     2965\CFA @signal@, 1 @monitor@      & 372.6         & 374.3         & 14.17         \\
     2966\CFA @signal@, 2 @monitor@      & 492.7         & 494.1         & 12.99         \\
     2967\CFA @signal@, 4 @monitor@      & 749.4         & 750.4         & 24.74         \\
     2968\uC @signal@                            & 320.5         & 321.0         & 3.36          \\
     2969Java @notify@                           & 10160.5       & 10169.4       & 267.71        \\
     2970Pthreads Cond. Variable         & 4949.6        & 5065.2        & 363
    31412971\end{tabular}
    31422972\end{multicols}
    31432973
    3144 \paragraph{Creation}
    3145 
    3146 Creation is measured by creating/deleting a specific kind of control-flow object.
    3147 Figure~\ref{f:creation} shows the code for \CFA with results in Table~\ref{t:creation}.
    3148 Note, the call stacks of \CFA coroutines are lazily created on the first resume, therefore the cost of creation with and without a stack are presented.
    3149 
    3150 \begin{multicols}{2}
    3151 \lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    3152 \begin{cfa}
    3153 @coroutine@ MyCoroutine {};
    3154 void ?{}( MyCoroutine & this ) {
    3155 #ifdef EAGER
    3156         resume( this );
    3157 #endif
    3158 }
    3159 void main( MyCoroutine & ) {}
    3160 int main() {
    3161         BENCH( for ( N ) { @MyCoroutine c;@ } )
    3162         sout | result;
    3163 }
    3164 \end{cfa}
    3165 \captionof{figure}{\CFA creation benchmark}
    3166 \label{f:creation}
    3167 
    3168 \columnbreak
    3169 
    3170 \vspace*{-16pt}
    3171 \captionof{table}{Creation comparison (nanoseconds)}
    3172 \label{t:creation}
    3173 
    3174 \begin{tabular}[t]{@{}r*{3}{D{.}{.}{5.2}}@{}}
    3175 \multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} & \multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    3176 \CFA generator                  & 0.6           & 0.6           & 0.0           \\
    3177 \CFA coroutine lazy             & 13.4          & 13.1          & 0.5           \\
    3178 \CFA coroutine eager    & 144.7         & 143.9         & 1.5           \\
    3179 \CFA thread                             & 466.4         & 468.0         & 11.3          \\
    3180 \uC coroutine                   & 155.6         & 155.7         & 1.7           \\
    3181 \uC thread                              & 523.4         & 523.9         & 7.7           \\
    3182 Python generator                & 123.2         & 124.3         & 4.1           \\
    3183 Node.js generator               & 32.3          & 32.2          & 0.3           \\
    3184 Goroutine thread                & 751.0         & 750.5         & 3.1           \\
    3185 Rust thread                             & 53801.0       & 53896.8       & 274.9         \\
    3186 Java thread                             & 120274.0      & 120722.9      & 2356.7        \\
    3187 Pthreads thread                 & 31465.5       & 31419.5       & 140.4
    3188 \end{tabular}
    3189 \end{multicols}
    3190 
    3191 
    3192 \subsection{Discussion}
    3193 
    3194 Languages using 1:1 threading based on pthreads can at best meet or exceed (due to language overhead) the pthread results.
    3195 Note, pthreads has a fast zero-contention mutex lock checked in user space.
    3196 Languages with M:N threading have better performance than 1:1 because there is no operating-system interactions.
    3197 Languages with stackful coroutines have higher cost than stackless coroutines because of stack allocation and context switching;
    3198 however, stackful \uC and \CFA coroutines have approximately the same performance as stackless Python and Node.js generators.
    3199 The \CFA stackless generator is approximately 25 times faster for suspend/resume and 200 times faster for creation than stackless Python and Node.js generators.
    3200 
    32012974
    32022975\section{Conclusion}
     
    32042977Advanced control-flow will always be difficult, especially when there is temporal ordering and nondeterminism.
    32052978However, many systems exacerbate the difficulty through their presentation mechanisms.
    3206 This paper shows it is possible to understand high-level control-flow using three properties: statefulness, thread, mutual-exclusion/synchronization.
    3207 Combining these properties creates a number of high-level, efficient, and maintainable control-flow types: generator, coroutine, thread, each of which can be a monitor.
    3208 Eliminated from \CFA are barging and spurious wakeup, which are nonintuitive and lead to errors, and having to work with a bewildering set of low-level locks and acquisition techniques.
    3209 \CFA high-level race-free monitors and threads provide the core mechanisms for mutual exclusion and synchronization, without having to resort to magic qualifiers like @volatile@/@atomic@.
     2979This paper shows it is possible to present a hierarchy of control-flow features, generator, coroutine, thread, and monitor, providing an integrated set of high-level, efficient, and maintainable control-flow features.
     2980Eliminated from \CFA are spurious wakeup and barging, which are nonintuitive and lead to errors, and having to work with a bewildering set of low-level locks and acquisition techniques.
     2981\CFA high-level race-free monitors and tasks provide the core mechanisms for mutual exclusion and synchronization, without having to resort to magic qualifiers like @volatile@/@atomic@.
    32102982Extending these mechanisms to handle high-level deadlock-free bulk acquire across both mutual exclusion and synchronization is a unique contribution.
    32112983The \CFA runtime provides concurrency based on a preemptive M:N user-level threading-system, executing in clusters, which encapsulate scheduling of work on multiple kernel threads providing parallelism.
    32122984The M:N model is judged to be efficient and provide greater flexibility than a 1:1 threading model.
    32132985These concepts and the \CFA runtime-system are written in the \CFA language, extensively leveraging the \CFA type-system, which demonstrates the expressiveness of the \CFA language.
    3214 Performance comparisons with other concurrent systems/languages show the \CFA approach is competitive across all basic operations, which translates directly into good performance in well-written applications with advanced control-flow.
    3215 C programmers should feel comfortable using these mechanisms for developing complex control-flow in applications, with the ability to obtain maximum available performance by selecting mechanisms at the appropriate level of need using only calling communication.
     2986Performance comparisons with other concurrent systems/languages show the \CFA approach is competitive across all low-level operations, which translates directly into good performance in well-written concurrent applications.
     2987C programmers should feel comfortable using these mechanisms for developing complex control-flow in applications, with the ability to obtain maximum available performance by selecting mechanisms at the appropriate level of need.
    32162988
    32172989
     
    32333005\label{futur:nbio}
    32343006
    3235 Many modern workloads are not bound by computation but IO operations, common cases being web servers and XaaS~\cite{XaaS} (anything as a service).
     3007Many modern workloads are not bound by computation but IO operations, a common case being web servers and XaaS~\cite{XaaS} (anything as a service).
    32363008These types of workloads require significant engineering to amortizing costs of blocking IO-operations.
    32373009At its core, non-blocking I/O is an operating-system level feature queuing IO operations, \eg network operations, and registering for notifications instead of waiting for requests to complete.
     
    32613033\section{Acknowledgements}
    32623034
    3263 The authors recognize the design assistance of Aaron Moss, Rob Schluntz, Andrew Beach, and Michael Brooks; David Dice for commenting and helping with the Java benchmarks; and Gregor Richards for helping with the Node.js benchmarks.
    3264 This research is funded by a grant from Waterloo-Huawei (\url{http://www.huawei.com}) Joint Innovation Lab. %, and Peter Buhr is partially funded by the Natural Sciences and Engineering Research Council of Canada.
     3035The authors would like to recognize the design assistance of Aaron Moss, Rob Schluntz, Andrew Beach and Michael Brooks on the features described in this paper.
     3036Funding for this project has been provided by Huawei Ltd.\ (\url{http://www.huawei.com}). %, and Peter Buhr is partially funded by the Natural Sciences and Engineering Research Council of Canada.
    32653037
    32663038{%
    3267 \fontsize{9bp}{11.5bp}\selectfont%
     3039\fontsize{9bp}{12bp}\selectfont%
    32683040\bibliography{pl,local}
    32693041}%
  • doc/papers/concurrency/examples/Fib.py

    r7030dab r71d6bd8  
    44        while True:
    55                fn = fn1 + fn2; fn2 = fn1; fn1 = fn; yield fn
     6
     7
    68
    79f1 = Fib()
     
    1214# Local Variables: #
    1315# tab-width: 4 #
    14 # compile-command: "python3.7 Fib.py" #
     16# compile-command: "python3.5 Fib.py" #
    1517# End: #
  • doc/papers/concurrency/examples/Fib2.c

    r7030dab r71d6bd8  
    11#include <stdio.h>
    22
     3void mary() {
     4        printf( "MARY\n" );
     5}
     6
    37#define FIB_INIT { 0 }
    4 typedef struct { int restart; int fn1, fn2; } Fib;
     8typedef struct { int next; int fn1, fn2; } Fib;
    59int fib( Fib * f ) {
    6         static void * states[] = { &&s0, &&s1, &&s2 };
    7         goto *states[f->restart];
    8   s0:
     10        static void * states[] = { &&s1, &&s2, &&s3 };
     11        goto *states[f->next];
     12  s1:
     13        mary();
    914        f->fn1 = 0;
    10         f->restart = 1;
     15        f->next = 1;
    1116        return f->fn1;
    12   s1:
     17  s2:
     18        mary();
    1319        f->fn2 = f->fn1;
    1420        f->fn1 = 1;
    15         f->restart = 2;
     21        f->next = 2;
    1622        return f->fn1;
    17   s2:;
     23  s3:;
     24        mary();
    1825        int fn = f->fn1 + f->fn2;
    1926        f->fn2 = f->fn1;
  • doc/papers/concurrency/examples/Fib2.py

    r7030dab r71d6bd8  
    11def Fib():
    2     fn1, fn = 1, 0
     2    fn1, fn = 0, 1
    33    while True:
    4         yield fn
     4        yield fn1
    55        fn1, fn = fn, fn1 + fn
    66
     
    1212# Local Variables: #
    1313# tab-width: 4 #
    14 # compile-command: "python3.7 Fib2.py" #
     14# compile-command: "python3.5 Fib2.py" #
    1515# End: #
  • doc/papers/concurrency/examples/Fib3.c

    r7030dab r71d6bd8  
    22
    33typedef struct {
    4         int restart, fn1, fn;
     4        int fn1, fn;
     5        void * next;
    56} Fib;
    6 #define FibCtor { 0, 1, 0 }
     7#define FibCtor { 1, 0, NULL }
    78
    89Fib * comain( Fib * f ) {
    9         static void * states[] = {&&s0, &&s1};
    10         goto *states[f->restart];
    11   s0: f->restart = 1;
     10        if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
     11        f->next = &&s1;
    1212        for ( ;; ) {
    1313                return f;
  • doc/papers/concurrency/examples/FibRefactor.py

    r7030dab r71d6bd8  
    2222# Local Variables: #
    2323# tab-width: 4 #
    24 # compile-command: "python3.7 FibRefactor.py" #
     24# compile-command: "python3.5 FibRefactor.py" #
    2525# End: #
  • doc/papers/concurrency/examples/Format.c

    r7030dab r71d6bd8  
    22
    33typedef struct {
    4         int restart, g, b;
     4        void * next;
    55        char ch;
     6        int g, b;
    67} Fmt;
    78
    89void comain( Fmt * f ) {
    9         static void * states[] = {&&s0, &&s1};
    10         goto *states[f->restart];
    11   s0: f->restart = 1;
     10        if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
     11        f->next = &&s1;
    1212        for ( ;; ) {
    1313                for ( f->g = 0; f->g < 5; f->g += 1 ) {                 // groups
    1414                        for ( f->b = 0; f->b < 4; f->b += 1 ) {         // blocks
    15                                 do {
    16                                         return;  s1: ;
    17                                 } while ( f->ch == '\n' );                              // ignore
     15                                return;
     16                          s1:;  while ( f->ch == '\n' ) return;         // ignore
    1817                                printf( "%c", f->ch );                                  // print character
    1918                        }
     
    2524
    2625int main() {
    27         Fmt fmt = { 0 };
     26        Fmt fmt = { NULL };
    2827        comain( &fmt );                                                                         // prime
    2928        for ( ;; ) {
  • doc/papers/concurrency/examples/Format.cc

    r7030dab r71d6bd8  
    66                        for ( g = 0; g < 5; g += 1 ) { // groups of 5 blocks
    77                                for ( b = 0; b < 4; b += 1 ) { // blocks of 4 characters
    8                                         for ( ;; ) { // for newline characters
     8//                                      for ( ;; ) { // for newline characters
    99                                                suspend();
    10                                                 if ( ch != '\n' ) break; // ignore newline
    11                                         }
     10//                                              if ( ch != '\n' ) break; // ignore newline
     11//                                      }
    1212//                                      cout << ch; // print character
    1313                                }
     
    3131// Local Variables: //
    3232// tab-width: 4 //
    33 // compile-command: "u++-work -O2 -nodebug Format.cc" //
     33// compile-command: "u++-work -O2 -nodebubg Format.cc" //
    3434// End: //
  • doc/papers/concurrency/examples/Format.cfa

    r7030dab r71d6bd8  
    1111                for ( g = 0; g < 5; g += 1 ) {          // groups of 5 blocks
    1212                        for ( b = 0; b < 4; b += 1 ) {  // blocks of 4 characters
    13                                 do {
     13//                              do {
    1414                                        suspend();
    15                                 } while ( ch == '\n' || ch == '\t' );
     15//                              } while ( ch == '\n' || ch == '\t' );
    1616                                sout | ch;                                      // print character
    1717                        }
  • doc/papers/concurrency/examples/Format.data

    r7030dab r71d6bd8  
    1 abcdefghijklmnop
    2 qrstuvwxyzx
    3 xxxxxxxxxxxxx
     1abcdefghijklmnopqrstuvwxyzxxxxxxxxxxxxxx
  • doc/papers/concurrency/examples/Format.py

    r7030dab r71d6bd8  
    44                        for g in range( 5 ):    # groups of 5 blocks
    55                                for b in range( 4 ): # blocks of 4 characters
    6                                         while True:
    7                                                 ch = (yield) # receive from send
    8                                                 if '\n' not in ch:
    9                                                         break
    10                                         print( ch, end='' ) # receive from send
     6                                        print( (yield), end='' ) # receive from send
    117                                print( '  ', end='' ) # block separator
    128                        print()                                 # group separator
     
    1511                        print()
    1612
    17 input = "abcdefghijklmnop\nqrstuvwx\nyzxxxxxxxxxxxxxx\n"
    18 
    1913fmt = Format()
    2014next( fmt )                                                     # prime generator
    21 for i in input:
    22         fmt.send( i );                          # send to yield
     15for i in range( 41 ):
     16        fmt.send( 'a' );                                # send to yield
    2317
    2418# Local Variables: #
    2519# tab-width: 4 #
    26 # compile-command: "python3.7 Format.py" #
     20# compile-command: "python3.5 Format.py" #
    2721# End: #
  • doc/papers/concurrency/examples/Format1.c

    r7030dab r71d6bd8  
    22
    33typedef struct {
    4         int restart, g, b;
     4        void * next;
    55        char ch;
     6        int g, b;
    67} Fmt;
    78
    89void format( Fmt * f ) {
    9         static void * states[] = {&&s0, &&s1};
    10         goto *states[f->restart];
    11   s0: f->restart = 1;
     10        if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
     11        f->next = &&s1;
    1212        for ( ;; ) {
    1313                for ( f->g = 0; f->g < 5; f->g += 1 ) {                 // groups
    1414                        for ( f->b = 0; f->b < 4; f->b += 1 ) {         // blocks
    1515                                return;
    16                           s1: if ( f->ch == '\0' ) goto fini;           // EOF ?
     16                          s1: ;
     17                                if ( f->ch == '\0' ) goto fini;                 // EOF ?
    1718                                while ( f->ch == '\n' ) return;                 // ignore
    18 //                              printf( "%c", f->ch );                                  // print character
     19                                printf( "%c", f->ch );                                  // print character
    1920                        }
    20 //                      printf( " " );                                                          // block separator
     21                        printf( " " );                                                          // block separator
    2122                }
    22 //              printf( "\n" );                                                                 // group separator
     23                printf( "\n" );                                                                 // group separator
    2324        }
    24   fini:;
    25 //      if ( f->g != 0 || f->b != 0 ) printf( "\n" );
     25  fini:
     26        if ( f->g != 0 || f->b != 0 ) printf( "\n" );
    2627}
    2728
    2829int main() {
    29         Fmt fmt = { 0 };
     30        Fmt fmt = { NULL };
    3031        format( &fmt );                                                                         // prime
    31         fmt.ch = 'a';
    32         for ( long int i = 0; i < 1000000000; i += 1 ) {
    33 //              scanf( "%c", &fmt.ch );                                                 // direct read into communication variable
    34 //        if ( feof( stdin ) ) break;
     32        for ( ;; ) {
     33                scanf( "%c", &fmt.ch );                                                 // direct read into communication variable
     34          if ( feof( stdin ) ) break;
    3535                format( &fmt );
    3636        }
    37         fmt.ch = '\0';                                                                          // sentential (EOF)
     37        fmt.ch = '\0';
    3838        format( &fmt );
    3939}
  • doc/papers/concurrency/examples/PingPong.c

    r7030dab r71d6bd8  
    22
    33typedef struct PingPong {
    4         int restart;                                                                            // style 1
     4        const char * name;
    55        int N, i;
    6         const char * name;
    76        struct PingPong * partner;
    8         void * next;                                                                            // style 2
     7        void * next;
    98} PingPong;
    10 #define PPCtor( name, N ) { 0, N, 0, name, NULL, NULL }
    11 
     9#define PPCtor( name, N ) { name, N, 0, NULL, NULL }
    1210void comain( PingPong * pp ) __attribute__(( noinline ));
    1311void comain( PingPong * pp ) {
     12        if ( __builtin_expect(pp->next != 0, 1) ) goto *pp->next;
    1413#if 0
    15         if ( __builtin_expect(pp->next != 0, 1) ) goto *pp->next;
     14        pp->next = &&here;
     15                asm( "mov  %0,%%rdi" : "=m" (pp) );
     16                asm( "mov  %rdi,%rax" );
     17#ifndef OPT
     18#ifdef PRINT
     19                asm( "add  $16, %rsp" );
     20#endif // PRINT
     21                asm( "popq %rbp" );
     22#endif // ! OPT
     23
     24#ifdef OPT
     25#ifdef PRINT
     26                asm( "popq %rbx" );
     27#endif // PRINT
     28#endif // OPT
     29                asm( "jmp  comain" );
     30  here: ;
     31#endif // 0
     32
    1633        pp->next = &&cycle;
    1734        for ( ; pp->i < pp->N; pp->i += 1 ) {
     
    3653          cycle: ;
    3754        } // for
    38 #endif // 0
    39 
    40 #if 1
    41         static void * states[] = {&&s0, &&s1};
    42         goto *states[pp->restart];
    43   s0: pp->restart = 1;
    44         for ( ; pp->i < pp->N; pp->i += 1 ) {
    45 #ifdef PRINT
    46                 printf( "%s %d\n", pp->name, pp->i );
    47 #endif // PRINT
    48                 asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
    49                 asm( "mov  %rdi,%rax" );
    50 #ifndef OPT
    51 #ifdef PRINT
    52                 asm( "add  $16, %rsp" );
    53 #endif // PRINT
    54                 asm( "popq %rbp" );
    55 #endif // ! OPT
    56 
    57 #ifdef OPT
    58 #ifdef PRINT
    59                 asm( "popq %rbx" );
    60 #endif // PRINT
    61 #endif // OPT
    62                 asm( "jmp  comain" );
    63           s1: ;
    64         } // for
    65 #endif // 0
    6655}
    6756
     
    8170// Local Variables: //
    8271// tab-width: 4 //
    83 // compile-command: "gcc-9 -g -DPRINT PingPong.c" //
     72// compile-command: "gcc-8 -g -DPRINT PingPong.c" //
    8473// End: //
  • doc/papers/concurrency/examples/Pingpong.py

    r7030dab r71d6bd8  
    11def PingPong( name, N ):
    2         partner = yield                         # get partner
    3         yield                                           # resume scheduler
     2        partner = (yield)           # get partner
     3        yield                       # resume scheduler
    44        for i in range( N ):
    55                print( name )
    6                 yield partner                   # execute next
     6                yield partner           # execute next
    77        print( "end", name )
    88
    99def Scheduler():
    10         n = yield                                       # starting coroutine
    11         try:
    12                 while True:
    13                         n = next( n )           # schedule coroutine
    14         except StopIteration:
    15                 pass
     10        n = (yield)                 # starting coroutine
     11        while True:
     12                n = next( n )           # schedule coroutine
    1613
    1714pi = PingPong( "ping", 5 )
    1815po = PingPong( "pong", 5 )
    19 next( pi )                                              # prime
    20 pi.send( po )                                   # send partner
    21 next( po )                                              # prime
    22 po.send( pi )                                   # send partner
     16next( pi )                      # prime
     17pi.send( po )                   # send partner
     18next( po )                      # prime
     19po.send( pi )                   # send partner
    2320
    2421s = Scheduler();
    25 next( s )                                               # prime
     22next( s )                       # prime
    2623try:
    2724        s.send( pi )                            # start cycle
    28 except StopIteration:                   # scheduler stopped
    29         pass
     25except StopIteration:
     26        print( "scheduler stop" )
    3027print( "stop" )
    3128
    3229# Local Variables: #
    3330# tab-width: 4 #
    34 # compile-command: "python3.7 Pingpong.py" #
     31# compile-command: "python3.5 Pingpong.py" #
    3532# End: #
  • doc/papers/concurrency/examples/ProdCons.py

    r7030dab r71d6bd8  
    11def Prod( N ):
    2         cons = yield                            # get cons
    3         yield                                           # resume scheduler
     2        cons = (yield)              # get cons
     3        yield                       # resume scheduler
    44        for i in range( N ):
    55                print( "prod" )
    6                 yield cons                              # execute next
     6                yield cons              # execute next
    77        print( "end", "prod" )
    88
    99def Cons( N ):
    10         prod = yield                            # get prod
    11         yield                                           # resume scheduler
     10        prod = (yield)              # get prod
     11        yield                       # resume scheduler
    1212        for i in range( N ):
    1313                print( "cons" )
    14                 yield prod                              # execute next
     14                yield prod              # execute next
    1515        print( "end", "cons" )
    1616
    1717def Scheduler():
    18         n = yield                                       # starting coroutine
    19         try:
    20                 while True:
    21                         n = next( n )           # schedule coroutine
    22         except StopIteration:
    23                 pass
     18        n = (yield)                 # starting coroutine
     19        while True:
     20                n = next( n )           # schedule coroutine
    2421
    2522prod = Prod( 5 )
    2623cons = Cons( 5 )
    27 next( prod )                                    # prime
    28 prod.send( cons )                               # send cons
    29 next( cons )                                    # prime
    30 cons.send( prod )                               # send prod
     24next( prod )                    # prime
     25prod.send( cons )               # send cons
     26next( cons )                    # prime
     27cons.send( prod )               # send prod
    3128
    3229s = Scheduler();
    33 next( s )                                               # prime
     30next( s )                       # prime
    3431try:
    3532        s.send( prod )                          # start cycle
    36 except StopIteration:                   # scheduler stopped
    37         pass
     33except StopIteration:
     34        print( "scheduler stop" )
    3835print( "stop" )
    3936
    4037# Local Variables: #
    4138# tab-width: 4 #
    42 # compile-command: "python3.7 ProdCons.py" #
     39# compile-command: "python3.5 ProdCons.py" #
    4340# End: #
  • doc/papers/concurrency/examples/Refactor.py

    r7030dab r71d6bd8  
    2626# Local Variables: #
    2727# tab-width: 4 #
    28 # compile-command: "python3.7 Refactor.py" #
     28# compile-command: "python3.5 Refactor.py" #
    2929# End: #
  • doc/papers/concurrency/figures/FullCoroutinePhases.fig

    r7030dab r71d6bd8  
    88-2
    991200 2
    10 5 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 5175.000 2437.500 4875 1875 5175 1800 5475 1875
     105 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 4575.000 2437.500 4275 1875 4575 1800 4875 1875
    1111        1 1 1.00 45.00 90.00
    12 5 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 5175.000 1537.500 5475 2100 5175 2175 4875 2100
     125 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 4575.000 1537.500 4875 2100 4575 2175 4275 2100
    1313        1 1 1.00 45.00 90.00
    14 5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 4807.500 1642.500 4725 1425 4575 1650 4800 1875
     145 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 4207.500 1642.500 4125 1425 3975 1650 4200 1875
    1515        1 1 1.00 45.00 90.00
    16 6 1575 1575 2700 2025
    17162 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    1817        1 1 1.00 45.00 90.00
     
    2120        1 1 1.00 45.00 90.00
    2221         2175 1575 2400 1800
     222 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
     23        1 1 1.00 45.00 90.00
     24         3300 1575 3300 1800
     252 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
     26        1 1 1.00 45.00 90.00
     27         3300 2025 3300 2250
     284 1 0 100 0 0 10 0.0000 2 105 555 2100 1200 creation\001
    23294 1 0 100 0 4 10 0.0000 2 165 300 1725 1950 ping\001
    24304 1 0 100 0 4 10 0.0000 2 135 360 2475 1950 pong\001
    25 -6
    26 6 3075 1575 4200 2025
    27 6 3075 1575 4200 2025
    28 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    29         1 1 1.00 45.00 90.00
    30          3525 1575 3300 1800
    31 2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    32         1 1 1.00 45.00 90.00
    33          3675 1575 3900 1800
    34 4 1 0 100 0 4 10 0.0000 2 165 300 3225 1950 ping\001
    35 4 1 0 100 0 4 10 0.0000 2 135 360 3975 1950 pong\001
    36 -6
    37 -6
     314 1 0 100 0 4 10 0.0000 2 165 300 3300 1950 ping\001
     324 1 0 100 0 4 10 0.0000 2 135 360 3300 2400 pong\001
     334 1 0 100 0 0 10 0.0000 2 105 675 4575 1200 execution\001
     344 1 0 100 0 4 10 0.0000 2 165 300 4275 2025 ping\001
     354 1 0 100 0 4 10 0.0000 2 135 360 4875 2025 pong\001
     364 1 0 100 0 0 10 0.0000 2 90 420 3300 1200 starter\001
    38374 1 0 100 0 4 10 0.0000 2 165 705 2100 1500 pgm main\001
    39 4 1 0 100 0 4 10 0.0000 2 165 705 3600 1500 pgm main\001
    40 4 1 0 100 0 4 10 0.0000 2 165 300 4875 2025 ping\001
    41 4 1 0 100 0 4 10 0.0000 2 135 360 5475 2025 pong\001
    42 4 1 0 100 0 4 10 0.0000 2 165 705 5100 1500 pgm main\001
    43 4 1 0 100 0 2 10 0.0000 2 105 540 2100 1275 creator\001
    44 4 1 0 100 0 2 10 0.0000 2 105 495 3600 1275 starter\001
    45 4 1 0 100 0 2 10 0.0000 2 105 690 5175 1275 execution\001
     384 1 0 100 0 4 10 0.0000 2 165 705 3300 1500 pgm main\001
     394 1 0 100 0 4 10 0.0000 2 165 705 4500 1500 pgm main\001
  • doc/papers/concurrency/figures/RunTimeStructure.fig

    r7030dab r71d6bd8  
    36361 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 3600 15 15 4500 3600 4515 3615
    3737-6
    38 6 3225 4125 4650 4425
    39 6 4350 4200 4650 4350
    40 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 4275 15 15 4425 4275 4440 4290
    41 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 4275 15 15 4500 4275 4515 4290
    42 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4575 4275 15 15 4575 4275 4590 4290
     386 2175 4650 7050 4950
     391 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
     401 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4200 4800 150 75 4200 4800 4350 4875
     411 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3275 4800 100 100 3275 4800 3375 4800
     422 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     43         5400 4950 5400 4725 5175 4725 5175 4950 5400 4950
     442 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
     45         6525 4950 6300 4950 6300 4725 6525 4725 6525 4950
     464 0 -1 0 0 0 10 0.0000 2 105 450 6600 4875 cluster\001
     474 0 -1 0 0 0 10 0.0000 2 105 660 5475 4875 processor\001
     484 0 -1 0 0 0 10 0.0000 2 105 555 4425 4875 monitor\001
     494 0 -1 0 0 0 10 0.0000 2 120 270 3450 4875 task\001
     504 0 -1 0 0 0 10 0.0000 2 105 660 2325 4875 coroutine\001
    4351-6
    44 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 4275 225 150 3450 4275 3675 4425
    45 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4275 225 150 4050 4275 4275 4425
     526 3450 1275 3750 1425
     531 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3525 1350 15 15 3525 1350 3540 1365
     541 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3600 1350 15 15 3600 1350 3615 1365
     551 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3675 1350 15 15 3675 1350 3690 1365
    4656-6
    47 6 6675 4125 7500 4425
    48 6 7200 4200 7500 4350
    49 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7275 4275 15 15 7275 4275 7290 4290
    50 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7350 4275 15 15 7350 4275 7365 4290
    51 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7425 4275 15 15 7425 4275 7440 4290
    52 -6
    53 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 4275 225 150 6900 4275 7125 4425
    54 -6
    55 6 6675 3525 8025 3975
    56 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    57         1 1 1.00 45.00 90.00
    58          6675 3750 6975 3750
    59 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    60         1 1 1.00 45.00 90.00
    61          7125 3750 7350 3750
    62 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    63          7800 3975 7800 3525 7350 3525 7350 3975 7800 3975
    64 2 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    65         1 1 1.00 45.00 90.00
    66          7800 3750 8025 3750
     576 5550 1275 5850 1425
     581 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5625 1350 15 15 5625 1350 5640 1365
     591 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5700 1350 15 15 5700 1350 5715 1365
     601 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5775 1350 15 15 5775 1350 5790 1365
    6761-6
    68621 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5550 2625 150 150 5550 2625 5700 2625
     
    73671 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2850 150 150 4425 2850 4575 2850
    74681 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 2475 150 150 4650 2475 4800 2475
     691 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
    75701 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 3600 150 150 3975 3600 4125 3600
    76711 3 0 1 0 0 0 0 0 0.000 1 0.0000 3525 3600 30 30 3525 3600 3555 3630
     
    79741 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850
    80751 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 7200 2775 150 150 7200 2775 7350 2775
    81 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
    82 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 7200 2775 30 30 7200 2775 7230 2805
    83 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
    84 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3875 4800 100 100 3875 4800 3975 4800
    85 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 4800 150 75 4650 4800 4800 4875
     761 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 1350 225 150 4650 1350 4875 1500
     771 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5250 1350 225 150 5250 1350 5475 1500
     781 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 1350 225 150 4050 1350 4275 1500
    86792 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    8780         2400 4200 2400 3750 1950 3750 1950 4200 2400 4200
     
    1471402 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    148141        1 1 1.00 45.00 90.00
     142         6675 3975 6975 3975
     1432 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
     144        1 1 1.00 45.00 90.00
    149145         7050 2775 6825 2775
    1501462 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
    151          6825 2775 6825 3750
     147         6825 2775 6825 3975
     1482 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
     149        1 1 1.00 45.00 90.00
     150         7125 3975 7350 3975
     1512 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
     152         7800 4200 7800 3750 7350 3750 7350 4200 7800 4200
     1532 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
     154        1 1 1.00 45.00 90.00
     155         7800 3975 8025 3975
    1521562 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 4
    153157        1 1 1.00 45.00 90.00
    154          7875 3750 7875 2325 7200 2325 7200 2550
    155 2 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    156          5850 4950 5850 4725 5625 4725 5625 4950 5850 4950
    157 2 2 1 1 -1 -1 0 0 -1 3.000 0 0 0 0 0 5
    158          6975 4950 6750 4950 6750 4725 6975 4725 6975 4950
     158         7875 3975 7875 2325 7200 2325 7200 2550
    1591594 1 -1 0 0 0 10 0.0000 2 105 720 5550 4425 Processors\001
    1601604 1 -1 0 0 0 10 0.0000 2 120 1005 4200 3225 Blocked Tasks\001
     
    1651654 1 -1 0 0 0 10 0.0000 2 105 990 2175 3525 Discrete-event\001
    1661664 1 -1 0 0 0 10 0.0000 2 135 795 2175 4350 preemption\001
    167 4 0 -1 0 0 0 10 0.0000 2 150 1290 2325 4875 genrator/coroutine\001
    168 4 0 -1 0 0 0 10 0.0000 2 120 270 4050 4875 task\001
    169 4 0 -1 0 0 0 10 0.0000 2 105 450 7050 4875 cluster\001
    170 4 0 -1 0 0 0 10 0.0000 2 105 660 5925 4875 processor\001
    171 4 0 -1 0 0 0 10 0.0000 2 105 555 4875 4875 monitor\001
  • doc/papers/concurrency/mail2

    r7030dab r71d6bd8  
    2222Software: Practice and Experience Editorial Office
    2323
    24 
    25 
    26 Date: Tue, 12 Nov 2019 22:25:17 +0000
    27 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    28 Reply-To: R.E.Jones@kent.ac.uk
    29 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    30 Subject: Software: Practice and Experience - Decision on Manuscript ID
    31  SPE-19-0219
    32 
    33 12-Nov-2019
    34 
    35 Dear Dr Buhr,
    36 
    37 Many thanks for submitting SPE-19-0219 entitled "Advanced Control-flow and Concurrency in Cforall" to Software: Practice and Experience. The paper has now been reviewed and the comments of the referees are included at the bottom of this letter.
    38 
    39 The decision on this paper is that it requires substantial further work is required. The referees have a number of substantial concerns. All the reviewers found the submission very hard to read; two of the reviewers state that it needs very substantial restructuring. These concerns must be addressed before your submission can be considered further.
    40 
    41 A revised version of your manuscript that takes into account the comments of the referees will be reconsidered for publication.
    42 
    43 Please note that submitting a revision of your manuscript does not guarantee eventual acceptance, and that your revision will be subject to re-review by the referees before a decision is rendered.
    44 
    45 You have 90 days from the date of this email to submit your revision. If you are unable to complete the revision within this time, please contact me to request an extension.
    46 
    47 You can upload your revised manuscript and submit it through your Author Center. Log into https://mc.manuscriptcentral.com/spe  and enter your Author Center, where you will find your manuscript title listed under "Manuscripts with Decisions".
    48 
    49 When submitting your revised manuscript, you will be able to respond to the comments made by the referee(s) in the space provided.  You can use this space to document any changes you make to the original manuscript.
    50 
    51 If you feel that your paper could benefit from English language polishing, you may wish to consider having your paper professionally edited for English language by a service such as Wiley's at http://wileyeditingservices.com. Please note that while this service will greatly improve the readability of your paper, it does not guarantee acceptance of your paper by the journal.
    52  
    53 Once again, thank you for submitting your manuscript to Software: Practice and Experience and I look forward to receiving your revision.
    54 
    55 
    56 Sincerely,
    57 
    58 Prof. Richard Jones
    59 Software: Practice and Experience
    60 R.E.Jones@kent.ac.uk
    61 
    62 
    63 Referee(s)' Comments to Author:
    64 
    65 Reviewing: 1
    66 
    67 Comments to the Author
    68 This article presents the design and rationale behind the various
    69 threading and synchronization mechanisms of C-forall, a new low-level
    70 programming language.  This paper is very similar to a companion paper
    71 which I have also received: as the papers are similar, so will these
    72 reviews be --- in particular any general comments from the other
    73 review apply to this paper also.
    74 
    75 As far as I can tell, the article contains three main ideas: an
    76 asynchronous execution / threading model; a model for monitors to
    77 provide mutual exclusion; and an implementation.  The first two ideas
    78 are drawn together in Table 1: unfortunately this is on page 25 of 30
    79 pages of text. Implementation choices and descriptions are scattered
    80 throughout the paper - and the sectioning of the paper seems almost
    81 arbitrary.
    82 
    83 The article is about its contributions.  Simply adding feature X to
    84 language Y isn't by itself a contribution, (when feature X isn't
    85 already a contribution).  The contribution can be in the design: the
    86 motivation, the space of potential design options, the particular
    87 design chosen and the rationale for that choice, or the resulting
    88 performance.  For example: why support two kinds of generators as well
    89 as user-level threads?  Why support both low and high level
    90 synchronization constructs?  Similarly I would have found the article
    91 easier to follow if it was written top down, presenting the design
    92 principles, present the space of language features, justify chosen
    93 language features (and rationale) and those excluded, and then present
    94 implementation, and performance.
    95 
    96 Then the writing of the article is often hard to follow, to say the
    97 least. Two examples: section 3 "stateful functions" - I've some idea
    98 what that is (a function with Algol's "own" or C's "static" variables?
    99 but in fact the paper has a rather more specific idea than that. The
    100 top of page 3 throws a whole lot of defintions at the reader
    101 "generator" "coroutine" "stackful" "stackless" "symmetric"
    102 "asymmetric" without every stopping to define each one --- but then in
    103 footnote "C" takes the time to explain what C's "main" function is?  I
    104 cannot imagine a reader of this paper who doesn't know what "main" is
    105 in C; especially if they understand the other concepts already
    106 presented in the paper.  The start of section 3 then does the same
    107 thing: putting up a whole lot of definitions, making distinctions and
    108 comparisons, even talking about some runtime details, but the critical
    109 definition of a monitor doesn't appear until three pages later, at the
    110 start of section 5 on p15, lines 29-34 are a good, clear, description
    111 of what a monitor actually is.  That needs to come first, rather than
    112 being buried again after two sections of comparisons, discussions,
    113 implementations, and options that are ungrounded because they haven't
    114 told the reader what they are actually talking about.  First tell the
    115 reader what something is, then how they might use it (as programmers:
    116 what are the rules and restrictions) and only then start comparison
    117 with other things, other approaches, other languages, or
    118 implementations.
    119 
    120 The description of the implementation is similarly lost in the trees
    121 without ever really seeing the wood. Figure 19 is crucial here, but
    122 it's pretty much at the end of the paper, and comments about
    123 implementations are threaded throughout the paper without the context
    124 (fig 19) to understand what's going on.   The protocol for performance
    125 testing may just about suffice for C (although is N constantly ten
    126 million, or does it vary for each benchmark) but such evaluation isn't
    127 appropriate for garbage-collected or JITTed languages like Java or Go.
    128 
    129 other comments working through the paper - these are mostly low level
    130 and are certainly not comprehensive.
    131 
    132 p1 only a subset of C-forall extensions?
    133 
    134 p1 "has features often associated with object-oriented programming
    135 languages, such as constructors, destructors, virtuals and simple
    136 inheritance."   There's no need to quibble about this. Once a language
    137 has inheritance, it's hard to claim it's not object-oriented.
    138 
    139 
    140 p2 barging? signals-as-hints?
    141 
    142 p3 start your discussion of generations with a simple example of a
    143 C-forall generator.  Fig 1(b) might do: but put it inline instead of
    144 the python example - and explain the key rules and restrictions on the
    145 construct.  Then don't even start to compare with coroutines until
    146 you've presented, described and explained your coroutines...
    147 p3 I'd probably leave out the various "C" versions unless there are
    148 key points to make you can't make in C-forall. All the alternatives
    149 are just confusing.
    150 
    151 
    152 p4 but what's that "with" in Fig 1(B)
    153 
    154 p5 start with the high level features of C-forall generators...
    155 
    156 p5 why is the paper explaining networking protocols?
    157 
    158 p7 lines 1-9 (transforming generator to coroutine - why would I do any
    159 of this? Why would I want one instead of the other (do not use "stack"
    160 in your answer!)
    161 
    162 p10 last para "A coroutine must retain its last resumer to suspend
    163 back because the resumer is on a different stack. These reverse
    164 pointers allow suspend to cycle backwards, "  I've no idea what is
    165 going on here?  why should I care?  Shouldn't I just be using threads
    166 instead?  why not?
    167 
    168 p16 for the same reasons - what reasons?
    169 
    170 p17 if the multiple-monitor entry procedure really is novel, write a
    171 paper about that, and only about that.
    172 
    173 p23 "Loose Object Definitions" - no idea what that means.  in that
    174 section: you can't leave out JS-style dynamic properties.  Even in
    175 OOLs that (one way or another) allow separate definitions of methods
    176 (like Objective-C, Swift, Ruby, C#) at any time a runtime class has a
    177 fixed definition.  Quite why the detail about bit mask implementation
    178 is here anyway, I've no idea.
    179 
    180 p25 this cluster isn't a CLU cluster then?
    181 
    182 * conclusion should conclude the paper, not the related.
    183 
    184 
    185 Reviewing: 2
    186 
    187 Comments to the Author
    188 This paper describes the concurrency features of an extension of C (whose name I will write as "C\/" here, for convenience), including much design-level discussion of the coroutine- and monitor-based features and some microbenchmarks exploring the current implementation's performance. The key message of the latter is that the system's concurrency abstractions are much lighter-weight than the threading found in mainstream C or Java implementations.
    189 
    190 There is much description of the system and its details, but nothing about (non-artificial) uses of it. Although the microbenchmark data is encouraging, arguably not enough practical experience with the system has been reported here to say much about either its usability advantages or its performance.
    191 
    192 As such, the main contribution of the paper seem to be to document the existence of the described system and to provide a detailed design rationale and (partial) tutorial. I believe that could be of interest to some readers, so an acceptable manuscript is lurking in here somewhere.
    193 
    194 Unfortunately, at present the writing style is somewhere between unclear and infuriating. It omits to define terms; it uses needlessly many terms for what are apparently (but not clearly) the same things; it interrupts itself rather than deliver the natural consequent of whatever it has just said; and so on. Section 5 is particularly bad in these regards -- see my detailed comments below. Fairly major additional efforts will be needed to turn the present text into a digestible design-and-tutorial document. I suspect that a shorter paper could do this job better than the present manuscript, which is overwrought in parts.
    195 
    196 p2: lines 4--9 are a little sloppy. It is not the languages but their popular implementations which "adopt" the 1:1 kernel threading model.
    197 
    198 line 10: "medium work" -- "medium-sized work"?
    199 
    200 line 18: "is all sequential to the compiler" -- not true in modern compilers, and in 2004 H-J Boehm wrote a tech report describing exactly why ("Threads cannot be implemented as a library", HP Labs).
    201 
    202 line 20: "knows the optimization boundaries" -- I found this vague. What's an example?
    203 
    204 line 31: this paragraph has made a lot of claims. Perhaps forward-reference to the parts of the paper that discuss each one.
    205 
    206 line 33: "so the reader can judge if" -- this reads rather passive-aggressively. Perhaps better: "... to support our argument that..."
    207 
    208 line 41: "a dynamic partitioning mechanism" -- I couldn't tell what this meant
    209 
    210 p3. Presenting concept of a "stateful function" as a new language feature seems odd. In C, functions often have local state thanks to static local variables (or globals, indeed). Of course, that has several limitations. Can you perhaps present your contributions by enumerating these limitations? See also my suggestion below about a possible framing centred on a strawman.
    211 
    212 line 2: "an old idea that is new again" -- this is too oblique
    213 
    214 lines 2--15: I found this to be a word/concept soup. Stacks, closures, generators, stackless stackful, coroutine, symmetric, asymmetric, resume/suspend versus resume/resume... there needs to be a more gradual and structured way to introduce all this, and ideally one that minimises redundancy. Maybe present it as a series of "definitions" each with its own heading, e.g. "A closure is stackless if its local state has statically known fixed size"; "A generator simply means a stackless closure." And so on. Perhaps also strongly introduce the word "activate" as a direct contrast with resume and suspend. These are just a flavour of the sort of changes that might make this paragraph into something readable.
    215 
    216 Continuing the thought: I found it confusing that by these definitinos, a stackful closure is not a stack, even though logically the stack *is* a kind of closure (it is a representation of the current thread's continuation).
    217 
    218 lines 24--27: without explaining what the boost functor types mean, I don't think the point here comes across.
    219 
    220 line 34: "semantically coupled" -- I wasn't surew hat this meant
    221 
    222 p4: the point of Figure 1 (C) was not immediately clear. It seem to be showing how one might "compile down" Figure 1 (B). Or is that Figure 1 (A)?
    223 
    224 It's right that the incidental language features of the system are not front-and-centre, but I'd appreciate some brief glossing of non-C languages features as they appear. Examples are the square bracket notation, the pipe notation and the constructor syntax. These explanations could go in the caption of the figure which first uses them, perhaps. Overall I found the figure captions to be terse, and a missed opportunity to explain clearly what was going on.
    225 
    226 p5 line 23: "This restriction is removed..." -- give us some up-front summary of your contributions and the elements of the language design that will be talked about, so that this isn't an aside. This will reduce the "twisty passages" feeling that characterises much of the paper.
    227 
    228 line 40: "a killer asymmetric generator" -- this is stylistically odd, and the sentence about failures doesn't convincigly argue that C\/ will help with them. Have you any experience writing device drivers using C\/? Or any argument that the kinds of failures can be traced to the "stack-ripping" style that one is forced to use without coroutines? Also, a typo on line 41: "device drives". And saying "Windows/Linux" is sloppy... what does the cited paper actually say?
    229 
    230 p6 lines 13--23: this paragraph is difficult to understand. It seems to be talking about a control-flow pattern roughly equivalent to tail recursion. What is the high-level point, other than that this is possible?
    231 
    232 line 34: "which they call coroutines" -- a better way to make this point is presumably that the C++20 proposal only provides a specialised kind of coroutine, namely generators, despite its use of the more general word.
    233 
    234 line 47: "... due to dynamic stack allocation, execution..." -- this sentence doesn't scan. I suggest adding "and for" in the relevant places where currently there are only commas.
    235 
    236 p8 / Figure 5 (B) -- the GNU C extension of unary "&&" needs to be explained. The whole figure needs a better explanation, in fact.
    237 
    238 p9, lines 1--10: I wasn't sure this stepping-through really added much value. What are the truly important points to note about this code?
    239 
    240 p10: similarly, lines 3--27 again are somewhere between tedious and confusing. I'm sure the motivation and details of "starter semantics" can both be stated much more pithily.
    241 
    242 line 32: "a self-resume does not overwrite the last resumer" -- is this a hack or a defensible principled decision?
    243 
    244 p11: "a common source of errors" -- among beginners or among production code? Presumably the former.
    245 
    246 line 23: "with builtin and library" -- not sure what this means
    247 
    248 lines 31--36: these can be much briefer. The only important point here seems to be that coroutines cannot be copied.
    249 
    250 p12: line 1: what is a "task"? Does it matter?
    251 
    252 line 7: calling it "heap stack" seems to be a recipe for confusion. "Stack-and-heap" might be better, and contrast with "stack-and-VLS" perhaps. When "VLS" is glossed, suggest actually expanding its initials: say "length" not "size".
    253 
    254 line 21: are you saying "cooperative threading" is the same as "non-preemptive scheduling", or that one is a special case (kind) of the other? Both are defensible, but be clear.
    255 
    256 line 27: "mutual exclusion and synchronization" -- the former is a kind of the latter, so I suggest "and other forms of synchronization".
    257 
    258 line 30: "can either be a stackless or stackful" -- stray "a", but also, this seems to be switching from generic/background terminology to C\/-specific terminology.
    259 
    260 An expositional idea occurs: start the paper with a strawman naive/limited realisation of coroutines -- say, Simon Tatham's popular "Coroutines in C" web page -- and identify point by point what the limitations are and how C\/ overcomes them. Currently the presentation is often flat (lacking motivating contrasts) and backwards (stating solutions before problems). The foregoing approach might fix both of these.
    261 
    262 page 13: line 23: it seems a distraction to mention the Python feature here.
    263 
    264 p14 line 5: it seems odd to describe these as "stateless" just because they lack shared mutable state. It means the code itself is even more stateful. Maybe the "stack ripping" argument could usefully be given here.
    265 
    266 line 16: "too restrictive" -- would be good to have a reference to justify this, or at least give a sense of what the state-of-the-art performance in transactional memory systems is (both software and hardware)
    267 
    268 line 22: "simulate monitors" -- what about just *implementing* monitors? isn't that what these systems do? or is the point more about refining them somehow into something more specialised?
    269 
    270 p15: sections 4.1 and 4.2 seem adrift and misplaced. Split them into basic parts (which go earlier) and more advanced parts (e.g. barging, which can be explained later).
    271 
    272 line 31: "acquire/release" -- misses an opportunity to contrast the monitor's "enter/exit" abstraction with the less structured acquire/release of locks.
    273 
    274 p16 line 12: the "implicit" versus "explicit" point is unclear. Is it perhaps about the contract between an opt-in *discipline* and a language-enforced *guarantee*?
    275 
    276 line 28: no need to spend ages dithering about which one is default and which one is the explicit qualifier. Tell us what you decided, briefly justify it, and move on.
    277 
    278 p17: Figure 11: since the main point seems to be to highlight bulk acquire, include a comment which identifies the line where this is happening.
    279 
    280 line 2: "impossible to statically..." -- or dynamically. Doing it dynamically would be perfectly acceptable (locking is a dynamic operation after all)
    281 
    282 "guarantees acquisition order is consistent" -- assuming it's done in a single bulk acquire.
    283 
    284 p18: section 5.3: the text here is a mess. The explanations of "internal" versus "external" scheduling are unclear, and "signals as hints" is not explained. "... can cause thread starvation" -- means including a while loop, or not doing so? "There are three signalling mechanisms.." but the text does not follow that by telling us what they are. My own scribbled attempt at unpicking the internal/external thing: "threads already in the monitor, albeit waiting, have priority over those trying to enter".
    285 
    286 p19: line 3: "empty condition" -- explain that condition variables don't store anything. So being "empty" means that the queue of waiting threads (threads waiting to be signalled that the condition has become true) is empty.
    287 
    288 line 6: "... can be transformed into external scheduling..." -- OK, but give some motivation.
    289 
    290 p20: line 6: "mechnaism"
    291 
    292 lines 16--20: this is dense and can probably only be made clear with an example
    293 
    294 p21 line 21: clarify that nested monitor deadlock was describe earlier (in 5.2). (Is the repetition necessary?)
    295 
    296 line 27: "locks, and by extension monitors" -- this is true but the "by extension" argument is faulty. It is perfectly possible to use locks as a primitive and build a compositional mechanism out of them, e.g. transactions.
    297 
    298 p22 line 2: should say "restructured"
    299 
    300 line 33: "Implementing a fast subset check..." -- make clear that the following section explains how to do this. Restructuring the sections themselves could do this, or noting in the text.
    301 
    302 p23: line 3: "dynamic member adding, eg, JavaScript" -- needs to say "as permitted in JavaScript", and "dynamically adding members" is stylistically better
    303 
    304 p23: line 18: "urgent stack" -- back-reference to where this was explained before
    305 
    306 p24 line 7: I did not understand what was more "direct" about "direct communication". Also, what is a "passive monitor" -- just a monitor, given that monitors are passive by design?
    307 
    308 line 14 / section 5.9: this table was useful and it (or something like it) could be used much earlier on to set the structure of the rest of the paper. The explanation at present is too brief, e.g. I did not really understand the point about cases 7 and 8.
    309 
    310 p25 line 2: instead of casually dropping in a terse explanation for the newly intrdouced term "virtual processor", introduce it properly. Presumably the point is to give a less ambiguous meaning to "thread" by reserving it only for C\/'s green threads.
    311 
    312 Table 1: what does "No / Yes" mean?
    313 
    314 p26 line 15: "transforms user threads into fibres" -- a reference is needed to explain what "fibres" means... guessing it's in the sense of Adya et al.
    315 
    316 line 20: "Microsoft runtime" -- means Windows?
    317 
    318 lines 21--26: don't say "interrupt" to mean "signal", especially not without clear introduction. You can use "POSIX signal" to disambiguate from condition variables' "signal".
    319 
    320 p27 line 3: "frequency is usually long" -- that's a "time period" or "interval", not a frequency
    321 
    322 line 5: the lengthy quotation is not really necessary; just paraphrase the first sentence and move on.
    323 
    324 line 20: "to verify the implementation" -- I don't think that means what is intended
    325 
    326 Tables in section 7 -- too many significant figures. How many overall runs are described? What is N in each case?
    327 
    328 p29 line 2: "to eliminate this cost" -- arguably confusing since nowadays on commodity CPUs most of the benefits of inlining are not to do with call overheads, but from later optimizations enabled as a consequence of the inlining
    329 
    330 line 41: "a hierarchy" -- are they a hierarchy? If so, this could be explained earlier. Also, to say these make up "an integrated set... of control-flow features" verges on the tautologous.
    331 
    332 p30 line 15: "a common case being web servers and XaaS" -- that's two cases
    333 
    334 
    335 Reviewing: 3
    336 
    337 Comments to the Author
    338 # Cforall review
    339 
    340 Overall, I quite enjoyed reading the paper. Cforall has some very interesting ideas. I did have some suggestions that I think would be helpful before final publication. I also left notes on various parts of the paper that I find confusing when reading, in hopes that it may be useful to you.
    341 
    342 ## Summary
    343 
    344 * Expand on the motivations for including both generator and coroutines, vs trying to build one atop the other
    345 * Expand on the motivations for having Why both symmetric and asymettric coroutines?
    346 * Comparison to async-await model adopted by other languages
    347     * C#, JS
    348     * Rust and its async/await model
    349 * Consider performance comparisons against node.js and Rust frameworks
    350 * Discuss performance of monitors vs finer-grained memory models and atomic operations found in other languages
    351 * Why both internal/external scheduling for synchronization?
    352 
    353 ## Generator/coroutines
    354 
    355 In general, this section was clear, but I thought it would be useful to provide a somewhat deeper look into why Cforall opted for the particular combination of features that it offers. I see three main differences from other languages:
    356 
    357 * Generators are not exposed as a "function" that returns a generator object, but rather as a kind of struct, with communication happening via mutable state instead of "return values". That is, the generator must be manually resumed and (if I understood) it is expected to store values that can then later be read (perhaps via methods), instead of having a `yield <Expr>` statement that yields up a value explicitly.
    358 * Both "symmetric" and "asymmetric" generators are supported, instead of only asymmetric.
    359 * Coroutines (multi-frame generators) are an explicit mechanism.
    360 
    361 In most other languages, coroutines are rather built by layering single-frame generators atop one another (e.g., using a mechanism like async-await), and symmetric coroutines are basically not supported. I'd like to see a bit more justification for Cforall including all the above mechanisms -- it seemed like symmetric coroutines were a useful building block for some of the user-space threading and custom scheduler mechanisms that were briefly mentioned later in the paper.
    362 
    363 In the discussion of coroutines, I would have expected a bit more of a comparison to the async-await mechanism offered in other languages. Certainly the semantics of async-await in JavaScript implies significantly more overhead (because each async fn is a distinct heap object). [Rust's approach avoids this overhead][zc], however, and might be worthy of a comparison (see the Performance section).
    364 
    365 ## Locks and threading
    366 
    367 ### Comparison to atomics overlooks performance
    368 
    369 There are several sections in the paper that compare against atomics -- for example, on page 15, the paper shows a simple monitor that encapsulates an integer and compares that to C++ atomics. Later, the paper compares the simplicity of monitors against the `volatile` quantifier from Java. The conclusion in section 8 also revisits this point.
    370 
    371 While I agree that monitors are simpler, they are obviously also significantly different from a performance perspective -- the paper doesn't seem to address this at all. It's plausible that (e.g.) the `Aint` monitor type described in the paper can be compiled and mapped to the specialized instructions offered by hardware, but I didn't see any mention of how this would be done. There is also no mention of the more nuanced memory ordering relations offered by C++11 and how one might achieve similar performance characteristics in Cforall (perhaps the answer is that one simply doesn't need to; I think that's defensible, but worth stating explicitly).
    372 
    373 ### Justification for external scheduling feels lacking
    374 
    375 Cforall includes both internal and external scheduling; I found the explanation for the external scheduling mechanism to be lacking in justification. Why include both mechanisms when most languages seem to make do with only internal scheduling? It would be useful to show some scenarios where external scheduling is truly more powerful.
    376 
    377 I would have liked to see some more discussion of external scheduling and how it  interacts with software engineering best practices. It seems somewhat similar to AOP in certain regards. It seems to add a bit of "extra semantics" to monitor methods, in that any method may now also become a kind of synchronization point. The "open-ended" nature of this feels like it could easily lead to subtle bugs, particularly when code refactoring occurs (which may e.g. split an existing method into two). This seems particularly true if external scheduling can occur across compilation units -- the paper suggested that this is true, but I wasn't entirely clear.
    378 
    379 I would have also appreciated a few more details on how external scheduling is implemented. It seems to me that there must be some sort of "hooks" on mutex methods so that they can detect whether some other function is waiting on them and awaken those blocked threads. I'm not sure how such hooks are inserted, particularly across compilation units. The material in Section 5.6 didn't quite clarify the matter for me. For example, it left me somewhat confused about whether the `f` and `g` functions declared were meant to be local to a translation unit, or shared with other unit.
    380 
    381 ### Presentation of monitors is somewhat confusing
    382 
    383 I found myself confused fairly often in the section on monitors. I'm just going to leave some notes here on places that I got confused in how that it could be useful to you as feedback on writing that might want to be clarified.
    384 
    385 To start, I did not realize that the `mutex_opt` notation was a keyword, I thought it was a type annotation. I think this could be called out more explicitly.
    386 
    387 Later, in section 5.2, the paper discusses `nomutex` annotations, which initially threw me, as they had not been introduced (now I realize that this paragraph is there to justify why there is no such keyword). The paragraph might be rearranged to make that clearer, perhaps by leading with the choice that Cforall made.
    388 
    389 On page 17, the paper states that "acquiring multiple monitors is safe from deadlock", but this could be stated a bit more precisely: acquiring multiple monitors in a bulk-acquire is safe from deadlock (deadlock can still result from nested acquires).
    390 
    391 On page 18, the paper states that wait states do not have to be enclosed in loops, as there is no concern of barging. This seems true but there are also other reasons to use loops (e.g., if there are multiple reasons to notify on the same condition). Thus the statement initially surprised me, as barging is only one of many reasons that I typically employ loops around waits.
    392 
    393 I did not understand the diagram in Figure 12 for some time. Initially, I thought that it was generic to all monitors, and I could not understand the state space. It was only later that I realized it was specific to your example. Updating the caption from "Monitor scheduling to "Monitor scheduling in the example from Fig 13" might have helped me quite a bit.
    394 
    395 I spent quite some time reading the boy/girl dating example (\*) and I admit I found it somewhat confusing. For example, I couldn't tell whether there were supposed to be many "girl" threads executing at once, or if there was only supposed to be one girl and one boy thread executing in a loop. Are the girl/boy threads supposed to invoke the girl/boy methods or vice versa? Surely there is some easier way to set this up? I believe that when reading the paper I convinced myself of how it was supposed to be working, but I'm writing this review some days later, and I find myself confused all over again and not able to easily figure it out.
    396 
    397 (\*) as an aside, I would consider modifying the example to some other form of matching, like customers and support personnel.
    398 
    399 ## Related work
    400 
    401 The paper offered a number of comparisons to Go, C#, Scala, and so forth, but seems to have overlooked another recent language, Rust. In many ways, Rust seems to be closest in philosophy to Cforall, so it seems like an odd omission. I already mentioned above that Rust is in the process of shipping [async-await syntax][aa], which is definitely an alternative to the generator/coroutine approach in Cforall (though one with clear pros/cons).
    402 
    403 ## Performance
    404 
    405 In the performance section in particular, you might consider comparing against some of the Rust web servers and threading systems. For example, actix is top of the [single query TechEmpower Framework benchmarks], and tokio is near the top of the [plainthreading benchmarks][pt] (hyper, the top, is more of an HTTP framework, though it is also written in Rust). It would seem worth trying to compare their "context switching" costs as well -- I believe both actix and tokio have a notion of threads that could be readily compared.
    406 
    407 Another addition that might be worth considering is to compare against node.js promises, although I think the comparison to process creation is not as clean.
    408 
    409 That said, I think that the performance comparison is not a big focus of the paper, so it may not be necessary to add anything to it.
    410 
    411 ## Authorship of this review
    412 
    413 I'm going to sign this review. This review was authored by Nicholas D. Matsakis. In the intrerest of full disclosure, I'm heavily involved in the Rust project, although I dont' think that influenced this review in particular. Feel free to reach out to me for clarifying questions.
    414 
    415 ## Links
    416 
    417 [aa]: https://blog.rust-lang.org/2019/09/30/Async-await-hits-beta.html
    418 [zc]: https://aturon.github.io/blog/2016/08/11/futures/
    419 [sq]: https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=db
    420 [pt]: https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=plaintext
    421 
    422 
    423 
    424 Subject: Re: manuscript SPE-19-0219
    425 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    426 From: Richard Jones <R.E.Jones@kent.ac.uk>
    427 Date: Tue, 12 Nov 2019 22:43:55 +0000
    428 
    429 Dear Dr Buhr
    430 
    431 Your should have received a decision letter on this today. I am sorry that this
    432 has taken so long. Unfortunately SP&E receives a lot of submissions and getting
    433 reviewers is a perennial problem.
    434 
    435 Regards
    436 Richard
    437 
    438 Peter A. Buhr wrote on 11/11/2019 13:10:
    439 >     26-Jun-2019
    440 >     Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall"
    441 >     has been received by Software: Practice and Experience. It will be given
    442 >     full consideration for publication in the journal.
    443 >
    444 > Hi, it has been over 4 months since submission of our manuscript SPE-19-0219
    445 > with no response.
    446 >
    447 > Currently, I am refereeing a paper for IEEE that already cites our prior SP&E
    448 > paper and the Master's thesis forming the bases of the SP&E paper under
    449 > review. Hence our work is apropos and we want to get it disseminates as soon as
    450 > possible.
    451 >
    452 > [3] A. Moss, R. Schluntz, and P. A. Buhr, "Cforall: Adding modern programming
    453 >      language features to C," Software - Practice and Experience, vol. 48,
    454 >      no. 12, pp. 2111-2146, 2018.
    455 >
    456 > [4] T. Delisle, "Concurrency in C for all," Master's thesis, University of
    457 >      Waterloo, 2018.  [Online].  Available:
    458 >      https://uwspace.uwaterloo.ca/bitstream/handle/10012/12888
    459 
    460 
    461 
    462 Date: Mon, 13 Jan 2020 05:33:15 +0000
    463 From: Richard Jones <onbehalfof@manuscriptcentral.com>
    464 Reply-To: R.E.Jones@kent.ac.uk
    465 To: pabuhr@uwaterloo.ca
    466 Subject: Revision reminder - SPE-19-0219
    467 
    468 13-Jan-2020
    469 Dear Dr Buhr
    470 SPE-19-0219
    471 
    472 This is a reminder that your opportunity to revise and re-submit your
    473 manuscript will expire 28 days from now. If you require more time please
    474 contact me directly and I may grant an extension to this deadline, otherwise
    475 the option to submit a revision online, will not be available.
    476 
    477 I look forward to receiving your revision.
    478 
    479 Sincerely,
    480 
    481 Prof. Richard Jones
    482 Editor, Software: Practice and Experience
    483 https://mc.manuscriptcentral.com/spe
    484 
    485 
    486 
    487 Date: Wed, 5 Feb 2020 04:22:18 +0000
    488 From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
    489 Reply-To: speoffice@wiley.com
    490 To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
    491 Subject: SPE-19-0219.R1 successfully submitted
    492 
    493 04-Feb-2020
    494 
    495 Dear Dr Buhr,
    496 
    497 Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" has
    498 been successfully submitted online and is presently being given full
    499 consideration for publication in Software: Practice and Experience.
    500 
    501 Your manuscript number is SPE-19-0219.R1.  Please mention this number in all
    502 future correspondence regarding this submission.
    503 
    504 You can view the status of your manuscript at any time by checking your Author
    505 Center after logging into https://mc.manuscriptcentral.com/spe.  If you have
    506 difficulty using this site, please click the 'Get Help Now' link at the top
    507 right corner of the site.
    508 
    509 Thank you for submitting your manuscript to Software: Practice and Experience.
    510 
    511 Sincerely,
    512 Software: Practice and Experience Editorial Office
    513 
  • doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp

    r7030dab r71d6bd8  
    99#include <vector>
    1010
    11 #include <getopt.h>
    1211#include <unistd.h>
    1312#include <sys/sysinfo.h>
     
    2221
    2322        int value;
    24         int id;
    25 
    26         Node() { creates++; }
    27         Node(int value): value(value) { creates++; }
    28         ~Node() { destroys++; }
     23        Node(int value): value(value) {
     24                creates++;
     25        }
     26
     27        ~Node() {
     28                destroys++;
     29        }
    2930};
    3031
     
    3233std::atomic_size_t Node::destroys = { 0 };
    3334
     35static const constexpr int nodes_per_threads = 128;
     36struct NodeArray {
     37        __attribute__((aligned(64))) Node * array[nodes_per_threads];
     38        __attribute__((aligned(64))) char pad;
     39};
     40
    3441bool enable_stats = false;
    35 
    36 template<>
    37 thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
    38 
    39 template<>
    40 relaxed_list<Node> * relaxed_list<Node>::head = nullptr;
    41 
    42 #ifndef NO_STATS
    43 template<>
    44 relaxed_list<Node>::GlobalStats relaxed_list<Node>::global_stats = {};
    45 #endif
    46 
    47 // ================================================================================================
    48 //                        UTILS
    49 // ================================================================================================
    5042
    5143struct local_stat_t {
     
    5547        size_t crc_in  = 0;
    5648        size_t crc_out = 0;
    57         size_t valmax = 0;
    58         size_t valmin = 100000000ul;
    5949};
    6050
    61 struct global_stat_t {
    62         std::atomic_size_t in  = { 0 };
    63         std::atomic_size_t out = { 0 };
    64         std::atomic_size_t empty = { 0 };
    65         std::atomic_size_t crc_in  = { 0 };
    66         std::atomic_size_t crc_out = { 0 };
    67         std::atomic_size_t valmax = { 0 };
    68         std::atomic_size_t valmin = { 100000000ul };
    69 };
    70 
    71 void atomic_max(std::atomic_size_t & target, size_t value) {
    72         for(;;) {
    73                 size_t expect = target.load(std::memory_order_relaxed);
    74                 if(value <= expect) return;
    75                 bool success = target.compare_exchange_strong(expect, value);
    76                 if(success) return;
    77         }
    78 }
    79 
    80 void atomic_min(std::atomic_size_t & target, size_t value) {
    81         for(;;) {
    82                 size_t expect = target.load(std::memory_order_relaxed);
    83                 if(value >= expect) return;
    84                 bool success = target.compare_exchange_strong(expect, value);
    85                 if(success) return;
    86         }
    87 }
    88 
    89 void tally_stats(global_stat_t & global, local_stat_t & local) {
    90 
    91         global.in    += local.in;
    92         global.out   += local.out;
    93         global.empty += local.empty;
    94 
    95         global.crc_in  += local.crc_in;
    96         global.crc_out += local.crc_out;
    97 
    98         atomic_max(global.valmax, local.valmax);
    99         atomic_min(global.valmin, local.valmin);
    100 
    101         relaxed_list<Node>::stats_tls_tally();
    102 }
    103 
    104 void waitfor(double & duration, barrier_t & barrier, std::atomic_bool & done) {
     51__attribute__((noinline)) void run_body(
     52        std::atomic<bool>& done,
     53        Random & rand,
     54        Node * (&my_nodes)[128],
     55        local_stat_t & local,
     56        relaxed_list<Node> & list
     57) {
     58        while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
     59                int idx = rand.next() % nodes_per_threads;
     60                if (auto node = my_nodes[idx]) {
     61                        local.crc_in += node->value;
     62                        list.push(node);
     63                        my_nodes[idx] = nullptr;
     64                        local.in++;
     65                }
     66                else if(auto node = list.pop()) {
     67                        local.crc_out += node->value;
     68                        my_nodes[idx] = node;
     69                        local.out++;
     70                }
     71                else {
     72                        local.empty++;
     73                }
     74        }
     75}
     76
     77void run(unsigned nthread, unsigned nqueues, unsigned fill, double duration) {
     78        // List being tested
     79        relaxed_list<Node> list = { nthread * nqueues };
     80
     81        // Barrier for synchronization
     82        barrier_t barrier(nthread + 1);
     83
     84        // Data to check everything is OK
     85        struct {
     86                std::atomic_size_t in  = { 0 };
     87                std::atomic_size_t out = { 0 };
     88                std::atomic_size_t empty = { 0 };
     89                std::atomic_size_t crc_in  = { 0 };
     90                std::atomic_size_t crc_out = { 0 };
     91                struct {
     92                        struct {
     93                                std::atomic_size_t attempt = { 0 };
     94                                std::atomic_size_t success = { 0 };
     95                        } push;
     96                        struct {
     97                                std::atomic_size_t attempt = { 0 };
     98                                std::atomic_size_t success = { 0 };
     99                        } pop;
     100                } pick;
     101        } global;
     102
     103        // Flag to signal termination
     104        std::atomic_bool done  = { false };
     105
     106        // Prep nodes
     107        std::cout << "Initializing ";
     108        size_t nnodes  = 0;
     109        size_t npushed = 0;
     110        NodeArray all_nodes[nthread];
     111        for(auto & nodes : all_nodes) {
     112                Random rand(rdtscl());
     113                for(auto & node : nodes.array) {
     114                        auto r = rand.next() % 100;
     115                        if(r < fill) {
     116                                node = new Node(rand.next() % 100);
     117                                nnodes++;
     118                        } else {
     119                                node = nullptr;
     120                        }
     121                }
     122
     123                for(int i = 0; i < 10; i++) {
     124                        int idx = rand.next() % nodes_per_threads;
     125                        if (auto node = nodes.array[idx]) {
     126                                global.crc_in += node->value;
     127                                list.push(node);
     128                                npushed++;
     129                                nodes.array[idx] = nullptr;
     130                        }
     131                }
     132        }
     133
     134        std::cout << nnodes << " nodes " << fill << "% (" << npushed << " pushed)" << std::endl;
     135
     136        enable_stats = true;
     137
     138        std::thread * threads[nthread];
     139        unsigned i = 1;
     140        for(auto & t : threads) {
     141                auto & my_nodes = all_nodes[i - 1].array;
     142                t = new std::thread([&done, &list, &barrier, &global, &my_nodes](unsigned tid) {
     143                        Random rand(tid + rdtscl());
     144
     145                        local_stat_t local;
     146
     147                        // affinity(tid);
     148
     149                        barrier.wait(tid);
     150
     151                        // EXPERIMENT START
     152
     153                        run_body(done, rand, my_nodes, local, list);
     154
     155                        // EXPERIMENT END
     156
     157                        barrier.wait(tid);
     158
     159                        global.in    += local.in;
     160                        global.out   += local.out;
     161                        global.empty += local.empty;
     162
     163                        for(auto node : my_nodes) {
     164                                delete node;
     165                        }
     166
     167                        global.crc_in  += local.crc_in;
     168                        global.crc_out += local.crc_out;
     169
     170                        global.pick.push.attempt += relaxed_list<Node>::tls.pick.push.attempt;
     171                        global.pick.push.success += relaxed_list<Node>::tls.pick.push.success;
     172                        global.pick.pop .attempt += relaxed_list<Node>::tls.pick.pop.attempt;
     173                        global.pick.pop .success += relaxed_list<Node>::tls.pick.pop.success;
     174                }, i++);
     175        }
     176
    105177        std::cout << "Starting" << std::endl;
    106178        auto before = Clock::now();
     
    124196        duration = durr.count();
    125197        std::cout << "\rClosing down" << std::endl;
    126 }
    127 
    128 void waitfor(double & duration, barrier_t & barrier, const std::atomic_size_t & count) {
    129         std::cout << "Starting" << std::endl;
    130         auto before = Clock::now();
    131         barrier.wait(0);
    132 
    133         while(true) {
    134                 usleep(100000);
    135                 size_t c = count.load();
    136                 if( c == 0 ) {
    137                         break;
    138                 }
    139                 std::cout << "\r" << c;
    140                 std::cout.flush();
    141         }
    142 
    143         barrier.wait(0);
    144         auto after = Clock::now();
    145         duration_t durr = after - before;
    146         duration = durr.count();
    147         std::cout << "\rClosing down" << std::endl;
    148 }
    149 
    150 void print_stats(double duration, unsigned nthread, global_stat_t & global) {
     198
     199        for(auto t : threads) {
     200                t->join();
     201                delete t;
     202        }
     203
     204        enable_stats = false;
     205
     206        while(auto node = list.pop()) {
     207                global.crc_out += node->value;
     208                delete node;
     209        }
     210
    151211        assert(Node::creates == Node::destroys);
    152212        assert(global.crc_in == global.crc_out);
     
    164224        std::cout << "Ops/sec       : " << ops_sec << "\n";
    165225        std::cout << "Total ops     : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
    166         if(global.valmax != 0) {
    167                 std::cout << "Max runs      : " << global.valmax << "\n";
    168                 std::cout << "Min runs      : " << global.valmin << "\n";
    169         }
    170226        #ifndef NO_STATS
    171                 relaxed_list<Node>::stats_print(std::cout);
     227                double push_sur = (100.0 * double(global.pick.push.success) / global.pick.push.attempt);
     228                double pop_sur  = (100.0 * double(global.pick.pop .success) / global.pick.pop .attempt);
     229                std::cout << "Push Pick %   : " << push_sur << "(" << global.pick.push.success << " / " << global.pick.push.attempt << ")\n";
     230                std::cout << "Pop  Pick %   : " << pop_sur  << "(" << global.pick.pop .success << " / " << global.pick.pop .attempt << ")\n";
    172231        #endif
    173232}
    174233
    175 void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output);
    176 
    177 // ================================================================================================
    178 //                        EXPERIMENTS
    179 // ================================================================================================
    180 
    181 // ================================================================================================
    182 __attribute__((noinline)) void runChurn_body(
    183         std::atomic<bool>& done,
    184         Random & rand,
    185         Node * my_nodes[],
    186         unsigned nslots,
    187         local_stat_t & local,
    188         relaxed_list<Node> & list
    189 ) {
    190         while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
    191                 int idx = rand.next() % nslots;
    192                 if (auto node = my_nodes[idx]) {
    193                         local.crc_in += node->value;
    194                         list.push(node);
    195                         my_nodes[idx] = nullptr;
    196                         local.in++;
    197                 }
    198                 else if(auto node = list.pop()) {
    199                         local.crc_out += node->value;
    200                         my_nodes[idx] = node;
    201                         local.out++;
    202                 }
    203                 else {
    204                         local.empty++;
    205                 }
    206         }
    207 }
    208 
    209 void runChurn(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const unsigned nslots) {
    210         std::cout << "Churn Benchmark" << std::endl;
    211         assert(nnodes <= nslots);
    212         // List being tested
    213 
    214         // Barrier for synchronization
    215         barrier_t barrier(nthread + 1);
    216 
    217         // Data to check everything is OK
    218         global_stat_t global;
    219 
    220         // Flag to signal termination
    221         std::atomic_bool done  = { false };
    222 
    223         // Prep nodes
    224         std::cout << "Initializing ";
    225         size_t npushed = 0;
    226         relaxed_list<Node> list = { nthread * nqueues };
    227         {
    228                 Node** all_nodes[nthread];
    229                 for(auto & nodes : all_nodes) {
    230                         nodes = new __attribute__((aligned(64))) Node*[nslots + 8];
    231                         Random rand(rdtscl());
    232                         for(unsigned i = 0; i < nnodes; i++) {
    233                                 nodes[i] = new Node(rand.next() % 100);
    234                         }
    235 
    236                         for(unsigned i = nnodes; i < nslots; i++) {
    237                                 nodes[i] = nullptr;
    238                         }
    239 
    240                         for(int i = 0; i < 10 && i < (int)nslots; i++) {
    241                                 int idx = rand.next() % nslots;
    242                                 if (auto node = nodes[idx]) {
    243                                         global.crc_in += node->value;
    244                                         list.push(node);
    245                                         npushed++;
    246                                         nodes[idx] = nullptr;
    247                                 }
    248                         }
    249                 }
    250 
    251                 std::cout << nnodes << " nodes (" << nslots << " slots)" << std::endl;
    252 
    253                 enable_stats = true;
    254 
    255                 std::thread * threads[nthread];
    256                 unsigned i = 1;
    257                 for(auto & t : threads) {
    258                         auto & my_nodes = all_nodes[i - 1];
    259                         t = new std::thread([&done, &list, &barrier, &global, &my_nodes, nslots](unsigned tid) {
    260                                 Random rand(tid + rdtscl());
    261 
    262                                 local_stat_t local;
    263 
    264                                 // affinity(tid);
    265 
    266                                 barrier.wait(tid);
    267 
    268                                 // EXPERIMENT START
    269 
    270                                 runChurn_body(done, rand, my_nodes, nslots, local, list);
    271 
    272                                 // EXPERIMENT END
    273 
    274                                 barrier.wait(tid);
    275 
    276                                 tally_stats(global, local);
    277 
    278                                 for(unsigned i = 0; i < nslots; i++) {
    279                                         delete my_nodes[i];
    280                                 }
    281                         }, i++);
    282                 }
    283 
    284                 waitfor(duration, barrier, done);
    285 
    286                 for(auto t : threads) {
    287                         t->join();
    288                         delete t;
    289                 }
    290 
    291                 enable_stats = false;
    292 
    293                 while(auto node = list.pop()) {
    294                         global.crc_out += node->value;
    295                         delete node;
    296                 }
    297 
    298                 for(auto nodes : all_nodes) {
    299                         delete[] nodes;
    300                 }
    301         }
    302 
    303         print_stats(duration, nthread, global);
    304 }
    305 
    306 // ================================================================================================
    307 __attribute__((noinline)) void runPingPong_body(
    308         std::atomic<bool>& done,
    309         Node initial_nodes[],
    310         unsigned nnodes,
    311         local_stat_t & local,
    312         relaxed_list<Node> & list
    313 ) {
    314         Node * nodes[nnodes];
    315         {
    316                 unsigned i = 0;
    317                 for(auto & n : nodes) {
    318                         n = &initial_nodes[i++];
    319                 }
    320         }
    321 
    322         while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
    323 
    324                 for(Node * & node : nodes) {
    325                         local.crc_in += node->value;
    326                         list.push(node);
    327                         local.in++;
    328                 }
    329 
    330                 // -----
    331 
    332                 for(Node * & node : nodes) {
    333                         node = list.pop();
    334                         assert(node);
    335                         local.crc_out += node->value;
    336                         local.out++;
    337                 }
    338         }
    339 }
    340 
    341 void runPingPong(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes) {
    342         std::cout << "PingPong Benchmark" << std::endl;
    343 
    344 
    345         // Barrier for synchronization
    346         barrier_t barrier(nthread + 1);
    347 
    348         // Data to check everything is OK
    349         global_stat_t global;
    350 
    351         // Flag to signal termination
    352         std::atomic_bool done  = { false };
    353 
    354         std::cout << "Initializing ";
    355         // List being tested
    356         relaxed_list<Node> list = { nthread * nqueues };
    357         {
    358                 enable_stats = true;
    359 
    360                 std::thread * threads[nthread];
    361                 unsigned i = 1;
    362                 for(auto & t : threads) {
    363                         t = new std::thread([&done, &list, &barrier, &global, nnodes](unsigned tid) {
    364                                 Random rand(tid + rdtscl());
    365 
    366                                 Node nodes[nnodes];
    367                                 for(auto & n : nodes) {
    368                                         n.value = (int)rand.next() % 100;
    369                                 }
    370 
    371                                 local_stat_t local;
    372 
    373                                 // affinity(tid);
    374 
    375                                 barrier.wait(tid);
    376 
    377                                 // EXPERIMENT START
    378 
    379                                 runPingPong_body(done, nodes, nnodes, local, list);
    380 
    381                                 // EXPERIMENT END
    382 
    383                                 barrier.wait(tid);
    384 
    385                                 tally_stats(global, local);
    386                         }, i++);
    387                 }
    388 
    389                 waitfor(duration, barrier, done);
    390 
    391                 for(auto t : threads) {
    392                         t->join();
    393                         delete t;
    394                 }
    395 
    396                 enable_stats = false;
    397         }
    398 
    399         print_stats(duration, nthread, global);
    400 }
    401 
    402 // ================================================================================================
    403 __attribute__((noinline)) void runFairness_body(
    404         unsigned tid,
    405         size_t width,
    406         size_t length,
    407         int output[],
    408         std::atomic_size_t & count,
    409         Node initial_nodes[],
    410         unsigned nnodes,
    411         local_stat_t & local,
    412         relaxed_list<Node> & list
    413 ) {
    414         Node * nodes[nnodes];
    415         {
    416                 unsigned i = 0;
    417                 for(auto & n : nodes) {
    418                         n = &initial_nodes[i++];
    419                 }
    420         }
    421 
    422         while(__builtin_expect(0 != count.load(std::memory_order_relaxed), true)) {
    423 
    424                 for(Node * & node : nodes) {
    425                         local.crc_in += node->id;
    426                         list.push(node);
    427                         local.in++;
    428                 }
    429 
    430                 // -----
    431 
    432                 for(Node * & node : nodes) {
    433                         node = list.pop();
    434                         assert(node);
    435 
    436                         if (unsigned(node->value) < length) {
    437                                 size_t idx = (node->value * width) + node->id;
    438                                 assert(idx < (width * length));
    439                                 output[idx] = tid;
    440                         }
    441 
    442                         node->value++;
    443                         if(unsigned(node->value) == length) count--;
    444 
    445                         local.crc_out += node->id;
    446                         local.out++;
    447                 }
    448         }
    449 }
    450 
    451 void runFairness(unsigned nthread, unsigned nqueues, double duration, unsigned nnodes, const std::string & output) {
    452         std::cout << "Fairness Benchmark, outputing to : " << output << std::endl;
    453 
    454         // Barrier for synchronization
    455         barrier_t barrier(nthread + 1);
    456 
    457         // Data to check everything is OK
    458         global_stat_t global;
    459 
    460         std::cout << "Initializing ";
    461 
    462         // Check fairness by creating a png of where the threads ran
    463         size_t width = nthread * nnodes;
    464         size_t length = 100000;
    465 
    466         std::unique_ptr<int[]> data_out { new int[width * length] };
    467 
    468         // Flag to signal termination
    469         std::atomic_size_t count = width;
    470 
    471         // List being tested
    472         relaxed_list<Node> list = { nthread * nqueues };
    473         {
    474                 enable_stats = true;
    475 
    476                 std::thread * threads[nthread];
    477                 unsigned i = 1;
    478                 for(auto & t : threads) {
    479                         t = new std::thread([&count, &list, &barrier, &global, nnodes, width, length, data_out = data_out.get()](unsigned tid) {
    480                                 unsigned int start = (tid - 1) * nnodes;
    481                                 Node nodes[nnodes];
    482                                 for(auto & n : nodes) {
    483                                         n.id = start;
    484                                         n.value = 0;
    485                                         start++;
    486                                 }
    487 
    488                                 local_stat_t local;
    489 
    490                                 // affinity(tid);
    491 
    492                                 barrier.wait(tid);
    493 
    494                                 // EXPERIMENT START
    495 
    496                                 runFairness_body(tid, width, length, data_out, count, nodes, nnodes, local, list);
    497 
    498                                 // EXPERIMENT END
    499 
    500                                 barrier.wait(tid);
    501 
    502                                 for(const auto & n : nodes) {
    503                                         local.valmax = max(local.valmax, size_t(n.value));
    504                                         local.valmin = min(local.valmin, size_t(n.value));
    505                                 }
    506 
    507                                 tally_stats(global, local);
    508                         }, i++);
    509                 }
    510 
    511                 waitfor(duration, barrier, count);
    512 
    513                 for(auto t : threads) {
    514                         t->join();
    515                         delete t;
    516                 }
    517 
    518                 enable_stats = false;
    519         }
    520 
    521         print_stats(duration, nthread, global);
    522 
    523         save_fairness(data_out.get(), 100, nthread, width, length, output);
    524 }
    525 
    526 // ================================================================================================
    527 
    528 bool iequals(const std::string& a, const std::string& b)
    529 {
    530     return std::equal(a.begin(), a.end(),
    531                       b.begin(), b.end(),
    532                       [](char a, char b) {
    533                           return std::tolower(a) == std::tolower(b);
    534                       });
     234void usage(char * argv[]) {
     235        std::cerr << argv[0] << ": [DURATION (FLOAT:SEC)] [NTHREADS] [NQUEUES] [FILL]" << std::endl;;
     236        std::exit(1);
    535237}
    536238
     
    539241        double duration   = 5.0;
    540242        unsigned nthreads = 2;
    541         unsigned nqueues  = 4;
    542         unsigned nnodes   = 100;
    543         unsigned nslots   = 100;
    544         std::string out   = "fairness.png";
    545 
    546         enum {
    547                 Churn,
    548                 PingPong,
    549                 Fairness,
    550                 NONE
    551         } benchmark = NONE;
     243        unsigned nqueues  = 2;
     244        unsigned fill     = 100;
    552245
    553246        std::cout.imbue(std::locale(""));
    554247
    555         for(;;) {
    556                 static struct option options[] = {
    557                         {"duration",  required_argument, 0, 'd'},
    558                         {"nthreads",  required_argument, 0, 't'},
    559                         {"nqueues",   required_argument, 0, 'q'},
    560                         {"benchmark", required_argument, 0, 'b'},
    561                         {0, 0, 0, 0}
    562                 };
    563 
    564                 int idx = 0;
    565                 int opt = getopt_long(argc, argv, "d:t:q:b:", options, &idx);
    566 
    567                 std::string arg = optarg ? optarg : "";
    568                 size_t len = 0;
    569                 switch(opt) {
    570                         // Exit Case
    571                         case -1:
    572                                 /* paranoid */ assert(optind <= argc);
    573                                 switch(benchmark) {
    574                                 case NONE:
    575                                         std::cerr << "Must specify a benchmark" << std::endl;
    576                                         goto usage;
    577                                 case PingPong:
    578                                         nnodes = 1;
    579                                         nslots = 1;
    580                                         switch(argc - optind) {
    581                                         case 0: break;
    582                                         case 1:
    583                                                 try {
    584                                                         arg = optarg = argv[optind];
    585                                                         nnodes = stoul(optarg, &len);
    586                                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    587                                                 } catch(std::invalid_argument &) {
    588                                                         std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
    589                                                         goto usage;
    590                                                 }
    591                                                 break;
    592                                         default:
    593                                                 std::cerr << "'PingPong' benchmark doesn't accept more than 2 extra arguments" << std::endl;
    594                                                 goto usage;
    595                                         }
    596                                         break;
    597                                 case Churn:
    598                                         nnodes = 100;
    599                                         nslots = 100;
    600                                         switch(argc - optind) {
    601                                         case 0: break;
    602                                         case 1:
    603                                                 try {
    604                                                         arg = optarg = argv[optind];
    605                                                         nnodes = stoul(optarg, &len);
    606                                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    607                                                         nslots = nnodes;
    608                                                 } catch(std::invalid_argument &) {
    609                                                         std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
    610                                                         goto usage;
    611                                                 }
    612                                                 break;
    613                                         case 2:
    614                                                 try {
    615                                                         arg = optarg = argv[optind];
    616                                                         nnodes = stoul(optarg, &len);
    617                                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    618                                                 } catch(std::invalid_argument &) {
    619                                                         std::cerr << "Number of nodes must be a positive integer, was " << arg << std::endl;
    620                                                         goto usage;
    621                                                 }
    622                                                 try {
    623                                                         arg = optarg = argv[optind + 1];
    624                                                         nslots = stoul(optarg, &len);
    625                                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    626                                                 } catch(std::invalid_argument &) {
    627                                                         std::cerr << "Number of slots must be a positive integer, was " << arg << std::endl;
    628                                                         goto usage;
    629                                                 }
    630                                                 break;
    631                                         default:
    632                                                 std::cerr << "'Churn' benchmark doesn't accept more than 2 extra arguments" << std::endl;
    633                                                 goto usage;
    634                                         }
    635                                         break;
    636                                 case Fairness:
    637                                         nnodes = 1;
    638                                         switch(argc - optind) {
    639                                         case 0: break;
    640                                         case 1:
    641                                                 arg = optarg = argv[optind];
    642                                                 out = arg;
    643                                                 break;
    644                                         default:
    645                                                 std::cerr << "'Churn' benchmark doesn't accept more than 2 extra arguments" << std::endl;
    646                                                 goto usage;
    647                                         }
    648                                 }
    649                                 goto run;
    650                         // Benchmarks
    651                         case 'b':
    652                                 if(benchmark != NONE) {
    653                                         std::cerr << "Only when benchmark can be run" << std::endl;
    654                                         goto usage;
    655                                 }
    656                                 if(iequals(arg, "churn")) {
    657                                         benchmark = Churn;
    658                                         break;
    659                                 }
    660                                 if(iequals(arg, "pingpong")) {
    661                                         benchmark = PingPong;
    662                                         break;
    663                                 }
    664                                 if(iequals(arg, "fairness")) {
    665                                         benchmark = Fairness;
    666                                         break;
    667                                 }
    668                                 std::cerr << "Unkown benchmark " << arg << std::endl;
    669                                 goto usage;
    670                         // Numeric Arguments
    671                         case 'd':
    672                                 try {
    673                                         duration = stod(optarg, &len);
    674                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    675                                 } catch(std::invalid_argument &) {
    676                                         std::cerr << "Duration must be a valid double, was " << arg << std::endl;
    677                                         goto usage;
    678                                 }
    679                                 break;
    680                         case 't':
    681                                 try {
    682                                         nthreads = stoul(optarg, &len);
    683                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    684                                 } catch(std::invalid_argument &) {
    685                                         std::cerr << "Number of threads must be a positive integer, was " << arg << std::endl;
    686                                         goto usage;
    687                                 }
    688                                 break;
    689                         case 'q':
    690                                 try {
    691                                         nqueues = stoul(optarg, &len);
    692                                         if(len != arg.size()) { throw std::invalid_argument(""); }
    693                                 } catch(std::invalid_argument &) {
    694                                         std::cerr << "Number of queues must be a positive integer, was " << arg << std::endl;
    695                                         goto usage;
    696                                 }
    697                                 break;
    698                         // Other cases
    699                         default: /* ? */
    700                                 std::cerr << opt << std::endl;
    701                         usage:
    702                                 std::cerr << "Usage: " << argv[0] << ": [options] -b churn [NNODES] [NSLOTS = NNODES]" << std::endl;
    703                                 std::cerr << "  or:  " << argv[0] << ": [options] -b pingpong [NNODES]" << std::endl;
    704                                 std::cerr << std::endl;
    705                                 std::cerr << "  -d, --duration=DURATION  Duration of the experiment, in seconds" << std::endl;
    706                                 std::cerr << "  -t, --nthreads=NTHREADS  Number of kernel threads" << std::endl;
    707                                 std::cerr << "  -q, --nqueues=NQUEUES    Number of queues per threads" << std::endl;
    708                                 std::exit(1);
    709                 }
    710         }
    711         run:
     248        switch (argc)
     249        {
     250        case 5:
     251                fill = std::stoul(argv[4]);
     252                [[fallthrough]];
     253        case 4:
     254                nqueues = std::stoul(argv[3]);
     255                [[fallthrough]];
     256        case 3:
     257                nthreads = std::stoul(argv[2]);
     258                [[fallthrough]];
     259        case 2:
     260                duration = std::stod(argv[1]);
     261                if( duration <= 0.0 ) {
     262                        std::cerr << "Duration must be positive, was " << argv[1] << "(" << duration << ")" << std::endl;
     263                        usage(argv);
     264                }
     265                [[fallthrough]];
     266        case 1:
     267                break;
     268        default:
     269                usage(argv);
     270                break;
     271        }
    712272
    713273        check_cache_line_size();
    714274
    715275        std::cout << "Running " << nthreads << " threads (" << (nthreads * nqueues) << " queues) for " << duration << " seconds" << std::endl;
    716         switch(benchmark) {
    717                 case Churn:
    718                         runChurn(nthreads, nqueues, duration, nnodes, nslots);
    719                         break;
    720                 case PingPong:
    721                         runPingPong(nthreads, nqueues, duration, nnodes);
    722                         break;
    723                 case Fairness:
    724                         runFairness(nthreads, nqueues, duration, nnodes, out);
    725                         break;
    726                 default:
    727                         abort();
    728         }
     276        run(nthreads, nqueues, fill, duration);
     277
    729278        return 0;
    730279}
    731280
     281template<>
     282thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
     283
     284template<>
     285relaxed_list<Node>::intrusive_queue_t::stat::Dif relaxed_list<Node>::intrusive_queue_t::stat::dif = {};
     286
    732287const char * __my_progname = "Relaxed List";
    733 
    734 struct rgb_t {
    735     double r;       // a fraction between 0 and 1
    736     double g;       // a fraction between 0 and 1
    737     double b;       // a fraction between 0 and 1
    738 };
    739 
    740 struct hsv_t {
    741     double h;       // angle in degrees
    742     double s;       // a fraction between 0 and 1
    743     double v;       // a fraction between 0 and 1
    744 };
    745 
    746 rgb_t hsv2rgb(hsv_t in) {
    747         double hh, p, q, t, ff;
    748         long   i;
    749         rgb_t  out;
    750 
    751         if(in.s <= 0.0) {       // < is bogus, just shuts up warnings
    752                 out.r = in.v;
    753                 out.g = in.v;
    754                 out.b = in.v;
    755                 return out;
    756         }
    757         hh = in.h;
    758         if(hh >= 360.0) hh = 0.0;
    759         hh /= 60.0;
    760         i = (long)hh;
    761         ff = hh - i;
    762         p = in.v * (1.0 - in.s);
    763         q = in.v * (1.0 - (in.s * ff));
    764         t = in.v * (1.0 - (in.s * (1.0 - ff)));
    765 
    766         switch(i) {
    767         case 0:
    768                 out.r = in.v;
    769                 out.g = t;
    770                 out.b = p;
    771                 break;
    772         case 1:
    773                 out.r = q;
    774                 out.g = in.v;
    775                 out.b = p;
    776                 break;
    777         case 2:
    778                 out.r = p;
    779                 out.g = in.v;
    780                 out.b = t;
    781                 break;
    782 
    783         case 3:
    784                 out.r = p;
    785                 out.g = q;
    786                 out.b = in.v;
    787                 break;
    788         case 4:
    789                 out.r = t;
    790                 out.g = p;
    791                 out.b = in.v;
    792                 break;
    793         case 5:
    794         default:
    795                 out.r = in.v;
    796                 out.g = p;
    797                 out.b = q;
    798                 break;
    799         }
    800         return out;
    801 }
    802 
    803 void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
    804         std::ofstream os(output);
    805         os << "<html>\n";
    806         os << "<head>\n";
    807         os << "<style>\n";
    808         os << "</style>\n";
    809         os << "</head>\n";
    810         os << "<body>\n";
    811         os << "<table style=\"width=100%\">\n";
    812 
    813         size_t idx = 0;
    814         for(size_t r = 0ul; r < rows; r++) {
    815                 os << "<tr>\n";
    816                 for(size_t c = 0ul; c < columns; c++) {
    817                         os << "<td class=\"custom custom" << data[idx] << "\"></td>\n";
    818                         idx++;
    819                 }
    820                 os << "</tr>\n";
    821         }
    822 
    823         os << "</table>\n";
    824         os << "</body>\n";
    825         os << "</html>\n";
    826         os << std::endl;
    827 }
    828 
    829 #include <png.h>
    830 #include <setjmp.h>
    831 
    832 /*
    833 void save_fairness(const int data[], int factor, unsigned nthreads, size_t columns, size_t rows, const std::string & output) {
    834         int width  = columns * factor;
    835         int height = rows / factor;
    836 
    837         int code = 0;
    838         int idx = 0;
    839         FILE *fp = NULL;
    840         png_structp png_ptr = NULL;
    841         png_infop info_ptr = NULL;
    842         png_bytep row = NULL;
    843 
    844         // Open file for writing (binary mode)
    845         fp = fopen(output.c_str(), "wb");
    846         if (fp == NULL) {
    847                 fprintf(stderr, "Could not open file %s for writing\n", output.c_str());
    848                 code = 1;
    849                 goto finalise;
    850         }
    851 
    852            // Initialize write structure
    853         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    854         if (png_ptr == NULL) {
    855                 fprintf(stderr, "Could not allocate write struct\n");
    856                 code = 1;
    857                 goto finalise;
    858         }
    859 
    860         // Initialize info structure
    861         info_ptr = png_create_info_struct(png_ptr);
    862         if (info_ptr == NULL) {
    863                 fprintf(stderr, "Could not allocate info struct\n");
    864                 code = 1;
    865                 goto finalise;
    866         }
    867 
    868         // Setup Exception handling
    869         if (setjmp(png_jmpbuf(png_ptr))) {
    870                 fprintf(stderr, "Error during png creation\n");
    871                 code = 1;
    872                 goto finalise;
    873         }
    874 
    875         png_init_io(png_ptr, fp);
    876 
    877         // Write header (8 bit colour depth)
    878         png_set_IHDR(png_ptr, info_ptr, width, height,
    879                 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
    880                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    881 
    882         png_write_info(png_ptr, info_ptr);
    883 
    884         // Allocate memory for one row (3 bytes per pixel - RGB)
    885         row = (png_bytep) malloc(3 * width * sizeof(png_byte));
    886 
    887         // Write image data
    888         int x, y;
    889         for (y=0 ; y<height ; y++) {
    890                 for (x=0 ; x<width ; x++) {
    891                         auto & r = row[(x * 3) + 0];
    892                         auto & g = row[(x * 3) + 1];
    893                         auto & b = row[(x * 3) + 2];
    894                         assert(idx < (rows * columns));
    895                         int color = data[idx] - 1;
    896                         assert(color < nthreads);
    897                         assert(color >= 0);
    898                         idx++;
    899 
    900                         double angle = double(color) / double(nthreads);
    901 
    902                         auto c = hsv2rgb({ 360.0 * angle, 0.8, 0.8 });
    903 
    904                         r = char(c.r * 255.0);
    905                         g = char(c.g * 255.0);
    906                         b = char(c.b * 255.0);
    907 
    908                 }
    909                 png_write_row(png_ptr, row);
    910         }
    911 
    912         assert(idx == (rows * columns));
    913 
    914         // End write
    915         png_write_end(png_ptr, NULL);
    916 
    917         finalise:
    918         if (fp != NULL) fclose(fp);
    919         if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
    920         if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
    921         if (row != NULL) free(row);
    922 }
    923 */
  • doc/theses/thierry_delisle_PhD/code/relaxed_list.hpp

    r7030dab r71d6bd8  
    3737};
    3838
    39 static inline bool bts(std::atomic_size_t & target, size_t bit ) {
    40         //*
    41         int result = 0;
    42         asm volatile(
    43                 "LOCK btsq %[bit], %[target]\n\t"
    44                 :"=@ccc" (result)
    45                 : [target] "m" (target), [bit] "r" (bit)
    46         );
    47         return result != 0;
    48         /*/
    49         size_t mask = 1ul << bit;
    50         size_t ret = target.fetch_or(mask, std::memory_order_relaxed);
    51         return (ret & mask) != 0;
    52         //*/
    53 }
    54 
    55 static inline bool btr(std::atomic_size_t & target, size_t bit ) {
    56         //*
    57         int result = 0;
    58         asm volatile(
    59                 "LOCK btrq %[bit], %[target]\n\t"
    60                 :"=@ccc" (result)
    61                 : [target] "m" (target), [bit] "r" (bit)
    62         );
    63         return result != 0;
    64         /*/
    65         size_t mask = 1ul << bit;
    66         size_t ret = target.fetch_and(~mask, std::memory_order_relaxed);
    67         return (ret & mask) != 0;
    68         //*/
    69 }
    7039
    7140extern bool enable_stats;
     
    7948                size_t attempt = 0;
    8049                size_t success = 0;
    81                 size_t mask_attempt = 0;
    82         } pop;
    83 };
    84 
    85 struct empty_stat {
    86         struct {
    87                 size_t value = 0;
    88                 size_t count = 0;
    89         } push;
    90         struct {
    91                 size_t value = 0;
    92                 size_t count = 0;
    9350        } pop;
    9451};
     
    10562        static_assert(std::is_same<decltype(node_t::_links), _LinksFields_t<node_t>>::value, "Node must have a links field");
    10663
     64
    10765public:
    10866        relaxed_list(unsigned numLists)
    109                 : lists(new intrusive_queue_t[numLists])
     67                : numNonEmpty{0}
     68                , lists(new intrusive_queue_t[numLists])
    11069                , numLists(numLists)
    111         {
    112                 assertf(7 * 8 * 8 >= numLists, "List currently only supports 448 sublists");
    113                 // assert(sizeof(*this) == 128);
    114                 std::cout << "Constructing Relaxed List with " << numLists << std::endl;
    115 
     70        {}
     71
     72        ~relaxed_list() {
     73                lists.reset();
    11674                #ifndef NO_STATS
    117                         if(head) this->next = head;
    118                         head = this;
     75                        std::cout << "Difference   : "
     76                                << ssize_t(double(intrusive_queue_t::stat::dif.value) / intrusive_queue_t::stat::dif.num  ) << " avg\t"
     77                                << intrusive_queue_t::stat::dif.max << "max" << std::endl;
    11978                #endif
    120         }
    121 
    122         ~relaxed_list() {
    123                 std::cout << "Destroying Relaxed List" << std::endl;
    124                 lists.reset();
    12579        }
    12680
     
    13084                while(true) {
    13185                        // Pick a random list
    132                         unsigned i = tls.rng.next() % numLists;
     86                        int i = tls.rng.next() % numLists;
    13387
    13488                        #ifndef NO_STATS
     
    13993                        if( !lists[i].lock.try_lock() ) continue;
    14094
    141                         __attribute__((unused)) int num = numNonEmpty;
    142 
    14395                        // Actually push it
    144                         if(lists[i].push(node)) {
    145                                 numNonEmpty++;
    146                                 size_t qword = i >> 6ull;
    147                                 size_t bit   = i & 63ull;
    148                                 assertf((list_mask[qword] & (1ul << bit)) == 0, "Before set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
    149                                 __attribute__((unused)) bool ret = bts(list_mask[qword], bit);
    150                                 assert(!ret);
    151                                 assertf((list_mask[qword] & (1ul << bit)) != 0, "After set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
    152                         }
     96                        lists[i].push(node, numNonEmpty);
    15397                        assert(numNonEmpty <= (int)numLists);
    15498
     
    158102                        #ifndef NO_STATS
    159103                                tls.pick.push.success++;
    160                                 tls.empty.push.value += num;
    161                                 tls.empty.push.count += 1;
    162104                        #endif
    163105                        return;
     
    166108
    167109        __attribute__((noinline, hot)) node_t * pop() {
    168                 #if !defined(NO_BITMASK)
    169                         // for(int r = 0; r < 10 && numNonEmpty != 0; r++) {
    170                         //      // Pick two lists at random
    171                         //      unsigned i = tls.rng.next() % numLists;
    172                         //      unsigned j = tls.rng.next() % numLists;
    173 
    174                         //      if(auto node = try_pop(i, j)) return node;
    175                         // }
    176                         int nnempty;
    177                         while(0 != (nnempty = numNonEmpty)) {
    178                                 tls.pick.pop.mask_attempt++;
    179                                 unsigned i, j;
    180                                 // if( numLists < 4 || (numLists / nnempty) < 4 ) {
    181                                 //      // Pick two lists at random
    182                                 //      i = tls.rng.next() % numLists;
    183                                 //      j = tls.rng.next() % numLists;
    184                                 // } else
    185                                 {
    186                                         #ifndef NO_STATS
    187                                                 // tls.pick.push.mask_attempt++;
    188                                         #endif
    189 
    190                                         // Pick two lists at random
    191                                         unsigned num = ((numLists - 1) >> 6) + 1;
    192 
    193                                         unsigned ri = tls.rng.next();
    194                                         unsigned rj = tls.rng.next();
    195 
    196                                         unsigned wdxi = (ri >> 6u) % num;
    197                                         unsigned wdxj = (rj >> 6u) % num;
    198 
    199                                         size_t maski = list_mask[wdxi].load(std::memory_order_relaxed);
    200                                         size_t maskj = list_mask[wdxj].load(std::memory_order_relaxed);
    201 
    202                                         if(maski == 0 && maskj == 0) continue;
    203 
    204                                         unsigned bi = rand_bit(ri, maski);
    205                                         unsigned bj = rand_bit(rj, maskj);
    206 
    207                                         assertf(bi < 64, "%zu %u", maski, bi);
    208                                         assertf(bj < 64, "%zu %u", maskj, bj);
    209 
    210                                         i = bi | (wdxi << 6);
    211                                         j = bj | (wdxj << 6);
    212 
    213                                         assertf(i < numLists, "%u", wdxi << 6);
    214                                         assertf(j < numLists, "%u", wdxj << 6);
    215                                 }
    216 
    217                                 if(auto node = try_pop(i, j)) return node;
    218                         }
    219                 #else
    220                         while(numNonEmpty != 0) {
    221                                 // Pick two lists at random
    222                                 int i = tls.rng.next() % numLists;
    223                                 int j = tls.rng.next() % numLists;
    224 
    225                                 if(auto node = try_pop(i, j)) return node;
    226                         }
    227                 #endif
     110                while(numNonEmpty != 0) {
     111                        // Pick two lists at random
     112                        int i = tls.rng.next() % numLists;
     113                        int j = tls.rng.next() % numLists;
     114
     115                        #ifndef NO_STATS
     116                                tls.pick.pop.attempt++;
     117                        #endif
     118
     119                        // Pick the bet list
     120                        int w = i;
     121                        if( __builtin_expect(lists[j].ts() != 0, true) ) {
     122                                w = (lists[i].ts() < lists[j].ts()) ? i : j;
     123                        }
     124
     125                        auto & list = lists[w];
     126                        // If list looks empty retry
     127                        if( list.ts() == 0 ) continue;
     128
     129                        // If we can't get the lock retry
     130                        if( !list.lock.try_lock() ) continue;
     131
     132                        // If list is empty, unlock and retry
     133                        if( list.ts() == 0 ) {
     134                                list.lock.unlock();
     135                                continue;
     136                        }
     137
     138                        // Actually pop the list
     139                        auto node = list.pop(numNonEmpty);
     140                        assert(node);
     141
     142                        // Unlock and return
     143                        list.lock.unlock();
     144                        assert(numNonEmpty >= 0);
     145                        #ifndef NO_STATS
     146                                tls.pick.pop.success++;
     147                        #endif
     148                        return node;
     149                }
    228150
    229151                return nullptr;
    230152        }
    231 
    232 private:
    233         node_t * try_pop(unsigned i, unsigned j) {
    234                 #ifndef NO_STATS
    235                         tls.pick.pop.attempt++;
    236                 #endif
    237 
    238                 // Pick the bet list
    239                 int w = i;
    240                 if( __builtin_expect(lists[j].ts() != 0, true) ) {
    241                         w = (lists[i].ts() < lists[j].ts()) ? i : j;
    242                 }
    243 
    244                 auto & list = lists[w];
    245                 // If list looks empty retry
    246                 if( list.ts() == 0 ) return nullptr;
    247 
    248                 // If we can't get the lock retry
    249                 if( !list.lock.try_lock() ) return nullptr;
    250 
    251                 __attribute__((unused)) int num = numNonEmpty;
    252 
    253                 // If list is empty, unlock and retry
    254                 if( list.ts() == 0 ) {
    255                         list.lock.unlock();
    256                         return nullptr;
    257                 }
    258 
    259                 // Actually pop the list
    260                 node_t * node;
    261                 bool emptied;
    262                 std::tie(node, emptied) = list.pop();
    263                 assert(node);
    264 
    265                 if(emptied) {
    266                         numNonEmpty--;
    267                         size_t qword = w >> 6ull;
    268                         size_t bit   = w & 63ull;
    269                         assert((list_mask[qword] & (1ul << bit)) != 0);
    270                         __attribute__((unused)) bool ret = btr(list_mask[qword], bit);
    271                         assert(ret);
    272                         assert((list_mask[qword] & (1ul << bit)) == 0);
    273                 }
    274 
    275                 // Unlock and return
    276                 list.lock.unlock();
    277                 assert(numNonEmpty >= 0);
    278                 #ifndef NO_STATS
    279                         tls.pick.pop.success++;
    280                         tls.empty.pop.value += num;
    281                         tls.empty.pop.count += 1;
    282                 #endif
    283                 return node;
    284         }
    285153
    286154private:
     
    294162                struct stat {
    295163                        ssize_t diff = 0;
    296                         size_t  push = 0;
    297                         size_t  pop  = 0;
    298                         // size_t value = 0;
    299                         // size_t count = 0;
     164
     165                        static struct Dif {
     166                                ssize_t value = 0;
     167                                size_t  num   = 0;
     168                                ssize_t max   = 0;
     169                        } dif;
    300170                };
    301171
     
    308178                sentinel_t before;
    309179                sentinel_t after;
    310                 #ifndef NO_STATS
    311                         stat s;
    312                 #endif
    313 
    314 #pragma GCC diagnostic push
    315 #pragma GCC diagnostic ignored "-Winvalid-offsetof"
     180                stat s;
     181
    316182                static constexpr auto fields_offset = offsetof( node_t, _links );
    317 #pragma GCC diagnostic pop
    318183        public:
    319184                intrusive_queue_t()
     
    321186                        , after {{ head(), nullptr }}
    322187                {
    323                         /* paranoid */ assert((reinterpret_cast<uintptr_t>( head() ) + fields_offset) == reinterpret_cast<uintptr_t>(&before));
    324                         /* paranoid */ assert((reinterpret_cast<uintptr_t>( tail() ) + fields_offset) == reinterpret_cast<uintptr_t>(&after ));
    325                         /* paranoid */ assert(head()->_links.prev == nullptr);
    326                         /* paranoid */ assert(head()->_links.next == tail() );
    327                         /* paranoid */ assert(tail()->_links.next == nullptr);
    328                         /* paranoid */ assert(tail()->_links.prev == head() );
    329                         /* paranoid */ assert(sizeof(*this) == 128);
    330                         /* paranoid */ assert((intptr_t(this) % 128) == 0);
    331                 }
    332 
    333                 ~intrusive_queue_t() = default;
     188                        assert((reinterpret_cast<uintptr_t>( head() ) + fields_offset) == reinterpret_cast<uintptr_t>(&before));
     189                        assert((reinterpret_cast<uintptr_t>( tail() ) + fields_offset) == reinterpret_cast<uintptr_t>(&after ));
     190                        assert(head()->_links.prev == nullptr);
     191                        assert(head()->_links.next == tail() );
     192                        assert(tail()->_links.next == nullptr);
     193                        assert(tail()->_links.prev == head() );
     194                        assert(sizeof(*this) == 128);
     195                        assert((intptr_t(this) % 128) == 0);
     196                }
     197
     198                ~intrusive_queue_t() {
     199                        #ifndef NO_STATS
     200                                stat::dif.value+= s.diff;
     201                                stat::dif.num  ++;
     202                                stat::dif.max  = std::abs(stat::dif.max) > std::abs(s.diff) ? stat::dif.max : s.diff;
     203                        #endif
     204                }
    334205
    335206                inline node_t * head() const {
     
    349220                }
    350221
    351                 inline bool push(node_t * node) {
     222                inline void push(node_t * node, std::atomic_int & nonEmpty) {
    352223                        assert(lock);
    353224                        assert(node->_links.ts != 0);
     
    361232                        prev->_links.next = node;
    362233                        tail->_links.prev = node;
    363                         #ifndef NO_STATS
    364                                 if(enable_stats) {
    365                                         s.diff++;
    366                                         s.push++;
    367                                 }
    368                         #endif
    369234                        if(before._links.ts == 0l) {
     235                                nonEmpty += 1;
    370236                                before._links.ts = node->_links.ts;
    371                                 assert(node->_links.prev == this->head());
    372                                 return true;
    373                         }
    374                         return false;
    375                 }
    376 
    377                 inline std::pair<node_t *, bool> pop() {
     237                        }
     238                        #ifndef NO_STATS
     239                                if(enable_stats) s.diff++;
     240                        #endif
     241                }
     242
     243                inline node_t * pop(std::atomic_int & nonEmpty) {
    378244                        assert(lock);
    379245                        node_t * head = this->head();
     
    382248                        node_t * node = head->_links.next;
    383249                        node_t * next = node->_links.next;
    384                         if(node == tail) return {nullptr, false};
     250                        if(node == tail) return nullptr;
    385251
    386252                        head->_links.next = next;
    387253                        next->_links.prev = head;
    388254
    389                         #ifndef NO_STATS
    390                                 if(enable_stats) {
    391                                         s.diff--;
    392                                         s.pop ++;
    393                                 }
    394                         #endif
    395255                        if(next == tail) {
    396256                                before._links.ts = 0l;
    397                                 return {node, true};
     257                                nonEmpty -= 1;
    398258                        }
    399259                        else {
     
    401261                                before._links.ts = next->_links.ts;
    402262                                assert(before._links.ts != 0);
    403                                 return {node, false};
    404                         }
     263                        }
     264                        #ifndef NO_STATS
     265                                if(enable_stats) s.diff--;
     266                        #endif
     267                        return node;
    405268                }
    406269
     
    414277
    415278        static __attribute__((aligned(128))) thread_local struct TLS {
    416                 Random     rng = { int(rdtscl()) };
    417                 pick_stat  pick;
    418                 empty_stat empty;
     279                Random    rng = { int(rdtscl()) };
     280                pick_stat pick;
    419281        } tls;
    420282
    421 public:
    422         std::atomic_int numNonEmpty  = { 0 };  // number of non-empty lists
    423         std::atomic_size_t list_mask[7] = { {0}, {0}, {0}, {0}, {0}, {0}, {0} }; // which queues are empty
    424283private:
     284        std::atomic_int numNonEmpty; // number of non-empty lists
    425285        __attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t []> lists;
    426286        const unsigned numLists;
     
    428288public:
    429289        static const constexpr size_t sizeof_queue = sizeof(intrusive_queue_t);
    430 
    431 #ifndef NO_STATS
    432         static void stats_print(std::ostream & os) {
    433                 auto it = head;
    434                 while(it) {
    435                         it->stats_print_local(os);
    436                         it = it->next;
    437                 }
    438         }
    439 
    440         static void stats_tls_tally() {
    441                 global_stats.pick.push.attempt += tls.pick.push.attempt;
    442                 global_stats.pick.push.success += tls.pick.push.success;
    443                 global_stats.pick.pop .attempt += tls.pick.pop.attempt;
    444                 global_stats.pick.pop .success += tls.pick.pop.success;
    445                 global_stats.pick.pop .mask_attempt += tls.pick.pop.mask_attempt;
    446 
    447                 global_stats.qstat.push.value += tls.empty.push.value;
    448                 global_stats.qstat.push.count += tls.empty.push.count;
    449                 global_stats.qstat.pop .value += tls.empty.pop .value;
    450                 global_stats.qstat.pop .count += tls.empty.pop .count;
    451         }
    452 
    453 private:
    454         static struct GlobalStats {
    455                 struct {
    456                         struct {
    457                                 std::atomic_size_t attempt = { 0 };
    458                                 std::atomic_size_t success = { 0 };
    459                         } push;
    460                         struct {
    461                                 std::atomic_size_t attempt = { 0 };
    462                                 std::atomic_size_t success = { 0 };
    463                                 std::atomic_size_t mask_attempt = { 0 };
    464                         } pop;
    465                 } pick;
    466                 struct {
    467                         struct {
    468                                 std::atomic_size_t value = { 0 };
    469                                 std::atomic_size_t count = { 0 };
    470                         } push;
    471                         struct {
    472                                 std::atomic_size_t value = { 0 };
    473                                 std::atomic_size_t count = { 0 };
    474                         } pop;
    475                 } qstat;
    476         } global_stats;
    477 
    478         // Link list of all lists for stats
    479         __attribute__((aligned(64))) relaxed_list<node_t> * next = nullptr;
    480 
    481         static relaxed_list<node_t> * head;
    482 
    483         void stats_print_local(std::ostream & os ) {
    484                 std::cout << "----- Relaxed List Stats -----" << std::endl;
    485                 {
    486                         ssize_t diff = 0;
    487                         size_t  num  = 0;
    488                         ssize_t max  = 0;
    489 
    490                         for(size_t i = 0; i < numLists; i++) {
    491                                 const auto & list = lists[i];
    492                                 diff+= list.s.diff;
    493                                 num ++;
    494                                 max  = std::abs(max) > std::abs(list.s.diff) ? max : list.s.diff;
    495                                 os << "Local Q ops   : " << (list.s.push + list.s.pop) << "(" << list.s.push << "i, " << list.s.pop << "o)\n";
    496                         }
    497 
    498                         os << "Difference   : " << ssize_t(double(diff) / num  ) << " avg\t" << max << "max" << std::endl;
    499                 }
    500 
    501                 const auto & global = global_stats;
    502 
    503                 double push_sur = (100.0 * double(global.pick.push.success) / global.pick.push.attempt);
    504                 double pop_sur  = (100.0 * double(global.pick.pop .success) / global.pick.pop .attempt);
    505                 double mpop_sur = (100.0 * double(global.pick.pop .success) / global.pick.pop .mask_attempt);
    506 
    507                 os << "Push   Pick % : " << push_sur << "(" << global.pick.push.success << " / " << global.pick.push.attempt << ")\n";
    508                 os << "Pop    Pick % : " << pop_sur  << "(" << global.pick.pop .success << " / " << global.pick.pop .attempt << ")\n";
    509                 os << "TryPop Pick % : " << mpop_sur << "(" << global.pick.pop .success << " / " << global.pick.pop .mask_attempt << ")\n";
    510 
    511                 double avgQ_push = double(global.qstat.push.value) / global.qstat.push.count;
    512                 double avgQ_pop  = double(global.qstat.pop .value) / global.qstat.pop .count;
    513                 double avgQ      = double(global.qstat.push.value + global.qstat.pop .value) / (global.qstat.push.count + global.qstat.pop .count);
    514                 os << "Push   Avg Qs : " << avgQ_push << " (" << global.qstat.push.count << "ops)\n";
    515                 os << "Pop    Avg Qs : " << avgQ_pop  << " (" << global.qstat.pop .count << "ops)\n";
    516                 os << "Global Avg Qs : " << avgQ      << " (" << (global.qstat.push.count + global.qstat.pop .count) << "ops)\n";
    517         }
    518 #endif
    519 };
     290};
  • doc/theses/thierry_delisle_PhD/code/utils.hpp

    r7030dab r71d6bd8  
    1010#include <unistd.h>
    1111#include <sys/sysinfo.h>
    12 
    13 #include <x86intrin.h>
    1412
    1513// Barrier from
     
    5856}
    5957
    60 static inline void affinity(int tid) {
     58void affinity(int tid) {
    6159        static int cpus = get_nprocs();
    6260
     
    7270
    7371static const constexpr std::size_t cache_line_size = 64;
    74 static inline void check_cache_line_size() {
     72void check_cache_line_size() {
    7573        std::cout << "Checking cache line size" << std::endl;
    7674        const std::string cache_file = "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size";
     
    105103        return std::chrono::duration_cast<std::chrono::duration<T, Ratio>>(std::chrono::duration<T>(seconds)).count();
    106104}
    107 
    108 static inline unsigned rand_bit(unsigned rnum, size_t mask) {
    109         unsigned bit = mask ? rnum % __builtin_popcountl(mask) : 0;
    110 #if !defined(__BMI2__)
    111         uint64_t v = mask;   // Input value to find position with rank r.
    112         unsigned int r = bit + 1;// Input: bit's desired rank [1-64].
    113         unsigned int s;      // Output: Resulting position of bit with rank r [1-64]
    114         uint64_t a, b, c, d; // Intermediate temporaries for bit count.
    115         unsigned int t;      // Bit count temporary.
    116 
    117         // Do a normal parallel bit count for a 64-bit integer,
    118         // but store all intermediate steps.
    119         a =  v - ((v >> 1) & ~0UL/3);
    120         b = (a & ~0UL/5) + ((a >> 2) & ~0UL/5);
    121         c = (b + (b >> 4)) & ~0UL/0x11;
    122         d = (c + (c >> 8)) & ~0UL/0x101;
    123 
    124 
    125         t = (d >> 32) + (d >> 48);
    126         // Now do branchless select!
    127         s  = 64;
    128         s -= ((t - r) & 256) >> 3; r -= (t & ((t - r) >> 8));
    129         t  = (d >> (s - 16)) & 0xff;
    130         s -= ((t - r) & 256) >> 4; r -= (t & ((t - r) >> 8));
    131         t  = (c >> (s - 8)) & 0xf;
    132         s -= ((t - r) & 256) >> 5; r -= (t & ((t - r) >> 8));
    133         t  = (b >> (s - 4)) & 0x7;
    134         s -= ((t - r) & 256) >> 6; r -= (t & ((t - r) >> 8));
    135         t  = (a >> (s - 2)) & 0x3;
    136         s -= ((t - r) & 256) >> 7; r -= (t & ((t - r) >> 8));
    137         t  = (v >> (s - 1)) & 0x1;
    138         s -= ((t - r) & 256) >> 8;
    139         return s - 1;
    140 #else
    141         uint64_t picked = _pdep_u64(1ul << bit, mask);
    142         return picked ? __builtin_ctzl(picked) : 0;
    143 #endif
    144 }
  • doc/user/user.tex

    r7030dab r71d6bd8  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Fri Mar  6 13:34:52 2020
    14 %% Update Count     : 3924
     13%% Last Modified On : Sat Jul 13 18:36:18 2019
     14%% Update Count     : 3876
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    211211Even with all its problems, C continues to be popular because it allows writing software at virtually any level in a computer system without restriction.
    212212For system programming, where direct access to hardware, storage management, and real-time issues are a requirement, C is usually the only language of choice.
    213 The TIOBE index~\cite{TIOBE} for February 2020 ranks the top six most \emph{popular} programming languages as \Index*{Java} 17.4\%, C 16.8\%, Python 9.3\%, \Index*[C++]{\CC{}} 6.2\%, \Csharp 5.9\%, Visual Basic 5.9\% = 61.5\%, where the next 50 languages are less than 2\% each, with a long tail.
    214 The top 4 rankings over the past 35 years are:
     213The TIOBE index~\cite{TIOBE} for July 2018 ranks the top five most \emph{popular} programming languages as \Index*{Java} 16\%, C 14\%, \Index*[C++]{\CC{}} 7.5\%, Python 6\%, Visual Basic 4\% = 47.5\%, where the next 50 languages are less than 4\% each, with a long tail.
     214The top 3 rankings over the past 30 years are:
    215215\begin{center}
    216216\setlength{\tabcolsep}{10pt}
    217 \begin{tabular}{@{}rcccccccc@{}}
    218                 & 2020  & 2015  & 2010  & 2005  & 2000  & 1995  & 1990  & 1985  \\ \hline
    219 Java    & 1             & 2             & 1             & 2             & 3             & -             & -             & -             \\
    220 \R{C}   & \R{2} & \R{1} & \R{2} & \R{1} & \R{1} & \R{2} & \R{1} & \R{1} \\
    221 Python  & 3             & 7             & 6             & 6             & 22    & 21    & -             & -             \\
    222 \CC             & 4             & 4             & 4             & 3             & 2             & 1             & 2             & 12    \\
     217\begin{tabular}{@{}rccccccc@{}}
     218                & 2018  & 2013  & 2008  & 2003  & 1998  & 1993  & 1988  \\ \hline
     219Java    & 1             & 2             & 1             & 1             & 16    & -             & -             \\
     220\R{C}   & \R{2} & \R{1} & \R{2} & \R{2} & \R{1} & \R{1} & \R{1} \\
     221\CC             & 3             & 4             & 3             & 3             & 2             & 2             & 5             \\
    223222\end{tabular}
    224223\end{center}
     
    513512Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
    514513\begin{cfa}
    515 int Ā®``Ā®otype = 3; §\C{// make keyword an identifier}§
    516 double Ā®``Ā®forall = 3.5;
     514int Ā®`Ā®otypeĀ®`Ā® = 3; §\C{// make keyword an identifier}§
     515double Ā®`Ā®forallĀ®`Ā® = 3.5;
    517516\end{cfa}
    518517
     
    525524// include file uses the CFA keyword "with".
    526525#if ! defined( with ) §\C{// nesting ?}§
    527 #define with Ā®``Ā®with §\C{// make keyword an identifier}§
     526#define with Ā®`Ā®withĀ®`Ā® §\C{// make keyword an identifier}§
    528527#define __CFA_BFD_H__
    529528#endif
    530 Ā§{\color{red}\#\textbf{include\_next} <bfdlink.h>}§ §\C{// must have internal check for multiple expansion}§
     529
     530Ā®#include_next <bfdlink.h> §\C{// must have internal check for multiple expansion}§
     531Ā®
    531532#if defined( with ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§
    532533#undef with
     
    575576\section{Exponentiation Operator}
    576577
    577 C, \CC, and Java (and many other programming languages) have no exponentiation operator\index{exponentiation!operator}\index{operator!exponentiation}, \ie $x^y$, and instead use a routine, like \Indexc{pow(x,y)}, to perform the exponentiation operation.
    578 \CFA extends the basic operators with the exponentiation operator Ā©?Ā®\Ā®?Ā©\index{?\\?@Ā©?Ā®\Ā®?Ā©} and Ā©?\=?Ā©\index{?\\=?@©®\Ā®=?Ā©}, as in, Ā©x Ā®\Ā® yĀ© and Ā©x Ā®\Ā®= yĀ©, which means $x^y$ and $x \leftarrow x^y$.
     578C, \CC, and Java (and many other programming languages) have no exponentiation operator\index{exponentiation!operator}\index{operator!exponentiation}, \ie $x^y$, and instead use a routine, like \Indexc{pow}, to perform the exponentiation operation.
     579\CFA extends the basic operators with the exponentiation operator Ā©?\?Ā©\index{?\\?@Ā©?\?Ā©} and Ā©?\=?Ā©\index{?\\=?@Ā©\=?Ā©}, as in, Ā©x \ yĀ© and Ā©x \= yĀ©, which means $x^y$ and $x \leftarrow x^y$.
    579580The priority of the exponentiation operator is between the cast and multiplicative operators, so that ©w * (int)x \ (int)y * z© is parenthesized as ©((w * (((int)x) \ ((int)y))) * z)©.
    580581
    581 There are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
     582As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    582583Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2).
    583 Overflow for a large exponent or negative exponent returns zero.
     584Overflow from large exponents or negative exponents return zero.
    584585Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    585586\begin{cfa}
     
    5885891 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
    589590\end{cfa}
    590 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.
     591Note, Ā©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.
    591592Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    592593The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
     
    597598OT ?Ā®\Ā®?( OT ep, unsigned long int y );
    598599\end{cfa}
    599 The user type Ā©TĀ© must define multiplication, one (Ā©1Ā©), and Ā©*Ā©.
     600The user type Ā©TĀ© must define multiplication, one, Ā©1Ā©, and, Ā©*Ā©.
    600601
    601602
     
    625626
    626627
    627 %\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
    628 \subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}}
    629 
    630 C restricts the Ā©caseĀ© clause of a Ā©switchĀ© statement to a single value.
    631 For multiple Ā©caseĀ© clauses associated with the same statement, it is necessary to have multiple Ā©caseĀ© clauses rather than multiple values.
    632 Requiring a Ā©caseĀ© clause for each value does not seem to be in the spirit of brevity normally associated with C.
    633 Therefore, the Ā©caseĀ© clause is extended with a list of values, as in:
     628\subsection{Loop Control}
     629
     630The Ā©forĀ©/Ā©whileĀ©/Ā©do-whileĀ© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
     631\begin{itemize}
     632\item
     633An empty conditional implies Ā©1Ā©.
     634\item
     635The up-to range Ā©~Ā©\index{~@Ā©~Ā©} means exclusive range [M,N).
     636\item
     637The up-to range Ā©~=Ā©\index{~=@Ā©~=Ā©} means inclusive range [M,N].
     638\item
     639The down-to range Ā©-~Ā©\index{-~@Ā©-~Ā©} means exclusive range [N,M).
     640\item
     641The down-to range Ā©-~=Ā©\index{-~=@Ā©-~=Ā©} means inclusive range [N,M].
     642\item
     643Ā©@Ā© means put nothing in this field.
     644\item
     645Ā©0Ā© is the implicit start value;
     646\item
     647Ā©1Ā© is the implicit increment value.
     648\item
     649The up-to range uses Ā©+=Ā© for increment;
     650\item
     651The down-to range uses Ā©-=Ā© for decrement.
     652\item
     653The loop index is polymorphic in the type of the start value or comparison value when start is implicitly Ā©0Ā©.
     654\end{itemize}
     655
     656\begin{figure}
    634657\begin{cquote}
    635 \begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
    636 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\
    637 \begin{cfa}
    638 switch ( i ) {
    639   case Ā®1, 3, 5Ā®:
    640         ...
    641   case Ā®2, 4, 6Ā®:
    642         ...
    643 }
     658\begin{tabular}{@{}l|l@{}}
     659\multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
     660\hline
     661\begin{cfa}
     662sout | nlOff;
     663while Ā®()Ā® { sout | "empty"; break; } sout | nl;
     664do { sout | "empty"; break; } while Ā®()Ā®; sout | nl;
     665for Ā®()Ā® { sout | "empty"; break; } sout | nl;
     666for ( Ā®0Ā® ) { sout | "A"; } sout | "zero" | nl;
     667for ( Ā®1Ā® ) { sout | "A"; } sout | nl;
     668for ( Ā®10Ā® ) { sout | "A"; } sout | nl;
     669for ( Ā®1 ~= 10 ~ 2Ā® ) { sout | "B"; } sout | nl;
     670for ( Ā®10 -~= 1 ~ 2Ā® ) { sout | "C"; } sout | nl;
     671for ( Ā®0.5 ~ 5.5Ā® ) { sout | "D"; } sout | nl;
     672for ( Ā®5.5 -~ 0.5Ā® ) { sout | "E"; } sout | nl;
     673for ( Ā®i; 10Ā® ) { sout | i; } sout | nl;
     674for ( Ā®i; 1 ~= 10 ~ 2Ā® ) { sout | i; } sout | nl;
     675for ( Ā®i; 10 -~= 1 ~ 2Ā® ) { sout | i; } sout | nl;
     676for ( Ā®i; 0.5 ~ 5.5Ā® ) { sout | i; } sout | nl;
     677for ( Ā®i; 5.5 -~ 0.5Ā® ) { sout | i; } sout | nl;
     678for ( Ā®ui; 2u ~= 10u ~ 2uĀ® ) { sout | ui; } sout | nl;
     679for ( Ā®ui; 10u -~= 2u ~ 2uĀ® ) { sout | ui; } sout | nl;
     680enum { N = 10 };
     681for ( Ā®NĀ® ) { sout | "N"; } sout | nl;
     682for ( Ā®i; NĀ® ) { sout | i; } sout | nl;
     683for ( Ā®i; N -~ 0Ā® ) { sout | i; } sout | nl;
     684const int start = 3, comp = 10, inc = 2;
     685for ( Ā®i; start ~ comp ~ inc + 1Ā® ) { sout | i; } sout | nl;
     686for ( Ā®i; 1 ~ @Ā® ) { if ( i > 10 ) break;
     687        sout | i; } sout | nl;
     688for ( Ā®i; 10 -~ @Ā® ) { if ( i < 0 ) break;
     689        sout | i; } sout | nl;
     690for ( Ā®i; 2 ~ @ ~ 2Ā® ) { if ( i > 10 ) break;
     691        sout | i; } sout | nl;
     692for ( Ā®i; 2.1 ~ @ ~ @Ā® ) { if ( i > 10.5 ) break;
     693        sout | i; i += 1.7; } sout | nl;
     694for ( Ā®i; 10 -~ @ ~ 2Ā® ) { if ( i < 0 ) break;
     695        sout | i; } sout | nl;
     696for ( Ā®i; 12.1 ~ @ ~ @Ā® ) { if ( i < 2.5 ) break;
     697        sout | i; i -= 1.7; } sout | nl;
     698for ( Ā®i; 5 : j; -5 ~ @Ā® ) { sout | i | j; } sout | nl;
     699for ( Ā®i; 5 : j; -5 -~ @Ā® ) { sout | i | j; } sout | nl;
     700for ( Ā®i; 5 : j; -5 ~ @ ~ 2Ā® ) { sout | i | j; } sout | nl;
     701for ( Ā®i; 5 : j; -5 -~ @ ~ 2Ā® ) { sout | i | j; } sout | nl;
     702for ( Ā®j; -5 ~ @ : i; 5Ā® ) { sout | i | j; } sout | nl;
     703for ( Ā®j; -5 -~ @ : i; 5Ā® ) { sout | i | j; } sout | nl;
     704for ( Ā®j; -5 ~ @ ~ 2 : i; 5Ā® ) { sout | i | j; } sout | nl;
     705for ( Ā®j; -5 -~ @ ~ 2 : i; 5Ā® ) { sout | i | j; } sout | nl;
     706for ( Ā®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @Ā® ) {
     707        sout | i | j | k; } sout | nl;
     708for ( Ā®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5Ā® ) {
     709        sout | i | j | k; } sout | nl;
     710for ( Ā®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5Ā® ) {
     711        sout | i | j | k; } sout | nl;
    644712\end{cfa}
    645713&
    646714\begin{cfa}
    647 switch ( i ) {
    648   case 1: case 3 : case 5:
    649         ...
    650   case 2: case 4 : case 6:
    651         ...
    652 }
    653 \end{cfa}
    654 &
    655 \begin{cfa}
    656 
    657 // odd values
    658 
    659 // even values
    660 
    661 
     715
     716empty
     717empty
     718empty
     719zero
     720A
     721A A A A A A A A A A
     722B B B B B
     723C C C C C
     724D D D D D
     725E E E E E
     7260 1 2 3 4 5 6 7 8 9
     7271 3 5 7 9
     72810 8 6 4 2
     7290.5 1.5 2.5 3.5 4.5
     7305.5 4.5 3.5 2.5 1.5
     7312 4 6 8 10
     73210 8 6 4 2
     733
     734N N N N N N N N N N
     7350 1 2 3 4 5 6 7 8 9
     73610 9 8 7 6 5 4 3 2 1
     737
     7383 6 9
     739
     7401 2 3 4 5 6 7 8 9 10
     741
     74210 9 8 7 6 5 4 3 2 1 0
     743
     7442 4 6 8 10
     745
     7462.1 3.8 5.5 7.2 8.9
     747
     74810 8 6 4 2 0
     749
     75012.1 10.4 8.7 7 5.3 3.6
     7510 -5 1 -4 2 -3 3 -2 4 -1
     7520 -5 1 -6 2 -7 3 -8 4 -9
     7530 -5 1 -3 2 -1 3 1 4 3
     7540 -5 1 -7 2 -9 3 -11 4 -13
     7550 -5 1 -4 2 -3 3 -2 4 -1
     7560 -5 1 -6 2 -7 3 -8 4 -9
     7570 -5 1 -3 2 -1 3 1 4 3
     7580 -5 1 -7 2 -9 3 -11 4 -13
     759
     7600 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     761
     7620 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     763
     7640 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    662765\end{cfa}
    663766\end{tabular}
    664767\end{cquote}
    665 In addition, subranges are allowed to specify case values.\footnote{
    666 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.}
    667 \begin{cfa}
    668 switch ( i ) {
    669   case Ā®1~5:Ā® §\C{// 1, 2, 3, 4, 5}§
    670         ...
    671   case Ā®10~15:Ā® §\C{// 10, 11, 12, 13, 14, 15}§
    672         ...
    673 }
    674 \end{cfa}
    675 Lists of subranges are also allowed.
    676 \begin{cfa}
    677 case Ā®1~5, 12~21, 35~42Ā®:
    678 \end{cfa}
     768\caption{Loop Control Examples}
     769\label{f:LoopControlExamples}
     770\end{figure}
    679771
    680772
     
    885977
    886978
    887 \subsection{Non-terminating and Labelled \texorpdfstring{\LstKeywordStyle{fallthrough}}{Non-terminating and Labelled fallthrough}}
    888 
    889 The Ā©fallthroughĀ© clause may be non-terminating within a Ā©caseĀ© clause or have a target label to common code from multiple case clauses.
    890 \begin{center}
    891 \begin{tabular}{@{}lll@{}}
    892 \begin{cfa}
    893 choose ( ... ) {
    894   case 3:
    895         if ( ... ) {
    896                 ... Ā®fallthru;Ā® // goto case 4
    897         } else {
    898                 ...
    899         }
    900         // implicit break
    901   case 4:
    902 
    903 
    904 
    905 
     979%\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
     980\subsection{\texorpdfstring{\LstKeywordStyle{case} Statement}{case Statement}}
     981
     982C restricts the Ā©caseĀ© clause of a Ā©switchĀ© statement to a single value.
     983For multiple Ā©caseĀ© clauses associated with the same statement, it is necessary to have multiple Ā©caseĀ© clauses rather than multiple values.
     984Requiring a Ā©caseĀ© clause for each value does not seem to be in the spirit of brevity normally associated with C.
     985Therefore, the Ā©caseĀ© clause is extended with a list of values, as in:
     986\begin{cquote}
     987\begin{tabular}{@{}l@{\hspace{3em}}l@{\hspace{2em}}l@{}}
     988\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c@{\hspace{2em}}}{\textbf{C}} \\
     989\begin{cfa}
     990switch ( i ) {
     991  case Ā®1, 3, 5Ā®:
     992        ...
     993  case Ā®2, 4, 6Ā®:
     994        ...
     995}
    906996\end{cfa}
    907997&
    908998\begin{cfa}
    909 choose ( ... ) {
    910   case 3:
    911         ... Ā®fallthrough common;Ā®
    912   case 4:
    913         ... Ā®fallthrough common;Ā®
    914 
    915   Ā®common:Ā® // below fallthrough
    916                           // at case-clause level
    917         ...     // common code for cases 3/4
    918         // implicit break
    919   case 4:
    920 
    921 
     999switch ( i ) {
     1000  case 1: case 3 : case 5:
     1001        ...
     1002  case 2: case 4 : case 6:
     1003        ...
     1004}
    9221005\end{cfa}
    9231006&
    9241007\begin{cfa}
    925 choose ( ... ) {
    926   case 3:
    927         choose ( ... ) {
    928           case 4:
    929                 for ( ... ) {
    930                         // multi-level transfer
    931                         ... Ā®fallthru common;Ā®
    932                 }
    933                 ...
    934         }
     1008
     1009// odd values
     1010
     1011// even values
     1012
     1013
     1014\end{cfa}
     1015\end{tabular}
     1016\end{cquote}
     1017In addition, subranges are allowed to specify case values.\footnote{
     1018gcc 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.}
     1019\begin{cfa}
     1020switch ( i ) {
     1021  case Ā®1~5:Ā® §\C{// 1, 2, 3, 4, 5}§
    9351022        ...
    936   Ā®common:Ā® // below fallthrough
    937                           // at case-clause level
    938 \end{cfa}
    939 \end{tabular}
    940 \end{center}
    941 The target label must be below the Ā©fallthroughĀ© and may not be nested in a control structure, and
    942 the target label must be at the same or higher level as the containing Ā©caseĀ© clause and located at
    943 the same level as a Ā©caseĀ© clause; the target label may be case Ā©defaultĀ©, but only associated
    944 with the current Ā©switchĀ©/Ā©chooseĀ© statement.
    945 
    946 
    947 \subsection{Loop Control}
    948 
    949 The Ā©forĀ©/Ā©whileĀ©/Ā©do-whileĀ© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
    950 \begin{itemize}
    951 \item
    952 The loop index is polymorphic in the type of the comparison value N (when the start value is implicit) or the start value M.
    953 \item
    954 An empty conditional implies comparison value of Ā©1Ā© (true).
    955 \item
    956 A comparison N is implicit up-to exclusive range [0,N©®)®©.
    957 \item
    958 A comparison Ā©=Ā© N is implicit up-to inclusive range [0,N©®]®©.
    959 \item
    960 The up-to range M Ā©~Ā©\index{~@Ā©~Ā©} N means exclusive range [M,N©®)®©.
    961 \item
    962 The up-to range M Ā©~=Ā©\index{~=@Ā©~=Ā©} N means inclusive range [M,N©®]®©.
    963 \item
    964 The down-to range M Ā©-~Ā©\index{-~@Ā©-~Ā©} N means exclusive range [N,M©®)®©.
    965 \item
    966 The down-to range M Ā©-~=Ā©\index{-~=@Ā©-~=Ā©} N means inclusive range [N,M©®]®©.
    967 \item
    968 Ā©0Ā© is the implicit start value;
    969 \item
    970 Ā©1Ā© is the implicit increment value.
    971 \item
    972 The up-to range uses operator Ā©+=Ā© for increment;
    973 \item
    974 The down-to range uses operator Ā©-=Ā© for decrement.
    975 \item
    976 Ā©@Ā© means put nothing in this field.
    977 \item
    978 Ā©:Ā© means start another index.
    979 \end{itemize}
    980 
    981 \begin{figure}
    982 \begin{tabular}{@{}l|l@{}}
    983 \multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    984 \hline
    985 \begin{cfa}[xleftmargin=0pt]
    986 while Ā®()Ā® { sout | "empty"; break; }
    987 do { sout | "empty"; break; } while Ā®()Ā®;
    988 for Ā®()Ā® { sout | "empty"; break; }
    989 for ( Ā®0Ā® ) { sout | "A"; } sout | "zero";
    990 for ( Ā®1Ā® ) { sout | "A"; }
    991 for ( Ā®10Ā® ) { sout | "A"; }
    992 for ( Ā®= 10Ā® ) { sout | "A"; }
    993 for ( Ā®1 ~= 10 ~ 2Ā® ) { sout | "B"; }
    994 for ( Ā®10 -~= 1 ~ 2Ā® ) { sout | "C"; }
    995 for ( Ā®0.5 ~ 5.5Ā® ) { sout | "D"; }
    996 for ( Ā®5.5 -~ 0.5Ā® ) { sout | "E"; }
    997 for ( Ā®i; 10Ā® ) { sout | i; }
    998 for ( Ā®i; = 10Ā® ) { sout | i; }
    999 for ( Ā®i; 1 ~= 10 ~ 2Ā® ) { sout | i; }
    1000 for ( Ā®i; 10 -~= 1 ~ 2Ā® ) { sout | i; }
    1001 for ( Ā®i; 0.5 ~ 5.5Ā® ) { sout | i; }
    1002 for ( Ā®i; 5.5 -~ 0.5Ā® ) { sout | i; }
    1003 for ( Ā®ui; 2u ~= 10u ~ 2uĀ® ) { sout | ui; }
    1004 for ( Ā®ui; 10u -~= 2u ~ 2uĀ® ) { sout | ui; }
    1005 enum { N = 10 };
    1006 for ( Ā®NĀ® ) { sout | "N"; }
    1007 for ( Ā®i; NĀ® ) { sout | i; }
    1008 for ( Ā®i; N -~ 0Ā® ) { sout | i; }
    1009 const int start = 3, comp = 10, inc = 2;
    1010 for ( Ā®i; start ~ comp ~ inc + 1Ā® ) { sout | i; }
    1011 for ( i; 1 ~ Ā®@Ā® ) { if ( i > 10 ) break; sout | i; }
    1012 for ( i; 10 -~ Ā®@Ā® ) { if ( i < 0 ) break; sout | i; }
    1013 for ( i; 2 ~ Ā®@Ā® ~ 2 ) { if ( i > 10 ) break; sout | i; }
    1014 for ( i; 2.1 ~ Ā®@Ā® ~ Ā®@Ā® ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
    1015 for ( i; 10 -~ Ā®@Ā® ~ 2 ) { if ( i < 0 ) break; sout | i; }
    1016 for ( i; 12.1 ~ Ā®@Ā® ~ Ā®@Ā® ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
    1017 for ( i; 5 Ā®:Ā® j; -5 ~ @ ) { sout | i | j; }
    1018 for ( i; 5 Ā®:Ā® j; -5 -~ @ ) { sout | i | j; }
    1019 for ( i; 5 Ā®:Ā® j; -5 ~ @ ~ 2 ) { sout | i | j; }
    1020 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j; }
    1021 for ( i; 5 Ā®:Ā® j; -5 ~ @ ) { sout | i | j; }
    1022 for ( i; 5 Ā®:Ā® j; -5 -~ @ ) { sout | i | j; }
    1023 for ( i; 5 Ā®:Ā® j; -5 ~ @ ~ 2 ) { sout | i | j; }
    1024 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j; }
    1025 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 Ā®:Ā® k; 1.5 ~ @ ) { sout | i | j | k; }
    1026 for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 Ā®:Ā® k; 1.5 ~ @ ) { sout | i | j | k; }
    1027 for ( i; 5 Ā®:Ā® k; 1.5 ~ @ Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j | k; }
    1028 \end{cfa}
    1029 &
    1030 \begin{cfa}
    1031 empty
    1032 empty
    1033 empty
    1034 zero
    1035 A
    1036 A A A A A A A A A A
    1037 A A A A A A A A A A A
    1038 B B B B B
    1039 C C C C C
    1040 D D D D D
    1041 E E E E E
    1042 0 1 2 3 4 5 6 7 8 9
    1043 0 1 2 3 4 5 6 7 8 9 10
    1044 1 3 5 7 9
    1045 10 8 6 4 2
    1046 0.5 1.5 2.5 3.5 4.5
    1047 5.5 4.5 3.5 2.5 1.5
    1048 2 4 6 8 10
    1049 10 8 6 4 2
    1050 
    1051 N N N N N N N N N N
    1052 0 1 2 3 4 5 6 7 8 9
    1053 10 9 8 7 6 5 4 3 2 1
    1054 
    1055 3 6 9
    1056 1 2 3 4 5 6 7 8 9 10
    1057 10 9 8 7 6 5 4 3 2 1 0
    1058 2 4 6 8 10
    1059 2.1 3.8 5.5 7.2 8.9
    1060 10 8 6 4 2 0
    1061 12.1 10.4 8.7 7. 5.3 3.6
    1062 0 -5 1 -4 2 -3 3 -2 4 -1
    1063 0 -5 1 -6 2 -7 3 -8 4 -9
    1064 0 -5 1 -3 2 -1 3 1 4 3
    1065 0 -5 1 -7 2 -9 3 -11 4 -13
    1066 0 -5 1 -4 2 -3 3 -2 4 -1
    1067 0 -5 1 -6 2 -7 3 -8 4 -9
    1068 0 -5 1 -3 2 -1 3 1 4 3
    1069 0 -5 1 -7 2 -9 3 -11 4 -13
    1070 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    1071 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    1072 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    1073 \end{cfa}
    1074 \end{tabular}
    1075 \caption{Loop Control Examples}
    1076 \label{f:LoopControlExamples}
    1077 \end{figure}
     1023  case Ā®10~15:Ā® §\C{// 10, 11, 12, 13, 14, 15}§
     1024        ...
     1025}
     1026\end{cfa}
     1027Lists of subranges are also allowed.
     1028\begin{cfa}
     1029case Ā®1~5, 12~21, 35~42Ā®:
     1030\end{cfa}
     1031
    10781032
    10791033% for ()  => for ( ;; )
     
    65936547hence, names in these include files are not mangled\index{mangling!name} (see~\VRef{s:Interoperability}).
    65946548All other C header files must be explicitly wrapped in ©extern "C"© to prevent name mangling.
    6595 This approach is different from \Index*[C++]{\CC{}} where the name-mangling issue is handled internally in C header-files through checks for preprocessor variable Ā©__cplusplusĀ©, which adds appropriate Ā©extern "C"Ā© qualifiers.
     6549For \Index*[C++]{\CC{}}, the name-mangling issue is often handled internally in many C header-files through checks for preprocessor variable Ā©__cplusplusĀ©, which adds appropriate Ā©extern "C"Ā© qualifiers.
    65966550
    65976551
     
    66076561The storage-management routines extend their C equivalents by overloading, alternate names, providing shallow type-safety, and removing the need to specify the allocation size for non-array types.
    66086562
    6609 C storage management provides the following capabilities:
     6563Storage management provides the following capabilities:
    66106564\begin{description}
    6611 \item[filled]
    6612 after allocation with a specified character or value.
     6565\item[fill]
     6566after allocation the storage is filled with a specified character.
    66136567\item[resize]
    6614 an existing allocation to decreased or increased its size.
    6615 In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
     6568an existing allocation is decreased or increased in size.
     6569In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied.
    66166570For an increase in storage size, new storage after the copied data may be filled.
    6617 \item[align]
    6618 an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
     6571\item[alignment]
     6572an allocation starts on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    66196573\item[array]
    66206574the allocation size is scaled to the specified number of array elements.
    66216575An array may be filled, resized, or aligned.
    66226576\end{description}
    6623 \VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
    6624 \begin{table}
    6625 \centering
    6626 \begin{minipage}{0.75\textwidth}
    6627 \begin{tabular}{@{}r|l|l|l|l|l@{}}
     6577The table shows allocation routines supporting different combinations of storage-management capabilities:
     6578\begin{center}
     6579\begin{tabular}{@{}r|r|l|l|l|l@{}}
    66286580\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
    66296581\hline
    66306582C               & Ā©mallocĀ©                      & no                    & no            & no            & no    \\
    66316583                & Ā©callocĀ©                      & yes (0 only)  & no            & no            & yes   \\
    6632                 & Ā©reallocĀ©                     & copy                  & yes           & no            & no    \\
     6584                & Ā©reallocĀ©                     & no/copy               & yes           & no            & no    \\
    66336585                & Ā©memalignĀ©            & no                    & no            & yes           & no    \\
    6634                 & Ā©aligned_allocĀ©\footnote{Same as Ā©memalignĀ© but size is an integral multiple of alignment, which is universally ignored.}
    6635                                                         & no                    & no            & yes           & no    \\
    66366586                & Ā©posix_memalignĀ©      & no                    & no            & yes           & no    \\
    6637                 & Ā©vallocĀ©                      & no                    & no            & yes (page size)& no   \\
    6638                 & Ā©pvallocĀ©\footnote{Same as Ā©vallocĀ© but rounds size to multiple of page size.}
    6639                                                         & no                    & no            & yes (page size)& no   \\
    66406587\hline
    6641 \CFA    & Ā©cmemalignĀ©           & yes (0 only)  & no            & yes           & yes   \\
    6642                 & Ā©reallocĀ©                     & copy                  & yes           & yes           & no    \\
    6643                 & Ā©allocĀ©                       & no                    & yes           & no            & yes   \\
    6644                 & Ā©alloc_setĀ©           & yes                   & yes           & no            & yes   \\
    6645                 & Ā©alloc_alignĀ©         & no                    & yes           & yes           & yes   \\
    6646                 & Ā©alloc_align_setĀ©     & yes                   & yes           & yes           & yes   \\
     6588C11             & Ā©aligned_allocĀ©       & no                    & no            & yes           & no    \\
     6589\hline
     6590\CFA    & Ā©allocĀ©                       & no/copy/yes   & no/yes        & no            & yes   \\
     6591                & Ā©align_allocĀ©         & no/yes                & no            & yes           & yes   \\
    66476592\end{tabular}
    6648 \end{minipage}
    6649 \caption{Allocation Routines versus Storage-Management Capabilities}
    6650 \label{t:AllocationVersusCapabilities}
    6651 \end{table}
    6652 
    6653 \CFA memory management extends the type safety of all allocations by using the type of the left-hand-side type to determine the allocation size and return a matching type for the new storage.
    6654 Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
    6655 \begin{cfa}
    6656 int * ip = (int *)malloc( sizeof(int) );                §\C{// C}§
    6657 int * ip = malloc();                                                    §\C{// \CFA type-safe version of C malloc}§
    6658 int * ip = alloc();                                                             Ā§\C{// \CFA type-safe uniform alloc}§
    6659 \end{cfa}
    6660 the latter two allocations determine the allocation size from the type of Ā©pĀ© (Ā©intĀ©) and cast the pointer to the allocated storage to Ā©int *Ā©.
    6661 
    6662 \CFA memory management extends allocation safety by implicitly honouring all alignment requirements, \eg in
    6663 \begin{cfa}
    6664 struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
    6665 S * sp = malloc();                                                              §\C{// honour type alignment}§
    6666 \end{cfa}
    6667 the storage allocation is implicitly aligned to 128 rather than the default 16.
    6668 The alignment check is performed at compile time so there is no runtime cost.
    6669 
    6670 \CFA memory management extends the resize capability with the notion of \newterm{sticky properties}.
    6671 Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
    6672 For example, an initial alignment and fill capability are preserved during a resize copy so the copy has the same alignment and extended storage is filled.
    6673 Without sticky properties it is dangerous to use Ā©reallocĀ©, resulting in an idiom of manually performing the reallocation to maintain correctness.
    6674 
    6675 \CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in
    6676 \begin{cfa}
    6677 struct S { int i; };                                                    §\C{// cache-line aglinment}§
    6678 void ?{}( S & s, int i ) { s.i = i; }
    6679 // assume ?|? operator for printing an S
    6680 
    6681 S & sp = *Ā®newĀ®( 3 );                                                   Ā§\C{// call constructor after allocation}§
    6682 sout | sp.i;
    6683 Ā®deleteĀ®( &sp );
    6684 
    6685 S * spa = Ā®anewĀ®( 10, 5 );                                              §\C{// allocate array and initialize each array element}§
    6686 for ( i; 10 ) sout | spa[i] | nonl;
    6687 sout | nl;
    6688 Ā®adeleteĀ®( 10, spa );
    6689 \end{cfa}
    6690 Allocation routines Ā©newĀ©/Ā©anewĀ© allocate a variable/array and initialize storage using the allocated type's constructor.
    6691 Note, the matching deallocation routines Ā©deleteĀ©/Ā©adeleteĀ©.
     6593\end{center}
     6594It is impossible to resize with alignment because the underlying Ā©reallocĀ© allocates storage if more space is needed, and it does not honour alignment from the original allocation.
    66926595
    66936596\leavevmode
    66946597\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     6598// C unsafe allocation
    66956599extern "C" {
    6696         // C unsafe allocation
    6697         void * malloc( size_t size );§\indexc{malloc}§
    6698         void * calloc( size_t dim, size_t size );§\indexc{calloc}§
    6699         void * realloc( void * ptr, size_t size );§\indexc{realloc}§
    6700         void * memalign( size_t align, size_t size );§\indexc{memalign}§
    6701         void * aligned_alloc( size_t align, size_t size );§\indexc{aligned_alloc}§
    6702         int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
    6703         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );§\indexc{cmemalign}§ // CFA
    6704 
    6705         // C unsafe initialization/copy
    6706         void * memset( void * dest, int c, size_t size );§\indexc{memset}§
    6707         void * memcpy( void * dest, const void * src, size_t size );§\indexc{memcpy}§
    6708 }
    6709 
    6710 void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
     6600void * malloc( size_t size );§\indexc{memset}§
     6601void * calloc( size_t dim, size_t size );§\indexc{calloc}§
     6602void * realloc( void * ptr, size_t size );§\indexc{realloc}§
     6603void * memalign( size_t align, size_t size );§\indexc{memalign}§
     6604int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
     6605
     6606// C unsafe initialization/copy
     6607void * memset( void * dest, int c, size_t size );
     6608void * memcpy( void * dest, const void * src, size_t size );
     6609}
    67116610
    67126611forall( dtype T | sized(T) ) {
    6713         // §\CFA§ safe equivalents, i.e., implicit size specification
     6612// §\CFA§ safe equivalents, i.e., implicit size specification
    67146613        T * malloc( void );
    67156614        T * calloc( size_t dim );
    67166615        T * realloc( T * ptr, size_t size );
    67176616        T * memalign( size_t align );
    6718         T * cmemalign( size_t align, size_t dim  );
    67196617        T * aligned_alloc( size_t align );
    67206618        int posix_memalign( T ** ptr, size_t align );
    67216619
    6722         // §\CFA§ safe general allocation, fill, resize, alignment, array
     6620// §\CFA§ safe general allocation, fill, resize, array
    67236621        T * alloc( void );§\indexc{alloc}§
     6622        T * alloc( char fill );
    67246623        T * alloc( size_t dim );
     6624        T * alloc( size_t dim, char fill );
    67256625        T * alloc( T ptr[], size_t dim );
    6726         T * alloc_set( char fill );§\indexc{alloc_set}§
    6727         T * alloc_set( T fill );
    6728         T * alloc_set( size_t dim, char fill );
    6729         T * alloc_set( size_t dim, T fill );
    6730         T * alloc_set( size_t dim, const T fill[] );
    6731         T * alloc_set( T ptr[], size_t dim, char fill );
    6732 
    6733         T * alloc_align( size_t align );
    6734         T * alloc_align( size_t align, size_t dim );
    6735         T * alloc_align( T ptr[], size_t align ); // aligned realloc array
    6736         T * alloc_align( T ptr[], size_t align, size_t dim ); // aligned realloc array
    6737         T * alloc_align_set( size_t align, char fill );
    6738         T * alloc_align_set( size_t align, T fill );
    6739         T * alloc_align_set( size_t align, size_t dim, char fill );
    6740         T * alloc_align_set( size_t align, size_t dim, T fill );
    6741         T * alloc_align_set( size_t align, size_t dim, const T fill[] );
    6742         T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill );
    6743 
    6744         // §\CFA§ safe initialization/copy, i.e., implicit size specification
    6745         T * memset( T * dest, char fill );§\indexc{memset}§
     6626        T * alloc( T ptr[], size_t dim, char fill );
     6627
     6628// §\CFA§ safe general allocation, align, fill, array
     6629        T * align_alloc( size_t align );
     6630        T * align_alloc( size_t align, char fill );
     6631        T * align_alloc( size_t align, size_t dim );
     6632        T * align_alloc( size_t align, size_t dim, char fill );
     6633
     6634// §\CFA§ safe initialization/copy, i.e., implicit size specification
     6635        T * memset( T * dest, char c );§\indexc{memset}§
    67466636        T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
    67476637
    6748         // §\CFA§ safe initialization/copy, i.e., implicit size specification, array types
    6749         T * amemset( T dest[], char fill, size_t dim );
     6638// §\CFA§ safe initialization/copy array
     6639        T * amemset( T dest[], char c, size_t dim );
    67506640        T * amemcpy( T dest[], const T src[], size_t dim );
    67516641}
    67526642
    6753 // §\CFA§ allocation/deallocation and constructor/destructor, non-array types
    6754 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
    6755 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
    6756 forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
     6643// §\CFA§ allocation/deallocation and constructor/destructor
     6644forall( dtype T | sized(T), ttype Params | { void ?{}( T *, Params ); } ) T * new( Params p );§\indexc{new}§
     6645forall( dtype T | { void ^?{}( T * ); } ) void delete( T * ptr );§\indexc{delete}§
     6646forall( dtype T, ttype Params | { void ^?{}( T * ); void delete( Params ); } )
    67576647  void delete( T * ptr, Params rest );
    67586648
    6759 // §\CFA§ allocation/deallocation and constructor/destructor, array types
    6760 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
    6761 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
    6762 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
     6649// §\CFA§ allocation/deallocation and constructor/destructor, array
     6650forall( dtype T | sized(T), ttype Params | { void ?{}( T *, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
     6651forall( dtype T | sized(T) | { void ^?{}( T * ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
     6652forall( dtype T | sized(T) | { void ^?{}( T * ); }, ttype Params | { void adelete( Params ); } )
    67636653  void adelete( size_t dim, T arr[], Params rest );
    67646654\end{cfa}
  • driver/cc1.cc

    r7030dab r71d6bd8  
    335335        #endif // __DEBUG_H__
    336336
    337         enum {
    338                 Color_Auto   = 0,
    339                 Color_Always = 1,
    340                 Color_Never  = 2,
    341         } color_arg = Color_Auto;
    342 
    343         const char * color_names[3] = { "--colors=auto", "--colors=always", "--colors=never" };
    344 
    345337        // process all the arguments
    346338
     
    349341                if ( prefix( arg, "-" ) ) {
    350342                        // strip inappropriate flags
    351 
    352                         if ( prefix( arg, "-fdiagnostics-color=" ) ) {
    353                                 string choice = arg.substr(20);
    354                                      if(choice == "always") color_arg = Color_Always;
    355                                 else if(choice == "never" ) color_arg = Color_Never;
    356                                 else if(choice == "auto"  ) color_arg = Color_Auto;
    357                         } else if ( arg == "-fno-diagnostics-color" ) {
    358                                 color_arg = Color_Auto;
    359                         }
    360343
    361344                        if ( arg == "-quiet" || arg == "-version" || arg == "-fpreprocessed" ||
     
    457440                        cargs[ncargs++] = cfa_cpp_out.c_str();
    458441                } // if
    459 
    460                 cargs[ncargs++] = color_names[color_arg];
    461 
    462442                cargs[ncargs] = nullptr;                                                // terminate argument list
    463443
  • driver/cfa.cc

    r7030dab r71d6bd8  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jan 31 16:48:03 2020
    13 // Update Count     : 421
     12// Last Modified On : Tue Sep 10 17:00:15 2019
     13// Update Count     : 420
    1414//
    1515
     
    187187                        } else if ( arg == "-XCFA" ) {                          // CFA pass through
    188188                                i += 1;
    189                                 if ( i == argc ) continue;                              // next argument available ?
    190189                                Putenv( argv, argv[i] );
    191190
     
    402401                args[nargs++] = "-Xlinker";
    403402                args[nargs++] = "--undefined=__cfaabi_appready_startup";
    404                 args[nargs++] = "-z";
    405                 args[nargs++] = "execstack";
    406403
    407404                // include the cfa library in case it is needed
     
    411408                args[nargs++] = "-lcfathread";
    412409                args[nargs++] = "-Wl,--pop-state";
    413                 args[nargs++] = "-Wl,--push-state,--no-as-needed";
    414410                args[nargs++] = "-lcfa";
    415                 args[nargs++] = "-Wl,--pop-state";
    416                 args[nargs++] = "-pthread";
     411                args[nargs++] = "-lpthread";
    417412                args[nargs++] = "-ldl";
    418413                args[nargs++] = "-lrt";
  • libcfa/configure

    r7030dab r71d6bd8  
    30003000case $CONFIGURATION in
    30013001        "debug"   )
    3002                 CONFIG_CFLAGS="-O0 -g"
     3002                CONFIG_CFLAGS="-Og -g"
    30033003                CONFIG_CFAFLAGS="-debug"
    30043004                CONFIG_BUILDLIB="yes"
  • libcfa/configure.ac

    r7030dab r71d6bd8  
    6868case $CONFIGURATION in
    6969        "debug"   )
    70                 CONFIG_CFLAGS="-O0 -g"
     70                CONFIG_CFLAGS="-Og -g"
    7171                CONFIG_CFAFLAGS="-debug"
    7272                CONFIG_BUILDLIB="yes"
  • libcfa/prelude/Makefile.am

    r7030dab r71d6bd8  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Feb  3 21:27:18 2020
    14 ## Update Count     : 208
     13## Last Modified On : Wed Dec 14 15:00:35 2016
     14## Update Count     : 205
    1515###############################################################################
    1616
     
    3636extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
    3737        ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx > extras.cf
    38         ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> extras.cf
    3938
    4039# create forward declarations for gcc builtins
  • libcfa/prelude/Makefile.in

    r7030dab r71d6bd8  
    1 # Makefile.in generated by automake 1.16.1 from Makefile.am.
     1# Makefile.in generated by automake 1.15 from Makefile.am.
    22# @configure_input@
    33
    4 # Copyright (C) 1994-2018 Free Software Foundation, Inc.
     4# Copyright (C) 1994-2014 Free Software Foundation, Inc.
    55
    66# This Makefile.in is free software; the Free Software Foundation
     
    331331            cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
    332332          *) \
    333             echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
    334             cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
     333            echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
     334            cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
    335335        esac;
    336336
     
    377377
    378378
    379 distdir: $(BUILT_SOURCES)
    380         $(MAKE) $(AM_MAKEFLAGS) distdir-am
    381 
    382 distdir-am: $(DISTFILES)
     379distdir: $(DISTFILES)
    383380        @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
    384381        topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
     
    543540extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
    544541        ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx > extras.cf
    545         ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> extras.cf
    546542
    547543# create forward declarations for gcc builtins
  • libcfa/prelude/builtins.c

    r7030dab r71d6bd8  
    1010// Created On       : Fri Jul 21 16:21:03 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Nov 21 16:31:39 2019
    13 // Update Count     : 101
     12// Last Modified On : Tue Jun 25 18:06:52 2019
     13// Update Count     : 97
    1414//
    1515
     
    4949void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    5050
    51 forall(dtype T)
    52 static inline T & identity(T & i) {
    53         return i;
    54 }
    55 
    56 // generator support
    57 struct $generator {
    58         inline int;
    59 };
    60 
    61 static inline void  ?{}($generator & this) { ((int&)this) = 0; }
    62 static inline void ^?{}($generator &) {}
    63 
    64 trait is_generator(dtype T) {
    65       void main(T & this);
    66       $generator * get_generator(T & this);
    67 };
    68 
    69 forall(dtype T | is_generator(T))
    70 static inline T & resume(T & gen) {
    71         main(gen);
    72         return gen;
    73 }
    74 
    7551// implicit increment, decrement if += defined, and implicit not if != defined
    7652
     
    9369
    9470// universal typed pointer constant
    95 static inline forall( dtype DT ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
     71// Compiler issue: there is a problem with anonymous types that do not have a size.
     72static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
    9673
    9774// exponentiation operator implementation
  • libcfa/prelude/extras.regx

    r7030dab r71d6bd8  
    2424typedef.* char32_t;
    2525typedef.* wchar_t;
     26extern.*\*malloc\(.*\).*
     27extern.* free\(.*\).*
     28extern.* exit\(.*\).*
     29extern.* atexit\(.*\).*
     30extern.* abort\(.*\).*
     31extern.* printf\(.*\).*
  • libcfa/prelude/prototypes.awk

    r7030dab r71d6bd8  
    1010# Created On       : Sat May 16 07:57:37 2015
    1111# Last Modified By : Peter A. Buhr
    12 # Last Modified On : Sat Feb  8 09:46:58 2020
    13 # Update Count     : 36
     12# Last Modified On : Thu Jun  6 20:46:28 2019
     13# Update Count     : 34
    1414#
    1515
     
    1717
    1818BEGIN {
    19         FS = "[( )]"
     19  FS = "[( )]"
    2020        # order so string search is longest string
    2121        i=-1
     
    8484
    8585/BT_FN/ {
    86         for (i = 1; i <= NF; i += 1 ) {
    87                 if ( match($i, "BT_FN") != 0 ) {
    88                         prototypes[$i] = $i
    89                 }
     86        for (i = 1; i <= NF; i++) {
     87          if( match($i, "BT_FN") != 0 ) {
     88                prototypes[$i] = $i
     89          }
    9090        }
    91 }
     91  }
    9292
    9393END {
     
    103103
    104104        for ( prototype in prototypes ) {
    105                 # printf( "//\"%s\"\n", prototype )
    106                 if ( index( "BT_LAST", prototype ) == 1 ) {
    107                         continue
     105          # printf( "//\"%s\"\n", prototype )
     106          if ( index( "BT_LAST", prototype ) == 1 ) {
     107                continue
     108          } # if
     109
     110          printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
     111
     112          if ( sub( "BT_FN_", "", prototype ) == 0 ) {
     113                printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
     114                exit 0
     115          } # if
     116
     117          # generate function return type as macro
     118          for ( t = 0; t < N; t += 1 ) {                                        # find longest match
     119                type = types[t];
     120                if ( index( prototype, type ) == 1 ) {          # found match
     121                  printf( "BT_%s, NAME", type )
     122                  sub( type, "", prototype )
     123                  break;
    108124                } # if
     125          } # for
    109126
    110                 printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
    111 
    112                 if ( sub( "BT_FN_", "", prototype ) == 0 ) {
    113                         printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
     127          # generate function parameter types as macro
     128          if ( index( prototype, "VAR" ) != 2 ) {                       # C-style empty parameters ?
     129                for ( p = 0; length( prototype ) > 0; p += 1 ) { # until all parameters types are removed
     130                  sub( "_", "", prototype)                              # remove "_"
     131                  printf( ", ", type )
     132                  temp = prototype
     133                  for ( t = 0; t < N; t += 1 ) {                        # find longest match
     134                        type = types[t];
     135                        if ( index( prototype, type ) == 1 ) { # found match
     136                          printf( "BT_%s", type )
     137                          sub( type, "", prototype )
     138                          break;
     139                        } # if
     140                  } # for
     141                  if ( temp == prototype ) {                            # no match found for parameter in macro table
     142                        printf( "\n********** MISSING TYPE \"%s\" **********\n", prototype )
    114143                        exit 0
    115                 } # if
    116 
    117                 # generate function return type as macro
    118                 for ( t = 0; t < N; t += 1 ) {                                  # find longest match
    119                         type = types[t];
    120                         if ( index( prototype, type ) == 1 ) {          # found match
    121                                 printf( "BT_%s, NAME", type )
    122                                 sub( type, "", prototype )
    123                                 break;
    124                         } # if
     144                  } # if
    125145                } # for
    126 
    127                 # generate function parameter types as macro
    128                 if ( index( prototype, "VAR" ) != 2 ) {                 # C-style empty parameters ?
    129                         for ( p = 0; length( prototype ) > 0; p += 1 ) { # until all parameters types are removed
    130                                 sub( "_", "", prototype)                                # remove "_"
    131                                 printf( ", ", type )
    132                                 temp = prototype
    133                                 for ( t = 0; t < N; t += 1 ) {                  # find longest match
    134                                         type = types[t];
    135                                         if ( index( prototype, type ) == 1 ) { # found match
    136                                                 printf( "BT_%s", type )
    137                                                 sub( type, "", prototype )
    138                                                 break;
    139                                         } # if
    140                                 } # for
    141                                 if ( temp == prototype ) {                              # no match found for parameter in macro table
    142                                         printf( "\n********** MISSING TYPE \"%s\" **********\n", prototype )
    143                                         exit 0
    144                                 } # if
    145                         } # for
    146                 } # if
    147                 printf( ")\n" )
     146          } # if
     147          printf( ")\n" )
    148148        } # for
    149149
  • libcfa/prelude/sync-builtins.cf

    r7030dab r71d6bd8  
    11char __sync_fetch_and_add(volatile char *, char,...);
     2char __sync_fetch_and_add_1(volatile char *, char,...);
    23signed char __sync_fetch_and_add(volatile signed char *, signed char,...);
     4signed char __sync_fetch_and_add_1(volatile signed char *, signed char,...);
    35unsigned char __sync_fetch_and_add(volatile unsigned char *, unsigned char,...);
     6unsigned char __sync_fetch_and_add_1(volatile unsigned char *, unsigned char,...);
    47signed short __sync_fetch_and_add(volatile signed short *, signed short,...);
     8signed short __sync_fetch_and_add_2(volatile signed short *, signed short,...);
    59unsigned short __sync_fetch_and_add(volatile unsigned short *, unsigned short,...);
     10unsigned short __sync_fetch_and_add_2(volatile unsigned short *, unsigned short,...);
    611signed int __sync_fetch_and_add(volatile signed int *, signed int,...);
     12signed int __sync_fetch_and_add_4(volatile signed int *, signed int,...);
    713unsigned int __sync_fetch_and_add(volatile unsigned int *, unsigned int,...);
    8 signed long int __sync_fetch_and_add(volatile signed long int *, signed long int,...);
    9 unsigned long int __sync_fetch_and_add(volatile unsigned long int *, unsigned long int,...);
     14unsigned int __sync_fetch_and_add_4(volatile unsigned int *, unsigned int,...);
    1015signed long long int __sync_fetch_and_add(volatile signed long long int *, signed long long int,...);
     16signed long long int __sync_fetch_and_add_8(volatile signed long long int *, signed long long int,...);
    1117unsigned long long int __sync_fetch_and_add(volatile unsigned long long int *, unsigned long long int,...);
     18unsigned long long int __sync_fetch_and_add_8(volatile unsigned long long int *, unsigned long long int,...);
    1219#if defined(__SIZEOF_INT128__)
    1320signed __int128 __sync_fetch_and_add(volatile signed __int128 *, signed __int128,...);
     21signed __int128 __sync_fetch_and_add_16(volatile signed __int128 *, signed __int128,...);
    1422unsigned __int128 __sync_fetch_and_add(volatile unsigned __int128 *, unsigned __int128,...);
     23unsigned __int128 __sync_fetch_and_add_16(volatile unsigned __int128 *, unsigned __int128,...);
    1524#endif
    1625
    1726char __sync_fetch_and_sub(volatile char *, char,...);
     27char __sync_fetch_and_sub_1(volatile char *, char,...);
    1828signed char __sync_fetch_and_sub(volatile signed char *, signed char,...);
     29signed char __sync_fetch_and_sub_1(volatile signed char *, signed char,...);
    1930unsigned char __sync_fetch_and_sub(volatile unsigned char *, unsigned char,...);
     31unsigned char __sync_fetch_and_sub_1(volatile unsigned char *, unsigned char,...);
    2032signed short __sync_fetch_and_sub(volatile signed short *, signed short,...);
     33signed short __sync_fetch_and_sub_2(volatile signed short *, signed short,...);
    2134unsigned short __sync_fetch_and_sub(volatile unsigned short *, unsigned short,...);
     35unsigned short __sync_fetch_and_sub_2(volatile unsigned short *, unsigned short,...);
    2236signed int __sync_fetch_and_sub(volatile signed int *, signed int,...);
     37signed int __sync_fetch_and_sub_4(volatile signed int *, signed int,...);
    2338unsigned int __sync_fetch_and_sub(volatile unsigned int *, unsigned int,...);
    24 signed long int __sync_fetch_and_sub(volatile signed long int *, signed long int,...);
    25 unsigned long int __sync_fetch_and_sub(volatile unsigned long int *, unsigned long int,...);
     39unsigned int __sync_fetch_and_sub_4(volatile unsigned int *, unsigned int,...);
    2640signed long long int __sync_fetch_and_sub(volatile signed long long int *, signed long long int,...);
     41signed long long int __sync_fetch_and_sub_8(volatile signed long long int *, signed long long int,...);
    2742unsigned long long int __sync_fetch_and_sub(volatile unsigned long long int *, unsigned long long int,...);
     43unsigned long long int __sync_fetch_and_sub_8(volatile unsigned long long int *, unsigned long long int,...);
    2844#if defined(__SIZEOF_INT128__)
    2945signed __int128 __sync_fetch_and_sub(volatile signed __int128 *, signed __int128,...);
     46signed __int128 __sync_fetch_and_sub_16(volatile signed __int128 *, signed __int128,...);
    3047unsigned __int128 __sync_fetch_and_sub(volatile unsigned __int128 *, unsigned __int128,...);
     48unsigned __int128 __sync_fetch_and_sub_16(volatile unsigned __int128 *, unsigned __int128,...);
    3149#endif
    3250
    3351char __sync_fetch_and_or(volatile char *, char,...);
     52char __sync_fetch_and_or_1(volatile char *, char,...);
    3453signed char __sync_fetch_and_or(volatile signed char *, signed char,...);
     54signed char __sync_fetch_and_or_1(volatile signed char *, signed char,...);
    3555unsigned char __sync_fetch_and_or(volatile unsigned char *, unsigned char,...);
     56unsigned char __sync_fetch_and_or_1(volatile unsigned char *, unsigned char,...);
    3657signed short __sync_fetch_and_or(volatile signed short *, signed short,...);
     58signed short __sync_fetch_and_or_2(volatile signed short *, signed short,...);
    3759unsigned short __sync_fetch_and_or(volatile unsigned short *, unsigned short,...);
     60unsigned short __sync_fetch_and_or_2(volatile unsigned short *, unsigned short,...);
    3861signed int __sync_fetch_and_or(volatile signed int *, signed int,...);
     62signed int __sync_fetch_and_or_4(volatile signed int *, signed int,...);
    3963unsigned int __sync_fetch_and_or(volatile unsigned int *, unsigned int,...);
    40 signed long int __sync_fetch_and_or(volatile signed long int *, signed long int,...);
    41 unsigned long int __sync_fetch_and_or(volatile unsigned long int *, unsigned long int,...);
     64unsigned int __sync_fetch_and_or_4(volatile unsigned int *, unsigned int,...);
    4265signed long long int __sync_fetch_and_or(volatile signed long long int *, signed long long int,...);
     66signed long long int __sync_fetch_and_or_8(volatile signed long long int *, signed long long int,...);
    4367unsigned long long int __sync_fetch_and_or(volatile unsigned long long int *, unsigned long long int,...);
     68unsigned long long int __sync_fetch_and_or_8(volatile unsigned long long int *, unsigned long long int,...);
    4469#if defined(__SIZEOF_INT128__)
    4570signed __int128 __sync_fetch_and_or(volatile signed __int128 *, signed __int128,...);
     71signed __int128 __sync_fetch_and_or_16(volatile signed __int128 *, signed __int128,...);
    4672unsigned __int128 __sync_fetch_and_or(volatile unsigned __int128 *, unsigned __int128,...);
     73unsigned __int128 __sync_fetch_and_or_16(volatile unsigned __int128 *, unsigned __int128,...);
    4774#endif
    4875
    4976char __sync_fetch_and_and(volatile char *, char,...);
     77char __sync_fetch_and_and_1(volatile char *, char,...);
    5078signed char __sync_fetch_and_and(volatile signed char *, signed char,...);
     79signed char __sync_fetch_and_and_1(volatile signed char *, signed char,...);
    5180unsigned char __sync_fetch_and_and(volatile unsigned char *, unsigned char,...);
     81unsigned char __sync_fetch_and_and_1(volatile unsigned char *, unsigned char,...);
    5282signed short __sync_fetch_and_and(volatile signed short *, signed short,...);
     83signed short __sync_fetch_and_and_2(volatile signed short *, signed short,...);
    5384unsigned short __sync_fetch_and_and(volatile unsigned short *, unsigned short,...);
     85unsigned short __sync_fetch_and_and_2(volatile unsigned short *, unsigned short,...);
    5486signed int __sync_fetch_and_and(volatile signed int *, signed int,...);
     87signed int __sync_fetch_and_and_4(volatile signed int *, signed int,...);
    5588unsigned int __sync_fetch_and_and(volatile unsigned int *, unsigned int,...);
    56 signed long int __sync_fetch_and_and(volatile signed long int *, signed long int,...);
    57 unsigned long int __sync_fetch_and_and(volatile unsigned long int *, unsigned long int,...);
     89unsigned int __sync_fetch_and_and_4(volatile unsigned int *, unsigned int,...);
    5890signed long long int __sync_fetch_and_and(volatile signed long long int *, signed long long int,...);
     91signed long long int __sync_fetch_and_and_8(volatile signed long long int *, signed long long int,...);
    5992unsigned long long int __sync_fetch_and_and(volatile unsigned long long int *, unsigned long long int,...);
     93unsigned long long int __sync_fetch_and_and_8(volatile unsigned long long int *, unsigned long long int,...);
    6094#if defined(__SIZEOF_INT128__)
    6195signed __int128 __sync_fetch_and_and(volatile signed __int128 *, signed __int128,...);
     96signed __int128 __sync_fetch_and_and_16(volatile signed __int128 *, signed __int128,...);
    6297unsigned __int128 __sync_fetch_and_and(volatile unsigned __int128 *, unsigned __int128,...);
     98unsigned __int128 __sync_fetch_and_and_16(volatile unsigned __int128 *, unsigned __int128,...);
    6399#endif
    64100
    65101char __sync_fetch_and_xor(volatile char *, char,...);
     102char __sync_fetch_and_xor_1(volatile char *, char,...);
    66103signed char __sync_fetch_and_xor(volatile signed char *, signed char,...);
     104signed char __sync_fetch_and_xor_1(volatile signed char *, signed char,...);
    67105unsigned char __sync_fetch_and_xor(volatile unsigned char *, unsigned char,...);
     106unsigned char __sync_fetch_and_xor_1(volatile unsigned char *, unsigned char,...);
    68107signed short __sync_fetch_and_xor(volatile signed short *, signed short,...);
     108signed short __sync_fetch_and_xor_2(volatile signed short *, signed short,...);
    69109unsigned short __sync_fetch_and_xor(volatile unsigned short *, unsigned short,...);
     110unsigned short __sync_fetch_and_xor_2(volatile unsigned short *, unsigned short,...);
    70111signed int __sync_fetch_and_xor(volatile signed int *, signed int,...);
     112signed int __sync_fetch_and_xor_4(volatile signed int *, signed int,...);
    71113unsigned int __sync_fetch_and_xor(volatile unsigned int *, unsigned int,...);
    72 signed long int __sync_fetch_and_xor(volatile signed long int *, signed long int,...);
    73 unsigned long int __sync_fetch_and_xor(volatile unsigned long int *, unsigned long int,...);
     114unsigned int __sync_fetch_and_xor_4(volatile unsigned int *, unsigned int,...);
    74115signed long long int __sync_fetch_and_xor(volatile signed long long int *, signed long long int,...);
     116signed long long int __sync_fetch_and_xor_8(volatile signed long long int *, signed long long int,...);
    75117unsigned long long int __sync_fetch_and_xor(volatile unsigned long long int *, unsigned long long int,...);
     118unsigned long long int __sync_fetch_and_xor_8(volatile unsigned long long int *, unsigned long long int,...);
    76119#if defined(__SIZEOF_INT128__)
    77120signed __int128 __sync_fetch_and_xor(volatile signed __int128 *, signed __int128,...);
     121signed __int128 __sync_fetch_and_xor_16(volatile signed __int128 *, signed __int128,...);
    78122unsigned __int128 __sync_fetch_and_xor(volatile unsigned __int128 *, unsigned __int128,...);
     123unsigned __int128 __sync_fetch_and_xor_16(volatile unsigned __int128 *, unsigned __int128,...);
    79124#endif
    80125
    81126char __sync_fetch_and_nand(volatile char *, char,...);
     127char __sync_fetch_and_nand_1(volatile char *, char,...);
    82128signed char __sync_fetch_and_nand(volatile signed char *, signed char,...);
     129signed char __sync_fetch_and_nand_1(volatile signed char *, signed char,...);
    83130unsigned char __sync_fetch_and_nand(volatile unsigned char *, unsigned char,...);
     131unsigned char __sync_fetch_and_nand_1(volatile unsigned char *, unsigned char,...);
    84132signed short __sync_fetch_and_nand(volatile signed short *, signed short,...);
     133signed short __sync_fetch_and_nand_2(volatile signed short *, signed short,...);
    85134unsigned short __sync_fetch_and_nand(volatile unsigned short *, unsigned short,...);
     135unsigned short __sync_fetch_and_nand_2(volatile unsigned short *, unsigned short,...);
    86136signed int __sync_fetch_and_nand(volatile signed int *, signed int,...);
     137signed int __sync_fetch_and_nand_4(volatile signed int *, signed int,...);
    87138unsigned int __sync_fetch_and_nand(volatile unsigned int *, unsigned int,...);
    88 signed long int __sync_fetch_and_nand(volatile signed long int *, signed long int,...);
    89 unsigned long int __sync_fetch_and_nand(volatile unsigned long int *, unsigned long int,...);
     139unsigned int __sync_fetch_and_nand_4(volatile unsigned int *, unsigned int,...);
    90140signed long long int __sync_fetch_and_nand(volatile signed long long int *, signed long long int,...);
     141signed long long int __sync_fetch_and_nand_8(volatile signed long long int *, signed long long int,...);
    91142unsigned long long int __sync_fetch_and_nand(volatile unsigned long long int *, unsigned long long int,...);
     143unsigned long long int __sync_fetch_and_nand_8(volatile unsigned long long int *, unsigned long long int,...);
    92144#if defined(__SIZEOF_INT128__)
    93145signed __int128 __sync_fetch_and_nand(volatile signed __int128 *, signed __int128,...);
     146signed __int128 __sync_fetch_and_nand_16(volatile signed __int128 *, signed __int128,...);
    94147unsigned __int128 __sync_fetch_and_nand(volatile unsigned __int128 *, unsigned __int128,...);
     148unsigned __int128 __sync_fetch_and_nand_16(volatile unsigned __int128 *, unsigned __int128,...);
    95149#endif
    96150
    97151char __sync_add_and_fetch(volatile char *, char,...);
     152char __sync_add_and_fetch_1(volatile char *, char,...);
    98153signed char __sync_add_and_fetch(volatile signed char *, signed char,...);
     154signed char __sync_add_and_fetch_1(volatile signed char *, signed char,...);
    99155unsigned char __sync_add_and_fetch(volatile unsigned char *, unsigned char,...);
     156unsigned char __sync_add_and_fetch_1(volatile unsigned char *, unsigned char,...);
    100157signed short __sync_add_and_fetch(volatile signed short *, signed short,...);
     158signed short __sync_add_and_fetch_2(volatile signed short *, signed short,...);
    101159unsigned short __sync_add_and_fetch(volatile unsigned short *, unsigned short,...);
     160unsigned short __sync_add_and_fetch_2(volatile unsigned short *, unsigned short,...);
    102161signed int __sync_add_and_fetch(volatile signed int *, signed int,...);
     162signed int __sync_add_and_fetch_4(volatile signed int *, signed int,...);
    103163signed int __sync_add_and_fetch(volatile signed int *, signed int,...);
    104 signed long int __sync_add_and_fetch(volatile signed long int *, signed long int,...);
    105 unsigned long int __sync_add_and_fetch(volatile unsigned long int *, unsigned long int,...);
     164signed int __sync_add_and_fetch_4(volatile signed int *, signed int,...);
    106165signed long long int __sync_add_and_fetch(volatile signed long long int *, signed long long int,...);
     166signed long long int __sync_add_and_fetch_8(volatile signed long long int *, signed long long int,...);
    107167unsigned long long int __sync_add_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
     168unsigned long long int __sync_add_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    108169#if defined(__SIZEOF_INT128__)
    109170signed __int128 __sync_add_and_fetch(volatile signed __int128 *, signed __int128,...);
     171signed __int128 __sync_add_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    110172unsigned __int128 __sync_add_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
     173unsigned __int128 __sync_add_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    111174#endif
    112175
    113176char __sync_sub_and_fetch(volatile char *, char,...);
     177char __sync_sub_and_fetch_1(volatile char *, char,...);
    114178signed char __sync_sub_and_fetch(volatile signed char *, signed char,...);
     179signed char __sync_sub_and_fetch_1(volatile signed char *, signed char,...);
    115180unsigned char __sync_sub_and_fetch(volatile unsigned char *, unsigned char,...);
     181unsigned char __sync_sub_and_fetch_1(volatile unsigned char *, unsigned char,...);
    116182signed short __sync_sub_and_fetch(volatile signed short *, signed short,...);
     183signed short __sync_sub_and_fetch_2(volatile signed short *, signed short,...);
    117184unsigned short __sync_sub_and_fetch(volatile unsigned short *, unsigned short,...);
     185unsigned short __sync_sub_and_fetch_2(volatile unsigned short *, unsigned short,...);
    118186signed int __sync_sub_and_fetch(volatile signed int *, signed int,...);
     187signed int __sync_sub_and_fetch_4(volatile signed int *, signed int,...);
    119188unsigned int __sync_sub_and_fetch(volatile unsigned int *, unsigned int,...);
    120 signed long int __sync_sub_and_fetch(volatile signed long int *, signed long int,...);
    121 unsigned long int __sync_sub_and_fetch(volatile unsigned long int *, unsigned long int,...);
     189unsigned int __sync_sub_and_fetch_4(volatile unsigned int *, unsigned int,...);
    122190signed long long int __sync_sub_and_fetch(volatile signed long long int *, signed long long int,...);
     191signed long long int __sync_sub_and_fetch_8(volatile signed long long int *, signed long long int,...);
    123192unsigned long long int __sync_sub_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
     193unsigned long long int __sync_sub_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    124194#if defined(__SIZEOF_INT128__)
    125195signed __int128 __sync_sub_and_fetch(volatile signed __int128 *, signed __int128,...);
     196signed __int128 __sync_sub_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    126197unsigned __int128 __sync_sub_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
     198unsigned __int128 __sync_sub_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    127199#endif
    128200
    129201char __sync_or_and_fetch(volatile char *, char,...);
     202char __sync_or_and_fetch_1(volatile char *, char,...);
    130203signed char __sync_or_and_fetch(volatile signed char *, signed char,...);
     204signed char __sync_or_and_fetch_1(volatile signed char *, signed char,...);
    131205unsigned char __sync_or_and_fetch(volatile unsigned char *, unsigned char,...);
     206unsigned char __sync_or_and_fetch_1(volatile unsigned char *, unsigned char,...);
    132207signed short __sync_or_and_fetch(volatile signed short *, signed short,...);
     208signed short __sync_or_and_fetch_2(volatile signed short *, signed short,...);
    133209unsigned short __sync_or_and_fetch(volatile unsigned short *, unsigned short,...);
     210unsigned short __sync_or_and_fetch_2(volatile unsigned short *, unsigned short,...);
    134211signed int __sync_or_and_fetch(volatile signed int *, signed int,...);
     212signed int __sync_or_and_fetch_4(volatile signed int *, signed int,...);
    135213unsigned int __sync_or_and_fetch(volatile unsigned int *, unsigned int,...);
    136 signed long int __sync_or_and_fetch(volatile signed long int *, signed long int,...);
    137 unsigned long int __sync_or_and_fetch(volatile unsigned long int *, unsigned long int,...);
     214unsigned int __sync_or_and_fetch_4(volatile unsigned int *, unsigned int,...);
    138215signed long long int __sync_or_and_fetch(volatile signed long long int *, signed long long int,...);
     216signed long long int __sync_or_and_fetch_8(volatile signed long long int *, signed long long int,...);
    139217unsigned long long int __sync_or_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
     218unsigned long long int __sync_or_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    140219#if defined(__SIZEOF_INT128__)
    141220signed __int128 __sync_or_and_fetch(volatile signed __int128 *, signed __int128,...);
     221signed __int128 __sync_or_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    142222unsigned __int128 __sync_or_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
     223unsigned __int128 __sync_or_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    143224#endif
    144225
    145226char __sync_and_and_fetch(volatile char *, char,...);
     227char __sync_and_and_fetch_1(volatile char *, char,...);
    146228signed char __sync_and_and_fetch(volatile signed char *, signed char,...);
     229signed char __sync_and_and_fetch_1(volatile signed char *, signed char,...);
    147230unsigned char __sync_and_and_fetch(volatile unsigned char *, unsigned char,...);
     231unsigned char __sync_and_and_fetch_1(volatile unsigned char *, unsigned char,...);
    148232signed short __sync_and_and_fetch(volatile signed short *, signed short,...);
     233signed short __sync_and_and_fetch_2(volatile signed short *, signed short,...);
    149234unsigned short __sync_and_and_fetch(volatile unsigned short *, unsigned short,...);
     235unsigned short __sync_and_and_fetch_2(volatile unsigned short *, unsigned short,...);
    150236signed int __sync_and_and_fetch(volatile signed int *, signed int,...);
     237signed int __sync_and_and_fetch_4(volatile signed int *, signed int,...);
    151238unsigned int __sync_and_and_fetch(volatile unsigned int *, unsigned int,...);
    152 signed long int __sync_and_and_fetch(volatile signed long int *, signed long int,...);
    153 unsigned long int __sync_and_and_fetch(volatile unsigned long int *, unsigned long int,...);
     239unsigned int __sync_and_and_fetch_4(volatile unsigned int *, unsigned int,...);
    154240signed long long int __sync_and_and_fetch(volatile signed long long int *, signed long long int,...);
     241signed long long int __sync_and_and_fetch_8(volatile signed long long int *, signed long long int,...);
    155242unsigned long long int __sync_and_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
     243unsigned long long int __sync_and_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    156244#if defined(__SIZEOF_INT128__)
    157245signed __int128 __sync_and_and_fetch(volatile signed __int128 *, signed __int128,...);
     246signed __int128 __sync_and_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    158247unsigned __int128 __sync_and_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
     248unsigned __int128 __sync_and_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    159249#endif
    160250
    161251char __sync_xor_and_fetch(volatile char *, char,...);
     252char __sync_xor_and_fetch_1(volatile char *, char,...);
    162253signed char __sync_xor_and_fetch(volatile signed char *, signed char,...);
     254signed char __sync_xor_and_fetch_1(volatile signed char *, signed char,...);
    163255unsigned char __sync_xor_and_fetch(volatile unsigned char *, unsigned char,...);
     256unsigned char __sync_xor_and_fetch_1(volatile unsigned char *, unsigned char,...);
    164257signed short __sync_xor_and_fetch(volatile signed short *, signed short,...);
     258signed short __sync_xor_and_fetch_2(volatile signed short *, signed short,...);
    165259unsigned short __sync_xor_and_fetch(volatile unsigned short *, unsigned short,...);
     260unsigned short __sync_xor_and_fetch_2(volatile unsigned short *, unsigned short,...);
    166261signed int __sync_xor_and_fetch(volatile signed int *, signed int,...);
     262signed int __sync_xor_and_fetch_4(volatile signed int *, signed int,...);
    167263unsigned int __sync_xor_and_fetch(volatile unsigned int *, unsigned int,...);
    168 signed long int __sync_xor_and_fetch(volatile signed long int *, signed long int,...);
    169 unsigned long int __sync_xor_and_fetch(volatile unsigned long int *, unsigned long int,...);
     264unsigned int __sync_xor_and_fetch_4(volatile unsigned int *, unsigned int,...);
    170265signed long long int __sync_xor_and_fetch(volatile signed long long int *, signed long long int,...);
     266signed long long int __sync_xor_and_fetch_8(volatile signed long long int *, signed long long int,...);
    171267unsigned long long int __sync_xor_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
     268unsigned long long int __sync_xor_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    172269#if defined(__SIZEOF_INT128__)
    173270signed __int128 __sync_xor_and_fetch(volatile signed __int128 *, signed __int128,...);
     271signed __int128 __sync_xor_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    174272unsigned __int128 __sync_xor_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
     273unsigned __int128 __sync_xor_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    175274#endif
    176275
    177276char __sync_nand_and_fetch(volatile char *, char,...);
     277char __sync_nand_and_fetch_1(volatile char *, char,...);
    178278signed char __sync_nand_and_fetch(volatile signed char *, signed char,...);
     279signed char __sync_nand_and_fetch_1(volatile signed char *, signed char,...);
    179280unsigned char __sync_nand_and_fetch(volatile unsigned char *, unsigned char,...);
     281unsigned char __sync_nand_and_fetch_1(volatile unsigned char *, unsigned char,...);
    180282signed short __sync_nand_and_fetch(volatile signed short *, signed short,...);
     283signed short __sync_nand_and_fetch_2(volatile signed short *, signed short,...);
    181284unsigned short __sync_nand_and_fetch(volatile unsigned short *, unsigned short,...);
     285unsigned short __sync_nand_and_fetch_2(volatile unsigned short *, unsigned short,...);
    182286signed int __sync_nand_and_fetch(volatile signed int *, signed int,...);
     287signed int __sync_nand_and_fetch_4(volatile signed int *, signed int,...);
    183288unsigned int __sync_nand_and_fetch(volatile unsigned int *, unsigned int,...);
    184 signed long int __sync_nand_and_fetch(volatile signed long int *, signed long int,...);
    185 unsigned long int __sync_nand_and_fetch(volatile unsigned long int *, unsigned long int,...);
     289unsigned int __sync_nand_and_fetch_4(volatile unsigned int *, unsigned int,...);
    186290signed long long int __sync_nand_and_fetch(volatile signed long long int *, signed long long int,...);
     291signed long long int __sync_nand_and_fetch_8(volatile signed long long int *, signed long long int,...);
    187292unsigned long long int __sync_nand_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
     293unsigned long long int __sync_nand_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    188294#if defined(__SIZEOF_INT128__)
    189295signed __int128 __sync_nand_and_fetch(volatile signed __int128 *, signed __int128,...);
     296signed __int128 __sync_nand_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    190297unsigned __int128 __sync_nand_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
     298unsigned __int128 __sync_nand_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    191299#endif
    192300
    193301_Bool __sync_bool_compare_and_swap(volatile char *, char, char,...);
     302_Bool __sync_bool_compare_and_swap_1(volatile char *, char, char,...);
    194303_Bool __sync_bool_compare_and_swap(volatile signed char *, signed char, signed char,...);
     304_Bool __sync_bool_compare_and_swap_1(volatile signed char *, signed char, signed char,...);
    195305_Bool __sync_bool_compare_and_swap(volatile unsigned char *, unsigned char, unsigned char,...);
     306_Bool __sync_bool_compare_and_swap_1(volatile unsigned char *, unsigned char, unsigned char,...);
    196307_Bool __sync_bool_compare_and_swap(volatile short *, signed short, signed short,...);
     308_Bool __sync_bool_compare_and_swap_2(volatile short *, signed short, signed short,...);
    197309_Bool __sync_bool_compare_and_swap(volatile short *, unsigned short, unsigned short,...);
     310_Bool __sync_bool_compare_and_swap_2(volatile short *, unsigned short, unsigned short,...);
    198311_Bool __sync_bool_compare_and_swap(volatile signed int *, signed int, signed int,...);
     312_Bool __sync_bool_compare_and_swap_4(volatile signed int *, signed int, signed int,...);
    199313_Bool __sync_bool_compare_and_swap(volatile unsigned int *, unsigned int, unsigned int,...);
    200 _Bool __sync_bool_compare_and_swap(volatile signed long int *, signed long int, signed long int,...);
    201 _Bool __sync_bool_compare_and_swap(volatile unsigned long int *, unsigned long int, unsigned long int,...);
     314_Bool __sync_bool_compare_and_swap_4(volatile unsigned int *, unsigned int, unsigned int,...);
    202315_Bool __sync_bool_compare_and_swap(volatile signed long long int *, signed long long int, signed long long int,...);
     316_Bool __sync_bool_compare_and_swap_8(volatile signed long long int *, signed long long int, signed long long int,...);
    203317_Bool __sync_bool_compare_and_swap(volatile unsigned long long int *, unsigned long long int, unsigned long long int,...);
     318_Bool __sync_bool_compare_and_swap_8(volatile unsigned long long int *, unsigned long long int, unsigned long long int,...);
    204319#if defined(__SIZEOF_INT128__)
    205320_Bool __sync_bool_compare_and_swap(volatile signed __int128 *, signed __int128, signed __int128,...);
     321_Bool __sync_bool_compare_and_swap_16(volatile signed __int128 *, signed __int128, signed __int128,...);
    206322_Bool __sync_bool_compare_and_swap(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
     323_Bool __sync_bool_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    207324#endif
    208325forall(dtype T) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...);
    209326
    210327char __sync_val_compare_and_swap(volatile char *, char, char,...);
     328char __sync_val_compare_and_swap_1(volatile char *, char, char,...);
    211329signed char __sync_val_compare_and_swap(volatile signed char *, signed char, signed char,...);
     330signed char __sync_val_compare_and_swap_1(volatile signed char *, signed char, signed char,...);
    212331unsigned char __sync_val_compare_and_swap(volatile unsigned char *, unsigned char, unsigned char,...);
     332unsigned char __sync_val_compare_and_swap_1(volatile unsigned char *, unsigned char, unsigned char,...);
    213333signed short __sync_val_compare_and_swap(volatile signed short *, signed short, signed short,...);
     334signed short __sync_val_compare_and_swap_2(volatile signed short *, signed short, signed short,...);
    214335unsigned short __sync_val_compare_and_swap(volatile unsigned short *, unsigned short, unsigned short,...);
     336unsigned short __sync_val_compare_and_swap_2(volatile unsigned short *, unsigned short, unsigned short,...);
    215337signed int __sync_val_compare_and_swap(volatile signed int *, signed int, signed int,...);
     338signed int __sync_val_compare_and_swap_4(volatile signed int *, signed int, signed int,...);
    216339unsigned int __sync_val_compare_and_swap(volatile unsigned int *, unsigned int, unsigned int,...);
    217 signed long int __sync_val_compare_and_swap(volatile signed long int *, signed long int, signed long int,...);
    218 unsigned long int __sync_val_compare_and_swap(volatile unsigned long int *, unsigned long int, unsigned long int,...);
     340unsigned int __sync_val_compare_and_swap_4(volatile unsigned int *, unsigned int, unsigned int,...);
    219341signed long long int __sync_val_compare_and_swap(volatile signed long long int *, signed long long int, signed long long int,...);
     342signed long long int __sync_val_compare_and_swap_8(volatile signed long long int *, signed long long int, signed long long int,...);
    220343unsigned long long int __sync_val_compare_and_swap(volatile unsigned long long int *, unsigned long long int, unsigned long long int,...);
     344unsigned long long int __sync_val_compare_and_swap_8(volatile unsigned long long int *, unsigned long long int, unsigned long long int,...);
    221345#if defined(__SIZEOF_INT128__)
    222346signed __int128 __sync_val_compare_and_swap(volatile signed __int128 *, signed __int128, signed __int128,...);
     347signed __int128 __sync_val_compare_and_swap_16(volatile signed __int128 *, signed __int128, signed __int128,...);
    223348unsigned __int128 __sync_val_compare_and_swap(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
     349unsigned __int128 __sync_val_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    224350#endif
    225351forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);
    226352
    227353char __sync_lock_test_and_set(volatile char *, char,...);
     354char __sync_lock_test_and_set_1(volatile char *, char,...);
    228355signed char __sync_lock_test_and_set(volatile signed char *, signed char,...);
     356signed char __sync_lock_test_and_set_1(volatile signed char *, signed char,...);
    229357unsigned char __sync_lock_test_and_set(volatile unsigned char *, unsigned char,...);
     358unsigned char __sync_lock_test_and_set_1(volatile unsigned char *, unsigned char,...);
    230359signed short __sync_lock_test_and_set(volatile signed short *, signed short,...);
     360signed short __sync_lock_test_and_set_2(volatile signed short *, signed short,...);
    231361unsigned short __sync_lock_test_and_set(volatile unsigned short *, unsigned short,...);
     362unsigned short __sync_lock_test_and_set_2(volatile unsigned short *, unsigned short,...);
    232363signed int __sync_lock_test_and_set(volatile signed int *, signed int,...);
     364signed int __sync_lock_test_and_set_4(volatile signed int *, signed int,...);
    233365unsigned int __sync_lock_test_and_set(volatile unsigned int *, unsigned int,...);
    234 signed long int __sync_lock_test_and_set(volatile signed long int *, signed long int,...);
    235 unsigned long int __sync_lock_test_and_set(volatile unsigned long int *, unsigned long int,...);
     366unsigned int __sync_lock_test_and_set_4(volatile unsigned int *, unsigned int,...);
    236367signed long long int __sync_lock_test_and_set(volatile signed long long int *, signed long long int,...);
     368signed long long int __sync_lock_test_and_set_8(volatile signed long long int *, signed long long int,...);
    237369unsigned long long int __sync_lock_test_and_set(volatile unsigned long long int *, unsigned long long int,...);
     370unsigned long long int __sync_lock_test_and_set_8(volatile unsigned long long int *, unsigned long long int,...);
    238371#if defined(__SIZEOF_INT128__)
    239372signed __int128 __sync_lock_test_and_set(volatile signed __int128 *, signed __int128,...);
     373signed __int128 __sync_lock_test_and_set_16(volatile signed __int128 *, signed __int128,...);
    240374unsigned __int128 __sync_lock_test_and_set(volatile unsigned __int128 *, unsigned __int128,...);
     375unsigned __int128 __sync_lock_test_and_set_16(volatile unsigned __int128 *, unsigned __int128,...);
    241376#endif
    242377
    243378void __sync_lock_release(volatile char *,...);
     379void __sync_lock_release_1(volatile char *,...);
    244380void __sync_lock_release(volatile signed char *,...);
     381void __sync_lock_release_1(volatile signed char *,...);
    245382void __sync_lock_release(volatile unsigned char *,...);
     383void __sync_lock_release_1(volatile unsigned char *,...);
    246384void __sync_lock_release(volatile signed short *,...);
     385void __sync_lock_release_2(volatile signed short *,...);
    247386void __sync_lock_release(volatile unsigned short *,...);
     387void __sync_lock_release_2(volatile unsigned short *,...);
    248388void __sync_lock_release(volatile signed int *,...);
     389void __sync_lock_release_4(volatile signed int *,...);
    249390void __sync_lock_release(volatile unsigned int *,...);
    250 void __sync_lock_release(volatile signed long int *,...);
    251 void __sync_lock_release(volatile unsigned long int *,...);
     391void __sync_lock_release_4(volatile unsigned int *,...);
    252392void __sync_lock_release(volatile signed long long int *,...);
     393void __sync_lock_release_8(volatile signed long long int *,...);
    253394void __sync_lock_release(volatile unsigned long long int *,...);
     395void __sync_lock_release_8(volatile unsigned long long int *,...);
    254396#if defined(__SIZEOF_INT128__)
    255397void __sync_lock_release(volatile signed __int128 *,...);
     398void __sync_lock_release_16(volatile signed __int128 *,...);
    256399void __sync_lock_release(volatile unsigned __int128 *,...);
     400void __sync_lock_release_16(volatile unsigned __int128 *,...);
    257401#endif
    258402
     
    270414_Bool __atomic_test_and_set(volatile signed int *, int);
    271415_Bool __atomic_test_and_set(volatile unsigned int *, int);
    272 _Bool __atomic_test_and_set(volatile signed long int *, int);
    273 _Bool __atomic_test_and_set(volatile unsigned long int *, int);
    274416_Bool __atomic_test_and_set(volatile signed long long int *, int);
    275417_Bool __atomic_test_and_set(volatile unsigned long long int *, int);
     
    287429void __atomic_clear(volatile signed int *, int);
    288430void __atomic_clear(volatile unsigned int *, int);
    289 void __atomic_clear(volatile signed long int *, int);
    290 void __atomic_clear(volatile unsigned long int *, int);
    291431void __atomic_clear(volatile signed long long int *, int);
    292432void __atomic_clear(volatile unsigned long long int *, int);
     
    296436#endif
    297437
    298 _Bool __atomic_exchange_n(volatile _Bool *, _Bool, int);
    299 void __atomic_exchange(volatile _Bool *, volatile _Bool *, volatile _Bool *, int);
    300438char __atomic_exchange_n(volatile char *, char, int);
     439char __atomic_exchange_1(volatile char *, char, int);
    301440void __atomic_exchange(volatile char *, volatile char *, volatile char *, int);
    302441signed char __atomic_exchange_n(volatile signed char *, signed char, int);
     442signed char __atomic_exchange_1(volatile signed char *, signed char, int);
    303443void __atomic_exchange(volatile signed char *, volatile signed char *, volatile signed char *, int);
    304444unsigned char __atomic_exchange_n(volatile unsigned char *, unsigned char, int);
     445unsigned char __atomic_exchange_1(volatile unsigned char *, unsigned char, int);
    305446void __atomic_exchange(volatile unsigned char *, volatile unsigned char *, volatile unsigned char *, int);
    306447signed short __atomic_exchange_n(volatile signed short *, signed short, int);
     448signed short __atomic_exchange_2(volatile signed short *, signed short, int);
    307449void __atomic_exchange(volatile signed short *, volatile signed short *, volatile signed short *, int);
    308450unsigned short __atomic_exchange_n(volatile unsigned short *, unsigned short, int);
     451unsigned short __atomic_exchange_2(volatile unsigned short *, unsigned short, int);
    309452void __atomic_exchange(volatile unsigned short *, volatile unsigned short *, volatile unsigned short *, int);
    310453signed int __atomic_exchange_n(volatile signed int *, signed int, int);
     454signed int __atomic_exchange_4(volatile signed int *, signed int, int);
    311455void __atomic_exchange(volatile signed int *, volatile signed int *, volatile signed int *, int);
    312456unsigned int __atomic_exchange_n(volatile unsigned int *, unsigned int, int);
     457unsigned int __atomic_exchange_4(volatile unsigned int *, unsigned int, int);
    313458void __atomic_exchange(volatile unsigned int *, volatile unsigned int *, volatile unsigned int *, int);
    314 signed long int __atomic_exchange_n(volatile signed long int *, signed long int, int);
    315 void __atomic_exchange(volatile signed long int *, volatile signed long int *, volatile signed long int *, int);
    316 unsigned long int __atomic_exchange_n(volatile unsigned long int *, unsigned long int, int);
    317 void __atomic_exchange(volatile unsigned long int *, volatile unsigned long int *, volatile unsigned long int *, int);
    318459signed long long int __atomic_exchange_n(volatile signed long long int *, signed long long int, int);
     460signed long long int __atomic_exchange_8(volatile signed long long int *, signed long long int, int);
    319461void __atomic_exchange(volatile signed long long int *, volatile signed long long int *, volatile signed long long int *, int);
    320462unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, unsigned long long int, int);
     463unsigned long long int __atomic_exchange_8(volatile unsigned long long int *, unsigned long long int, int);
    321464void __atomic_exchange(volatile unsigned long long int *, volatile unsigned long long int *, volatile unsigned long long int *, int);
    322465#if defined(__SIZEOF_INT128__)
    323466signed __int128 __atomic_exchange_n(volatile signed __int128 *, signed __int128, int);
     467signed __int128 __atomic_exchange_16(volatile signed __int128 *, signed __int128, int);
    324468void __atomic_exchange(volatile signed __int128 *, volatile signed __int128 *, volatile signed __int128 *, int);
    325469unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, unsigned __int128, int);
     470unsigned __int128 __atomic_exchange_16(volatile unsigned __int128 *, unsigned __int128, int);
    326471void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    327472#endif
     
    332477void __atomic_load(const volatile _Bool *, volatile _Bool *, int);
    333478char __atomic_load_n(const volatile char *, int);
     479char __atomic_load_1(const volatile char *, int);
    334480void __atomic_load(const volatile char *, volatile char *, int);
    335481signed char __atomic_load_n(const volatile signed char *, int);
     482signed char __atomic_load_1(const volatile signed char *, int);
    336483void __atomic_load(const volatile signed char *, volatile signed char *, int);
    337484unsigned char __atomic_load_n(const volatile unsigned char *, int);
     485unsigned char __atomic_load_1(const volatile unsigned char *, int);
    338486void __atomic_load(const volatile unsigned char *, volatile unsigned char *, int);
    339487signed short __atomic_load_n(const volatile signed short *, int);
     488signed short __atomic_load_2(const volatile signed short *, int);
    340489void __atomic_load(const volatile signed short *, volatile signed short *, int);
    341490unsigned short __atomic_load_n(const volatile unsigned short *, int);
     491unsigned short __atomic_load_2(const volatile unsigned short *, int);
    342492void __atomic_load(const volatile unsigned short *, volatile unsigned short *, int);
    343493signed int __atomic_load_n(const volatile signed int *, int);
     494signed int __atomic_load_4(const volatile signed int *, int);
    344495void __atomic_load(const volatile signed int *, volatile signed int *, int);
    345496unsigned int __atomic_load_n(const volatile unsigned int *, int);
     497unsigned int __atomic_load_4(const volatile unsigned int *, int);
    346498void __atomic_load(const volatile unsigned int *, volatile unsigned int *, int);
    347 signed long int __atomic_load_n(const volatile signed long int *, int);
    348 void __atomic_load(const volatile signed long int *, volatile signed long int *, int);
    349 unsigned long int __atomic_load_n(const volatile unsigned long int *, int);
    350 void __atomic_load(const volatile unsigned long int *, volatile unsigned long int *, int);
    351499signed long long int __atomic_load_n(const volatile signed long long int *, int);
     500signed long long int __atomic_load_8(const volatile signed long long int *, int);
    352501void __atomic_load(const volatile signed long long int *, volatile signed long long int *, int);
    353502unsigned long long int __atomic_load_n(const volatile unsigned long long int *, int);
     503unsigned long long int __atomic_load_8(const volatile unsigned long long int *, int);
    354504void __atomic_load(const volatile unsigned long long int *, volatile unsigned long long int *, int);
    355505#if defined(__SIZEOF_INT128__)
    356506signed __int128 __atomic_load_n(const volatile signed __int128 *, int);
     507signed __int128 __atomic_load_16(const volatile signed __int128 *, int);
    357508void __atomic_load(const volatile signed __int128 *, volatile signed __int128 *, int);
    358509unsigned __int128 __atomic_load_n(const volatile unsigned __int128 *, int);
     510unsigned __int128 __atomic_load_16(const volatile unsigned __int128 *, int);
    359511void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    360512#endif
     
    363515
    364516_Bool __atomic_compare_exchange_n(volatile char *, char *, char, _Bool, int, int);
     517_Bool __atomic_compare_exchange_1(volatile char *, char *, char, _Bool, int, int);
    365518_Bool __atomic_compare_exchange  (volatile char *, char *, char *, _Bool, int, int);
    366519_Bool __atomic_compare_exchange_n(volatile signed char *, signed char *, signed char, _Bool, int, int);
     520_Bool __atomic_compare_exchange_1(volatile signed char *, signed char *, signed char, _Bool, int, int);
    367521_Bool __atomic_compare_exchange  (volatile signed char *, signed char *, signed char *, _Bool, int, int);
    368522_Bool __atomic_compare_exchange_n(volatile unsigned char *, unsigned char *, unsigned char, _Bool, int, int);
     523_Bool __atomic_compare_exchange_1(volatile unsigned char *, unsigned char *, unsigned char, _Bool, int, int);
    369524_Bool __atomic_compare_exchange  (volatile unsigned char *, unsigned char *, unsigned char *, _Bool, int, int);
    370525_Bool __atomic_compare_exchange_n(volatile signed short *, signed short *, signed short, _Bool, int, int);
     526_Bool __atomic_compare_exchange_2(volatile signed short *, signed short *, signed short, _Bool, int, int);
    371527_Bool __atomic_compare_exchange  (volatile signed short *, signed short *, signed short *, _Bool, int, int);
    372528_Bool __atomic_compare_exchange_n(volatile unsigned short *, unsigned short *, unsigned short, _Bool, int, int);
     529_Bool __atomic_compare_exchange_2(volatile unsigned short *, unsigned short *, unsigned short, _Bool, int, int);
    373530_Bool __atomic_compare_exchange  (volatile unsigned short *, unsigned short *, unsigned short *, _Bool, int, int);
    374531_Bool __atomic_compare_exchange_n(volatile signed int *, signed int *, signed int, _Bool, int, int);
     532_Bool __atomic_compare_exchange_4(volatile signed int *, signed int *, signed int, _Bool, int, int);
    375533_Bool __atomic_compare_exchange  (volatile signed int *, signed int *, signed int *, _Bool, int, int);
    376534_Bool __atomic_compare_exchange_n(volatile unsigned int *, unsigned int *, unsigned int, _Bool, int, int);
     535_Bool __atomic_compare_exchange_4(volatile unsigned int *, unsigned int *, unsigned int, _Bool, int, int);
    377536_Bool __atomic_compare_exchange  (volatile unsigned int *, unsigned int *, unsigned int *, _Bool, int, int);
    378 _Bool __atomic_compare_exchange_n(volatile signed long int *, signed long int *, signed long int, _Bool, int, int);
    379 _Bool __atomic_compare_exchange  (volatile signed long int *, signed long int *, signed long int *, _Bool, int, int);
    380 _Bool __atomic_compare_exchange_n(volatile unsigned long int *, unsigned long int *, unsigned long int, _Bool, int, int);
    381 _Bool __atomic_compare_exchange  (volatile unsigned long int *, unsigned long int *, unsigned long int *, _Bool, int, int);
    382537_Bool __atomic_compare_exchange_n(volatile signed long long int *, signed long long int *, signed long long int, _Bool, int, int);
     538_Bool __atomic_compare_exchange_8(volatile signed long long int *, signed long long int *, signed long long int, _Bool, int, int);
    383539_Bool __atomic_compare_exchange  (volatile signed long long int *, signed long long int *, signed long long int *, _Bool, int, int);
    384540_Bool __atomic_compare_exchange_n(volatile unsigned long long int *, unsigned long long int *, unsigned long long int, _Bool, int, int);
     541_Bool __atomic_compare_exchange_8(volatile unsigned long long int *, unsigned long long int *, unsigned long long int, _Bool, int, int);
    385542_Bool __atomic_compare_exchange  (volatile unsigned long long int *, unsigned long long int *, unsigned long long int *, _Bool, int, int);
    386543#if defined(__SIZEOF_INT128__)
    387544_Bool __atomic_compare_exchange_n (volatile signed __int128 *, signed __int128 *, signed __int128, _Bool, int, int);
     545_Bool __atomic_compare_exchange_16(volatile signed __int128 *, signed __int128 *, signed __int128, _Bool, int, int);
    388546_Bool __atomic_compare_exchange   (volatile signed __int128 *, signed __int128 *, signed __int128 *, _Bool, int, int);
    389547_Bool __atomic_compare_exchange_n (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128, _Bool, int, int);
     548_Bool __atomic_compare_exchange_16(volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128, _Bool, int, int);
    390549_Bool __atomic_compare_exchange   (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int);
    391550#endif
     
    396555void __atomic_store(volatile _Bool *, _Bool *, int);
    397556void __atomic_store_n(volatile char *, char, int);
     557void __atomic_store_1(volatile char *, char, int);
    398558void __atomic_store(volatile char *, char *, int);
    399559void __atomic_store_n(volatile signed char *, signed char, int);
     560void __atomic_store_1(volatile signed char *, signed char, int);
    400561void __atomic_store(volatile signed char *, signed char *, int);
    401562void __atomic_store_n(volatile unsigned char *, unsigned char, int);
     563void __atomic_store_1(volatile unsigned char *, unsigned char, int);
    402564void __atomic_store(volatile unsigned char *, unsigned char *, int);
    403565void __atomic_store_n(volatile signed short *, signed short, int);
     566void __atomic_store_2(volatile signed short *, signed short, int);
    404567void __atomic_store(volatile signed short *, signed short *, int);
    405568void __atomic_store_n(volatile unsigned short *, unsigned short, int);
     569void __atomic_store_2(volatile unsigned short *, unsigned short, int);
    406570void __atomic_store(volatile unsigned short *, unsigned short *, int);
    407571void __atomic_store_n(volatile signed int *, signed int, int);
     572void __atomic_store_4(volatile signed int *, signed int, int);
    408573void __atomic_store(volatile signed int *, signed int *, int);
    409574void __atomic_store_n(volatile unsigned int *, unsigned int, int);
     575void __atomic_store_4(volatile unsigned int *, unsigned int, int);
    410576void __atomic_store(volatile unsigned int *, unsigned int *, int);
    411 void __atomic_store_n(volatile signed long int *, signed long int, int);
    412 void __atomic_store(volatile signed long int *, signed long int *, int);
    413 void __atomic_store_n(volatile unsigned long int *, unsigned long int, int);
    414 void __atomic_store(volatile unsigned long int *, unsigned long int *, int);
    415577void __atomic_store_n(volatile signed long long int *, signed long long int, int);
     578void __atomic_store_8(volatile signed long long int *, signed long long int, int);
    416579void __atomic_store(volatile signed long long int *, signed long long int *, int);
    417580void __atomic_store_n(volatile unsigned long long int *, unsigned long long int, int);
     581void __atomic_store_8(volatile unsigned long long int *, unsigned long long int, int);
    418582void __atomic_store(volatile unsigned long long int *, unsigned long long int *, int);
    419583#if defined(__SIZEOF_INT128__)
    420584void __atomic_store_n(volatile signed __int128 *, signed __int128, int);
     585void __atomic_store_16(volatile signed __int128 *, signed __int128, int);
    421586void __atomic_store(volatile signed __int128 *, signed __int128 *, int);
    422587void __atomic_store_n(volatile unsigned __int128 *, unsigned __int128, int);
     588void __atomic_store_16(volatile unsigned __int128 *, unsigned __int128, int);
    423589void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int);
    424590#endif
     
    427593
    428594char __atomic_add_fetch  (volatile char *, char, int);
     595char __atomic_add_fetch_1(volatile char *, char, int);
    429596signed char __atomic_add_fetch  (volatile signed char *, signed char, int);
     597signed char __atomic_add_fetch_1(volatile signed char *, signed char, int);
    430598unsigned char __atomic_add_fetch  (volatile unsigned char *, unsigned char, int);
     599unsigned char __atomic_add_fetch_1(volatile unsigned char *, unsigned char, int);
    431600signed short __atomic_add_fetch  (volatile signed short *, signed short, int);
     601signed short __atomic_add_fetch_2(volatile signed short *, signed short, int);
    432602unsigned short __atomic_add_fetch  (volatile unsigned short *, unsigned short, int);
     603unsigned short __atomic_add_fetch_2(volatile unsigned short *, unsigned short, int);
    433604signed int __atomic_add_fetch  (volatile signed int *, signed int, int);
     605signed int __atomic_add_fetch_4(volatile signed int *, signed int, int);
    434606unsigned int __atomic_add_fetch  (volatile unsigned int *, unsigned int, int);
    435 signed long int __atomic_add_fetch  (volatile signed long int *, signed long int, int);
    436 unsigned long int __atomic_add_fetch  (volatile unsigned long int *, unsigned long int, int);
     607unsigned int __atomic_add_fetch_4(volatile unsigned int *, unsigned int, int);
    437608signed long long int __atomic_add_fetch  (volatile signed long long int *, signed long long int, int);
     609signed long long int __atomic_add_fetch_8(volatile signed long long int *, signed long long int, int);
    438610unsigned long long int __atomic_add_fetch  (volatile unsigned long long int *, unsigned long long int, int);
     611unsigned long long int __atomic_add_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    439612#if defined(__SIZEOF_INT128__)
    440613signed __int128 __atomic_add_fetch   (volatile signed __int128 *, signed __int128, int);
     614signed __int128 __atomic_add_fetch_16(volatile signed __int128 *, signed __int128, int);
    441615unsigned __int128 __atomic_add_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
     616unsigned __int128 __atomic_add_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    442617#endif
    443618
    444619char __atomic_sub_fetch  (volatile char *, char, int);
     620char __atomic_sub_fetch_1(volatile char *, char, int);
    445621signed char __atomic_sub_fetch  (volatile signed char *, signed char, int);
     622signed char __atomic_sub_fetch_1(volatile signed char *, signed char, int);
    446623unsigned char __atomic_sub_fetch  (volatile unsigned char *, unsigned char, int);
     624unsigned char __atomic_sub_fetch_1(volatile unsigned char *, unsigned char, int);
    447625signed short __atomic_sub_fetch  (volatile signed short *, signed short, int);
     626signed short __atomic_sub_fetch_2(volatile signed short *, signed short, int);
    448627unsigned short __atomic_sub_fetch  (volatile unsigned short *, unsigned short, int);
     628unsigned short __atomic_sub_fetch_2(volatile unsigned short *, unsigned short, int);
    449629signed int __atomic_sub_fetch  (volatile signed int *, signed int, int);
     630signed int __atomic_sub_fetch_4(volatile signed int *, signed int, int);
    450631unsigned int __atomic_sub_fetch  (volatile unsigned int *, unsigned int, int);
    451 signed long long int __atomic_sub_fetch  (volatile signed long int *, signed long int, int);
    452 unsigned long long int __atomic_sub_fetch  (volatile unsigned long int *, unsigned long int, int);
     632unsigned int __atomic_sub_fetch_4(volatile unsigned int *, unsigned int, int);
    453633signed long long int __atomic_sub_fetch  (volatile signed long long int *, signed long long int, int);
     634signed long long int __atomic_sub_fetch_8(volatile signed long long int *, signed long long int, int);
    454635unsigned long long int __atomic_sub_fetch  (volatile unsigned long long int *, unsigned long long int, int);
     636unsigned long long int __atomic_sub_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    455637#if defined(__SIZEOF_INT128__)
    456638signed __int128 __atomic_sub_fetch   (volatile signed __int128 *, signed __int128, int);
     639signed __int128 __atomic_sub_fetch_16(volatile signed __int128 *, signed __int128, int);
    457640unsigned __int128 __atomic_sub_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
     641unsigned __int128 __atomic_sub_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    458642#endif
    459643
    460644char __atomic_and_fetch  (volatile char *, char, int);
     645char __atomic_and_fetch_1(volatile char *, char, int);
    461646signed char __atomic_and_fetch  (volatile signed char *, signed char, int);
     647signed char __atomic_and_fetch_1(volatile signed char *, signed char, int);
    462648unsigned char __atomic_and_fetch  (volatile unsigned char *, unsigned char, int);
     649unsigned char __atomic_and_fetch_1(volatile unsigned char *, unsigned char, int);
    463650signed short __atomic_and_fetch  (volatile signed short *, signed short, int);
     651signed short __atomic_and_fetch_2(volatile signed short *, signed short, int);
    464652unsigned short __atomic_and_fetch  (volatile unsigned short *, unsigned short, int);
     653unsigned short __atomic_and_fetch_2(volatile unsigned short *, unsigned short, int);
    465654signed int __atomic_and_fetch  (volatile signed int *, signed int, int);
     655signed int __atomic_and_fetch_4(volatile signed int *, signed int, int);
    466656unsigned int __atomic_and_fetch  (volatile unsigned int *, unsigned int, int);
    467 signed long int __atomic_and_fetch  (volatile signed long int *, signed long int, int);
    468 unsigned long int __atomic_and_fetch  (volatile unsigned long int *, unsigned long int, int);
     657unsigned int __atomic_and_fetch_4(volatile unsigned int *, unsigned int, int);
    469658signed long long int __atomic_and_fetch  (volatile signed long long int *, signed long long int, int);
     659signed long long int __atomic_and_fetch_8(volatile signed long long int *, signed long long int, int);
    470660unsigned long long int __atomic_and_fetch  (volatile unsigned long long int *, unsigned long long int, int);
     661unsigned long long int __atomic_and_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    471662#if defined(__SIZEOF_INT128__)
    472663signed __int128 __atomic_and_fetch   (volatile signed __int128 *, signed __int128, int);
     664signed __int128 __atomic_and_fetch_16(volatile signed __int128 *, signed __int128, int);
    473665unsigned __int128 __atomic_and_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
     666unsigned __int128 __atomic_and_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    474667#endif
    475668
    476669char __atomic_nand_fetch  (volatile char *, char, int);
     670char __atomic_nand_fetch_1(volatile char *, char, int);
    477671signed char __atomic_nand_fetch  (volatile signed char *, signed char, int);
     672signed char __atomic_nand_fetch_1(volatile signed char *, signed char, int);
    478673unsigned char __atomic_nand_fetch  (volatile unsigned char *, unsigned char, int);
     674unsigned char __atomic_nand_fetch_1(volatile unsigned char *, unsigned char, int);
    479675signed short __atomic_nand_fetch  (volatile signed short *, signed short, int);
     676signed short __atomic_nand_fetch_2(volatile signed short *, signed short, int);
    480677unsigned short __atomic_nand_fetch  (volatile unsigned short *, unsigned short, int);
     678unsigned short __atomic_nand_fetch_2(volatile unsigned short *, unsigned short, int);
    481679signed int __atomic_nand_fetch  (volatile signed int *, signed int, int);
     680signed int __atomic_nand_fetch_4(volatile signed int *, signed int, int);
    482681unsigned int __atomic_nand_fetch  (volatile unsigned int *, unsigned int, int);
    483 signed long int __atomic_nand_fetch  (volatile signed long int *, signed long int, int);
    484 unsigned long int __atomic_nand_fetch  (volatile unsigned long int *, unsigned long int, int);
     682unsigned int __atomic_nand_fetch_4(volatile unsigned int *, unsigned int, int);
    485683signed long long int __atomic_nand_fetch  (volatile signed long long int *, signed long long int, int);
     684signed long long int __atomic_nand_fetch_8(volatile signed long long int *, signed long long int, int);
    486685unsigned long long int __atomic_nand_fetch  (volatile unsigned long long int *, unsigned long long int, int);
     686unsigned long long int __atomic_nand_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    487687#if defined(__SIZEOF_INT128__)
    488688signed __int128 __atomic_nand_fetch   (volatile signed __int128 *, signed __int128, int);
     689signed __int128 __atomic_nand_fetch_16(volatile signed __int128 *, signed __int128, int);
    489690unsigned __int128 __atomic_nand_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
     691unsigned __int128 __atomic_nand_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    490692#endif
    491693
    492694char __atomic_xor_fetch  (volatile char *, char, int);
     695char __atomic_xor_fetch_1(volatile char *, char, int);
    493696signed char __atomic_xor_fetch  (volatile signed char *, signed char, int);
     697signed char __atomic_xor_fetch_1(volatile signed char *, signed char, int);
    494698unsigned char __atomic_xor_fetch  (volatile unsigned char *, unsigned char, int);
     699unsigned char __atomic_xor_fetch_1(volatile unsigned char *, unsigned char, int);
    495700signed short __atomic_xor_fetch  (volatile signed short *, signed short, int);
     701signed short __atomic_xor_fetch_2(volatile signed short *, signed short, int);
    496702unsigned short __atomic_xor_fetch  (volatile unsigned short *, unsigned short, int);
     703unsigned short __atomic_xor_fetch_2(volatile unsigned short *, unsigned short, int);
    497704signed int __atomic_xor_fetch  (volatile signed int *, signed int, int);
     705signed int __atomic_xor_fetch_4(volatile signed int *, signed int, int);
    498706unsigned int __atomic_xor_fetch  (volatile unsigned int *, unsigned int, int);
    499 signed long int __atomic_xor_fetch  (volatile signed long int *, signed long int, int);
    500 unsigned long int __atomic_xor_fetch  (volatile unsigned long int *, unsigned long int, int);
     707unsigned int __atomic_xor_fetch_4(volatile unsigned int *, unsigned int, int);
    501708signed long long int __atomic_xor_fetch  (volatile signed long long int *, signed long long int, int);
     709signed long long int __atomic_xor_fetch_8(volatile signed long long int *, signed long long int, int);
    502710unsigned long long int __atomic_xor_fetch  (volatile unsigned long long int *, unsigned long long int, int);
     711unsigned long long int __atomic_xor_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    503712#if defined(__SIZEOF_INT128__)
    504713signed __int128 __atomic_xor_fetch   (volatile signed __int128 *, signed __int128, int);
     714signed __int128 __atomic_xor_fetch_16(volatile signed __int128 *, signed __int128, int);
    505715unsigned __int128 __atomic_xor_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
     716unsigned __int128 __atomic_xor_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    506717#endif
    507718
    508719char __atomic_or_fetch  (volatile char *, char, int);
     720char __atomic_or_fetch_1(volatile char *, char, int);
    509721signed char __atomic_or_fetch  (volatile signed char *, signed char, int);
     722signed char __atomic_or_fetch_1(volatile signed char *, signed char, int);
    510723unsigned char __atomic_or_fetch  (volatile unsigned char *, unsigned char, int);
     724unsigned char __atomic_or_fetch_1(volatile unsigned char *, unsigned char, int);
    511725signed short __atomic_or_fetch  (volatile signed short *, signed short, int);
     726signed short __atomic_or_fetch_2(volatile signed short *, signed short, int);
    512727unsigned short __atomic_or_fetch  (volatile unsigned short *, unsigned short, int);
     728unsigned short __atomic_or_fetch_2(volatile unsigned short *, unsigned short, int);
    513729signed int __atomic_or_fetch  (volatile signed int *, signed int, int);
     730signed int __atomic_or_fetch_4(volatile signed int *, signed int, int);
    514731unsigned int __atomic_or_fetch  (volatile unsigned int *, unsigned int, int);
    515 signed long int __atomic_or_fetch  (volatile signed long int *, signed long int, int);
    516 unsigned long int __atomic_or_fetch  (volatile unsigned long int *, unsigned long int, int);
     732unsigned int __atomic_or_fetch_4(volatile unsigned int *, unsigned int, int);
    517733signed long long int __atomic_or_fetch  (volatile signed long long int *, signed long long int, int);
     734signed long long int __atomic_or_fetch_8(volatile signed long long int *, signed long long int, int);
    518735unsigned long long int __atomic_or_fetch  (volatile unsigned long long int *, unsigned long long int, int);
     736unsigned long long int __atomic_or_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    519737#if defined(__SIZEOF_INT128__)
    520738signed __int128 __atomic_or_fetch   (volatile signed __int128 *, signed __int128, int);
     739signed __int128 __atomic_or_fetch_16(volatile signed __int128 *, signed __int128, int);
    521740unsigned __int128 __atomic_or_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
     741unsigned __int128 __atomic_or_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    522742#endif
    523743
    524744char __atomic_fetch_add  (volatile char *, char, int);
     745char __atomic_fetch_add_1(volatile char *, char, int);
    525746signed char __atomic_fetch_add  (volatile signed char *, signed char, int);
     747signed char __atomic_fetch_add_1(volatile signed char *, signed char, int);
    526748unsigned char __atomic_fetch_add  (volatile unsigned char *, unsigned char, int);
     749unsigned char __atomic_fetch_add_1(volatile unsigned char *, unsigned char, int);
    527750signed short __atomic_fetch_add  (volatile signed short *, signed short, int);
     751signed short __atomic_fetch_add_2(volatile signed short *, signed short, int);
    528752unsigned short __atomic_fetch_add  (volatile unsigned short *, unsigned short, int);
     753unsigned short __atomic_fetch_add_2(volatile unsigned short *, unsigned short, int);
    529754signed int __atomic_fetch_add  (volatile signed int *, signed int, int);
     755signed int __atomic_fetch_add_4(volatile signed int *, signed int, int);
    530756unsigned int __atomic_fetch_add  (volatile unsigned int *, unsigned int, int);
    531 signed long int __atomic_fetch_add  (volatile signed long int *, signed long int, int);
    532 unsigned long int __atomic_fetch_add  (volatile unsigned long int *, unsigned long int, int);
     757unsigned int __atomic_fetch_add_4(volatile unsigned int *, unsigned int, int);
    533758signed long long int __atomic_fetch_add  (volatile signed long long int *, signed long long int, int);
     759signed long long int __atomic_fetch_add_8(volatile signed long long int *, signed long long int, int);
    534760unsigned long long int __atomic_fetch_add  (volatile unsigned long long int *, unsigned long long int, int);
     761unsigned long long int __atomic_fetch_add_8(volatile unsigned long long int *, unsigned long long int, int);
    535762#if defined(__SIZEOF_INT128__)
    536763signed __int128 __atomic_fetch_add   (volatile signed __int128 *, signed __int128, int);
     764signed __int128 __atomic_fetch_add_16(volatile signed __int128 *, signed __int128, int);
    537765unsigned __int128 __atomic_fetch_add   (volatile unsigned __int128 *, unsigned __int128, int);
     766unsigned __int128 __atomic_fetch_add_16(volatile unsigned __int128 *, unsigned __int128, int);
    538767#endif
    539768
    540769char __atomic_fetch_sub  (volatile char *, char, int);
     770char __atomic_fetch_sub_1(volatile char *, char, int);
    541771signed char __atomic_fetch_sub  (volatile signed char *, signed char, int);
     772signed char __atomic_fetch_sub_1(volatile signed char *, signed char, int);
    542773unsigned char __atomic_fetch_sub  (volatile unsigned char *, unsigned char, int);
     774unsigned char __atomic_fetch_sub_1(volatile unsigned char *, unsigned char, int);
    543775signed short __atomic_fetch_sub  (volatile signed short *, signed short, int);
     776signed short __atomic_fetch_sub_2(volatile signed short *, signed short, int);
    544777unsigned short __atomic_fetch_sub  (volatile unsigned short *, unsigned short, int);
     778unsigned short __atomic_fetch_sub_2(volatile unsigned short *, unsigned short, int);
    545779signed int __atomic_fetch_sub  (volatile signed int *, signed int, int);
     780signed int __atomic_fetch_sub_4(volatile signed int *, signed int, int);
    546781unsigned int __atomic_fetch_sub  (volatile unsigned int *, unsigned int, int);
    547 signed long int __atomic_fetch_sub  (volatile signed long int *, signed long int, int);
    548 unsigned long int __atomic_fetch_sub  (volatile unsigned long int *, unsigned long int, int);
     782unsigned int __atomic_fetch_sub_4(volatile unsigned int *, unsigned int, int);
    549783signed long long int __atomic_fetch_sub  (volatile signed long long int *, signed long long int, int);
     784signed long long int __atomic_fetch_sub_8(volatile signed long long int *, signed long long int, int);
    550785unsigned long long int __atomic_fetch_sub  (volatile unsigned long long int *, unsigned long long int, int);
     786unsigned long long int __atomic_fetch_sub_8(volatile unsigned long long int *, unsigned long long int, int);
    551787#if defined(__SIZEOF_INT128__)
    552788signed __int128 __atomic_fetch_sub   (volatile signed  __int128 *, signed __int128, int);
     789signed __int128 __atomic_fetch_sub_16(volatile signed  __int128 *, signed __int128, int);
    553790unsigned __int128 __atomic_fetch_sub   (volatile unsigned  __int128 *, unsigned __int128, int);
     791unsigned __int128 __atomic_fetch_sub_16(volatile unsigned  __int128 *, unsigned __int128, int);
    554792#endif
    555793
    556794char __atomic_fetch_and  (volatile char *, char, int);
     795char __atomic_fetch_and_1(volatile char *, char, int);
    557796signed char __atomic_fetch_and  (volatile signed char *, signed char, int);
     797signed char __atomic_fetch_and_1(volatile signed char *, signed char, int);
    558798unsigned char __atomic_fetch_and  (volatile unsigned char *, unsigned char, int);
     799unsigned char __atomic_fetch_and_1(volatile unsigned char *, unsigned char, int);
    559800signed short __atomic_fetch_and  (volatile signed short *, signed short, int);
     801signed short __atomic_fetch_and_2(volatile signed short *, signed short, int);
    560802unsigned short __atomic_fetch_and  (volatile unsigned short *, unsigned short, int);
     803unsigned short __atomic_fetch_and_2(volatile unsigned short *, unsigned short, int);
    561804signed int __atomic_fetch_and  (volatile signed int *, signed int, int);
     805signed int __atomic_fetch_and_4(volatile signed int *, signed int, int);
    562806unsigned int __atomic_fetch_and  (volatile unsigned int *, unsigned int, int);
    563 signed long int __atomic_fetch_and  (volatile signed long int *, signed long int, int);
    564 unsigned long int __atomic_fetch_and  (volatile unsigned long int *, unsigned long int, int);
     807unsigned int __atomic_fetch_and_4(volatile unsigned int *, unsigned int, int);
    565808signed long long int __atomic_fetch_and  (volatile signed long long int *, signed long long int, int);
     809signed long long int __atomic_fetch_and_8(volatile signed long long int *, signed long long int, int);
    566810unsigned long long int __atomic_fetch_and  (volatile unsigned long long int *, unsigned long long int, int);
     811unsigned long long int __atomic_fetch_and_8(volatile unsigned long long int *, unsigned long long int, int);
    567812#if defined(__SIZEOF_INT128__)
    568813signed __int128 __atomic_fetch_and   (volatile signed __int128 *, signed __int128, int);
     814signed __int128 __atomic_fetch_and_16(volatile signed __int128 *, signed __int128, int);
    569815unsigned __int128 __atomic_fetch_and   (volatile unsigned __int128 *, unsigned __int128, int);
     816unsigned __int128 __atomic_fetch_and_16(volatile unsigned __int128 *, unsigned __int128, int);
    570817#endif
    571818
    572819char __atomic_fetch_nand  (volatile char *, char, int);
     820char __atomic_fetch_nand_1(volatile char *, char, int);
    573821signed char __atomic_fetch_nand  (volatile signed char *, signed char, int);
     822signed char __atomic_fetch_nand_1(volatile signed char *, signed char, int);
    574823unsigned char __atomic_fetch_nand  (volatile unsigned char *, unsigned char, int);
     824unsigned char __atomic_fetch_nand_1(volatile unsigned char *, unsigned char, int);
    575825signed short __atomic_fetch_nand  (volatile signed short *, signed short, int);
     826signed short __atomic_fetch_nand_2(volatile signed short *, signed short, int);
    576827unsigned short __atomic_fetch_nand  (volatile unsigned short *, unsigned short, int);
     828unsigned short __atomic_fetch_nand_2(volatile unsigned short *, unsigned short, int);
    577829signed int __atomic_fetch_nand  (volatile signed int *, signed int, int);
     830signed int __atomic_fetch_nand_4(volatile signed int *, signed int, int);
    578831unsigned int __atomic_fetch_nand  (volatile unsigned int *, unsigned int, int);
    579 signed long int __atomic_fetch_nand  (volatile signed long int *, signed long int, int);
    580 unsigned long int __atomic_fetch_nand  (volatile unsigned long int *, unsigned long int, int);
     832unsigned int __atomic_fetch_nand_4(volatile unsigned int *, unsigned int, int);
    581833signed long long int __atomic_fetch_nand  (volatile signed long long int *, signed long long int, int);
     834signed long long int __atomic_fetch_nand_8(volatile signed long long int *, signed long long int, int);
    582835unsigned long long int __atomic_fetch_nand  (volatile unsigned long long int *, unsigned long long int, int);
     836unsigned long long int __atomic_fetch_nand_8(volatile unsigned long long int *, unsigned long long int, int);
    583837#if defined(__SIZEOF_INT128__)
    584838signed __int128 __atomic_fetch_nand   (volatile signed __int128 *, signed __int128, int);
     839signed __int128 __atomic_fetch_nand_16(volatile signed __int128 *, signed __int128, int);
    585840unsigned __int128 __atomic_fetch_nand   (volatile unsigned __int128 *, unsigned __int128, int);
     841unsigned __int128 __atomic_fetch_nand_16(volatile unsigned __int128 *, unsigned __int128, int);
    586842#endif
    587843
    588844char __atomic_fetch_xor  (volatile char *, char, int);
     845char __atomic_fetch_xor_1(volatile char *, char, int);
    589846signed char __atomic_fetch_xor  (volatile signed char *, signed char, int);
     847signed char __atomic_fetch_xor_1(volatile signed char *, signed char, int);
    590848unsigned char __atomic_fetch_xor  (volatile unsigned char *, unsigned char, int);
     849unsigned char __atomic_fetch_xor_1(volatile unsigned char *, unsigned char, int);
    591850signed short __atomic_fetch_xor  (volatile signed short *, signed short, int);
     851signed short __atomic_fetch_xor_2(volatile signed short *, signed short, int);
    592852unsigned short __atomic_fetch_xor  (volatile unsigned short *, unsigned short, int);
     853unsigned short __atomic_fetch_xor_2(volatile unsigned short *, unsigned short, int);
    593854signed int __atomic_fetch_xor  (volatile signed int *, signed int, int);
     855signed int __atomic_fetch_xor_4(volatile signed int *, signed int, int);
    594856unsigned int __atomic_fetch_xor  (volatile unsigned int *, unsigned int, int);
    595 signed long int __atomic_fetch_xor  (volatile signed long int *, signed long int, int);
    596 unsigned long int __atomic_fetch_xor  (volatile unsigned long int *, unsigned long int, int);
     857unsigned int __atomic_fetch_xor_4(volatile unsigned int *, unsigned int, int);
    597858signed long long int __atomic_fetch_xor  (volatile signed long long int *, signed long long int, int);
     859signed long long int __atomic_fetch_xor_8(volatile signed long long int *, signed long long int, int);
    598860unsigned long long int __atomic_fetch_xor  (volatile unsigned long long int *, unsigned long long int, int);
     861unsigned long long int __atomic_fetch_xor_8(volatile unsigned long long int *, unsigned long long int, int);
    599862#if defined(__SIZEOF_INT128__)
    600863signed __int128 __atomic_fetch_xor   (volatile signed __int128 *, signed __int128, int);
     864signed __int128 __atomic_fetch_xor_16(volatile signed __int128 *, signed __int128, int);
    601865unsigned __int128 __atomic_fetch_xor   (volatile unsigned __int128 *, unsigned __int128, int);
     866unsigned __int128 __atomic_fetch_xor_16(volatile unsigned __int128 *, unsigned __int128, int);
    602867#endif
    603868
    604869char __atomic_fetch_or  (volatile char *, char, int);
     870char __atomic_fetch_or_1(volatile char *, char, int);
    605871signed char __atomic_fetch_or  (volatile signed char *, signed char, int);
     872signed char __atomic_fetch_or_1(volatile signed char *, signed char, int);
    606873unsigned char __atomic_fetch_or  (volatile unsigned char *, unsigned char, int);
     874unsigned char __atomic_fetch_or_1(volatile unsigned char *, unsigned char, int);
    607875signed short __atomic_fetch_or  (volatile signed short *, signed short, int);
     876signed short __atomic_fetch_or_2(volatile signed short *, signed short, int);
    608877unsigned short __atomic_fetch_or  (volatile unsigned short *, unsigned short, int);
     878unsigned short __atomic_fetch_or_2(volatile unsigned short *, unsigned short, int);
    609879signed int __atomic_fetch_or  (volatile signed int *, signed int, int);
     880signed int __atomic_fetch_or_4(volatile signed int *, signed int, int);
    610881unsigned int __atomic_fetch_or  (volatile unsigned int *, unsigned int, int);
    611 signed long int __atomic_fetch_or  (volatile signed long int *, signed long int, int);
    612 unsigned long int __atomic_fetch_or  (volatile unsigned long int *, unsigned long int, int);
     882unsigned int __atomic_fetch_or_4(volatile unsigned int *, unsigned int, int);
    613883signed long long int __atomic_fetch_or  (volatile signed long long int *, signed long long int, int);
     884signed long long int __atomic_fetch_or_8(volatile signed long long int *, signed long long int, int);
    614885unsigned long long int __atomic_fetch_or  (volatile unsigned long long int *, unsigned long long int, int);
     886unsigned long long int __atomic_fetch_or_8(volatile unsigned long long int *, unsigned long long int, int);
    615887#if defined(__SIZEOF_INT128__)
    616888signed __int128 __atomic_fetch_or   (volatile signed __int128 *, signed __int128, int);
     889signed __int128 __atomic_fetch_or_16(volatile signed __int128 *, signed __int128, int);
    617890unsigned __int128 __atomic_fetch_or   (volatile unsigned __int128 *, unsigned __int128, int);
     891unsigned __int128 __atomic_fetch_or_16(volatile unsigned __int128 *, unsigned __int128, int);
    618892#endif
    619893
  • libcfa/src/Makefile.am

    r7030dab r71d6bd8  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Mar 16 18:07:59 2020
    14 ## Update Count     : 242
     13## Last Modified On : Mon Jul 15 22:43:27 2019
     14## Update Count     : 241
    1515###############################################################################
    1616
     
    3333# The built sources must not depend on the installed headers
    3434AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
    35 AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
     35AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3636AM_CCASFLAGS = -g -Wall -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3737CFACC = @CFACC@
     
    3939#----------------------------------------------------------------------------------------------------------------
    4040if BUILDLIB
    41 headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa
     41headers_nosrc = math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa
    4242headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
    4343          containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
  • libcfa/src/Makefile.in

    r7030dab r71d6bd8  
    237237        limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
    238238        containers/maybe.hfa containers/pair.hfa containers/result.hfa \
    239         containers/vector.hfa bitmanip.hfa math.hfa gmp.hfa time_t.hfa \
     239        containers/vector.hfa math.hfa gmp.hfa time_t.hfa \
    240240        bits/align.hfa bits/containers.hfa bits/defs.hfa \
    241241        bits/debug.hfa bits/locks.hfa concurrency/coroutine.hfa \
     
    416416LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    417417        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
    418         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
     418        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
     419        $(AM_CFLAGS) $(CFLAGS)
    419420
    420421AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    422423am__v_CFA_0 = @echo "  CFA     " $@;
    423424am__v_CFA_1 =
     425AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     426am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     427am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     428am__v_JAVAC_1 =
     429AM_V_GOC = $(am__v_GOC_@AM_V@)
     430am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     431am__v_GOC_0 = @echo "  GOC     " $@;
     432am__v_GOC_1 =
    424433UPPCC = u++
    425434UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    428437am__v_UPP_0 = @echo "  UPP     " $@;
    429438am__v_UPP_1 =
    430 AM_V_GOC = $(am__v_GOC_@AM_V@)
    431 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    432 am__v_GOC_0 = @echo "  GOC     " $@;
    433 am__v_GOC_1 =
    434 AM_V_PY = $(am__v_PY_@AM_V@)
    435 am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
    436 am__v_PY_0 = @echo "  PYTHON  " $@;
    437 am__v_PY_1 =
    438 AM_V_RUST = $(am__v_RUST_@AM_V@)
    439 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
    440 am__v_RUST_0 = @echo "  RUST    " $@;
    441 am__v_RUST_1 =
    442 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
    443 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
    444 am__v_NODEJS_0 = @echo "  NODEJS  " $@;
    445 am__v_NODEJS_1 =
    446 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    447 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    448 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    449 am__v_JAVAC_1 =
    450439lib_LTLIBRARIES = libcfa.la libcfathread.la
    451440gdbwaittarget = ""
     
    456445# The built sources must not depend on the installed headers
    457446AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
    458 AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
     447AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC @ARCH_FLAGS@ @CONFIG_CFLAGS@
    459448AM_CCASFLAGS = -g -Wall -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    460449@BUILDLIB_FALSE@headers_nosrc =
    461450
    462451#----------------------------------------------------------------------------------------------------------------
    463 @BUILDLIB_TRUE@headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa
     452@BUILDLIB_TRUE@headers_nosrc = math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa
    464453@BUILDLIB_FALSE@headers =
    465454@BUILDLIB_TRUE@headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
  • libcfa/src/assert.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:00:18 2020
    13 // Update Count     : 6
     12// Last Modified On : Thu Jul 20 15:10:26 2017
     13// Update Count     : 2
    1414//
    1515
     
    1717#include <stdarg.h>                                                             // varargs
    1818#include <stdio.h>                                                              // fprintf
    19 #include <unistd.h>                                                             // STDERR_FILENO
    2019#include "bits/debug.hfa"
    2120
     
    2625
    2726        // called by macro assert in assert.h
    28         void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) {
    29                 __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
     27        void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function ) {
     28                __cfaabi_dbg_bits_print_safe( CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
    3029                abort();
    3130        }
    3231
    3332        // called by macro assertf
    34         void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) {
    35                 __cfaabi_bits_acquire();
    36                 __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
     33        void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {
     34                __cfaabi_dbg_bits_acquire();
     35                __cfaabi_dbg_bits_print_nolock( CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
    3736
    3837                va_list args;
    3938                va_start( args, fmt );
    40                 __cfaabi_bits_print_vararg( STDERR_FILENO, fmt, args );
     39                __cfaabi_dbg_bits_print_vararg( fmt, args );
    4140                va_end( args );
    4241
    43                 __cfaabi_bits_print_nolock( STDERR_FILENO, "\n" );
    44                 __cfaabi_bits_release();
     42                __cfaabi_dbg_bits_print_nolock( "\n" );
     43                __cfaabi_dbg_bits_release();
    4544                abort();
    4645        }
  • libcfa/src/bits/align.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Nov 16 18:58:22 2019
    13 // Update Count     : 3
     12// Last Modified On : Fri Jul 21 23:05:35 2017
     13// Update Count     : 2
    1414//
    1515// This  library is free  software; you  can redistribute  it and/or  modify it
     
    3333
    3434// Minimum size used to align memory boundaries for memory allocations.
    35 //#define libAlign() (sizeof(double))
    36 // gcc-7 uses xmms instructions, which require 16 byte alignment.
    37 #define libAlign() (16)
     35#define libAlign() (sizeof(double))
    3836
    3937// Check for power of 2
  • libcfa/src/bits/containers.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Oct 31 16:38:50 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jan 15 07:42:35 2020
    13 // Update Count     : 28
     12// Last Modified On : Wed Jun 26 08:52:20 2019
     13// Update Count     : 4
    1414
    1515#pragma once
     
    4444
    4545        forall(dtype T | sized(T))
    46         static inline T & ?[?]( __small_array(T) & this, __lock_size_t idx ) {
     46        static inline T& ?[?]( __small_array(T) & this, __lock_size_t idx) {
    4747                return ((typeof(this.data))this.data)[idx];
    4848        }
    4949
    5050        forall(dtype T | sized(T))
    51         static inline T & ?[?]( const __small_array(T) & this, __lock_size_t idx ) {
     51        static inline T& ?[?]( const __small_array(T) & this, __lock_size_t idx) {
    5252                return ((typeof(this.data))this.data)[idx];
    5353        }
    5454
    55         forall(dtype T)
    56         static inline T * begin( const __small_array(T) & this ) {
     55        forall(dtype T | sized(T))
     56        static inline T* begin( const __small_array(T) & this ) {
    5757                return ((typeof(this.data))this.data);
    5858        }
    5959
    6060        forall(dtype T | sized(T))
    61         static inline T * end( const __small_array(T) & this ) {
     61        static inline T* end( const __small_array(T) & this ) {
    6262                return ((typeof(this.data))this.data) + this.size;
    6363        }
     
    7070#ifdef __cforall
    7171        trait is_node(dtype T) {
    72                 T *& get_next( T & );
     72                T*& get_next( T& );
    7373        };
    7474#endif
     
    9797        forall(dtype T)
    9898        static inline void ?{}( __stack(T) & this ) {
    99                 (this.top){ 0p };
    100         }
    101 
    102         static inline forall( dtype T | is_node(T) ) {
    103                 void push( __stack(T) & this, T * val ) {
    104                         verify( !get_next( *val ) );
    105                         get_next( *val ) = this.top;
    106                         this.top = val;
    107                 }
    108 
    109                 T * pop( __stack(T) & this ) {
    110                         T * top = this.top;
    111                         if( top ) {
    112                                 this.top = get_next( *top );
    113                                 get_next( *top ) = 0p;
    114                         }
    115                         return top;
    116                 }
    117 
    118                 int ?!=?( const __stack(T) & this, __attribute__((unused)) zero_t zero ) {
    119                         return this.top != 0;
    120                 }
     99                (this.top){ NULL };
     100        }
     101
     102        forall(dtype T | is_node(T) | sized(T))
     103        static inline void push( __stack(T) & this, T * val ) {
     104                verify( !get_next( *val ) );
     105                get_next( *val ) = this.top;
     106                this.top = val;
     107        }
     108
     109        forall(dtype T | is_node(T) | sized(T))
     110        static inline T * pop( __stack(T) & this ) {
     111                T * top = this.top;
     112                if( top ) {
     113                        this.top = get_next( *top );
     114                        get_next( *top ) = NULL;
     115                }
     116                return top;
     117        }
     118
     119        forall(dtype T | is_node(T))
     120        static inline int ?!=?( const __stack(T) & this, __attribute__((unused)) zero_t zero ) {
     121                return this.top != 0;
    121122        }
    122123#endif
     
    144145
    145146#ifdef __cforall
    146         static inline forall( dtype T | is_node(T) ) {
    147                 void ?{}( __queue(T) & this ) with( this ) {
    148                         head{ 1p };
    149                         tail{ &head };
    150                         verify(*tail == 1p);
    151                 }
    152 
    153                 void append( __queue(T) & this, T * val ) with( this ) {
    154                         verify(tail != 0p);
    155                         verify(*tail == 1p);
    156                         *tail = val;
    157                         tail = &get_next( *val );
    158                         *tail = 1p;
    159                 }
    160 
    161                 T * pop_head( __queue(T) & this ) {
    162                         verify(*this.tail == 1p);
    163                         T * head = this.head;
    164                         if( head != 1p ) {
    165                                 this.head = get_next( *head );
    166                                 if( get_next( *head ) == 1p ) {
    167                                         this.tail = &this.head;
    168                                 }
    169                                 get_next( *head ) = 0p;
    170                                 verify(*this.tail == 1p);
    171                                 verify( get_next(*head) == 0p );
    172                                 return head;
     147
     148        forall(dtype T)
     149        static inline void ?{}( __queue(T) & this ) with( this ) {
     150                head{ NULL };
     151                tail{ &head };
     152        }
     153
     154        forall(dtype T | is_node(T) | sized(T))
     155        static inline void append( __queue(T) & this, T * val ) with( this ) {
     156                verify(tail != NULL);
     157                *tail = val;
     158                tail = &get_next( *val );
     159        }
     160
     161        forall(dtype T | is_node(T) | sized(T))
     162        static inline T * pop_head( __queue(T) & this ) {
     163                T * head = this.head;
     164                if( head ) {
     165                        this.head = get_next( *head );
     166                        if( !get_next( *head ) ) {
     167                                this.tail = &this.head;
    173168                        }
    174                         verify(*this.tail == 1p);
    175                         return 0p;
    176                 }
    177 
    178                 T * remove( __queue(T) & this, T ** it ) with( this ) {
    179                         T * val = *it;
    180                         verify( val );
    181 
    182                         (*it) = get_next( *val );
    183 
    184                         if( tail == &get_next( *val ) ) {
    185                                 tail = it;
    186                         }
    187 
    188                         get_next( *val ) = 0p;
    189 
    190                         verify( (head == 1p) == (&head == tail) );
    191                         verify( *tail == 1p );
    192                         return val;
    193                 }
    194 
    195                 int ?!=?( const __queue(T) & this, __attribute__((unused)) zero_t zero ) {
    196                         return this.head != 0;
    197                 }
     169                        get_next( *head ) = NULL;
     170                }
     171                return head;
     172        }
     173
     174        forall(dtype T | is_node(T) | sized(T))
     175        static inline T * remove( __queue(T) & this, T ** it ) with( this ) {
     176                T * val = *it;
     177                verify( val );
     178
     179                (*it) = get_next( *val );
     180
     181                if( tail == &get_next( *val ) ) {
     182                        tail = it;
     183                }
     184
     185                get_next( *val ) = NULL;
     186
     187                verify( (head == NULL) == (&head == tail) );
     188                verify( *tail == NULL );
     189                return val;
     190        }
     191
     192        forall(dtype T | is_node(T))
     193        static inline int ?!=?( const __queue(T) & this, __attribute__((unused)) zero_t zero ) {
     194                return this.head != 0;
    198195        }
    199196#endif
     
    226223
    227224#ifdef __cforall
    228         forall(dtype T )
     225
     226        forall(dtype T | sized(T))
    229227        static inline [void] ?{}( __dllist(T) & this, * [T * & next, T * & prev] ( T & ) __get ) {
    230                 this.head{ 0p };
     228                this.head{ NULL };
    231229                this.__get = __get;
    232230        }
     
    234232        #define next 0
    235233        #define prev 1
    236         static inline forall(dtype T) {
    237                 void push_front( __dllist(T) & this, T & node ) with( this ) {
    238                         verify(__get);
    239                         if ( head ) {
    240                                 __get( node ).next = head;
    241                                 __get( node ).prev = __get( *head ).prev;
    242                                 // inserted node must be consistent before it is seen
    243                                 // prevent code movement across barrier
    244                                 asm( "" : : : "memory" );
    245                                 __get( *head ).prev = &node;
    246                                 T & _prev = *__get( node ).prev;
    247                                 __get( _prev ).next = &node;
    248                         } else {
    249                                 __get( node ).next = &node;
    250                                 __get( node ).prev = &node;
    251                         }
    252 
     234        forall(dtype T | sized(T))
     235        static inline void push_front( __dllist(T) & this, T & node ) with( this ) {
     236                verify(__get);
     237                if ( head ) {
     238                        __get( node ).next = head;
     239                        __get( node ).prev = __get( *head ).prev;
     240                        // inserted node must be consistent before it is seen
    253241                        // prevent code movement across barrier
    254242                        asm( "" : : : "memory" );
    255                         head = &node;
    256                 }
    257 
    258                 void remove( __dllist(T) & this, T & node ) with( this ) {
    259                         verify(__get);
    260                         if ( &node == head ) {
    261                                 if ( __get( *head ).next == head ) {
    262                                         head = 0p;
    263                                 } else {
    264                                         head = __get( *head ).next;
    265                                 }
     243                        __get( *head ).prev = &node;
     244                        T & _prev = *__get( node ).prev;
     245                        __get( _prev ).next = &node;
     246                }
     247                else {
     248                        __get( node ).next = &node;
     249                        __get( node ).prev = &node;
     250                }
     251
     252                // prevent code movement across barrier
     253                asm( "" : : : "memory" );
     254                head = &node;
     255        }
     256
     257        forall(dtype T | sized(T))
     258        static inline void remove( __dllist(T) & this, T & node ) with( this ) {
     259                verify(__get);
     260                if ( &node == head ) {
     261                        if ( __get( *head ).next == head ) {
     262                                head = NULL;
    266263                        }
    267                         __get( *__get( node ).next ).prev = __get( node ).prev;
    268                         __get( *__get( node ).prev ).next = __get( node ).next;
    269                         __get( node ).next = 0p;
    270                         __get( node ).prev = 0p;
    271                 }
    272 
    273                 int ?!=?( const __dllist(T) & this, __attribute__((unused)) zero_t zero ) {
    274                         return this.head != 0;
    275                 }
    276 
    277                 void move_to_front( __dllist(T) & src, __dllist(T) & dst, T & node ) {
    278                         remove    (src, node);
    279                         push_front(dst, node);
    280                 }
     264                        else {
     265                                head = __get( *head ).next;
     266                        }
     267                }
     268                __get( *__get( node ).next ).prev = __get( node ).prev;
     269                __get( *__get( node ).prev ).next = __get( node ).next;
     270                __get( node ).next = NULL;
     271                __get( node ).prev = NULL;
     272        }
     273
     274        forall(dtype T | sized(T))
     275        static inline int ?!=?( const __dllist(T) & this, __attribute__((unused)) zero_t zero ) {
     276                return this.head != 0;
    281277        }
    282278        #undef next
     
    290286
    291287#endif
    292 
    293 // Local Variables: //
    294 // tab-width: 4 //
    295 // End: //
  • libcfa/src/bits/debug.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Thu Mar 30 12:30:01 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:16 2020
    13 // Update Count     : 11
     12// Last Modified On : Sun Jul 14 22:17:35 2019
     13// Update Count     : 4
    1414//
    1515
     
    2727
    2828extern "C" {
    29         void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) {
     29
     30        void __cfaabi_dbg_bits_write( const char *in_buffer, int len ) {
    3031                // ensure all data is written
    3132                for ( int count = 0, retcode; count < len; count += retcode ) {
     
    3334
    3435                        for ( ;; ) {
    35                                 retcode = write( fd, in_buffer, len - count );
     36                                retcode = write( STDERR_FILENO, in_buffer, len - count );
    3637
    3738                                // not a timer interrupt ?
     
    4344        }
    4445
    45         void __cfaabi_bits_acquire() __attribute__((__weak__)) {}
    46         void __cfaabi_bits_release() __attribute__((__weak__)) {}
     46        void __cfaabi_dbg_bits_acquire() __attribute__((__weak__)) {}
     47        void __cfaabi_dbg_bits_release() __attribute__((__weak__)) {}
    4748
    48         void __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) {
     49        void __cfaabi_dbg_bits_print_safe  ( const char fmt[], ... ) __attribute__(( format(printf, 1, 2) )) {
    4950                va_list args;
    5051
    5152                va_start( args, fmt );
    52                 __cfaabi_bits_acquire();
     53                __cfaabi_dbg_bits_acquire();
    5354
    5455                int len = vsnprintf( buffer, buffer_size, fmt, args );
    55                 __cfaabi_bits_write( fd, buffer, len );
     56                __cfaabi_dbg_bits_write( buffer, len );
    5657
    57                 __cfaabi_bits_release();
     58                __cfaabi_dbg_bits_release();
    5859                va_end( args );
    5960        }
    6061
    61         void __cfaabi_bits_print_nolock( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) {
     62        void __cfaabi_dbg_bits_print_nolock( const char fmt[], ... ) __attribute__(( format(printf, 1, 2) )) {
    6263                va_list args;
    6364
     
    6566
    6667                int len = vsnprintf( buffer, buffer_size, fmt, args );
    67                 __cfaabi_bits_write( fd, buffer, len );
     68                __cfaabi_dbg_bits_write( buffer, len );
    6869
    6970                va_end( args );
    7071        }
    7172
    72         void __cfaabi_bits_print_vararg( int fd, const char fmt[], va_list args ) {
     73        void __cfaabi_dbg_bits_print_vararg( const char fmt[], va_list args ) {
    7374                int len = vsnprintf( buffer, buffer_size, fmt, args );
    74                 __cfaabi_bits_write( fd, buffer, len );
     75                __cfaabi_dbg_bits_write( buffer, len );
    7576        }
    7677
    77         void __cfaabi_bits_print_buffer( int fd, char in_buffer[], int in_buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 4, 5) )) {
     78        void __cfaabi_dbg_bits_print_buffer( char in_buffer[], int in_buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 3, 4) )) {
    7879                va_list args;
    7980
     
    8182
    8283                int len = vsnprintf( in_buffer, in_buffer_size, fmt, args );
    83                 __cfaabi_bits_write( fd, in_buffer, len );
     84                __cfaabi_dbg_bits_write( in_buffer, len );
    8485
    8586                va_end( args );
  • libcfa/src/bits/debug.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:21 2020
    13 // Update Count     : 9
     12// Last Modified On : Thu Feb  8 12:35:19 2018
     13// Update Count     : 2
    1414//
    1515
     
    2121        #define __cfaabi_dbg_ctx __PRETTY_FUNCTION__
    2222        #define __cfaabi_dbg_ctx2 , __PRETTY_FUNCTION__
    23         #define __cfaabi_dbg_ctx_param const char caller[]
    24         #define __cfaabi_dbg_ctx_param2 , const char caller[]
    25         #define __cfaabi_dbg_ctx_fwd caller
    26         #define __cfaabi_dbg_ctx_fwd2 , caller
     23        #define __cfaabi_dbg_ctx_param const char * caller
     24        #define __cfaabi_dbg_ctx_param2 , const char * caller
    2725#else
    2826        #define __cfaabi_dbg_debug_do(...)
     
    3230        #define __cfaabi_dbg_ctx_param
    3331        #define __cfaabi_dbg_ctx_param2
    34         #define __cfaabi_dbg_ctx_fwd
    35         #define __cfaabi_dbg_ctx_fwd2
    3632#endif
    3733
     
    4238        #include <stdio.h>
    4339
    44         extern void __cfaabi_bits_write( int fd, const char buffer[], int len );
    45         extern void __cfaabi_bits_acquire();
    46         extern void __cfaabi_bits_release();
    47         extern void __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) ));
    48         extern void __cfaabi_bits_print_nolock( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) ));
    49         extern void __cfaabi_bits_print_vararg( int fd, const char fmt[], va_list arg );
    50         extern void __cfaabi_bits_print_buffer( int fd, char buffer[], int buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 4, 5) ));
     40      extern void __cfaabi_dbg_bits_write( const char *buffer, int len );
     41      extern void __cfaabi_dbg_bits_acquire();
     42      extern void __cfaabi_dbg_bits_release();
     43      extern void __cfaabi_dbg_bits_print_safe  ( const char fmt[], ... ) __attribute__(( format(printf, 1, 2) ));
     44      extern void __cfaabi_dbg_bits_print_nolock( const char fmt[], ... ) __attribute__(( format(printf, 1, 2) ));
     45      extern void __cfaabi_dbg_bits_print_vararg( const char fmt[], va_list arg );
     46      extern void __cfaabi_dbg_bits_print_buffer( char buffer[], int buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 3, 4) ));
    5147#ifdef __cforall
    5248}
     
    5450
    5551#ifdef __CFA_DEBUG_PRINT__
    56         #define __cfaabi_dbg_write( buffer, len )         __cfaabi_bits_write( STDERR_FILENO, buffer, len )
    57         #define __cfaabi_dbg_acquire()                    __cfaabi_bits_acquire()
    58         #define __cfaabi_dbg_release()                    __cfaabi_bits_release()
    59         #define __cfaabi_dbg_print_safe(...)              __cfaabi_bits_print_safe   (__VA_ARGS__)
    60         #define __cfaabi_dbg_print_nolock(...)            __cfaabi_bits_print_nolock (__VA_ARGS__)
    61         #define __cfaabi_dbg_print_buffer(...)            __cfaabi_bits_print_buffer (__VA_ARGS__)
    62         #define __cfaabi_dbg_print_buffer_decl(...)       char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len );
    63         #define __cfaabi_dbg_print_buffer_local(...)      __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_write( __dbg_text, __dbg_len );
     52        #define __cfaabi_dbg_write( buffer, len )         __cfaabi_dbg_bits_write( buffer, len )
     53        #define __cfaabi_dbg_acquire()                    __cfaabi_dbg_bits_acquire()
     54        #define __cfaabi_dbg_release()                    __cfaabi_dbg_bits_release()
     55        #define __cfaabi_dbg_print_safe(...)              __cfaabi_dbg_bits_print_safe   (__VA_ARGS__)
     56        #define __cfaabi_dbg_print_nolock(...)            __cfaabi_dbg_bits_print_nolock (__VA_ARGS__)
     57        #define __cfaabi_dbg_print_buffer(...)            __cfaabi_dbg_bits_print_buffer (__VA_ARGS__)
     58        #define __cfaabi_dbg_print_buffer_decl(...)       char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_bits_write( __dbg_text, __dbg_len );
     59        #define __cfaabi_dbg_print_buffer_local(...)      __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_bits_write( __dbg_text, __dbg_len );
    6460#else
    6561        #define __cfaabi_dbg_write(...)               ((void)0)
  • libcfa/src/bits/defs.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Thu Nov  9 13:24:10 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jan 28 22:38:27 2020
    13 // Update Count     : 9
     12// Last Modified On : Thu Feb  8 16:22:41 2018
     13// Update Count     : 8
    1414//
    1515
     
    3434
    3535#ifdef __cforall
    36 void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    37 void abort( bool signalAbort, const char fmt[], ... ) __attribute__ (( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
     36void abort ( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    3837extern "C" {
    3938#endif
  • libcfa/src/bits/locks.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Oct 31 15:14:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:19 2020
    13 // Update Count     : 11
     12// Last Modified On : Sat Aug 11 15:42:24 2018
     13// Update Count     : 10
    1414//
    1515
     
    5454
    5555                #ifdef __CFA_DEBUG__
    56                         void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]);
     56                        void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name);
    5757                #else
    58                         #define __cfaabi_dbg_record_lock(x, y)
     58                        #define __cfaabi_dbg_record(x, y)
    5959                #endif
    6060        }
     61
     62        extern void yield( unsigned int );
    6163
    6264        static inline void ?{}( __spinlock_t & this ) {
     
    6668        // Lock the spinlock, return false if already acquired
    6769        static inline bool try_lock  ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
    68                 disable_interrupts();
    6970                bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
    7071                if( result ) {
    71                         __cfaabi_dbg_record_lock( this, caller );
    72                 } else {
    73                         enable_interrupts_noPoll();
     72                        disable_interrupts();
     73                        __cfaabi_dbg_record( this, caller );
    7474                }
    7575                return result;
     
    8383                #endif
    8484
    85                 disable_interrupts();
    8685                for ( unsigned int i = 1;; i += 1 ) {
    8786                        if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
     
    9998                        #endif
    10099                }
    101                 __cfaabi_dbg_record_lock( this, caller );
     100                disable_interrupts();
     101                __cfaabi_dbg_record( this, caller );
    102102        }
    103103
    104104        static inline void unlock( __spinlock_t & this ) {
     105                enable_interrupts_noPoll();
    105106                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
    106                 enable_interrupts_noPoll();
    107107        }
    108108
     
    139139        }
    140140
    141         static inline bool post(__bin_sem_t & this) with( this ) {
     141        static inline void post(__bin_sem_t & this) with( this ) {
     142                verify(__cfaabi_dbg_in_kernel());
     143
    142144                pthread_mutex_lock(&lock);
    143145                        bool needs_signal = !signaled;
     
    145147                pthread_mutex_unlock(&lock);
    146148
    147                 if (needs_signal) pthread_cond_signal(&cond);
    148 
    149                 return needs_signal;
     149                if (needs_signal)
     150                        pthread_cond_signal(&cond);
    150151        }
    151152#endif
  • libcfa/src/bits/signal.hfa

    r7030dab r71d6bd8  
    3737
    3838        act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
    39         sigemptyset( &act.sa_mask );
    40         sigaddset( &act.sa_mask, SIGALRM );             // disabled during signal handler
    41         sigaddset( &act.sa_mask, SIGUSR1 );
    42         sigaddset( &act.sa_mask, SIGSEGV );
    43         sigaddset( &act.sa_mask, SIGBUS );
    44         sigaddset( &act.sa_mask, SIGILL );
    45         sigaddset( &act.sa_mask, SIGFPE );
    46         sigaddset( &act.sa_mask, SIGHUP );              // revert to default on second delivery
    47         sigaddset( &act.sa_mask, SIGTERM );
    48         sigaddset( &act.sa_mask, SIGINT );
    4939        act.sa_flags = flags;
    5040
    51         if ( sigaction( sig, &act, 0p ) == -1 ) {
     41        if ( sigaction( sig, &act, NULL ) == -1 ) {
    5242                __cfaabi_dbg_print_buffer_decl(
    5343                        " __cfaabi_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
     
    5545                );
    5646                _exit( EXIT_FAILURE );
    57         } // if
     47        }
    5848}
     49
     50// Sigaction wrapper : restore default handler
     51static void __cfaabi_sigdefault( int sig ) {
     52        struct sigaction act;
     53
     54        act.sa_handler = SIG_DFL;
     55        act.sa_flags = 0;
     56        sigemptyset( &act.sa_mask );
     57
     58        if ( sigaction( sig, &act, NULL ) == -1 ) {
     59                __cfaabi_dbg_print_buffer_decl(
     60                        " __cfaabi_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",
     61                        sig, errno, strerror( errno )
     62                );
     63                _exit( EXIT_FAILURE );
     64        }
     65}
  • libcfa/src/clock.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Thu Apr 12 14:36:06 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan  6 12:49:58 2020
    13 // Update Count     : 9
     12// Last Modified On : Thu Jun 13 21:21:13 2019
     13// Update Count     : 8
    1414//
    1515
    1616#include <time.hfa>
     17
    1718
    1819//######################### C time #########################
     
    2526static inline tm * localtime_r( time_t tp, tm * result ) { return localtime_r( &tp, result ); }
    2627
     28
    2729//######################### Clock #########################
    2830
    2931struct Clock {                                                                                  // private
    3032        Duration offset;                                                                        // for virtual clock: contains offset from real-time
     33        int clocktype;                                                                          // implementation only -1 (virtual), CLOCK_REALTIME
    3134};
    3235
    3336static inline {
     37        void resetClock( Clock & clk ) with( clk ) {
     38                clocktype = CLOCK_REALTIME_COARSE;
     39        } // Clock::resetClock
     40
    3441        void resetClock( Clock & clk, Duration adj ) with( clk ) {
     42                clocktype = -1;
    3543                offset = adj + __timezone`s;                                    // timezone (global) is (UTC - local time) in seconds
    3644        } // resetClock
    3745
     46        void ?{}( Clock & clk ) { resetClock( clk ); }
    3847        void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
    3948
     
    8089                return ret;
    8190        } // getTime
    82 
    83         Time getCPUTime() {
    84                 timespec ts;
    85                 clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
    86                 return (Time){ ts };
    87     } // getCPUTime
    8891} // distribution
    8992
  • libcfa/src/concurrency/CtxSwitch-arm.S

    r7030dab r71d6bd8  
    1313        .text
    1414        .align  2
    15         .global __cfactx_switch
    16         .type   __cfactx_switch, %function
     15        .global CtxSwitch
     16        .type   CtxSwitch, %function
    1717
    18 __cfactx_switch:
     18CtxSwitch:
    1919        @ save callee-saved registers: r4-r8, r10, r11, r13(sp) (plus r9 depending on platform specification)
    2020        @ I've seen reference to 31 registers on 64-bit, if this is the case, more need to be saved
     
    5252        mov r15, r14
    5353        #endif // R9_SPECIAL
    54 
     54       
    5555        .text
    5656        .align  2
    57         .global __cfactx_invoke_stub
    58         .type   __cfactx_invoke_stub, %function
     57        .global CtxInvokeStub
     58        .type   CtxInvokeStub, %function
    5959
    60 __cfactx_invoke_stub:
     60CtxInvokeStub:
    6161        ldmfd r13!, {r0-r1}
    6262        mov r15, r1
  • libcfa/src/concurrency/CtxSwitch-i386.S

    r7030dab r71d6bd8  
    4343        .text
    4444        .align 2
    45         .globl __cfactx_switch
    46         .type  __cfactx_switch, @function
    47 __cfactx_switch:
     45        .globl CtxSwitch
     46        .type  CtxSwitch, @function
     47CtxSwitch:
    4848
    4949        // Copy the "from" context argument from the stack to register eax
     
    8383
    8484        ret
    85         .size  __cfactx_switch, .-__cfactx_switch
     85        .size  CtxSwitch, .-CtxSwitch
    8686
    8787// Local Variables: //
  • libcfa/src/concurrency/CtxSwitch-x86_64.S

    r7030dab r71d6bd8  
    4444        .text
    4545        .align 2
    46         .globl __cfactx_switch
    47         .type  __cfactx_switch, @function
    48 __cfactx_switch:
     46        .globl CtxSwitch
     47        .type  CtxSwitch, @function
     48CtxSwitch:
    4949
    5050        // Save volatile registers on the stack.
     
    7777
    7878        ret
    79         .size  __cfactx_switch, .-__cfactx_switch
     79        .size  CtxSwitch, .-CtxSwitch
    8080
    8181//-----------------------------------------------------------------------------
     
    8383        .text
    8484        .align 2
    85         .globl __cfactx_invoke_stub
    86         .type    __cfactx_invoke_stub, @function
    87 __cfactx_invoke_stub:
     85        .globl CtxInvokeStub
     86        .type    CtxInvokeStub, @function
     87CtxInvokeStub:
    8888        movq %rbx, %rdi
    89         movq %r12, %rsi
    90         jmp *%r13
    91         .size  __cfactx_invoke_stub, .-__cfactx_invoke_stub
     89        jmp *%r12
     90        .size  CtxInvokeStub, .-CtxInvokeStub
    9291
    9392// Local Variables: //
  • libcfa/src/concurrency/alarm.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Fri Jun 2 11:31:25 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jan  5 08:41:36 2020
    13 // Update Count     : 69
     12// Last Modified On : Fri May 25 06:25:47 2018
     13// Update Count     : 67
    1414//
    1515
     
    3939
    4040void __kernel_set_timer( Duration alarm ) {
    41         verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm`ns);
    42         setitimer( ITIMER_REAL, &(itimerval){ alarm }, 0p );
     41        verifyf(alarm >= 1`us || alarm == 0, "Setting timer to < 1us (%jins)", alarm.tv);
     42        setitimer( ITIMER_REAL, &(itimerval){ alarm }, NULL );
    4343}
    4444
     
    4747//=============================================================================================
    4848
    49 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period ) with( this ) {
     49void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period ) with( this ) {
    5050        this.thrd = thrd;
    5151        this.alarm = alarm;
     
    113113                        this->tail = &this->head;
    114114                }
    115                 head->next = 0p;
     115                head->next = NULL;
    116116        }
    117117        verify( validate( this ) );
     
    127127                this->tail = it;
    128128        }
    129         n->next = 0p;
     129        n->next = NULL;
    130130
    131131        verify( validate( this ) );
  • libcfa/src/concurrency/alarm.hfa

    r7030dab r71d6bd8  
    2323#include "time.hfa"
    2424
    25 struct $thread;
     25struct thread_desc;
    2626struct processor;
    2727
     
    4343
    4444        union {
    45                 $thread * thrd; // thrd who created event
     45                thread_desc * thrd;     // thrd who created event
    4646                processor * proc;               // proc who created event
    4747        };
     
    5353typedef alarm_node_t ** __alarm_it_t;
    5454
    55 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period );
     55void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period );
    5656void ?{}( alarm_node_t & this, processor   * proc, Time alarm, Duration period );
    5757void ^?{}( alarm_node_t & this );
  • libcfa/src/concurrency/coroutine.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:25 2020
    13 // Update Count     : 16
     12// Last Modified On : Fri Mar 30 17:20:57 2018
     13// Update Count     : 9
    1414//
    1515
     
    3737
    3838extern "C" {
    39         void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
     39        void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    4040        static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));
    4141        static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {
     
    8989}
    9090
    91 void ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize ) with( this ) {
    92         (this.context){0p, 0p};
     91void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
     92        (this.context){NULL, NULL};
    9393        (this.stack){storage, storageSize};
    9494        this.name = name;
    9595        state = Start;
    96         starter = 0p;
    97         last = 0p;
    98         cancellation = 0p;
    99 }
    100 
    101 void ^?{}($coroutine& this) {
     96        starter = NULL;
     97        last = NULL;
     98        cancellation = NULL;
     99}
     100
     101void ^?{}(coroutine_desc& this) {
    102102        if(this.state != Halted && this.state != Start && this.state != Primed) {
    103                 $coroutine * src = TL_GET( this_thread )->curr_cor;
    104                 $coroutine * dst = &this;
     103                coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     104                coroutine_desc * dst = &this;
    105105
    106106                struct _Unwind_Exception storage;
     
    115115                }
    116116
    117                 $ctx_switch( src, dst );
     117                CoroutineCtxSwitch( src, dst );
    118118        }
    119119}
     
    123123forall(dtype T | is_coroutine(T))
    124124void prime(T& cor) {
    125         $coroutine* this = get_coroutine(cor);
     125        coroutine_desc* this = get_coroutine(cor);
    126126        assert(this->state == Start);
    127127
     
    131131
    132132[void *, size_t] __stack_alloc( size_t storageSize ) {
    133         const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
     133        static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    134134        assert(__page_size != 0l);
    135135        size_t size = libCeiling( storageSize, 16 ) + stack_data_size;
     
    157157
    158158void __stack_prepare( __stack_info_t * this, size_t create_size ) {
    159         const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
     159        static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
    160160        bool userStack;
    161161        void * storage;
     
    187187// is not inline (We can't inline Cforall in C)
    188188extern "C" {
    189         void __cfactx_cor_leave( struct $coroutine * src ) {
    190                 $coroutine * starter = src->cancellation != 0 ? src->last : src->starter;
     189        void __suspend_internal(void) {
     190                suspend();
     191        }
     192
     193        void __leave_coroutine( coroutine_desc * src ) {
     194                coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
    191195
    192196                src->state = Halted;
     
    201205                        src->name, src, starter->name, starter );
    202206
    203                 $ctx_switch( src, starter );
    204         }
    205 
    206         struct $coroutine * __cfactx_cor_finish(void) {
    207                 struct $coroutine * cor = kernelTLS.this_thread->curr_cor;
    208 
    209                 if(cor->state == Primed) {
    210                         __cfactx_suspend();
    211                 }
    212 
    213                 cor->state = Active;
    214 
    215                 return cor;
     207                CoroutineCtxSwitch( src, starter );
    216208        }
    217209}
  • libcfa/src/concurrency/coroutine.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:26 2020
    13 // Update Count     : 11
     12// Last Modified On : Fri Jun 21 17:49:39 2019
     13// Update Count     : 9
    1414//
    1515
     
    2525trait is_coroutine(dtype T) {
    2626      void main(T & this);
    27       $coroutine * get_coroutine(T & this);
     27      coroutine_desc * get_coroutine(T & this);
    2828};
    2929
    30 #define DECL_COROUTINE(X) static inline $coroutine* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
     30#define DECL_COROUTINE(X) static inline coroutine_desc* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
    3131
    3232//-----------------------------------------------------------------------------
     
    3535// void ^?{}( coStack_t & this );
    3636
    37 void  ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );
    38 void ^?{}( $coroutine & this );
     37void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
     38void ^?{}( coroutine_desc & this );
    3939
    40 static inline void ?{}( $coroutine & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
    41 static inline void ?{}( $coroutine & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
    42 static inline void ?{}( $coroutine & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
    43 static inline void ?{}( $coroutine & this, const char name[])                    { this{ name, 0p, 0 }; }
    44 static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
     40static inline void ?{}( coroutine_desc & this)                                       { this{ "Anonymous Coroutine", NULL, 0 }; }
     41static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", NULL, stackSize }; }
     42static inline void ?{}( coroutine_desc & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
     43static inline void ?{}( coroutine_desc & this, const char * name)                    { this{ name, NULL, 0 }; }
     44static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, NULL, stackSize }; }
    4545
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
     48static inline void suspend(void);
     49
     50forall(dtype T | is_coroutine(T))
     51static inline T & resume(T & cor);
     52
    4853forall(dtype T | is_coroutine(T))
    4954void prime(T & cor);
    5055
    51 static inline struct $coroutine * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
     56static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    5257
    5358//-----------------------------------------------------------------------------
     
    5661// Start coroutine routines
    5762extern "C" {
    58         void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
     63      forall(dtype T | is_coroutine(T))
     64      void CtxInvokeCoroutine(T * this);
    5965
    60         forall(dtype T)
    61         void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
     66      forall(dtype T | is_coroutine(T))
     67      void CtxStart(T * this, void ( *invoke)(T *));
    6268
    63         extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
     69        extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    6470
    65         extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
     71        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    6672}
    6773
    6874// Private wrappers for context switch and stack creation
    6975// Wrapper for co
    70 static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {
     76static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    7177        // set state of current coroutine to inactive
    72         src->state = src->state == Halted ? Halted : Blocked;
     78        src->state = src->state == Halted ? Halted : Inactive;
    7379
    7480        // set new coroutine that task is executing
     
    7783        // context switch to specified coroutine
    7884        verify( dst->context.SP );
    79         __cfactx_switch( &src->context, &dst->context );
    80         // when __cfactx_switch returns we are back in the src coroutine
     85        CtxSwitch( &src->context, &dst->context );
     86        // when CtxSwitch returns we are back in the src coroutine
    8187
    8288        // set state of new coroutine to active
    8389        src->state = Active;
    8490
    85         if( unlikely(src->cancellation != 0p) ) {
    86                 __cfactx_coroutine_unwind(src->cancellation, src);
     91        if( unlikely(src->cancellation != NULL) ) {
     92                _CtxCoroutine_Unwind(src->cancellation, src);
    8793        }
    8894}
     
    9197
    9298// Suspend implementation inlined for performance
    93 extern "C" {
    94         static inline void __cfactx_suspend(void) {
    95                 // optimization : read TLS once and reuse it
    96                 // Safety note: this is preemption safe since if
    97                 // preemption occurs after this line, the pointer
    98                 // will also migrate which means this value will
    99                 // stay in syn with the TLS
    100                 $coroutine * src = TL_GET( this_thread )->curr_cor;
     99static inline void suspend(void) {
     100        // optimization : read TLS once and reuse it
     101        // Safety note: this is preemption safe since if
     102        // preemption occurs after this line, the pointer
     103        // will also migrate which means this value will
     104        // stay in syn with the TLS
     105        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    101106
    102                 assertf( src->last != 0,
    103                         "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
    104                         "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    105                         src->name, src );
    106                 assertf( src->last->state != Halted,
    107                         "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
    108                         "Possible cause is terminated coroutine's main routine has already returned.",
    109                         src->name, src, src->last->name, src->last );
     107        assertf( src->last != 0,
     108                "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
     109                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     110                src->name, src );
     111        assertf( src->last->state != Halted,
     112                "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
     113                "Possible cause is terminated coroutine's main routine has already returned.",
     114                src->name, src, src->last->name, src->last );
    110115
    111                 $ctx_switch( src, src->last );
    112         }
     116        CoroutineCtxSwitch( src, src->last );
    113117}
    114118
     
    121125        // will also migrate which means this value will
    122126        // stay in syn with the TLS
    123         $coroutine * src = TL_GET( this_thread )->curr_cor;
    124         $coroutine * dst = get_coroutine(cor);
     127        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     128        coroutine_desc * dst = get_coroutine(cor);
    125129
    126         if( unlikely(dst->context.SP == 0p) ) {
    127                 TL_GET( this_thread )->curr_cor = dst;
     130        if( unlikely(dst->context.SP == NULL) ) {
    128131                __stack_prepare(&dst->stack, 65000);
    129                 __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
    130                 TL_GET( this_thread )->curr_cor = src;
     132                CtxStart(&cor, CtxInvokeCoroutine);
    131133        }
    132134
     
    144146
    145147        // always done for performance testing
    146         $ctx_switch( src, dst );
     148        CoroutineCtxSwitch( src, dst );
    147149
    148150        return cor;
    149151}
    150152
    151 static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {
     153static inline void resume(coroutine_desc * dst) {
    152154        // optimization : read TLS once and reuse it
    153155        // Safety note: this is preemption safe since if
     
    155157        // will also migrate which means this value will
    156158        // stay in syn with the TLS
    157         $coroutine * src = TL_GET( this_thread )->curr_cor;
     159        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    158160
    159161        // not resuming self ?
     
    169171
    170172        // always done for performance testing
    171         $ctx_switch( src, dst );
     173        CoroutineCtxSwitch( src, dst );
    172174}
    173175
  • libcfa/src/concurrency/invoke.c

    r7030dab r71d6bd8  
    2929// Called from the kernel when starting a coroutine or task so must switch back to user mode.
    3030
    31 extern struct $coroutine * __cfactx_cor_finish(void);
    32 extern void __cfactx_cor_leave ( struct $coroutine * );
    33 extern void __cfactx_thrd_leave();
    34 
     31extern void __suspend_internal(void);
     32extern void __leave_coroutine( struct coroutine_desc * );
     33extern void __finish_creation( struct thread_desc * );
     34extern void __leave_thread_monitor( struct thread_desc * this );
    3535extern void disable_interrupts() OPTIONAL_THREAD;
    3636extern void enable_interrupts( __cfaabi_dbg_ctx_param );
    3737
    38 void __cfactx_invoke_coroutine(
     38void CtxInvokeCoroutine(
    3939        void (*main)(void *),
     40        struct coroutine_desc *(*get_coroutine)(void *),
    4041        void *this
    4142) {
    42         // Finish setting up the coroutine by setting its state
    43         struct $coroutine * cor = __cfactx_cor_finish();
     43        struct coroutine_desc* cor = get_coroutine( this );
    4444
    45         // Call the main of the coroutine
     45        if(cor->state == Primed) {
     46                __suspend_internal();
     47        }
     48
     49        cor->state = Active;
     50
    4651        main( this );
    4752
    4853        //Final suspend, should never return
    49         __cfactx_cor_leave( cor );
     54        __leave_coroutine( cor );
    5055        __cabi_abort( "Resumed dead coroutine" );
    5156}
    5257
    53 static _Unwind_Reason_Code __cfactx_coroutine_unwindstop(
     58static _Unwind_Reason_Code _CtxCoroutine_UnwindStop(
    5459        __attribute((__unused__)) int version,
    5560        _Unwind_Action actions,
     
    6267                // We finished unwinding the coroutine,
    6368                // leave it
    64                 __cfactx_cor_leave( param );
     69                __leave_coroutine( param );
    6570                __cabi_abort( "Resumed dead coroutine" );
    6671        }
     
    7075}
    7176
    72 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) __attribute__ ((__noreturn__));
    73 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) {
    74         _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor );
     77void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__));
     78void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) {
     79        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor );
    7580        printf("UNWIND ERROR %d after force unwind\n", ret);
    7681        abort();
    7782}
    7883
    79 void __cfactx_invoke_thread(
     84void CtxInvokeThread(
     85        void (*dtor)(void *),
    8086        void (*main)(void *),
     87        struct thread_desc *(*get_thread)(void *),
    8188        void *this
    8289) {
     90        // Fetch the thread handle from the user defined thread structure
     91        struct thread_desc* thrd = get_thread( this );
     92
     93        // First suspend, once the thread arrives here,
     94        // the function pointer to main can be invalidated without risk
     95        __finish_creation( thrd );
     96
    8397        // Officially start the thread by enabling preemption
    8498        enable_interrupts( __cfaabi_dbg_ctx );
     
    94108        // The order of these 4 operations is very important
    95109        //Final suspend, should never return
    96         __cfactx_thrd_leave();
     110        __leave_thread_monitor( thrd );
    97111        __cabi_abort( "Resumed dead thread" );
    98112}
    99113
    100 void __cfactx_start(
     114
     115void CtxStart(
    101116        void (*main)(void *),
    102         struct $coroutine * cor,
     117        struct coroutine_desc *(*get_coroutine)(void *),
    103118        void *this,
    104119        void (*invoke)(void *)
    105120) {
     121        struct coroutine_desc * cor = get_coroutine( this );
    106122        struct __stack_t * stack = cor->stack.storage;
    107123
     
    122138
    123139        fs->dummyReturn = NULL;
    124         fs->argument[0] = main;     // argument to invoke
    125         fs->argument[1] = this;     // argument to invoke
     140        fs->argument[0] = this;     // argument to invoke
    126141        fs->rturn = invoke;
    127142
     
    140155
    141156        fs->dummyReturn = NULL;
    142         fs->rturn = __cfactx_invoke_stub;
    143         fs->fixedRegisters[0] = main;
    144         fs->fixedRegisters[1] = this;
    145         fs->fixedRegisters[2] = invoke;
     157        fs->rturn = CtxInvokeStub;
     158        fs->fixedRegisters[0] = this;
     159        fs->fixedRegisters[1] = invoke;
    146160
    147161#elif defined( __ARM_ARCH )
    148 #error ARM needs to be upgrade to use to parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
     162
    149163        struct FakeStack {
    150164                float fpRegs[16];                       // floating point registers
     
    158172        struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    159173
    160         fs->intRegs[8] = __cfactx_invoke_stub;
     174        fs->intRegs[8] = CtxInvokeStub;
    161175        fs->arg[0] = this;
    162176        fs->arg[1] = invoke;
  • libcfa/src/concurrency/invoke.h

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Dec  5 16:26:03 2019
    13 // Update Count     : 44
     12// Last Modified On : Sat Jun 22 18:19:13 2019
     13// Update Count     : 40
    1414//
    1515
     
    4747        extern "Cforall" {
    4848                extern __attribute__((aligned(128))) thread_local struct KernelThreadData {
    49                         struct $thread    * volatile this_thread;
     49                        struct thread_desc    * volatile this_thread;
    5050                        struct processor      * volatile this_processor;
    5151
     
    9292        };
    9393
    94         enum coroutine_state { Halted, Start, Primed, Blocked, Ready, Active, Rerun };
    95         enum __Preemption_Reason { __NO_PREEMPTION, __ALARM_PREEMPTION, __POLL_PREEMPTION, __MANUAL_PREEMPTION };
    96 
    97         struct $coroutine {
    98                 // context that is switch during a __cfactx_switch
     94        enum coroutine_state { Halted, Start, Inactive, Active, Primed };
     95
     96        struct coroutine_desc {
     97                // context that is switch during a CtxSwitch
    9998                struct __stack_context_t context;
    10099
     
    109108
    110109                // first coroutine to resume this one
    111                 struct $coroutine * starter;
     110                struct coroutine_desc * starter;
    112111
    113112                // last coroutine to resume this one
    114                 struct $coroutine * last;
     113                struct coroutine_desc * last;
    115114
    116115                // If non-null stack must be unwound with this exception
     
    118117
    119118        };
    120 
    121         static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); }
    122119
    123120        // struct which calls the monitor is accepting
     
    130127        };
    131128
    132         struct $monitor {
     129        struct monitor_desc {
    133130                // spinlock to protect internal data
    134131                struct __spinlock_t lock;
    135132
    136133                // current owner of the monitor
    137                 struct $thread * owner;
     134                struct thread_desc * owner;
    138135
    139136                // queue of threads that are blocked waiting for the monitor
    140                 __queue_t(struct $thread) entry_queue;
     137                __queue_t(struct thread_desc) entry_queue;
    141138
    142139                // stack of conditions to run next once we exit the monitor
     
    155152        struct __monitor_group_t {
    156153                // currently held monitors
    157                 __cfa_anonymous_object( __small_array_t($monitor*) );
     154                __cfa_anonymous_object( __small_array_t(monitor_desc*) );
    158155
    159156                // last function that acquired monitors
     
    161158        };
    162159
    163         struct $thread {
     160        struct thread_desc {
    164161                // Core threading fields
    165                 // context that is switch during a __cfactx_switch
     162                // context that is switch during a CtxSwitch
    166163                struct __stack_context_t context;
    167164
    168165                // current execution status for coroutine
    169                 volatile int state;
    170                 enum __Preemption_Reason preempted;
     166                enum coroutine_state state;
    171167
    172168                //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it
    173169
    174170                // coroutine body used to store context
    175                 struct $coroutine  self_cor;
     171                struct coroutine_desc  self_cor;
    176172
    177173                // current active context
    178                 struct $coroutine * curr_cor;
     174                struct coroutine_desc * curr_cor;
    179175
    180176                // monitor body used for mutual exclusion
    181                 struct $monitor    self_mon;
     177                struct monitor_desc    self_mon;
    182178
    183179                // pointer to monitor with sufficient lifetime for current monitors
    184                 struct $monitor *  self_mon_p;
     180                struct monitor_desc *  self_mon_p;
    185181
    186182                // pointer to the cluster on which the thread is running
     
    192188                // Link lists fields
    193189                // instrusive link field for threads
    194                 struct $thread * next;
     190                struct thread_desc * next;
    195191
    196192                struct {
    197                         struct $thread * next;
    198                         struct $thread * prev;
     193                        struct thread_desc * next;
     194                        struct thread_desc * prev;
    199195                } node;
    200 
    201                 #ifdef __CFA_DEBUG__
    202                         // previous function to park/unpark the thread
    203                         const char * park_caller;
    204                         enum coroutine_state park_result;
    205                         bool park_stale;
    206                         const char * unpark_caller;
    207                         enum coroutine_state unpark_result;
    208                         bool unpark_stale;
    209                 #endif
    210         };
    211 
    212         #ifdef __CFA_DEBUG__
    213                 void __cfaabi_dbg_record_thrd($thread & this, bool park, const char prev_name[]);
    214         #else
    215                 #define __cfaabi_dbg_record_thrd(x, y, z)
    216         #endif
     196        };
    217197
    218198        #ifdef __cforall
    219199        extern "Cforall" {
    220                 static inline $thread *& get_next( $thread & this ) __attribute__((const)) {
     200                static inline thread_desc *& get_next( thread_desc & this ) {
    221201                        return this.next;
    222202                }
    223203
    224                 static inline [$thread *&, $thread *& ] __get( $thread & this ) __attribute__((const)) {
     204                static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) {
    225205                        return this.node.[next, prev];
    226206                }
    227207
    228208                static inline void ?{}(__monitor_group_t & this) {
    229                         (this.data){0p};
     209                        (this.data){NULL};
    230210                        (this.size){0};
    231211                        (this.func){NULL};
    232212                }
    233213
    234                 static inline void ?{}(__monitor_group_t & this, struct $monitor ** data, __lock_size_t size, fptr_t func) {
     214                static inline void ?{}(__monitor_group_t & this, struct monitor_desc ** data, __lock_size_t size, fptr_t func) {
    235215                        (this.data){data};
    236216                        (this.size){size};
     
    238218                }
    239219
    240                 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) __attribute__((const)) {
     220                static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) {
    241221                        if( (lhs.data != 0) != (rhs.data != 0) ) return false;
    242222                        if( lhs.size != rhs.size ) return false;
     
    272252
    273253        // assembler routines that performs the context switch
    274         extern void __cfactx_invoke_stub( void );
    275         extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
     254        extern void CtxInvokeStub( void );
     255        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    276256        // void CtxStore ( void * this ) asm ("CtxStore");
    277257        // void CtxRet   ( void * dst  ) asm ("CtxRet");
  • libcfa/src/concurrency/kernel.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:15 2020
    13 // Update Count     : 58
     12// Last Modified On : Thu Jun 20 17:21:23 2019
     13// Update Count     : 25
    1414//
    1515
     
    2626#include <signal.h>
    2727#include <unistd.h>
    28 #include <limits.h>                                                                             // PTHREAD_STACK_MIN
    29 #include <sys/mman.h>                                                                   // mprotect
    3028}
    3129
     
    4240//-----------------------------------------------------------------------------
    4341// Some assembly required
    44 #if defined( __i386 )
     42#if   defined( __i386 )
    4543        #define CtxGet( ctx )        \
    4644                __asm__ volatile (     \
     
    110108//-----------------------------------------------------------------------------
    111109//Start and stop routine for the kernel, declared first to make sure they run first
    112 static void __kernel_startup (void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
    113 static void __kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
    114 
    115 //-----------------------------------------------------------------------------
    116 // Kernel Scheduling logic
    117 static $thread * __next_thread(cluster * this);
    118 static void __run_thread(processor * this, $thread * dst);
    119 static $thread * __halt(processor * this);
    120 static bool __wake_one(cluster * cltr, bool was_empty);
    121 static bool __wake_proc(processor *);
     110static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     111static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
    122112
    123113//-----------------------------------------------------------------------------
     
    125115KERNEL_STORAGE(cluster,         mainCluster);
    126116KERNEL_STORAGE(processor,       mainProcessor);
    127 KERNEL_STORAGE($thread, mainThread);
     117KERNEL_STORAGE(thread_desc,     mainThread);
    128118KERNEL_STORAGE(__stack_t,       mainThreadCtx);
    129119
    130120cluster     * mainCluster;
    131121processor   * mainProcessor;
    132 $thread * mainThread;
     122thread_desc * mainThread;
    133123
    134124extern "C" {
    135         struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
     125struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
    136126}
    137127
     
    141131// Global state
    142132thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = {
    143         NULL,                                                                                           // cannot use 0p
     133        NULL,
    144134        NULL,
    145135        { 1, false, false },
     
    150140// Struct to steal stack
    151141struct current_stack_info_t {
    152         __stack_t * storage;                                                            // pointer to stack object
    153         void * base;                                                                            // base of stack
    154         void * limit;                                                                           // stack grows towards stack limit
    155         void * context;                                                                         // address of cfa_context_t
     142        __stack_t * storage;            // pointer to stack object
     143        void *base;                             // base of stack
     144        void *limit;                    // stack grows towards stack limit
     145        void *context;                  // address of cfa_context_t
    156146};
    157147
     
    172162// Main thread construction
    173163
    174 void ?{}( $coroutine & this, current_stack_info_t * info) with( this ) {
     164void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
    175165        stack.storage = info->storage;
    176166        with(*stack.storage) {
     
    182172        name = "Main Thread";
    183173        state = Start;
    184         starter = 0p;
    185         last = 0p;
    186         cancellation = 0p;
    187 }
    188 
    189 void ?{}( $thread & this, current_stack_info_t * info) with( this ) {
     174        starter = NULL;
     175        last = NULL;
     176        cancellation = NULL;
     177}
     178
     179void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
    190180        state = Start;
    191181        self_cor{ info };
     
    195185        self_mon.recursion = 1;
    196186        self_mon_p = &self_mon;
    197         next = 0p;
    198 
    199         node.next = 0p;
    200         node.prev = 0p;
     187        next = NULL;
     188
     189        node.next = NULL;
     190        node.prev = NULL;
    201191        doregister(curr_cluster, this);
    202192
     
    216206}
    217207
    218 static void * __invoke_processor(void * arg);
    219 
    220 void ?{}(processor & this, const char name[], cluster & cltr) with( this ) {
     208static void start(processor * this);
     209void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
    221210        this.name = name;
    222211        this.cltr = &cltr;
    223212        terminated{ 0 };
    224         destroyer = 0p;
    225213        do_terminate = false;
    226         preemption_alarm = 0p;
     214        preemption_alarm = NULL;
    227215        pending_preemption = false;
    228216        runner.proc = &this;
    229217
    230         idle{};
    231 
    232         __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", &this);
    233 
    234         this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this );
    235 
    236         __cfaabi_dbg_print_safe("Kernel : core %p started\n", &this);
     218        idleLock{};
     219
     220        start( &this );
    237221}
    238222
     
    242226
    243227                __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
    244                 __wake_proc( &this );
     228                wake( &this );
    245229
    246230                P( terminated );
     
    248232        }
    249233
    250         pthread_join( kernel_thread, 0p );
    251         free( this.stack );
    252 }
    253 
    254 void ?{}(cluster & this, const char name[], Duration preemption_rate) with( this ) {
     234        pthread_join( kernel_thread, NULL );
     235}
     236
     237void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {
    255238        this.name = name;
    256239        this.preemption_rate = preemption_rate;
     
    272255// Kernel Scheduling logic
    273256//=============================================================================================
     257static void runThread(processor * this, thread_desc * dst);
     258static void finishRunning(processor * this);
     259static void halt(processor * this);
     260
    274261//Main of the processor contexts
    275262void main(processorCtx_t & runner) {
     
    291278                __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
    292279
    293                 $thread * readyThread = 0p;
    294                 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ ) {
    295                         // Try to get the next thread
    296                         readyThread = __next_thread( this->cltr );
    297 
    298                         // If no ready thread
    299                         if( readyThread == 0p ) {
    300                                 // Block until a thread is ready
    301                                 readyThread = __halt(this);
     280                thread_desc * readyThread = NULL;
     281                for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ )
     282                {
     283                        readyThread = nextThread( this->cltr );
     284
     285                        if(readyThread)
     286                        {
     287                                verify( ! kernelTLS.preemption_state.enabled );
     288
     289                                runThread(this, readyThread);
     290
     291                                verify( ! kernelTLS.preemption_state.enabled );
     292
     293                                //Some actions need to be taken from the kernel
     294                                finishRunning(this);
     295
     296                                spin_count = 0;
    302297                        }
    303 
    304                         // Check if we actually found a thread
    305                         if( readyThread ) {
    306                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    307                                 /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted);
    308                                 /* paranoid */ verifyf( readyThread->next == 0p, "Expected null got %p", readyThread->next );
    309 
    310                                 // We found a thread run it
    311                                 __run_thread(this, readyThread);
    312 
    313                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     298                        else
     299                        {
     300                                // spin(this, &spin_count);
     301                                halt(this);
    314302                        }
    315303                }
     
    323311
    324312        __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
    325 
    326         // HACK : the coroutine context switch expects this_thread to be set
    327         // and it make sense for it to be set in all other cases except here
    328         // fake it
    329         if( this == mainProcessor ) kernelTLS.this_thread = mainThread;
    330313}
    331314
     
    336319// runThread runs a thread by context switching
    337320// from the processor coroutine to the target thread
    338 static void __run_thread(processor * this, $thread * thrd_dst) {
    339         $coroutine * proc_cor = get_coroutine(this->runner);
     321static void runThread(processor * this, thread_desc * thrd_dst) {
     322        coroutine_desc * proc_cor = get_coroutine(this->runner);
     323
     324        // Reset the terminating actions here
     325        this->finish.action_code = No_Action;
    340326
    341327        // Update global state
    342328        kernelTLS.this_thread = thrd_dst;
    343329
    344         // set state of processor coroutine to inactive
    345         verify(proc_cor->state == Active);
    346         proc_cor->state = Blocked;
    347 
    348         // Actually run the thread
    349         RUNNING:  while(true) {
    350                 if(unlikely(thrd_dst->preempted)) {
    351                         thrd_dst->preempted = __NO_PREEMPTION;
    352                         verify(thrd_dst->state == Active  || thrd_dst->state == Rerun);
    353                 } else {
    354                         verify(thrd_dst->state == Blocked || thrd_dst->state == Ready); // Ready means scheduled normally, blocked means rerun
    355                         thrd_dst->state = Active;
     330        // set state of processor coroutine to inactive and the thread to active
     331        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
     332        thrd_dst->state = Active;
     333
     334        // set context switch to the thread that the processor is executing
     335        verify( thrd_dst->context.SP );
     336        CtxSwitch( &proc_cor->context, &thrd_dst->context );
     337        // when CtxSwitch returns we are back in the processor coroutine
     338
     339        // set state of processor coroutine to active and the thread to inactive
     340        thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive;
     341        proc_cor->state = Active;
     342}
     343
     344// KERNEL_ONLY
     345static void returnToKernel() {
     346        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
     347        thread_desc * thrd_src = kernelTLS.this_thread;
     348
     349        // set state of current coroutine to inactive
     350        thrd_src->state = thrd_src->state == Halted ? Halted : Inactive;
     351        proc_cor->state = Active;
     352        int local_errno = *__volatile_errno();
     353        #if defined( __i386 ) || defined( __x86_64 )
     354                __x87_store;
     355        #endif
     356
     357        // set new coroutine that the processor is executing
     358        // and context switch to it
     359        verify( proc_cor->context.SP );
     360        CtxSwitch( &thrd_src->context, &proc_cor->context );
     361
     362        // set state of new coroutine to active
     363        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
     364        thrd_src->state = Active;
     365
     366        #if defined( __i386 ) || defined( __x86_64 )
     367                __x87_load;
     368        #endif
     369        *__volatile_errno() = local_errno;
     370}
     371
     372// KERNEL_ONLY
     373// Once a thread has finished running, some of
     374// its final actions must be executed from the kernel
     375static void finishRunning(processor * this) with( this->finish ) {
     376        verify( ! kernelTLS.preemption_state.enabled );
     377        choose( action_code ) {
     378        case No_Action:
     379                break;
     380        case Release:
     381                unlock( *lock );
     382        case Schedule:
     383                ScheduleThread( thrd );
     384        case Release_Schedule:
     385                unlock( *lock );
     386                ScheduleThread( thrd );
     387        case Release_Multi:
     388                for(int i = 0; i < lock_count; i++) {
     389                        unlock( *locks[i] );
    356390                }
    357 
    358                 __cfaabi_dbg_debug_do(
    359                         thrd_dst->park_stale   = true;
    360                         thrd_dst->unpark_stale = true;
    361                 )
    362 
    363                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    364                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor
    365                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor
    366 
    367                 // set context switch to the thread that the processor is executing
    368                 verify( thrd_dst->context.SP );
    369                 __cfactx_switch( &proc_cor->context, &thrd_dst->context );
    370                 // when __cfactx_switch returns we are back in the processor coroutine
    371 
    372                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst );
    373                 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst );
    374                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    375 
    376 
    377                 // We just finished running a thread, there are a few things that could have happened.
    378                 // 1 - Regular case : the thread has blocked and now one has scheduled it yet.
    379                 // 2 - Racy case    : the thread has blocked but someone has already tried to schedule it.
    380                 // 4 - Preempted
    381                 // In case 1, we may have won a race so we can't write to the state again.
    382                 // In case 2, we lost the race so we now own the thread.
    383 
    384                 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    385                         // The thread was preempted, reschedule it and reset the flag
    386                         __schedule_thread( thrd_dst );
    387                         break RUNNING;
     391        case Release_Multi_Schedule:
     392                for(int i = 0; i < lock_count; i++) {
     393                        unlock( *locks[i] );
    388394                }
    389 
    390                 // set state of processor coroutine to active and the thread to inactive
    391                 static_assert(sizeof(thrd_dst->state) == sizeof(int));
    392                 enum coroutine_state old_state = __atomic_exchange_n(&thrd_dst->state, Blocked, __ATOMIC_SEQ_CST);
    393                 __cfaabi_dbg_debug_do( thrd_dst->park_result = old_state; )
    394                 switch(old_state) {
    395                         case Halted:
    396                                 // The thread has halted, it should never be scheduled/run again, leave it back to Halted and move on
    397                                 thrd_dst->state = Halted;
    398 
    399                                 // We may need to wake someone up here since
    400                                 unpark( this->destroyer __cfaabi_dbg_ctx2 );
    401                                 this->destroyer = 0p;
    402                                 break RUNNING;
    403                         case Active:
    404                                 // This is case 1, the regular case, nothing more is needed
    405                                 break RUNNING;
    406                         case Rerun:
    407                                 // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    408                                 // In this case, just run it again.
    409                                 continue RUNNING;
    410                         default:
    411                                 // This makes no sense, something is wrong abort
    412                                 abort("Finished running a thread that was Blocked/Start/Primed %d\n", old_state);
     395                for(int i = 0; i < thrd_count; i++) {
     396                        ScheduleThread( thrds[i] );
    413397                }
    414         }
    415 
    416         // Just before returning to the processor, set the processor coroutine to active
    417         proc_cor->state = Active;
    418         kernelTLS.this_thread = 0p;
    419 }
    420 
    421 // KERNEL_ONLY
    422 void returnToKernel() {
    423         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    424         $coroutine * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
    425         $thread * thrd_src = kernelTLS.this_thread;
    426 
    427         // Run the thread on this processor
    428         {
    429                 int local_errno = *__volatile_errno();
    430                 #if defined( __i386 ) || defined( __x86_64 )
    431                         __x87_store;
    432                 #endif
    433                 verify( proc_cor->context.SP );
    434                 __cfactx_switch( &thrd_src->context, &proc_cor->context );
    435                 #if defined( __i386 ) || defined( __x86_64 )
    436                         __x87_load;
    437                 #endif
    438                 *__volatile_errno() = local_errno;
    439         }
    440 
    441         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    442         /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too small.\n", thrd_src );
    443         /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too large.\n", thrd_src );
     398        case Callback:
     399                callback();
     400        default:
     401                abort("KERNEL ERROR: Unexpected action to run after thread");
     402        }
    444403}
    445404
     
    448407// This is the entry point for processors (kernel threads)
    449408// It effectively constructs a coroutine by stealing the pthread stack
    450 static void * __invoke_processor(void * arg) {
     409static void * CtxInvokeProcessor(void * arg) {
    451410        processor * proc = (processor *) arg;
    452411        kernelTLS.this_processor = proc;
    453         kernelTLS.this_thread    = 0p;
     412        kernelTLS.this_thread    = NULL;
    454413        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
    455414        // SKULLDUGGERY: We want to create a context for the processor coroutine
     
    464423
    465424        //Set global state
    466         kernelTLS.this_thread = 0p;
     425        kernelTLS.this_thread    = NULL;
    467426
    468427        //We now have a proper context from which to schedule threads
     
    480439        __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);
    481440
    482         return 0p;
    483 }
    484 
    485 static void Abort( int ret, const char func[] ) {
    486         if ( ret ) {                                                                            // pthread routines return errno values
    487                 abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) );
    488         } // if
    489 } // Abort
    490 
    491 void * __create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) {
    492         pthread_attr_t attr;
    493 
    494         Abort( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
    495 
    496         size_t stacksize;
    497         // default stack size, normally defined by shell limit
    498         Abort( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );
    499         assert( stacksize >= PTHREAD_STACK_MIN );
    500 
    501         void * stack;
    502         __cfaabi_dbg_debug_do(
    503                 stack = memalign( __page_size, stacksize + __page_size );
    504                 // pthread has no mechanism to create the guard page in user supplied stack.
    505                 if ( mprotect( stack, __page_size, PROT_NONE ) == -1 ) {
    506                         abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );
    507                 } // if
    508         );
    509         __cfaabi_dbg_no_debug_do(
    510                 stack = malloc( stacksize );
    511         );
    512 
    513         Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
    514 
    515         Abort( pthread_create( pthread, &attr, start, arg ), "pthread_create" );
    516         return stack;
     441        return NULL;
     442}
     443
     444static void start(processor * this) {
     445        __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
     446
     447        pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
     448
     449        __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
    517450}
    518451
    519452// KERNEL_ONLY
    520 static void __kernel_first_resume( processor * this ) {
    521         $thread * src = mainThread;
    522         $coroutine * dst = get_coroutine(this->runner);
    523 
    524         verify( ! kernelTLS.preemption_state.enabled );
    525 
    526         kernelTLS.this_thread->curr_cor = dst;
     453void kernel_first_resume( processor * this ) {
     454        thread_desc * src = mainThread;
     455        coroutine_desc * dst = get_coroutine(this->runner);
     456
     457        verify( ! kernelTLS.preemption_state.enabled );
     458
    527459        __stack_prepare( &dst->stack, 65000 );
    528         __cfactx_start(main, dst, this->runner, __cfactx_invoke_coroutine);
     460        CtxStart(&this->runner, CtxInvokeCoroutine);
    529461
    530462        verify( ! kernelTLS.preemption_state.enabled );
     
    533465        dst->starter = dst->starter ? dst->starter : &src->self_cor;
    534466
    535         // make sure the current state is still correct
    536         /* paranoid */ verify(src->state == Ready);
     467        // set state of current coroutine to inactive
     468        src->state = src->state == Halted ? Halted : Inactive;
    537469
    538470        // context switch to specified coroutine
    539471        verify( dst->context.SP );
    540         __cfactx_switch( &src->context, &dst->context );
    541         // when __cfactx_switch returns we are back in the src coroutine
    542 
    543         mainThread->curr_cor = &mainThread->self_cor;
    544 
    545         // make sure the current state has been update
    546         /* paranoid */ verify(src->state == Active);
     472        CtxSwitch( &src->context, &dst->context );
     473        // when CtxSwitch returns we are back in the src coroutine
     474
     475        // set state of new coroutine to active
     476        src->state = Active;
    547477
    548478        verify( ! kernelTLS.preemption_state.enabled );
     
    550480
    551481// KERNEL_ONLY
    552 static void __kernel_last_resume( processor * this ) {
    553         $coroutine * src = &mainThread->self_cor;
    554         $coroutine * dst = get_coroutine(this->runner);
     482void kernel_last_resume( processor * this ) {
     483        coroutine_desc * src = &mainThread->self_cor;
     484        coroutine_desc * dst = get_coroutine(this->runner);
    555485
    556486        verify( ! kernelTLS.preemption_state.enabled );
     
    558488        verify( dst->context.SP );
    559489
    560         // SKULLDUGGERY in debug the processors check that the
    561         // stack is still within the limit of the stack limits after running a thread.
    562         // that check doesn't make sense if we context switch to the processor using the
    563         // coroutine semantics. Since this is a special case, use the current context
    564         // info to populate these fields.
    565         __cfaabi_dbg_debug_do(
    566                 __stack_context_t ctx;
    567                 CtxGet( ctx );
    568                 mainThread->context.SP = ctx.SP;
    569                 mainThread->context.FP = ctx.FP;
    570         )
    571 
    572490        // context switch to the processor
    573         __cfactx_switch( &src->context, &dst->context );
     491        CtxSwitch( &src->context, &dst->context );
    574492}
    575493
    576494//-----------------------------------------------------------------------------
    577495// Scheduler routines
     496
    578497// KERNEL ONLY
    579 void __schedule_thread( $thread * thrd ) with( *thrd->curr_cluster ) {
    580         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    581         /* paranoid */ #if defined( __CFA_WITH_VERIFY__ )
    582         /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,
    583                           "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted );
    584         /* paranoid */ if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active || thrd->state == Rerun,
    585                           "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );
    586         /* paranoid */ #endif
    587         /* paranoid */ verifyf( thrd->next == 0p, "Expected null got %p", thrd->next );
    588 
    589         if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    590 
    591         lock  ( ready_queue_lock __cfaabi_dbg_ctx2 );
    592         bool was_empty = !(ready_queue != 0);
    593         append( ready_queue, thrd );
     498void ScheduleThread( thread_desc * thrd ) {
     499        verify( thrd );
     500        verify( thrd->state != Halted );
     501
     502        verify( ! kernelTLS.preemption_state.enabled );
     503
     504        verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
     505
     506        with( *thrd->curr_cluster ) {
     507                lock  ( ready_queue_lock __cfaabi_dbg_ctx2 );
     508                bool was_empty = !(ready_queue != 0);
     509                append( ready_queue, thrd );
     510                unlock( ready_queue_lock );
     511
     512                if(was_empty) {
     513                        lock      (proc_list_lock __cfaabi_dbg_ctx2);
     514                        if(idles) {
     515                                wake_fast(idles.head);
     516                        }
     517                        unlock    (proc_list_lock);
     518                }
     519                else if( struct processor * idle = idles.head ) {
     520                        wake_fast(idle);
     521                }
     522
     523        }
     524
     525        verify( ! kernelTLS.preemption_state.enabled );
     526}
     527
     528// KERNEL ONLY
     529thread_desc * nextThread(cluster * this) with( *this ) {
     530        verify( ! kernelTLS.preemption_state.enabled );
     531        lock( ready_queue_lock __cfaabi_dbg_ctx2 );
     532        thread_desc * head = pop_head( ready_queue );
    594533        unlock( ready_queue_lock );
    595 
    596         __wake_one(thrd->curr_cluster, was_empty);
    597 
    598         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     534        verify( ! kernelTLS.preemption_state.enabled );
     535        return head;
     536}
     537
     538void BlockInternal() {
     539        disable_interrupts();
     540        verify( ! kernelTLS.preemption_state.enabled );
     541        returnToKernel();
     542        verify( ! kernelTLS.preemption_state.enabled );
     543        enable_interrupts( __cfaabi_dbg_ctx );
     544}
     545
     546void BlockInternal( __spinlock_t * lock ) {
     547        disable_interrupts();
     548        with( *kernelTLS.this_processor ) {
     549                finish.action_code = Release;
     550                finish.lock        = lock;
     551        }
     552
     553        verify( ! kernelTLS.preemption_state.enabled );
     554        returnToKernel();
     555        verify( ! kernelTLS.preemption_state.enabled );
     556
     557        enable_interrupts( __cfaabi_dbg_ctx );
     558}
     559
     560void BlockInternal( thread_desc * thrd ) {
     561        disable_interrupts();
     562        with( * kernelTLS.this_processor ) {
     563                finish.action_code = Schedule;
     564                finish.thrd        = thrd;
     565        }
     566
     567        verify( ! kernelTLS.preemption_state.enabled );
     568        returnToKernel();
     569        verify( ! kernelTLS.preemption_state.enabled );
     570
     571        enable_interrupts( __cfaabi_dbg_ctx );
     572}
     573
     574void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) {
     575        assert(thrd);
     576        disable_interrupts();
     577        with( * kernelTLS.this_processor ) {
     578                finish.action_code = Release_Schedule;
     579                finish.lock        = lock;
     580                finish.thrd        = thrd;
     581        }
     582
     583        verify( ! kernelTLS.preemption_state.enabled );
     584        returnToKernel();
     585        verify( ! kernelTLS.preemption_state.enabled );
     586
     587        enable_interrupts( __cfaabi_dbg_ctx );
     588}
     589
     590void BlockInternal(__spinlock_t * locks [], unsigned short count) {
     591        disable_interrupts();
     592        with( * kernelTLS.this_processor ) {
     593                finish.action_code = Release_Multi;
     594                finish.locks       = locks;
     595                finish.lock_count  = count;
     596        }
     597
     598        verify( ! kernelTLS.preemption_state.enabled );
     599        returnToKernel();
     600        verify( ! kernelTLS.preemption_state.enabled );
     601
     602        enable_interrupts( __cfaabi_dbg_ctx );
     603}
     604
     605void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
     606        disable_interrupts();
     607        with( *kernelTLS.this_processor ) {
     608                finish.action_code = Release_Multi_Schedule;
     609                finish.locks       = locks;
     610                finish.lock_count  = lock_count;
     611                finish.thrds       = thrds;
     612                finish.thrd_count  = thrd_count;
     613        }
     614
     615        verify( ! kernelTLS.preemption_state.enabled );
     616        returnToKernel();
     617        verify( ! kernelTLS.preemption_state.enabled );
     618
     619        enable_interrupts( __cfaabi_dbg_ctx );
     620}
     621
     622void BlockInternal(__finish_callback_fptr_t callback) {
     623        disable_interrupts();
     624        with( *kernelTLS.this_processor ) {
     625                finish.action_code = Callback;
     626                finish.callback    = callback;
     627        }
     628
     629        verify( ! kernelTLS.preemption_state.enabled );
     630        returnToKernel();
     631        verify( ! kernelTLS.preemption_state.enabled );
     632
     633        enable_interrupts( __cfaabi_dbg_ctx );
    599634}
    600635
    601636// KERNEL ONLY
    602 static $thread * __next_thread(cluster * this) with( *this ) {
    603         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    604 
    605         lock( ready_queue_lock __cfaabi_dbg_ctx2 );
    606         $thread * head = pop_head( ready_queue );
    607         unlock( ready_queue_lock );
    608 
    609         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    610         return head;
    611 }
    612 
    613 void unpark( $thread * thrd __cfaabi_dbg_ctx_param2 ) {
    614         if( !thrd ) return;
    615 
    616         disable_interrupts();
    617         static_assert(sizeof(thrd->state) == sizeof(int));
    618 
    619         // record activity
    620         __cfaabi_dbg_record_thrd( *thrd, false, caller );
    621 
    622         enum coroutine_state old_state = __atomic_exchange_n(&thrd->state, Rerun, __ATOMIC_SEQ_CST);
    623         __cfaabi_dbg_debug_do( thrd->unpark_result = old_state; )
    624         switch(old_state) {
    625                 case Active:
    626                         // Wake won the race, the thread will reschedule/rerun itself
    627                         break;
    628                 case Blocked:
    629                         /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    630 
    631                         // Wake lost the race,
    632                         thrd->state = Blocked;
    633                         __schedule_thread( thrd );
    634                         break;
    635                 case Rerun:
    636                         abort("More than one thread attempted to schedule thread %p\n", thrd);
    637                         break;
    638                 case Halted:
    639                 case Start:
    640                 case Primed:
    641                 default:
    642                         // This makes no sense, something is wrong abort
    643                         abort();
    644         }
    645         enable_interrupts( __cfaabi_dbg_ctx );
    646 }
    647 
    648 void park( __cfaabi_dbg_ctx_param ) {
    649         /* paranoid */ verify( kernelTLS.preemption_state.enabled );
    650         disable_interrupts();
    651         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    652         /* paranoid */ verify( kernelTLS.this_thread->preempted == __NO_PREEMPTION );
    653 
    654         // record activity
    655         __cfaabi_dbg_record_thrd( *kernelTLS.this_thread, true, caller );
     637void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
     638        verify( ! kernelTLS.preemption_state.enabled );
     639        with( * kernelTLS.this_processor ) {
     640                finish.action_code = thrd ? Release_Schedule : Release;
     641                finish.lock        = lock;
     642                finish.thrd        = thrd;
     643        }
    656644
    657645        returnToKernel();
    658 
    659         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    660         enable_interrupts( __cfaabi_dbg_ctx );
    661         /* paranoid */ verify( kernelTLS.preemption_state.enabled );
    662 
    663 }
    664 
    665 // KERNEL ONLY
    666 void __leave_thread() {
    667         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    668         returnToKernel();
    669         abort();
    670 }
    671 
    672 // KERNEL ONLY
    673 bool force_yield( __Preemption_Reason reason ) {
    674         /* paranoid */ verify( kernelTLS.preemption_state.enabled );
    675         disable_interrupts();
    676         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    677 
    678         $thread * thrd = kernelTLS.this_thread;
    679         /* paranoid */ verify(thrd->state == Active || thrd->state == Rerun);
    680 
    681         // SKULLDUGGERY: It is possible that we are preempting this thread just before
    682         // it was going to park itself. If that is the case and it is already using the
    683         // intrusive fields then we can't use them to preempt the thread
    684         // If that is the case, abandon the preemption.
    685         bool preempted = false;
    686         if(thrd->next == 0p) {
    687                 preempted = true;
    688                 thrd->preempted = reason;
    689                 returnToKernel();
    690         }
    691 
    692         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    693         enable_interrupts_noPoll();
    694         /* paranoid */ verify( kernelTLS.preemption_state.enabled );
    695 
    696         return preempted;
    697646}
    698647
     
    702651//-----------------------------------------------------------------------------
    703652// Kernel boot procedures
    704 static void __kernel_startup(void) {
     653static void kernel_startup(void) {
    705654        verify( ! kernelTLS.preemption_state.enabled );
    706655        __cfaabi_dbg_print_safe("Kernel : Starting\n");
     
    720669        // SKULLDUGGERY: the mainThread steals the process main thread
    721670        // which will then be scheduled by the mainProcessor normally
    722         mainThread = ($thread *)&storage_mainThread;
     671        mainThread = (thread_desc *)&storage_mainThread;
    723672        current_stack_info_t info;
    724673        info.storage = (__stack_t*)&storage_mainThreadCtx;
     
    732681        void ?{}(processorCtx_t & this, processor * proc) {
    733682                (this.__cor){ "Processor" };
    734                 this.__cor.starter = 0p;
     683                this.__cor.starter = NULL;
    735684                this.proc = proc;
    736685        }
     
    741690                terminated{ 0 };
    742691                do_terminate = false;
    743                 preemption_alarm = 0p;
     692                preemption_alarm = NULL;
    744693                pending_preemption = false;
    745694                kernel_thread = pthread_self();
     
    763712        // Add the main thread to the ready queue
    764713        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    765         __schedule_thread(mainThread);
     714        ScheduleThread(mainThread);
    766715
    767716        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
    768         // context. Hence, the main thread does not begin through __cfactx_invoke_thread, like all other threads. The trick here is that
     717        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    769718        // mainThread is on the ready queue when this call is made.
    770         __kernel_first_resume( kernelTLS.this_processor );
     719        kernel_first_resume( kernelTLS.this_processor );
    771720
    772721
     
    780729}
    781730
    782 static void __kernel_shutdown(void) {
     731static void kernel_shutdown(void) {
    783732        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
    784733
    785         /* paranoid */ verify( TL_GET( preemption_state.enabled ) );
     734        verify( TL_GET( preemption_state.enabled ) );
    786735        disable_interrupts();
    787         /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     736        verify( ! kernelTLS.preemption_state.enabled );
    788737
    789738        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
     
    791740        // which is currently here
    792741        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
    793         __kernel_last_resume( kernelTLS.this_processor );
     742        kernel_last_resume( kernelTLS.this_processor );
    794743        mainThread->self_cor.state = Halted;
    795744
     
    801750        // Destroy the main processor and its context in reverse order of construction
    802751        // These were manually constructed so we need manually destroy them
    803         ^(*mainProcessor){};
     752        ^(mainProcessor->runner){};
     753        ^(mainProcessor){};
    804754
    805755        // Final step, destroy the main thread since it is no longer needed
    806756        // Since we provided a stack to this taxk it will not destroy anything
    807         /* paranoid */ verify(mainThread->self_cor.stack.storage == (__stack_t*)(((uintptr_t)&storage_mainThreadCtx)| 0x1));
    808         ^(*mainThread){};
     757        ^(mainThread){};
    809758
    810759        ^(__cfa_dbg_global_clusters.list){};
     
    815764
    816765//=============================================================================================
    817 // Kernel Idle Sleep
     766// Kernel Quiescing
    818767//=============================================================================================
    819 static $thread * __halt(processor * this) with( *this ) {
    820         if( do_terminate ) return 0p;
    821 
    822         // First, lock the cluster idle
    823         lock( cltr->idle_lock __cfaabi_dbg_ctx2 );
    824 
    825         // Check if we can find a thread
    826         if( $thread * found = __next_thread( cltr ) ) {
    827                 unlock( cltr->idle_lock );
    828                 return found;
    829         }
    830 
    831         // Move this processor from the active list to the idle list
    832         move_to_front(cltr->procs, cltr->idles, *this);
    833 
    834         // Unlock the idle lock so we don't go to sleep with a lock
    835         unlock    (cltr->idle_lock);
    836 
    837         // We are ready to sleep
     768static void halt(processor * this) with( *this ) {
     769        // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
     770
     771        with( *cltr ) {
     772                lock      (proc_list_lock __cfaabi_dbg_ctx2);
     773                remove    (procs, *this);
     774                push_front(idles, *this);
     775                unlock    (proc_list_lock);
     776        }
     777
    838778        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
    839         wait( idle );
    840 
    841         // We have woken up
     779
     780        wait( idleLock );
     781
    842782        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
    843783
    844         // Get ourself off the idle list
    845784        with( *cltr ) {
    846                 lock  (idle_lock __cfaabi_dbg_ctx2);
    847                 move_to_front(idles, procs, *this);
    848                 unlock(idle_lock);
    849         }
    850 
    851         // Don't check the ready queue again, we may not be in a position to run a thread
    852         return 0p;
    853 }
    854 
    855 // Wake a thread from the front if there are any
    856 static bool __wake_one(cluster * this, __attribute__((unused)) bool force) {
    857         // if we don't want to force check if we know it's false
    858         if( !this->idles.head && !force ) return false;
    859 
    860         // First, lock the cluster idle
    861         lock( this->idle_lock __cfaabi_dbg_ctx2 );
    862 
    863         // Check if there is someone to wake up
    864         if( !this->idles.head ) {
    865                 // Nope unlock and return false
    866                 unlock( this->idle_lock );
    867                 return false;
    868         }
    869 
    870         // Wake them up
    871         post( this->idles.head->idle );
    872 
    873         // Unlock and return true
    874         unlock( this->idle_lock );
    875         return true;
    876 }
    877 
    878 // Unconditionnaly wake a thread
    879 static bool __wake_proc(processor * this) {
    880         return post( this->idle );
     785                lock      (proc_list_lock __cfaabi_dbg_ctx2);
     786                remove    (idles, *this);
     787                push_front(procs, *this);
     788                unlock    (proc_list_lock);
     789        }
    881790}
    882791
     
    899808                sigemptyset( &mask );
    900809                sigaddset( &mask, SIGALRM );            // block SIGALRM signals
    901                 sigaddset( &mask, SIGUSR1 );            // block SIGALRM signals
    902                 sigsuspend( &mask );                            // block the processor to prevent further damage during abort
    903                 _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it
     810                sigsuspend( &mask );                    // block the processor to prevent further damage during abort
     811                _exit( EXIT_FAILURE );                  // if processor unblocks before it is killed, terminate it
    904812        }
    905813        else {
     
    912820
    913821void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
    914         $thread * thrd = kernel_data;
     822        thread_desc * thrd = kernel_data;
    915823
    916824        if(thrd) {
    917825                int len = snprintf( abort_text, abort_text_size, "Error occurred while executing thread %.256s (%p)", thrd->self_cor.name, thrd );
    918                 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
     826                __cfaabi_dbg_bits_write( abort_text, len );
    919827
    920828                if ( &thrd->self_cor != thrd->curr_cor ) {
    921829                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
    922                         __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
     830                        __cfaabi_dbg_bits_write( abort_text, len );
    923831                }
    924832                else {
    925                         __cfaabi_bits_write( STDERR_FILENO, ".\n", 2 );
     833                        __cfaabi_dbg_bits_write( ".\n", 2 );
    926834                }
    927835        }
    928836        else {
    929837                int len = snprintf( abort_text, abort_text_size, "Error occurred outside of any thread.\n" );
    930                 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
     838                __cfaabi_dbg_bits_write( abort_text, len );
    931839        }
    932840}
     
    939847
    940848extern "C" {
    941         void __cfaabi_bits_acquire() {
     849        void __cfaabi_dbg_bits_acquire() {
    942850                lock( kernel_debug_lock __cfaabi_dbg_ctx2 );
    943851        }
    944852
    945         void __cfaabi_bits_release() {
     853        void __cfaabi_dbg_bits_release() {
    946854                unlock( kernel_debug_lock );
    947855        }
     
    968876
    969877                // atomically release spin lock and block
    970                 unlock( lock );
    971                 park( __cfaabi_dbg_ctx );
     878                BlockInternal( &lock );
    972879        }
    973880        else {
     
    976883}
    977884
    978 bool V(semaphore & this) with( this ) {
    979         $thread * thrd = 0p;
     885void V(semaphore & this) with( this ) {
     886        thread_desc * thrd = NULL;
    980887        lock( lock __cfaabi_dbg_ctx2 );
    981888        count += 1;
     
    988895
    989896        // make new owner
    990         unpark( thrd __cfaabi_dbg_ctx2 );
    991 
    992         return thrd != 0p;
     897        WakeThread( thrd );
    993898}
    994899
     
    1007912}
    1008913
    1009 void doregister( cluster * cltr, $thread & thrd ) {
     914void doregister( cluster * cltr, thread_desc & thrd ) {
    1010915        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    1011916        cltr->nthreads += 1;
     
    1014919}
    1015920
    1016 void unregister( cluster * cltr, $thread & thrd ) {
     921void unregister( cluster * cltr, thread_desc & thrd ) {
    1017922        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    1018923        remove(cltr->threads, thrd );
     
    1022927
    1023928void doregister( cluster * cltr, processor * proc ) {
    1024         lock      (cltr->idle_lock __cfaabi_dbg_ctx2);
     929        lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
    1025930        cltr->nprocessors += 1;
    1026931        push_front(cltr->procs, *proc);
    1027         unlock    (cltr->idle_lock);
     932        unlock    (cltr->proc_list_lock);
    1028933}
    1029934
    1030935void unregister( cluster * cltr, processor * proc ) {
    1031         lock  (cltr->idle_lock __cfaabi_dbg_ctx2);
     936        lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
    1032937        remove(cltr->procs, *proc );
    1033938        cltr->nprocessors -= 1;
    1034         unlock(cltr->idle_lock);
     939        unlock(cltr->proc_list_lock);
    1035940}
    1036941
     
    1039944__cfaabi_dbg_debug_do(
    1040945        extern "C" {
    1041                 void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]) {
     946                void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
    1042947                        this.prev_name = prev_name;
    1043948                        this.prev_thrd = kernelTLS.this_thread;
    1044949                }
    1045 
    1046                 void __cfaabi_dbg_record_thrd($thread & this, bool park, const char prev_name[]) {
    1047                         if(park) {
    1048                                 this.park_caller   = prev_name;
    1049                                 this.park_stale    = false;
    1050                         }
    1051                         else {
    1052                                 this.unpark_caller = prev_name;
    1053                                 this.unpark_stale  = false;
    1054                         }
    1055                 }
    1056950        }
    1057951)
     
    1059953//-----------------------------------------------------------------------------
    1060954// Debug
    1061 bool threading_enabled(void) __attribute__((const)) {
     955bool threading_enabled(void) {
    1062956        return true;
    1063957}
  • libcfa/src/concurrency/kernel.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:26 2020
    13 // Update Count     : 22
     12// Last Modified On : Sat Jun 22 11:39:17 2019
     13// Update Count     : 16
    1414//
    1515
     
    2020#include "invoke.h"
    2121#include "time_t.hfa"
    22 #include "coroutine.hfa"
    2322
    2423extern "C" {
     
    3231        __spinlock_t lock;
    3332        int count;
    34         __queue_t($thread) waiting;
     33        __queue_t(thread_desc) waiting;
    3534};
    3635
     
    3837void ^?{}(semaphore & this);
    3938void   P (semaphore & this);
    40 bool   V (semaphore & this);
     39void   V (semaphore & this);
    4140
    4241
     
    4443// Processor
    4544extern struct cluster * mainCluster;
     45
     46enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback };
     47
     48typedef void (*__finish_callback_fptr_t)(void);
     49
     50//TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI)
     51struct FinishAction {
     52        FinishOpCode action_code;
     53        /*
     54        // Union of possible actions
     55        union {
     56                // Option 1 : locks and threads
     57                struct {
     58                        // 1 thread or N thread
     59                        union {
     60                                thread_desc * thrd;
     61                                struct {
     62                                        thread_desc ** thrds;
     63                                        unsigned short thrd_count;
     64                                };
     65                        };
     66                        // 1 lock or N lock
     67                        union {
     68                                __spinlock_t * lock;
     69                                struct {
     70                                        __spinlock_t ** locks;
     71                                        unsigned short lock_count;
     72                                };
     73                        };
     74                };
     75                // Option 2 : action pointer
     76                __finish_callback_fptr_t callback;
     77        };
     78        /*/
     79        thread_desc * thrd;
     80        thread_desc ** thrds;
     81        unsigned short thrd_count;
     82        __spinlock_t * lock;
     83        __spinlock_t ** locks;
     84        unsigned short lock_count;
     85        __finish_callback_fptr_t callback;
     86        //*/
     87};
     88static inline void ?{}(FinishAction & this) {
     89        this.action_code = No_Action;
     90        this.thrd = NULL;
     91        this.lock = NULL;
     92}
     93static inline void ^?{}(FinishAction &) {}
    4694
    4795// Processor
     
    67115        // RunThread data
    68116        // Action to do after a thread is ran
    69         $thread * destroyer;
     117        struct FinishAction finish;
    70118
    71119        // Preemption data
     
    76124        bool pending_preemption;
    77125
    78         // Idle lock (kernel semaphore)
    79         __bin_sem_t idle;
     126        // Idle lock
     127        __bin_sem_t idleLock;
    80128
    81129        // Termination
     
    83131        volatile bool do_terminate;
    84132
    85         // Termination synchronisation (user semaphore)
     133        // Termination synchronisation
    86134        semaphore terminated;
    87 
    88         // pthread Stack
    89         void * stack;
    90135
    91136        // Link lists fields
     
    101146};
    102147
    103 void  ?{}(processor & this, const char name[], struct cluster & cltr);
     148void  ?{}(processor & this, const char * name, struct cluster & cltr);
    104149void ^?{}(processor & this);
    105150
    106151static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
    107152static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
    108 static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    109 
    110 static inline [processor *&, processor *& ] __get( processor & this ) __attribute__((const)) { return this.node.[next, prev]; }
     153static inline void  ?{}(processor & this, const char * name) { this{name, *mainCluster }; }
     154
     155static inline [processor *&, processor *& ] __get( processor & this ) {
     156        return this.node.[next, prev];
     157}
    111158
    112159//-----------------------------------------------------------------------------
     
    117164
    118165        // Ready queue for threads
    119         __queue_t($thread) ready_queue;
     166        __queue_t(thread_desc) ready_queue;
    120167
    121168        // Name of the cluster
     
    126173
    127174        // List of processors
    128         __spinlock_t idle_lock;
     175        __spinlock_t proc_list_lock;
    129176        __dllist_t(struct processor) procs;
    130177        __dllist_t(struct processor) idles;
     
    133180        // List of threads
    134181        __spinlock_t thread_list_lock;
    135         __dllist_t(struct $thread) threads;
     182        __dllist_t(struct thread_desc) threads;
    136183        unsigned int nthreads;
    137184
     
    144191extern Duration default_preemption();
    145192
    146 void ?{} (cluster & this, const char name[], Duration preemption_rate);
     193void ?{} (cluster & this, const char * name, Duration preemption_rate);
    147194void ^?{}(cluster & this);
    148195
    149196static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
    150197static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
    151 static inline void ?{} (cluster & this, const char name[])        { this{name, default_preemption()}; }
    152 
    153 static inline [cluster *&, cluster *& ] __get( cluster & this ) __attribute__((const)) { return this.node.[next, prev]; }
     198static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
     199
     200static inline [cluster *&, cluster *& ] __get( cluster & this ) {
     201        return this.node.[next, prev];
     202}
    154203
    155204static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE
  • libcfa/src/concurrency/kernel_private.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Feb 13 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Nov 30 19:25:02 2019
    13 // Update Count     : 8
     12// Last Modified On : Thu Mar 29 14:06:40 2018
     13// Update Count     : 3
    1414//
    1515
     
    3131}
    3232
    33 void __schedule_thread( $thread * ) __attribute__((nonnull (1)));
     33void ScheduleThread( thread_desc * );
     34static inline void WakeThread( thread_desc * thrd ) {
     35        if( !thrd ) return;
     36
     37        verify(thrd->state == Inactive);
     38
     39        disable_interrupts();
     40        ScheduleThread( thrd );
     41        enable_interrupts( __cfaabi_dbg_ctx );
     42}
     43thread_desc * nextThread(cluster * this);
    3444
    3545//Block current thread and release/wake-up the following resources
    36 void __leave_thread() __attribute__((noreturn));
     46void BlockInternal(void);
     47void BlockInternal(__spinlock_t * lock);
     48void BlockInternal(thread_desc * thrd);
     49void BlockInternal(__spinlock_t * lock, thread_desc * thrd);
     50void BlockInternal(__spinlock_t * locks [], unsigned short count);
     51void BlockInternal(__spinlock_t * locks [], unsigned short count, thread_desc * thrds [], unsigned short thrd_count);
     52void BlockInternal(__finish_callback_fptr_t callback);
     53void LeaveThread(__spinlock_t * lock, thread_desc * thrd);
    3754
    3855//-----------------------------------------------------------------------------
     
    4057void main(processorCtx_t *);
    4158
    42 void * __create_pthread( pthread_t *, void * (*)(void *), void * );
     59static inline void wake_fast(processor * this) {
     60        __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
     61        post( this->idleLock );
     62}
    4363
    44 
     64static inline void wake(processor * this) {
     65        disable_interrupts();
     66        wake_fast(this);
     67        enable_interrupts( __cfaabi_dbg_ctx );
     68}
    4569
    4670struct event_kernel_t {
     
    6286// Threads
    6387extern "C" {
    64       void __cfactx_invoke_thread(void (*main)(void *), void * this);
     88      forall(dtype T | is_thread(T))
     89      void CtxInvokeThread(T * this);
    6590}
    6691
     92extern void ThreadCtxSwitch(coroutine_desc * src, coroutine_desc * dst);
     93
    6794__cfaabi_dbg_debug_do(
    68         extern void __cfaabi_dbg_thread_register  ( $thread * thrd );
    69         extern void __cfaabi_dbg_thread_unregister( $thread * thrd );
     95        extern void __cfaabi_dbg_thread_register  ( thread_desc * thrd );
     96        extern void __cfaabi_dbg_thread_unregister( thread_desc * thrd );
    7097)
    7198
     
    74101#define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)]
    75102
    76 static inline uint32_t __tls_rand() {
     103static inline uint32_t tls_rand() {
    77104        kernelTLS.rand_seed ^= kernelTLS.rand_seed << 6;
    78105        kernelTLS.rand_seed ^= kernelTLS.rand_seed >> 21;
     
    85112void unregister( struct cluster & cltr );
    86113
    87 void doregister( struct cluster * cltr, struct $thread & thrd );
    88 void unregister( struct cluster * cltr, struct $thread & thrd );
     114void doregister( struct cluster * cltr, struct thread_desc & thrd );
     115void unregister( struct cluster * cltr, struct thread_desc & thrd );
    89116
    90117void doregister( struct cluster * cltr, struct processor * proc );
  • libcfa/src/concurrency/monitor.cfa

    r7030dab r71d6bd8  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // $monitor.c --
     7// monitor_desc.c --
    88//
    99// Author           : Thierry Delisle
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 07:55:14 2019
    13 // Update Count     : 10
     12// Last Modified On : Fri Mar 30 14:30:26 2018
     13// Update Count     : 9
    1414//
    1515
     
    2727//-----------------------------------------------------------------------------
    2828// Forward declarations
    29 static inline void __set_owner ( $monitor * this, $thread * owner );
    30 static inline void __set_owner ( $monitor * storage [], __lock_size_t count, $thread * owner );
    31 static inline void set_mask  ( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask );
    32 static inline void reset_mask( $monitor * this );
    33 
    34 static inline $thread * next_thread( $monitor * this );
    35 static inline bool is_accepted( $monitor * this, const __monitor_group_t & monitors );
     29static inline void set_owner ( monitor_desc * this, thread_desc * owner );
     30static inline void set_owner ( monitor_desc * storage [], __lock_size_t count, thread_desc * owner );
     31static inline void set_mask  ( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask );
     32static inline void reset_mask( monitor_desc * this );
     33
     34static inline thread_desc * next_thread( monitor_desc * this );
     35static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & monitors );
    3636
    3737static inline void lock_all  ( __spinlock_t * locks [], __lock_size_t count );
    38 static inline void lock_all  ( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count );
     38static inline void lock_all  ( monitor_desc * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count );
    3939static inline void unlock_all( __spinlock_t * locks [], __lock_size_t count );
    40 static inline void unlock_all( $monitor * locks [], __lock_size_t count );
    41 
    42 static inline void save   ( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );
    43 static inline void restore( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );
    44 
    45 static inline void init     ( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    46 static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    47 
    48 static inline $thread *        check_condition   ( __condition_criterion_t * );
     40static inline void unlock_all( monitor_desc * locks [], __lock_size_t count );
     41
     42static inline void save   ( monitor_desc * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );
     43static inline void restore( monitor_desc * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );
     44
     45static inline void init     ( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     46static inline void init_push( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     47
     48static inline thread_desc *        check_condition   ( __condition_criterion_t * );
    4949static inline void                 brand_condition   ( condition & );
    50 static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t &, $monitor * monitors [], __lock_size_t count );
     50static inline [thread_desc *, int] search_entry_queue( const __waitfor_mask_t &, monitor_desc * monitors [], __lock_size_t count );
    5151
    5252forall(dtype T | sized( T ))
    5353static inline __lock_size_t insert_unique( T * array [], __lock_size_t & size, T * val );
    5454static inline __lock_size_t count_max    ( const __waitfor_mask_t & mask );
    55 static inline __lock_size_t aggregate    ( $monitor * storage [], const __waitfor_mask_t & mask );
     55static inline __lock_size_t aggregate    ( monitor_desc * storage [], const __waitfor_mask_t & mask );
    5656
    5757//-----------------------------------------------------------------------------
     
    6868
    6969#define monitor_ctx( mons, cnt )                                /* Define that create the necessary struct for internal/external scheduling operations */ \
    70         $monitor ** monitors = mons;                          /* Save the targeted monitors                                                          */ \
     70        monitor_desc ** monitors = mons;                          /* Save the targeted monitors                                                          */ \
    7171        __lock_size_t count = cnt;                                /* Save the count to a local variable                                                  */ \
    7272        unsigned int recursions[ count ];                         /* Save the current recursion levels to restore them later                             */ \
     
    8080//-----------------------------------------------------------------------------
    8181// Enter/Leave routines
    82 // Enter single monitor
    83 static void __enter( $monitor * this, const __monitor_group_t & group ) {
    84         // Lock the monitor spinlock
    85         lock( this->lock __cfaabi_dbg_ctx2 );
    86         // Interrupts disable inside critical section
    87         $thread * thrd = kernelTLS.this_thread;
    88 
    89         __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner);
    90 
    91         if( !this->owner ) {
    92                 // No one has the monitor, just take it
    93                 __set_owner( this, thrd );
    94 
    95                 __cfaabi_dbg_print_safe( "Kernel :  mon is free \n" );
    96         }
    97         else if( this->owner == thrd) {
    98                 // We already have the monitor, just note how many times we took it
    99                 this->recursion += 1;
    100 
    101                 __cfaabi_dbg_print_safe( "Kernel :  mon already owned \n" );
    102         }
    103         else if( is_accepted( this, group) ) {
    104                 // Some one was waiting for us, enter
    105                 __set_owner( this, thrd );
    106 
    107                 // Reset mask
    108                 reset_mask( this );
    109 
    110                 __cfaabi_dbg_print_safe( "Kernel :  mon accepts \n" );
    111         }
    112         else {
    113                 __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
    114 
    115                 // Some one else has the monitor, wait in line for it
    116                 /* paranoid */ verify( thrd->next == 0p );
    117                 append( this->entry_queue, thrd );
    118                 /* paranoid */ verify( thrd->next == 1p );
    119 
    120                 unlock( this->lock );
    121                 park( __cfaabi_dbg_ctx );
     82
     83
     84extern "C" {
     85        // Enter single monitor
     86        static void __enter_monitor_desc( monitor_desc * this, const __monitor_group_t & group ) {
     87                // Lock the monitor spinlock
     88                lock( this->lock __cfaabi_dbg_ctx2 );
     89                // Interrupts disable inside critical section
     90                thread_desc * thrd = kernelTLS.this_thread;
     91
     92                __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner);
     93
     94                if( !this->owner ) {
     95                        // No one has the monitor, just take it
     96                        set_owner( this, thrd );
     97
     98                        __cfaabi_dbg_print_safe( "Kernel :  mon is free \n" );
     99                }
     100                else if( this->owner == thrd) {
     101                        // We already have the monitor, just note how many times we took it
     102                        this->recursion += 1;
     103
     104                        __cfaabi_dbg_print_safe( "Kernel :  mon already owned \n" );
     105                }
     106                else if( is_accepted( this, group) ) {
     107                        // Some one was waiting for us, enter
     108                        set_owner( this, thrd );
     109
     110                        // Reset mask
     111                        reset_mask( this );
     112
     113                        __cfaabi_dbg_print_safe( "Kernel :  mon accepts \n" );
     114                }
     115                else {
     116                        __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
     117
     118                        // Some one else has the monitor, wait in line for it
     119                        append( this->entry_queue, thrd );
     120
     121                        BlockInternal( &this->lock );
     122
     123                        __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
     124
     125                        // BlockInternal will unlock spinlock, no need to unlock ourselves
     126                        return;
     127                }
    122128
    123129                __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
    124130
    125                 /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    126                 return;
    127         }
    128 
    129         __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
    130 
    131         /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    132         /* paranoid */ verify( this->lock.lock );
    133 
    134         // Release the lock and leave
    135         unlock( this->lock );
    136         return;
    137 }
    138 
    139 static void __dtor_enter( $monitor * this, fptr_t func ) {
    140         // Lock the monitor spinlock
    141         lock( this->lock __cfaabi_dbg_ctx2 );
    142         // Interrupts disable inside critical section
    143         $thread * thrd = kernelTLS.this_thread;
    144 
    145         __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner);
    146 
    147 
    148         if( !this->owner ) {
    149                 __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this);
    150 
    151                 // No one has the monitor, just take it
    152                 __set_owner( this, thrd );
    153 
    154                 verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    155 
     131                // Release the lock and leave
    156132                unlock( this->lock );
    157133                return;
    158134        }
    159         else if( this->owner == thrd) {
    160                 // We already have the monitor... but where about to destroy it so the nesting will fail
    161                 // Abort!
    162                 abort( "Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.", this, thrd->self_cor.name, thrd );
    163         }
    164 
    165         __lock_size_t count = 1;
    166         $monitor ** monitors = &this;
    167         __monitor_group_t group = { &this, 1, func };
    168         if( is_accepted( this, group) ) {
    169                 __cfaabi_dbg_print_safe( "Kernel :  mon accepts dtor, block and signal it \n" );
    170 
    171                 // Wake the thread that is waiting for this
    172                 __condition_criterion_t * urgent = pop( this->signal_stack );
    173                 /* paranoid */ verify( urgent );
    174 
    175                 // Reset mask
    176                 reset_mask( this );
    177 
    178                 // Create the node specific to this wait operation
    179                 wait_ctx_primed( thrd, 0 )
    180 
    181                 // Some one else has the monitor, wait for him to finish and then run
     135
     136        static void __enter_monitor_dtor( monitor_desc * this, fptr_t func ) {
     137                // Lock the monitor spinlock
     138                lock( this->lock __cfaabi_dbg_ctx2 );
     139                // Interrupts disable inside critical section
     140                thread_desc * thrd = kernelTLS.this_thread;
     141
     142                __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner);
     143
     144
     145                if( !this->owner ) {
     146                        __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this);
     147
     148                        // No one has the monitor, just take it
     149                        set_owner( this, thrd );
     150
     151                        unlock( this->lock );
     152                        return;
     153                }
     154                else if( this->owner == thrd) {
     155                        // We already have the monitor... but where about to destroy it so the nesting will fail
     156                        // Abort!
     157                        abort( "Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.", this, thrd->self_cor.name, thrd );
     158                }
     159
     160                __lock_size_t count = 1;
     161                monitor_desc ** monitors = &this;
     162                __monitor_group_t group = { &this, 1, func };
     163                if( is_accepted( this, group) ) {
     164                        __cfaabi_dbg_print_safe( "Kernel :  mon accepts dtor, block and signal it \n" );
     165
     166                        // Wake the thread that is waiting for this
     167                        __condition_criterion_t * urgent = pop( this->signal_stack );
     168                        verify( urgent );
     169
     170                        // Reset mask
     171                        reset_mask( this );
     172
     173                        // Create the node specific to this wait operation
     174                        wait_ctx_primed( thrd, 0 )
     175
     176                        // Some one else has the monitor, wait for him to finish and then run
     177                        BlockInternal( &this->lock, urgent->owner->waiting_thread );
     178
     179                        // Some one was waiting for us, enter
     180                        set_owner( this, thrd );
     181                }
     182                else {
     183                        __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
     184
     185                        wait_ctx( thrd, 0 )
     186                        this->dtor_node = &waiter;
     187
     188                        // Some one else has the monitor, wait in line for it
     189                        append( this->entry_queue, thrd );
     190                        BlockInternal( &this->lock );
     191
     192                        // BlockInternal will unlock spinlock, no need to unlock ourselves
     193                        return;
     194                }
     195
     196                __cfaabi_dbg_print_safe( "Kernel : Destroying %p\n", this);
     197
     198        }
     199
     200        // Leave single monitor
     201        void __leave_monitor_desc( monitor_desc * this ) {
     202                // Lock the monitor spinlock
     203                lock( this->lock __cfaabi_dbg_ctx2 );
     204
     205                __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", kernelTLS.this_thread, this, this->owner);
     206
     207                verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
     208
     209                // Leaving a recursion level, decrement the counter
     210                this->recursion -= 1;
     211
     212                // If we haven't left the last level of recursion
     213                // it means we don't need to do anything
     214                if( this->recursion != 0) {
     215                        __cfaabi_dbg_print_safe( "Kernel :  recursion still %d\n", this->recursion);
     216                        unlock( this->lock );
     217                        return;
     218                }
     219
     220                // Get the next thread, will be null on low contention monitor
     221                thread_desc * new_owner = next_thread( this );
     222
     223                // We can now let other threads in safely
    182224                unlock( this->lock );
    183225
    184                 // Release the next thread
    185                 /* paranoid */ verifyf( urgent->owner->waiting_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    186                 unpark( urgent->owner->waiting_thread __cfaabi_dbg_ctx2 );
    187 
    188                 // Park current thread waiting
    189                 park( __cfaabi_dbg_ctx );
    190 
    191                 // Some one was waiting for us, enter
    192                 /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    193         }
    194         else {
    195                 __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
    196 
    197                 wait_ctx( thrd, 0 )
    198                 this->dtor_node = &waiter;
    199 
    200                 // Some one else has the monitor, wait in line for it
    201                 /* paranoid */ verify( thrd->next == 0p );
    202                 append( this->entry_queue, thrd );
    203                 /* paranoid */ verify( thrd->next == 1p );
    204                 unlock( this->lock );
    205 
    206                 // Park current thread waiting
    207                 park( __cfaabi_dbg_ctx );
    208 
    209                 /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    210                 return;
    211         }
    212 
    213         __cfaabi_dbg_print_safe( "Kernel : Destroying %p\n", this);
    214 
    215 }
    216 
    217 // Leave single monitor
    218 void __leave( $monitor * this ) {
    219         // Lock the monitor spinlock
    220         lock( this->lock __cfaabi_dbg_ctx2 );
    221 
    222         __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", kernelTLS.this_thread, this, this->owner);
    223 
    224         /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    225 
    226         // Leaving a recursion level, decrement the counter
    227         this->recursion -= 1;
    228 
    229         // If we haven't left the last level of recursion
    230         // it means we don't need to do anything
    231         if( this->recursion != 0) {
    232                 __cfaabi_dbg_print_safe( "Kernel :  recursion still %d\n", this->recursion);
    233                 unlock( this->lock );
    234                 return;
    235         }
    236 
    237         // Get the next thread, will be null on low contention monitor
    238         $thread * new_owner = next_thread( this );
    239 
    240         // Check the new owner is consistent with who we wake-up
    241         // new_owner might be null even if someone owns the monitor when the owner is still waiting for another monitor
    242         /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    243 
    244         // We can now let other threads in safely
    245         unlock( this->lock );
    246 
    247         //We need to wake-up the thread
    248         /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    249         unpark( new_owner __cfaabi_dbg_ctx2 );
    250 }
    251 
    252 // Leave single monitor for the last time
    253 void __dtor_leave( $monitor * this ) {
    254         __cfaabi_dbg_debug_do(
    255                 if( TL_GET( this_thread ) != this->owner ) {
    256                         abort( "Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, TL_GET( this_thread ), this->owner);
    257                 }
    258                 if( this->recursion != 1 ) {
    259                         abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
    260                 }
    261         )
    262 }
    263 
    264 extern "C" {
     226                //We need to wake-up the thread
     227                WakeThread( new_owner );
     228        }
     229
     230        // Leave single monitor for the last time
     231        void __leave_dtor_monitor_desc( monitor_desc * this ) {
     232                __cfaabi_dbg_debug_do(
     233                        if( TL_GET( this_thread ) != this->owner ) {
     234                                abort( "Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, TL_GET( this_thread ), this->owner);
     235                        }
     236                        if( this->recursion != 1 ) {
     237                                abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
     238                        }
     239                )
     240        }
     241
    265242        // Leave the thread monitor
    266243        // last routine called by a thread.
    267244        // Should never return
    268         void __cfactx_thrd_leave() {
    269                 $thread * thrd = TL_GET( this_thread );
    270                 $monitor * this = &thrd->self_mon;
     245        void __leave_thread_monitor( thread_desc * thrd ) {
     246                monitor_desc * this = &thrd->self_mon;
    271247
    272248                // Lock the monitor now
     
    275251                disable_interrupts();
    276252
    277                 thrd->state = Halted;
    278 
    279                 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );
     253                thrd->self_cor.state = Halted;
     254
     255                verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );
    280256
    281257                // Leaving a recursion level, decrement the counter
     
    287263
    288264                // Fetch the next thread, can be null
    289                 $thread * new_owner = next_thread( this );
    290 
    291                 // Release the monitor lock
    292                 unlock( this->lock );
    293 
    294                 // Unpark the next owner if needed
    295                 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );
    296                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    297                 /* paranoid */ verify( ! kernelTLS.this_processor->destroyer );
    298                 /* paranoid */ verify( thrd->state == Halted );
    299 
    300                 kernelTLS.this_processor->destroyer = new_owner;
    301 
    302                 // Leave the thread
    303                 __leave_thread();
     265                thread_desc * new_owner = next_thread( this );
     266
     267                // Leave the thread, this will unlock the spinlock
     268                // Use leave thread instead of BlockInternal which is
     269                // specialized for this case and supports null new_owner
     270                LeaveThread( &this->lock, new_owner );
    304271
    305272                // Control flow should never reach here!
     
    311278static inline void enter( __monitor_group_t monitors ) {
    312279        for( __lock_size_t i = 0; i < monitors.size; i++) {
    313                 __enter( monitors[i], monitors );
     280                __enter_monitor_desc( monitors[i], monitors );
    314281        }
    315282}
     
    317284// Leave multiple monitor
    318285// relies on the monitor array being sorted
    319 static inline void leave($monitor * monitors [], __lock_size_t count) {
     286static inline void leave(monitor_desc * monitors [], __lock_size_t count) {
    320287        for( __lock_size_t i = count - 1; i >= 0; i--) {
    321                 __leave( monitors[i] );
     288                __leave_monitor_desc( monitors[i] );
    322289        }
    323290}
     
    325292// Ctor for monitor guard
    326293// Sorts monitors before entering
    327 void ?{}( monitor_guard_t & this, $monitor * m [], __lock_size_t count, fptr_t func ) {
    328         $thread * thrd = TL_GET( this_thread );
     294void ?{}( monitor_guard_t & this, monitor_desc * m [], __lock_size_t count, fptr_t func ) {
     295        thread_desc * thrd = TL_GET( this_thread );
    329296
    330297        // Store current array
     
    366333// Ctor for monitor guard
    367334// Sorts monitors before entering
    368 void ?{}( monitor_dtor_guard_t & this, $monitor * m [], fptr_t func ) {
     335void ?{}( monitor_dtor_guard_t & this, monitor_desc * m [], fptr_t func ) {
    369336        // optimization
    370         $thread * thrd = TL_GET( this_thread );
     337        thread_desc * thrd = TL_GET( this_thread );
    371338
    372339        // Store current array
     
    379346        (thrd->monitors){m, 1, func};
    380347
    381         __dtor_enter( this.m, func );
     348        __enter_monitor_dtor( this.m, func );
    382349}
    383350
     
    385352void ^?{}( monitor_dtor_guard_t & this ) {
    386353        // Leave the monitors in order
    387         __dtor_leave( this.m );
     354        __leave_dtor_monitor_desc( this.m );
    388355
    389356        // Restore thread context
     
    393360//-----------------------------------------------------------------------------
    394361// Internal scheduling types
    395 void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
     362void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
    396363        this.waiting_thread = waiting_thread;
    397364        this.count = count;
    398         this.next = 0p;
     365        this.next = NULL;
    399366        this.user_info = user_info;
    400367}
     
    402369void ?{}(__condition_criterion_t & this ) with( this ) {
    403370        ready  = false;
    404         target = 0p;
    405         owner  = 0p;
    406         next   = 0p;
    407 }
    408 
    409 void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t & owner ) {
     371        target = NULL;
     372        owner  = NULL;
     373        next   = NULL;
     374}
     375
     376void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t & owner ) {
    410377        this.ready  = false;
    411378        this.target = target;
    412379        this.owner  = &owner;
    413         this.next   = 0p;
     380        this.next   = NULL;
    414381}
    415382
     
    420387
    421388        // Check that everything is as expected
    422         assertf( this.monitors != 0p, "Waiting with no monitors (%p)", this.monitors );
     389        assertf( this.monitors != NULL, "Waiting with no monitors (%p)", this.monitors );
    423390        verifyf( this.monitor_count != 0, "Waiting with 0 monitors (%"PRIiFAST16")", this.monitor_count );
    424391        verifyf( this.monitor_count < 32u, "Excessive monitor count (%"PRIiFAST16")", this.monitor_count );
     
    432399        // Append the current wait operation to the ones already queued on the condition
    433400        // We don't need locks for that since conditions must always be waited on inside monitor mutual exclusion
    434         /* paranoid */ verify( waiter.next == 0p );
    435401        append( this.blocked, &waiter );
    436         /* paranoid */ verify( waiter.next == 1p );
    437402
    438403        // Lock all monitors (aggregates the locks as well)
     
    441406        // Find the next thread(s) to run
    442407        __lock_size_t thread_count = 0;
    443         $thread * threads[ count ];
     408        thread_desc * threads[ count ];
    444409        __builtin_memset( threads, 0, sizeof( threads ) );
    445410
     
    449414        // Remove any duplicate threads
    450415        for( __lock_size_t i = 0; i < count; i++) {
    451                 $thread * new_owner = next_thread( monitors[i] );
     416                thread_desc * new_owner = next_thread( monitors[i] );
    452417                insert_unique( threads, thread_count, new_owner );
    453418        }
    454419
    455         // Unlock the locks, we don't need them anymore
    456         for(int i = 0; i < count; i++) {
    457                 unlock( *locks[i] );
    458         }
    459 
    460         // Wake the threads
    461         for(int i = 0; i < thread_count; i++) {
    462                 unpark( threads[i] __cfaabi_dbg_ctx2 );
    463         }
    464 
    465420        // Everything is ready to go to sleep
    466         park( __cfaabi_dbg_ctx );
     421        BlockInternal( locks, count, threads, thread_count );
    467422
    468423        // We are back, restore the owners and recursions
     
    479434        //Some more checking in debug
    480435        __cfaabi_dbg_debug_do(
    481                 $thread * this_thrd = TL_GET( this_thread );
     436                thread_desc * this_thrd = TL_GET( this_thread );
    482437                if ( this.monitor_count != this_thrd->monitors.size ) {
    483438                        abort( "Signal on condition %p made with different number of monitor(s), expected %zi got %zi", &this, this.monitor_count, this_thrd->monitors.size );
     
    494449
    495450        // Lock all monitors
    496         lock_all( this.monitors, 0p, count );
     451        lock_all( this.monitors, NULL, count );
    497452
    498453        //Pop the head of the waiting queue
     
    516471
    517472        //Check that everything is as expected
    518         verifyf( this.monitors != 0p, "Waiting with no monitors (%p)", this.monitors );
     473        verifyf( this.monitors != NULL, "Waiting with no monitors (%p)", this.monitors );
    519474        verifyf( this.monitor_count != 0, "Waiting with 0 monitors (%"PRIiFAST16")", this.monitor_count );
    520475
     
    533488
    534489        //Find the thread to run
    535         $thread * signallee = pop_head( this.blocked )->waiting_thread;
    536         __set_owner( monitors, count, signallee );
     490        thread_desc * signallee = pop_head( this.blocked )->waiting_thread;
     491        set_owner( monitors, count, signallee );
    537492
    538493        __cfaabi_dbg_print_buffer_decl( "Kernel : signal_block condition %p (s: %p)\n", &this, signallee );
    539494
    540         // unlock all the monitors
    541         unlock_all( locks, count );
    542 
    543         // unpark the thread we signalled
    544         unpark( signallee __cfaabi_dbg_ctx2 );
    545 
    546495        //Everything is ready to go to sleep
    547         park( __cfaabi_dbg_ctx );
     496        BlockInternal( locks, count, &signallee, 1 );
    548497
    549498
     
    586535        // Create one!
    587536        __lock_size_t max = count_max( mask );
    588         $monitor * mon_storage[max];
     537        monitor_desc * mon_storage[max];
    589538        __builtin_memset( mon_storage, 0, sizeof( mon_storage ) );
    590539        __lock_size_t actual_count = aggregate( mon_storage, mask );
     
    604553        {
    605554                // Check if the entry queue
    606                 $thread * next; int index;
     555                thread_desc * next; int index;
    607556                [next, index] = search_entry_queue( mask, monitors, count );
    608557
     
    614563                                verifyf( accepted.size == 1,  "ERROR: Accepted dtor has more than 1 mutex parameter." );
    615564
    616                                 $monitor * mon2dtor = accepted[0];
     565                                monitor_desc * mon2dtor = accepted[0];
    617566                                verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." );
    618567
     
    640589
    641590                                // Set the owners to be the next thread
    642                                 __set_owner( monitors, count, next );
    643 
    644                                 // unlock all the monitors
    645                                 unlock_all( locks, count );
    646 
    647                                 // unpark the thread we signalled
    648                                 unpark( next __cfaabi_dbg_ctx2 );
    649 
    650                                 //Everything is ready to go to sleep
    651                                 park( __cfaabi_dbg_ctx );
     591                                set_owner( monitors, count, next );
     592
     593                                // Everything is ready to go to sleep
     594                                BlockInternal( locks, count, &next, 1 );
    652595
    653596                                // We are back, restore the owners and recursions
     
    687630        }
    688631
    689         // unlock all the monitors
    690         unlock_all( locks, count );
    691 
    692632        //Everything is ready to go to sleep
    693         park( __cfaabi_dbg_ctx );
     633        BlockInternal( locks, count );
    694634
    695635
     
    708648// Utilities
    709649
    710 static inline void __set_owner( $monitor * this, $thread * owner ) {
    711         /* paranoid */ verify( this->lock.lock );
     650static inline void set_owner( monitor_desc * this, thread_desc * owner ) {
     651        // __cfaabi_dbg_print_safe( "Kernal :   Setting owner of %p to %p ( was %p)\n", this, owner, this->owner );
    712652
    713653        //Pass the monitor appropriately
     
    718658}
    719659
    720 static inline void __set_owner( $monitor * monitors [], __lock_size_t count, $thread * owner ) {
    721         /* paranoid */ verify ( monitors[0]->lock.lock );
    722         /* paranoid */ verifyf( monitors[0]->owner == kernelTLS.this_thread, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, monitors[0]->owner, monitors[0]->recursion, monitors[0] );
    723         monitors[0]->owner        = owner;
    724         monitors[0]->recursion    = 1;
     660static inline void set_owner( monitor_desc * monitors [], __lock_size_t count, thread_desc * owner ) {
     661        monitors[0]->owner     = owner;
     662        monitors[0]->recursion = 1;
    725663        for( __lock_size_t i = 1; i < count; i++ ) {
    726                 /* paranoid */ verify ( monitors[i]->lock.lock );
    727                 /* paranoid */ verifyf( monitors[i]->owner == kernelTLS.this_thread, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, monitors[i]->owner, monitors[i]->recursion, monitors[i] );
    728                 monitors[i]->owner        = owner;
    729                 monitors[i]->recursion    = 0;
    730         }
    731 }
    732 
    733 static inline void set_mask( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) {
     664                monitors[i]->owner     = owner;
     665                monitors[i]->recursion = 0;
     666        }
     667}
     668
     669static inline void set_mask( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) {
    734670        for( __lock_size_t i = 0; i < count; i++) {
    735671                storage[i]->mask = mask;
     
    737673}
    738674
    739 static inline void reset_mask( $monitor * this ) {
    740         this->mask.accepted = 0p;
    741         this->mask.data = 0p;
     675static inline void reset_mask( monitor_desc * this ) {
     676        this->mask.accepted = NULL;
     677        this->mask.data = NULL;
    742678        this->mask.size = 0;
    743679}
    744680
    745 static inline $thread * next_thread( $monitor * this ) {
     681static inline thread_desc * next_thread( monitor_desc * this ) {
    746682        //Check the signaller stack
    747683        __cfaabi_dbg_print_safe( "Kernel :  mon %p AS-stack top %p\n", this, this->signal_stack.top);
     
    751687                //regardless of if we are ready to baton pass,
    752688                //we need to set the monitor as in use
    753                 /* paranoid */ verifyf( !this->owner || kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    754                 __set_owner( this,  urgent->owner->waiting_thread );
     689                set_owner( this,  urgent->owner->waiting_thread );
    755690
    756691                return check_condition( urgent );
     
    759694        // No signaller thread
    760695        // Get the next thread in the entry_queue
    761         $thread * new_owner = pop_head( this->entry_queue );
    762         /* paranoid */ verifyf( !this->owner || kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    763         /* paranoid */ verify( !new_owner || new_owner->next == 0p );
    764         __set_owner( this, new_owner );
     696        thread_desc * new_owner = pop_head( this->entry_queue );
     697        set_owner( this, new_owner );
    765698
    766699        return new_owner;
    767700}
    768701
    769 static inline bool is_accepted( $monitor * this, const __monitor_group_t & group ) {
     702static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & group ) {
    770703        __acceptable_t * it = this->mask.data; // Optim
    771704        __lock_size_t count = this->mask.size;
     
    789722}
    790723
    791 static inline void init( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
     724static inline void init( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
    792725        for( __lock_size_t i = 0; i < count; i++) {
    793726                (criteria[i]){ monitors[i], waiter };
     
    797730}
    798731
    799 static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
     732static inline void init_push( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
    800733        for( __lock_size_t i = 0; i < count; i++) {
    801734                (criteria[i]){ monitors[i], waiter };
     
    813746}
    814747
    815 static inline void lock_all( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {
     748static inline void lock_all( monitor_desc * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {
    816749        for( __lock_size_t i = 0; i < count; i++ ) {
    817750                __spinlock_t * l = &source[i]->lock;
     
    827760}
    828761
    829 static inline void unlock_all( $monitor * locks [], __lock_size_t count ) {
     762static inline void unlock_all( monitor_desc * locks [], __lock_size_t count ) {
    830763        for( __lock_size_t i = 0; i < count; i++ ) {
    831764                unlock( locks[i]->lock );
     
    834767
    835768static inline void save(
    836         $monitor * ctx [],
     769        monitor_desc * ctx [],
    837770        __lock_size_t count,
    838771        __attribute((unused)) __spinlock_t * locks [],
     
    847780
    848781static inline void restore(
    849         $monitor * ctx [],
     782        monitor_desc * ctx [],
    850783        __lock_size_t count,
    851784        __spinlock_t * locks [],
     
    865798// 2 - Checks if all the monitors are ready to run
    866799//     if so return the thread to run
    867 static inline $thread * check_condition( __condition_criterion_t * target ) {
     800static inline thread_desc * check_condition( __condition_criterion_t * target ) {
    868801        __condition_node_t * node = target->owner;
    869802        unsigned short count = node->count;
     
    883816        }
    884817
    885         __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : 0p );
    886         return ready2run ? node->waiting_thread : 0p;
     818        __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : NULL );
     819        return ready2run ? node->waiting_thread : NULL;
    887820}
    888821
    889822static inline void brand_condition( condition & this ) {
    890         $thread * thrd = TL_GET( this_thread );
     823        thread_desc * thrd = TL_GET( this_thread );
    891824        if( !this.monitors ) {
    892825                // __cfaabi_dbg_print_safe( "Branding\n" );
    893                 assertf( thrd->monitors.data != 0p, "No current monitor to brand condition %p", thrd->monitors.data );
     826                assertf( thrd->monitors.data != NULL, "No current monitor to brand condition %p", thrd->monitors.data );
    894827                this.monitor_count = thrd->monitors.size;
    895828
    896                 this.monitors = ($monitor **)malloc( this.monitor_count * sizeof( *this.monitors ) );
     829                this.monitors = (monitor_desc **)malloc( this.monitor_count * sizeof( *this.monitors ) );
    897830                for( int i = 0; i < this.monitor_count; i++ ) {
    898831                        this.monitors[i] = thrd->monitors[i];
     
    901834}
    902835
    903 static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t & mask, $monitor * monitors [], __lock_size_t count ) {
    904 
    905         __queue_t($thread) & entry_queue = monitors[0]->entry_queue;
     836static inline [thread_desc *, int] search_entry_queue( const __waitfor_mask_t & mask, monitor_desc * monitors [], __lock_size_t count ) {
     837
     838        __queue_t(thread_desc) & entry_queue = monitors[0]->entry_queue;
    906839
    907840        // For each thread in the entry-queue
    908         for(    $thread ** thrd_it = &entry_queue.head;
    909                 *thrd_it != 1p;
     841        for(    thread_desc ** thrd_it = &entry_queue.head;
     842                *thrd_it;
    910843                thrd_it = &(*thrd_it)->next
    911844        ) {
     
    950883}
    951884
    952 static inline __lock_size_t aggregate( $monitor * storage [], const __waitfor_mask_t & mask ) {
     885static inline __lock_size_t aggregate( monitor_desc * storage [], const __waitfor_mask_t & mask ) {
    953886        __lock_size_t size = 0;
    954887        for( __lock_size_t i = 0; i < mask.size; i++ ) {
  • libcfa/src/concurrency/monitor.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 07:55:32 2019
    13 // Update Count     : 11
     12// Last Modified On : Sat Oct  7 18:06:45 2017
     13// Update Count     : 10
    1414//
    1515
     
    2323
    2424trait is_monitor(dtype T) {
    25         $monitor * get_monitor( T & );
     25        monitor_desc * get_monitor( T & );
    2626        void ^?{}( T & mutex );
    2727};
    2828
    29 static inline void ?{}($monitor & this) with( this ) {
     29static inline void ?{}(monitor_desc & this) with( this ) {
    3030        lock{};
    3131        entry_queue{};
    3232        signal_stack{};
    33         owner         = 0p;
     33        owner         = NULL;
    3434        recursion     = 0;
    35         mask.accepted = 0p;
    36         mask.data     = 0p;
     35        mask.accepted = NULL;
     36        mask.data     = NULL;
    3737        mask.size     = 0;
    38         dtor_node     = 0p;
     38        dtor_node     = NULL;
    3939}
    4040
    41 static inline void ^?{}($monitor & ) {}
    42 
    4341struct monitor_guard_t {
    44         $monitor **     m;
     42        monitor_desc **         m;
    4543        __lock_size_t           count;
    4644        __monitor_group_t prev;
    4745};
    4846
    49 void ?{}( monitor_guard_t & this, $monitor ** m, __lock_size_t count, void (*func)() );
     47void ?{}( monitor_guard_t & this, monitor_desc ** m, __lock_size_t count, void (*func)() );
    5048void ^?{}( monitor_guard_t & this );
    5149
    5250struct monitor_dtor_guard_t {
    53         $monitor *    m;
     51        monitor_desc *    m;
    5452        __monitor_group_t prev;
    5553};
    5654
    57 void ?{}( monitor_dtor_guard_t & this, $monitor ** m, void (*func)() );
     55void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, void (*func)() );
    5856void ^?{}( monitor_dtor_guard_t & this );
    5957
     
    7270
    7371        // The monitor this criterion concerns
    74         $monitor * target;
     72        monitor_desc * target;
    7573
    7674        // The parent node to which this criterion belongs
     
    8785struct __condition_node_t {
    8886        // Thread that needs to be woken when all criteria are met
    89         $thread * waiting_thread;
     87        thread_desc * waiting_thread;
    9088
    9189        // Array of criteria (Criterions are contiguous in memory)
     
    106104}
    107105
    108 void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info );
     106void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info );
    109107void ?{}(__condition_criterion_t & this );
    110 void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t * owner );
     108void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t * owner );
    111109
    112110struct condition {
     
    115113
    116114        // Array of monitor pointers (Monitors are NOT contiguous in memory)
    117         $monitor ** monitors;
     115        monitor_desc ** monitors;
    118116
    119117        // Number of monitors in the array
     
    122120
    123121static inline void ?{}( condition & this ) {
    124         this.monitors = 0p;
     122        this.monitors = NULL;
    125123        this.monitor_count = 0;
    126124}
     
    133131              bool signal      ( condition & this );
    134132              bool signal_block( condition & this );
    135 static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
     133static inline bool is_empty    ( condition & this ) { return !this.blocked.head; }
    136134         uintptr_t front       ( condition & this );
    137135
  • libcfa/src/concurrency/mutex.cfa

    r7030dab r71d6bd8  
    1111// Author           : Thierry Delisle
    1212// Created On       : Fri May 25 01:37:11 2018
    13 // Last Modified By : Peter A. Buhr
    14 // Last Modified On : Wed Dec  4 09:16:39 2019
    15 // Update Count     : 1
     13// Last Modified By : Thierry Delisle
     14// Last Modified On : Fri May 25 01:37:51 2018
     15// Update Count     : 0
    1616//
    1717
     
    4040        if( is_locked ) {
    4141                append( blocked_threads, kernelTLS.this_thread );
    42                 unlock( lock );
    43                 park( __cfaabi_dbg_ctx );
     42                BlockInternal( &lock );
    4443        }
    4544        else {
     
    6362        lock( this.lock __cfaabi_dbg_ctx2 );
    6463        this.is_locked = (this.blocked_threads != 0);
    65         unpark(
    66                 pop_head( this.blocked_threads ) __cfaabi_dbg_ctx2
     64        WakeThread(
     65                pop_head( this.blocked_threads )
    6766        );
    6867        unlock( this.lock );
     
    7473        this.lock{};
    7574        this.blocked_threads{};
    76         this.owner = 0p;
     75        this.owner = NULL;
    7776        this.recursion_count = 0;
    7877}
     
    8483void lock(recursive_mutex_lock & this) with(this) {
    8584        lock( lock __cfaabi_dbg_ctx2 );
    86         if( owner == 0p ) {
     85        if( owner == NULL ) {
    8786                owner = kernelTLS.this_thread;
    8887                recursion_count = 1;
     
    9594        else {
    9695                append( blocked_threads, kernelTLS.this_thread );
    97                 unlock( lock );
    98                 park( __cfaabi_dbg_ctx );
     96                BlockInternal( &lock );
    9997        }
    10098}
     
    103101        bool ret = false;
    104102        lock( lock __cfaabi_dbg_ctx2 );
    105         if( owner == 0p ) {
     103        if( owner == NULL ) {
    106104                owner = kernelTLS.this_thread;
    107105                recursion_count = 1;
     
    120118        recursion_count--;
    121119        if( recursion_count == 0 ) {
    122                 $thread * thrd = pop_head( blocked_threads );
     120                thread_desc * thrd = pop_head( blocked_threads );
    123121                owner = thrd;
    124122                recursion_count = (thrd ? 1 : 0);
    125                 unpark( thrd __cfaabi_dbg_ctx2 );
     123                WakeThread( thrd );
    126124        }
    127125        unlock( lock );
     
    140138void notify_one(condition_variable & this) with(this) {
    141139        lock( lock __cfaabi_dbg_ctx2 );
    142         unpark(
    143                 pop_head( this.blocked_threads ) __cfaabi_dbg_ctx2
     140        WakeThread(
     141                pop_head( this.blocked_threads )
    144142        );
    145143        unlock( lock );
     
    149147        lock( lock __cfaabi_dbg_ctx2 );
    150148        while(this.blocked_threads) {
    151                 unpark(
    152                         pop_head( this.blocked_threads ) __cfaabi_dbg_ctx2
     149                WakeThread(
     150                        pop_head( this.blocked_threads )
    153151                );
    154152        }
     
    159157        lock( this.lock __cfaabi_dbg_ctx2 );
    160158        append( this.blocked_threads, kernelTLS.this_thread );
    161         unlock( this.lock );
    162         park( __cfaabi_dbg_ctx );
     159        BlockInternal( &this.lock );
    163160}
    164161
     
    167164        lock( this.lock __cfaabi_dbg_ctx2 );
    168165        append( this.blocked_threads, kernelTLS.this_thread );
    169         unlock(l);
    170         unlock(this.lock);
    171         park( __cfaabi_dbg_ctx );
     166        void __unlock(void) {
     167                unlock(l);
     168                unlock(this.lock);
     169        }
     170        BlockInternal( __unlock );
    172171        lock(l);
    173172}
  • libcfa/src/concurrency/mutex.hfa

    r7030dab r71d6bd8  
    1111// Author           : Thierry Delisle
    1212// Created On       : Fri May 25 01:24:09 2018
    13 // Last Modified By : Peter A. Buhr
    14 // Last Modified On : Wed Dec  4 09:16:53 2019
    15 // Update Count     : 1
     13// Last Modified By : Thierry Delisle
     14// Last Modified On : Fri May 25 01:24:12 2018
     15// Update Count     : 0
    1616//
    1717
     
    3636
    3737        // List of blocked threads
    38         __queue_t(struct $thread) blocked_threads;
     38        __queue_t(struct thread_desc) blocked_threads;
    3939
    4040        // Locked flag
     
    5555
    5656        // List of blocked threads
    57         __queue_t(struct $thread) blocked_threads;
     57        __queue_t(struct thread_desc) blocked_threads;
    5858
    5959        // Current thread owning the lock
    60         struct $thread * owner;
     60        struct thread_desc * owner;
    6161
    6262        // Number of recursion level
     
    8383
    8484        // List of blocked threads
    85         __queue_t(struct $thread) blocked_threads;
     85        __queue_t(struct thread_desc) blocked_threads;
    8686};
    8787
     
    110110
    111111        static inline void ?{}(lock_scope(L) & this) {
    112                 this.locks = 0p;
     112                this.locks = NULL;
    113113                this.count = 0;
    114114        }
  • libcfa/src/concurrency/preemption.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Dec  5 16:34:05 2019
    13 // Update Count     : 43
     12// Last Modified On : Tue Jun  5 17:35:49 2018
     13// Update Count     : 37
    1414//
    1515
     
    2424#include <string.h>
    2525#include <unistd.h>
    26 #include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2726}
    2827
     
    3938// FwdDeclarations : timeout handlers
    4039static void preempt( processor   * this );
    41 static void timeout( $thread * this );
     40static void timeout( thread_desc * this );
    4241
    4342// FwdDeclarations : Signal handlers
     
    6564event_kernel_t * event_kernel;                        // kernel public handle to even kernel
    6665static pthread_t alarm_thread;                        // pthread handle to alarm thread
    67 static void * alarm_stack;                                                        // pthread stack for alarm thread
    6866
    6967static void ?{}(event_kernel_t & this) with( this ) {
     
    8381// Get next expired node
    8482static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) {
    85         if( !alarms->head ) return 0p;                                          // If no alarms return null
    86         if( alarms->head->alarm >= currtime ) return 0p;        // If alarms head not expired return null
    87         return pop(alarms);                                                                     // Otherwise just pop head
     83        if( !alarms->head ) return NULL;                          // If no alarms return null
     84        if( alarms->head->alarm >= currtime ) return NULL;        // If alarms head not expired return null
     85        return pop(alarms);                                       // Otherwise just pop head
    8886}
    8987
    9088// Tick one frame of the Discrete Event Simulation for alarms
    9189static void tick_preemption() {
    92         alarm_node_t * node = 0p;                                                       // Used in the while loop but cannot be declared in the while condition
    93         alarm_list_t * alarms = &event_kernel->alarms;          // Local copy for ease of reading
    94         Time currtime = __kernel_get_time();                            // Check current time once so everything "happens at once"
     90        alarm_node_t * node = NULL;                     // Used in the while loop but cannot be declared in the while condition
     91        alarm_list_t * alarms = &event_kernel->alarms;  // Local copy for ease of reading
     92        Time currtime = __kernel_get_time();                    // Check current time once so we everything "happens at once"
    9593
    9694        //Loop throught every thing expired
     
    184182
    185183        // Enable interrupts by decrementing the counter
    186         // If counter reaches 0, execute any pending __cfactx_switch
     184        // If counter reaches 0, execute any pending CtxSwitch
    187185        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    188186                processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store
     187                thread_desc * thrd = kernelTLS.this_thread;       // Cache the thread now since interrupts can start happening after the atomic store
    189188
    190189                with( kernelTLS.preemption_state ){
     
    208207                                if( proc->pending_preemption ) {
    209208                                        proc->pending_preemption = false;
    210                                         force_yield( __POLL_PREEMPTION );
     209                                        BlockInternal( thrd );
    211210                                }
    212211                        }
     
    218217
    219218        // Disable interrupts by incrementint the counter
    220         // Don't execute any pending __cfactx_switch even if counter reaches 0
     219        // Don't execute any pending CtxSwitch even if counter reaches 0
    221220        void enable_interrupts_noPoll() {
    222221                unsigned short prev = kernelTLS.preemption_state.disable_count;
     
    244243        sigaddset( &mask, sig );
    245244
    246         if ( pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {
     245        if ( pthread_sigmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
    247246            abort( "internal error, pthread_sigmask" );
    248247        }
     
    255254        sigaddset( &mask, sig );
    256255
    257         if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     256        if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
    258257            abort( "internal error, pthread_sigmask" );
    259258        }
     
    267266
    268267// reserved for future use
    269 static void timeout( $thread * this ) {
     268static void timeout( thread_desc * this ) {
    270269        //TODO : implement waking threads
    271270}
    272271
    273272// KERNEL ONLY
    274 // Check if a __cfactx_switch signal handler shoud defer
     273// Check if a CtxSwitch signal handler shoud defer
    275274// If true  : preemption is safe
    276275// If false : preemption is unsafe and marked as pending
     
    302301
    303302        // Setup proper signal handlers
    304         __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
     303        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART );         // CtxSwitch handler
    305304
    306305        signal_block( SIGALRM );
    307306
    308         alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p );
     307        pthread_create( &alarm_thread, NULL, alarm_loop, NULL );
    309308}
    310309
     
    317316        sigset_t mask;
    318317        sigfillset( &mask );
    319         sigprocmask( SIG_BLOCK, &mask, 0p );
     318        sigprocmask( SIG_BLOCK, &mask, NULL );
    320319
    321320        // Notify the alarm thread of the shutdown
     
    324323
    325324        // Wait for the preemption thread to finish
    326 
    327         pthread_join( alarm_thread, 0p );
    328         free( alarm_stack );
     325        pthread_join( alarm_thread, NULL );
    329326
    330327        // Preemption is now fully stopped
     
    383380        static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" );
    384381        #endif
    385         if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {
     382        if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), NULL ) == -1 ) {
    386383                abort( "internal error, sigprocmask" );
    387384        }
     
    393390        // Preemption can occur here
    394391
    395         force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch
     392        BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch
    396393}
    397394
     
    402399        sigset_t mask;
    403400        sigfillset(&mask);
    404         if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     401        if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
    405402            abort( "internal error, pthread_sigmask" );
    406403        }
     
    423420                                        {__cfaabi_dbg_print_buffer_decl( " KERNEL: Spurious wakeup %d.\n", err );}
    424421                                        continue;
    425                                 case EINVAL :
     422                        case EINVAL :
    426423                                        abort( "Timeout was invalid." );
    427424                                default:
     
    456453EXIT:
    457454        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    458         return 0p;
     455        return NULL;
    459456}
    460457
     
    469466        sigset_t oldset;
    470467        int ret;
    471         ret = pthread_sigmask(0, 0p, &oldset);
     468        ret = pthread_sigmask(0, NULL, &oldset);
    472469        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    473470
  • libcfa/src/concurrency/thread.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 09:17:49 2019
    13 // Update Count     : 9
     12// Last Modified On : Fri Mar 30 17:19:52 2018
     13// Update Count     : 8
    1414//
    1515
     
    2323#include "invoke.h"
    2424
     25extern "C" {
     26        #include <fenv.h>
     27        #include <stddef.h>
     28}
     29
     30//extern volatile thread_local processor * this_processor;
     31
    2532//-----------------------------------------------------------------------------
    2633// Thread ctors and dtors
    27 void ?{}($thread & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
    28         context{ 0p, 0p };
     34void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
     35        context{ NULL, NULL };
    2936        self_cor{ name, storage, storageSize };
    3037        state = Start;
    31         preempted = __NO_PREEMPTION;
    3238        curr_cor = &self_cor;
    3339        self_mon.owner = &this;
     
    3541        self_mon_p = &self_mon;
    3642        curr_cluster = &cl;
    37         next = 0p;
     43        next = NULL;
    3844
    39         node.next = 0p;
    40         node.prev = 0p;
     45        node.next = NULL;
     46        node.prev = NULL;
    4147        doregister(curr_cluster, this);
    4248
     
    4450}
    4551
    46 void ^?{}($thread& this) with( this ) {
     52void ^?{}(thread_desc& this) with( this ) {
    4753        unregister(curr_cluster, this);
    4854        ^self_cor{};
    4955}
    5056
    51 //-----------------------------------------------------------------------------
    52 // Starting and stopping threads
    53 forall( dtype T | is_thread(T) )
    54 void __thrd_start( T & this, void (*main_p)(T &) ) {
    55         $thread * this_thrd = get_thread(this);
    56 
    57         disable_interrupts();
    58         __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread);
    59 
    60         this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
    61         verify( this_thrd->context.SP );
    62 
    63         __schedule_thread(this_thrd);
    64         enable_interrupts( __cfaabi_dbg_ctx );
    65 }
    66 
    67 //-----------------------------------------------------------------------------
    68 // Support for threads that don't ues the thread keyword
    6957forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } )
    7058void ?{}( scoped(T)& this ) with( this ) {
    7159        handle{};
    72         __thrd_start(handle, main);
     60        __thrd_start(handle);
    7361}
    7462
     
    7664void ?{}( scoped(T)& this, P params ) with( this ) {
    7765        handle{ params };
    78         __thrd_start(handle, main);
     66        __thrd_start(handle);
    7967}
    8068
     
    8472}
    8573
     74//-----------------------------------------------------------------------------
     75// Starting and stopping threads
     76forall( dtype T | is_thread(T) )
     77void __thrd_start( T& this ) {
     78        thread_desc * this_thrd = get_thread(this);
     79        thread_desc * curr_thrd = TL_GET( this_thread );
     80
     81        disable_interrupts();
     82        CtxStart(&this, CtxInvokeThread);
     83        this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
     84        verify( this_thrd->context.SP );
     85        CtxSwitch( &curr_thrd->context, &this_thrd->context );
     86
     87        ScheduleThread(this_thrd);
     88        enable_interrupts( __cfaabi_dbg_ctx );
     89}
     90
     91extern "C" {
     92        // KERNEL ONLY
     93        void __finish_creation(thread_desc * this) {
     94                // set new coroutine that the processor is executing
     95                // and context switch to it
     96                verify( kernelTLS.this_thread != this );
     97                verify( kernelTLS.this_thread->context.SP );
     98                CtxSwitch( &this->context, &kernelTLS.this_thread->context );
     99        }
     100}
     101
     102void yield( void ) {
     103        // Safety note : This could cause some false positives due to preemption
     104      verify( TL_GET( preemption_state.enabled ) );
     105        BlockInternal( TL_GET( this_thread ) );
     106        // Safety note : This could cause some false positives due to preemption
     107      verify( TL_GET( preemption_state.enabled ) );
     108}
     109
     110void yield( unsigned times ) {
     111        for( unsigned i = 0; i < times; i++ ) {
     112                yield();
     113        }
     114}
     115
    86116// Local Variables: //
    87117// mode: c //
  • libcfa/src/concurrency/thread.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 09:18:14 2019
    13 // Update Count     : 6
     12// Last Modified On : Fri Jun 21 17:51:33 2019
     13// Update Count     : 5
    1414//
    1515
     
    2828      void ^?{}(T& mutex this);
    2929      void main(T& this);
    30       $thread* get_thread(T& this);
     30      thread_desc* get_thread(T& this);
    3131};
    3232
    33 // define that satisfies the trait without using the thread keyword
    34 #define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this)
    35 
    36 // Inline getters for threads/coroutines/monitors
    37 forall( dtype T | is_thread(T) )
    38 static inline $coroutine* get_coroutine(T & this) __attribute__((const)) { return &get_thread(this)->self_cor; }
     33#define DECL_THREAD(X) thread_desc* get_thread(X& this) { return &this.__thrd; } void main(X& this)
    3934
    4035forall( dtype T | is_thread(T) )
    41 static inline $monitor  * get_monitor  (T & this) __attribute__((const)) { return &get_thread(this)->self_mon; }
     36static inline coroutine_desc* get_coroutine(T & this) {
     37        return &get_thread(this)->self_cor;
     38}
    4239
    43 static inline $coroutine* get_coroutine($thread * this) __attribute__((const)) { return &this->self_cor; }
    44 static inline $monitor  * get_monitor  ($thread * this) __attribute__((const)) { return &this->self_mon; }
     40forall( dtype T | is_thread(T) )
     41static inline monitor_desc* get_monitor(T & this) {
     42        return &get_thread(this)->self_mon;
     43}
    4544
    46 //-----------------------------------------------------------------------------
    47 // forward declarations needed for threads
     45static inline coroutine_desc* get_coroutine(thread_desc * this) {
     46        return &this->self_cor;
     47}
     48
     49static inline monitor_desc* get_monitor(thread_desc * this) {
     50        return &this->self_mon;
     51}
     52
    4853extern struct cluster * mainCluster;
    4954
    5055forall( dtype T | is_thread(T) )
    51 void __thrd_start( T & this, void (*)(T &) );
     56void __thrd_start( T & this );
    5257
    5358//-----------------------------------------------------------------------------
    5459// Ctors and dtors
    55 void ?{}($thread & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );
    56 void ^?{}($thread & this);
     60void ?{}(thread_desc & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );
     61void ^?{}(thread_desc & this);
    5762
    58 static inline void ?{}($thread & this)                                                                  { this{ "Anonymous Thread", *mainCluster, 0p, 65000 }; }
    59 static inline void ?{}($thread & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, 0p, stackSize }; }
    60 static inline void ?{}($thread & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
    61 static inline void ?{}($thread & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, 0p, 65000 }; }
    62 static inline void ?{}($thread & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, 0p, stackSize }; }
    63 static inline void ?{}($thread & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
    64 static inline void ?{}($thread & this, const char * const name)                                         { this{ name, *mainCluster, 0p, 65000 }; }
    65 static inline void ?{}($thread & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
    66 static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
     63static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; }
     64static inline void ?{}(thread_desc & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, NULL, stackSize }; }
     65static inline void ?{}(thread_desc & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
     66static inline void ?{}(thread_desc & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, NULL, 65000 }; }
     67static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, NULL, stackSize }; }
     68static inline void ?{}(thread_desc & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
     69static inline void ?{}(thread_desc & this, const char * const name)                                         { this{ name, *mainCluster, NULL, 65000 }; }
     70static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, NULL, 65000 }; }
     71static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, NULL, stackSize }; }
    6772
    6873//-----------------------------------------------------------------------------
     
    8388void ^?{}( scoped(T)& this );
    8489
    85 //-----------------------------------------------------------------------------
    86 // Thread getters
    87 static inline struct $thread * active_thread () { return TL_GET( this_thread ); }
     90void yield();
     91void yield( unsigned times );
    8892
    89 //-----------------------------------------------------------------------------
    90 // Scheduler API
    91 
    92 //----------
    93 // Park thread: block until corresponding call to unpark, won't block if unpark is already called
    94 void park( __cfaabi_dbg_ctx_param );
    95 
    96 //----------
    97 // Unpark a thread, if the thread is already blocked, schedule it
    98 //                  if the thread is not yet block, signal that it should rerun immediately
    99 void unpark( $thread * this __cfaabi_dbg_ctx_param2 );
    100 
    101 forall( dtype T | is_thread(T) )
    102 static inline void unpark( T & this __cfaabi_dbg_ctx_param2 ) { if(!&this) return; unpark( get_thread( this ) __cfaabi_dbg_ctx_fwd2 );}
    103 
    104 //----------
    105 // Yield: force thread to block and be rescheduled
    106 bool force_yield( enum __Preemption_Reason );
    107 
    108 static inline void yield() {
    109         force_yield(__MANUAL_PREEMPTION);
    110 }
    111 
    112 // Yield: yield N times
    113 static inline void yield( unsigned times ) {
    114         for( times ) {
    115                 yield();
    116         }
    117 }
     93static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); }
    11894
    11995// Local Variables: //
  • libcfa/src/exception.c

    r7030dab r71d6bd8  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:13:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Apr 03 11:57:00 2020
    13 // Update Count     : 14
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb 22 18:17:34 2018
     13// Update Count     : 11
    1414//
    1515
    16 // Normally we would get this from the CFA prelude.
    1716#include <stddef.h> // for size_t
    1817
    1918#include "exception.h"
    2019
    21 // Implementation of the secret header is hardware dependent.
    22 #if !( defined( __x86_64 ) || defined( __i386 ) )
    23 #error Exception Handling: No known architecture detected.
    24 #endif
     20// Implementation of the secret header.
    2521
    2622#include <stdlib.h>
     
    3127// FIX ME: temporary hack to keep ARM build working
    3228#ifndef _URC_FATAL_PHASE1_ERROR
    33 #define _URC_FATAL_PHASE1_ERROR 3
     29#define _URC_FATAL_PHASE1_ERROR 2
    3430#endif // ! _URC_FATAL_PHASE1_ERROR
    3531#ifndef _URC_FATAL_PHASE2_ERROR
     
    3935#include "lsda.h"
    4036
    41 /* The exception class for our exceptions. Because of the vendor component
    42  * its value would not be standard.
    43  * Vendor: UWPL
    44  * Language: CFA\0
    45  */
    46 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    4737
    4838// 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 = {
     39struct __cfaabi_ehm__base_exception_t_vtable
     40                ___cfaabi_ehm__base_exception_t_vtable_instance = {
    5141        .parent = NULL,
    5242        .size = 0,
     
    5949// Temperary global exception context. Does not work with concurency.
    6050struct exception_context_t {
    61         struct __cfaehm_try_resume_node * top_resume;
    62 
    63         exception_t * current_exception;
    64         int current_handler_index;
    65 } static shared_stack = {NULL, NULL, 0};
     51    struct __cfaabi_ehm__try_resume_node * top_resume;
     52    struct __cfaabi_ehm__try_resume_node * current_resume;
     53
     54    exception_t * current_exception;
     55    int current_handler_index;
     56} shared_stack = {NULL, NULL, 0, 0};
    6657
    6758// Get the current exception context.
     
    7162        return &shared_stack;
    7263}
     64//#define SAVE_EXCEPTION_CONTEXT(to_name)
     65//struct exception_context_t * to_name = this_exception_context();
     66//exception * this_exception() {
     67//    return this_exception_context()->current_exception;
     68//}
     69
     70
     71// This macro should be the only thing that needs to change across machines.  Used in the personality function, way down
     72// in termination.
     73// struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception_t *)
     74#define MATCHER_FROM_CONTEXT(ptr_to_context) \
     75        (*(_Unwind_Reason_Code(**)(exception_t *))(_Unwind_GetCFA(ptr_to_context) + 8))
    7376
    7477
    7578// RESUMPTION ================================================================
    7679
    77 void __cfaehm_throw_resume(exception_t * except) {
    78         struct exception_context_t * context = this_exception_context();
     80void __cfaabi_ehm__throw_resume(exception_t * except) {
    7981
    8082        __cfaabi_dbg_print_safe("Throwing resumption exception\n");
    8183
    82         struct __cfaehm_try_resume_node * original_head = context->top_resume;
    83         struct __cfaehm_try_resume_node * current = context->top_resume;
     84        struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume;
     85        struct __cfaabi_ehm__try_resume_node * current =
     86                (original_head) ? original_head->next : shared_stack.top_resume;
    8487
    8588        for ( ; current ; current = current->next) {
    86                 context->top_resume = current->next;
     89                shared_stack.current_resume = current;
    8790                if (current->handler(except)) {
    88                         context->top_resume = original_head;
     91                        shared_stack.current_resume = original_head;
    8992                        return;
    9093                }
     
    9295
    9396        __cfaabi_dbg_print_safe("Unhandled exception\n");
    94         context->top_resume = original_head;
     97        shared_stack.current_resume = original_head;
    9598
    9699        // Fall back to termination:
    97         __cfaehm_throw_terminate(except);
     100        __cfaabi_ehm__throw_terminate(except);
    98101        // TODO: Default handler for resumption.
    99102}
    100103
    101 // Do we control where exceptions get thrown even with concurency?
    102 // If not these are not quite thread safe, the cleanup hook has to
    103 // be added after the node is built but before it is made the top node.
    104 
    105 void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node,
     104// Do we control where exceptions get thrown even with concurency?  If not these are not quite thread safe, the cleanup
     105// hook has to be added after the node is built but before it is made the top node.
     106
     107void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
    106108                        _Bool (*handler)(exception_t * except)) {
    107         struct exception_context_t * context = this_exception_context();
    108         node->next = context->top_resume;
     109        node->next = shared_stack.top_resume;
    109110        node->handler = handler;
    110         context->top_resume = node;
    111 }
    112 
    113 void __cfaehm_try_resume_cleanup(struct __cfaehm_try_resume_node * node) {
    114         struct exception_context_t * context = this_exception_context();
    115         context->top_resume = node->next;
     111        shared_stack.top_resume = node;
     112}
     113
     114void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
     115        shared_stack.top_resume = node->next;
    116116}
    117117
     
    122122// May have to move to cfa for constructors and destructors (references).
    123123
    124 // How to clean up an exception in various situations.
    125 static void __cfaehm_exception_cleanup(
    126                 _Unwind_Reason_Code reason,
    127                 struct _Unwind_Exception * exception) {
    128         switch (reason) {
    129         case _URC_FOREIGN_EXCEPTION_CAUGHT:
    130                 // This one we could clean-up to allow cross-language exceptions.
    131         case _URC_FATAL_PHASE1_ERROR:
    132         case _URC_FATAL_PHASE2_ERROR:
    133         default:
    134                 abort();
    135         }
    136 }
    137 
    138 // We need a piece of storage to raise the exception, for now its a single
    139 // piece.
    140 static struct _Unwind_Exception this_exception_storage;
    141 
    142 struct __cfaehm_node {
    143         struct __cfaehm_node * next;
     124struct __cfaabi_ehm__node {
     125        struct __cfaabi_ehm__node * next;
    144126};
    145127
    146128#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    147 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
     129#define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1)
    148130
    149131// Creates a copy of the indicated exception and sets current_exception to it.
    150 static void __cfaehm_allocate_exception( exception_t * except ) {
     132static void __cfaabi_ehm__allocate_exception( exception_t * except ) {
    151133        struct exception_context_t * context = this_exception_context();
    152134
    153135        // Allocate memory for the exception.
    154         struct __cfaehm_node * store = malloc(
    155                 sizeof( struct __cfaehm_node ) + except->virtual_table->size );
     136        struct __cfaabi_ehm__node * store = malloc(
     137                sizeof( struct __cfaabi_ehm__node ) + except->virtual_table->size );
    156138
    157139        if ( ! store ) {
     
    166148        // Copy the exception to storage.
    167149        except->virtual_table->copy( context->current_exception, except );
    168 
    169         // Set up the exception storage.
    170         this_exception_storage.exception_class = __cfaehm_exception_class;
    171         this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
    172150}
    173151
    174152// Delete the provided exception, unsetting current_exception if relivant.
    175 static void __cfaehm_delete_exception( exception_t * except ) {
     153static void __cfaabi_ehm__delete_exception( exception_t * except ) {
    176154        struct exception_context_t * context = this_exception_context();
    177155
     
    179157
    180158        // Remove the exception from the list.
    181         struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except);
    182         struct __cfaehm_node * node;
     159        struct __cfaabi_ehm__node * to_free = EXCEPT_TO_NODE(except);
     160        struct __cfaabi_ehm__node * node;
    183161
    184162        if ( context->current_exception == except ) {
     
    188166                node = EXCEPT_TO_NODE(context->current_exception);
    189167                // It may always be in the first or second position.
    190                 while ( to_free != node->next ) {
     168                while( to_free != node->next ) {
    191169                        node = node->next;
    192170                }
     
    200178
    201179// If this isn't a rethrow (*except==0), delete the provided exception.
    202 void __cfaehm_cleanup_terminate( void * except ) {
    203         if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except );
    204 }
     180void __cfaabi_ehm__cleanup_terminate( void * except ) {
     181        if ( *(void**)except ) __cfaabi_ehm__delete_exception( *(exception_t **)except );
     182}
     183
     184
     185// We need a piece of storage to raise the exception
     186struct _Unwind_Exception this_exception_storage;
    205187
    206188// Function needed by force unwind
     
    209191                int version,
    210192                _Unwind_Action actions,
    211                 _Unwind_Exception_Class exception_class,
     193                _Unwind_Exception_Class exceptionClass,
    212194                struct _Unwind_Exception * unwind_exception,
    213                 struct _Unwind_Context * unwind_context,
    214                 void * stop_param) {
    215         if ( actions & _UA_END_OF_STACK  ) exit(1);
    216         if ( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
     195                struct _Unwind_Context * context,
     196                void * some_param) {
     197        if( actions & _UA_END_OF_STACK  ) exit(1);
     198        if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
    217199
    218200        return _URC_FATAL_PHASE2_ERROR;
     
    220202
    221203// The exception that is being thrown must already be stored.
    222 static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) {
     204__attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {
    223205        if ( ! this_exception_context()->current_exception ) {
    224206                printf("UNWIND ERROR missing exception in begin unwind\n");
     
    226208        }
    227209
     210
    228211        // Call stdlibc to raise the exception
    229212        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    230213
    231         // If we reach here it means something happened. For resumption to work we need to find a way
    232         // to return back to here. Most of them will probably boil down to setting a global flag and
    233         // making the phase 1 either stop or fail. Causing an error on purpose may help avoiding
    234         // unnecessary work but it might have some weird side effects. If we just pretend no handler
    235         // was found that would work but may be expensive for no reason since we will always search
    236         // the whole stack.
    237 
    238         if ( ret == _URC_END_OF_STACK ) {
    239                 // No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
    240                 // Here we force unwind the stack, basically raising a cancellation.
     214        // If we reach here it means something happened.  For resumption to work we need to find a way to return back to
     215        // here.  Most of them will probably boil down to setting a global flag and making the phase 1 either stop or
     216        // fail.  Causing an error on purpose may help avoiding unnecessary work but it might have some weird side
     217        // effects.  If we just pretend no handler was found that would work but may be expensive for no reason since we
     218        // will always search the whole stack.
     219
     220        if( ret == _URC_END_OF_STACK ) {
     221                // No proper handler was found.  This can be handled in several way.  C++ calls std::terminate Here we
     222                // force unwind the stack, basically raising a cancellation.
    241223                printf("Uncaught exception %p\n", &this_exception_storage);
    242224
     
    246228        }
    247229
    248         // We did not simply reach the end of the stack without finding a handler. This is an error.
     230        // We did not simply reach the end of the stack without finding a handler.  Something wen't wrong
    249231        printf("UNWIND ERROR %d after raise exception\n", ret);
    250232        abort();
    251233}
    252234
    253 void __cfaehm_throw_terminate( exception_t * val ) {
     235void __cfaabi_ehm__throw_terminate( exception_t * val ) {
    254236        __cfaabi_dbg_print_safe("Throwing termination exception\n");
    255237
    256         __cfaehm_allocate_exception( val );
    257         __cfaehm_begin_unwind();
    258 }
    259 
    260 void __cfaehm_rethrow_terminate(void) {
     238        __cfaabi_ehm__allocate_exception( val );
     239        __cfaabi_ehm__begin_unwind();
     240}
     241
     242void __cfaabi_ehm__rethrow_terminate(void) {
    261243        __cfaabi_dbg_print_safe("Rethrowing termination exception\n");
    262244
    263         __cfaehm_begin_unwind();
    264 }
    265 
    266 // This is our personality routine. For every stack frame annotated with
    267 // ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
    268 //  Once in the search phase and once in the cleanup phase.
    269 _Unwind_Reason_Code __gcfa_personality_v0(
    270                 int version,
    271                 _Unwind_Action actions,
    272                 unsigned long long exception_class,
    273                 struct _Unwind_Exception * unwind_exception,
    274                 struct _Unwind_Context * unwind_context)
     245        __cfaabi_ehm__begin_unwind();
     246}
     247
     248#if defined(PIC)
     249#warning Exceptions not yet supported when using Position-Independent Code
     250__attribute__((noinline))
     251void __cfaabi_ehm__try_terminate(void (*try_block)(),
     252                void (*catch_block)(int index, exception_t * except),
     253                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     254        abort();
     255}
     256#else
     257// This is our personality routine.  For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0".
     258// This function will be called twice when unwinding.  Once in the search phased and once in the cleanup phase.
     259_Unwind_Reason_Code __gcfa_personality_v0 (
     260                int version, _Unwind_Action actions, unsigned long long exceptionClass,
     261                struct _Unwind_Exception* unwind_exception,
     262                struct _Unwind_Context* context)
    275263{
    276264
    277265        //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    278         __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
    279                         version, actions, exception_class, unwind_exception, unwind_context);
     266        __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
    280267
    281268        // If we've reached the end of the stack then there is nothing much we can do...
    282         if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;
     269        if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
    283270
    284271        if (actions & _UA_SEARCH_PHASE) {
     
    295282
    296283        // Get a pointer to the language specific data from which we will read what we need
    297         const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
    298 
    299         if ( !lsd ) {   //Nothing to do, keep unwinding
     284        const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
     285
     286        if( !lsd ) {    //Nothing to do, keep unwinding
    300287                printf(" no LSD");
    301288                goto UNWIND;
     
    304291        // Get the instuction pointer and a reading pointer into the exception table
    305292        lsda_header_info lsd_info;
    306         const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info);
    307         _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context);
    308 
    309         struct exception_context_t * context = this_exception_context();
     293        const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
     294        _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
    310295
    311296        // Linearly search the table for stuff to do
    312         while ( cur_ptr < lsd_info.action_table ) {
     297        while( cur_ptr < lsd_info.action_table ) {
    313298                _Unwind_Ptr callsite_start;
    314299                _Unwind_Ptr callsite_len;
     
    317302
    318303                // Decode the common stuff we have in here
    319                 cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
    320                 cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
    321                 cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
    322                 cur_ptr = read_uleb128(cur_ptr, &callsite_action);
     304                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
     305                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
     306                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
     307                cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
    323308
    324309                // Have we reach the correct frame info yet?
    325                 if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     310                if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    326311#ifdef __CFA_DEBUG_PRINT__
    327312                        void * ls = (void*)lsd_info.Start;
     
    331316                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    332317                        void * ip = (void*)instruction_ptr;
    333                         __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
    334                                         bp, ep, ls, cs, cl, ip);
     318                        __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
    335319#endif // __CFA_DEBUG_PRINT__
    336320                        continue;
    337321                }
    338322
    339                 // Have we gone too far?
    340                 if ( lsd_info.Start + callsite_start > instruction_ptr ) {
     323                // Have we gone too far
     324                if( lsd_info.Start + callsite_start > instruction_ptr ) {
    341325                        printf(" gone too far");
    342326                        break;
    343327                }
    344328
    345                 // Check for what we must do:
    346                 if ( 0 == callsite_landing_pad ) {
    347                         // Nothing to do, move along
    348                         __cfaabi_dbg_print_safe(" no landing pad");
    349                 } else if (actions & _UA_SEARCH_PHASE) {
    350                         // In search phase, these means we found a potential handler we must check.
    351 
    352                         // We have arbitrarily decided that 0 means nothing to do and 1 means there is
    353                         // a potential handler. This doesn't seem to conflict the gcc default behavior.
    354                         if (callsite_action != 0) {
    355                                 // Now we want to run some code to see if the handler matches
    356                                 // This is the tricky part where we want to the power to run arbitrary code
    357                                 // However, generating a new exception table entry and try routine every time
    358                                 // is way more expansive than we might like
    359                                 // The information we have is :
    360                                 //  - The GR (Series of registers)
    361                                 //    GR1=GP Global Pointer of frame ref by context
    362                                 //  - The instruction pointer
    363                                 //  - The instruction pointer info (???)
    364                                 //  - The CFA (Canonical Frame Address)
    365                                 //  - The BSP (Probably the base stack pointer)
    366 
    367                                 // The current apprach uses one exception table entry per try block
    368                                 _uleb128_t imatcher;
    369                                 // Get the relative offset to the {...}?
    370                                 cur_ptr = read_uleb128(cur_ptr, &imatcher);
    371 
    372 #                               if defined( __x86_64 )
    373                                 _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 8;
    374 #                               elif defined( __i386 )
    375                                 _Unwind_Word match_pos = _Unwind_GetCFA(unwind_context) + 24;
    376 #                               endif
    377                                 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos;
    378 
    379                                 int index = matcher(context->current_exception);
    380                                 _Unwind_Reason_Code ret = (0 == index)
    381                                         ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    382                                 context->current_handler_index = index;
    383 
    384                                 // Based on the return value, check if we matched the exception
    385                                 if (ret == _URC_HANDLER_FOUND) {
    386                                         __cfaabi_dbg_print_safe(" handler found\n");
    387                                 } else {
    388                                         __cfaabi_dbg_print_safe(" no handler\n");
     329                // Something to do?
     330                if( callsite_landing_pad ) {
     331                        // Which phase are we in
     332                        if (actions & _UA_SEARCH_PHASE) {
     333                                // Search phase, this means we probably found a potential handler and must check if it is a match
     334
     335                                // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
     336                                // This doesn't seem to conflict the gcc default behavior
     337                                if (callsite_action != 0) {
     338                                        // Now we want to run some code to see if the handler matches
     339                                        // This is the tricky part where we want to the power to run arbitrary code
     340                                        // However, generating a new exception table entry and try routine every time
     341                                        // is way more expansive than we might like
     342                                        // The information we have is :
     343                                        //  - The GR (Series of registers)
     344                                        //    GR1=GP Global Pointer of frame ref by context
     345                                        //  - The instruction pointer
     346                                        //  - The instruction pointer info (???)
     347                                        //  - The CFA (Canonical Frame Address)
     348                                        //  - The BSP (Probably the base stack pointer)
     349
     350
     351                                        // The current apprach uses one exception table entry per try block
     352                                        _uleb128_t imatcher;
     353                                        // Get the relative offset to the
     354                                        cur_ptr = read_uleb128 (cur_ptr, &imatcher);
     355
     356                                        // Get a function pointer from the relative offset and call it
     357                                        // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;
     358
     359                                        _Unwind_Reason_Code (*matcher)(exception_t *) =
     360                                                MATCHER_FROM_CONTEXT(context);
     361                                        int index = matcher(shared_stack.current_exception);
     362                                        _Unwind_Reason_Code ret = (0 == index)
     363                                                ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     364                                        shared_stack.current_handler_index = index;
     365
     366                                        // Based on the return value, check if we matched the exception
     367                                        if( ret == _URC_HANDLER_FOUND) {
     368                                                __cfaabi_dbg_print_safe(" handler found\n");
     369                                        } else {
     370                                                __cfaabi_dbg_print_safe(" no handler\n");
     371                                        }
     372                                        return ret;
    389373                                }
    390                                 return ret;
     374
     375                                // This is only a cleanup handler, ignore it
     376                                __cfaabi_dbg_print_safe(" no action");
    391377                        }
    392 
    393                         // This is only a cleanup handler, ignore it
    394                         __cfaabi_dbg_print_safe(" no action");
    395                 } else if (actions & _UA_CLEANUP_PHASE) {
    396                         // In clean-up phase, no destructors here but this could be the handler.
    397 
    398                         if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
    399                                 // If this is a potential exception handler
    400                                 // but not the one that matched the exception in the seach phase,
    401                                 // just ignore it
    402                                 goto UNWIND;
     378                        else if (actions & _UA_CLEANUP_PHASE) {
     379
     380                                if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     381                                        // If this is a potential exception handler
     382                                        // but not the one that matched the exception in the seach phase,
     383                                        // just ignore it
     384                                        goto UNWIND;
     385                                }
     386
     387                                // We need to run some clean-up or a handler
     388                                // These statment do the right thing but I don't know any specifics at all
     389                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
     390                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
     391
     392                                // I assume this sets the instruction pointer to the adress of the landing pad
     393                                // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
     394                                _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
     395
     396                                __cfaabi_dbg_print_safe(" action\n");
     397
     398                                // Return have some action to run
     399                                return _URC_INSTALL_CONTEXT;
    403400                        }
    404 
    405                         // We need to run some clean-up or a handler
    406                         // These statment do the right thing but I don't know any specifics at all
    407                         _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0),
    408                                 (_Unwind_Ptr)unwind_exception );
    409                         _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 );
    410 
    411                         // I assume this sets the instruction pointer to the adress of the landing pad
    412                         // It doesn't actually set it, it only state the value that needs to be set once we
    413                         // return _URC_INSTALL_CONTEXT
    414                         _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) );
    415 
    416                         __cfaabi_dbg_print_safe(" action\n");
    417 
    418                         // Return have some action to run
    419                         return _URC_INSTALL_CONTEXT;
    420401                }
     402
     403                // Nothing to do, move along
     404                __cfaabi_dbg_print_safe(" no landing pad");
    421405        }
    422406        // No handling found
     
    430414}
    431415
    432 #pragma GCC push_options
    433 #pragma GCC optimize("O0")
    434 
    435 // Try statements are hoisted out see comments for details. While this could probably be unique
    436 // and simply linked from libcfa but there is one problem left, see the exception table for details
     416// Try statements are hoisted out see comments for details.  With this could probably be unique and simply linked from
     417// libcfa but there is one problem left, see the exception table for details
    437418__attribute__((noinline))
    438 void __cfaehm_try_terminate(void (*try_block)(),
     419void __cfaabi_ehm__try_terminate(void (*try_block)(),
    439420                void (*catch_block)(int index, exception_t * except),
    440421                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     
    442423        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    443424
    444         // Setup the personality routine and exception table.
    445         // Unforturnately these clobber gcc cancellation support which means we can't get access to
    446         // the attribute cleanup tables at the same time. We would have to inspect the assembly to
    447         // create a new set ourselves.
    448 #ifdef __PIC__
    449         asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0");
    450         asm volatile (".cfi_lsda 0x1b, .LLSDACFA2");
    451 #else
     425        // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.
     426        // However, they clobber gcc cancellation support from gcc.  We can replace the personality routine but
     427        // replacing the exception table gcc generates is not really doable, it generates labels based on how the
     428        // assembly works.
     429
     430        // Setup the personality routine
    452431        asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
     432        // Setup the exception table
    453433        asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
    454 #endif
    455434
    456435        // Label which defines the start of the area for which the handler is setup.
     
    463442        asm volatile goto ("" : : : : CATCH );
    464443
    465         // Normal return for when there is no throw.
     444        // Normal return
    466445        return;
    467446
     
    470449        // Label which defines the end of the area for which the handler is setup.
    471450        asm volatile (".TRYEND:");
    472         // Label which defines the start of the exception landing pad. Basically what is called when
    473         // the exception is caught. Note, if multiple handlers are given, the multiplexing should be
    474         // done by the generated code, not the exception runtime.
     451        // Label which defines the start of the exception landing pad.  Basically what is called when the exception is
     452        // caught.  Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the
     453        // exception runtime.
    475454        asm volatile (".CATCH:");
    476455
    477456        // Exception handler
    478         // Note: Saving the exception context on the stack breaks termination exceptions.
    479         catch_block( this_exception_context()->current_handler_index,
    480                      this_exception_context()->current_exception );
    481 }
    482 
    483 // Exception table data we need to generate. While this is almost generic, the custom data refers
    484 // to {*}try_terminate, which is no way generic. Some more works need to be done if we want to
    485 // have a single call to the try routine.
    486 
    487 #ifdef __PIC__
     457        catch_block( shared_stack.current_handler_index,
     458                     shared_stack.current_exception );
     459}
     460
     461// Exception table data we need to generate.  While this is almost generic, the custom data refers to foo_try_match try
     462// match, which is no way generic.  Some more works need to be done if we want to have a single call to the try routine.
     463
     464#if defined( __i386 ) || defined( __x86_64 )
    488465asm (
    489         // HEADER
     466        //HEADER
    490467        ".LFECFA1:\n"
    491468        "       .globl  __gcfa_personality_v0\n"
    492469        "       .section        .gcc_except_table,\"a\",@progbits\n"
    493         // TABLE HEADER (important field is the BODY length at the end)
    494         ".LLSDACFA2:\n"
     470        ".LLSDACFA2:\n"                                                 //TABLE header
    495471        "       .byte   0xff\n"
    496472        "       .byte   0xff\n"
    497473        "       .byte   0x1\n"
    498         "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
    499         // BODY (language specific data)
    500         // This uses language specific data and can be modified arbitrarily
    501         // We use handled area offset, handled area length,
    502         // handler landing pad offset and 1 (action code, gcc seems to use 0).
    503         ".LLSDACSBCFA2:\n"
    504         "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    505         "       .uleb128 .TRYEND-.TRYSTART\n"
    506         "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    507         "       .uleb128 1\n"
    508         ".LLSDACSECFA2:\n"
    509         // TABLE FOOTER
    510         "       .text\n"
    511         "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
     474        "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"         // BODY length
     475        // Body uses language specific data and therefore could be modified arbitrarily
     476        ".LLSDACSBCFA2:\n"                                              // BODY start
     477        "       .uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"               // Handled area start  (relative to start of function)
     478        "       .uleb128 .TRYEND-.TRYSTART\n"                           // Handled area length
     479        "       .uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"                          // Hanlder landing pad adress  (relative to start of function)
     480        "       .uleb128 1\n"                                           // Action code, gcc seems to use always 0
     481        ".LLSDACSECFA2:\n"                                              // BODY end
     482        "       .text\n"                                                        // TABLE footer
     483        "       .size   __cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
     484        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
     485//      "       .section        .note.GNU-stack,\"x\",@progbits\n"
    512486);
    513 
    514 // Somehow this piece of helps with the resolution of debug symbols.
    515 __attribute__((unused)) static const int dummy = 0;
    516 
    517 asm (
    518         // Add a hidden symbol which points at the function.
    519         "       .hidden CFA.ref.__gcfa_personality_v0\n"
    520         "       .weak   CFA.ref.__gcfa_personality_v0\n"
    521         // No clue what this does specifically
    522         "       .section        .data.rel.local.CFA.ref.__gcfa_personality_v0,\"awG\",@progbits,CFA.ref.__gcfa_personality_v0,comdat\n"
    523         "       .align 8\n"
    524         "       .type CFA.ref.__gcfa_personality_v0, @object\n"
    525         "       .size CFA.ref.__gcfa_personality_v0, 8\n"
    526         "CFA.ref.__gcfa_personality_v0:\n"
    527 #if defined( __x86_64 )
    528         "       .quad __gcfa_personality_v0\n"
    529 #else // then __i386
    530         "   .long __gcfa_personality_v0\n"
    531 #endif
    532 );
    533 #else // __PIC__
    534 asm (
    535         // HEADER
    536         ".LFECFA1:\n"
    537         "       .globl  __gcfa_personality_v0\n"
    538         "       .section        .gcc_except_table,\"a\",@progbits\n"
    539         // TABLE HEADER (important field is the BODY length at the end)
    540         ".LLSDACFA2:\n"
    541         "       .byte   0xff\n"
    542         "       .byte   0xff\n"
    543         "       .byte   0x1\n"
    544         "       .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
    545         // BODY (language specific data)
    546         ".LLSDACSBCFA2:\n"
    547         //      Handled area start (relative to start of function)
    548         "       .uleb128 .TRYSTART-__cfaehm_try_terminate\n"
    549         //      Handled area length
    550         "       .uleb128 .TRYEND-.TRYSTART\n"
    551         //      Handler landing pad address (relative to start of function)
    552         "       .uleb128 .CATCH-__cfaehm_try_terminate\n"
    553         //      Action code, gcc seems to always use 0.
    554         "       .uleb128 1\n"
    555         // TABLE FOOTER
    556         ".LLSDACSECFA2:\n"
    557         "       .text\n"
    558         "       .size   __cfaehm_try_terminate, .-__cfaehm_try_terminate\n"
    559         "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    560         "       .section        .note.GNU-stack,\"x\",@progbits\n"
    561 );
    562 #endif // __PIC__
    563 
    564 #pragma GCC pop_options
     487#endif // __i386 || __x86_64
     488#endif //PIC
  • libcfa/src/exception.h

    r7030dab r71d6bd8  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 27 10:16:00 2020
    13 // Update Count     : 9
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb 22 18:11:15 2018
     13// Update Count     : 8
    1414//
    1515
     
    2121#endif
    2222
    23 struct __cfaehm_base_exception_t;
    24 typedef struct __cfaehm_base_exception_t exception_t;
    25 struct __cfaehm_base_exception_t_vtable {
    26         const struct __cfaehm_base_exception_t_vtable * parent;
     23struct __cfaabi_ehm__base_exception_t;
     24typedef struct __cfaabi_ehm__base_exception_t exception_t;
     25struct __cfaabi_ehm__base_exception_t_vtable {
     26        const struct __cfaabi_ehm__base_exception_t_vtable * parent;
    2727        size_t size;
    28         void (*copy)(struct __cfaehm_base_exception_t *this,
    29                      struct __cfaehm_base_exception_t * other);
    30         void (*free)(struct __cfaehm_base_exception_t *this);
    31         const char * (*msg)(struct __cfaehm_base_exception_t *this);
     28        void (*copy)(struct __cfaabi_ehm__base_exception_t *this,
     29                     struct __cfaabi_ehm__base_exception_t * other);
     30        void (*free)(struct __cfaabi_ehm__base_exception_t *this);
     31        const char * (*msg)(struct __cfaabi_ehm__base_exception_t *this);
    3232};
    33 struct __cfaehm_base_exception_t {
    34         struct __cfaehm_base_exception_t_vtable const * virtual_table;
     33struct __cfaabi_ehm__base_exception_t {
     34        struct __cfaabi_ehm__base_exception_t_vtable const * virtual_table;
    3535};
    36 extern struct __cfaehm_base_exception_t_vtable
    37         ___cfaehm_base_exception_t_vtable_instance;
     36extern struct __cfaabi_ehm__base_exception_t_vtable
     37        ___cfaabi_ehm__base_exception_t_vtable_instance;
    3838
    3939
    4040// Used in throw statement translation.
    41 void __cfaehm_throw_terminate(exception_t * except) __attribute__((noreturn));
    42 void __cfaehm_rethrow_terminate() __attribute__((noreturn));
    43 void __cfaehm_throw_resume(exception_t * except);
     41void __cfaabi_ehm__throw_terminate(exception_t * except) __attribute__((noreturn));
     42void __cfaabi_ehm__rethrow_terminate() __attribute__((noreturn));
     43void __cfaabi_ehm__throw_resume(exception_t * except);
    4444
    4545// Function catches termination exceptions.
    46 void __cfaehm_try_terminate(
     46void __cfaabi_ehm__try_terminate(
    4747    void (*try_block)(),
    4848    void (*catch_block)(int index, exception_t * except),
     
    5050
    5151// Clean-up the exception in catch blocks.
    52 void __cfaehm_cleanup_terminate(void * except);
     52void __cfaabi_ehm__cleanup_terminate(void * except);
    5353
    5454// Data structure creates a list of resume handlers.
    55 struct __cfaehm_try_resume_node {
    56     struct __cfaehm_try_resume_node * next;
     55struct __cfaabi_ehm__try_resume_node {
     56    struct __cfaabi_ehm__try_resume_node * next;
    5757    _Bool (*handler)(exception_t * except);
    5858};
    5959
    6060// These act as constructor and destructor for the resume node.
    61 void __cfaehm_try_resume_setup(
    62     struct __cfaehm_try_resume_node * node,
     61void __cfaabi_ehm__try_resume_setup(
     62    struct __cfaabi_ehm__try_resume_node * node,
    6363    _Bool (*handler)(exception_t * except));
    64 void __cfaehm_try_resume_cleanup(
    65     struct __cfaehm_try_resume_node * node);
     64void __cfaabi_ehm__try_resume_cleanup(
     65    struct __cfaabi_ehm__try_resume_node * node);
    6666
    6767// Check for a standard way to call fake deconstructors.
    68 struct __cfaehm_cleanup_hook {};
     68struct __cfaabi_ehm__cleanup_hook {};
    6969
    7070#ifdef __cforall
  • libcfa/src/executor.cfa

    r7030dab r71d6bd8  
    88#include <stdio.h>
    99
    10 forall( dtype T )
    11 monitor Buffer {                                        // unbounded buffer
    12     __queue_t( T ) queue;                               // unbounded list of work requests
    13     condition delay;
    14 }; // Buffer
    15 forall( dtype T | is_node(T) ) {
     10forall( otype T | is_node(T) | is_monitor(T) ) {
     11    monitor Buffer {                                    // unbounded buffer
     12        __queue_t( T ) queue;                           // unbounded list of work requests
     13        condition delay;
     14    }; // Buffer
     15
    1616    void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) {
    1717        append( queue, elem );                          // insert element into buffer
     
    2020
    2121    T * remove( Buffer( T ) & mutex buf ) with(buf) {
    22         if ( queue.head != 0 ) wait( delay );                   // no request to process ? => wait
    23 //      return pop_head( queue );
     22        if ( ! queue ) wait( delay );                   // no request to process ? => wait
     23        return pop_head( queue );
    2424    } // remove
    2525} // distribution
  • libcfa/src/fstream.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:01:01 2020
    13 // Update Count     : 363
     12// Last Modified On : Tue Sep 10 22:19:56 2019
     13// Update Count     : 354
    1414//
    1515
     
    3232
    3333void ?{}( ofstream & os, void * file ) {
    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 ) );
     34        os.file = file;
     35        os.sepDefault = true;
     36        os.sepOnOff = false;
     37        os.nlOnOff = true;
     38        os.prt = false;
     39        os.sawNL = false;
    4140        sepSet( os, " " );
     41        sepSetCur( os, sepGet( os ) );
    4242        sepSetTuple( os, ", " );
    4343} // ?{}
    4444
    4545// private
    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; }
     46bool sepPrt( ofstream & os ) { setNL( os, false ); return os.sepOnOff; }
     47void sepReset( ofstream & os ) { os.sepOnOff = os.sepDefault; }
     48void sepReset( ofstream & os, bool reset ) { os.sepDefault = reset; os.sepOnOff = os.sepDefault; }
     49const char * sepGetCur( ofstream & os ) { return os.sepCur; }
     50void sepSetCur( ofstream & os, const char * sepCur ) { os.sepCur = sepCur; }
     51bool getNL( ofstream & os ) { return os.sawNL; }
     52void setNL( ofstream & os, bool state ) { os.sawNL = state; }
     53bool getANL( ofstream & os ) { return os.nlOnOff; }
     54bool getPrt( ofstream & os ) { return os.prt; }
     55void setPrt( ofstream & os, bool state ) { os.prt = state; }
    5656
    5757// public
    58 void ?{}( ofstream & os ) { os.$file = 0p; }
    59 
    60 void ?{}( ofstream & os, const char name[], const char mode[] ) {
     58void ?{}( ofstream & os ) { os.file = 0; }
     59
     60void ?{}( ofstream & os, const char * name, const char * mode ) {
    6161        open( os, name, mode );
    6262} // ?{}
    6363
    64 void ?{}( ofstream & os, const char name[] ) {
     64void ?{}( ofstream & os, const char * name ) {
    6565        open( os, name, "w" );
    6666} // ?{}
    6767
    68 void ^?{}( ofstream & os ) {
    69         close( os );
    70 } // ^?{}
    71 
    72 void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); }
    73 void sepOff( ofstream & os ) { os.$sepOnOff = false; }
     68void sepOn( ofstream & os ) { os.sepOnOff = ! getNL( os ); }
     69void sepOff( ofstream & os ) { os.sepOnOff = false; }
    7470
    7571bool sepDisable( ofstream & os ) {
    76         bool temp = os.$sepDefault;
    77         os.$sepDefault = false;
    78         $sepReset( os );
     72        bool temp = os.sepDefault;
     73        os.sepDefault = false;
     74        sepReset( os );
    7975        return temp;
    8076} // sepDisable
    8177
    8278bool sepEnable( ofstream & os ) {
    83         bool temp = os.$sepDefault;
    84         os.$sepDefault = true;
    85         if ( os.$sepOnOff ) $sepReset( os );                            // start of line ?
     79        bool temp = os.sepDefault;
     80        os.sepDefault = true;
     81        if ( os.sepOnOff ) sepReset( os );                                      // start of line ?
    8682        return temp;
    8783} // sepEnable
    8884
    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; }
    93 void sepSet( ofstream & os, const char s[] ) {
     85void nlOn( ofstream & os ) { os.nlOnOff = true; }
     86void nlOff( ofstream & os ) { os.nlOnOff = false; }
     87
     88const char * sepGet( ofstream & os ) { return os.separator; }
     89void sepSet( ofstream & os, const char * s ) {
    9490        assert( s );
    95         strncpy( os.$separator, s, sepSize - 1 );
    96         os.$separator[sepSize - 1] = '\0';
     91        strncpy( os.separator, s, sepSize - 1 );
     92        os.separator[sepSize - 1] = '\0';
    9793} // sepSet
    9894
    99 const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; }
    100 void sepSetTuple( ofstream & os, const char s[] ) {
     95const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator; }
     96void sepSetTuple( ofstream & os, const char * s ) {
    10197        assert( s );
    102         strncpy( os.$tupleSeparator, s, sepSize - 1 );
    103         os.$tupleSeparator[sepSize - 1] = '\0';
     98        strncpy( os.tupleSeparator, s, sepSize - 1 );
     99        os.tupleSeparator[sepSize - 1] = '\0';
    104100} // sepSet
    105101
    106102void ends( ofstream & os ) {
    107         if ( $getANL( os ) ) nl( os );
    108         else $setPrt( os, false );                                                      // turn off
     103        if ( getANL( os ) ) nl( os );
     104        else setPrt( os, false );                                                       // turn off
    109105        if ( &os == &exit ) exit( EXIT_FAILURE );
    110106        if ( &os == &abort ) abort();
     
    112108
    113109int fail( ofstream & os ) {
    114         return os.$file == 0 || ferror( (FILE *)(os.$file) );
     110        return os.file == 0 || ferror( (FILE *)(os.file) );
    115111} // fail
    116112
    117113int flush( ofstream & os ) {
    118         return fflush( (FILE *)(os.$file) );
     114        return fflush( (FILE *)(os.file) );
    119115} // flush
    120116
    121 void open( ofstream & os, const char name[], const char mode[] ) {
     117void open( ofstream & os, const char * name, const char * mode ) {
    122118        FILE * file = fopen( name, mode );
    123119        #ifdef __CFA_DEBUG__
    124         if ( file == 0p ) {
     120        if ( file == 0 ) {
    125121                abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
    126122        } // if
     
    129125} // open
    130126
    131 void open( ofstream & os, const char name[] ) {
     127void open( ofstream & os, const char * name ) {
    132128        open( os, name, "w" );
    133129} // open
    134130
    135131void close( ofstream & os ) {
    136         if ( (FILE *)(os.$file) == stdout || (FILE *)(os.$file) == stderr ) return;
    137 
    138         if ( fclose( (FILE *)(os.$file) ) == EOF ) {
     132        if ( (FILE *)(os.file) == stdout || (FILE *)(os.file) == stderr ) return;
     133
     134        if ( fclose( (FILE *)(os.file) ) == EOF ) {
    139135                abort | IO_MSG "close output" | nl | strerror( errno );
    140136        } // if
    141137} // close
    142138
    143 ofstream & write( ofstream & os, const char data[], size_t size ) {
     139ofstream & write( ofstream & os, const char * data, size_t size ) {
    144140        if ( fail( os ) ) {
    145141                abort | IO_MSG "attempt write I/O on failed stream";
    146142        } // if
    147143
    148         if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) {
     144        if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
    149145                abort | IO_MSG "write" | nl | strerror( errno );
    150146        } // if
     
    155151        va_list args;
    156152        va_start( args, format );
    157         int len = vfprintf( (FILE *)(os.$file), format, args );
     153        int len = vfprintf( (FILE *)(os.file), format, args );
    158154        if ( len == EOF ) {
    159                 if ( ferror( (FILE *)(os.$file) ) ) {
     155                if ( ferror( (FILE *)(os.file) ) ) {
    160156                        abort | IO_MSG "invalid write";
    161157                } // if
     
    163159        va_end( args );
    164160
    165         $setPrt( os, true );                                                            // called in output cascade
    166         $sepReset( os );                                                                        // reset separator
     161        setPrt( os, true );                                                                     // called in output cascade
     162        sepReset( os );                                                                         // reset separator
    167163        return len;
    168164} // fmt
     
    184180// private
    185181void ?{}( ifstream & is, void * file ) {
    186         is.$file = file;
    187         is.$nlOnOff = false;
     182        is.file = file;
     183        is.nlOnOff = false;
    188184} // ?{}
    189185
    190186// public
    191 void ?{}( ifstream & is ) { is.$file = 0p; }
    192 
    193 void ?{}( ifstream & is, const char name[], const char mode[] ) {
     187void ?{}( ifstream & is ) {     is.file = 0; }
     188
     189void ?{}( ifstream & is, const char * name, const char * mode ) {
    194190        open( is, name, mode );
    195191} // ?{}
    196192
    197 void ?{}( ifstream & is, const char name[] ) {
     193void ?{}( ifstream & is, const char * name ) {
    198194        open( is, name, "r" );
    199195} // ?{}
    200196
    201 void ^?{}( ifstream & is ) {
    202         close( is );
    203 } // ^?{}
    204 
    205 void nlOn( ifstream & os ) { os.$nlOnOff = true; }
    206 void nlOff( ifstream & os ) { os.$nlOnOff = false; }
    207 bool getANL( ifstream & os ) { return os.$nlOnOff; }
     197void nlOn( ifstream & os ) { os.nlOnOff = true; }
     198void nlOff( ifstream & os ) { os.nlOnOff = false; }
     199bool getANL( ifstream & os ) { return os.nlOnOff; }
    208200
    209201int fail( ifstream & is ) {
    210         return is.$file == 0p || ferror( (FILE *)(is.$file) );
     202        return is.file == 0 || ferror( (FILE *)(is.file) );
    211203} // fail
    212204
    213205int eof( ifstream & is ) {
    214         return feof( (FILE *)(is.$file) );
     206        return feof( (FILE *)(is.file) );
    215207} // eof
    216208
    217 void open( ifstream & is, const char name[], const char mode[] ) {
     209void open( ifstream & is, const char * name, const char * mode ) {
    218210        FILE * file = fopen( name, mode );
    219211        #ifdef __CFA_DEBUG__
    220         if ( file == 0p ) {
     212        if ( file == 0 ) {
    221213                abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
    222214        } // if
    223215        #endif // __CFA_DEBUG__
    224         is.$file = file;
    225 } // open
    226 
    227 void open( ifstream & is, const char name[] ) {
     216        is.file = file;
     217} // open
     218
     219void open( ifstream & is, const char * name ) {
    228220        open( is, name, "r" );
    229221} // open
    230222
    231223void close( ifstream & is ) {
    232         if ( (FILE *)(is.$file) == stdin ) return;
    233 
    234         if ( fclose( (FILE *)(is.$file) ) == EOF ) {
     224        if ( (FILE *)(is.file) == stdin ) return;
     225
     226        if ( fclose( (FILE *)(is.file) ) == EOF ) {
    235227                abort | IO_MSG "close input" | nl | strerror( errno );
    236228        } // if
     
    242234        } // if
    243235
    244         if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) {
     236        if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
    245237                abort | IO_MSG "read" | nl | strerror( errno );
    246238        } // if
     
    253245        } // if
    254246
    255         if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) {
     247        if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
    256248                abort | IO_MSG "ungetc" | nl | strerror( errno );
    257249        } // if
     
    263255
    264256        va_start( args, format );
    265         int len = vfscanf( (FILE *)(is.$file), format, args );
     257        int len = vfscanf( (FILE *)(is.file), format, args );
    266258        if ( len == EOF ) {
    267                 if ( ferror( (FILE *)(is.$file) ) ) {
     259                if ( ferror( (FILE *)(is.file) ) ) {
    268260                        abort | IO_MSG "invalid read";
    269261                } // if
  • libcfa/src/fstream.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Feb 17 08:29:23 2020
    13 // Update Count     : 175
     12// Last Modified On : Mon Jul 15 18:10:23 2019
     13// Update Count     : 167
    1414//
    1515
     
    2424enum { sepSize = 16 };
    2525struct ofstream {
    26         void * $file;
    27         bool $sepDefault;
    28         bool $sepOnOff;
    29         bool $nlOnOff;
    30         bool $prt;                                                                                      // print text
    31         bool $sawNL;
    32         const char * $sepCur;
    33         char $separator[sepSize];
    34         char $tupleSeparator[sepSize];
     26        void * file;
     27        bool sepDefault;
     28        bool sepOnOff;
     29        bool nlOnOff;
     30        bool prt;                                                                                       // print text
     31        bool sawNL;
     32        const char * sepCur;
     33        char separator[sepSize];
     34        char tupleSeparator[sepSize];
    3535}; // ofstream
    3636
    3737// private
    38 bool $sepPrt( ofstream & );
    39 void $sepReset( ofstream & );
    40 void $sepReset( ofstream &, bool );
    41 const char * $sepGetCur( ofstream & );
    42 void $sepSetCur( ofstream &, const char [] );
    43 bool $getNL( ofstream & );
    44 void $setNL( ofstream &, bool );
    45 bool $getANL( ofstream & );
    46 bool $getPrt( ofstream & );
    47 void $setPrt( ofstream &, bool );
     38bool sepPrt( ofstream & );
     39void sepReset( ofstream & );
     40void sepReset( ofstream &, bool );
     41const char * sepGetCur( ofstream & );
     42void sepSetCur( ofstream &, const char * );
     43bool getNL( ofstream & );
     44void setNL( ofstream &, bool );
     45bool getANL( ofstream & );
     46bool getPrt( ofstream & );
     47void setPrt( ofstream &, bool );
    4848
    4949// public
     
    5656
    5757const char * sepGet( ofstream & );
    58 void sepSet( ofstream &, const char [] );
     58void sepSet( ofstream &, const char * );
    5959const char * sepGetTuple( ofstream & );
    60 void sepSetTuple( ofstream &, const char [] );
     60void sepSetTuple( ofstream &, const char * );
    6161
    6262void ends( ofstream & os );
    6363int fail( ofstream & );
    6464int flush( ofstream & );
    65 void open( ofstream &, const char name[], const char mode[] );
    66 void open( ofstream &, const char name[] );
     65void open( ofstream &, const char * name, const char * mode );
     66void open( ofstream &, const char * name );
    6767void close( ofstream & );
    68 ofstream & write( ofstream &, const char data[], size_t size );
    69 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
     68ofstream & write( ofstream &, const char * data, size_t size );
     69int fmt( ofstream &, const char format[], ... );
    7070
    7171void ?{}( ofstream & os );
    72 void ?{}( ofstream & os, const char name[], const char mode[] );
    73 void ?{}( ofstream & os, const char name[] );
    74 void ^?{}( ofstream & os );
     72void ?{}( ofstream & os, const char * name, const char * mode );
     73void ?{}( ofstream & os, const char * name );
    7574
    7675extern ofstream & sout, & stdout, & serr, & stderr;             // aliases
     
    8281
    8382struct ifstream {
    84         void * $file;
    85         bool $nlOnOff;
     83        void * file;
     84        bool nlOnOff;
    8685}; // ifstream
    8786
     
    9291int fail( ifstream & is );
    9392int eof( ifstream & is );
    94 void open( ifstream & is, const char name[], const char mode[] );
    95 void open( ifstream & is, const char name[] );
     93void open( ifstream & is, const char * name, const char * mode );
     94void open( ifstream & is, const char * name );
    9695void close( ifstream & is );
    9796ifstream & read( ifstream & is, char * data, size_t size );
    9897ifstream & ungetc( ifstream & is, char c );
    99 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     98int fmt( ifstream &, const char format[], ... );
    10099
    101100void ?{}( ifstream & is );
    102 void ?{}( ifstream & is, const char name[], const char mode[] );
    103 void ?{}( ifstream & is, const char name[] );
    104 void ^?{}( ifstream & is );
     101void ?{}( ifstream & is, const char * name, const char * mode );
     102void ?{}( ifstream & is, const char * name );
    105103
    106104extern ifstream & sin, & stdin;                                                 // aliases
  • libcfa/src/gmp.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb  9 09:56:54 2020
    13 // Update Count     : 31
     12// Last Modified On : Sat Jul 13 15:25:05 2019
     13// Update Count     : 27
    1414//
    1515
     
    2424
    2525static inline {
    26         // constructor, zero_t/one_t are unnecessary because of relationship with signed/unsigned int
     26        // constructor
    2727        void ?{}( Int & this ) { mpz_init( this.mpz ); }
    2828        void ?{}( Int & this, Int init ) { mpz_init_set( this.mpz, init.mpz ); }
     29        void ?{}( Int & this, zero_t ) { mpz_init_set_si( this.mpz, 0 ); }
     30        void ?{}( Int & this, one_t ) { mpz_init_set_si( this.mpz, 1 ); }
    2931        void ?{}( Int & this, signed long int init ) { mpz_init_set_si( this.mpz, init ); }
    3032        void ?{}( Int & this, unsigned long int init ) { mpz_init_set_ui( this.mpz, init ); }
    31         void ?{}( Int & this, const char val[] ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
     33        void ?{}( Int & this, const char * val ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
    3234        void ^?{}( Int & this ) { mpz_clear( this.mpz ); }
    3335
     
    3537        Int ?`mp( signed long int init ) { return (Int){ init }; }
    3638        Int ?`mp( unsigned long int init ) { return (Int){ init }; }
    37         Int ?`mp( const char init[] ) { return (Int){ init }; }
     39        Int ?`mp( const char * init ) { return (Int){ init }; }
    3840
    3941        // assignment
     
    4143        Int ?=?( Int & lhs, long int rhs ) { mpz_set_si( lhs.mpz, rhs ); return lhs; }
    4244        Int ?=?( Int & lhs, unsigned long int rhs ) { mpz_set_ui( lhs.mpz, rhs ); return lhs; }
    43         Int ?=?( Int & lhs, const char rhs[] ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
     45        Int ?=?( Int & lhs, const char * rhs ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
    4446
    4547        char ?=?( char & lhs, Int rhs ) { char val = mpz_get_si( rhs.mpz ); lhs = val; return lhs; }
     
    263265        forall( dtype ostype | ostream( ostype ) ) {
    264266                ostype & ?|?( ostype & os, Int mp ) {
    265                         if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     267                        if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    266268                        gmp_printf( "%Zd", mp.mpz );
    267269                        sepOn( os );
  • libcfa/src/heap.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr  1 15:59:53 2020
    13 // Update Count     : 692
     12// Last Modified On : Fri Oct 18 07:42:09 2019
     13// Update Count     : 556
    1414//
    1515
     
    1818#include <stdio.h>                                                                              // snprintf, fileno
    1919#include <errno.h>                                                                              // errno
    20 #include <string.h>                                                                             // memset, memcpy
    2120extern "C" {
    2221#include <sys/mman.h>                                                                   // mmap, munmap
     
    2827#include "bits/locks.hfa"                                                               // __spinlock_t
    2928#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    30 //#include "stdlib.hfa"                                                                 // bsearchl
     29#include "stdlib.hfa"                                                                   // bsearchl
    3130#include "malloc.h"
    3231
    33 #define MIN(x, y) (y > x ? x : y)
    3432
    3533static bool traceHeap = false;
    3634
    37 inline bool traceHeap() { return traceHeap; }
     35inline bool traceHeap() {
     36        return traceHeap;
     37} // traceHeap
    3838
    3939bool traceHeapOn() {
     
    4949} // traceHeapOff
    5050
    51 bool traceHeapTerm() { return false; }
    52 
    53 
    54 static bool prtFree = false;
    55 
    56 inline bool prtFree() {
    57         return prtFree;
    58 } // prtFree
    59 
    60 bool prtFreeOn() {
    61         bool temp = prtFree;
    62         prtFree = true;
     51
     52static bool checkFree = false;
     53
     54inline bool checkFree() {
     55        return checkFree;
     56} // checkFree
     57
     58bool checkFreeOn() {
     59        bool temp = checkFree;
     60        checkFree = true;
    6361        return temp;
    64 } // prtFreeOn
    65 
    66 bool prtFreeOff() {
    67         bool temp = prtFree;
    68         prtFree = false;
     62} // checkFreeOn
     63
     64bool checkFreeOff() {
     65        bool temp = checkFree;
     66        checkFree = false;
    6967        return temp;
    70 } // prtFreeOff
     68} // checkFreeOff
     69
     70
     71// static bool traceHeapTerm = false;
     72
     73// inline bool traceHeapTerm() {
     74//      return traceHeapTerm;
     75// } // traceHeapTerm
     76
     77// bool traceHeapTermOn() {
     78//      bool temp = traceHeapTerm;
     79//      traceHeapTerm = true;
     80//      return temp;
     81// } // traceHeapTermOn
     82
     83// bool traceHeapTermOff() {
     84//      bool temp = traceHeapTerm;
     85//      traceHeapTerm = false;
     86//      return temp;
     87// } // traceHeapTermOff
    7188
    7289
    7390enum {
    74         // Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address,
    75         // the brk address is extended by the extension amount.
     91        __CFA_DEFAULT_MMAP_START__ = (512 * 1024 + 1),
    7692        __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
    77 
    78         // Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets;
    79         // values greater than or equal to this value are mmap from the operating system.
    80         __CFA_DEFAULT_MMAP_START__ = (512 * 1024 + 1),
    8193};
    8294
     
    93105static unsigned int allocFree;                                                  // running total of allocations minus frees
    94106
    95 static void prtUnfreed() {
     107static void checkUnfreed() {
    96108        if ( allocFree != 0 ) {
    97109                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    98                 char helpText[512];
    99                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
    100                                                         "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    101                                                         (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
    102                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    103         } // if
    104 } // prtUnfreed
     110                // char helpText[512];
     111                // int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
     112                //                                      "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
     113                //                                      (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
     114                // __cfaabi_dbg_bits_write( helpText, len );
     115        } // if
     116} // checkUnfreed
    105117
    106118extern "C" {
     
    111123        void heapAppStop() {                                                            // called by __cfaabi_appready_startdown
    112124                fclose( stdin ); fclose( stdout );
    113                 prtUnfreed();
     125                checkUnfreed();
    114126        } // heapAppStop
    115127} // extern "C"
    116128#endif // __CFA_DEBUG__
    117 
    118129
    119130// statically allocated variables => zero filled.
     
    123134static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    124135
     136
     137// #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa
     138#define ALIGN 16
    125139
    126140#define SPINLOCK 0
     
    133147// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    134148// Break recusion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
    135 enum { NoBucketSizes = 91 };                                                    // number of buckets sizes
     149enum { NoBucketSizes = 93 };                                                    // number of buckets sizes
    136150
    137151struct HeapManager {
     
    150164                                                        union {
    151165//                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
    152                                                                 // 2nd low-order bit => zero filled
    153166                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    154167                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     
    170183                                struct FakeHeader {
    171184                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    172                                         // 1st low-order bit => fake header & alignment
    173                                         uint32_t alignment;
     185                                        uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
    174186                                        #endif // __ORDER_LITTLE_ENDIAN__
    175187
     
    181193                                } fake; // FakeHeader
    182194                        } kind; // Kind
    183                         uint32_t dimension;                                                     // used by calloc-like to remember number of array elements
    184195                } header; // Header
    185                 char pad[libAlign() - sizeof( Header )];
     196                char pad[ALIGN - sizeof( Header )];
    186197                char data[0];                                                                   // storage
    187198        }; // Storage
    188199
    189         static_assert( libAlign() >= sizeof( Storage ), "libAlign() < sizeof( Storage )" );
     200        static_assert( ALIGN >= sizeof( Storage ), "ALIGN < sizeof( Storage )" );
    190201
    191202        struct FreeHeader {
     
    217228#define __STATISTICS__
    218229
    219 // Bucket size must be multiple of 16.
    220230// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    221231static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    222         16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
    223         96, 112, 128 + sizeof(HeapManager.Storage), // 3
    224         160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    225         320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
    226         640, 768, 896, 1_024 + sizeof(HeapManager.Storage), // 4
    227         1_536, 2_048 + sizeof(HeapManager.Storage), // 2
    228         2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), // 4
    229         6_144, 8_192 + sizeof(HeapManager.Storage), // 2
    230         9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(HeapManager.Storage), // 8
    231         18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(HeapManager.Storage), // 8
    232         36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(HeapManager.Storage), // 8
    233         73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(HeapManager.Storage), // 8
    234         147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(HeapManager.Storage), // 8
    235         294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(HeapManager.Storage), // 8
    236         655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), // 4
    237         1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), // 8
    238         2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(HeapManager.Storage), // 4
     232        16, 32, 48, 64,
     233        64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224,
     234        256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896,
     235        1_024 + sizeof(HeapManager.Storage), 1_536, 2_048 + sizeof(HeapManager.Storage), 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), 6_144,
     236        8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360,
     237        16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720,
     238        32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440,
     239        65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880,
     240        131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760,
     241        262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520,
     242        524_288 + sizeof(HeapManager.Storage), 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), 1_179_648, 1_310_720, 1_441_792,
     243        1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), 2_621_440, 3_145_728, 3_670_016,
     244        4_194_304 + sizeof(HeapManager.Storage)
    239245};
    240246
     
    245251static unsigned char lookup[LookupSizes];                               // O(1) lookup for small sizes
    246252#endif // FASTLOOKUP
    247 
    248253static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
     254
     255
    249256#ifdef __CFA_DEBUG__
    250257static bool heapBoot = 0;                                                               // detect recursion during boot
     
    252259static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    253260
     261// #comment TD : The return type of this function should be commented
     262static inline bool setMmapStart( size_t value ) {
     263  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
     264        mmapStart = value;                                                                      // set global
     265
     266        // find the closest bucket size less than or equal to the mmapStart size
     267        maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
     268        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
     269        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
     270        return false;
     271} // setMmapStart
     272
     273
     274static void ?{}( HeapManager & manager ) with ( manager ) {
     275        pageSize = sysconf( _SC_PAGESIZE );
     276
     277        for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
     278                freeLists[i].blockSize = bucketSizes[i];
     279        } // for
     280
     281        #ifdef FASTLOOKUP
     282        unsigned int idx = 0;
     283        for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {
     284                if ( i > bucketSizes[idx] ) idx += 1;
     285                lookup[i] = idx;
     286        } // for
     287        #endif // FASTLOOKUP
     288
     289        if ( setMmapStart( default_mmap_start() ) ) {
     290                abort( "HeapManager : internal error, mmap start initialization failure." );
     291        } // if
     292        heapExpand = default_heap_expansion();
     293
     294        char * End = (char *)sbrk( 0 );
     295        sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment
     296        heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
     297} // HeapManager
     298
     299
     300static void ^?{}( HeapManager & ) {
     301        #ifdef __STATISTICS__
     302        // if ( traceHeapTerm() ) {
     303        //      printStats();
     304        //      if ( checkfree() ) checkFree( heapManager, true );
     305        // } // if
     306        #endif // __STATISTICS__
     307} // ~HeapManager
     308
     309
     310static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
     311void memory_startup( void ) {
     312        #ifdef __CFA_DEBUG__
     313        if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
     314                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
     315                abort( "boot() : internal error, recursively invoked during system boot." );
     316        } // if
     317        heapBoot = true;
     318        #endif // __CFA_DEBUG__
     319
     320        //assert( heapManager.heapBegin != 0 );
     321        //heapManager{};
     322        if ( heapManager.heapBegin == 0 ) heapManager{};
     323} // memory_startup
     324
     325static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
     326void memory_shutdown( void ) {
     327        ^heapManager{};
     328} // memory_shutdown
     329
    254330
    255331#ifdef __STATISTICS__
    256 // Heap statistics counters.
    257 static unsigned long long int mmap_storage;
     332static unsigned long long int mmap_storage;                             // heap statistics counters
    258333static unsigned int mmap_calls;
    259334static unsigned long long int munmap_storage;
     
    271346static unsigned long long int cmemalign_storage;
    272347static unsigned int cmemalign_calls;
    273 static unsigned long long int resize_storage;
    274 static unsigned int resize_calls;
    275348static unsigned long long int realloc_storage;
    276349static unsigned int realloc_calls;
    277 // Statistics file descriptor (changed by malloc_stats_fd).
    278 static int statfd = STDERR_FILENO;                                              // default stderr
     350
     351static int statfd;                                                                              // statistics file descriptor (changed by malloc_stats_fd)
     352
    279353
    280354// Use "write" because streams may be shutdown when calls are made.
    281355static void printStats() {
    282356        char helpText[512];
    283         __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
     357        __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText),
    284358                                                                        "\nHeap statistics:\n"
    285359                                                                        "  malloc: calls %u / storage %llu\n"
     
    287361                                                                        "  memalign: calls %u / storage %llu\n"
    288362                                                                        "  cmemalign: calls %u / storage %llu\n"
    289                                                                         "  resize: calls %u / storage %llu\n"
    290363                                                                        "  realloc: calls %u / storage %llu\n"
    291364                                                                        "  free: calls %u / storage %llu\n"
     
    297370                                                                        memalign_calls, memalign_storage,
    298371                                                                        cmemalign_calls, cmemalign_storage,
    299                                                                         resize_calls, resize_storage,
    300372                                                                        realloc_calls, realloc_storage,
    301373                                                                        free_calls, free_storage,
     
    317389                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
    318390                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
    319                                                 "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    320391                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    321392                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    328399                                                memalign_calls, memalign_storage,
    329400                                                cmemalign_calls, cmemalign_storage,
    330                                                 resize_calls, resize_storage,
    331401                                                realloc_calls, realloc_storage,
    332402                                                free_calls, free_storage,
     
    335405                                                sbrk_calls, sbrk_storage
    336406                );
    337         __cfaabi_bits_write( fileno( stream ), helpText, len ); // ensures all bytes written or exit
    338         return len;
     407        return write( fileno( stream ), helpText, len );        // -1 => error
    339408} // printStatsXML
    340409#endif // __STATISTICS__
    341410
    342 
    343 // static inline void noMemory() {
    344 //      abort( "Heap memory exhausted at %zu bytes.\n"
    345 //                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
    346 //                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
    347 // } // noMemory
     411// #comment TD : Is this the samething as Out-of-Memory?
     412static inline void noMemory() {
     413        abort( "Heap memory exhausted at %zu bytes.\n"
     414                   "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
     415                   ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
     416} // noMemory
     417
     418
     419static inline void checkAlign( size_t alignment ) {
     420        if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) {
     421                abort( "Alignment %zu for memory allocation is less than sizeof(void *) and/or not a power of 2.", alignment );
     422        } // if
     423} // checkAlign
    348424
    349425
     
    355431
    356432
    357 // thunk problem
     433static inline void checkHeader( bool check, const char * name, void * addr ) {
     434        if ( unlikely( check ) ) {                                                      // bad address ?
     435                abort( "Attempt to %s storage %p with address outside the heap.\n"
     436                           "Possible cause is duplicate free on same block or overwriting of memory.",
     437                           name, addr );
     438        } // if
     439} // checkHeader
     440
     441// #comment TD : function should be commented and/or have a more evocative name
     442//               this isn't either a check or a constructor which is what I would expect this function to be
     443static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & size, size_t & alignment ) {
     444        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
     445                size_t offset = header->kind.fake.offset;
     446                alignment = header->kind.fake.alignment & -2;   // remove flag from value
     447                #ifdef __CFA_DEBUG__
     448                checkAlign( alignment );                                                // check alignment
     449                #endif // __CFA_DEBUG__
     450                header = (HeapManager.Storage.Header *)((char *)header - offset);
     451        } // if
     452} // fakeHeader
     453
     454// #comment TD : Why is this a define
     455#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
     456
     457static inline bool headers( const char * name, void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
     458        header = headerAddr( addr );
     459
     460        if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
     461                fakeHeader( header, size, alignment );
     462                size = header->kind.real.blockSize & -3;                // mmap size
     463                return true;
     464        } // if
     465
     466        #ifdef __CFA_DEBUG__
     467        checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     468        #endif // __CFA_DEBUG__
     469
     470        // #comment TD : This code looks weird...
     471        //               It's called as the first statement of both branches of the last if, with the same parameters in all cases
     472
     473        // header may be safe to dereference
     474        fakeHeader( header, size, alignment );
     475        #ifdef __CFA_DEBUG__
     476        checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
     477        #endif // __CFA_DEBUG__
     478
     479        freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
     480        #ifdef __CFA_DEBUG__
     481        if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {
     482                abort( "Attempt to %s storage %p with corrupted header.\n"
     483                           "Possible cause is duplicate free on same block or overwriting of header information.",
     484                           name, addr );
     485        } // if
     486        #endif // __CFA_DEBUG__
     487        size = freeElem->blockSize;
     488        return false;
     489} // headers
     490
     491
     492static inline void * extend( size_t size ) with ( heapManager ) {
     493        lock( extlock __cfaabi_dbg_ctx2 );
     494        ptrdiff_t rem = heapRemaining - size;
     495        if ( rem < 0 ) {
     496                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
     497
     498                size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
     499                if ( sbrk( increase ) == (void *)-1 ) {
     500                        unlock( extlock );
     501                        errno = ENOMEM;
     502                        return 0;
     503                } // if
     504                #ifdef __STATISTICS__
     505                sbrk_calls += 1;
     506                sbrk_storage += increase;
     507                #endif // __STATISTICS__
     508                #ifdef __CFA_DEBUG__
     509                // Set new memory to garbage so subsequent uninitialized usages might fail.
     510                memset( (char *)heapEnd + heapRemaining, '\377', increase );
     511                #endif // __CFA_DEBUG__
     512                rem = heapRemaining + increase - size;
     513        } // if
     514
     515        HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;
     516        heapRemaining = rem;
     517        heapEnd = (char *)heapEnd + size;
     518        unlock( extlock );
     519        return block;
     520} // extend
     521
     522
    358523size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
    359524        size_t l = 0, m, h = dim;
     
    370535
    371536
    372 static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    373   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    374         mmapStart = value;                                                                      // set global
    375 
    376         // find the closest bucket size less than or equal to the mmapStart size
    377         maxBucketsUsed = Bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
    378         assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    379         assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    380         return false;
    381 } // setMmapStart
    382 
    383 
    384 // <-------+----------------------------------------------------> bsize (bucket size)
    385 // |header |addr
    386 //==================================================================================
    387 //                   align/offset |
    388 // <-----------------<------------+-----------------------------> bsize (bucket size)
    389 //                   |fake-header | addr
    390 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    391 #define realHeader( header ) ((HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset))
    392 
    393 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    394 // |header |addr
    395 //==================================================================================
    396 //                   align/offset |
    397 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    398 //                   |fake-header |addr
    399 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    400 
    401 
    402 static inline void checkAlign( size_t alignment ) {
    403         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
    404                 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    405         } // if
    406 } // checkAlign
    407 
    408 
    409 static inline void checkHeader( bool check, const char name[], void * addr ) {
    410         if ( unlikely( check ) ) {                                                      // bad address ?
    411                 abort( "Attempt to %s storage %p with address outside the heap.\n"
    412                            "Possible cause is duplicate free on same block or overwriting of memory.",
    413                            name, addr );
    414         } // if
    415 } // checkHeader
    416 
    417 
    418 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    419         if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
    420                 alignment = header->kind.fake.alignment & -2;   // remove flag from value
    421                 #ifdef __CFA_DEBUG__
    422                 checkAlign( alignment );                                                // check alignment
    423                 #endif // __CFA_DEBUG__
    424                 header = realHeader( header );                                  // backup from fake to real header
    425         } // if
    426 } // fakeHeader
    427 
    428 
    429 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
    430         header = headerAddr( addr );
    431 
    432         if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    433                 fakeHeader( header, alignment );
    434                 size = header->kind.real.blockSize & -3;                // mmap size
    435                 return true;
    436         } // if
    437 
    438         #ifdef __CFA_DEBUG__
    439         checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    440         #endif // __CFA_DEBUG__
    441 
    442         // header may be safe to dereference
    443         fakeHeader( header, alignment );
    444         #ifdef __CFA_DEBUG__
    445         checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
    446         #endif // __CFA_DEBUG__
    447 
    448         freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
    449         #ifdef __CFA_DEBUG__
    450         if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {
    451                 abort( "Attempt to %s storage %p with corrupted header.\n"
    452                            "Possible cause is duplicate free on same block or overwriting of header information.",
    453                            name, addr );
    454         } // if
    455         #endif // __CFA_DEBUG__
    456         size = freeElem->blockSize;
    457         return false;
    458 } // headers
    459 
    460 
    461 static inline void * extend( size_t size ) with ( heapManager ) {
    462         lock( extlock __cfaabi_dbg_ctx2 );
    463         ptrdiff_t rem = heapRemaining - size;
    464         if ( rem < 0 ) {
    465                 // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    466 
    467                 size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
    468                 if ( sbrk( increase ) == (void *)-1 ) {
    469                         unlock( extlock );
    470                         errno = ENOMEM;
    471                         return 0p;
    472                 } // if
    473                 #ifdef __STATISTICS__
    474                 sbrk_calls += 1;
    475                 sbrk_storage += increase;
    476                 #endif // __STATISTICS__
    477                 #ifdef __CFA_DEBUG__
    478                 // Set new memory to garbage so subsequent uninitialized usages might fail.
    479                 memset( (char *)heapEnd + heapRemaining, '\377', increase );
    480                 #endif // __CFA_DEBUG__
    481                 rem = heapRemaining + increase - size;
    482         } // if
    483 
    484         HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;
    485         heapRemaining = rem;
    486         heapEnd = (char *)heapEnd + size;
    487         unlock( extlock );
    488         return block;
    489 } // extend
    490 
    491 
    492537static inline void * doMalloc( size_t size ) with ( heapManager ) {
    493538        HeapManager.Storage * block;                                            // pointer to new block of storage
     
    496541        // along with the block and is a multiple of the alignment size.
    497542
    498   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
     543  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0;
    499544        size_t tsize = size + sizeof(HeapManager.Storage);
    500545        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    529574                block = freeElem->freeList.pop();
    530575                #endif // SPINLOCK
    531                 if ( unlikely( block == 0p ) ) {                                // no free block ?
     576                if ( unlikely( block == 0 ) ) {                                 // no free block ?
    532577                        #if defined( SPINLOCK )
    533578                        unlock( freeElem->lock );
     
    538583
    539584                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    540   if ( unlikely( block == 0p ) ) return 0p;
    541                 #if defined( SPINLOCK )
     585  if ( unlikely( block == 0 ) ) return 0;
     586                        #if defined( SPINLOCK )
    542587                } else {
    543588                        freeElem->freeList = block->header.kind.real.next;
    544589                        unlock( freeElem->lock );
    545                 #endif // SPINLOCK
     590                        #endif // SPINLOCK
    546591                } // if
    547592
    548593                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    549594        } else {                                                                                        // large size => mmap
    550   if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
     595  if ( unlikely( size > ~0ul - pageSize ) ) return 0;
    551596                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    552597                #ifdef __STATISTICS__
     
    566611        } // if
    567612
    568         void * addr = &(block->data);                                           // adjust off header to user bytes
     613        void * area = &(block->data);                                           // adjust off header to user bytes
    569614
    570615        #ifdef __CFA_DEBUG__
    571         assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
     616        assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?
    572617        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    573618        if ( traceHeap() ) {
    574619                enum { BufferSize = 64 };
    575620                char helpText[BufferSize];
    576                 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    577                 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    578                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     621                int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize );
     622                // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size );
     623                __cfaabi_dbg_bits_write( helpText, len );
    579624        } // if
    580625        #endif // __CFA_DEBUG__
    581626
    582         return addr;
     627        return area;
    583628} // doMalloc
    584629
     
    586631static inline void doFree( void * addr ) with ( heapManager ) {
    587632        #ifdef __CFA_DEBUG__
    588         if ( unlikely( heapManager.heapBegin == 0p ) ) {
     633        if ( unlikely( heapManager.heapBegin == 0 ) ) {
    589634                abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
    590635        } // if
     
    632677                char helpText[BufferSize];
    633678                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    634                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     679                __cfaabi_dbg_bits_write( helpText, len );
    635680        } // if
    636681        #endif // __CFA_DEBUG__
     
    638683
    639684
    640 size_t prtFree( HeapManager & manager ) with ( manager ) {
     685size_t checkFree( HeapManager & manager ) with ( manager ) {
    641686        size_t total = 0;
    642687        #ifdef __STATISTICS__
    643         __cfaabi_bits_acquire();
    644         __cfaabi_bits_print_nolock( STDERR_FILENO, "\nBin lists (bin size : free blocks on list)\n" );
     688        __cfaabi_dbg_bits_acquire();
     689        __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" );
    645690        #endif // __STATISTICS__
    646691        for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
     
    651696
    652697                #if defined( SPINLOCK )
    653                 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
     698                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) {
    654699                #else
    655                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
     700                for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0; p = p->header.kind.real.next.top ) {
    656701                #endif // SPINLOCK
    657702                        total += size;
     
    662707
    663708                #ifdef __STATISTICS__
    664                 __cfaabi_bits_print_nolock( STDERR_FILENO, "%7zu, %-7u  ", size, N );
    665                 if ( (i + 1) % 8 == 0 ) __cfaabi_bits_print_nolock( STDERR_FILENO, "\n" );
     709                __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u  ", size, N );
     710                if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" );
    666711                #endif // __STATISTICS__
    667712        } // for
    668713        #ifdef __STATISTICS__
    669         __cfaabi_bits_print_nolock( STDERR_FILENO, "\ntotal free blocks:%zu\n", total );
    670         __cfaabi_bits_release();
     714        __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );
     715        __cfaabi_dbg_bits_release();
    671716        #endif // __STATISTICS__
    672717        return (char *)heapEnd - (char *)heapBegin - total;
    673 } // prtFree
    674 
    675 
    676 static void ?{}( HeapManager & manager ) with ( manager ) {
    677         pageSize = sysconf( _SC_PAGESIZE );
    678 
    679         for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
    680                 freeLists[i].blockSize = bucketSizes[i];
    681         } // for
    682 
    683         #ifdef FASTLOOKUP
    684         unsigned int idx = 0;
    685         for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {
    686                 if ( i > bucketSizes[idx] ) idx += 1;
    687                 lookup[i] = idx;
    688         } // for
    689         #endif // FASTLOOKUP
    690 
    691         if ( setMmapStart( default_mmap_start() ) ) {
    692                 abort( "HeapManager : internal error, mmap start initialization failure." );
    693         } // if
    694         heapExpand = default_heap_expansion();
    695 
    696         char * end = (char *)sbrk( 0 );
    697         sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    698         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
    699 } // HeapManager
    700 
    701 
    702 static void ^?{}( HeapManager & ) {
    703         #ifdef __STATISTICS__
    704         if ( traceHeapTerm() ) {
    705                 printStats();
    706                 // if ( prtfree() ) prtFree( heapManager, true );
    707         } // if
    708         #endif // __STATISTICS__
    709 } // ~HeapManager
    710 
    711 
    712 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
    713 void memory_startup( void ) {
    714         #ifdef __CFA_DEBUG__
    715         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
    716                 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    717                 abort( "boot() : internal error, recursively invoked during system boot." );
    718         } // if
    719         heapBoot = true;
    720         #endif // __CFA_DEBUG__
    721 
    722         //assert( heapManager.heapBegin != 0 );
    723         //heapManager{};
    724         if ( heapManager.heapBegin == 0p ) heapManager{};
    725 } // memory_startup
    726 
    727 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
    728 void memory_shutdown( void ) {
    729         ^heapManager{};
    730 } // memory_shutdown
     718} // checkFree
    731719
    732720
    733721static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    734722        //assert( heapManager.heapBegin != 0 );
    735         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
    736         void * addr = doMalloc( size );
    737         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    738         return addr;
     723        if ( unlikely( heapManager.heapBegin == 0 ) ) heapManager{}; // called before memory_startup ?
     724        void * area = doMalloc( size );
     725        if ( unlikely( area == 0 ) ) errno = ENOMEM;            // POSIX
     726        return area;
    739727} // mallocNoStats
    740 
    741 
    742 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
    743         size_t size = noOfElems * elemSize;
    744         char * addr = (char *)mallocNoStats( size );
    745   if ( unlikely( addr == 0p ) ) return 0p;
    746 
    747         HeapManager.Storage.Header * header;
    748         HeapManager.FreeHeader * freeElem;
    749         size_t bsize, alignment;
    750         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    751         #ifndef __CFA_DEBUG__
    752         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    753         if ( ! mapped )
    754         #endif // __CFA_DEBUG__
    755                 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    756                 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
    757                 // `-header`-addr                      `-size
    758                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
    759 
    760         assert( noOfElems <= UINT32_MAX );
    761         header->dimension = noOfElems;                                          // store number of array elements
    762         header->kind.real.blockSize |= 2;                                       // mark as zero filled
    763         return addr;
    764 } // callocNoStats
    765728
    766729
     
    782745        // subtract libAlign() because it is already the minimum alignment
    783746        // add sizeof(Storage) for fake header
    784         char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    785   if ( unlikely( addr == 0p ) ) return addr;
     747        // #comment TD : this is the only place that calls doMalloc without calling mallocNoStats, why ?
     748        char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
     749  if ( unlikely( area == 0 ) ) return area;
    786750
    787751        // address in the block of the "next" alignment address
    788         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     752        char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment );
    789753
    790754        // address of header from malloc
    791         HeapManager.Storage.Header * realHeader = headerAddr( addr );
     755        HeapManager.Storage.Header * realHeader = headerAddr( area );
    792756        // address of fake header * before* the alignment location
    793757        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    799763        return user;
    800764} // memalignNoStats
    801 
    802 
    803 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
    804         size_t size = noOfElems * elemSize;
    805         char * addr = (char *)memalignNoStats( alignment, size );
    806   if ( unlikely( addr == 0p ) ) return 0p;
    807         HeapManager.Storage.Header * header;
    808         HeapManager.FreeHeader * freeElem;
    809         size_t bsize;
    810         bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    811         #ifndef __CFA_DEBUG__
    812         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    813         if ( ! mapped )
    814         #endif // __CFA_DEBUG__
    815                 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    816 
    817         assert( noOfElems <= UINT32_MAX );
    818         header->dimension = noOfElems;                                          // store initial array size
    819         header->kind.real.blockSize |= 2;                                       // mark as zero filled
    820         return addr;
    821 } // cmemalignNoStats
    822765
    823766
     
    832775
    833776extern "C" {
    834         // Allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0,
    835         // then malloc() returns either 0p, or a unique pointer value that can later be successfully passed to free().
     777        // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
     778        // initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
     779        // successfully passed to free().
    836780        void * malloc( size_t size ) {
    837781                #ifdef __STATISTICS__
     
    843787        } // malloc
    844788
    845         // Allocate memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated
    846         // memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a unique pointer
    847         // value that can later be successfully passed to free().
     789        // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to
     790        // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a
     791        // unique pointer value that can later be successfully passed to free().
    848792        void * calloc( size_t noOfElems, size_t elemSize ) {
     793                size_t size = noOfElems * elemSize;
    849794                #ifdef __STATISTICS__
    850795                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    851                 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    852                 #endif // __STATISTICS__
    853 
    854                 return callocNoStats( noOfElems, elemSize );
    855         } // calloc
    856 
    857         // Change the size of the memory block pointed to by ptr to size bytes. The contents are undefined.  If ptr is 0p,
    858         // then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p,
    859         // then the call is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to
    860         // malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
    861 
    862         void * resize( void * oaddr, size_t size ) {
    863                 #ifdef __STATISTICS__
    864                 __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    865                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    866                 #endif // __STATISTICS__
    867 
    868                 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    869           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    870           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     796                __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST );
     797                #endif // __STATISTICS__
     798
     799                char * area = (char *)mallocNoStats( size );
     800          if ( unlikely( area == 0 ) ) return 0;
    871801
    872802                HeapManager.Storage.Header * header;
    873803                HeapManager.FreeHeader * freeElem;
    874                 size_t bsize, oalign = 0;
    875                 headers( "resize", oaddr, header, freeElem, bsize, oalign );
    876                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    877 
    878                 // same size, DO NOT preserve STICKY PROPERTIES.
    879                 if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    880                         header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
    881                         return oaddr;
    882                 } // if
    883        
    884                 // change size, DO NOT preserve STICKY PROPERTIES.
    885                 void * naddr = mallocNoStats( size );                   // create new area
    886                 free( oaddr );
    887                 return naddr;
    888         } // resize
    889 
    890 
    891         // Same as resize but the contents shall be unchanged in the range from the start of the region up to the minimum of
    892         // the old and new sizes.
    893         void * realloc( void * oaddr, size_t size ) {
    894                 #ifdef __STATISTICS__
    895                 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    896                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    897                 #endif // __STATISTICS__
    898 
    899                 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    900           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    901           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    902 
     804                size_t asize, alignment;
     805                bool mapped __attribute__(( unused )) = headers( "calloc", area, header, freeElem, asize, alignment );
     806                #ifndef __CFA_DEBUG__
     807                // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     808                if ( ! mapped )
     809                #endif // __CFA_DEBUG__
     810                        memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros
     811
     812                header->kind.real.blockSize |= 2;                               // mark as zero filled
     813                return area;
     814        } // calloc
     815
     816        // #comment TD : Document this function
     817        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
     818                size_t size = noOfElems * elemSize;
     819                #ifdef __STATISTICS__
     820                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
     821                __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
     822                #endif // __STATISTICS__
     823
     824                char * area = (char *)memalignNoStats( alignment, size );
     825          if ( unlikely( area == 0 ) ) return 0;
    903826                HeapManager.Storage.Header * header;
    904827                HeapManager.FreeHeader * freeElem;
    905                 size_t bsize, oalign = 0;
    906                 headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    907 
    908                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    909           if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
    910                         // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    911                         // where to start filling, i.e., do not overwrite existing values in space.
    912                         return oaddr;
     828                size_t asize;
     829                bool mapped __attribute__(( unused )) = headers( "cmemalign", area, header, freeElem, asize, alignment );
     830                #ifndef __CFA_DEBUG__
     831                // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     832                if ( ! mapped )
     833                        #endif // __CFA_DEBUG__
     834                        memset( area, '\0', asize - ( (char *)area - (char *)header ) ); // set to zeros
     835                header->kind.real.blockSize |= 2;                               // mark as zero filled
     836
     837                return area;
     838        } // cmemalign
     839
     840        // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
     841        // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size
     842        // is larger than the old size, the added memory will not be initialized.  If ptr is NULL, then the call is
     843        // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call
     844        // is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(),
     845        // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
     846        void * realloc( void * addr, size_t size ) {
     847                #ifdef __STATISTICS__
     848                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     849                #endif // __STATISTICS__
     850
     851          if ( unlikely( addr == 0 ) ) return mallocNoStats( size ); // special cases
     852          if ( unlikely( size == 0 ) ) { free( addr ); return 0; }
     853
     854                HeapManager.Storage.Header * header;
     855                HeapManager.FreeHeader * freeElem;
     856                size_t asize, alignment = 0;
     857                headers( "realloc", addr, header, freeElem, asize, alignment );
     858
     859                size_t usize = asize - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
     860                if ( usize >= size ) {                                                  // already sufficient storage
     861                        // This case does not result in a new profiler entry because the previous one still exists and it must match with
     862                        // the free for this memory.  Hence, this realloc does not appear in the profiler output.
     863                        return addr;
    913864                } // if
    914865
    915                 // change size and copy old content to new storage
    916 
    917                 void * naddr;
    918                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    919                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    920                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    921                         } else {
    922                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
    923                         } // if
     866                #ifdef __STATISTICS__
     867                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     868                #endif // __STATISTICS__
     869
     870                void * area;
     871                if ( unlikely( alignment != 0 ) ) {                             // previous request memalign?
     872                        area = memalign( alignment, size );                     // create new aligned area
    924873                } else {
    925                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    926                                 naddr = callocNoStats( 1, size );               // create new area
    927                         } else {
    928                                 naddr = mallocNoStats( size );                  // create new area
    929                         } // if
     874                        area = mallocNoStats( size );                           // create new area
    930875                } // if
    931           if ( unlikely( naddr == 0p ) ) return 0p;
    932 
    933                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    934                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    935                 // To preserve prior fill, the entire bucket must be copied versus the size.
    936                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    937                 free( oaddr );
    938                 return naddr;
     876          if ( unlikely( area == 0 ) ) return 0;
     877                if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill (calloc/cmemalign) ?
     878                        assert( (header->kind.real.blockSize & 1) == 0 );
     879                        bool mapped __attribute__(( unused )) = headers( "realloc", area, header, freeElem, asize, alignment );
     880                        #ifndef __CFA_DEBUG__
     881                        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     882                        if ( ! mapped )
     883                        #endif // __CFA_DEBUG__
     884                                memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part
     885                        header->kind.real.blockSize |= 2;                       // mark new request as zero fill
     886                } // if
     887                memcpy( area, addr, usize );                                    // copy bytes
     888                free( addr );
     889                return area;
    939890        } // realloc
    940891
    941         // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of
    942         // alignment, which must be a power of two. (obsolete)
     892        // The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory
     893        // address will be a multiple of alignment, which must be a power of two.
    943894        void * memalign( size_t alignment, size_t size ) {
    944895                #ifdef __STATISTICS__
     
    947898                #endif // __STATISTICS__
    948899
    949                 return memalignNoStats( alignment, size );
     900                void * area = memalignNoStats( alignment, size );
     901
     902                return area;
    950903        } // memalign
    951904
    952 
    953         // Same as calloc() with memory alignment.
    954         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
    955                 #ifdef __STATISTICS__
    956                 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    957                 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    958                 #endif // __STATISTICS__
    959 
    960                 return cmemalignNoStats( alignment, noOfElems, elemSize );
    961         } // cmemalign
    962 
    963         // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
    964     // of alignment. This requirement is universally ignored.
     905        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     906        // multiple of alignment.
    965907        void * aligned_alloc( size_t alignment, size_t size ) {
    966908                return memalign( alignment, size );
     
    968910
    969911
    970         // Allocates size bytes and places the address of the allocated memory in *memptr. The address of the allocated
    971         // memory shall be a multiple of alignment, which must be a power of two and a multiple of sizeof(void *). If size
    972         // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
    973         // free(3).
     912        // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
     913        // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of
     914        // sizeof(void *). If size is 0, then posix_memalign() returns either NULL, or a unique pointer value that can later
     915        // be successfully passed to free(3).
    974916        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    975917          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    976918                * memptr = memalign( alignment, size );
    977           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
     919          if ( unlikely( * memptr == 0 ) ) return ENOMEM;
    978920                return 0;
    979921        } // posix_memalign
    980922
    981         // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
    982         // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
     923        // The obsolete function valloc() allocates size bytes and returns a pointer to the allocated memory. The memory
     924        // address will be a multiple of the page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    983925        void * valloc( size_t size ) {
    984926                return memalign( pageSize, size );
     
    986928
    987929
    988         // Same as valloc but rounds size to multiple of page size.
    989         void * pvalloc( size_t size ) {
    990                 return memalign( pageSize, libCeiling( size, pageSize ) );
    991         } // pvalloc
    992 
    993 
    994         // Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc()
    995         // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is
    996         // 0p, no operation is performed.
     930        // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
     931        // malloc(), calloc() or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior
     932        // occurs. If ptr is NULL, no operation is performed.
    997933        void free( void * addr ) {
    998934                #ifdef __STATISTICS__
     
    1000936                #endif // __STATISTICS__
    1001937
    1002           if ( unlikely( addr == 0p ) ) {                                       // special case
    1003                         // #ifdef __CFA_DEBUG__
    1004                         // if ( traceHeap() ) {
    1005                         //      #define nullmsg "Free( 0x0 ) size:0\n"
    1006                         //      // Do not debug print free( 0p ), as it can cause recursive entry from sprintf.
    1007                         //      __cfaabi_dbg_write( nullmsg, sizeof(nullmsg) - 1 );
    1008                         // } // if
    1009                         // #endif // __CFA_DEBUG__
     938                // #comment TD : To decrease nesting I would but the special case in the
     939                //               else instead, plus it reads more naturally to have the
     940                //               short / normal case instead
     941                if ( unlikely( addr == 0 ) ) {                                  // special case
     942                        #ifdef __CFA_DEBUG__
     943                        if ( traceHeap() ) {
     944                                #define nullmsg "Free( 0x0 ) size:0\n"
     945                                // Do not debug print free( 0 ), as it can cause recursive entry from sprintf.
     946                                __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 );
     947                        } // if
     948                        #endif // __CFA_DEBUG__
    1010949                        return;
    1011950                } // exit
     
    1014953        } // free
    1015954
    1016 
    1017         // Returns the alignment of the allocation.
     955        // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
     956        // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
     957        // parameter.
     958        int mallopt( int option, int value ) {
     959                choose( option ) {
     960                  case M_TOP_PAD:
     961                        if ( setHeapExpand( value ) ) fallthru default;
     962                  case M_MMAP_THRESHOLD:
     963                        if ( setMmapStart( value ) ) fallthru default;
     964                  default:
     965                        // #comment TD : 1 for unsopported feels wrong
     966                        return 1;                                                                       // success, or unsupported
     967                } // switch
     968                return 0;                                                                               // error
     969        } // mallopt
     970
     971        // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
     972        // suitable argument).
     973        int malloc_trim( size_t ) {
     974                return 0;                                                                               // => impossible to release memory
     975        } // malloc_trim
     976
     977        // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
     978        // a block of memory allocated by malloc(3) or a related function.
     979        size_t malloc_usable_size( void * addr ) {
     980          if ( unlikely( addr == 0 ) ) return 0;                        // null allocation has 0 size
     981
     982                HeapManager.Storage.Header * header;
     983                HeapManager.FreeHeader * freeElem;
     984                size_t size, alignment;
     985
     986                headers( "malloc_usable_size", addr, header, freeElem, size, alignment );
     987                size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
     988                return usize;
     989        } // malloc_usable_size
     990
     991
     992    // The malloc_alignment() function returns the alignment of the allocation.
    1018993        size_t malloc_alignment( void * addr ) {
    1019           if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     994          if ( unlikely( addr == 0 ) ) return libAlign();       // minimum alignment
    1020995                HeapManager.Storage.Header * header = headerAddr( addr );
    1021996                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1022997                        return header->kind.fake.alignment & -2;        // remove flag from value
    1023998                } else {
    1024                         return libAlign();                                                      // minimum alignment
     999                        return libAlign ();                                                     // minimum alignment
    10251000                } // if
    10261001        } // malloc_alignment
    10271002
    10281003
    1029         // Returns true if the allocation is zero filled, i.e., initially allocated by calloc().
     1004    // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    10301005        bool malloc_zero_fill( void * addr ) {
    1031           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1006          if ( unlikely( addr == 0 ) ) return false;            // null allocation is not zero fill
    10321007                HeapManager.Storage.Header * header = headerAddr( addr );
    10331008                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1034                         header = realHeader( header );                          // backup from fake to real header
     1009                        header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
    10351010                } // if
    10361011                return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
     
    10381013
    10391014
    1040         // Returns number of elements if the allocation is for an array, i.e., by calloc().
    1041         size_t malloc_dimension( void * addr ) {
    1042           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    1043                 HeapManager.Storage.Header * header = headerAddr( addr );
    1044                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1045                         header = realHeader( header );                          // backup from fake to real header
    1046                 } // if
    1047                 return header->dimension;                                               // array (calloc/cmemalign)
    1048         } // malloc_zero_fill
    1049 
    1050 
    1051         // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
    1052         // malloc or a related function.
    1053         size_t malloc_usable_size( void * addr ) {
    1054           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    1055                 HeapManager.Storage.Header * header;
    1056                 HeapManager.FreeHeader * freeElem;
    1057                 size_t bsize, alignment;
    1058 
    1059                 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1060                 return dataStorage( bsize, addr, header );      // data storage in bucket
    1061         } // malloc_usable_size
    1062 
    1063 
    1064         // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
     1015    // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
     1016    // related functions.
    10651017        void malloc_stats( void ) {
    10661018                #ifdef __STATISTICS__
    10671019                printStats();
    1068                 if ( prtFree() ) prtFree( heapManager );
     1020                if ( checkFree() ) checkFree( heapManager );
    10691021                #endif // __STATISTICS__
    10701022        } // malloc_stats
    10711023
    1072         // Changes the file descripter where malloc_stats() writes statistics.
    1073         int malloc_stats_fd( int fd __attribute__(( unused )) ) {
     1024        // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
     1025        int malloc_stats_fd( int fd ) {
    10741026                #ifdef __STATISTICS__
    10751027                int temp = statfd;
     
    10811033        } // malloc_stats_fd
    10821034
    1083 
    1084         // Adjusts parameters that control the behavior of the memory-allocation functions (see malloc). The param argument
    1085         // specifies the parameter to be modified, and value specifies the new value for that parameter.
    1086         int mallopt( int option, int value ) {
    1087                 choose( option ) {
    1088                   case M_TOP_PAD:
    1089                         if ( setHeapExpand( value ) ) return 1;
    1090                   case M_MMAP_THRESHOLD:
    1091                         if ( setMmapStart( value ) ) return 1;
    1092                 } // switch
    1093                 return 0;                                                                               // error, unsupported
    1094         } // mallopt
    1095 
    1096         // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
    1097         int malloc_trim( size_t ) {
    1098                 return 0;                                                                               // => impossible to release memory
    1099         } // malloc_trim
    1100 
    1101 
    1102         // Exports an XML string that describes the current state of the memory-allocation implementation in the caller.
    1103         // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
    1104         // malloc).
     1035        // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
     1036        // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
     1037        // information about all arenas (see malloc(3)).
    11051038        int malloc_info( int options, FILE * stream ) {
    1106                 if ( options != 0 ) { errno = EINVAL; return -1; }
    11071039                return printStatsXML( stream );
    11081040        } // malloc_info
    11091041
    11101042
    1111         // Records the current state of all malloc internal bookkeeping variables (but not the actual contents of the heap
    1112         // or the state of malloc_hook functions pointers).  The state is recorded in a system-dependent opaque data
    1113         // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
    1114         // result.  (The caller must free this memory.)
     1043        // The malloc_get_state() function records the current state of all malloc(3) internal bookkeeping variables (but
     1044        // not the actual contents of the heap or the state of malloc_hook(3) functions pointers).  The state is recorded in
     1045        // a system-dependent opaque data structure dynamically allocated via malloc(3), and a pointer to that data
     1046        // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
    11151047        void * malloc_get_state( void ) {
    1116                 return 0p;                                                                              // unsupported
     1048                return 0;                                                                               // unsupported
    11171049        } // malloc_get_state
    11181050
    11191051
    1120         // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    1121         // structure pointed to by state.
     1052        // The malloc_set_state() function restores the state of all malloc(3) internal bookkeeping variables to the values
     1053        // recorded in the opaque data structure pointed to by state.
    11221054        int malloc_set_state( void * ptr ) {
    11231055                return 0;                                                                               // unsupported
     
    11261058
    11271059
    1128 // Must have CFA linkage to overload with C linkage realloc.
    1129 void * resize( void * oaddr, size_t nalign, size_t size ) {
    1130         #ifdef __STATISTICS__
    1131         __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    1132         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1133         #endif // __STATISTICS__
    1134 
    1135         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1136   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
    1137   if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    1138 
    1139 
    1140         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
    1141         #ifdef __CFA_DEBUG__
    1142         else
    1143                 checkAlign( nalign );                                                   // check alignment
    1144         #endif // __CFA_DEBUG__
    1145 
    1146         HeapManager.Storage.Header * header;
    1147         HeapManager.FreeHeader * freeElem;
    1148         size_t bsize, oalign = 0;
    1149         headers( "resize", oaddr, header, freeElem, bsize, oalign );
    1150         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1151 
    1152         if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
    1153                 if ( oalign >= libAlign() ) {                                   // fake header ?
    1154                         headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1155                 } // if
    1156                 if ( size <= odsize && odsize <= size * 2 ) {   // allow 50% wasted storage for smaller size
    1157                         header->kind.real.blockSize &= -2;                      // turn off 0 fill
    1158                         return oaddr;
    1159                 } // if
    1160         } // if
    1161 
    1162         // change size
    1163 
    1164         void * naddr;
    1165         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1166                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1167         } else {
    1168                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1169         } // if
    1170 
    1171         free( oaddr );
    1172         return naddr;
    1173 } // resize
    1174 
    1175 
    1176 void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1177         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
    1178         #ifdef __CFA_DEBUG__
    1179         else
    1180                 checkAlign( nalign );                                                   // check alignment
    1181         #endif // __CFA_DEBUG__
    1182 
    1183         HeapManager.Storage.Header * header;
    1184         HeapManager.FreeHeader * freeElem;
    1185         size_t bsize, oalign = 0;
    1186         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1187         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1188 
    1189         if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
    1190                 if ( oalign >= libAlign() ) {                                   // fake header ?
    1191                         headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1192                 } // if
    1193                 return realloc( oaddr, size );
    1194         } // if
    1195 
    1196         // change size and copy old content to new storage
    1197 
    1198         #ifdef __STATISTICS__
    1199         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    1200         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1201         #endif // __STATISTICS__
    1202 
    1203         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1204   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
    1205   if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    1206 
    1207         void * naddr;
    1208         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1209                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1210         } else {
    1211                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1212         } // if
    1213 
    1214         headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1215         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage available in bucket
    1216         // To preserve prior fill, the entire bucket must be copied versus the size.
    1217         memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
    1218         free( oaddr );
    1219         return naddr;
    1220 } // realloc
    1221 
    1222 
    12231060// Local Variables: //
    12241061// tab-width: 4 //
  • libcfa/src/interpose.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 13 17:35:37 2020
    13 // Update Count     : 178
     12// Last Modified On : Sun Jul 14 22:57:16 2019
     13// Update Count     : 116
    1414//
    1515
     
    2929#include "bits/signal.hfa"                                                              // sigHandler_?
    3030#include "startup.hfa"                                                                  // STARTUP_PRIORITY_CORE
    31 #include <assert.h>
    3231
    3332//=============================================================================================
     
    4140
    4241typedef void (* generic_fptr_t)(void);
    43 generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
     42generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
    4443        const char * error;
    4544
     
    9695        void __cfaabi_interpose_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));
    9796        void __cfaabi_interpose_startup( void ) {
    98                 const char *version = 0p;
     97                const char *version = NULL;
    9998
    10099                preload_libgcc();
     
    106105#pragma GCC diagnostic pop
    107106
    108                 // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
    109                 // task stacks might be very small (4K) and the signal delivery corrupts memory to the point that a clean
    110                 // shutdown is impossible. Also, when a stack overflow encounters the non-accessible sentinel page (debug only)
    111                 // and generates a segment fault, the signal cannot be delivered on the sentinel page. Finally, calls to abort
    112                 // print a stack trace that uses substantial stack space.
    113 
    114                 #define MINSTKSZ SIGSTKSZ * 8
    115                 static char stack[MINSTKSZ] __attribute__(( aligned (16) ));
    116                 static stack_t ss;
    117 
    118                 ss.ss_sp = stack;
    119                 ss.ss_size = MINSTKSZ;
    120                 ss.ss_flags = 0;
    121                 if ( sigaltstack( &ss, 0p ) == -1 ) {
    122                         abort( "__cfaabi_interpose_startup : internal error, sigaltstack error(%d) %s.", errno, strerror( errno ) );
    123                 } // if
    124 
    125107                // Failure handler
    126                 __cfaabi_sigaction( SIGSEGV, sigHandler_segv, SA_SIGINFO | SA_ONSTACK );
    127                 __cfaabi_sigaction( SIGBUS , sigHandler_segv, SA_SIGINFO | SA_ONSTACK );
    128                 __cfaabi_sigaction( SIGILL , sigHandler_ill , SA_SIGINFO | SA_ONSTACK );
    129                 __cfaabi_sigaction( SIGFPE , sigHandler_fpe , SA_SIGINFO | SA_ONSTACK );
    130                 __cfaabi_sigaction( SIGTERM, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // one shot handler, return to default
    131                 __cfaabi_sigaction( SIGINT , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND );
    132                 __cfaabi_sigaction( SIGABRT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND );
    133                 __cfaabi_sigaction( SIGHUP , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // terminal hangup
     108                __cfaabi_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO );
     109                __cfaabi_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO );
     110                __cfaabi_sigaction( SIGILL , sigHandler_ill  , SA_SIGINFO );
     111                __cfaabi_sigaction( SIGFPE , sigHandler_fpe  , SA_SIGINFO );
     112                __cfaabi_sigaction( SIGABRT, sigHandler_abrt, SA_SIGINFO | SA_RESETHAND);
     113                __cfaabi_sigaction( SIGTERM, sigHandler_term , SA_SIGINFO );
     114                __cfaabi_sigaction( SIGINT , sigHandler_term , SA_SIGINFO );
    134115        }
    135116}
     
    142123void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    143124void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
    144 void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    145 void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
    146125
    147126extern "C" {
    148127        void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    149                 abort( false, "%s", "" );
     128                abort( NULL );
    150129        }
    151130
     
    153132                va_list argp;
    154133                va_start( argp, fmt );
    155                 __abort( false, fmt, argp );
     134                abort( fmt, argp );
    156135                va_end( argp );
    157136        }
     
    162141}
    163142
    164 void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; }
    165 void kernel_abort_msg( void * data, char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
    166 // See concurrency/kernel.cfa for strong definition used in multi-processor mode.
     143void * kernel_abort    ( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return NULL; }
     144void   kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
    167145int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
    168146
    169147enum { abort_text_size = 1024 };
    170148static char abort_text[ abort_text_size ];
    171 
    172 static void __cfaabi_backtrace( int start ) {
    173         enum { Frames = 50, };                                                          // maximum number of stack frames
    174         int last = kernel_abort_lastframe();                            // skip last N stack frames
     149static int abort_lastframe;
     150
     151void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )) {
     152    va_list args;
     153    va_start( args, fmt );
     154    vfprintf( stderr, fmt, args );
     155    va_end( args );
     156        __cabi_libc.exit( status );
     157}
     158
     159void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
     160        void * kernel_data = kernel_abort();                    // must be done here to lock down kernel
     161        int len;
     162
     163        abort_lastframe = kernel_abort_lastframe();
     164        len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
     165        __cfaabi_dbg_bits_write( abort_text, len );
     166
     167        if ( fmt ) {
     168                va_list args;
     169                va_start( args, fmt );
     170
     171                len = vsnprintf( abort_text, abort_text_size, fmt, args );
     172                va_end( args );
     173                __cfaabi_dbg_bits_write( abort_text, len );
     174
     175                if ( fmt[strlen( fmt ) - 1] != '\n' ) {         // add optional newline if missing at the end of the format text
     176                        __cfaabi_dbg_bits_write( "\n", 1 );
     177                }
     178        }
     179
     180        kernel_abort_msg( kernel_data, abort_text, abort_text_size );
     181        __cabi_libc.abort();
     182}
     183
     184static void __cfaabi_backtrace() {
     185        enum {
     186                Frames = 50,                                                                    // maximum number of stack frames
     187                Start = 8,                                                                              // skip first N stack frames
     188        };
    175189
    176190        void * array[Frames];
    177191        size_t size = backtrace( array, Frames );
    178         char ** messages = backtrace_symbols( array, size ); // does not demangle names
    179 
    180         *index( messages[0], '(' ) = '\0';                                      // find executable name
    181         __cfaabi_bits_print_nolock( STDERR_FILENO, "Stack back trace for: %s\n", messages[0]);
    182 
    183         for ( unsigned int i = start; i < size - last && messages != 0p; i += 1 ) {
    184                 char * name = 0p, * offset_begin = 0p, * offset_end = 0p;
    185 
    186                 for ( char * p = messages[i]; *p; p += 1 ) {    // find parantheses and +offset
    187                         //__cfaabi_bits_print_nolock( "X %s\n", p);
     192        char ** messages = backtrace_symbols( array, size );
     193
     194        // find executable name
     195        *index( messages[0], '(' ) = '\0';
     196        __cfaabi_dbg_bits_print_nolock( "Stack back trace for: %s\n", messages[0]);
     197
     198        for ( int i = Start; i < size - abort_lastframe && messages != NULL; i += 1 ) {
     199                char * name = NULL, * offset_begin = NULL, * offset_end = NULL;
     200
     201                for ( char * p = messages[i]; *p; ++p ) {
     202                        //__cfaabi_dbg_bits_print_nolock( "X %s\n", p);
     203                        // find parantheses and +offset
    188204                        if ( *p == '(' ) {
    189205                                name = p;
     
    196212                }
    197213
    198                 // if line contains symbol, print it
    199                 int frameNo = i - start;
     214                // if line contains symbol print it
     215                int frameNo = i - Start;
    200216                if ( name && offset_begin && offset_end && name < offset_begin ) {
    201                         *name++ = '\0';                                                         // delimit strings
     217                        // delimit strings
     218                        *name++ = '\0';
    202219                        *offset_begin++ = '\0';
    203220                        *offset_end++ = '\0';
    204221
    205                         __cfaabi_bits_print_nolock( STDERR_FILENO, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
     222                        __cfaabi_dbg_bits_print_nolock( "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
    206223                } else {                                                                                // otherwise, print the whole line
    207                         __cfaabi_bits_print_nolock( STDERR_FILENO, "(%i) %s\n", frameNo, messages[i] );
     224                        __cfaabi_dbg_bits_print_nolock( "(%i) %s\n", frameNo, messages[i] );
    208225                }
    209226        }
     
    211228}
    212229
    213 void exit( int status, const char fmt[], ... ) {
    214         va_list args;
    215         va_start( args, fmt );
    216         vfprintf( stderr, fmt, args );
    217         va_end( args );
    218         __cabi_libc.exit( status );
    219 }
    220 
    221 // Cannot forward va_list.
    222 void __abort( bool signalAbort, const char fmt[], va_list args ) {
    223         void * kernel_data = kernel_abort();                            // must be done here to lock down kernel
    224         int len;
    225 
    226         signal( SIGABRT, SIG_DFL );                                                     // prevent final "real" abort from recursing to handler
    227 
    228         len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
    229         __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    230 
    231         assert( fmt );
    232         len = vsnprintf( abort_text, abort_text_size, fmt, args );
    233         __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    234 
    235         if ( fmt[strlen( fmt ) - 1] != '\n' ) {                         // add optional newline if missing at the end of the format text
    236                 __cfaabi_bits_write( STDERR_FILENO, "\n", 1 );
    237         } // if
    238         kernel_abort_msg( kernel_data, abort_text, abort_text_size );
    239 
    240         __cfaabi_backtrace( signalAbort ? 4 : 2 );
    241 
    242         __cabi_libc.abort();                                                            // print stack trace in handler
    243 }
    244 
    245 void abort( const char fmt[], ... ) {
    246         va_list args;
    247         va_start( args, fmt );
    248         __abort( false, fmt, args );
    249     // CONTROL NEVER REACHES HERE!
    250         va_end( args );
    251 }
    252 
    253 void abort( bool signalAbort, const char fmt[], ... ) {
    254     va_list args;
    255     va_start( args, fmt );
    256     __abort( signalAbort, fmt, args );
    257     // CONTROL NEVER REACHES HERE!
    258     va_end( args );
    259 }
    260 
    261230void sigHandler_segv( __CFA_SIGPARMS__ ) {
    262                 if ( sfp->si_addr == 0p ) {
    263                         abort( true, "Null pointer (0p) dereference.\n" );
    264                 } else {
    265                         abort( true, "%s at memory location %p.\n"
    266                                    "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript.\n",
    267                                    (sig == SIGSEGV ? "Segment fault" : "Bus error"), sfp->si_addr );
    268                 }
     231        abort( "Addressing invalid memory at location %p\n"
     232                        "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript.\n",
     233                        sfp->si_addr );
    269234}
    270235
    271236void sigHandler_ill( __CFA_SIGPARMS__ ) {
    272         abort( true, "Executing illegal instruction at location %p.\n"
     237        abort( "Executing illegal instruction at location %p.\n"
    273238                        "Possible cause is stack corruption.\n",
    274239                        sfp->si_addr );
     
    286251          default: msg = "unknown";
    287252        } // choose
    288         abort( true, "Computation error %s at location %p.\n", msg, sfp->si_addr );
     253        abort( "Computation error %s at location %p.\n", msg, sfp->si_addr );
     254}
     255
     256void sigHandler_abrt( __CFA_SIGPARMS__ ) {
     257        __cfaabi_backtrace();
     258
     259        // reset default signal handler
     260        __cfaabi_sigdefault( SIGABRT );
     261
     262        raise( SIGABRT );
    289263}
    290264
    291265void sigHandler_term( __CFA_SIGPARMS__ ) {
    292         abort( true, "Application interrupted by signal: %s.\n", strsignal( sig ) );
     266        abort( "Application stopped by %s signal.", sig == SIGINT ? "an interrupt (SIGINT)" : "a terminate (SIGTERM)" );
    293267}
    294268
  • libcfa/src/iostream.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar 11 14:35:35 2020
    13 // Update Count     : 860
     12// Last Modified On : Sat Jul 13 08:07:59 2019
     13// Update Count     : 821
    1414//
    1515
     
    1919#include <stdio.h>
    2020#include <stdbool.h>                                                                    // true/false
    21 #include <stdint.h>                                                                             // UINT64_MAX
    2221//#include <string.h>                                                                   // strlen, strcmp
    2322extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
     
    3635forall( dtype ostype | ostream( ostype ) ) {
    3736        ostype & ?|?( ostype & os, zero_t ) {
    38                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     37                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    3938                fmt( os, "%d", 0n );
    4039                return os;
     
    4544
    4645        ostype & ?|?( ostype & os, one_t ) {
    47                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     46                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    4847                fmt( os, "%d", 1n );
    4948                return os;
     
    5453
    5554        ostype & ?|?( ostype & os, bool b ) {
    56                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     55                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    5756                fmt( os, "%s", b ? "true" : "false" );
    5857                return os;
     
    6463        ostype & ?|?( ostype & os, char c ) {
    6564                fmt( os, "%c", c );
    66                 if ( c == '\n' ) $setNL( os, true );
     65                if ( c == '\n' ) setNL( os, true );
    6766                return sepOff( os );
    6867        } // ?|?
     
    7271
    7372        ostype & ?|?( ostype & os, signed char sc ) {
    74                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     73                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    7574                fmt( os, "%hhd", sc );
    7675                return os;
     
    8180
    8281        ostype & ?|?( ostype & os, unsigned char usc ) {
    83                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     82                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    8483                fmt( os, "%hhu", usc );
    8584                return os;
     
    9089
    9190        ostype & ?|?( ostype & os, short int si ) {
    92                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     91                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    9392                fmt( os, "%hd", si );
    9493                return os;
     
    9998
    10099        ostype & ?|?( ostype & os, unsigned short int usi ) {
    101                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     100                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    102101                fmt( os, "%hu", usi );
    103102                return os;
     
    108107
    109108        ostype & ?|?( ostype & os, int i ) {
    110                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     109                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    111110                fmt( os, "%d", i );
    112111                return os;
     
    117116
    118117        ostype & ?|?( ostype & os, unsigned int ui ) {
    119                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     118                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    120119                fmt( os, "%u", ui );
    121120                return os;
     
    126125
    127126        ostype & ?|?( ostype & os, long int li ) {
    128                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     127                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    129128                fmt( os, "%ld", li );
    130129                return os;
     
    135134
    136135        ostype & ?|?( ostype & os, unsigned long int uli ) {
    137                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     136                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    138137                fmt( os, "%lu", uli );
    139138                return os;
     
    144143
    145144        ostype & ?|?( ostype & os, long long int lli ) {
    146                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     145                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    147146                fmt( os, "%lld", lli );
    148147                return os;
     
    153152
    154153        ostype & ?|?( ostype & os, unsigned long long int ulli ) {
    155                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     154                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    156155                fmt( os, "%llu", ulli );
    157156                return os;
     
    160159                (ostype &)(os | ulli); ends( os );
    161160        } // ?|?
    162 
    163 #if defined( __SIZEOF_INT128__ )
    164         //      UINT64_MAX 18_446_744_073_709_551_615_ULL
    165         #define P10_UINT64 10_000_000_000_000_000_000_ULL       // 19 zeroes
    166 
    167         static void base10_128( ostype & os, unsigned int128 val ) {
    168                 if ( val > UINT64_MAX ) {
    169                         base10_128( os, val / P10_UINT64 );                     // recursive
    170                         fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
    171                 } else {
    172                         fmt( os, "%lu", (uint64_t)val );
    173                 } // if
    174         } // base10_128
    175 
    176         static void base10_128( ostype & os, int128 val ) {
    177                 if ( val < 0 ) {
    178                         fmt( os, "-" );                                                         // leading negative sign
    179                         val = -val;
    180                 } // if
    181                 base10_128( os, (unsigned int128)val );                 // print zero/positive value
    182         } // base10_128
    183 
    184         ostype & ?|?( ostype & os, int128 llli ) {
    185                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    186                 base10_128( os, llli );
    187                 return os;
    188         } // ?|?
    189         void & ?|?( ostype & os, int128 llli ) {
    190                 (ostype &)(os | llli); ends( os );
    191         } // ?|?
    192 
    193         ostype & ?|?( ostype & os, unsigned int128 ullli ) {
    194                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    195                 base10_128( os, ullli );
    196                 return os;
    197         } // ?|?
    198         void & ?|?( ostype & os, unsigned int128 ullli ) {
    199                 (ostype &)(os | ullli); ends( os );
    200         } // ?|?
    201 #endif // __SIZEOF_INT128__
    202161
    203162        #define PrintWithDP( os, format, val, ... ) \
     
    216175
    217176        ostype & ?|?( ostype & os, float f ) {
    218                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     177                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    219178                PrintWithDP( os, "%g", f );
    220179                return os;
     
    225184
    226185        ostype & ?|?( ostype & os, double d ) {
    227                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     186                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    228187                PrintWithDP( os, "%.*lg", d, DBL_DIG );
    229188                return os;
     
    234193
    235194        ostype & ?|?( ostype & os, long double ld ) {
    236                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     195                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    237196                PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
    238197                return os;
     
    243202
    244203        ostype & ?|?( ostype & os, float _Complex fc ) {
    245                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     204                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    246205//              os | crealf( fc ) | nonl;
    247206                PrintWithDP( os, "%g", crealf( fc ) );
     
    255214
    256215        ostype & ?|?( ostype & os, double _Complex dc ) {
    257                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     216                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    258217//              os | creal( dc ) | nonl;
    259218                PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG );
     
    267226
    268227        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    269                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     228                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    270229//              os | creall( ldc ) || nonl;
    271230                PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG );
     
    278237        } // ?|?
    279238
    280         ostype & ?|?( ostype & os, const char str[] ) {
     239        ostype & ?|?( ostype & os, const char * str ) {
    281240                enum { Open = 1, Close, OpenClose };
    282241                static const unsigned char mask[256] @= {
     
    298257                // first character IS NOT spacing or closing punctuation => add left separator
    299258                unsigned char ch = str[0];                                              // must make unsigned
    300                 if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
    301                         fmt( os, "%s", $sepGetCur( os ) );
     259                if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
     260                        fmt( os, "%s", sepGetCur( os ) );
    302261                } // if
    303262
    304263                // if string starts line, must reset to determine open state because separator is off
    305                 $sepReset( os );                                                                // reset separator
     264                sepReset( os );                                                                 // reset separator
    306265
    307266                // last character IS spacing or opening punctuation => turn off separator for next item
    308267                size_t len = strlen( str );
    309268                ch = str[len - 1];                                                              // must make unsigned
    310                 if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
     269                if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
    311270                        sepOn( os );
    312271                } else {
    313272                        sepOff( os );
    314273                } // if
    315                 if ( ch == '\n' ) $setNL( os, true );                   // check *AFTER* $sepPrt call above as it resets NL flag
     274                if ( ch == '\n' ) setNL( os, true );                    // check *AFTER* sepPrt call above as it resets NL flag
    316275                return write( os, str, len );
    317276        } // ?|?
    318 
    319         void ?|?( ostype & os, const char str[] ) {
     277        void ?|?( ostype & os, const char * str ) {
    320278                (ostype &)(os | str); ends( os );
    321279        } // ?|?
    322280
    323281//      ostype & ?|?( ostype & os, const char16_t * str ) {
    324 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     282//              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    325283//              fmt( os, "%ls", str );
    326284//              return os;
     
    329287// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    330288//      ostype & ?|?( ostype & os, const char32_t * str ) {
    331 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     289//              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    332290//              fmt( os, "%ls", str );
    333291//              return os;
     
    336294
    337295//      ostype & ?|?( ostype & os, const wchar_t * str ) {
    338 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     296//              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    339297//              fmt( os, "%ls", str );
    340298//              return os;
     
    342300
    343301        ostype & ?|?( ostype & os, const void * p ) {
    344                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     302                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    345303                fmt( os, "%p", p );
    346304                return os;
     
    357315        void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    358316                (ostype &)(manip( os ));
    359                 if ( $getPrt( os ) ) ends( os );                                // something printed ?
    360                 $setPrt( os, false );                                                   // turn off
     317                if ( getPrt( os ) ) ends( os );                                 // something printed ?
     318                setPrt( os, false );                                                    // turn off
    361319        } // ?|?
    362320
     
    371329        ostype & nl( ostype & os ) {
    372330                (ostype &)(os | '\n');
    373                 $setPrt( os, false );                                                   // turn off
    374                 $setNL( os, true );
     331                setPrt( os, false );                                                    // turn off
     332                setNL( os, true );
    375333                flush( os );
    376334                return sepOff( os );                                                    // prepare for next line
     
    378336
    379337        ostype & nonl( ostype & os ) {
    380                 $setPrt( os, false );                                                   // turn off
     338                setPrt( os, false );                                                    // turn off
    381339                return os;
    382340        } // nonl
     
    417375        ostype & ?|?( ostype & os, T arg, Params rest ) {
    418376                (ostype &)(os | arg);                                                   // print first argument
    419                 $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
     377                sepSetCur( os, sepGetTuple( os ) );                             // switch to tuple separator
    420378                (ostype &)(os | rest);                                                  // print remaining arguments
    421                 $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
     379                sepSetCur( os, sepGet( os ) );                                  // switch to regular separator
    422380                return os;
    423381        } // ?|?
     
    425383                // (ostype &)(?|?( os, arg, rest )); ends( os );
    426384                (ostype &)(os | arg);                                                   // print first argument
    427                 $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
     385                sepSetCur( os, sepGetTuple( os ) );                             // switch to tuple separator
    428386                (ostype &)(os | rest);                                                  // print remaining arguments
    429                 $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
     387                sepSetCur( os, sepGet( os ) );                                  // switch to regular separator
    430388                ends( os );
    431389        } // ?|?
     
    456414forall( dtype ostype | ostream( ostype ) ) { \
    457415        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    458                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     416                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
    459417\
    460418                if ( f.base == 'b' || f.base == 'B' ) {                 /* bespoke binary format */ \
     
    505463\
    506464                if ( ! f.flags.pc ) {                                                   /* no precision */ \
     465                        /* printf( "%s\n", &fmtstr[star] ); */ \
    507466                        fmtstr[sizeof(IFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    508                         /* printf( "%s %c %c\n", &fmtstr[star], f.base, CODE ); */ \
    509467                        fmt( os, &fmtstr[star], f.wd, f.val ); \
    510468                } else {                                                                                /* precision */ \
    511469                        fmtstr[sizeof(IFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    512                         /* printf( "%s %c %c\n", &fmtstr[star], f.base, CODE ); */ \
     470                        /* printf( "%s\n", &fmtstr[star] ); */ \
    513471                        fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \
    514472                } /* if */ \
     
    528486IntegralFMTImpl( signed long long int, 'd', "%    *ll ", "%    *.*ll " )
    529487IntegralFMTImpl( unsigned long long int, 'u', "%    *ll ", "%    *.*ll " )
    530 
    531 
    532 #if defined( __SIZEOF_INT128__ )
    533 // Default prefix for non-decimal prints is 0b, 0, 0x.
    534 #define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
    535 forall( dtype ostype | ostream( ostype ) ) \
    536 static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
    537         if ( f.val > UINT64_MAX ) { \
    538                 unsigned long long int lsig = f.val % P10_UINT64; \
    539                 f.val /= P10_UINT64; /* msig */ \
    540                 base10_128( os, f ); /* recursion */ \
    541                 _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \
    542                 fmt.flags.nobsdp = true; \
    543                 /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \
    544                 sepOff( os ); \
    545                 (ostype &)(os | fmt); \
    546         } else { \
    547                 /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \
    548                 _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \
    549                 (ostype &)(os | fmt); \
    550         } /* if */ \
    551 } /* base10_128 */ \
    552 forall( dtype ostype | ostream( ostype ) ) { \
    553         ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    554                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    555 \
    556                 if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
    557                         unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
    558                         unsigned long long int lsig = (unsigned long long int)(f.val); \
    559                         _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
    560                         _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
    561                         if ( msig == 0 ) { \
    562                                 fmt.val = lsig; \
    563                                 (ostype &)(os | fmt); \
    564                         } else { \
    565                                 fmt2.flags.pad0 = fmt2.flags.nobsdp = true;     \
    566                                 if ( f.base == 'b' | f.base == 'B' ) { \
    567                                         if ( f.wd > 64 ) fmt.wd = f.wd - 64; \
    568                                         if ( f.flags.pc && f.pc > 64 ) fmt.pc = f.pc - 64; \
    569                                         fmt2.wd = 64; \
    570                                         (ostype &)(os | fmt | "" | fmt2); \
    571                                 } else if ( f.base == 'o' ) { \
    572                                         fmt.val = (unsigned long long int)fmt.val >> 2; \
    573                                         if ( f.wd > 21 ) fmt.wd = f.wd - 21; \
    574                                         if ( f.flags.pc && f.pc > 21 ) fmt.pc = f.pc - 21; \
    575                                         fmt2.wd = 1; \
    576                                         fmt2.val = ((msig & 0x3) << 1) + 1; \
    577                                         (ostype &)(os | fmt | "" | fmt2); \
    578                                         sepOff( os ); \
    579                                         fmt2.wd = 21; \
    580                                         fmt2.val = lsig & 0x7fffffffffffffff; \
    581                                         (ostype &)(os | fmt2); \
    582                                 } else { \
    583                                         if ( f.flags.left ) { \
    584                                                 if ( f.wd > 16 ) fmt2.wd = f.wd - 16; \
    585                                                 fmt.wd = 16; \
    586                                         } else { \
    587                                                 if ( f.wd > 16 ) fmt.wd = f.wd - 16; \
    588                                                 if ( f.flags.pc && f.pc > 16 ) fmt.pc = f.pc - 16; \
    589                                                 fmt2.wd = 16; \
    590                                         } /* if */ \
    591                                         (ostype &)(os | fmt | "" | fmt2); \
    592                                 } /* if */ \
    593                         } /* if */ \
    594                 } else { \
    595                         if ( CODE == 'd' ) { \
    596                                 if ( f.val < 0 )  { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \
    597                         } /* if */ \
    598                         base10_128( os, f ); \
    599                 } /* if */ \
    600                 return os; \
    601         } /* ?|? */ \
    602         void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    603 } // distribution
    604 
    605 IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
    606 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
    607 #endif // __SIZEOF_INT128__
    608488
    609489//*********************************** floating point ***********************************
     
    633513forall( dtype ostype | ostream( ostype ) ) { \
    634514        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    635                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     515                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
    636516                char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
    637517                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
     
    656536                return os; \
    657537        } /* ?|? */ \
    658 \
    659538        void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    660539} // distribution
     
    676555                } // if
    677556
    678                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     557                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    679558
    680559                #define CFMTNP "% * "
     
    692571                return os;
    693572        } // ?|?
    694 
    695573        void ?|?( ostype & os, _Ostream_Manip(char) f ) { (ostype &)(os | f); ends( os ); }
    696574} // distribution
     
    714592                } // if
    715593
    716                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     594                if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
    717595
    718596                #define SFMTNP "% * "
     
    738616                return os;
    739617        } // ?|?
    740 
    741618        void ?|?( ostype & os, _Ostream_Manip(const char *) f ) { (ostype &)(os | f); ends( os ); }
    742619} // distribution
     
    858735        } // ?|?
    859736
    860         // istype & ?|?( istype & is, const char fmt[] ) {
     737        // istype & ?|?( istype & is, const char * fmt ) {
    861738        //      fmt( is, fmt, "" );
    862739        //      return is;
  • libcfa/src/iostream.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 20 15:30:56 2020
    13 // Update Count     : 337
     12// Last Modified On : Fri Jul 12 12:08:38 2019
     13// Update Count     : 334
    1414//
    1515
     
    2424trait ostream( dtype ostype ) {
    2525        // private
    26         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
     26        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
    3636        // public
    3737        void sepOn( ostype & );                                                         // turn separator state on
     
    4343
    4444        const char * sepGet( ostype & );                                        // get separator string
    45         void sepSet( ostype &, const char [] );                         // set separator to string (15 character maximum)
     45        void sepSet( ostype &, const char * );                          // set separator to string (15 character maximum)
    4646        const char * sepGetTuple( ostype & );                           // get tuple separator string
    47         void sepSetTuple( ostype &, const char [] );            // set tuple separator to string (15 character maximum)
     47        void sepSetTuple( ostype &, const char * );                     // set tuple separator to string (15 character maximum)
    4848
    4949        void ends( ostype & os );                                                       // end of output statement
    5050        int fail( ostype & );
    5151        int flush( ostype & );
    52         void open( ostype & os, const char name[], const char mode[] );
     52        void open( ostype & os, const char * name, const char * mode );
    5353        void close( ostype & os );
    54         ostype & write( ostype &, const char [], size_t );
     54        ostype & write( ostype &, const char *, size_t );
    5555        int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    5656}; // ostream
     
    9898        ostype & ?|?( ostype &, unsigned long long int );
    9999        void ?|?( ostype &, unsigned long long int );
    100 #if defined( __SIZEOF_INT128__ )
    101         ostype & ?|?( ostype &, int128 );
    102         void ?|?( ostype &, int128 );
    103         ostype & ?|?( ostype &, unsigned int128 );
    104         void ?|?( ostype &, unsigned int128 );
    105 #endif // __SIZEOF_INT128__
    106100
    107101        ostype & ?|?( ostype &, float );
     
    119113        void ?|?( ostype &, long double _Complex );
    120114
    121         ostype & ?|?( ostype &, const char [] );
    122         void ?|?( ostype &, const char [] );
     115        ostype & ?|?( ostype &, const char * );
     116        void ?|?( ostype &, const char * );
    123117        // ostype & ?|?( ostype &, const char16_t * );
    124118#if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
     
    212206IntegralFMTDecl( signed long long int, 'd' )
    213207IntegralFMTDecl( unsigned long long int, 'u' )
    214 #if defined( __SIZEOF_INT128__ )
    215 IntegralFMTDecl( int128, 'd' )
    216 IntegralFMTDecl( unsigned int128, 'u' )
    217 #endif
    218208
    219209//*********************************** floating point ***********************************
     
    266256
    267257static inline {
    268         _Ostream_Manip(const char *) bin( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
    269         _Ostream_Manip(const char *) oct( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
    270         _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
    271         _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
    272         _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 } }; }
     258        _Ostream_Manip(const char *) bin( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }
     259        _Ostream_Manip(const char *) oct( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }
     260        _Ostream_Manip(const char *) hex( const char * s ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
     261        _Ostream_Manip(const char *) wd( unsigned int w, const char * s ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
     262        _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 } }; }
    273263        _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
    274264        _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; }
     
    291281        int fail( istype & );
    292282        int eof( istype & );
    293         void open( istype & is, const char name[] );
     283        void open( istype & is, const char * name );
    294284        void close( istype & is );
    295285        istype & read( istype &, char *, size_t );
     
    326316        istype & ?|?( istype &, long double _Complex & );
    327317
    328 //      istype & ?|?( istype &, const char [] );
     318//      istype & ?|?( istype &, const char * );
    329319        istype & ?|?( istype &, char * );
    330320
     
    353343static inline {
    354344        _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
    355         _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
    356         _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
    357         _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
    358         _Istream_Cstr excl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
    359         _Istream_Cstr & excl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
    360         _Istream_Cstr ignore( const char s[] ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
     345        _Istream_Cstr skip( const char * scanset ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
     346        _Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
     347        _Istream_Cstr & incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
     348        _Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }
     349        _Istream_Cstr & excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
     350        _Istream_Cstr ignore( const char * s ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }
    361351        _Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
    362         _Istream_Cstr wdi( unsigned int w, char s[] ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
     352        _Istream_Cstr wdi( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
    363353        _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    364354} // distribution
  • libcfa/src/math.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Apr 18 23:37:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 10:27:11 2020
    13 // Update Count     : 117
     12// Last Modified On : Fri Jul 13 11:02:15 2018
     13// Update Count     : 116
    1414//
    1515
     
    5151static inline long double fdim( long double x, long double y ) { return fdiml( x, y ); }
    5252
    53 static inline float nan( const char tag[] ) { return nanf( tag ); }
    54 // extern "C" { double nan( const char [] ); }
    55 static inline long double nan( const char tag[] ) { return nanl( tag ); }
     53static inline float nan( const char * tag ) { return nanf( tag ); }
     54// extern "C" { double nan( const char * ); }
     55static inline long double nan( const char * tag ) { return nanl( tag ); }
    5656
    5757//---------------------- Exponential ----------------------
  • libcfa/src/rational.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb  8 17:56:36 2020
    13 // Update Count     : 187
     12// Last Modified On : Fri Jul 12 18:12:08 2019
     13// Update Count     : 184
    1414//
    1515
     
    5656        } // rational
    5757
    58         void ?{}( Rational(RationalImpl) & r, zero_t ) {
    59                 r{ (RationalImpl){0}, (RationalImpl){1} };
    60         } // rational
    61 
    62         void ?{}( Rational(RationalImpl) & r, one_t ) {
    63                 r{ (RationalImpl){1}, (RationalImpl){1} };
    64         } // rational
    6558
    6659        // getter for numerator/denominator
  • libcfa/src/startup.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jul 24 16:21:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:18 2020
    13 // Update Count     : 30
     12// Last Modified On : Wed Jul 25 16:42:01 2018
     13// Update Count     : 11
    1414//
    1515
    16 #include <time.h>                                                                               // tzset
    1716#include "startup.hfa"
     17#include <unistd.h>
     18
    1819
    1920extern "C" {
    20     void __cfaabi_appready_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_APPREADY ) ));
     21    static void __cfaabi_appready_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_APPREADY ) ));
    2122    void __cfaabi_appready_startup( void ) {
    22                 tzset();                                                                                // initialize time global variables
    2323                #ifdef __CFA_DEBUG__
    2424                extern void heapAppStart();
     
    2727    } // __cfaabi_appready_startup
    2828
    29     void __cfaabi_appready_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_APPREADY ) ));
     29    static void __cfaabi_appready_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_APPREADY ) ));
    3030    void __cfaabi_appready_shutdown( void ) {
    3131                #ifdef __CFA_DEBUG__
     
    4141struct __spinlock_t;
    4242extern "C" {
    43         void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {}
     43        void __cfaabi_dbg_record(struct __spinlock_t & this, const char * prev_name) __attribute__(( weak )) {}
    4444}
    4545
  • libcfa/src/stdhdr/assert.h

    r7030dab r71d6bd8  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:58:49 2020
    13 // Update Count     : 15
     12// Last Modified On : Mon Jul 31 23:09:32 2017
     13// Update Count     : 13
    1414//
    1515
     
    2727        #define assertf( expr, fmt, ... ) ((expr) ? ((void)0) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ ))
    2828
    29         void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) __attribute__((noreturn, format( printf, 5, 6) ));
     29        void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn, format( printf, 5, 6) ));
    3030#endif
    3131
  • libcfa/src/stdhdr/bfdlink.h

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jul 18 07:26:04 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:08 2020
    13 // Update Count     : 6
     12// Last Modified On : Sun Jul 22 13:49:30 2018
     13// Update Count     : 4
    1414//
    1515
    1616// include file uses the CFA keyword "with".
    1717#if ! defined( with )                                                                   // nesting ?
    18 #define with ``with                                                                             // make keyword an identifier
     18#define with `with`                                                                             // make keyword an identifier
    1919#define __CFA_BFDLINK_H__
    2020#endif
  • libcfa/src/stdhdr/hwloc.h

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jul 18 07:45:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:18 2020
    13 // Update Count     : 6
     12// Last Modified On : Sun Jul 22 13:49:58 2018
     13// Update Count     : 4
    1414//
    1515
    1616// include file uses the CFA keyword "thread".
    1717#if ! defined( thread )                                                                 // nesting ?
    18 #define thread ``thread                                                                 // make keyword an identifier
     18#define thread `thread`                                                                 // make keyword an identifier
    1919#define __CFA_HWLOC_H__
    2020#endif
  • libcfa/src/stdhdr/krb5.h

    r7030dab r71d6bd8  
    1010// Created On       : Tue Jul 18 07:55:44 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:35 2020
    13 // Update Count     : 6
     12// Last Modified On : Sun Jul 22 13:50:24 2018
     13// Update Count     : 4
    1414//
    1515
    1616// include file uses the CFA keyword "enable".
    1717#if ! defined( enable )                                                                 // nesting ?
    18 #define enable ``enable                                                                 // make keyword an identifier
     18#define enable `enable`                                                                 // make keyword an identifier
    1919#define __CFA_KRB5_H__
    2020#endif
  • libcfa/src/stdhdr/malloc.h

    r7030dab r71d6bd8  
    1010// Created On       : Thu Jul 20 15:58:16 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Mar  8 10:01:20 2020
    13 // Update Count     : 11
     12// Last Modified On : Sat Aug 11 09:06:31 2018
     13// Update Count     : 10
    1414//
    1515
     
    3131
    3232extern "C" {
    33 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );
    3433size_t malloc_alignment( void * );
    3534bool malloc_zero_fill( void * );
    36 size_t malloc_dimension( void * );
    3735int malloc_stats_fd( int fd );
     36void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );
    3837} // extern "C"
    3938
  • libcfa/src/stdhdr/math.h

    r7030dab r71d6bd8  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:27 2020
    13 // Update Count     : 15
     12// Last Modified On : Thu Feb 22 18:16:07 2018
     13// Update Count     : 13
    1414//
    1515
    1616extern "C" {
    1717#if ! defined( exception )                                                              // nesting ?
    18 #define exception ``exception                                                   // make keyword an identifier
     18#define exception `exception`                                                   // make keyword an identifier
    1919#define __CFA_MATH_H__
    2020#endif
  • libcfa/src/stdhdr/sys/ucontext.h

    r7030dab r71d6bd8  
    1010// Created On       : Thu Feb  8 23:48:16 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:05:41 2020
    13 // Update Count     : 6
     12// Last Modified On : Thu Feb  8 23:50:44 2018
     13// Update Count     : 4
    1414//
    1515
    1616#if ! defined( ftype )                                                                  // nesting ?
    17 #define ftype ``ftype                                                                   // make keyword an identifier
     17#define ftype `ftype`                                                                   // make keyword an identifier
    1818#define __CFA_UCONTEXT_H__
    1919#endif
  • libcfa/src/stdlib.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 31 13:26:46 2020
    13 // Update Count     : 495
     12// Last Modified On : Tue Oct 22 08:57:52 2019
     13// Update Count     : 478
    1414//
    1515
     
    2020#define _XOPEN_SOURCE 600                                                               // posix_memalign, *rand48
    2121#include <string.h>                                                                             // memcpy, memset
     22#include <malloc.h>                                                                             // malloc_usable_size
    2223//#include <math.h>                                                                             // fabsf, fabs, fabsl
    2324#include <complex.h>                                                                    // _Complex_I
     
    2930        T * alloc_set( T ptr[], size_t dim, char fill ) {       // realloc array with fill
    3031                size_t olen = malloc_usable_size( ptr );                // current allocation
    31                 void * nptr = (void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     32                char * nptr = (char *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
    3233                size_t nlen = malloc_usable_size( nptr );               // new allocation
    3334                if ( nlen > olen ) {                                                    // larger ?
    34                         memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage
     35                        memset( nptr + olen, (int)fill, nlen - olen ); // initialize added storage
    3536                } // if
    3637                return (T *)nptr;
    3738        } // alloc_set
    3839
    39         T * alloc_set( T ptr[], size_t dim, T fill ) { // realloc array with fill
     40        T * alloc_align( T ptr[], size_t align ) {                      // aligned realloc array
     41                char * nptr;
     42                size_t alignment = malloc_alignment( ptr );
     43                if ( align != alignment && (uintptr_t)ptr % align != 0 ) {
     44                        size_t olen = malloc_usable_size( ptr );        // current allocation
     45                        nptr = (char *)memalign( align, olen );
     46                        size_t nlen = malloc_usable_size( nptr );       // new allocation
     47                        size_t lnth = olen < nlen ? olen : nlen;        // min
     48                        memcpy( nptr, ptr, lnth );                                      // initialize storage
     49                        free( ptr );
     50                } else {
     51                        nptr = (char *)ptr;
     52                } // if
     53                return (T *)nptr;
     54        } // alloc_align
     55
     56        T * alloc_align( T ptr[], size_t align, size_t dim ) { // aligned realloc array
     57                char * nptr;
     58                size_t alignment = malloc_alignment( ptr );
     59                if ( align != alignment ) {
     60                        size_t olen = malloc_usable_size( ptr );        // current allocation
     61                        nptr = (char *)memalign( align, dim * sizeof(T) );
     62                        size_t nlen = malloc_usable_size( nptr );       // new allocation
     63                        size_t lnth = olen < nlen ? olen : nlen;        // min
     64                        memcpy( nptr, ptr, lnth );                                      // initialize storage
     65                        free( ptr );
     66                } else {
     67                        nptr = (char *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     68                } // if
     69                return (T *)nptr;
     70        } // alloc_align
     71
     72        T * alloc_align_set( T ptr[], size_t align, char fill ) { // aligned realloc with fill
    4073                size_t olen = malloc_usable_size( ptr );                // current allocation
    41                 void * nptr = (void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     74                char * nptr = alloc_align( ptr, align );
    4275                size_t nlen = malloc_usable_size( nptr );               // new allocation
    4376                if ( nlen > olen ) {                                                    // larger ?
    44                         for ( i; dim ) { memcpy( &ptr[i], &fill, sizeof(T) ); } // initialize with fill value
    45                 } // if
    46                 return (T *)nptr;
    47         } // alloc_align_set
    48 
    49         T * alloc_align_set( T ptr[], size_t align, char fill ) { // aligned realloc with fill
    50                 size_t olen = malloc_usable_size( ptr );                // current allocation
    51                 void * nptr = (void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc
    52                 // char * nptr = alloc_align( ptr, align );
    53                 size_t nlen = malloc_usable_size( nptr );               // new allocation
    54                 if ( nlen > olen ) {                                                    // larger ?
    55                         memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage
    56                 } // if
    57                 return (T *)nptr;
    58         } // alloc_align_set
    59 
    60         T * alloc_align_set( T ptr[], size_t align, size_t dim, T fill ) { // aligned realloc with fill
    61                 size_t olen = malloc_usable_size( ptr );                // current allocation
    62                 void * nptr = (void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc
    63                 // char * nptr = alloc_align( ptr, align );
    64                 size_t nlen = malloc_usable_size( nptr );               // new allocation
    65                 if ( nlen > olen ) {                                                    // larger ?
    66                         for ( i; dim ) { memcpy( &ptr[i], &fill, sizeof(T) ); } // initialize with fill value
     77                        memset( nptr + olen, (int)fill, nlen - olen ); // initialize added storage
    6778                } // if
    6879                return (T *)nptr;
     
    127138//---------------------------------------
    128139
    129 float _Complex strto( const char sptr[], char ** eptr ) {
     140float _Complex strto( const char * sptr, char ** eptr ) {
    130141        float re, im;
    131142        char * eeptr;
     
    138149} // strto
    139150
    140 double _Complex strto( const char sptr[], char ** eptr ) {
     151double _Complex strto( const char * sptr, char ** eptr ) {
    141152        double re, im;
    142153        char * eeptr;
     
    149160} // strto
    150161
    151 long double _Complex strto( const char sptr[], char ** eptr ) {
     162long double _Complex strto( const char * sptr, char ** eptr ) {
    152163        long double re, im;
    153164        char * eeptr;
  • libcfa/src/stdlib.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr  1 18:38:41 2020
    13 // Update Count     : 429
     12// Last Modified On : Sun Oct 20 22:57:33 2019
     13// Update Count     : 390
    1414//
    1515
     
    2121#include <stdlib.h>                                                                             // *alloc, strto*, ato*
    2222
    23 // Reduce includes by explicitly defining these routines.
    2423extern "C" {
    2524        void * memalign( size_t align, size_t size );           // malloc.h
    26         size_t malloc_usable_size( void * ptr );                        // malloc.h
    27         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap
    2825        void * memset( void * dest, int fill, size_t size ); // string.h
    2926        void * memcpy( void * dest, const void * src, size_t size ); // string.h
    30         void * resize( void * oaddr, size_t size );                     // CFA heap
     27    void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap
    3128} // extern "C"
    32 
    33 void * resize( void * oaddr, size_t nalign, size_t size ); // CFA heap
    34 void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
    3529
    3630//---------------------------------------
     
    4438
    4539static inline forall( dtype T | sized(T) ) {
    46         // Cforall safe equivalents, i.e., implicit size specification
     40        // C dynamic allocation
    4741
    4842        T * malloc( void ) {
     
    5650        } // calloc
    5751
    58         T * realloc( T * ptr, size_t size ) {                           // CFA realloc, eliminate return-type cast
     52        T * realloc( T * ptr, size_t size ) {
     53                if ( unlikely( ptr == 0 ) ) return malloc();
    5954                return (T *)(void *)realloc( (void *)ptr, size ); // C realloc
    6055        } // realloc
     
    6459        } // memalign
    6560
    66         T * cmemalign( size_t align, size_t dim  ) {
    67                 return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign
    68         } // cmemalign
    69 
    7061        T * aligned_alloc( size_t align ) {
    7162                return (T *)aligned_alloc( align, sizeof(T) );  // C aligned_alloc
     
    7566                return posix_memalign( (void **)ptr, align, sizeof(T) ); // C posix_memalign
    7667        } // posix_memalign
    77 } // distribution
    78 
    79 static inline forall( dtype T | sized(T) ) {
    80         // Cforall safe general allocation, fill, resize, array
     68
     69        // Cforall dynamic allocation
    8170
    8271        T * alloc( void ) {
     
    8978        } // alloc
    9079
    91         forall( dtype S | sized(S) )
    92         T * alloc( S ptr[], size_t dim = 1 ) {                          // singleton/array resize
    93                 size_t len = malloc_usable_size( ptr );                 // current bucket size
    94                 if ( sizeof(T) * dim > len ) {                                  // not enough space ?
    95                         T * temp = alloc( dim );                                        // new storage
    96                         free( ptr );                                                            // free old storage
    97                         return temp;
    98                 } else {
    99                         return (T *)ptr;
    100                 } // if
    101         } // alloc
    102 
    103         T * alloc( T ptr[], size_t dim, bool copy = true ) {
    104                 if ( copy ) {                                                                   // realloc
    105                         return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
    106                 } else {
    107                         struct __Unknown {};
    108                         return alloc( (__Unknown *)ptr, dim );          // reuse, cheat making T/S different types
    109                 } // if
     80        T * alloc( T ptr[], size_t dim ) {                                      // realloc
     81                return realloc( ptr, dim * sizeof(T) );
    11082        } // alloc
    11183
     
    135107forall( dtype T | sized(T) ) {
    136108        T * alloc_set( T ptr[], size_t dim, char fill );        // realloc array with fill
    137         T * alloc_set( T ptr[], size_t dim, T fill );           // realloc array with fill
    138109} // distribution
    139110
     
    145116        T * alloc_align( size_t align, size_t dim ) {
    146117                return (T *)memalign( align, dim * sizeof(T) );
    147         } // alloc_align
    148 
    149         T * alloc_align( T ptr[], size_t align ) {                      // aligned realloc array
    150                 return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc
    151         } // alloc_align
    152 
    153         forall( dtype S | sized(S) )
    154         T * alloc_align( S ptr[], size_t align ) {                      // aligned reuse array
    155                 return (T *)(void *)resize( (void *)ptr, align, sizeof(T) ); // CFA realloc
    156         } // alloc_align
    157 
    158         T * alloc_align( T ptr[], size_t align, size_t dim ) { // aligned realloc array
    159                 return (T *)(void *)realloc( (void *)ptr, align, dim * sizeof(T) ); // CFA realloc
    160118        } // alloc_align
    161119
     
    184142
    185143forall( dtype T | sized(T) ) {
    186         T * alloc_align_set( T ptr[], size_t align, char fill ); // aligned realloc with fill
    187         T * alloc_align_set( T ptr[], size_t align, T fill ); // aligned realloc with fill
     144        T * alloc_align( T ptr[], size_t align );                       // realign
     145        T * alloc_align( T ptr[], size_t align, size_t dim ); // aligned realloc array
    188146        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); // aligned realloc array with fill
    189         T * alloc_align_set( T ptr[], size_t align, size_t dim, T fill ); // aligned realloc array with fill
    190 } // distribution
    191 
    192 static inline forall( dtype T | sized(T) ) {
    193         // Cforall safe initialization/copy, i.e., implicit size specification, non-array types
     147} // distribution
     148
     149static inline forall( dtype T | sized(T) ) {
     150        // data, non-array types
    194151        T * memset( T * dest, char fill ) {
    195152                return (T *)memset( dest, fill, sizeof(T) );
     
    202159
    203160static inline forall( dtype T | sized(T) ) {
    204         // Cforall safe initialization/copy, i.e., implicit size specification, array types
     161        // data, array types
    205162        T * amemset( T dest[], char fill, size_t dim ) {
    206163                return (T *)(void *)memset( dest, fill, dim * sizeof(T) ); // C memset
     
    212169} // distribution
    213170
    214 // Cforall allocation/deallocation and constructor/destructor, non-array types
     171// allocation/deallocation and constructor/destructor, non-array types
    215172forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );
    216173forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );
    217174forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } ) void delete( T * ptr, Params rest );
    218175
    219 // Cforall allocation/deallocation and constructor/destructor, array types
     176// allocation/deallocation and constructor/destructor, array types
    220177forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );
    221178forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );
     
    225182
    226183static inline {
    227         int strto( const char sptr[], char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }
    228         unsigned int strto( const char sptr[], char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }
    229         long int strto( const char sptr[], char ** eptr, int base ) { return strtol( sptr, eptr, base ); }
    230         unsigned long int strto( const char sptr[], char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }
    231         long long int strto( const char sptr[], char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }
    232         unsigned long long int strto( const char sptr[], char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }
    233 
    234         float strto( const char sptr[], char ** eptr ) { return strtof( sptr, eptr ); }
    235         double strto( const char sptr[], char ** eptr ) { return strtod( sptr, eptr ); }
    236         long double strto( const char sptr[], char ** eptr ) { return strtold( sptr, eptr ); }
    237 } // distribution
    238 
    239 float _Complex strto( const char sptr[], char ** eptr );
    240 double _Complex strto( const char sptr[], char ** eptr );
    241 long double _Complex strto( const char sptr[], char ** eptr );
     184        int strto( const char * sptr, char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }
     185        unsigned int strto( const char * sptr, char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }
     186        long int strto( const char * sptr, char ** eptr, int base ) { return strtol( sptr, eptr, base ); }
     187        unsigned long int strto( const char * sptr, char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }
     188        long long int strto( const char * sptr, char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }
     189        unsigned long long int strto( const char * sptr, char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }
     190
     191        float strto( const char * sptr, char ** eptr ) { return strtof( sptr, eptr ); }
     192        double strto( const char * sptr, char ** eptr ) { return strtod( sptr, eptr ); }
     193        long double strto( const char * sptr, char ** eptr ) { return strtold( sptr, eptr ); }
     194} // distribution
     195
     196float _Complex strto( const char * sptr, char ** eptr );
     197double _Complex strto( const char * sptr, char ** eptr );
     198long double _Complex strto( const char * sptr, char ** eptr );
    242199
    243200static inline {
    244         int ato( const char sptr[] ) { return (int)strtol( sptr, 0p, 10 ); }
    245         unsigned int ato( const char sptr[] ) { return (unsigned int)strtoul( sptr, 0p, 10 ); }
    246         long int ato( const char sptr[] ) { return strtol( sptr, 0p, 10 ); }
    247         unsigned long int ato( const char sptr[] ) { return strtoul( sptr, 0p, 10 ); }
    248         long long int ato( const char sptr[] ) { return strtoll( sptr, 0p, 10 ); }
    249         unsigned long long int ato( const char sptr[] ) { return strtoull( sptr, 0p, 10 ); }
    250 
    251         float ato( const char sptr[] ) { return strtof( sptr, 0p ); }
    252         double ato( const char sptr[] ) { return strtod( sptr, 0p ); }
    253         long double ato( const char sptr[] ) { return strtold( sptr, 0p ); }
    254 
    255         float _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
    256         double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
    257         long double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); }
     201        int ato( const char * sptr ) { return (int)strtol( sptr, 0, 10 ); }
     202        unsigned int ato( const char * sptr ) { return (unsigned int)strtoul( sptr, 0, 10 ); }
     203        long int ato( const char * sptr ) { return strtol( sptr, 0, 10 ); }
     204        unsigned long int ato( const char * sptr ) { return strtoul( sptr, 0, 10 ); }
     205        long long int ato( const char * sptr ) { return strtoll( sptr, 0, 10 ); }
     206        unsigned long long int ato( const char * sptr ) { return strtoull( sptr, 0, 10 ); }
     207
     208        float ato( const char * sptr ) { return strtof( sptr, 0 ); }
     209        double ato( const char * sptr ) { return strtod( sptr, 0 ); }
     210        long double ato( const char * sptr ) { return strtold( sptr, 0 ); }
     211
     212        float _Complex ato( const char * sptr ) { return strto( sptr, NULL ); }
     213        double _Complex ato( const char * sptr ) { return strto( sptr, NULL ); }
     214        long double _Complex ato( const char * sptr ) { return strto( sptr, NULL ); }
    258215} // distribution
    259216
  • libcfa/src/time.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Mar 27 13:33:14 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 08:24:18 2020
    13 // Update Count     : 70
     12// Last Modified On : Sat Jul 13 08:41:55 2019
     13// Update Count     : 65
    1414//
    1515
     
    3333forall( dtype ostype | ostream( ostype ) ) {
    3434        ostype & ?|?( ostype & os, Duration dur ) with( dur ) {
    35                 (ostype &)(os | tn / TIMEGRAN);                                 // print seconds
    36                 long int ns = (tn < 0 ? -tn : tn) % TIMEGRAN;   // compute nanoseconds
     35                (ostype &)(os | tv / TIMEGRAN);                                 // print seconds
     36                long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;   // compute nanoseconds
    3737                if ( ns != 0 ) {                                                                // some ?
    3838                        char buf[16];
     
    5252
    5353#ifdef __CFA_DEBUG__
    54 static void tabort( int year, int month, int day, int hour, int min, int sec, int64_t nsec ) {
     54static void tabort( int year, int month, int day, int hour, int min, int sec, int nsec ) {
    5555        abort | "Attempt to create Time( year=" | year | "(>=1970), month=" | month | "(1-12), day=" | day | "(1-31), hour=" | hour | "(0-23), min=" | min | "(0-59), sec=" | sec
    56                   | "(0-60), nsec=" | nsec | "(0-999_999_999), which is not in the range 00:00:00 UTC, January 1, 1970 to 03:14:07 UTC, January 19, 2038, where month and day have 1 origin.";
     56                  | "(0-60), nsec=" | nsec | "(0-999_999_999), which exceeds range 00:00:00 UTC, January 1, 1970 to 03:14:07 UTC, January 19, 2038.";
    5757} // tabort
    5858#endif // __CFA_DEBUG__
    5959
    60 void ?{}( Time & time, int year, int month, int day, int hour, int min, int sec, int64_t nsec ) with( time ) {
     60void ?{}( Time & time, int year, int month, int day, int hour, int min, int sec, int nsec ) with( time ) {
    6161        tm tm;
    6262
    63         // Values can be in any range (+/-) but result must be in the epoch.
     63        tm.tm_isdst = -1;                                                                       // let mktime determine if alternate timezone is in effect
    6464        tm.tm_year = year - 1900;                                                       // mktime uses 1900 as its starting point
    65         // Make month in range 1-12 to match with day.
     65#ifdef __CFA_DEBUG__
     66        if ( month < 1 || 12 < month ) {
     67                tabort( year, month, day, hour, min, sec, nsec );
     68        } // if
     69#endif // __CFA_DEBUG__
    6670        tm.tm_mon = month - 1;                                                          // mktime uses range 0-11
     71#ifdef __CFA_DEBUG__
     72        if ( day < 1 || 31 < day ) {
     73                tabort( year, month, day, hour, min, sec, nsec );
     74        } // if
     75#endif // __CFA_DEBUG__
    6776        tm.tm_mday = day;                                                                       // mktime uses range 1-31
    6877        tm.tm_hour = hour;
    6978        tm.tm_min = min;
    7079        tm.tm_sec = sec;
    71         tm.tm_isdst = -1;                                                                       // let mktime determine if alternate timezone is in effect
    7280        time_t epochsec = mktime( &tm );
    7381#ifdef __CFA_DEBUG__
    74         if ( epochsec <= (time_t)-1 ) {                                         // MUST BE LESS THAN OR EQUAL!
     82        if ( epochsec == (time_t)-1 ) {
    7583                tabort( year, month, day, hour, min, sec, nsec );
    7684        } // if
    7785#endif // __CFA_DEBUG__
    78         tn = (int64_t)(epochsec) * TIMEGRAN + nsec;                     // convert to nanoseconds
     86        tv = (int64_t)(epochsec) * TIMEGRAN + nsec;                     // convert to nanoseconds
    7987#ifdef __CFA_DEBUG__
    80         if ( tn > 2147483647LL * TIMEGRAN ) {                           // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
     88        if ( tv > 2147483647LL * TIMEGRAN ) {                           // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
    8189                tabort( year, month, day, hour, min, sec, nsec );
    8290        } // if
     
    8593
    8694char * yy_mm_dd( Time time, char * buf ) with( time ) {
    87         time_t s = tn / TIMEGRAN;
     95        time_t s = tv / TIMEGRAN;
    8896        tm tm;
    8997        gmtime_r( &s, &tm );                                                            // tm_mon <= 11, tm_mday <= 31
     
    100108
    101109char * mm_dd_yy( Time time, char * buf ) with( time ) {
    102         time_t s = tn / TIMEGRAN;
     110        time_t s = tv / TIMEGRAN;
    103111        tm tm;
    104112        gmtime_r( &s, &tm );                                                            // tm_mon <= 11, tm_mday <= 31
     
    115123
    116124char * dd_mm_yy( Time time, char * buf ) with( time ) {
    117         time_t s = tn / TIMEGRAN;
     125        time_t s = tv / TIMEGRAN;
    118126        tm tm;
    119127        gmtime_r( &s, &tm );                                                            // tm_mon <= 11, tm_mday <= 31
     
    129137} // dd_mm_yy
    130138
    131 size_t strftime( char buf[], size_t size, const char fmt[], Time time ) with( time ) {
    132         time_t s = tn / TIMEGRAN;
     139size_t strftime( char * buf, size_t size, const char * fmt, Time time ) with( time ) {
     140        time_t s = tv / TIMEGRAN;
    133141        tm tm;
    134142        gmtime_r( &s, &tm );
     
    139147        ostype & ?|?( ostype & os, Time time ) with( time ) {
    140148                char buf[32];                                                                   // at least 26
    141                 time_t s = tn / TIMEGRAN;
     149                time_t s = tv / TIMEGRAN;
    142150                ctime_r( &s, (char *)&buf );                                    // 26 characters: "Wed Jun 30 21:49:08 1993\n"
    143151                buf[24] = '\0';                                                                 // remove trailing '\n'
    144                 long int ns = (tn < 0 ? -tn : tn) % TIMEGRAN;   // compute nanoseconds
     152                long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;   // compute nanoseconds
    145153                if ( ns == 0 ) {                                                                // none ?
    146154                        (ostype &)(os | buf);                                           // print date/time/year
  • libcfa/src/time.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Mar 14 23:18:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 08:24:32 2020
    13 // Update Count     : 654
     12// Last Modified On : Sat Sep 22 12:25:34 2018
     13// Update Count     : 643
    1414//
    1515
     
    3232        Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
    3333
    34         Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
    35         Duration ?+?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tn + rhs.tn }; }
     34        Duration +?( Duration rhs ) with( rhs ) {       return (Duration)@{ +tv }; }
     35        Duration ?+?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tv + rhs.tv }; }
    3636        Duration ?+=?( Duration & lhs, Duration rhs ) { lhs = lhs + rhs; return lhs; }
    3737
    38         Duration -?( Duration rhs ) with( rhs ) { return (Duration)@{ -tn }; }
    39         Duration ?-?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tn - rhs.tn }; }
     38        Duration -?( Duration rhs ) with( rhs ) { return (Duration)@{ -tv }; }
     39        Duration ?-?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tv - rhs.tv }; }
    4040        Duration ?-=?( Duration & lhs, Duration rhs ) { lhs = lhs - rhs; return lhs; }
    4141
    42         Duration ?*?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tn * rhs }; }
    43         Duration ?*?( int64_t lhs, Duration rhs ) { return (Duration)@{ lhs * rhs.tn }; }
     42        Duration ?*?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv * rhs }; }
     43        Duration ?*?( int64_t lhs, Duration rhs ) { return (Duration)@{ lhs * rhs.tv }; }
    4444        Duration ?*=?( Duration & lhs, int64_t rhs ) { lhs = lhs * rhs; return lhs; }
    4545
    46         int64_t ?/?( Duration lhs, Duration rhs ) { return lhs.tn / rhs.tn; }
    47         Duration ?/?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tn / rhs }; }
     46        int64_t ?/?( Duration lhs, Duration rhs ) { return lhs.tv / rhs.tv; }
     47        Duration ?/?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv / rhs }; }
    4848        Duration ?/=?( Duration & lhs, int64_t rhs ) { lhs = lhs / rhs; return lhs; }
    49         double div( Duration lhs, Duration rhs ) { return (double)lhs.tn / (double)rhs.tn; }
    50 
    51         Duration ?%?( Duration lhs, Duration rhs ) { return (Duration)@{ lhs.tn % rhs.tn }; }
     49        double div( Duration lhs, Duration rhs ) { return (double)lhs.tv / (double)rhs.tv; }
     50
     51        Duration ?%?( Duration lhs, Duration rhs ) { return (Duration)@{ lhs.tv % rhs.tv }; }
    5252        Duration ?%=?( Duration & lhs, Duration rhs ) { lhs = lhs % rhs; return lhs; }
    5353
    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; }
    58         bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn >  rhs.tn; }
    59         bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; }
    60 
    61         bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; }
    62         bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn != 0; }
    63         bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <  0; }
    64         bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <= 0; }
    65         bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >  0; }
    66         bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; }
    67 
    68         Duration abs( Duration rhs ) { return rhs.tn >= 0 ? rhs : -rhs; }
     54        bool ?==?( Duration lhs, Duration rhs ) { return lhs.tv == rhs.tv; }
     55        bool ?!=?( Duration lhs, Duration rhs ) { return lhs.tv != rhs.tv; }
     56        bool ?<? ( Duration lhs, Duration rhs ) { return lhs.tv <  rhs.tv; }
     57        bool ?<=?( Duration lhs, Duration rhs ) { return lhs.tv <= rhs.tv; }
     58        bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tv >  rhs.tv; }
     59        bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tv >= rhs.tv; }
     60
     61        bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv == 0; }
     62        bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv != 0; }
     63        bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv <  0; }
     64        bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv <= 0; }
     65        bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv >  0; }
     66        bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tv >= 0; }
     67
     68        Duration abs( Duration rhs ) { return rhs.tv >= 0 ? rhs : -rhs; }
    6969
    7070        Duration ?`ns( int64_t nsec ) { return (Duration)@{ nsec }; }
     
    8282        Duration ?`w( double weeks ) { return (Duration)@{ weeks * (7LL * 24LL * 60LL * 60LL * TIMEGRAN) }; }
    8383
    84         int64_t ?`ns( Duration dur ) { return dur.tn; }
    85         int64_t ?`us( Duration dur ) { return dur.tn / (TIMEGRAN / 1_000_000LL); }
    86         int64_t ?`ms( Duration dur ) { return dur.tn / (TIMEGRAN / 1_000LL); }
    87         int64_t ?`s( Duration dur ) { return dur.tn / TIMEGRAN; }
    88         int64_t ?`m( Duration dur ) { return dur.tn / (60LL * TIMEGRAN); }
    89         int64_t ?`h( Duration dur ) { return dur.tn / (60LL * 60LL * TIMEGRAN); }
    90         int64_t ?`d( Duration dur ) { return dur.tn / (24LL * 60LL * 60LL * TIMEGRAN); }
    91         int64_t ?`w( Duration dur ) { return dur.tn / (7LL * 24LL * 60LL * 60LL * TIMEGRAN); }
    92 
    93         Duration max( Duration lhs, Duration rhs ) { return  (lhs.tn < rhs.tn) ? rhs : lhs;}
    94         Duration min( Duration lhs, Duration rhs ) { return !(rhs.tn < lhs.tn) ? lhs : rhs;}
     84        int64_t ?`ns( Duration dur ) { return dur.tv; }
     85        int64_t ?`us( Duration dur ) { return dur.tv / (TIMEGRAN / 1_000_000LL); }
     86        int64_t ?`ms( Duration dur ) { return dur.tv / (TIMEGRAN / 1_000LL); }
     87        int64_t ?`s( Duration dur ) { return dur.tv / TIMEGRAN; }
     88        int64_t ?`m( Duration dur ) { return dur.tv / (60LL * TIMEGRAN); }
     89        int64_t ?`h( Duration dur ) { return dur.tv / (60LL * 60LL * TIMEGRAN); }
     90        int64_t ?`d( Duration dur ) { return dur.tv / (24LL * 60LL * 60LL * TIMEGRAN); }
     91        int64_t ?`w( Duration dur ) { return dur.tv / (7LL * 24LL * 60LL * 60LL * TIMEGRAN); }
     92
     93        Duration max( Duration lhs, Duration rhs ) { return  (lhs.tv < rhs.tv) ? rhs : lhs;}
     94        Duration min( Duration lhs, Duration rhs ) { return !(rhs.tv < lhs.tv) ? lhs : rhs;}
    9595} // distribution
    9696
     
    143143//######################### Time #########################
    144144
    145 void ?{}( Time & time, int year, int month = 1, int day = 1, int hour = 0, int min = 0, int sec = 0, int64_t nsec = 0 );
     145void ?{}( Time & time, int year, int month = 0, int day = 0, int hour = 0, int min = 0, int sec = 0, int nsec = 0 );
    146146static inline {
    147147        Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }
    148148
    149         void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
     149        void ?{}( Time & time, timeval t ) with( time ) { tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
    150150        Time ?=?( Time & time, timeval t ) with( time ) {
    151                 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
     151                tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
    152152                return time;
    153153        } // ?=?
    154154
    155         void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
     155        void ?{}( Time & time, timespec t ) with( time ) { tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    156156        Time ?=?( Time & time, timespec t ) with( time ) {
    157                 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
     157                tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
    158158                return time;
    159159        } // ?=?
    160160
    161         Time ?+?( Time & lhs, Duration rhs ) { return (Time)@{ lhs.tn + rhs.tn }; }
     161        Time ?+?( Time & lhs, Duration rhs ) { return (Time)@{ lhs.tv + rhs.tv }; }
    162162        Time ?+?( Duration lhs, Time rhs ) { return rhs + lhs; }
    163163        Time ?+=?( Time & lhs, Duration rhs ) { lhs = lhs + rhs; return lhs; }
    164164
    165         Duration ?-?( Time lhs, Time rhs ) { return (Duration)@{ lhs.tn - rhs.tn }; }
    166         Time ?-?( Time lhs, Duration rhs ) { return (Time)@{ lhs.tn - rhs.tn }; }
     165        Duration ?-?( Time lhs, Time rhs ) { return (Duration)@{ lhs.tv - rhs.tv }; }
     166        Time ?-?( Time lhs, Duration rhs ) { return (Time)@{ lhs.tv - rhs.tv }; }
    167167        Time ?-=?( Time & lhs, Duration rhs ) { lhs = lhs - rhs; return lhs; }
    168         bool ?==?( Time lhs, Time rhs ) { return lhs.tn == rhs.tn; }
    169         bool ?!=?( Time lhs, Time rhs ) { return lhs.tn != rhs.tn; }
    170         bool ?<?( Time lhs, Time rhs ) { return lhs.tn < rhs.tn; }
    171         bool ?<=?( Time lhs, Time rhs ) { return lhs.tn <= rhs.tn; }
    172         bool ?>?( Time lhs, Time rhs ) { return lhs.tn > rhs.tn; }
    173         bool ?>=?( Time lhs, Time rhs ) { return lhs.tn >= rhs.tn; }
    174 
    175         int64_t ?`ns( Time t ) { return t.tn; }
     168        bool ?==?( Time lhs, Time rhs ) { return lhs.tv == rhs.tv; }
     169        bool ?!=?( Time lhs, Time rhs ) { return lhs.tv != rhs.tv; }
     170        bool ?<?( Time lhs, Time rhs ) { return lhs.tv < rhs.tv; }
     171        bool ?<=?( Time lhs, Time rhs ) { return lhs.tv <= rhs.tv; }
     172        bool ?>?( Time lhs, Time rhs ) { return lhs.tv > rhs.tv; }
     173        bool ?>=?( Time lhs, Time rhs ) { return lhs.tv >= rhs.tv; }
    176174} // distribution
    177175
     
    191189} // dmy
    192190
    193 size_t strftime( char buf[], size_t size, const char fmt[], Time time );
     191size_t strftime( char * buf, size_t size, const char * fmt, Time time );
    194192
    195193//------------------------- timeval (cont) -------------------------
    196194
    197195static inline void ?{}( timeval & t, Time time ) with( t, time ) {
    198         tv_sec = tn / TIMEGRAN;                                                         // seconds
    199         tv_usec = tn % TIMEGRAN / (TIMEGRAN / 1_000_000LL);     // microseconds
     196        tv_sec = tv / TIMEGRAN;                                                         // seconds
     197        tv_usec = tv % TIMEGRAN / (TIMEGRAN / 1_000_000LL);     // microseconds
    200198} // ?{}
    201199
     
    203201
    204202static inline void ?{}( timespec & t, Time time ) with( t, time ) {
    205         tv_sec = tn / TIMEGRAN;                                                         // seconds
    206         tv_nsec = tn % TIMEGRAN;                                                        // nanoseconds
     203        tv_sec = tv / TIMEGRAN;                                                         // seconds
     204        tv_nsec = tv % TIMEGRAN;                                                        // nanoseconds
    207205} // ?{}
    208206
  • libcfa/src/time_t.hfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Apr 10 14:42:03 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jan  5 08:22:46 2020
    13 // Update Count     : 7
     12// Last Modified On : Fri Apr 13 07:51:47 2018
     13// Update Count     : 6
    1414//
    1515
     
    2020
    2121struct Duration {                                                                               // private
    22         int64_t tn;                                                                                     // nanoseconds
     22        int64_t tv;                                                                                     // nanoseconds
    2323}; // Duration
    2424
    25 static inline void ?{}( Duration & dur ) with( dur ) { tn = 0; }
    26 static inline void ?{}( Duration & dur, __attribute__((unused)) zero_t ) with( dur ) { tn = 0; }
     25static inline void ?{}( Duration & dur ) with( dur ) { tv = 0; }
     26static inline void ?{}( Duration & dur, __attribute__((unused)) zero_t ) with( dur ) { tv = 0; }
    2727
    2828
     
    3030
    3131struct Time {                                                                                   // private
    32         uint64_t tn;                                                                            // nanoseconds since UNIX epoch
     32        uint64_t tv;                                                                            // nanoseconds since UNIX epoch
    3333}; // Time
    3434
    35 static inline void ?{}( Time & time ) with( time ) { tn = 0; }
    36 static inline void ?{}( Time & time, __attribute__((unused)) zero_t ) with( time ) { tn = 0; }
     35static inline void ?{}( Time & time ) with( time ) { tv = 0; }
     36static inline void ?{}( Time & time, __attribute__((unused)) zero_t ) with( time ) { tv = 0; }
    3737
    3838// Local Variables: //
  • longrun_tests/Makefile.in

    r7030dab r71d6bd8  
    486486LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    487487        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
    488         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
     488        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
     489        $(AM_CFLAGS) $(CFLAGS)
    489490
    490491AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    492493am__v_CFA_0 = @echo "  CFA     " $@;
    493494am__v_CFA_1 =
     495AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     496am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     497am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     498am__v_JAVAC_1 =
     499AM_V_GOC = $(am__v_GOC_@AM_V@)
     500am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     501am__v_GOC_0 = @echo "  GOC     " $@;
     502am__v_GOC_1 =
    494503UPPCC = u++
    495504UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    498507am__v_UPP_0 = @echo "  UPP     " $@;
    499508am__v_UPP_1 =
    500 AM_V_GOC = $(am__v_GOC_@AM_V@)
    501 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    502 am__v_GOC_0 = @echo "  GOC     " $@;
    503 am__v_GOC_1 =
    504 AM_V_PY = $(am__v_PY_@AM_V@)
    505 am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
    506 am__v_PY_0 = @echo "  PYTHON  " $@;
    507 am__v_PY_1 =
    508 AM_V_RUST = $(am__v_RUST_@AM_V@)
    509 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
    510 am__v_RUST_0 = @echo "  RUST    " $@;
    511 am__v_RUST_1 =
    512 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
    513 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
    514 am__v_NODEJS_0 = @echo "  NODEJS  " $@;
    515 am__v_NODEJS_1 =
    516 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    517 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    518 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    519 am__v_JAVAC_1 =
    520509repeats = 10
    521510max_time = 600
  • src/AST/Convert.cpp

    r7030dab r71d6bd8  
    1010// Created On       : Thu May 09 15::37::05 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:39:32 2019
    13 // Update Count     : 33
     12// Last Modified On : Thu Jul 25 22:21:46 2019
     13// Update Count     : 13
    1414//
    1515
     
    245245                auto decl = new StructDecl(
    246246                        node->name,
    247                         (AggregateDecl::Aggregate)node->kind,
     247                        node->kind,
    248248                        get<Attribute>().acceptL( node->attributes ),
    249249                        LinkageSpec::Spec( node->linkage.val )
     
    493493        }
    494494
    495         const ast::Stmt * visit(const ast::SuspendStmt * node ) override final {
    496                 if ( inCache( node ) ) return nullptr;
    497                 auto stmt = new SuspendStmt();
    498                 stmt->then   = get<CompoundStmt>().accept1( node->then   );
    499                 switch(node->type) {
    500                         case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    501                         case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
    502                         case ast::SuspendStmt::Generator: stmt->type = SuspendStmt::Generator; break;
    503                 }
    504                 return stmtPostamble( stmt, node );
    505         }
    506 
    507495        const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    508496                if ( inCache( node ) ) return nullptr;
     
    698686
    699687        const ast::Expr * visit( const ast::KeywordCastExpr * node ) override final {
    700                 AggregateDecl::Aggregate castTarget = (AggregateDecl::Aggregate)node->target;
    701                 assert( AggregateDecl::Generator <= castTarget && castTarget <= AggregateDecl::Thread );
     688                KeywordCastExpr::Target castTarget = KeywordCastExpr::NUMBER_OF_TARGETS;
     689                switch (node->target) {
     690                        case ast::KeywordCastExpr::Coroutine:
     691                                castTarget = KeywordCastExpr::Coroutine;
     692                                break;
     693                        case ast::KeywordCastExpr::Thread:
     694                                castTarget = KeywordCastExpr::Thread;
     695                                break;
     696                        case ast::KeywordCastExpr::Monitor:
     697                                castTarget = KeywordCastExpr::Monitor;
     698                                break;
     699                        default:
     700                                break;
     701                }
     702                assert ( castTarget < KeywordCastExpr::NUMBER_OF_TARGETS );
    702703                auto expr = visitBaseExpr( node,
    703704                        new KeywordCastExpr(
     
    12461247                                cv( node ),
    12471248                                node->name,
    1248                                 node->kind == ast::TypeDecl::Ftype,
     1249                                node->kind == ast::TypeVar::Ftype,
    12491250                                get<Attribute>().acceptL( node->attributes )
    12501251                        };
     
    15141515                        old->location,
    15151516                        old->name,
    1516                         (ast::AggregateDecl::Aggregate)old->kind,
     1517                        old->kind,
    15171518                        GET_ACCEPT_V(attributes, Attribute),
    15181519                        { old->linkage.val }
     
    16011602                        { old->storageClasses.val },
    16021603                        GET_ACCEPT_1(base, Type),
    1603                         (ast::TypeDecl::Kind)(unsigned)old->kind,
     1604                        (ast::TypeVar::Kind)(unsigned)old->kind,
    16041605                        old->sized,
    16051606                        GET_ACCEPT_1(init, Type)
     
    18821883        }
    18831884
    1884         virtual void visit( const SuspendStmt * old ) override final {
    1885                 if ( inCache( old ) ) return;
    1886                 ast::SuspendStmt::Type type;
    1887                 switch (old->type) {
    1888                         case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
    1889                         case SuspendStmt::Generator: type = ast::SuspendStmt::Generator; break;
    1890                         case SuspendStmt::None     : type = ast::SuspendStmt::None     ; break;
    1891                         default: abort();
    1892                 }
    1893                 this->node = new ast::SuspendStmt(
    1894                         old->location,
    1895                         GET_ACCEPT_1(then  , CompoundStmt),
    1896                         type,
    1897                         GET_LABELS_V(old->labels)
    1898                 );
    1899                 cache.emplace( old, this->node );
    1900         }
    1901 
    19021885        virtual void visit( const WaitForStmt * old ) override final {
    19031886                if ( inCache( old ) ) return;
     
    20732056        }
    20742057
    2075         virtual void visit( const KeywordCastExpr * old ) override final {
    2076                 ast::AggregateDecl::Aggregate castTarget = (ast::AggregateDecl::Aggregate)old->target;
    2077                 assert( ast::AggregateDecl::Generator <= castTarget && castTarget <= ast::AggregateDecl::Thread );
     2058        virtual void visit( const KeywordCastExpr * old) override final {
     2059                ast::KeywordCastExpr::Target castTarget = ast::KeywordCastExpr::NUMBER_OF_TARGETS;
     2060                switch (old->target) {
     2061                        case KeywordCastExpr::Coroutine:
     2062                                castTarget = ast::KeywordCastExpr::Coroutine;
     2063                                break;
     2064                        case KeywordCastExpr::Thread:
     2065                                castTarget = ast::KeywordCastExpr::Thread;
     2066                                break;
     2067                        case KeywordCastExpr::Monitor:
     2068                                castTarget = ast::KeywordCastExpr::Monitor;
     2069                                break;
     2070                        default:
     2071                                break;
     2072                }
     2073                assert ( castTarget < ast::KeywordCastExpr::NUMBER_OF_TARGETS );
    20782074                this->node = visitBaseExpr( old,
    20792075                        new ast::KeywordCastExpr(
     
    26032599                        ty = new ast::TypeInstType{
    26042600                                old->name,
    2605                                 old->isFtype ? ast::TypeDecl::Ftype : ast::TypeDecl::Dtype,
     2601                                old->isFtype ? ast::TypeVar::Ftype : ast::TypeVar::Dtype,
    26062602                                cv( old ),
    26072603                                GET_ACCEPT_V( attributes, Attribute )
  • src/AST/Decl.cpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 16:23:15 2019
    13 // Update Count     : 20
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu May 9 10:00:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    1818#include <cassert>             // for assert, strict_dynamic_cast
    1919#include <iostream>
     20#include <string>
    2021#include <unordered_map>
    2122
     
    2627#include "Node.hpp"            // for readonly
    2728#include "Type.hpp"            // for readonly
     29#include "Parser/ParseNode.h"  // for DeclarationNode
    2830
    2931namespace ast {
     
    5658// --- TypeDecl
    5759
    58 const char * TypeDecl::typeString() const {
    59         static const char * kindNames[] = { "sized data type", "sized object type", "sized function type", "sized tuple type" };
    60         static_assert( sizeof(kindNames)/sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." );
    61         assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
    62         return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
     60std::string TypeDecl::typeString() const {
     61        static const std::string kindNames[] = { "object type", "function type", "tuple type" };
     62        assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1,
     63                "typeString: kindNames is out of sync." );
     64        assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
     65        return (sized ? "sized " : "") + kindNames[ kind ];
    6366}
    6467
    65 const char * TypeDecl::genTypeString() const {
    66         static const char * kindNames[] = { "dtype", "otype", "ftype", "ttype" };
    67         static_assert( sizeof(kindNames)/sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "genTypeString: kindNames is out of sync." );
    68         assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
     68std::string TypeDecl::genTypeString() const {
     69        static const std::string kindNames[] = { "dtype", "ftype", "ttype" };
     70        assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1, "genTypeString: kindNames is out of sync." );
     71        assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
    6972        return kindNames[ kind ];
    7073}
     
    7275std::ostream & operator<< ( std::ostream & out, const TypeDecl::Data & data ) {
    7376        return out << data.kind << ", " << data.isComplete;
    74 }
    75 
    76 // --- AggregateDecl
    77 
    78 // These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
    79 static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
    80 
    81 const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
    82         return aggregateNames[aggr];
    8377}
    8478
  • src/AST/Decl.hpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 17:38:33 2019
    13 // Update Count     : 29
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu May 9 10:00:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    2020#include <unordered_map>
    2121#include <vector>
    22 #include <algorithm>
    2322
    2423#include "FunctionSpec.hpp"
     
    2827#include "ParseNode.hpp"
    2928#include "StorageClasses.hpp"
     29#include "TypeVar.hpp"
    3030#include "Visitor.hpp"
    31 #include "Common/utility.h"
    32 #include "Common/SemanticError.h"                                               // error_str
     31#include "Parser/ParseNode.h"  // for DeclarationNode::Aggregate
    3332
    3433// Must be included in *all* AST classes; should be #undef'd at the end of the file
     
    128127        std::vector< ptr<Expr> > withExprs;
    129128
    130         FunctionDecl( const CodeLocation & loc, const std::string & name, FunctionType * type,
     129        FunctionDecl( const CodeLocation & loc, const std::string &name, FunctionType * type,
    131130                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    132131                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
     
    139138        bool has_body() const { return stmts; }
    140139
    141         const DeclWithType * accept( Visitor & v ) const override { return v.visit( this ); }
     140        const DeclWithType * accept( Visitor &v ) const override { return v.visit( this ); }
    142141private:
    143142        FunctionDecl * clone() const override { return new FunctionDecl( *this ); }
     
    152151        std::vector<ptr<DeclWithType>> assertions;
    153152
    154         NamedTypeDecl(
     153        NamedTypeDecl( 
    155154                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    156155                const Type * b, Linkage::Spec spec = Linkage::Cforall )
     
    158157
    159158        /// Produces a name for the kind of alias
    160         virtual const char * typeString() const = 0;
     159        virtual std::string typeString() const = 0;
    161160
    162161private:
     
    167166/// Cforall type variable: `dtype T`
    168167class TypeDecl final : public NamedTypeDecl {
    169   public:
    170         enum Kind { Dtype, Otype, Ftype, Ttype, NUMBER_OF_KINDS };
    171 
    172         Kind kind;
     168public:
     169        TypeVar::Kind kind;
    173170        bool sized;
    174171        ptr<Type> init;
     
    176173        /// Data extracted from a type decl
    177174        struct Data {
    178                 Kind kind;
     175                TypeVar::Kind kind;
    179176                bool isComplete;
    180177
    181                 Data() : kind( NUMBER_OF_KINDS ), isComplete( false ) {}
     178                Data() : kind( (TypeVar::Kind)-1 ), isComplete( false ) {}
    182179                Data( const TypeDecl * d ) : kind( d->kind ), isComplete( d->sized ) {}
    183                 Data( Kind k, bool c ) : kind( k ), isComplete( c ) {}
     180                Data( TypeVar::Kind k, bool c ) : kind( k ), isComplete( c ) {}
    184181                Data( const Data & d1, const Data & d2 )
    185                         : kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
    186 
    187                 bool operator==( const Data & o ) const { return kind == o.kind && isComplete == o.isComplete; }
    188                 bool operator!=( const Data & o ) const { return !(*this == o); }
     182                : kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
     183
     184                bool operator== ( const Data & o ) const {
     185                        return kind == o.kind && isComplete == o.isComplete;
     186                }
     187                bool operator!= ( const Data & o ) const { return !(*this == o); }
    189188        };
    190189
    191         TypeDecl(
    192                 const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     190        TypeDecl( 
     191                const CodeLocation & loc, const std::string & name, Storage::Classes storage, 
    193192                const Type * b, TypeVar::Kind k, bool s, const Type * i = nullptr )
    194193        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ),
    195194          init( i ) {}
    196195
    197         const char * typeString() const override;
     196        std::string typeString() const override;
    198197        /// Produces a name for generated code
    199         const char * genTypeString() const;
     198        std::string genTypeString() const;
    200199
    201200        /// convenience accessor to match Type::isComplete()
     
    203202
    204203        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    205   private:
     204private:
    206205        TypeDecl * clone() const override { return new TypeDecl{ *this }; }
    207206        MUTATE_FRIEND
     
    217216        : NamedTypeDecl( loc, name, storage, b, spec ) {}
    218217
    219         const char * typeString() const override { return "typedef"; }
     218        std::string typeString() const override { return "typedef"; }
    220219
    221220        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    228227class AggregateDecl : public Decl {
    229228public:
    230         enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
    231         static const char * aggrString( Aggregate aggr );
    232 
    233229        std::vector<ptr<Decl>> members;
    234230        std::vector<ptr<TypeDecl>> params;
     
    245241
    246242        /// Produces a name for the kind of aggregate
    247         virtual const char * typeString() const = 0;
     243        virtual std::string typeString() const = 0;
    248244
    249245private:
     
    255251class StructDecl final : public AggregateDecl {
    256252public:
    257         Aggregate kind;
     253        DeclarationNode::Aggregate kind;
    258254
    259255        StructDecl( const CodeLocation& loc, const std::string& name,
    260                 Aggregate kind = Struct,
     256                DeclarationNode::Aggregate kind = DeclarationNode::Struct,
    261257                std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
    262258        : AggregateDecl( loc, name, std::move(attrs), linkage ), kind( kind ) {}
    263259
    264         bool is_coroutine() { return kind == Coroutine; }
    265         bool is_generator() { return kind == Generator; }
    266         bool is_monitor  () { return kind == Monitor  ; }
    267         bool is_thread   () { return kind == Thread   ; }
    268 
    269         const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    270 
    271         const char * typeString() const override { return aggrString( kind ); }
     260        bool is_coroutine() { return kind == DeclarationNode::Coroutine; }
     261        bool is_monitor() { return kind == DeclarationNode::Monitor; }
     262        bool is_thread() { return kind == DeclarationNode::Thread; }
     263
     264        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
     265
     266        std::string typeString() const override { return "struct"; }
    272267
    273268private:
     
    285280        const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
    286281
    287         const char * typeString() const override { return aggrString( Union ); }
     282        std::string typeString() const override { return "union"; }
    288283
    289284private:
     
    304299        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    305300
    306         const char * typeString() const override { return aggrString( Enum ); }
     301        std::string typeString() const override { return "enum"; }
    307302
    308303private:
     
    323318        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    324319
    325         const char * typeString() const override { return "trait"; }
     320        std::string typeString() const override { return "trait"; }
    326321
    327322private:
     
    349344        ptr<AsmStmt> stmt;
    350345
    351         AsmDecl( const CodeLocation & loc, AsmStmt * stmt )
     346        AsmDecl( const CodeLocation & loc, AsmStmt *stmt )
    352347        : Decl( loc, "", {}, {} ), stmt(stmt) {}
    353348
    354         const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); }
    355 private:
    356         AsmDecl * clone() const override { return new AsmDecl( *this ); }
     349        const AsmDecl * accept( Visitor &v ) const override { return v.visit( this ); }
     350private:
     351        AsmDecl *clone() const override { return new AsmDecl( *this ); }
    357352        MUTATE_FRIEND
    358353};
     
    366361        : Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {}
    367362
    368         const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     363        const StaticAssertDecl * accept( Visitor &v ) const override { return v.visit( this ); }
    369364private:
    370365        StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); }
  • src/AST/Expr.cpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May 15 17:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Created On       : Thr Jun 13 13:38:00 2019
    13 // Update Count     : 6
     11// Last Modified By : Andrew Beach
     12// Created On       : Fri Oct  4 15:34:00 2019
     13// Update Count     : 4
    1414//
    1515
     
    163163// --- KeywordCastExpr
    164164
    165 const char * KeywordCastExpr::targetString() const {
    166         return AggregateDecl::aggrString( target );
     165const std::string & KeywordCastExpr::targetString() const {
     166        static const std::string targetStrs[] = {
     167                "coroutine", "thread", "monitor"
     168        };
     169        static_assert(
     170                (sizeof(targetStrs) / sizeof(targetStrs[0])) == ((unsigned long)NUMBER_OF_TARGETS),
     171                "Each KeywordCastExpr::Target should have a corresponding string representation"
     172        );
     173        return targetStrs[(unsigned long)target];
    167174}
    168175
  • src/AST/Expr.hpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Fri May 10 10:30:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Created On       : Fri May 10 10:30:00 2019
    13 // Update Count     : 7
     11// Last Modified By : Andrew Beach
     12// Created On       : Thr Sep 26 12:51:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    2626#include "Fwd.hpp"        // for UniqueId
    2727#include "Label.hpp"
    28 #include "Decl.hpp"
    2928#include "ParseNode.hpp"
    3029#include "Visitor.hpp"
     
    311310public:
    312311        ptr<Expr> arg;
    313         ast::AggregateDecl::Aggregate target;
    314 
    315         KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t )
     312        enum Target { Coroutine, Thread, Monitor, NUMBER_OF_TARGETS } target;
     313
     314        KeywordCastExpr( const CodeLocation & loc, const Expr * a, Target t )
    316315        : Expr( loc ), arg( a ), target( t ) {}
    317316
    318317        /// Get a name for the target type
    319         const char * targetString() const;
     318        const std::string& targetString() const;
    320319
    321320        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    r7030dab r71d6bd8  
    5353class CatchStmt;
    5454class FinallyStmt;
    55 class SuspendStmt;
    5655class WaitForStmt;
    5756class WithStmt;
  • src/AST/Pass.hpp

    r7030dab r71d6bd8  
    114114        const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
    115115        const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
    116         const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
    117116        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    118117        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    r7030dab r71d6bd8  
    838838
    839839//--------------------------------------------------------------------------
    840 // FinallyStmt
    841 template< typename pass_t >
    842 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {
    843         VISIT_START( node );
    844 
    845         VISIT(
    846                 maybe_accept( node, &SuspendStmt::then   );
    847         )
    848 
    849         VISIT_END( Stmt, node );
    850 }
    851 
    852 //--------------------------------------------------------------------------
    853840// WaitForStmt
    854841template< typename pass_t >
  • src/AST/Print.cpp

    r7030dab r71d6bd8  
    674674                safe_print( node->body );
    675675                --indent;
    676 
    677                 return node;
    678         }
    679 
    680         virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    681                 os << "Suspend Statement";
    682                 switch (node->type) {
    683                         case ast::SuspendStmt::None     : os << " with implicit target"; break;
    684                         case ast::SuspendStmt::Generator: os << " for generator"; break;
    685                         case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
    686                 }
    687                 os << endl;
    688 
    689                 ++indent;
    690                 if(node->then) {
    691                         os << indent << " with post statement :" << endl;
    692                         safe_print( node->then );
    693                 }
    694                 ++indent;
    695676
    696677                return node;
     
    13781359                preprint( node );
    13791360                os << "instance of type " << node->name
    1380                    << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
     1361                   << " (" << (node->kind == ast::TypeVar::Ftype ? "" : "not ") << "function type)";
    13811362                print( node->params );
    13821363
  • src/AST/Stmt.hpp

    r7030dab r71d6bd8  
    344344};
    345345
    346 /// Suspend statement
    347 class SuspendStmt final : public Stmt {
    348 public:
    349         ptr<CompoundStmt> then;
    350         enum Type { None, Coroutine, Generator } type = None;
    351 
    352         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} )
    353         : Stmt(loc, std::move(labels)), then(then), type(type) {}
    354 
    355         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    356 private:
    357         SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }
    358         MUTATE_FRIEND
    359 };
    360 
    361346/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
    362347class WaitForStmt final : public Stmt {
  • src/AST/Type.cpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 15 16:56:28 2019
    13 // Update Count     : 4
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon May 13 15:00:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    5050// --- BasicType
    5151
    52 // GENERATED START, DO NOT EDIT
    53 // GENERATED BY BasicTypes-gen.cc
    54 const char * BasicType::typeNames[] = {
     52const char *BasicType::typeNames[] = {
    5553        "_Bool",
    5654        "char",
     
    9088        "_Float128x _Complex",
    9189};
    92 // GENERATED END
     90static_assert(
     91        sizeof(BasicType::typeNames)/sizeof(BasicType::typeNames[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
     92        "Each basic type name should have a corresponding kind enum value"
     93);
    9394
    9495// --- ParameterizedType
  • src/AST/Type.hpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:56:46 2019
    13 // Update Count     : 5
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu May 9 10:00:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    2626#include "Fwd.hpp"
    2727#include "Node.hpp"          // for Node, ptr, ptr_base
     28#include "TypeVar.hpp"
    2829#include "Visitor.hpp"
    2930
     
    447448public:
    448449        readonly<TypeDecl> base;
    449         TypeDecl::Kind kind;
     450        TypeVar::Kind kind;
    450451
    451452        TypeInstType(
     
    453454                std::vector<ptr<Attribute>> && as = {} )
    454455        : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
    455         TypeInstType( const std::string& n, TypeDecl::Kind k, CV::Qualifiers q = {},
     456
     457        TypeInstType(
     458                const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {},
    456459                std::vector<ptr<Attribute>> && as = {} )
    457460        : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
  • src/AST/TypeEnvironment.cpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May 29 11:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:49:13 2019
    13 // Update Count     : 4
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed May 29 11:00:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    240240                return true;
    241241        } else if ( auto typeInst = dynamic_cast< const TypeInstType * >( type ) ) {
    242                 return typeInst->kind == TypeDecl::Ftype;
     242                return typeInst->kind == TypeVar::Ftype;
    243243        } else return false;
    244244}
     
    248248        bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) {
    249249                switch ( data.kind ) {
    250                   case TypeDecl::Dtype:
     250                  case TypeVar::Dtype:
    251251                        // to bind to an object type variable, the type must not be a function type.
    252252                        // if the type variable is specified to be a complete type then the incoming
     
    254254                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
    255255                        return ! isFtype( type ) && ( ! data.isComplete || type->isComplete() );
    256                   case TypeDecl::Ftype:
     256                  case TypeVar::Ftype:
    257257                        return isFtype( type );
    258                   case TypeDecl::Ttype:
     258                  case TypeVar::Ttype:
    259259                        // ttype unifies with any tuple type
    260260                        return dynamic_cast< const TupleType * >( type ) || Tuples::isTtype( type );
  • src/AST/TypeEnvironment.hpp

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May 29 11:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:55:54 2019
    13 // Update Count     : 3
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed May 29 11:00:00 2019
     13// Update Count     : 1
    1414//
    1515
     
    2828#include "Type.hpp"
    2929#include "TypeSubstitution.hpp"
     30#include "TypeVar.hpp"
    3031#include "Common/Indenter.h"
    3132#include "ResolvExpr/WidenMode.h"
     
    106107        /// Singleton class constructor from substitution
    107108        EqvClass( const std::string & v, const Type * b )
    108         : vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {}
     109        : vars{ v }, bound( b ), allowWidening( false ), data( TypeVar::Dtype, false ) {}
    109110
    110111        /// Single-var constructor (strips qualifiers from bound type)
  • src/AST/Visitor.hpp

    r7030dab r71d6bd8  
    4747    virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) = 0;
    4848    virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) = 0;
    49     virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
    5049    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5150    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
  • src/AST/module.mk

    r7030dab r71d6bd8  
    1010## Author           : Thierry Delisle
    1111## Created On       : Thu May 09 16:05:36 2019
    12 ## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Dec 14 07:29:10 2019
    14 ## Update Count     : 3
     12## Last Modified By :
     13## Last Modified On :
     14## Update Count     :
    1515###############################################################################
    1616
     
    3535        AST/TypeSubstitution.cpp
    3636
     37
     38
    3739SRC += $(SRC_AST)
    3840SRCDEMANGLE += $(SRC_AST)
  • src/BasicTypes-gen.cc

    r7030dab r71d6bd8  
    273273
    274274
    275         #define TypeH TOP_SRCDIR "src/SynTree/Type.h"
    276         resetInput( file, TypeH, buffer, code, str );
    277 
    278         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH );
     275        #define Type TOP_SRCDIR "src/SynTree/Type.h"
     276        resetInput( file, Type, buffer, code, str );
     277
     278        if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", Type );
    279279        start += sizeof( STARTMK );                                                     // includes newline
    280280        code << str.substr( 0, start );
     
    289289        code << "\t";                                                                           // indentation for end marker
    290290
    291         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );
     291        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", Type );
    292292        code << str.substr( start );
    293293
    294         output( file, TypeH, code );
     294        output( file, Type, code );
    295295        // cout << code.str();
    296296
    297297
    298         #define TypeC TOP_SRCDIR "src/SynTree/Type.cc"
    299         resetInput( file, TypeC, buffer, code, str );
    300 
    301         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC );
    302         start += sizeof( STARTMK );                                                     // includes newline
    303         code << str.substr( 0, start );
    304 
    305         code << BYMK << endl;
    306         code << "const char * BasicType::typeNames[] = {" << endl;
    307         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    308                 code << "\t\"" << graph[r].type << "\"," << endl;
    309         } // for       
    310         code << "};" << endl;
    311 
    312         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC );
    313         code << str.substr( start );
    314 
    315         output( file, TypeC, code );
    316         // cout << code.str();
    317 
    318 
    319298        // TEMPORARY DURING CHANGE OVER
    320         #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp"
    321         resetInput( file, TypeH_AST, buffer, code, str );
    322 
    323         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST );
     299        #define TypeAST TOP_SRCDIR "src/AST/Type.hpp"
     300        resetInput( file, TypeAST, buffer, code, str );
     301
     302        if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeAST );
    324303        start += sizeof( STARTMK );                                                     // includes newline
    325304        code << str.substr( 0, start );
     
    334313        code << "\t";                                                                           // indentation for end marker
    335314
    336         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
     315        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeAST );
    337316        code << str.substr( start );
    338317
    339         output( file, TypeH_AST, code );
    340         // cout << code.str();
    341 
    342 
    343         #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp"
    344         resetInput( file, TypeC_AST, buffer, code, str );
    345 
    346         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST );
    347         start += sizeof( STARTMK );                                                     // includes newline
    348         code << str.substr( 0, start );
    349 
    350         code << BYMK << endl;
    351         code << "const char * BasicType::typeNames[] = {" << endl;
    352         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    353                 code << "\t\"" << graph[r].type << "\"," << endl;
    354         } // for       
    355         code << "};" << endl;
    356 
    357         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC_AST );
    358         code << str.substr( start );
    359 
    360         output( file, TypeC_AST, code );
     318        output( file, TypeAST, code );
    361319        // cout << code.str();
    362320
  • src/CodeGen/CodeGenerator.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:32:48 2020
    13 // Update Count     : 532
     12// Last Modified On : Sat Oct 19 19:30:38 2019
     13// Update Count     : 506
    1414//
    1515#include "CodeGenerator.h"
     
    2323#include "InitTweak/InitTweak.h"     // for getPointerBase
    2424#include "OperatorTable.h"           // for OperatorInfo, operatorLookup
    25 #include "SynTree/LinkageSpec.h"     // for Spec, Intrinsic
     25#include "Parser/LinkageSpec.h"      // for Spec, Intrinsic
    2626#include "SynTree/Attribute.h"       // for Attribute
    2727#include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
     
    3939        int CodeGenerator::tabsize = 4;
    4040
    41         // The kinds of statements that would ideally be followed by whitespace.
     41        // the kinds of statements that would ideally be followed by whitespace
    4242        bool wantSpacing( Statement * stmt) {
    4343                return dynamic_cast< IfStmt * >( stmt ) || dynamic_cast< CompoundStmt * >( stmt ) ||
     
    7878        }
    7979
    80         // Using updateLocation at the beginning of a node and endl within a node should become the method of formating.
     80        /* Using updateLocation at the beginning of a node and endl
     81         * within a node should become the method of formating.
     82         */
    8183        void CodeGenerator::updateLocation( CodeLocation const & to ) {
    8284                // skip if linemarks shouldn't appear or if codelocation is unset
     
    9395                } else {
    9496                        output << "\n# " << to.first_line << " \"" << to.filename
    95                                    << "\"\n" << indent;
     97                               << "\"\n" << indent;
    9698                        currentLocation = to;
    9799                }
     
    129131
    130132        void CodeGenerator::genAttributes( list< Attribute * > & attributes ) {
    131                 if ( attributes.empty() ) return;
     133          if ( attributes.empty() ) return;
    132134                output << "__attribute__ ((";
    133135                for ( list< Attribute * >::iterator attr( attributes.begin() );; ) {
     
    138140                                output << ")";
    139141                        } // if
    140                         if ( ++attr == attributes.end() ) break;
     142                  if ( ++attr == attributes.end() ) break;
    141143                        output << ",";                                                          // separator
    142144                } // for
     
    163165                previsit( (BaseSyntaxNode *)node );
    164166                GuardAction( [this, node](){
    165                                 if ( options.printExprTypes && node->result ) {
    166                                         output << " /* " << genType( node->result, "", options ) << " */ ";
    167                                 }
    168                         } );
     167                        if ( options.printExprTypes && node->result ) {
     168                                output << " /* " << genType( node->result, "", options ) << " */ ";
     169                        }
     170                } );
    169171        }
    170172
     
    397399                extension( applicationExpr );
    398400                if ( VariableExpr * varExpr = dynamic_cast< VariableExpr* >( applicationExpr->get_function() ) ) {
    399                         const OperatorInfo * opInfo;
    400                         if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && ( opInfo = operatorLookup( varExpr->get_var()->get_name() ) ) ) {
     401                        OperatorInfo opInfo;
     402                        if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( varExpr->get_var()->get_name(), opInfo ) ) {
    401403                                std::list< Expression* >::iterator arg = applicationExpr->get_args().begin();
    402                                 switch ( opInfo->type ) {
     404                                switch ( opInfo.type ) {
    403405                                  case OT_INDEX:
    404406                                        assert( applicationExpr->get_args().size() == 2 );
     
    421423                                                output << "(";
    422424                                                (*arg++)->accept( *visitor );
    423                                                 output << ") /* " << opInfo->inputName << " */";
     425                                                output << ") /* " << opInfo.inputName << " */";
    424426                                        } else if ( applicationExpr->get_args().size() == 2 ) {
    425427                                                // intrinsic two parameter constructors are essentially bitwise assignment
    426428                                                output << "(";
    427429                                                (*arg++)->accept( *visitor );
    428                                                 output << opInfo->symbol;
     430                                                output << opInfo.symbol;
    429431                                                (*arg)->accept( *visitor );
    430                                                 output << ") /* " << opInfo->inputName << " */";
     432                                                output << ") /* " << opInfo.inputName << " */";
    431433                                        } else {
    432434                                                // no constructors with 0 or more than 2 parameters
     
    439441                                        assert( applicationExpr->get_args().size() == 1 );
    440442                                        output << "(";
    441                                         output << opInfo->symbol;
     443                                        output << opInfo.symbol;
    442444                                        (*arg)->accept( *visitor );
    443445                                        output << ")";
     
    448450                                        assert( applicationExpr->get_args().size() == 1 );
    449451                                        (*arg)->accept( *visitor );
    450                                         output << opInfo->symbol;
     452                                        output << opInfo.symbol;
    451453                                        break;
    452454
     
    457459                                        output << "(";
    458460                                        (*arg++)->accept( *visitor );
    459                                         output << opInfo->symbol;
     461                                        output << opInfo.symbol;
    460462                                        (*arg)->accept( *visitor );
    461463                                        output << ")";
     
    484486                extension( untypedExpr );
    485487                if ( NameExpr * nameExpr = dynamic_cast< NameExpr* >( untypedExpr->function ) ) {
    486                         const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
    487                         if ( opInfo ) {
     488                        OperatorInfo opInfo;
     489                        if ( operatorLookup( nameExpr->name, opInfo ) ) {
    488490                                std::list< Expression* >::iterator arg = untypedExpr->args.begin();
    489                                 switch ( opInfo->type ) {
     491                                switch ( opInfo.type ) {
    490492                                  case OT_INDEX:
    491493                                        assert( untypedExpr->args.size() == 2 );
     
    506508                                                output << "(";
    507509                                                (*arg++)->accept( *visitor );
    508                                                 output << ") /* " << opInfo->inputName << " */";
     510                                                output << ") /* " << opInfo.inputName << " */";
    509511                                        } else if ( untypedExpr->get_args().size() == 2 ) {
    510512                                                // intrinsic two parameter constructors are essentially bitwise assignment
    511513                                                output << "(";
    512514                                                (*arg++)->accept( *visitor );
    513                                                 output << opInfo->symbol;
     515                                                output << opInfo.symbol;
    514516                                                (*arg)->accept( *visitor );
    515                                                 output << ") /* " << opInfo->inputName << " */";
     517                                                output << ") /* " << opInfo.inputName << " */";
    516518                                        } else {
    517519                                                // no constructors with 0 or more than 2 parameters
     
    519521                                                output << "(";
    520522                                                (*arg++)->accept( *visitor );
    521                                                 output << opInfo->symbol << "{ ";
     523                                                output << opInfo.symbol << "{ ";
    522524                                                genCommaList( arg, untypedExpr->args.end() );
    523                                                 output << "}) /* " << opInfo->inputName << " */";
     525                                                output << "}) /* " << opInfo.inputName << " */";
    524526                                        } // if
    525527                                        break;
     
    530532                                        assert( untypedExpr->args.size() == 1 );
    531533                                        output << "(";
    532                                         output << opInfo->symbol;
     534                                        output << opInfo.symbol;
    533535                                        (*arg)->accept( *visitor );
    534536                                        output << ")";
     
    539541                                        assert( untypedExpr->args.size() == 1 );
    540542                                        (*arg)->accept( *visitor );
    541                                         output << opInfo->symbol;
     543                                        output << opInfo.symbol;
    542544                                        break;
    543545
     
    547549                                        output << "(";
    548550                                        (*arg++)->accept( *visitor );
    549                                         output << opInfo->symbol;
     551                                        output << opInfo.symbol;
    550552                                        (*arg)->accept( *visitor );
    551553                                        output << ")";
     
    579581        void CodeGenerator::postvisit( NameExpr * nameExpr ) {
    580582                extension( nameExpr );
    581                 const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
    582                 if ( opInfo ) {
    583                         if ( opInfo->type == OT_CONSTANT ) {
    584                                 output << opInfo->symbol;
     583                OperatorInfo opInfo;
     584                if ( operatorLookup( nameExpr->name, opInfo ) ) {
     585                        if ( opInfo.type == OT_CONSTANT ) {
     586                                output << opInfo.symbol;
    585587                        } else {
    586                                 output << opInfo->outputName;
     588                                output << opInfo.outputName;
    587589                        }
    588590                } else {
     
    652654        void CodeGenerator::postvisit( VariableExpr * variableExpr ) {
    653655                extension( variableExpr );
    654                 const OperatorInfo * opInfo;
    655                 if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && (opInfo = operatorLookup( variableExpr->get_var()->get_name() )) && opInfo->type == OT_CONSTANT ) {
    656                         output << opInfo->symbol;
     656                OperatorInfo opInfo;
     657                if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( variableExpr->get_var()->get_name(), opInfo ) && opInfo.type == OT_CONSTANT ) {
     658                        output << opInfo.symbol;
    657659                } else {
    658660                        output << mangleName( variableExpr->get_var() );
     
    10091011                  case BranchStmt::FallThroughDefault:
    10101012                        assertf( ! options.genC, "fallthru should not reach code generation." );
    1011                         output << "fallthru";
     1013                  output << "fallthru";
    10121014                        break;
    10131015                } // switch
     
    10331035
    10341036                output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
    1035                                    "throw" : "throwResume");
     1037                           "throw" : "throwResume");
    10361038                if (throwStmt->get_expr()) {
    10371039                        output << " ";
     
    10481050
    10491051                output << ((stmt->get_kind() == CatchStmt::Terminate) ?
    1050                                    "catch" : "catchResume");
     1052                "catch" : "catchResume");
    10511053                output << "( ";
    10521054                stmt->decl->accept( *visitor );
     
    11851187
    11861188        std::string genName( DeclarationWithType * decl ) {
    1187                 const OperatorInfo * opInfo = operatorLookup( decl->get_name() );
    1188                 if ( opInfo ) {
    1189                         return opInfo->outputName;
     1189                CodeGen::OperatorInfo opInfo;
     1190                if ( operatorLookup( decl->get_name(), opInfo ) ) {
     1191                        return opInfo.outputName;
    11901192                } else {
    11911193                        return decl->get_name();
  • src/CodeGen/CodeGenerator.h

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:58:31 2020
    13 // Update Count     : 62
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr 30 12:01:00 2019
     13// Update Count     : 57
    1414//
    1515
     
    2929namespace CodeGen {
    3030        struct CodeGenerator : public WithShortCircuiting, public WithGuards, public WithVisitorRef<CodeGenerator> {
    31                 static int tabsize;
     31          static int tabsize;
    3232
    3333                CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false );
     
    104104                void postvisit( AsmStmt * );
    105105                void postvisit( DirectiveStmt * );
    106                 void postvisit( AsmDecl * );                                    // special: statement in declaration context
     106                void postvisit( AsmDecl * );                            // special: statement in declaration context
    107107                void postvisit( IfStmt * );
    108108                void postvisit( SwitchStmt * );
     
    147147                LabelPrinter printLabels;
    148148                Options options;
    149           public:
     149        public:
    150150                LineEnder endl;
    151           private:
     151        private:
    152152
    153153                CodeLocation currentLocation;
     
    162162        template< class Iterator >
    163163        void CodeGenerator::genCommaList( Iterator begin, Iterator end ) {
    164                 if ( begin == end ) return;
     164          if ( begin == end ) return;
    165165                for ( ;; ) {
    166166                        (*begin++)->accept( *visitor );
    167                         if ( begin == end ) break;
     167                  if ( begin == end ) break;
    168168                        output << ", ";                                                         // separator
    169169                } // for
  • src/CodeGen/FixMain.h

    r7030dab r71d6bd8  
    1010// Created On       : Thr Jan 12 14:11:09 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:24:32 2020
    13 // Update Count     : 5
     12// Last Modified On : Fri Jul 21 22:16:59 2017
     13// Update Count     : 1
    1414//
    1515
     
    1919#include <memory>
    2020
    21 #include "SynTree/LinkageSpec.h"
     21#include "Parser/LinkageSpec.h"
    2222
    2323class FunctionDecl;
     
    4242                static std::unique_ptr<FunctionDecl> main_signature;
    4343        };
    44 } // namespace CodeGen
     44};
  • src/CodeGen/FixNames.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:39:14 2019
    13 // Update Count     : 21
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jun 28 15:26:00 2017
     13// Update Count     : 20
    1414//
    1515
     
    2222#include "Common/SemanticError.h"  // for SemanticError
    2323#include "FixMain.h"               // for FixMain
     24#include "Parser/LinkageSpec.h"    // for Cforall, isMangled
    2425#include "SymTab/Mangler.h"        // for Mangler
    25 #include "SynTree/LinkageSpec.h"   // for Cforall, isMangled
    2626#include "SynTree/Constant.h"      // for Constant
    2727#include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declarat...
  • src/CodeGen/GenType.h

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 04:11:40 2020
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr 30 11:47:00 2019
     13// Update Count     : 3
    1414//
    1515
     
    2525        std::string genType( Type *type, const std::string &baseString, const Options &options );
    2626        std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
    27         std::string genPrettyType( Type * type, const std::string & baseString );
     27  std::string genPrettyType( Type * type, const std::string & baseString );
    2828} // namespace CodeGen
    2929
  • src/CodeGen/Generate.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:01:51 2020
    13 // Update Count     : 9
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Aug 18 15:39:00 2017
     13// Update Count     : 7
    1414//
    1515#include "Generate.h"
     
    2222#include "GenType.h"                 // for genPrettyType
    2323#include "Common/PassVisitor.h"      // for PassVisitor
    24 #include "SynTree/LinkageSpec.h"     // for isBuiltin, isGeneratable
     24#include "Parser/LinkageSpec.h"      // for isBuiltin, isGeneratable
    2525#include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
    2626#include "SynTree/Declaration.h"     // for Declaration
     
    6464        void generate( BaseSyntaxNode * node, std::ostream & os ) {
    6565                if ( Type * type = dynamic_cast< Type * >( node ) ) {
    66                         os << genPrettyType( type, "" );
     66                        os << CodeGen::genPrettyType( type, "" );
    6767                } else {
    6868                        PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
  • src/CodeGen/OperatorTable.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 18 15:55:01 2020
    13 // Update Count     : 55
     12// Last Modified On : Sat Jul 15 17:12:22 2017
     13// Update Count     : 15
    1414//
    1515
     
    1717#include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
    1818#include <utility>    // for pair
    19 using namespace std;
    2019
    2120#include "OperatorTable.h"
     
    2322
    2423namespace CodeGen {
    25         const OperatorInfo CodeGen::tableValues[] = {
    26                 // inputName symbol   outputName                     friendlyName                  type
    27                 {       "?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
    28                 {       "?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
    29                 {       "^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
    30                 {       "?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
    31                 {       "?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
    32                 {       "?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
    33                 {       "*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
    34                 {       "+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
    35                 {       "-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
    36                 {       "~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
    37                 {       "!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
    38                 {       "++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
    39                 {       "--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
    40                 {       "?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
    41                 {       "?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
    42                 {       "?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
    43                 {       "?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
    44                 {       "?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
    45                 {       "?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
    46                 {       "?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
    47                 {       "?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
    48                 {       "?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
    49                 {       "?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
    50                 {       "?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
    51                 {       "?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
    52                 {       "?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
    53                 {       "?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
    54                 {       "?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
    55                 {       "?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
    56                 {       "?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
    57                 {       "?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
    58                 {       "?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
    59                 {       "?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
    60                 {       "?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
    61                 {       "?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
    62                 {       "?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
    63                 {       "?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
    64                 {       "?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
    65                 {       "?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
    66                 {       "?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
    67                 {       "?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
    68                 {       "?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
    69         }; // tableValues
     24        namespace {
     25                const OperatorInfo tableValues[] = {
     26                        {       "?[?]",         "",             "_operator_index",                              OT_INDEX                        },
     27                        {       "?{}",          "=",    "_constructor",                                 OT_CTOR                         },
     28                        {       "^?{}",         "",             "_destructor",                                  OT_DTOR                         },
     29                        {       "?()",          "",             "_operator_call",                               OT_CALL                         },
     30                        {       "?++",          "++",   "_operator_postincr",                   OT_POSTFIXASSIGN        },
     31                        {       "?--",          "--",   "_operator_postdecr",                   OT_POSTFIXASSIGN        },
     32                        {       "*?",           "*",    "_operator_deref",                              OT_PREFIX                       },
     33                        {       "+?",           "+",    "_operator_unaryplus",                  OT_PREFIX                       },
     34                        {       "-?",           "-",    "_operator_unaryminus",                 OT_PREFIX                       },
     35                        {       "~?",           "~",    "_operator_bitnot",                             OT_PREFIX                       },
     36                        {       "!?",           "!",    "_operator_lognot",                             OT_PREFIX                       },
     37                        {       "++?",          "++",   "_operator_preincr",                    OT_PREFIXASSIGN         },
     38                        {       "--?",          "--",   "_operator_predecr",                    OT_PREFIXASSIGN         },
     39                        {       "?\\?",         "\\",   "_operator_exponential",                OT_INFIX                        },
     40                        {       "?*?",          "*",    "_operator_multiply",                   OT_INFIX                        },
     41                        {       "?/?",          "/",    "_operator_divide",                             OT_INFIX                        },
     42                        {       "?%?",          "%",    "_operator_modulus",                    OT_INFIX                        },
     43                        {       "?+?",          "+",    "_operator_add",                                OT_INFIX                        },
     44                        {       "?-?",          "-",    "_operator_subtract",                   OT_INFIX                        },
     45                        {       "?<<?",         "<<",   "_operator_shiftleft",                  OT_INFIX                        },
     46                        {       "?>>?",         ">>",   "_operator_shiftright",                 OT_INFIX                        },
     47                        {       "?<?",          "<",    "_operator_less",                               OT_INFIX                        },
     48                        {       "?>?",          ">",    "_operator_greater",                    OT_INFIX                        },
     49                        {       "?<=?",         "<=",   "_operator_lessequal",                  OT_INFIX                        },
     50                        {       "?>=?",         ">=",   "_operator_greaterequal",               OT_INFIX                        },
     51                        {       "?==?",         "==",   "_operator_equal",                              OT_INFIX                        },
     52                        {       "?!=?",         "!=",   "_operator_notequal",                   OT_INFIX                        },
     53                        {       "?&?",          "&",    "_operator_bitand",                             OT_INFIX                        },
     54                        {       "?^?",          "^",    "_operator_bitxor",                             OT_INFIX                        },
     55                        {       "?|?",          "|",    "_operator_bitor",                              OT_INFIX                        },
     56                        {       "?=?",          "=",    "_operator_assign",                             OT_INFIXASSIGN          },
     57                        {       "?\\=?",        "\\=",  "_operator_expassign",                  OT_INFIXASSIGN          },
     58                        {       "?*=?",         "*=",   "_operator_multassign",                 OT_INFIXASSIGN          },
     59                        {       "?/=?",         "/=",   "_operator_divassign",                  OT_INFIXASSIGN          },
     60                        {       "?%=?",         "%=",   "_operator_modassign",                  OT_INFIXASSIGN          },
     61                        {       "?+=?",         "+=",   "_operator_addassign",                  OT_INFIXASSIGN          },
     62                        {       "?-=?",         "-=",   "_operator_subassign",                  OT_INFIXASSIGN          },
     63                        {       "?<<=?",        "<<=",  "_operator_shiftleftassign",    OT_INFIXASSIGN          },
     64                        {       "?>>=?",        ">>=",  "_operator_shiftrightassign",   OT_INFIXASSIGN          },
     65                        {       "?&=?",         "&=",   "_operator_bitandassign",               OT_INFIXASSIGN          },
     66                        {       "?^=?",         "^=",   "_operator_bitxorassign",               OT_INFIXASSIGN          },
     67                        {       "?|=?",         "|=",   "_operator_bitorassign",                OT_INFIXASSIGN          },
     68                };
    7069
    71         std::map< std::string, OperatorInfo > CodeGen::table;
     70                const int numOps = sizeof( tableValues ) / sizeof( OperatorInfo );
    7271
    73         CodeGen::CodeGen() {
    74                 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
    75                 for ( int i = 0; i < numOps; i += 1 ) {
    76                         table[ tableValues[i].inputName ] = tableValues[i];
    77                 } // for
     72                std::map< std::string, OperatorInfo > table;
     73
     74                void initialize() {
     75                        for ( int i = 0; i < numOps; ++i ) {
     76                                table[ tableValues[i].inputName ] = tableValues[i];
     77                        } // for
     78                }
     79        } // namespace
     80
     81        bool operatorLookup( const std::string & funcName, OperatorInfo & info ) {
     82                static bool init = false;
     83                if ( ! init ) {
     84                        initialize();
     85                } // if
     86
     87                std::map< std::string, OperatorInfo >::const_iterator i = table.find( funcName );
     88                if ( i == table.end() ) {
     89                        if ( isPrefix( funcName, "?`" ) ) {
     90                                // handle literal suffixes, which are user-defined postfix operators
     91                                info.inputName = funcName;
     92                                info.symbol = funcName.substr(2);
     93                                info.outputName = toString( "__operator_literal_", info.symbol );
     94                                info.type = OT_POSTFIX;
     95                                return true;
     96                        }
     97                        return false;
     98                } else {
     99                        info = i->second;
     100                        return true;
     101                } // if
    78102        }
    79103
    80         const OperatorInfo * operatorLookup( const string & funcName ) {
    81                 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter
    82                 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table
    83                 assert( ret );
    84                 return ret;
     104        bool isOperator( const std::string & funcName ) {
     105                OperatorInfo info;
     106                return operatorLookup( funcName, info );
    85107        }
    86108
    87         bool isOperator( const string & funcName ) {
    88                 return operatorLookup( funcName ) != nullptr;
    89         }
    90 
    91         string operatorFriendlyName( const string & funcName ) {
    92                 const OperatorInfo * info = operatorLookup( funcName );
    93                 if ( info ) return info->friendlyName;
    94                 return "";
    95         }
    96 
    97         bool isConstructor( const string & funcName ) {
    98                 const OperatorInfo * info = operatorLookup( funcName );
    99                 if ( info ) return info->type == OT_CTOR;
     109        /// determines if a given function name is one of the operator types between [begin, end)
     110        template<typename Iterator>
     111        bool isOperatorType( const std::string & funcName, Iterator begin, Iterator end ) {
     112                OperatorInfo info;
     113                if ( operatorLookup( funcName, info ) ) {
     114                        return std::find( begin, end, info.type ) != end;
     115                }
    100116                return false;
    101117        }
    102118
    103         bool isDestructor( const string & funcName ) {
    104                 const OperatorInfo * info = operatorLookup( funcName );
    105                 if ( info ) return info->type == OT_DTOR;
    106                 return false;
     119        bool isConstructor( const std::string & funcName ) {
     120                static OperatorType types[] = { OT_CTOR };
     121                return isOperatorType( funcName, std::begin(types), std::end(types) );
    107122        }
    108123
    109         bool isCtorDtor( const string & funcName ) {
    110                 const OperatorInfo * info = operatorLookup( funcName );
    111                 if ( info ) return info->type <= OT_CONSTRUCTOR;
    112                 return false;
     124        bool isDestructor( const std::string & funcName ) {
     125                static OperatorType types[] = { OT_DTOR };
     126                return isOperatorType( funcName, std::begin(types), std::end(types) );
    113127        }
    114128
    115         bool isAssignment( const string & funcName ) {
    116                 const OperatorInfo * info = operatorLookup( funcName );
    117                 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
    118                 return false;
     129        bool isAssignment( const std::string & funcName ) {
     130                static OperatorType types[] = { OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
     131                return isOperatorType( funcName, std::begin(types), std::end(types) );
    119132        }
    120133
    121         bool isCtorDtorAssign( const string & funcName ) {
    122                 const OperatorInfo * info = operatorLookup( funcName );
    123                 if ( info ) return info->type <= OT_ASSIGNMENT;
    124                 return false;
     134        bool isCtorDtor( const std::string & funcName ) {
     135                static OperatorType types[] = { OT_CTOR, OT_DTOR };
     136                return isOperatorType( funcName, std::begin(types), std::end(types) );
    125137        }
    126138
    127         CodeGen codegen;                                                                        // initialize singleton package
     139        bool isCtorDtorAssign( const std::string & funcName ) {
     140                static OperatorType types[] = { OT_CTOR, OT_DTOR, OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
     141                return isOperatorType( funcName, std::begin(types), std::end(types) );
     142        }
    128143} // namespace CodeGen
    129144
    130145// Local Variables: //
    131146// tab-width: 4 //
     147// mode: c++ //
     148// compile-command: "make install" //
    132149// End: //
  • src/CodeGen/OperatorTable.h

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:13:34 2020
    13 // Update Count     : 26
     12// Last Modified On : Fri Jul 21 22:17:11 2017
     13// Update Count     : 6
    1414//
    1515
     
    1717
    1818#include <string>
    19 #include <map>
    2019
    2120namespace CodeGen {
    2221        enum OperatorType {
     22                OT_INDEX,
    2323                OT_CTOR,
    2424                OT_DTOR,
    25                 OT_CONSTRUCTOR = OT_DTOR,
     25                OT_CALL,
     26                OT_PREFIX,
     27                OT_POSTFIX,
     28                OT_INFIX,
    2629                OT_PREFIXASSIGN,
    2730                OT_POSTFIXASSIGN,
    2831                OT_INFIXASSIGN,
    29                 OT_ASSIGNMENT = OT_INFIXASSIGN,
    30                 OT_CALL,
    31                 OT_PREFIX,
    32                 OT_INFIX,
    33                 OT_POSTFIX,
    34                 OT_INDEX,
    3532                OT_LABELADDRESS,
    3633                OT_CONSTANT
     
    4138                std::string symbol;
    4239                std::string outputName;
    43                 std::string friendlyName;
    4440                OperatorType type;
    4541        };
    4642
    47         class CodeGen {
    48                 friend const OperatorInfo * operatorLookup( const std::string & funcName );
    49 
    50                 static const OperatorInfo tableValues[];
    51                 static std::map< std::string, OperatorInfo > table;
    52           public:
    53                 CodeGen();
    54         }; // CodeGen
    55 
    5643        bool isOperator( const std::string & funcName );
    57         const OperatorInfo * operatorLookup( const std::string & funcName );
    58         std::string operatorFriendlyName( const std::string & funcName );
     44        bool operatorLookup( const std::string & funcName, OperatorInfo & info );
    5945
    6046        bool isConstructor( const std::string & );
  • src/CodeGen/Options.h

    r7030dab r71d6bd8  
    99// Author           : Andrew Beach
    1010// Created On       : Tue Apr 30 11:36:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 18:37:06 2020
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May  2 10:45:00 2019
     13// Update Count     : 2
    1414//
    1515
    1616#pragma once
    1717
    18 struct Options {
    19         // External Options: Same thoughout a pass.
    20         bool pretty;
    21         bool genC;
    22         bool lineMarks;
    23         bool printExprTypes;
     18namespace CodeGen {
     19        struct Options {
     20                // External Options: Same thoughout a pass.
     21                bool pretty;
     22                bool genC;
     23                bool lineMarks;
     24                bool printExprTypes;
    2425
    25         // Internal Options: Changed on some recurisive calls.
    26         bool anonymousUnused = false;
     26                // Internal Options: Changed on some recurisive calls.
     27                bool anonymousUnused = false;
    2728
    28         Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) :
    29                 pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes)
     29                Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) :
     30                        pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes)
    3031                {}
    31 };
     32        };
     33} // namespace CodeGen
    3234
    3335// Local Variables: //
  • src/CodeGen/module.mk

    r7030dab r71d6bd8  
    1111## Created On       : Mon Jun  1 17:49:17 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Dec 14 07:29:42 2019
    14 ## Update Count     : 4
     13## Last Modified On : Tue Jun  2 11:17:02 2015
     14## Update Count     : 3
    1515###############################################################################
    1616
     
    2424        CodeGen/OperatorTable.cc
    2525
     26
    2627SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc
    2728SRCDEMANGLE += $(SRC_CODEGEN)
  • src/CodeTools/DeclStats.cc

    r7030dab r71d6bd8  
    99// Author           : Aaron Moss
    1010// Created On       : Wed Jan 31 16:40:00 2016
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:39:33 2019
    13 // Update Count     : 2
     11// Last Modified By : Aaron Moss
     12// Last Modified On : Wed Jan 31 16:40:00 2016
     13// Update Count     : 1
    1414//
    1515
     
    2626#include "Common/VectorMap.h"      // for VectorMap
    2727#include "GenPoly/GenPoly.h"       // for hasPolyBase
    28 #include "SynTree/LinkageSpec.h"   // for ::NoOfSpecs, Spec
     28#include "Parser/LinkageSpec.h"    // for ::NoOfSpecs, Spec
    2929#include "SynTree/Declaration.h"   // for FunctionDecl, TypeDecl, Declaration
    3030#include "SynTree/Expression.h"    // for UntypedExpr, Expression
  • src/CodeTools/ResolvProtoDump.cc

    r7030dab r71d6bd8  
    99// Author           : Aaron Moss
    1010// Created On       : Tue Sep 11 09:04:00 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 13:50:11 2020
    13 // Update Count     : 3
     11// Last Modified By : Aaron Moss
     12// Last Modified On : Tue Sep 11 09:04:00 2018
     13// Update Count     : 1
    1414//
    1515
     
    182182
    183183                        // replace operator names
    184                         const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( name );
    185                         if ( opInfo ) {
     184                        CodeGen::OperatorInfo info;
     185                        if ( CodeGen::operatorLookup( name, info ) ) {
    186186                                ss << new_prefix(pre, "");
    187                                 op_name( opInfo->outputName, ss );
     187                                op_name( info.outputName, ss );
    188188                                return;
    189189                        }
  • src/Common/Debug.h

    r7030dab r71d6bd8  
    99// Author           : Rob Schluntz
    1010// Created On       : Fri Sep 1 11:09:14 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:39:42 2019
    13 // Update Count     : 3
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Fri Sep 1 11:09:36 2017
     13// Update Count     : 2
    1414//
    1515
     
    2121
    2222#include "CodeGen/Generate.h"
    23 #include "SynTree/LinkageSpec.h"
     23#include "Parser/LinkageSpec.h"
    2424#include "SynTree/Declaration.h"
    2525
  • src/Common/PassVisitor.h

    r7030dab r71d6bd8  
    110110        virtual void visit( FinallyStmt * finallyStmt ) override final;
    111111        virtual void visit( const FinallyStmt * finallyStmt ) override final;
    112         virtual void visit( SuspendStmt * suspendStmt ) override final;
    113         virtual void visit( const SuspendStmt * suspendStmt ) override final;
    114112        virtual void visit( WaitForStmt * waitforStmt ) override final;
    115113        virtual void visit( const WaitForStmt * waitforStmt ) override final;
     
    278276        virtual Statement * mutate( CatchStmt * catchStmt ) override final;
    279277        virtual Statement * mutate( FinallyStmt * finallyStmt ) override final;
    280         virtual Statement * mutate( SuspendStmt * suspendStmt ) override final;
    281278        virtual Statement * mutate( WaitForStmt * waitforStmt ) override final;
    282279        virtual Declaration * mutate( WithStmt * withStmt ) override final;
  • src/Common/PassVisitor.impl.h

    r7030dab r71d6bd8  
    15221522
    15231523//--------------------------------------------------------------------------
    1524 // SuspendStmt
    1525 template< typename pass_type >
    1526 void PassVisitor< pass_type >::visit( SuspendStmt * node ) {
    1527         VISIT_START( node );
    1528 
    1529         maybeAccept_impl( node->then  , *this );
    1530 
    1531         VISIT_END( node );
    1532 }
    1533 
    1534 template< typename pass_type >
    1535 void PassVisitor< pass_type >::visit( const SuspendStmt * node ) {
    1536         VISIT_START( node );
    1537 
    1538         maybeAccept_impl( node->then  , *this );
    1539 
    1540         VISIT_END( node );
    1541 }
    1542 
    1543 template< typename pass_type >
    1544 Statement * PassVisitor< pass_type >::mutate( SuspendStmt * node ) {
    1545         MUTATE_START( node );
    1546 
    1547         maybeMutate_impl( node->then  , *this );
    1548 
    1549         MUTATE_END( Statement, node );
    1550 }
    1551 
    1552 //--------------------------------------------------------------------------
    15531524// WaitForStmt
    15541525template< typename pass_type >
     
    33313302        VISIT_START( node );
    33323303
    3333         indexerAddUnion( node->name );
     3304        indexerAddStruct( node->name );
    33343305
    33353306        {
     
    33463317        VISIT_START( node );
    33473318
    3348         indexerAddUnion( node->name );
     3319        indexerAddStruct( node->name );
    33493320
    33503321        {
     
    33613332        MUTATE_START( node );
    33623333
    3363         indexerAddUnion( node->name );
     3334        indexerAddStruct( node->name );
    33643335
    33653336        {
  • src/Common/SemanticError.cc

    r7030dab r71d6bd8  
    149149// Helpers
    150150namespace ErrorHelpers {
    151         Colors colors = Colors::Auto;
    152 
    153         static inline bool with_colors() {
    154                 return colors == Colors::Auto ? isatty( STDERR_FILENO ) : bool(colors);
    155         }
    156 
    157151        const std::string & error_str() {
    158                 static std::string str = with_colors() ? "\e[31merror:\e[39m " : "error: ";
     152                static std::string str = isatty( STDERR_FILENO ) ? "\e[31merror:\e[39m " : "error: ";
    159153                return str;
    160154        }
    161155
    162156        const std::string & warning_str() {
    163                 static std::string str = with_colors() ? "\e[95mwarning:\e[39m " : "warning: ";
     157                static std::string str = isatty( STDERR_FILENO ) ? "\e[95mwarning:\e[39m " : "warning: ";
    164158                return str;
    165159        }
    166160
    167161        const std::string & bold_ttycode() {
    168                 static std::string str = with_colors() ? "\e[1m" : "";
     162                static std::string str = isatty( STDERR_FILENO ) ? "\e[1m" : "";
    169163                return str;
    170164        }
    171165
    172166        const std::string & reset_font_ttycode() {
    173                 static std::string str = with_colors() ? "\e[0m" : "";
     167                static std::string str = isatty( STDERR_FILENO ) ? "\e[0m" : "";
    174168                return str;
    175169        }
  • src/Common/SemanticError.h

    r7030dab r71d6bd8  
    4949struct WarningData {
    5050        const char * const name;
     51        const char * const message;
    5152        const Severity default_severity;
    52         const char * const message;
    5353};
    5454
    5555constexpr WarningData WarningFormats[] = {
    56         {"self-assign"            , Severity::Warn    , "self assignment of expression: %s"                          },
    57         {"reference-conversion"   , Severity::Warn    , "rvalue to reference conversion of rvalue: %s"               },
    58         {"qualifiers-zero_t-one_t", Severity::Warn    , "questionable use of type qualifier %s with %s"              },
    59         {"aggregate-forward-decl" , Severity::Warn    , "forward declaration of nested aggregate: %s"                },
    60         {"superfluous-decl"       , Severity::Warn    , "declaration does not allocate storage: %s"                  },
    61         {"gcc-attributes"         , Severity::Warn    , "invalid attribute: %s"                                      },
    62         {"c++-like-copy"          , Severity::Warn    , "Constructor from reference is not a valid copy constructor" },
     56        {"self-assign"            , "self assignment of expression: %s"            , Severity::Warn},
     57        {"reference-conversion"   , "rvalue to reference conversion of rvalue: %s" , Severity::Warn},
     58        {"qualifiers-zero_t-one_t", "questionable use of type qualifier %s with %s", Severity::Warn},
     59        {"aggregate-forward-decl" , "forward declaration of nested aggregate: %s"  , Severity::Warn},
     60        {"superfluous-decl"       , "declaration does not allocate storage: %s"    , Severity::Warn},
     61        {"gcc-attributes"         , "invalid attribute: %s"                        , Severity::Warn},
    6362};
    6463
     
    7069        SuperfluousDecl,
    7170        GccAttributes,
    72         CppCopy,
    7371        NUMBER_OF_WARNINGS, // This MUST be the last warning
    7472};
     
    9997// Helpers
    10098namespace ErrorHelpers {
    101         enum class Colors {
    102                 Never = false,
    103                 Always = true,
    104                 Auto,
    105         };
    106 
    107         extern Colors colors;
    108 
    10999        const std::string & error_str();
    110100        const std::string & warning_str();
  • src/Common/Stats/Time.h

    r7030dab r71d6bd8  
    99// Author           : Thierry Delisle
    1010// Created On       : Fri Mar 01 15:14:11 2019
    11 // Last Modified By : Andrew Beach
     11// Last Modified By :
    1212// Last Modified On :
    1313// Update Count     :
     
    4141                                f();
    4242                        }
    43 
    44                         template<typename ret_t = void, typename func_t, typename... arg_t>
    45                         inline ret_t TimeCall(
    46                                         const char *, func_t func, arg_t&&... arg) {
    47                                 return func(std::forward<arg_t>(arg)...);
    48                         }
    4943#               else
    5044                        void StartGlobal();
     
    6559                                func();
    6660                        }
    67 
    68                         template<typename ret_t = void, typename func_t, typename... arg_t>
    69                         inline ret_t TimeCall(
    70                                         const char * name, func_t func, arg_t&&... arg) {
    71                                 BlockGuard guard(name);
    72                                 return func(std::forward<arg_t>(arg)...);
    73                         }
    7461#               endif
    7562        }
  • src/Common/utility.h

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 11 13:00:36 2020
    13 // Update Count     : 50
     12// Last Modified On : Wed Jul 24 14:28:19 2019
     13// Update Count     : 41
    1414//
    1515
     
    2929#include <utility>
    3030#include <vector>
    31 #include <cstring>                                                                              // memcmp
    3231
    3332#include "Common/Indenter.h"
     
    265264}
    266265
    267 // determines if pref is a prefix of str
    268 static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
     266/// determines if `pref` is a prefix of `str`
     267static inline bool isPrefix( const std::string & str, const std::string & pref ) {
    269268        if ( pref.size() > str.size() ) return false;
    270     return 0 == memcmp( str.c_str() + start, pref.c_str(), pref.size() );
    271         // return prefix == full.substr(0, prefix.size()); // for future, requires c++17
     269        auto its = std::mismatch( pref.begin(), pref.end(), str.begin() );
     270        return its.first == pref.end();
    272271}
    273272
  • src/Concurrency/Keywords.cc

    r7030dab r71d6bd8  
    1111// Last Modified By :
    1212// Last Modified On :
    13 // Update Count     : 10
     13// Update Count     : 5
    1414//
    1515
    1616#include "Concurrency/Keywords.h"
    1717
    18 #include <cassert>                        // for assert
    19 #include <string>                         // for string, operator==
    20 
    21 #include "Common/PassVisitor.h"           // for PassVisitor
    22 #include "Common/SemanticError.h"         // for SemanticError
    23 #include "Common/utility.h"               // for deleteAll, map_range
    24 #include "CodeGen/OperatorTable.h"        // for isConstructor
    25 #include "ControlStruct/LabelGenerator.h" // for LebelGenerator
    26 #include "InitTweak/InitTweak.h"          // for getPointerBase
    27 #include "SynTree/LinkageSpec.h"          // for Cforall
    28 #include "SynTree/Constant.h"             // for Constant
    29 #include "SynTree/Declaration.h"          // for StructDecl, FunctionDecl, ObjectDecl
    30 #include "SynTree/Expression.h"           // for VariableExpr, ConstantExpr, Untype...
    31 #include "SynTree/Initializer.h"          // for SingleInit, ListInit, Initializer ...
    32 #include "SynTree/Label.h"                // for Label
    33 #include "SynTree/Statement.h"            // for CompoundStmt, DeclStmt, ExprStmt
    34 #include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
    35 #include "SynTree/Visitor.h"              // for Visitor, acceptAll
     18#include <cassert>                 // for assert
     19#include <string>                  // for string, operator==
     20
     21#include "Common/PassVisitor.h"    // for PassVisitor
     22#include "Common/SemanticError.h"  // for SemanticError
     23#include "Common/utility.h"        // for deleteAll, map_range
     24#include "CodeGen/OperatorTable.h" // for isConstructor
     25#include "InitTweak/InitTweak.h"   // for getPointerBase
     26#include "Parser/LinkageSpec.h"    // for Cforall
     27#include "SynTree/Constant.h"      // for Constant
     28#include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
     29#include "SynTree/Expression.h"    // for VariableExpr, ConstantExpr, Untype...
     30#include "SynTree/Initializer.h"   // for SingleInit, ListInit, Initializer ...
     31#include "SynTree/Label.h"         // for Label
     32#include "SynTree/Statement.h"     // for CompoundStmt, DeclStmt, ExprStmt
     33#include "SynTree/Type.h"          // for StructInstType, Type, PointerType
     34#include "SynTree/Visitor.h"       // for Visitor, acceptAll
    3635
    3736class Attribute;
     
    5453          public:
    5554
    56                 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
     55                ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, KeywordCastExpr::Target cast_target ) :
    5756                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
    5857
     
    6059
    6160                Declaration * postmutate( StructDecl * decl );
    62                 DeclarationWithType * postmutate( FunctionDecl * decl );
    6361
    6462                void handle( StructDecl * );
     
    7775                const std::string context_error;
    7876                bool needs_main;
    79                 AggregateDecl::Aggregate cast_target;
    80 
    81                 StructDecl   * type_decl = nullptr;
    82                 FunctionDecl * dtor_decl = nullptr;
     77                KeywordCastExpr::Target cast_target;
     78
     79                StructDecl* type_decl = nullptr;
    8380        };
    8481
     
    8986        //      int data;                                  int data;
    9087        //      a_struct_t more_data;                      a_struct_t more_data;
    91         //                                =>             $thread __thrd_d;
     88        //                                =>             thread_desc __thrd_d;
    9289        // };                                        };
    93         //                                           static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
     90        //                                           static inline thread_desc * get_thread( MyThread * this ) { return &this->__thrd_d; }
    9491        //
    9592        class ThreadKeyword final : public ConcurrentSueKeyword {
     
    9794
    9895                ThreadKeyword() : ConcurrentSueKeyword(
    99                         "$thread",
     96                        "thread_desc",
    10097                        "__thrd",
    10198                        "get_thread",
    102                         "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
     99                        "thread keyword requires threads to be in scope, add #include <thread.hfa>",
    103100                        true,
    104                         AggregateDecl::Thread
     101                        KeywordCastExpr::Thread
    105102                )
    106103                {}
     
    121118        //      int data;                                  int data;
    122119        //      a_struct_t more_data;                      a_struct_t more_data;
    123         //                                =>             $coroutine __cor_d;
     120        //                                =>             coroutine_desc __cor_d;
    124121        // };                                        };
    125         //                                           static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
     122        //                                           static inline coroutine_desc * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
    126123        //
    127124        class CoroutineKeyword final : public ConcurrentSueKeyword {
     
    129126
    130127                CoroutineKeyword() : ConcurrentSueKeyword(
    131                         "$coroutine",
     128                        "coroutine_desc",
    132129                        "__cor",
    133130                        "get_coroutine",
    134                         "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
     131                        "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>",
    135132                        true,
    136                         AggregateDecl::Coroutine
     133                        KeywordCastExpr::Coroutine
    137134                )
    138135                {}
     
    147144                }
    148145        };
    149 
    150 
    151146
    152147        //-----------------------------------------------------------------------------
     
    155150        //      int data;                                  int data;
    156151        //      a_struct_t more_data;                      a_struct_t more_data;
    157         //                                =>             $monitor __mon_d;
     152        //                                =>             monitor_desc __mon_d;
    158153        // };                                        };
    159         //                                           static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
     154        //                                           static inline monitor_desc * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
    160155        //
    161156        class MonitorKeyword final : public ConcurrentSueKeyword {
     
    163158
    164159                MonitorKeyword() : ConcurrentSueKeyword(
    165                         "$monitor",
     160                        "monitor_desc",
    166161                        "__mon",
    167162                        "get_monitor",
    168                         "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
     163                        "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>",
    169164                        false,
    170                         AggregateDecl::Monitor
     165                        KeywordCastExpr::Monitor
    171166                )
    172167                {}
     
    183178
    184179        //-----------------------------------------------------------------------------
    185         //Handles generator type declarations :
    186         // generator MyGenerator {                   struct MyGenerator {
    187         //      int data;                                  int data;
    188         //      a_struct_t more_data;                      a_struct_t more_data;
    189         //                                =>             int __gen_next;
    190         // };                                        };
    191         //
    192         class GeneratorKeyword final : public ConcurrentSueKeyword {
    193           public:
    194 
    195                 GeneratorKeyword() : ConcurrentSueKeyword(
    196                         "$generator",
    197                         "__generator_state",
    198                         "get_generator",
    199                         "Unable to find builtin type $generator\n",
    200                         true,
    201                         AggregateDecl::Generator
    202                 )
    203                 {}
    204 
    205                 virtual ~GeneratorKeyword() {}
    206 
    207                 virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
    208 
    209                 static void implement( std::list< Declaration * > & translationUnit ) {
    210                         PassVisitor< GeneratorKeyword > impl;
    211                         mutateAll( translationUnit, impl );
    212                 }
    213         };
    214 
    215 
    216         //-----------------------------------------------------------------------------
    217         class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
    218         public:
    219                 SuspendKeyword() = default;
    220                 virtual ~SuspendKeyword() = default;
    221 
    222                 void  premutate( FunctionDecl * );
    223                 DeclarationWithType * postmutate( FunctionDecl * );
    224 
    225                 Statement * postmutate( SuspendStmt * );
    226 
    227                 static void implement( std::list< Declaration * > & translationUnit ) {
    228                         PassVisitor< SuspendKeyword > impl;
    229                         mutateAll( translationUnit, impl );
    230                 }
    231 
    232         private:
    233                 DeclarationWithType * is_main( FunctionDecl * );
    234                 bool is_real_suspend( FunctionDecl * );
    235 
    236                 Statement * make_generator_suspend( SuspendStmt * );
    237                 Statement * make_coroutine_suspend( SuspendStmt * );
    238 
    239                 struct LabelPair {
    240                         Label obj;
    241                         int   idx;
    242                 };
    243 
    244                 LabelPair make_label() {
    245                         labels.push_back( gen.newLabel("generator") );
    246                         return { labels.back(), int(labels.size()) };
    247                 }
    248 
    249                 DeclarationWithType * in_generator = nullptr;
    250                 FunctionDecl * decl_suspend = nullptr;
    251                 std::vector<Label> labels;
    252                 ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
    253         };
    254 
    255         //-----------------------------------------------------------------------------
    256180        //Handles mutex routines definitions :
    257181        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
    258         //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     182        //                                                                       monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    259183        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
    260184        //    /*Some code*/                                       =>           /*Some code*/
     
    295219        //Handles mutex routines definitions :
    296220        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
    297         //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     221        //                                                                       monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    298222        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
    299223        //    /*Some code*/                                       =>           /*Some code*/
     
    325249                CoroutineKeyword        ::implement( translationUnit );
    326250                MonitorKeyword  ::implement( translationUnit );
    327                 GeneratorKeyword  ::implement( translationUnit );
    328                 SuspendKeyword    ::implement( translationUnit );
    329251        }
    330252
     
    362284        }
    363285
    364         DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
    365                 if( !type_decl ) return decl;
    366                 if( !CodeGen::isDestructor( decl->name ) ) return decl;
    367 
    368                 auto params = decl->type->parameters;
    369                 if( params.size() != 1 ) return decl;
    370 
    371                 auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
    372                 if( !type ) return decl;
    373 
    374                 auto stype = dynamic_cast<StructInstType*>( type->base );
    375                 if( !stype ) return decl;
    376                 if( stype->baseStruct != type_decl ) return decl;
    377 
    378                 if( !dtor_decl ) dtor_decl = decl;
    379                 return decl;
    380         }
    381 
    382286        Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
    383287                if ( cast_target == cast->target ) {
    384                         // convert (thread &)t to ($thread &)*get_thread(t), etc.
     288                        // convert (thread &)t to (thread_desc &)*get_thread(t), etc.
    385289                        if( !type_decl ) SemanticError( cast, context_error );
    386                         if( !dtor_decl ) SemanticError( cast, context_error );
    387                         assert( cast->result == nullptr );
    388                         cast->set_result( new ReferenceType( noQualifiers, new StructInstType( noQualifiers, type_decl ) ) );
    389                         cast->concrete_target.field  = field_name;
    390                         cast->concrete_target.getter = getter_name;
     290                        Expression * arg = cast->arg;
     291                        cast->arg = nullptr;
     292                        delete cast;
     293                        return new CastExpr(
     294                                UntypedExpr::createDeref(
     295                                        new UntypedExpr( new NameExpr( getter_name ), { arg } )
     296                                ),
     297                                new ReferenceType(
     298                                        noQualifiers,
     299                                        new StructInstType( noQualifiers, type_decl ) )
     300                                );
    391301                }
    392302                return cast;
     
    398308
    399309                if( !type_decl ) SemanticError( decl, context_error );
    400                 if( !dtor_decl ) SemanticError( decl, context_error );
    401310
    402311                FunctionDecl * func = forwardDeclare( decl );
     
    453362                        get_type,
    454363                        nullptr,
    455                         { new Attribute("const") },
     364                        noAttributes,
    456365                        Type::Inline
    457366                );
     
    522431
    523432                declsToAddAfter.push_back( get_decl );
    524         }
    525 
    526         //=============================================================================================
    527         // Suspend keyword implementation
    528         //=============================================================================================
    529         DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) {
    530                 if(func->name != "main") return nullptr;
    531                 if(func->type->parameters.size() != 1) return nullptr;
    532 
    533                 auto param = func->type->parameters.front();
    534 
    535                 auto type  = dynamic_cast<ReferenceType * >(param->get_type());
    536                 if(!type) return nullptr;
    537 
    538                 auto obj   = dynamic_cast<StructInstType *>(type->base);
    539                 if(!obj) return nullptr;
    540 
    541                 if(!obj->baseStruct->is_generator()) return nullptr;
    542 
    543                 return param;
    544         }
    545 
    546         bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
    547                 if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
    548                 if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
    549                 if(func->type->parameters.size() != 0) return false; // Too many parameters
    550                 if(func->type->returnVals.size() != 0) return false; // Too many return values
    551 
    552                 return true;
    553         }
    554 
    555         void SuspendKeyword::premutate( FunctionDecl * func ) {
    556                 GuardValue(in_generator);
    557                 in_generator = nullptr;
    558 
    559                 // Is this the real suspend?
    560                 if(is_real_suspend(func)) {
    561                         decl_suspend = decl_suspend ? decl_suspend : func;
    562                         return;
    563                 }
    564 
    565                 // Is this the main of a generator?
    566                 auto param = is_main( func );
    567                 if(!param) return;
    568 
    569                 if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
    570 
    571                 in_generator = param;
    572                 GuardValue(labels);
    573                 labels.clear();
    574         }
    575 
    576         DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
    577                 if( !func->statements ) return func; // Not the actual definition, don't do anything
    578                 if( !in_generator     ) return func; // Not in a generator, don't do anything
    579                 if( labels.empty()    ) return func; // Generator has no states, nothing to do, could throw a warning
    580 
    581                 // This is a generator main, we need to add the following code to the top
    582                 // static void * __generator_labels[] = {&&s0, &&s1, ...};
    583                 // goto * __generator_labels[gen.__generator_state];
    584                 const auto & loc = func->location;
    585 
    586                 const auto first_label = gen.newLabel("generator");
    587 
    588                 // for each label add to declaration
    589                 std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
    590                 for(const auto & label : labels) {
    591                         inits.push_back(
    592                                 new SingleInit(
    593                                         new LabelAddressExpr( label )
    594                                 )
    595                         );
    596                 }
    597                 auto init = new ListInit(std::move(inits), noDesignators, true);
    598                 labels.clear();
    599 
    600                 // create decl
    601                 auto decl = new ObjectDecl(
    602                         "__generator_labels",
    603                         Type::StorageClasses( Type::Static ),
    604                         LinkageSpec::AutoGen,
    605                         nullptr,
    606                         new ArrayType(
    607                                 Type::Qualifiers(),
    608                                 new PointerType(
    609                                         Type::Qualifiers(),
    610                                         new VoidType( Type::Qualifiers() )
    611                                 ),
    612                                 nullptr,
    613                                 false, false
    614                         ),
    615                         init
    616                 );
    617 
    618                 // create the goto
    619                 assert(in_generator);
    620 
    621                 auto go_decl = new ObjectDecl(
    622                         "__generator_label",
    623                         noStorageClasses,
    624                         LinkageSpec::AutoGen,
    625                         nullptr,
    626                         new PointerType(
    627                                 Type::Qualifiers(),
    628                                 new VoidType( Type::Qualifiers() )
    629                         ),
    630                         new SingleInit(
    631                                 new UntypedExpr(
    632                                         new NameExpr("?[?]"),
    633                                         {
    634                                                 new NameExpr("__generator_labels"),
    635                                                 new UntypedMemberExpr(
    636                                                         new NameExpr("__generator_state"),
    637                                                         new VariableExpr( in_generator )
    638                                                 )
    639                                         }
    640                                 )
    641                         )
    642                 );
    643                 go_decl->location = loc;
    644 
    645                 auto go = new BranchStmt(
    646                         new VariableExpr( go_decl ),
    647                         BranchStmt::Goto
    648                 );
    649                 go->location = loc;
    650                 go->computedTarget->location = loc;
    651 
    652                 auto noop = new NullStmt({ first_label });
    653                 noop->location = loc;
    654 
    655                 // wrap everything in a nice compound
    656                 auto body = new CompoundStmt({
    657                         new DeclStmt( decl ),
    658                         new DeclStmt( go_decl ),
    659                         go,
    660                         noop,
    661                         func->statements
    662                 });
    663                 body->location   = loc;
    664                 func->statements = body;
    665 
    666                 return func;
    667         }
    668 
    669         Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
    670                 SuspendStmt::Type type = stmt->type;
    671                 if(type == SuspendStmt::None) {
    672                         // This suspend has a implicit target, find it
    673                         type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
    674                 }
    675 
    676                 // Check that the target makes sense
    677                 if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
    678 
    679                 // Act appropriately
    680                 switch(type) {
    681                         case SuspendStmt::Generator: return make_generator_suspend(stmt);
    682                         case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
    683                         default: abort();
    684                 }
    685         }
    686 
    687         Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
    688                 assert(in_generator);
    689                 // Target code is :
    690                 //   gen.__generator_state = X;
    691                 //   { THEN }
    692                 //   return;
    693                 //   __gen_X:;
    694 
    695                 // Save the location and delete the old statement, we only need the location from this point on
    696                 auto loc = stmt->location;
    697 
    698                 // Build the label and get its index
    699                 auto label = make_label();
    700 
    701                 // Create the context saving statement
    702                 auto save = new ExprStmt( new UntypedExpr(
    703                         new NameExpr( "?=?" ),
    704                         {
    705                                 new UntypedMemberExpr(
    706                                         new NameExpr("__generator_state"),
    707                                         new VariableExpr( in_generator )
    708                                 ),
    709                                 new ConstantExpr(
    710                                         Constant::from_int( label.idx )
    711                                 )
    712                         }
    713                 ));
    714                 assert(save->expr);
    715                 save->location = loc;
    716                 stmtsToAddBefore.push_back( save );
    717 
    718                 // if we have a then add it here
    719                 auto then = stmt->then;
    720                 stmt->then = nullptr;
    721                 delete stmt;
    722                 if(then) stmtsToAddBefore.push_back( then );
    723 
    724                 // Create the return statement
    725                 auto ret = new ReturnStmt( nullptr );
    726                 ret->location = loc;
    727                 stmtsToAddBefore.push_back( ret );
    728 
    729                 // Create the null statement with the created label
    730                 auto noop = new NullStmt({ label.obj });
    731                 noop->location = loc;
    732 
    733                 // Return the null statement to take the place of the previous statement
    734                 return noop;
    735         }
    736 
    737         Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
    738                 if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
    739 
    740                 // Save the location and delete the old statement, we only need the location from this point on
    741                 auto loc = stmt->location;
    742                 delete stmt;
    743 
    744                 // Create the call expression
    745                 if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
    746                 auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
    747                 expr->location = loc;
    748 
    749                 // Change this statement into a regular expr
    750                 assert(expr);
    751                 auto nstmt = new ExprStmt( expr );
    752                 nstmt->location = loc;
    753                 return nstmt;
    754         }
    755 
     433
     434                // get_decl->fixUniqueId();
     435        }
    756436
    757437        //=============================================================================================
     
    821501        void MutexKeyword::postvisit(StructDecl* decl) {
    822502
    823                 if( decl->name == "$monitor" && decl->body ) {
     503                if( decl->name == "monitor_desc" && decl->body ) {
    824504                        assert( !monitor_decl );
    825505                        monitor_decl = decl;
     
    917597                );
    918598
    919                 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     599                //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    920600                body->push_front( new DeclStmt( monitors) );
    921601        }
     
    978658                );
    979659
    980                 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
     660                //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
    981661                body->push_front( new DeclStmt( monitors) );
    982662        }
     
    986666        //=============================================================================================
    987667        void ThreadStarter::previsit( StructDecl * decl ) {
    988                 if( decl->name == "$thread" && decl->body ) {
     668                if( decl->name == "thread_desc" && decl->body ) {
    989669                        assert( !thread_decl );
    990670                        thread_decl = decl;
     
    1021701                                new UntypedExpr(
    1022702                                        new NameExpr( "__thrd_start" ),
    1023                                         { new VariableExpr( param ), new NameExpr("main") }
     703                                        { new VariableExpr( param ) }
    1024704                                )
    1025705                        )
  • src/Concurrency/Waitfor.cc

    r7030dab r71d6bd8  
    1111// Last Modified By :
    1212// Last Modified On :
    13 // Update Count     : 12
     13// Update Count     : 7
    1414//
    1515
     
    2323#include "Common/PassVisitor.h"    // for PassVisitor
    2424#include "Common/SemanticError.h"  // for SemanticError
    25 #include "Common/UniqueName.h"     // for UniqueName
    2625#include "Common/utility.h"        // for deleteAll, map_range
    2726#include "CodeGen/OperatorTable.h" // for isConstructor
    2827#include "InitTweak/InitTweak.h"   // for getPointerBase
     28#include "Parser/LinkageSpec.h"    // for Cforall
    2929#include "ResolvExpr/Resolver.h"   // for findVoidExpression
    30 #include "SynTree/LinkageSpec.h"   // for Cforall
    3130#include "SynTree/Constant.h"      // for Constant
    3231#include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
     
    4241void foo() {
    4342        while( true ) {
    44                 when( a < 1 ) waitfor( f : a ) { bar(); }
     43                when( a < 1 ) waitfor( f, a ) { bar(); }
    4544                or timeout( swagl() );
    46                 or waitfor( g : a ) { baz(); }
    47                 or waitfor( ^?{} : a ) { break; }
     45                or waitfor( g, a ) { baz(); }
     46                or waitfor( ^?{}, a ) { break; }
    4847                or waitfor( ^?{} ) { break; }
    4948        }
     
    244243                        decl_mask = decl;
    245244                }
    246                 else if( decl->name == "$monitor" ) {
     245                else if( decl->name == "monitor_desc" ) {
    247246                        assert( !decl_monitor );
    248247                        decl_monitor = decl;
  • src/ControlStruct/ExceptTranslate.cc

    r7030dab r71d6bd8  
    99// Author           : Andrew Beach
    1010// Created On       : Wed Jun 14 16:49:00 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 27 11:58:00 2020
    13 // Update Count     : 13
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Feb 13 18:15:29 2019
     13// Update Count     : 11
    1414//
    1515
     
    2424#include "Common/SemanticError.h"     // for SemanticError
    2525#include "Common/utility.h"           // for CodeLocation
    26 #include "SynTree/LinkageSpec.h"      // for Cforall
     26#include "Parser/LinkageSpec.h"       // for Cforall
    2727#include "SynTree/Attribute.h"        // for Attribute
    2828#include "SynTree/Constant.h"         // for Constant
     
    211211                        ThrowStmt *throwStmt ) {
    212212                // __throw_terminate( `throwStmt->get_name()` ); }
    213                 return create_given_throw( "__cfaehm_throw_terminate", throwStmt );
     213                return create_given_throw( "__cfaabi_ehm__throw_terminate", throwStmt );
    214214        }
    215215
     
    232232                        ) ) );
    233233                result->push_back( new ExprStmt(
    234                         new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) )
     234                        new UntypedExpr( new NameExpr( "__cfaabi_ehm__rethrow_terminate" ) )
    235235                        ) );
    236236                delete throwStmt;
     
    241241                        ThrowStmt *throwStmt ) {
    242242                // __throw_resume( `throwStmt->get_name` );
    243                 return create_given_throw( "__cfaehm_throw_resume", throwStmt );
     243                return create_given_throw( "__cfaabi_ehm__throw_resume", throwStmt );
    244244        }
    245245
     
    309309                        local_except->get_attributes().push_back( new Attribute(
    310310                                "cleanup",
    311                                 { new NameExpr( "__cfaehm_cleanup_terminate" ) }
     311                                { new NameExpr( "__cfaabi_ehm__cleanup_terminate" ) }
    312312                                ) );
    313313
     
    429429                        FunctionDecl * terminate_catch,
    430430                        FunctionDecl * terminate_match ) {
    431                 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
     431                // { __cfaabi_ehm__try_terminate(`try`, `catch`, `match`); }
    432432
    433433                UntypedExpr * caller = new UntypedExpr( new NameExpr(
    434                         "__cfaehm_try_terminate" ) );
     434                        "__cfaabi_ehm__try_terminate" ) );
    435435                std::list<Expression *>& args = caller->get_args();
    436436                args.push_back( nameOf( try_wrapper ) );
     
    486486
    487487                // struct __try_resume_node __resume_node
    488                 //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
     488                //      __attribute__((cleanup( __cfaabi_ehm__try_resume_cleanup )));
    489489                // ** unwinding of the stack here could cause problems **
    490490                // ** however I don't think that can happen currently **
    491                 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
     491                // __cfaabi_ehm__try_resume_setup( &__resume_node, resume_handler );
    492492
    493493                std::list< Attribute * > attributes;
     
    495495                        std::list< Expression * > attr_params;
    496496                        attr_params.push_back( new NameExpr(
    497                                 "__cfaehm_try_resume_cleanup" ) );
     497                                "__cfaabi_ehm__try_resume_cleanup" ) );
    498498                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
    499499                }
     
    514514
    515515                UntypedExpr *setup = new UntypedExpr( new NameExpr(
    516                         "__cfaehm_try_resume_setup" ) );
     516                        "__cfaabi_ehm__try_resume_setup" ) );
    517517                setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
    518518                setup->get_args().push_back( nameOf( resume_handler ) );
     
    539539        ObjectDecl * ExceptionMutatorCore::create_finally_hook(
    540540                        FunctionDecl * finally_wrapper ) {
    541                 // struct __cfaehm_cleanup_hook __finally_hook
     541                // struct __cfaabi_ehm__cleanup_hook __finally_hook
    542542                //      __attribute__((cleanup( finally_wrapper )));
    543543
     
    593593                        // Skip children?
    594594                        return;
    595                 } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) {
     595                } else if ( structDecl->get_name() == "__cfaabi_ehm__base_exception_t" ) {
    596596                        assert( nullptr == except_decl );
    597597                        except_decl = structDecl;
    598598                        init_func_types();
    599                 } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) {
     599                } else if ( structDecl->get_name() == "__cfaabi_ehm__try_resume_node" ) {
    600600                        assert( nullptr == node_decl );
    601601                        node_decl = structDecl;
    602                 } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) {
     602                } else if ( structDecl->get_name() == "__cfaabi_ehm__cleanup_hook" ) {
    603603                        assert( nullptr == hook_decl );
    604604                        hook_decl = structDecl;
  • src/ControlStruct/LabelFixer.cc

    r7030dab r71d6bd8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Jan 21 10:32:00 2020
    13 // Update Count     : 160
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:26:02 2019
     13// Update Count     : 159
    1414//
    1515
     
    2121#include "ControlStruct/LabelGenerator.h"  // for LabelGenerator
    2222#include "LabelFixer.h"
    23 #include "MLEMutator.h"                    // for MultiLevelExitMutator
     23#include "MLEMutator.h"                    // for MLEMutator
    2424#include "SynTree/Declaration.h"           // for FunctionDecl
    2525#include "SynTree/Expression.h"            // for NameExpr, Expression, Unty...
     
    4444
    4545        void LabelFixer::postvisit( FunctionDecl * functionDecl ) {
    46                 PassVisitor<MultiLevelExitMutator> mlem( resolveJumps(), generator );
    47                 // We start in the body so we can stop when we hit another FunctionDecl.
    48                 maybeMutate( functionDecl->statements, mlem );
     46                PassVisitor<MLEMutator> mlemut( resolveJumps(), generator );
     47                functionDecl->acceptMutator( mlemut );
    4948        }
    5049
     
    7675
    7776
    78         // Sets the definition of the labelTable entry to be the provided statement for every label in
    79         // the list parameter. Happens for every kind of statement.
     77        // sets the definition of the labelTable entry to be the provided statement for every label in the list
     78        // parameter. Happens for every kind of statement
    8079        Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {
    8180                assert( definition != 0 );
    8281                assert( llabel.size() > 0 );
     82
     83                Entry * e = new Entry( definition );
    8384
    8485                for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) {
     
    8687                        l.set_statement( definition ); // attach statement to the label to be used later
    8788                        if ( labelTable.find( l ) == labelTable.end() ) {
    88                                 // All labels on this statement need to use the same entry,
    89                                 // so this should only be created once.
     89                                // all labels on this statement need to use the same entry, so this should only be created once
    9090                                // undefined and unused until now, add an entry
    91                                 labelTable[ l ] = new Entry( definition );
     91                                labelTable[ l ] =  e;
    9292                        } else if ( labelTable[ l ]->defined() ) {
    9393                                // defined twice, error
    94                                 SemanticError( l.get_statement()->location,
    95                                         "Duplicate definition of label: " + l.get_name() );
    96                         } else {
     94                                SemanticError( l.get_statement()->location, "Duplicate definition of label: " + l.get_name() );
     95                        }       else {
    9796                                // used previously, but undefined until now -> link with this entry
    98                                 // Question: Is changing objects important?
    9997                                delete labelTable[ l ];
    100                                 labelTable[ l ] = new Entry( definition );
     98                                labelTable[ l ] = e;
    10199                        } // if
    102100                } // for
    103101
    104                 // Produce one of the labels attached to this statement to be temporarily used as the
    105                 // canonical label.
     102                // produce one of the labels attached to this statement to be temporarily used as the canonical label
    106103                return labelTable[ llabel.front() ]->get_label();
    107104        }
  • src/ControlStruct/MLEMutator.cc

    r7030dab r71d6bd8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jan 22 11:50:00 2020
    13 // Update Count     : 223
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue Oct 22 17:22:44 2019
     13// Update Count     : 220
    1414//
    1515
     
    3333
    3434namespace ControlStruct {
    35         MultiLevelExitMutator::~MultiLevelExitMutator() {
     35        MLEMutator::~MLEMutator() {
    3636                delete targetTable;
    3737                targetTable = 0;
    3838        }
    3939        namespace {
    40                 bool isLoop( const MultiLevelExitMutator::Entry & e ) {
    41                         return dynamic_cast< WhileStmt * >( e.get_controlStructure() )
    42                                 || dynamic_cast< ForStmt * >( e.get_controlStructure() );
    43                 }
    44                 bool isSwitch( const MultiLevelExitMutator::Entry & e ) {
    45                         return dynamic_cast< SwitchStmt *>( e.get_controlStructure() );
    46                 }
    47 
    48                 bool isBreakTarget( const MultiLevelExitMutator::Entry & e ) {
    49                         return isLoop( e ) || isSwitch( e )
    50                                 || dynamic_cast< CompoundStmt *>( e.get_controlStructure() );
    51                 }
    52                 bool isContinueTarget( const MultiLevelExitMutator::Entry & e ) {
    53                         return isLoop( e );
    54                 }
    55                 bool isFallthroughTarget( const MultiLevelExitMutator::Entry & e ) {
    56                         return dynamic_cast< CaseStmt *>( e.get_controlStructure() );
    57                 }
    58                 bool isFallthroughDefaultTarget( const MultiLevelExitMutator::Entry & e ) {
    59                         return isSwitch( e );
    60                 }
     40                bool isLoop( const MLEMutator::Entry & e ) { return dynamic_cast< WhileStmt * >( e.get_controlStructure() ) || dynamic_cast< ForStmt * >( e.get_controlStructure() ); }
     41                bool isSwitch( const MLEMutator::Entry & e ) { return dynamic_cast< SwitchStmt *>( e.get_controlStructure() ); }
     42
     43                bool isBreakTarget( const MLEMutator::Entry & e ) { return isLoop( e ) || isSwitch( e ) || dynamic_cast< CompoundStmt *>( e.get_controlStructure() ); }
     44                bool isContinueTarget( const MLEMutator::Entry & e ) { return isLoop( e ); }
     45                bool isFallthroughTarget( const MLEMutator::Entry & e ) { return dynamic_cast< CaseStmt *>( e.get_controlStructure() );; }
     46                bool isFallthroughDefaultTarget( const MLEMutator::Entry & e ) { return isSwitch( e ); }
    6147        } // namespace
    62 
    63         void MultiLevelExitMutator::premutate( FunctionDecl * ) {
    64                 visit_children = false;
    65         }
    6648
    6749        // break labels have to come after the statement they break out of, so mutate a statement, then if they inform us
    6850        // through the breakLabel field tha they need a place to jump to on a break statement, add the break label to the
    6951        // body of statements
    70         void MultiLevelExitMutator::fixBlock( std::list< Statement * > &kids, bool caseClause ) {
     52        void MLEMutator::fixBlock( std::list< Statement * > &kids, bool caseClause ) {
    7153                SemanticErrorException errors;
    7254
     
    9981        }
    10082
    101         void MultiLevelExitMutator::premutate( CompoundStmt *cmpndStmt ) {
     83        void MLEMutator::premutate( CompoundStmt *cmpndStmt ) {
    10284                visit_children = false;
    10385                bool labeledBlock = !(cmpndStmt->labels.empty());
     
    136118                        }
    137119                }
    138                 assertf( false, "Could not find label '%s' on statement %s",
    139                         originalTarget.get_name().c_str(), toString( stmt ).c_str() );
    140         }
    141 
    142 
    143         Statement *MultiLevelExitMutator::postmutate( BranchStmt *branchStmt )
    144                         throw ( SemanticErrorException ) {
     120                assertf( false, "Could not find label '%s' on statement %s", originalTarget.get_name().c_str(), toString( stmt ).c_str() );
     121        }
     122
     123
     124        Statement *MLEMutator::postmutate( BranchStmt *branchStmt ) throw ( SemanticErrorException ) {
    145125                std::string originalTarget = branchStmt->originalTarget;
    146126
     
    250230        }
    251231
    252         Statement *MultiLevelExitMutator::mutateLoop( Statement *bodyLoop, Entry &e ) {
     232        Statement *MLEMutator::mutateLoop( Statement *bodyLoop, Entry &e ) {
     233                // ensure loop body is a block
     234                CompoundStmt *newBody;
     235                if ( ! (newBody = dynamic_cast<CompoundStmt *>( bodyLoop )) ) {
     236                        newBody = new CompoundStmt();
     237                        newBody->get_kids().push_back( bodyLoop );
     238                } // if
     239
    253240                // only generate these when needed
    254                 if( !e.isContUsed() && !e.isBreakUsed() ) return bodyLoop;
    255 
    256                 // ensure loop body is a block
    257                 CompoundStmt * newBody = new CompoundStmt();
    258                 newBody->get_kids().push_back( bodyLoop );
    259241
    260242                if ( e.isContUsed() ) {
     
    273255
    274256        template< typename LoopClass >
    275         void MultiLevelExitMutator::prehandleLoopStmt( LoopClass * loopStmt ) {
     257        void MLEMutator::prehandleLoopStmt( LoopClass * loopStmt ) {
    276258                // remember this as the most recent enclosing loop, then mutate the body of the loop -- this will determine
    277259                // whether brkLabel and contLabel are used with branch statements and will recursively do the same to nested
     
    284266
    285267        template< typename LoopClass >
    286         Statement * MultiLevelExitMutator::posthandleLoopStmt( LoopClass * loopStmt ) {
     268        Statement * MLEMutator::posthandleLoopStmt( LoopClass * loopStmt ) {
    287269                assert( ! enclosingControlStructures.empty() );
    288270                Entry &e = enclosingControlStructures.back();
     
    295277        }
    296278
    297         void MultiLevelExitMutator::premutate( WhileStmt * whileStmt ) {
     279        void MLEMutator::premutate( WhileStmt * whileStmt ) {
    298280                return prehandleLoopStmt( whileStmt );
    299281        }
    300282
    301         void MultiLevelExitMutator::premutate( ForStmt * forStmt ) {
     283        void MLEMutator::premutate( ForStmt * forStmt ) {
    302284                return prehandleLoopStmt( forStmt );
    303285        }
    304286
    305         Statement * MultiLevelExitMutator::postmutate( WhileStmt * whileStmt ) {
     287        Statement * MLEMutator::postmutate( WhileStmt * whileStmt ) {
    306288                return posthandleLoopStmt( whileStmt );
    307289        }
    308290
    309         Statement * MultiLevelExitMutator::postmutate( ForStmt * forStmt ) {
     291        Statement * MLEMutator::postmutate( ForStmt * forStmt ) {
    310292                return posthandleLoopStmt( forStmt );
    311293        }
    312294
    313         void MultiLevelExitMutator::premutate( IfStmt * ifStmt ) {
     295        void MLEMutator::premutate( IfStmt * ifStmt ) {
    314296                // generate a label for breaking out of a labeled if
    315297                bool labeledBlock = !(ifStmt->get_labels().empty());
     
    321303        }
    322304
    323         Statement * MultiLevelExitMutator::postmutate( IfStmt * ifStmt ) {
     305        Statement * MLEMutator::postmutate( IfStmt * ifStmt ) {
    324306                bool labeledBlock = !(ifStmt->get_labels().empty());
    325307                if ( labeledBlock ) {
     
    331313        }
    332314
    333         void MultiLevelExitMutator::premutate( TryStmt * tryStmt ) {
     315        void MLEMutator::premutate( TryStmt * tryStmt ) {
    334316                // generate a label for breaking out of a labeled if
    335317                bool labeledBlock = !(tryStmt->get_labels().empty());
     
    341323        }
    342324
    343         Statement * MultiLevelExitMutator::postmutate( TryStmt * tryStmt ) {
     325        Statement * MLEMutator::postmutate( TryStmt * tryStmt ) {
    344326                bool labeledBlock = !(tryStmt->get_labels().empty());
    345327                if ( labeledBlock ) {
     
    351333        }
    352334
    353         void MultiLevelExitMutator::premutate( FinallyStmt * ) {
    354                 GuardAction([this, old = std::move(enclosingControlStructures)]() {
    355                         enclosingControlStructures = std::move(old);
    356                 });
    357                 enclosingControlStructures = std::list<Entry>();
    358                 GuardValue( inFinally );
    359                 inFinally = true;
    360         }
    361 
    362         void MultiLevelExitMutator::premutate( ReturnStmt *returnStmt ) {
    363                 if ( inFinally ) {
    364                         SemanticError( returnStmt->location, "'return' may not appear in a finally clause" );
    365                 }
    366         }
    367 
    368         void MultiLevelExitMutator::premutate( CaseStmt *caseStmt ) {
     335        void MLEMutator::premutate( CaseStmt *caseStmt ) {
    369336                visit_children = false;
    370337
     
    405372        }
    406373
    407         void MultiLevelExitMutator::premutate( SwitchStmt *switchStmt ) {
     374        void MLEMutator::premutate( SwitchStmt *switchStmt ) {
    408375                // generate a label for breaking out of a labeled switch
    409376                Label brkLabel = generator->newLabel("switchBreak", switchStmt);
     
    431398        }
    432399
    433         Statement * MultiLevelExitMutator::postmutate( SwitchStmt * switchStmt ) {
     400        Statement * MLEMutator::postmutate( SwitchStmt * switchStmt ) {
    434401                Entry &e = enclosingControlStructures.back();
    435402                assert ( e == switchStmt );
  • src/ControlStruct/MLEMutator.h

    r7030dab r71d6bd8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jan 22 11:50:00 2020
    13 // Update Count     : 48
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue Oct 22 17:22:47 2019
     13// Update Count     : 45
    1414//
    1515
     
    3030        class LabelGenerator;
    3131
    32         class MultiLevelExitMutator : public WithVisitorRef<MultiLevelExitMutator>,
    33                         public WithShortCircuiting, public WithGuards {
     32        class MLEMutator : public WithVisitorRef<MLEMutator>, public WithShortCircuiting, public WithGuards {
    3433          public:
    3534                class Entry;
    36                 MultiLevelExitMutator( std::map<Label, Statement *> *t, LabelGenerator *gen = 0 ) :
    37                         targetTable( t ), breakLabel(std::string("")), generator( gen ) {}
    38                 ~MultiLevelExitMutator();
    39 
    40                 void premutate( FunctionDecl * );
     35                MLEMutator( std::map<Label, Statement *> *t, LabelGenerator *gen = 0 ) : targetTable( t ), breakLabel(std::string("")), generator( gen ) {}
     36                ~MLEMutator();
    4137
    4238                void premutate( CompoundStmt *cmpndStmt );
     
    5147                void premutate( SwitchStmt *switchStmt );
    5248                Statement * postmutate( SwitchStmt *switchStmt );
    53                 void premutate( ReturnStmt *returnStmt );
    5449                void premutate( TryStmt *tryStmt );
    5550                Statement * postmutate( TryStmt *tryStmt );
    56                 void premutate( FinallyStmt *finallyStmt );
    5751
    5852                Statement *mutateLoop( Statement *bodyLoop, Entry &e );
     
    116110                Label breakLabel;
    117111                LabelGenerator *generator;
    118                 bool inFinally = false;
    119112
    120113                template< typename LoopClass >
  • src/ControlStruct/Mutate.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:22:07 2020
    13 // Update Count     : 10
     12// Last Modified On : Thu Aug  4 11:39:08 2016
     13// Update Count     : 9
    1414//
    1515
     
    3737                mutateAll( translationUnit, formut );
    3838        }
    39 } // namespace ControlStruct
     39} // namespace CodeGen
    4040
    4141// Local Variables: //
  • src/GenPoly/Box.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:40:34 2019
    13 // Update Count     : 347
     12// Last Modified On : Wed Jun 21 15:49:59 2017
     13// Update Count     : 346
    1414//
    1515
     
    3737#include "InitTweak/InitTweak.h"         // for getFunctionName, isAssignment
    3838#include "Lvalue.h"                      // for generalizedLvalue
     39#include "Parser/LinkageSpec.h"          // for C, Spec, Cforall, Intrinsic
    3940#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass
    4041#include "ResolvExpr/typeops.h"          // for typesCompatible
     
    4344#include "SymTab/Indexer.h"              // for Indexer
    4445#include "SymTab/Mangler.h"              // for Mangler
    45 #include "SynTree/LinkageSpec.h"         // for C, Spec, Cforall, Intrinsic
    4646#include "SynTree/Attribute.h"           // for Attribute
    4747#include "SynTree/Constant.h"            // for Constant
  • src/GenPoly/Lvalue.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:14:38 2019
    13 // Update Count     : 7
     12// Last Modified On : Fri Mar 17 09:11:18 2017
     13// Update Count     : 5
    1414//
    1515
     
    1717#include <string>                        // for string
    1818
    19 #include "Common/UniqueName.h"
    2019#include "Common/PassVisitor.h"
    2120#include "GenPoly.h"                     // for isPolyType
     
    2322
    2423#include "InitTweak/InitTweak.h"
     24#include "Parser/LinkageSpec.h"          // for Spec, isBuiltin, Intrinsic
    2525#include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    2626#include "ResolvExpr/Unify.h"            // for unify
    2727#include "ResolvExpr/typeops.h"
    2828#include "SymTab/Indexer.h"              // for Indexer
    29 #include "SynTree/LinkageSpec.h"         // for Spec, isBuiltin, Intrinsic
    3029#include "SynTree/Declaration.h"         // for Declaration, FunctionDecl
    3130#include "SynTree/Expression.h"          // for Expression, ConditionalExpr
     
    6160                }
    6261
    63                 struct ReferenceConversions final : public WithStmtsToAdd, public WithGuards {
     62                struct ReferenceConversions final : public WithStmtsToAdd {
    6463                        Expression * postmutate( CastExpr * castExpr );
    6564                        Expression * postmutate( AddressExpr * addrExpr );
     
    7271
    7372                struct FixIntrinsicResult final : public WithGuards {
    74                         enum {
    75                                 NoSkip,
    76                                 Skip,
    77                                 SkipInProgress
    78                         } skip = NoSkip;
    79 
    80                         void premutate( AsmExpr * ) { GuardValue( skip ); skip = Skip; }
    81                         void premutate( ApplicationExpr * ) { GuardValue( skip ); skip = (skip == Skip) ? SkipInProgress : NoSkip; }
    82 
    83 
    8473                        Expression * postmutate( ApplicationExpr * appExpr );
    8574                        void premutate( FunctionDecl * funcDecl );
     
    173162
    174163                Expression * FixIntrinsicResult::postmutate( ApplicationExpr * appExpr ) {
    175                         if ( skip != SkipInProgress && isIntrinsicReference( appExpr ) ) {
     164                        if ( isIntrinsicReference( appExpr ) ) {
    176165                                // eliminate reference types from intrinsic applications - now they return lvalues
    177166                                ReferenceType * result = strict_dynamic_cast< ReferenceType * >( appExpr->result );
  • src/GenPoly/Specialize.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:40:49 2019
    13 // Update Count     : 32
     12// Last Modified On : Thu Mar 16 07:53:59 2017
     13// Update Count     : 31
    1414//
    1515
     
    2727#include "GenPoly.h"                     // for getFunctionType
    2828#include "InitTweak/InitTweak.h"         // for isIntrinsicCallExpr
     29#include "Parser/LinkageSpec.h"          // for C
    2930#include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
    3031#include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
    3132#include "Specialize.h"
    32 #include "SynTree/LinkageSpec.h"         // for C
    3333#include "SynTree/Attribute.h"           // for Attribute
    3434#include "SynTree/Declaration.h"         // for FunctionDecl, DeclarationWit...
  • src/InitTweak/FixGlobalInit.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 04 15:14:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:41:10 2019
    13 // Update Count     : 19
     12// Last Modified On : Thu Mar 16 07:53:11 2017
     13// Update Count     : 18
    1414//
    1515
     
    2323#include "Common/UniqueName.h"     // for UniqueName
    2424#include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    25 #include "SynTree/LinkageSpec.h"   // for C
     25#include "Parser/LinkageSpec.h"    // for C
    2626#include "SynTree/Attribute.h"     // for Attribute
    2727#include "SynTree/Constant.h"      // for Constant
  • src/InitTweak/FixInit.cc

    r7030dab r71d6bd8  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 04:17:07 2020
    13 // Update Count     : 82
     12// Last Modified On : Wed Feb 13 18:15:56 2019
     13// Update Count     : 76
    1414//
    1515#include "FixInit.h"
     
    3838#include "GenPoly/GenPoly.h"           // for getFunctionType
    3939#include "InitTweak.h"                 // for getFunctionName, getCallArg
     40#include "Parser/LinkageSpec.h"        // for C, Spec, Cforall, isBuiltin
    4041#include "ResolvExpr/Resolver.h"       // for findVoidExpression
    4142#include "ResolvExpr/typeops.h"        // for typesCompatible
     
    4344#include "SymTab/Indexer.h"            // for Indexer
    4445#include "SymTab/Mangler.h"            // for Mangler
    45 #include "SynTree/LinkageSpec.h"       // for C, Spec, Cforall, isBuiltin
    4646#include "SynTree/Attribute.h"         // for Attribute
    4747#include "SynTree/Constant.h"          // for Constant
     
    745745                }
    746746
    747                 // to prevent warnings ('_unq0' may be used uninitialized in this function),
     747                // to prevent warnings (ā€˜_unq0’ may be used uninitialized in this function),
    748748                // insert an appropriate zero initializer for UniqueExpr temporaries.
    749749                Initializer * makeInit( Type * t ) {
  • src/InitTweak/FixInit.h

    r7030dab r71d6bd8  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 07:54:50 2020
    13 // Update Count     : 8
     12// Last Modified On : Sat Jul 22 09:31:06 2017
     13// Update Count     : 6
    1414//
    1515
     
    2222
    2323namespace InitTweak {
    24         /// replace constructor initializers with expression statements and unwrap basic C-style initializers
     24  /// replace constructor initializers with expression statements
     25  /// and unwrap basic C-style initializers
    2526        void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
    2627} // namespace
  • src/InitTweak/GenInit.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:15:10 2019
    13 // Update Count     : 184
     12// Last Modified On : Fri Mar 17 09:12:36 2017
     13// Update Count     : 183
    1414//
    1515#include "GenInit.h"
     
    3434#include "GenPoly/ScopedSet.h"         // for ScopedSet, ScopedSet<>::const_iter...
    3535#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
     36#include "Parser/LinkageSpec.h"        // for isOverridable, C
    3637#include "ResolvExpr/Resolver.h"
    3738#include "SymTab/Autogen.h"            // for genImplicitCall
    3839#include "SymTab/Mangler.h"            // for Mangler
    39 #include "SynTree/LinkageSpec.h"       // for isOverridable, C
    4040#include "SynTree/Declaration.h"       // for ObjectDecl, DeclarationWithType
    4141#include "SynTree/Expression.h"        // for VariableExpr, UntypedExpr, Address...
  • src/InitTweak/InitTweak.cc

    r7030dab r71d6bd8  
    1010// Created On       : Fri May 13 11:26:36 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:15:52 2019
    13 // Update Count     : 8
     12// Last Modified On : Thu Jul 25 22:21:48 2019
     13// Update Count     : 7
    1414//
    1515
     
    3333#include "GenPoly/GenPoly.h"       // for getFunctionType
    3434#include "InitTweak.h"
     35#include "Parser/LinkageSpec.h"    // for Spec, isBuiltin, Intrinsic
    3536#include "ResolvExpr/typeops.h"    // for typesCompatibleIgnoreQualifiers
    3637#include "SymTab/Autogen.h"
    3738#include "SymTab/Indexer.h"        // for Indexer
    38 #include "SynTree/LinkageSpec.h"   // for Spec, isBuiltin, Intrinsic
    3939#include "SynTree/Attribute.h"     // for Attribute
    4040#include "SynTree/Constant.h"      // for Constant
  • src/MakeLibCfa.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 10:33:33 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:49:49 2020
    13 // Update Count     : 45
     12// Last Modified On : Sun Feb 17 21:08:09 2019
     13// Update Count     : 41
    1414//
    1515
     
    2323#include "Common/SemanticError.h"   // for SemanticError
    2424#include "Common/UniqueName.h"      // for UniqueName
    25 #include "SynTree/LinkageSpec.h"    // for Spec, Intrinsic, C
     25#include "Parser/LinkageSpec.h"     // for Spec, Intrinsic, C
    2626#include "SynTree/Declaration.h"    // for FunctionDecl, ObjectDecl, Declara...
    2727#include "SynTree/Expression.h"     // for NameExpr, UntypedExpr, VariableExpr
     
    9696
    9797                        FunctionDecl *funcDecl = origFuncDecl->clone();
    98                         const CodeGen::OperatorInfo * opInfo;
    99                         opInfo = CodeGen::operatorLookup( funcDecl->get_name() );
    100                         assert( opInfo );
     98                        CodeGen::OperatorInfo opInfo;
     99                        bool lookResult = CodeGen::operatorLookup( funcDecl->get_name(), opInfo );
     100                        assert( lookResult );
    101101                        assert( ! funcDecl->get_statements() );
    102102                        // build a recursive call - this is okay, as the call will actually be codegen'd using operator syntax
     
    120120
    121121                        Statement * stmt = nullptr;
    122                         switch ( opInfo->type ) {
     122                        switch ( opInfo.type ) {
    123123                          case CodeGen::OT_INDEX:
    124124                          case CodeGen::OT_CALL:
  • src/Makefile.in

    r7030dab r71d6bd8  
    213213        SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \
    214214        SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT)
    215 am__objects_7 = SynTree/AddressExpr.$(OBJEXT) \
    216         SynTree/AggregateDecl.$(OBJEXT) \
    217         SynTree/ApplicationExpr.$(OBJEXT) SynTree/ArrayType.$(OBJEXT) \
    218         SynTree/AttrType.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
    219         SynTree/BasicType.$(OBJEXT) SynTree/CommaExpr.$(OBJEXT) \
    220         SynTree/CompoundStmt.$(OBJEXT) SynTree/Constant.$(OBJEXT) \
    221         SynTree/DeclReplacer.$(OBJEXT) SynTree/DeclStmt.$(OBJEXT) \
     215am__objects_7 = SynTree/Type.$(OBJEXT) SynTree/VoidType.$(OBJEXT) \
     216        SynTree/BasicType.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \
     217        SynTree/ArrayType.$(OBJEXT) SynTree/ReferenceType.$(OBJEXT) \
     218        SynTree/FunctionType.$(OBJEXT) \
     219        SynTree/ReferenceToType.$(OBJEXT) SynTree/TupleType.$(OBJEXT) \
     220        SynTree/TypeofType.$(OBJEXT) SynTree/AttrType.$(OBJEXT) \
     221        SynTree/VarArgsType.$(OBJEXT) SynTree/ZeroOneType.$(OBJEXT) \
     222        SynTree/Constant.$(OBJEXT) SynTree/Expression.$(OBJEXT) \
     223        SynTree/TupleExpr.$(OBJEXT) SynTree/CommaExpr.$(OBJEXT) \
     224        SynTree/TypeExpr.$(OBJEXT) SynTree/ApplicationExpr.$(OBJEXT) \
     225        SynTree/AddressExpr.$(OBJEXT) SynTree/Statement.$(OBJEXT) \
     226        SynTree/CompoundStmt.$(OBJEXT) SynTree/DeclStmt.$(OBJEXT) \
    222227        SynTree/Declaration.$(OBJEXT) \
    223228        SynTree/DeclarationWithType.$(OBJEXT) \
    224         SynTree/Expression.$(OBJEXT) SynTree/FunctionDecl.$(OBJEXT) \
    225         SynTree/FunctionType.$(OBJEXT) SynTree/Initializer.$(OBJEXT) \
    226         SynTree/LinkageSpec.$(OBJEXT) SynTree/NamedTypeDecl.$(OBJEXT) \
    227         SynTree/ObjectDecl.$(OBJEXT) SynTree/PointerType.$(OBJEXT) \
    228         SynTree/ReferenceToType.$(OBJEXT) \
    229         SynTree/ReferenceType.$(OBJEXT) SynTree/Statement.$(OBJEXT) \
    230         SynTree/TupleExpr.$(OBJEXT) SynTree/TupleType.$(OBJEXT) \
    231         SynTree/Type.$(OBJEXT) SynTree/TypeDecl.$(OBJEXT) \
    232         SynTree/TypeExpr.$(OBJEXT) SynTree/TypeSubstitution.$(OBJEXT) \
    233         SynTree/TypeofType.$(OBJEXT) SynTree/VarArgsType.$(OBJEXT) \
    234         SynTree/VoidType.$(OBJEXT) SynTree/ZeroOneType.$(OBJEXT)
     229        SynTree/ObjectDecl.$(OBJEXT) SynTree/FunctionDecl.$(OBJEXT) \
     230        SynTree/AggregateDecl.$(OBJEXT) \
     231        SynTree/NamedTypeDecl.$(OBJEXT) SynTree/TypeDecl.$(OBJEXT) \
     232        SynTree/Initializer.$(OBJEXT) \
     233        SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
     234        SynTree/DeclReplacer.$(OBJEXT)
    235235am__objects_8 = CompilationState.$(OBJEXT) $(am__objects_1) \
    236236        $(am__objects_2) Concurrency/Keywords.$(OBJEXT) \
    237237        $(am__objects_3) $(am__objects_4) GenPoly/GenPoly.$(OBJEXT) \
    238238        GenPoly/Lvalue.$(OBJEXT) InitTweak/GenInit.$(OBJEXT) \
    239         InitTweak/InitTweak.$(OBJEXT) $(am__objects_5) \
    240         $(am__objects_6) SymTab/Demangle.$(OBJEXT) $(am__objects_7) \
    241         Tuples/TupleAssignment.$(OBJEXT) \
     239        InitTweak/InitTweak.$(OBJEXT) Parser/LinkageSpec.$(OBJEXT) \
     240        $(am__objects_5) $(am__objects_6) SymTab/Demangle.$(OBJEXT) \
     241        $(am__objects_7) Tuples/TupleAssignment.$(OBJEXT) \
    242242        Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
    243243        Tuples/Tuples.$(OBJEXT) Validate/HandleAttributes.$(OBJEXT) \
     
    262262        InitTweak/GenInit.$(OBJEXT) InitTweak/FixInit.$(OBJEXT) \
    263263        InitTweak/FixGlobalInit.$(OBJEXT) \
    264         InitTweak/InitTweak.$(OBJEXT) Parser/DeclarationNode.$(OBJEXT) \
    265         Parser/ExpressionNode.$(OBJEXT) \
    266         Parser/InitializerNode.$(OBJEXT) Parser/ParseNode.$(OBJEXT) \
    267         Parser/StatementNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \
    268         Parser/TypedefTable.$(OBJEXT) Parser/lex.$(OBJEXT) \
    269         Parser/parser.$(OBJEXT) Parser/parserutility.$(OBJEXT) \
     264        InitTweak/InitTweak.$(OBJEXT) Parser/parser.$(OBJEXT) \
     265        Parser/lex.$(OBJEXT) Parser/TypedefTable.$(OBJEXT) \
     266        Parser/ParseNode.$(OBJEXT) Parser/DeclarationNode.$(OBJEXT) \
     267        Parser/ExpressionNode.$(OBJEXT) Parser/StatementNode.$(OBJEXT) \
     268        Parser/InitializerNode.$(OBJEXT) Parser/TypeData.$(OBJEXT) \
     269        Parser/LinkageSpec.$(OBJEXT) Parser/parserutility.$(OBJEXT) \
    270270        $(am__objects_5) ResolvExpr/AlternativePrinter.$(OBJEXT) \
    271271        $(am__objects_6) $(am__objects_7) \
     
    560560        InitTweak/GenInit.cc InitTweak/FixInit.cc \
    561561        InitTweak/FixGlobalInit.cc InitTweak/InitTweak.cc \
    562         Parser/DeclarationNode.cc Parser/ExpressionNode.cc \
    563         Parser/InitializerNode.cc Parser/ParseNode.cc \
    564         Parser/StatementNode.cc Parser/TypeData.cc \
    565         Parser/TypedefTable.cc Parser/lex.ll Parser/parser.yy \
    566         Parser/parserutility.cc $(SRC_RESOLVEXPR) \
    567         ResolvExpr/AlternativePrinter.cc $(SRC_SYMTAB) $(SRC_SYNTREE) \
    568         Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
    569         Tuples/Explode.cc Tuples/Tuples.cc \
     562        Parser/parser.yy Parser/lex.ll Parser/TypedefTable.cc \
     563        Parser/ParseNode.cc Parser/DeclarationNode.cc \
     564        Parser/ExpressionNode.cc Parser/StatementNode.cc \
     565        Parser/InitializerNode.cc Parser/TypeData.cc \
     566        Parser/LinkageSpec.cc Parser/parserutility.cc \
     567        $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc \
     568        $(SRC_SYMTAB) $(SRC_SYNTREE) Tuples/TupleAssignment.cc \
     569        Tuples/TupleExpansion.cc Tuples/Explode.cc Tuples/Tuples.cc \
    570570        Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc \
    571571        Virtual/ExpandCasts.cc
     
    573573        Concurrency/Keywords.cc $(SRC_COMMON) $(SRC_CONTROLSTRUCT) \
    574574        GenPoly/GenPoly.cc GenPoly/Lvalue.cc InitTweak/GenInit.cc \
    575         InitTweak/InitTweak.cc $(SRC_RESOLVEXPR) $(SRC_SYMTAB) \
    576         SymTab/Demangle.cc $(SRC_SYNTREE) Tuples/TupleAssignment.cc \
    577         Tuples/TupleExpansion.cc Tuples/Explode.cc Tuples/Tuples.cc \
     575        InitTweak/InitTweak.cc Parser/LinkageSpec.cc $(SRC_RESOLVEXPR) \
     576        $(SRC_SYMTAB) SymTab/Demangle.cc $(SRC_SYNTREE) \
     577        Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
     578        Tuples/Explode.cc Tuples/Tuples.cc \
    578579        Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
    579580MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
     
    664665
    665666SRC_SYNTREE = \
     667      SynTree/Type.cc \
     668      SynTree/VoidType.cc \
     669      SynTree/BasicType.cc \
     670      SynTree/PointerType.cc \
     671      SynTree/ArrayType.cc \
     672      SynTree/ReferenceType.cc \
     673      SynTree/FunctionType.cc \
     674      SynTree/ReferenceToType.cc \
     675      SynTree/TupleType.cc \
     676      SynTree/TypeofType.cc \
     677      SynTree/AttrType.cc \
     678      SynTree/VarArgsType.cc \
     679      SynTree/ZeroOneType.cc \
     680      SynTree/Constant.cc \
     681      SynTree/Expression.cc \
     682      SynTree/TupleExpr.cc \
     683      SynTree/CommaExpr.cc \
     684      SynTree/TypeExpr.cc \
     685      SynTree/ApplicationExpr.cc \
    666686      SynTree/AddressExpr.cc \
    667       SynTree/AggregateDecl.cc \
    668       SynTree/ApplicationExpr.cc \
    669       SynTree/ArrayType.cc \
    670       SynTree/AttrType.cc \
    671       SynTree/Attribute.cc \
    672       SynTree/BasicType.cc \
    673       SynTree/CommaExpr.cc \
     687      SynTree/Statement.cc \
    674688      SynTree/CompoundStmt.cc \
    675       SynTree/Constant.cc \
    676       SynTree/DeclReplacer.cc \
    677689      SynTree/DeclStmt.cc \
    678690      SynTree/Declaration.cc \
    679691      SynTree/DeclarationWithType.cc \
    680       SynTree/Expression.cc \
     692      SynTree/ObjectDecl.cc \
    681693      SynTree/FunctionDecl.cc \
    682       SynTree/FunctionType.cc \
     694      SynTree/AggregateDecl.cc \
     695      SynTree/NamedTypeDecl.cc \
     696      SynTree/TypeDecl.cc \
    683697      SynTree/Initializer.cc \
    684       SynTree/LinkageSpec.cc \
    685       SynTree/NamedTypeDecl.cc \
    686       SynTree/ObjectDecl.cc \
    687       SynTree/PointerType.cc \
    688       SynTree/ReferenceToType.cc \
    689       SynTree/ReferenceType.cc \
    690       SynTree/Statement.cc \
    691       SynTree/TupleExpr.cc \
    692       SynTree/TupleType.cc \
    693       SynTree/Type.cc \
    694       SynTree/TypeDecl.cc \
    695       SynTree/TypeExpr.cc \
    696698      SynTree/TypeSubstitution.cc \
    697       SynTree/TypeofType.cc \
    698       SynTree/VarArgsType.cc \
    699       SynTree/VoidType.cc \
    700       SynTree/ZeroOneType.cc
     699      SynTree/Attribute.cc \
     700      SynTree/DeclReplacer.cc
    701701
    702702
     
    873873InitTweak/InitTweak.$(OBJEXT): InitTweak/$(am__dirstamp) \
    874874        InitTweak/$(DEPDIR)/$(am__dirstamp)
     875Parser/$(am__dirstamp):
     876        @$(MKDIR_P) Parser
     877        @: > Parser/$(am__dirstamp)
     878Parser/$(DEPDIR)/$(am__dirstamp):
     879        @$(MKDIR_P) Parser/$(DEPDIR)
     880        @: > Parser/$(DEPDIR)/$(am__dirstamp)
     881Parser/LinkageSpec.$(OBJEXT): Parser/$(am__dirstamp) \
     882        Parser/$(DEPDIR)/$(am__dirstamp)
    875883ResolvExpr/$(am__dirstamp):
    876884        @$(MKDIR_P) ResolvExpr
     
    953961        @$(MKDIR_P) SynTree/$(DEPDIR)
    954962        @: > SynTree/$(DEPDIR)/$(am__dirstamp)
     963SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
     964        SynTree/$(DEPDIR)/$(am__dirstamp)
     965SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
     966        SynTree/$(DEPDIR)/$(am__dirstamp)
     967SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
     968        SynTree/$(DEPDIR)/$(am__dirstamp)
     969SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
     970        SynTree/$(DEPDIR)/$(am__dirstamp)
     971SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
     972        SynTree/$(DEPDIR)/$(am__dirstamp)
     973SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
     974        SynTree/$(DEPDIR)/$(am__dirstamp)
     975SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
     976        SynTree/$(DEPDIR)/$(am__dirstamp)
     977SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
     978        SynTree/$(DEPDIR)/$(am__dirstamp)
     979SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
     980        SynTree/$(DEPDIR)/$(am__dirstamp)
     981SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
     982        SynTree/$(DEPDIR)/$(am__dirstamp)
     983SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
     984        SynTree/$(DEPDIR)/$(am__dirstamp)
     985SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
     986        SynTree/$(DEPDIR)/$(am__dirstamp)
     987SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
     988        SynTree/$(DEPDIR)/$(am__dirstamp)
     989SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
     990        SynTree/$(DEPDIR)/$(am__dirstamp)
     991SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
     992        SynTree/$(DEPDIR)/$(am__dirstamp)
     993SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     994        SynTree/$(DEPDIR)/$(am__dirstamp)
     995SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     996        SynTree/$(DEPDIR)/$(am__dirstamp)
     997SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     998        SynTree/$(DEPDIR)/$(am__dirstamp)
     999SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     1000        SynTree/$(DEPDIR)/$(am__dirstamp)
    9551001SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    9561002        SynTree/$(DEPDIR)/$(am__dirstamp)
     1003SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
     1004        SynTree/$(DEPDIR)/$(am__dirstamp)
     1005SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     1006        SynTree/$(DEPDIR)/$(am__dirstamp)
     1007SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     1008        SynTree/$(DEPDIR)/$(am__dirstamp)
     1009SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
     1010        SynTree/$(DEPDIR)/$(am__dirstamp)
     1011SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1012        SynTree/$(DEPDIR)/$(am__dirstamp)
     1013SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     1014        SynTree/$(DEPDIR)/$(am__dirstamp)
     1015SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     1016        SynTree/$(DEPDIR)/$(am__dirstamp)
    9571017SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    9581018        SynTree/$(DEPDIR)/$(am__dirstamp)
    959 SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    960         SynTree/$(DEPDIR)/$(am__dirstamp)
    961 SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
    962         SynTree/$(DEPDIR)/$(am__dirstamp)
    963 SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1019SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     1020        SynTree/$(DEPDIR)/$(am__dirstamp)
     1021SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     1022        SynTree/$(DEPDIR)/$(am__dirstamp)
     1023SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
     1024        SynTree/$(DEPDIR)/$(am__dirstamp)
     1025SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
    9641026        SynTree/$(DEPDIR)/$(am__dirstamp)
    9651027SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
    9661028        SynTree/$(DEPDIR)/$(am__dirstamp)
    967 SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
    968         SynTree/$(DEPDIR)/$(am__dirstamp)
    969 SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    970         SynTree/$(DEPDIR)/$(am__dirstamp)
    971 SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    972         SynTree/$(DEPDIR)/$(am__dirstamp)
    973 SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
    974         SynTree/$(DEPDIR)/$(am__dirstamp)
    9751029SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
    976         SynTree/$(DEPDIR)/$(am__dirstamp)
    977 SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    978         SynTree/$(DEPDIR)/$(am__dirstamp)
    979 SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
    980         SynTree/$(DEPDIR)/$(am__dirstamp)
    981 SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
    982         SynTree/$(DEPDIR)/$(am__dirstamp)
    983 SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
    984         SynTree/$(DEPDIR)/$(am__dirstamp)
    985 SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    986         SynTree/$(DEPDIR)/$(am__dirstamp)
    987 SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
    988         SynTree/$(DEPDIR)/$(am__dirstamp)
    989 SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
    990         SynTree/$(DEPDIR)/$(am__dirstamp)
    991 SynTree/LinkageSpec.$(OBJEXT): SynTree/$(am__dirstamp) \
    992         SynTree/$(DEPDIR)/$(am__dirstamp)
    993 SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    994         SynTree/$(DEPDIR)/$(am__dirstamp)
    995 SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    996         SynTree/$(DEPDIR)/$(am__dirstamp)
    997 SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
    998         SynTree/$(DEPDIR)/$(am__dirstamp)
    999 SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1000         SynTree/$(DEPDIR)/$(am__dirstamp)
    1001 SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1002         SynTree/$(DEPDIR)/$(am__dirstamp)
    1003 SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
    1004         SynTree/$(DEPDIR)/$(am__dirstamp)
    1005 SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    1006         SynTree/$(DEPDIR)/$(am__dirstamp)
    1007 SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1008         SynTree/$(DEPDIR)/$(am__dirstamp)
    1009 SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
    1010         SynTree/$(DEPDIR)/$(am__dirstamp)
    1011 SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    1012         SynTree/$(DEPDIR)/$(am__dirstamp)
    1013 SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    1014         SynTree/$(DEPDIR)/$(am__dirstamp)
    1015 SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
    1016         SynTree/$(DEPDIR)/$(am__dirstamp)
    1017 SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1018         SynTree/$(DEPDIR)/$(am__dirstamp)
    1019 SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1020         SynTree/$(DEPDIR)/$(am__dirstamp)
    1021 SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1022         SynTree/$(DEPDIR)/$(am__dirstamp)
    1023 SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
    10241030        SynTree/$(DEPDIR)/$(am__dirstamp)
    10251031Tuples/$(am__dirstamp):
     
    11381144InitTweak/FixGlobalInit.$(OBJEXT): InitTweak/$(am__dirstamp) \
    11391145        InitTweak/$(DEPDIR)/$(am__dirstamp)
    1140 Parser/$(am__dirstamp):
    1141         @$(MKDIR_P) Parser
    1142         @: > Parser/$(am__dirstamp)
    1143 Parser/$(DEPDIR)/$(am__dirstamp):
    1144         @$(MKDIR_P) Parser/$(DEPDIR)
    1145         @: > Parser/$(DEPDIR)/$(am__dirstamp)
     1146Parser/parser.hh: Parser/parser.cc
     1147        @if test ! -f $@; then rm -f Parser/parser.cc; else :; fi
     1148        @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) Parser/parser.cc; else :; fi
     1149Parser/parser.$(OBJEXT): Parser/$(am__dirstamp) \
     1150        Parser/$(DEPDIR)/$(am__dirstamp)
     1151Parser/lex.$(OBJEXT): Parser/$(am__dirstamp) \
     1152        Parser/$(DEPDIR)/$(am__dirstamp)
     1153Parser/TypedefTable.$(OBJEXT): Parser/$(am__dirstamp) \
     1154        Parser/$(DEPDIR)/$(am__dirstamp)
     1155Parser/ParseNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1156        Parser/$(DEPDIR)/$(am__dirstamp)
    11461157Parser/DeclarationNode.$(OBJEXT): Parser/$(am__dirstamp) \
    11471158        Parser/$(DEPDIR)/$(am__dirstamp)
    11481159Parser/ExpressionNode.$(OBJEXT): Parser/$(am__dirstamp) \
    11491160        Parser/$(DEPDIR)/$(am__dirstamp)
     1161Parser/StatementNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1162        Parser/$(DEPDIR)/$(am__dirstamp)
    11501163Parser/InitializerNode.$(OBJEXT): Parser/$(am__dirstamp) \
    11511164        Parser/$(DEPDIR)/$(am__dirstamp)
    1152 Parser/ParseNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1153         Parser/$(DEPDIR)/$(am__dirstamp)
    1154 Parser/StatementNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1155         Parser/$(DEPDIR)/$(am__dirstamp)
    11561165Parser/TypeData.$(OBJEXT): Parser/$(am__dirstamp) \
    1157         Parser/$(DEPDIR)/$(am__dirstamp)
    1158 Parser/TypedefTable.$(OBJEXT): Parser/$(am__dirstamp) \
    1159         Parser/$(DEPDIR)/$(am__dirstamp)
    1160 Parser/lex.$(OBJEXT): Parser/$(am__dirstamp) \
    1161         Parser/$(DEPDIR)/$(am__dirstamp)
    1162 Parser/parser.hh: Parser/parser.cc
    1163         @if test ! -f $@; then rm -f Parser/parser.cc; else :; fi
    1164         @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) Parser/parser.cc; else :; fi
    1165 Parser/parser.$(OBJEXT): Parser/$(am__dirstamp) \
    11661166        Parser/$(DEPDIR)/$(am__dirstamp)
    11671167Parser/parserutility.$(OBJEXT): Parser/$(am__dirstamp) \
     
    12751275@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/ExpressionNode.Po@am__quote@
    12761276@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/InitializerNode.Po@am__quote@
     1277@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/LinkageSpec.Po@am__quote@
    12771278@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/ParseNode.Po@am__quote@
    12781279@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/StatementNode.Po@am__quote@
     
    13331334@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/FunctionType.Po@am__quote@
    13341335@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/Initializer.Po@am__quote@
    1335 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/LinkageSpec.Po@am__quote@
    13361336@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/NamedTypeDecl.Po@am__quote@
    13371337@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/ObjectDecl.Po@am__quote@
  • src/Parser/DeclarationNode.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:32:22 2019
    13 // Update Count     : 1133
     12// Last Modified On : Thu Jul 25 22:17:10 2019
     13// Update Count     : 1116
    1414//
    1515
     
    2424#include "Common/UniqueName.h"     // for UniqueName
    2525#include "Common/utility.h"        // for maybeClone, maybeBuild, CodeLocation
     26#include "Parser/LinkageSpec.h"    // for Spec, linkageName, Cforall
    2627#include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
    27 #include "SynTree/LinkageSpec.h"   // for Spec, linkageName, Cforall
    2828#include "SynTree/Attribute.h"     // for Attribute
    2929#include "SynTree/Declaration.h"   // for TypeDecl, ObjectDecl, Declaration
     
    4747const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" };
    4848const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" };
     49const char * DeclarationNode::aggregateNames[] = { "struct", "union", "trait", "coroutine", "monitor", "thread", "NoAggregateNames" };
     50const char * DeclarationNode::typeClassNames[] = { "otype", "dtype", "ftype", "NoTypeClassNames" };
    4951const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" };
    5052
     
    5759
    5860//      variable.name = nullptr;
    59         variable.tyClass = TypeDecl::NUMBER_OF_KINDS;
     61        variable.tyClass = NoTypeClass;
    6062        variable.assertions = nullptr;
    6163        variable.initializer = nullptr;
     
    133135
    134136        if ( linkage != LinkageSpec::Cforall ) {
    135                 os << LinkageSpec::name( linkage ) << " ";
     137                os << LinkageSpec::linkageName( linkage ) << " ";
    136138        } // if
    137139
     
    265267}
    266268
    267 DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
     269DeclarationNode * DeclarationNode::newAggregate( Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
    268270        DeclarationNode * newnode = new DeclarationNode;
    269271        newnode->type = new TypeData( TypeData::Aggregate );
     
    311313} // DeclarationNode::newFromTypeGen
    312314
    313 DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
     315DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, const string * name ) {
    314316        DeclarationNode * newnode = new DeclarationNode;
    315317        newnode->type = nullptr;
     
    326328        newnode->type = new TypeData( TypeData::Aggregate );
    327329        newnode->type->aggregate.name = name;
    328         newnode->type->aggregate.kind = AggregateDecl::Trait;
     330        newnode->type->aggregate.kind = Trait;
    329331        newnode->type->aggregate.params = params;
    330332        newnode->type->aggregate.fields = asserts;
     
    336338        newnode->type = new TypeData( TypeData::AggregateInst );
    337339        newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
    338         newnode->type->aggInst.aggregate->aggregate.kind = AggregateDecl::Trait;
     340        newnode->type->aggInst.aggregate->aggregate.kind = Trait;
    339341        newnode->type->aggInst.aggregate->aggregate.name = name;
    340342        newnode->type->aggInst.params = params;
     
    669671
    670672DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
    671         if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
     673        if ( variable.tyClass != NoTypeClass ) {
    672674                if ( variable.assertions ) {
    673675                        variable.assertions->appendList( assertions );
     
    874876
    875877DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
    876         assertf( variable.tyClass != TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
     878        assertf( variable.tyClass != NoTypeClass, "Called addTypeInitializer on something that isn't a type variable." );
    877879        variable.initializer = init;
    878880        return this;
     
    10731075        } // if
    10741076
    1075         if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
     1077        if ( variable.tyClass != NoTypeClass ) {
    10761078                // otype is internally converted to dtype + otype parameters
    10771079                static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype };
    1078                 static_assert( sizeof(kindMap)/sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
     1080                assertf( sizeof(kindMap)/sizeof(kindMap[0]) == NoTypeClass, "DeclarationNode::build: kindMap is out of sync." );
    10791081                assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
    1080                 TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype, variable.initializer ? variable.initializer->buildType() : nullptr );
     1082                TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == Otype, variable.initializer ? variable.initializer->buildType() : nullptr );
    10811083                buildList( variable.assertions, ret->get_assertions() );
    10821084                return ret;
  • src/Parser/ExpressionNode.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 18 21:14:58 2019
    13 // Update Count     : 981
     12// Last Modified On : Sun Aug  4 20:57:55 2019
     13// Update Count     : 978
    1414//
    1515
     
    265265        static const BasicType::Kind kind[2][12] = {
    266266                { BasicType::Float, BasicType::Double, BasicType::LongDouble, BasicType::uuFloat80, BasicType::uuFloat128, BasicType::uFloat16, BasicType::uFloat32, BasicType::uFloat32x, BasicType::uFloat64, BasicType::uFloat64x, BasicType::uFloat128, BasicType::uFloat128x },
    267                 { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::NUMBER_OF_BASIC_TYPES, BasicType::NUMBER_OF_BASIC_TYPES, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex },
     267                { BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex, (BasicType::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex },
    268268        };
    269269
     
    374374
    375375Expression * build_field_name_FLOATING_DECIMALconstant( const string & str ) {
    376         if ( str[str.size() - 1] != '.' ) SemanticError( yylloc, "invalid tuple index " + str );
     376        if ( str[str.size()-1] != '.' ) SemanticError( yylloc, "invalid tuple index " + str );
    377377        Expression * ret = build_constantInteger( *new string( str.substr( 0, str.size()-1 ) ) );
    378378        delete &str;
     
    434434} // build_cast
    435435
    436 Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) {
     436Expression * build_keyword_cast( KeywordCastExpr::Target target, ExpressionNode * expr_node ) {
    437437        return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target );
    438438}
  • src/Parser/ParseNode.h

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 17:56:02 2020
    13 // Update Count     : 891
     12// Last Modified On : Thu Jul 25 22:17:10 2019
     13// Update Count     : 876
    1414//
    1515
     
    2828#include "Common/UniqueName.h"     // for UniqueName
    2929#include "Common/utility.h"        // for maybeClone, maybeBuild
    30 #include "SynTree/LinkageSpec.h"   // for Spec
    31 #include "SynTree/Declaration.h"   // for Aggregate
     30#include "Parser/LinkageSpec.h"    // for Spec
    3231#include "SynTree/Expression.h"    // for Expression, ConstantExpr (ptr only)
    3332#include "SynTree/Label.h"         // for Label
     
    185184
    186185Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
    187 Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node );
     186Expression * build_keyword_cast( KeywordCastExpr::Target target, ExpressionNode * expr_node );
    188187Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
    189188Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member );
     
    218217        enum Length { Short, Long, LongLong, NoLength };
    219218        static const char * lengthNames[];
     219        enum Aggregate { Struct, Union, Exception, Trait, Coroutine, Monitor, Thread, NoAggregate };
     220        static const char * aggregateNames[];
     221        enum TypeClass { Otype, Dtype, Ftype, Ttype, NoTypeClass };
     222        static const char * typeClassNames[];
    220223        enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
    221224        static const char * builtinTypeNames[];
     
    234237        static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
    235238        static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
    236         static DeclarationNode * newAggregate( AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
     239        static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
    237240        static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body );
    238241        static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
    239242        static DeclarationNode * newName( const std::string * );
    240243        static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );
    241         static DeclarationNode * newTypeParam( TypeDecl::Kind, const std::string * );
     244        static DeclarationNode * newTypeParam( TypeClass, const std::string * );
    242245        static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
    243246        static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
     
    309312        struct Variable_t {
    310313//              const std::string * name;
    311                 TypeDecl::Kind tyClass;
     314                DeclarationNode::TypeClass tyClass;
    312315                DeclarationNode * assertions;
    313316                DeclarationNode * initializer;
     
    428431Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    429432Statement * build_directive( std::string * directive );
    430 SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
    431433WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
    432434WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
     
    450452                                * out++ = result;
    451453                        } else {
    452                                 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
     454                                assertf(false, "buildList unknown type");
    453455                        } // if
    454456                } catch( SemanticErrorException & e ) {
  • src/Parser/ParserTypes.h

    r7030dab r71d6bd8  
    1010// Created On       : Sat Sep 22 08:58:10 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 11:04:40 2020
    13 // Update Count     : 351
     12// Last Modified On : Sat Jul 22 09:33:28 2017
     13// Update Count     : 350
    1414//
    1515
     
    2727// current location in the input
    2828extern int yylineno;
    29 extern char * yyfilename;
     29extern char *yyfilename;
    3030
    3131struct Location {
    32     char * file;
     32    char *file;
    3333    int line;
    3434}; // Location
    3535
    3636struct Token {
    37     std::string * str;                                                                  // must be pointer as used in union
     37    std::string *str;                                                                   // must be pointer as used in union
    3838    Location loc;
    3939
  • src/Parser/StatementNode.cc

    r7030dab r71d6bd8  
    249249} // build_finally
    250250
    251 SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {
    252         auto node = new SuspendStmt();
    253 
    254         node->type = type;
    255 
    256         std::list< Statement * > stmts;
    257         buildMoveList< Statement, StatementNode >( then, stmts );
    258         if(!stmts.empty()) {
    259                 assert( stmts.size() == 1 );
    260                 node->then = dynamic_cast< CompoundStmt * >( stmts.front() );
    261         }
    262 
    263         return node;
    264 }
    265 
    266251WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    267252        auto node = new WaitForStmt();
  • src/Parser/TypeData.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 15:12:51 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 07:56:46 2019
    13 // Update Count     : 662
     12// Last Modified On : Wed Feb 13 18:16:23 2019
     13// Update Count     : 649
    1414//
    1515
     
    6767          case Aggregate:
    6868                // aggregate = new Aggregate_t;
    69                 aggregate.kind = AggregateDecl::NoAggregate;
     69                aggregate.kind = DeclarationNode::NoAggregate;
    7070                aggregate.name = nullptr;
    7171                aggregate.params = nullptr;
     
    345345                break;
    346346          case Aggregate:
    347                 os << AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
     347                os << DeclarationNode::aggregateNames[ aggregate.kind ] << ' ' << *aggregate.name << endl;
    348348                if ( aggregate.params ) {
    349349                        os << string( indent + 2, ' ' ) << "with type parameters" << endl;
     
    489489        for ( typename ForallList::iterator i = outputList.begin(); i != outputList.end(); ++i, n = (DeclarationNode*)n->get_next() ) {
    490490                TypeDecl * td = static_cast<TypeDecl *>(*i);
    491                 if ( n->variable.tyClass == TypeDecl::Otype ) {
     491                if ( n->variable.tyClass == DeclarationNode::Otype ) {
    492492                        // add assertion parameters to `type' tyvars in reverse order
    493493                        // add dtor:  void ^?{}(T *)
     
    522522        switch ( td->kind ) {
    523523          case TypeData::Unknown:
    524                 // fill in implicit int
    525                 return new BasicType( buildQualifiers( td ), BasicType::SignedInt );
     524                        // fill in implicit int
     525                        return new BasicType( buildQualifiers( td ), BasicType::SignedInt );
    526526          case TypeData::Basic:
    527                 return buildBasicType( td );
     527                        return buildBasicType( td );
    528528          case TypeData::Pointer:
    529                 return buildPointer( td );
     529                        return buildPointer( td );
    530530          case TypeData::Array:
    531                 return buildArray( td );
     531                        return buildArray( td );
    532532          case TypeData::Reference:
    533                 return buildReference( td );
     533                        return buildReference( td );
    534534          case TypeData::Function:
    535                 return buildFunction( td );
     535                        return buildFunction( td );
    536536          case TypeData::AggregateInst:
    537                 return buildAggInst( td );
     537                        return buildAggInst( td );
    538538          case TypeData::EnumConstant:
    539                 // the name gets filled in later -- by SymTab::Validate
    540                 return new EnumInstType( buildQualifiers( td ), "" );
     539                        // the name gets filled in later -- by SymTab::Validate
     540                        return new EnumInstType( buildQualifiers( td ), "" );
    541541          case TypeData::SymbolicInst:
    542                 return buildSymbolicInst( td );
     542                        return buildSymbolicInst( td );
    543543          case TypeData::Tuple:
    544                 return buildTuple( td );
     544                        return buildTuple( td );
    545545          case TypeData::Typeof:
    546546          case TypeData::Basetypeof:
    547                 return buildTypeof( td );
     547                        return buildTypeof( td );
    548548          case TypeData::Builtin:
    549                 switch ( td->builtintype ) {
    550                   case DeclarationNode::Zero:
    551                         return new ZeroType( noQualifiers );
    552                   case DeclarationNode::One:
    553                         return new OneType( noQualifiers );
    554                   default:
    555                         return new VarArgsType( buildQualifiers( td ) );
    556                 } // switch
     549                        if (td->builtintype == DeclarationNode::Zero) {
     550                                return new ZeroType( noQualifiers );
     551                        }
     552                        else if (td->builtintype == DeclarationNode::One) {
     553                                return new OneType( noQualifiers );
     554                        }
     555                        else {
     556                                return new VarArgsType( buildQualifiers( td ) );
     557                        }
    557558          case TypeData::GlobalScope:
    558                 return new GlobalScopeType();
    559           case TypeData::Qualified:
    560                 return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
     559                        return new GlobalScopeType();
     560                case TypeData::Qualified:
     561                        return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
    561562          case TypeData::Symbolic:
    562563          case TypeData::Enum:
    563564          case TypeData::Aggregate:
    564                 assert( false );
     565                        assert( false );
    565566        } // switch
    566567
     
    767768        AggregateDecl * at;
    768769        switch ( td->aggregate.kind ) {
    769           case AggregateDecl::Struct:
    770           case AggregateDecl::Coroutine:
    771           case AggregateDecl::Generator:
    772           case AggregateDecl::Monitor:
    773           case AggregateDecl::Thread:
     770          case DeclarationNode::Struct:
     771          case DeclarationNode::Coroutine:
     772          case DeclarationNode::Monitor:
     773          case DeclarationNode::Thread:
    774774                at = new StructDecl( *td->aggregate.name, td->aggregate.kind, attributes, linkage );
    775775                buildForall( td->aggregate.params, at->get_parameters() );
    776776                break;
    777           case AggregateDecl::Union:
     777          case DeclarationNode::Union:
    778778                at = new UnionDecl( *td->aggregate.name, attributes, linkage );
    779779                buildForall( td->aggregate.params, at->get_parameters() );
    780780                break;
    781           case AggregateDecl::Trait:
     781          case DeclarationNode::Trait:
    782782                at = new TraitDecl( *td->aggregate.name, attributes, linkage );
    783783                buildList( td->aggregate.params, at->get_parameters() );
     
    809809                          AggregateDecl * typedecl = buildAggregate( type, attributes, linkage );
    810810                          switch ( type->aggregate.kind ) {
    811                                 case AggregateDecl::Struct:
    812                                 case AggregateDecl::Coroutine:
    813                                 case AggregateDecl::Monitor:
    814                                 case AggregateDecl::Thread:
     811                                case DeclarationNode::Struct:
     812                                case DeclarationNode::Coroutine:
     813                                case DeclarationNode::Monitor:
     814                                case DeclarationNode::Thread:
    815815                                  ret = new StructInstType( buildQualifiers( type ), (StructDecl *)typedecl );
    816816                                  break;
    817                                 case AggregateDecl::Union:
     817                                case DeclarationNode::Union:
    818818                                  ret = new UnionInstType( buildQualifiers( type ), (UnionDecl *)typedecl );
    819819                                  break;
    820                                 case AggregateDecl::Trait:
     820                                case DeclarationNode::Trait:
    821821                                  assert( false );
    822822                                  //ret = new TraitInstType( buildQualifiers( type ), (TraitDecl *)typedecl );
     
    827827                  } else {
    828828                          switch ( type->aggregate.kind ) {
    829                                 case AggregateDecl::Struct:
    830                                 case AggregateDecl::Coroutine:
    831                                 case AggregateDecl::Monitor:
    832                                 case AggregateDecl::Thread:
     829                                case DeclarationNode::Struct:
     830                                case DeclarationNode::Coroutine:
     831                                case DeclarationNode::Monitor:
     832                                case DeclarationNode::Thread:
    833833                                  ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
    834834                                  break;
    835                                 case AggregateDecl::Union:
     835                                case DeclarationNode::Union:
    836836                                  ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
    837837                                  break;
    838                                 case AggregateDecl::Trait:
     838                                case DeclarationNode::Trait:
    839839                                  ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
    840840                                  break;
     
    863863          case TypeData::Aggregate: {
    864864                  switch ( type->aggregate.kind ) {
    865                         case AggregateDecl::Struct:
    866                         case AggregateDecl::Coroutine:
    867                         case AggregateDecl::Monitor:
    868                         case AggregateDecl::Thread:
     865                        case DeclarationNode::Struct:
     866                        case DeclarationNode::Coroutine:
     867                        case DeclarationNode::Monitor:
     868                        case DeclarationNode::Thread:
    869869                          ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
    870870                          break;
    871                         case AggregateDecl::Union:
     871                        case DeclarationNode::Union:
    872872                          ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
    873873                          break;
    874                         case AggregateDecl::Trait:
     874                        case DeclarationNode::Trait:
    875875                          ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
    876876                          break;
  • src/Parser/TypeData.h

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 15:18:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:42:35 2019
    13 // Update Count     : 199
     12// Last Modified On : Thu Nov  1 20:56:46 2018
     13// Update Count     : 196
    1414//
    1515
     
    2121
    2222#include "ParseNode.h"           // for DeclarationNode, DeclarationNode::Ag...
    23 #include "SynTree/LinkageSpec.h" // for Spec
     23#include "Parser/LinkageSpec.h" // for Spec
    2424#include "SynTree/Type.h"        // for Type, ReferenceToType (ptr only)
    2525#include "SynTree/SynTree.h"     // for Visitor Nodes
     
    3030
    3131        struct Aggregate_t {
    32                 AggregateDecl::Aggregate kind;
     32                DeclarationNode::Aggregate kind;
    3333                const std::string * name = nullptr;
    3434                DeclarationNode * params = nullptr;
  • src/Parser/TypedefTable.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 08:06:36 2020
    13 // Update Count     : 259
     12// Last Modified On : Wed Jul 25 15:32:35 2018
     13// Update Count     : 258
    1414//
    1515
     
    4747} // TypedefTable::~TypedefTable
    4848
    49 bool TypedefTable::exists( const string & identifier ) const {
     49bool TypedefTable::exists( const string & identifier ) {
    5050        return kindTable.find( identifier ) != kindTable.end();
    5151} // TypedefTable::exists
    5252
    53 bool TypedefTable::existsCurr( const string & identifier ) const {
     53bool TypedefTable::existsCurr( const string & identifier ) {
    5454        return kindTable.findAt( kindTable.currentScope() - 1, identifier ) != kindTable.end();
    5555} // TypedefTable::exists
  • src/Parser/TypedefTable.h

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 15:24:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 08:06:37 2020
    13 // Update Count     : 117
     12// Last Modified On : Wed Jul 25 15:33:55 2018
     13// Update Count     : 114
    1414//
    1515
     
    3030        ~TypedefTable();
    3131
    32         bool exists( const std::string & identifier ) const;
    33         bool existsCurr( const std::string & identifier ) const;
     32        bool exists( const std::string & identifier );
     33        bool existsCurr( const std::string & identifier );
    3434        int isKind( const std::string & identifier ) const;
    3535        void makeTypedef( const std::string & name, int kind = TYPEDEFname );
  • src/Parser/lex.ll

    r7030dab r71d6bd8  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Sat Feb 15 11:05:50 2020
    13  * Update Count     : 737
     12 * Last Modified On : Sun Aug  4 20:53:47 2019
     13 * Update Count     : 719
    1414 */
    1515
     
    4343#include "TypedefTable.h"
    4444
    45 string * build_postfix_name( string * name );
    46 
    4745char *yyfilename;
    4846string *strtext;                                                                                // accumulate parts of character and string constant value
     
    6563#define FLOATXX(v) KEYWORD_RETURN(v);
    6664#else
    67 #define FLOATXX(v) IDENTIFIER_RETURN();
     65#define FLOATXX(v) IDENTIFIER_RETURN(); 
    6866#endif // HAVE_KEYWORDS_FLOATXX
    6967
     
    301299_Static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C11
    302300struct                  { KEYWORD_RETURN(STRUCT); }
    303 suspend                 { KEYWORD_RETURN(SUSPEND); }                    // CFA
     301        /* suspend                      { KEYWORD_RETURN(SUSPEND); }                    // CFA */
    304302switch                  { KEYWORD_RETURN(SWITCH); }
    305303thread                  { KEYWORD_RETURN(THREAD); }                             // C11
     
    332330                                /* identifier */
    333331{identifier}    { IDENTIFIER_RETURN(); }
    334 "``"{identifier} {                                                                              // CFA
    335         yytext[yyleng] = '\0'; yytext += 2;                                     // SKULLDUGGERY: remove backquotes (ok to shorten?)
     332"`"{identifier}"`" {                                                                    // CFA
     333        yytext[yyleng - 1] = '\0'; yytext += 1;                         // SKULLDUGGERY: remove backquotes (ok to shorten?)
    336334        IDENTIFIER_RETURN();
    337335}
     
    434432"?"({op_unary_pre_post}|"()"|"[?]"|"{}") { IDENTIFIER_RETURN(); }
    435433"^?{}"                  { IDENTIFIER_RETURN(); }
    436 "?`"{identifier} {                                                                              // postfix operator
    437         yylval.tok.str = new string( &yytext[2] );                      // remove ?`
    438         yylval.tok.str = build_postfix_name( yylval.tok.str ); // add prefix
    439         RETURN_LOCN( typedefTable.isKind( *yylval.tok.str ) );
    440 }
     434"?`"{identifier} { IDENTIFIER_RETURN(); }                               // postfix operator
    441435"?"{op_binary_over}"?"  { IDENTIFIER_RETURN(); }                // binary
    442436        /*
  • src/Parser/module.mk

    r7030dab r71d6bd8  
    1111## Created On       : Sat May 16 15:29:09 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Dec 14 07:34:47 2019
    14 ## Update Count     : 107
     13## Last Modified On : Wed Jun 28 21:58:29 2017
     14## Update Count     : 104
    1515###############################################################################
    1616
     
    1919AM_YFLAGS = -d -t -v
    2020
    21 SRC += \
     21SRC += Parser/parser.yy \
     22       Parser/lex.ll \
     23       Parser/TypedefTable.cc \
     24       Parser/ParseNode.cc \
    2225       Parser/DeclarationNode.cc \
    2326       Parser/ExpressionNode.cc \
     27       Parser/StatementNode.cc \
    2428       Parser/InitializerNode.cc \
    25        Parser/ParseNode.cc \
    26        Parser/StatementNode.cc \
    2729       Parser/TypeData.cc \
    28        Parser/TypedefTable.cc \
    29        Parser/lex.ll \
    30        Parser/parser.yy \
     30       Parser/LinkageSpec.cc \
    3131       Parser/parserutility.cc
    3232
     33SRCDEMANGLE += \
     34        Parser/LinkageSpec.cc
     35
     36
    3337MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output
  • src/Parser/parser.yy

    r7030dab r71d6bd8  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar  6 17:26:45 2020
    13 // Update Count     : 4474
     12// Last Modified On : Sun Aug  4 21:48:23 2019
     13// Update Count     : 4364
    1414//
    1515
     
    5151using namespace std;
    5252
    53 #include "SynTree/Declaration.h"
    5453#include "ParseNode.h"
    5554#include "TypedefTable.h"
    5655#include "TypeData.h"
    57 #include "SynTree/LinkageSpec.h"
     56#include "LinkageSpec.h"
    5857#include "Common/SemanticError.h"                                               // error_str
    5958#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     
    166165} // rebindForall
    167166
    168 string * build_postfix_name( string * name ) {
    169         *name = string("__postfix_func_") + *name;
    170         return name;
     167NameExpr * build_postfix_name( const string * name ) {
     168        NameExpr * new_name = build_varref( new string( "?`" + *name ) );
     169        delete name;
     170        return new_name;
    171171} // build_postfix_name
    172172
     
    210210        } // if
    211211} // forCtrl
     212
    212213
    213214bool forall = false, yyy = false;                                               // aggregate have one or more forall qualifiers ?
     
    236237        ExpressionNode * en;
    237238        DeclarationNode * decl;
    238         AggregateDecl::Aggregate aggKey;
    239         TypeDecl::Kind tclass;
     239        DeclarationNode::Aggregate aggKey;
     240        DeclarationNode::TypeClass tclass;
    240241        StatementNode * sn;
    241242        WaitForStmt * wfs;
     
    278279%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    279280%token SIZEOF OFFSETOF
    280 // %token RESUME                                                                        // CFA
    281 %token SUSPEND                                                                  // CFA
     281// %token SUSPEND RESUME                                                                        // CFA
    282282%token ATTRIBUTE EXTENSION                                                              // GCC
    283283%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
     
    323323%type<op> ptrref_operator                               unary_operator                          assignment_operator
    324324%type<en> primary_expression                    postfix_expression                      unary_expression
    325 %type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     325%type<en> cast_expression                               exponential_expression          multiplicative_expression       additive_expression
    326326%type<en> shift_expression                              relational_expression           equality_expression
    327327%type<en> AND_expression                                exclusive_OR_expression         inclusive_OR_expression
     
    365365%type<decl> abstract_parameter_declaration
    366366
    367 %type<aggKey> aggregate_key aggregate_data aggregate_control
     367%type<aggKey> aggregate_key
    368368%type<decl> aggregate_type aggregate_type_nobody
    369369
     
    579579        | '(' compound_statement ')'                                            // GCC, lambda expression
    580580                { $$ = new ExpressionNode( new StmtExpr( dynamic_cast< CompoundStmt * >(maybeMoveBuild< Statement >($2) ) ) ); }
     581        | constant '`' IDENTIFIER                                                       // CFA, postfix call
     582                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), $1 ) ); }
     583        | string_literal '`' IDENTIFIER                                         // CFA, postfix call
     584                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), new ExpressionNode( $1 ) ) ); }
     585        | IDENTIFIER '`' IDENTIFIER                                                     // CFA, postfix call
     586                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), new ExpressionNode( build_varref( $1 ) ) ) ); }
     587        | tuple '`' IDENTIFIER                                                          // CFA, postfix call
     588                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $3 ) ), $1 ) ); }
     589        | '(' comma_expression ')' '`' IDENTIFIER                       // CFA, postfix call
     590                { $$ = new ExpressionNode( build_func( new ExpressionNode( build_postfix_name( $5 ) ), $2 ) ); }
    581591        | type_name '.' identifier                                                      // CFA, nested type
    582592                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     
    632642        | postfix_expression '(' argument_expression_list ')'
    633643                { $$ = new ExpressionNode( build_func( $1, $3 ) ); }
    634         | postfix_expression '`' identifier                                     // CFA, postfix call
    635                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
    636         | constant '`' identifier                                                       // CFA, postfix call
    637                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); }
    638         | string_literal '`' identifier                                         // CFA, postfix call
    639                 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
    640644        | postfix_expression '.' identifier
    641645                { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
     
    646650        | postfix_expression '.' '[' field_name_list ']'        // CFA, tuple field selector
    647651                { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
    648         | postfix_expression '.' aggregate_control
    649                 { $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }
    650652        | postfix_expression ARROW identifier
    651653                { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
     
    662664        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    663665                { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    664         | '^' primary_expression '{' argument_expression_list '}' // CFA, destructor call
     666        | '^' primary_expression '{' argument_expression_list '}' // CFA
    665667                {
    666668                        Token fn;
     
    675677        | argument_expression
    676678        | argument_expression_list ',' argument_expression
    677                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     679                { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
    678680        ;
    679681
     
    687689field_name_list:                                                                                // CFA, tuple field selector
    688690        field
    689         | field_name_list ',' field                                     { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     691        | field_name_list ',' field                                     { $$ = (ExpressionNode *)$1->set_last( $3 ); }
    690692        ;
    691693
     
    791793        | '(' type_no_function ')' cast_expression
    792794                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    793         | '(' aggregate_control '&' ')' cast_expression         // CFA
    794                 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     795                // keyword cast cannot be grouped because of reduction in aggregate_key
     796        | '(' GENERATOR '&' ')' cast_expression                         // CFA
     797                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
     798        | '(' COROUTINE '&' ')' cast_expression                         // CFA
     799                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
     800        | '(' THREAD '&' ')' cast_expression                            // CFA
     801                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Thread, $5 ) ); }
     802        | '(' MONITOR '&' ')' cast_expression                           // CFA
     803                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Monitor, $5 ) ); }
    795804                // VIRTUAL cannot be opt because of look ahead issues
    796805        | '(' VIRTUAL ')' cast_expression                                       // CFA
     
    919928        conditional_expression
    920929        | unary_expression assignment_operator assignment_expression
    921                 {
    922                         if ( $2 == OperKinds::AtAssn ) {
    923                                 SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr;
    924                         } else {
    925                                 $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );
    926                         } // if
    927                 }
     930                { $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); }
    928931        | unary_expression '=' '{' initializer_list_opt comma_opt '}'
    929932                { SemanticError( yylloc, "Initializer assignment is currently unimplemented." ); $$ = nullptr; }
     
    962965                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
    963966        | '[' push assignment_expression pop ',' tuple_expression_list ']'
    964                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $6 ) ) )); }
     967                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)$3->set_last( $6 ) ) ); }
    965968        ;
    966969
     
    968971        assignment_expression_opt
    969972        | tuple_expression_list ',' assignment_expression_opt
    970                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     973                { $$ = (ExpressionNode *)$1->set_last( $3 ); }
    971974        ;
    972975
     
    11921195                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11931196                                                OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1194         | '=' comma_expression                                                                  // CFA
    1195                 { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    1196                                                 OperKinds::LEThan, $2->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    11971197        | comma_expression inclexcl comma_expression            // CFA
    11981198                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    12021202                { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    12031203                                                OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1204         | comma_expression ';' '=' comma_expression                             // CFA
    1205                 { $$ = forCtrl( $4, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    1206                                                 OperKinds::LEThan, $4->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    12071204        | comma_expression ';' comma_expression inclexcl comma_expression // CFA
    12081205                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    12661263        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    12671264                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    1268         | SUSPEND ';'
    1269                 { $$ = new StatementNode( build_suspend( nullptr ) ); }
    1270         | SUSPEND compound_statement
    1271                 { $$ = new StatementNode( build_suspend( $2 ) ); }
    1272         | SUSPEND COROUTINE ';'
    1273                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
    1274         | SUSPEND COROUTINE compound_statement
    1275                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
    1276         | SUSPEND GENERATOR ';'
    1277                 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
    1278         | SUSPEND GENERATOR compound_statement
    1279                 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
     1265        // | SUSPEND ';'
     1266        //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
     1267        // | SUSPEND compound_statement ';'
     1268        //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
    12801269        | THROW assignment_expression_opt ';'                           // handles rethrow
    12811270                { $$ = new StatementNode( build_throw( $2 ) ); }
     
    13171306        WAITFOR '(' cast_expression ')'
    13181307                { $$ = $3; }
    1319 //      | WAITFOR '(' cast_expression ',' argument_expression_list ')'
    1320 //              { $$ = (ExpressionNode *)$3->set_last( $5 ); }
    1321         | WAITFOR '(' cast_expression_list ':' argument_expression_list ')'
    1322                 { $$ = (ExpressionNode *)($3->set_last( $5 )); }
    1323         ;
    1324 
    1325 cast_expression_list:
    1326         cast_expression
    1327         | cast_expression_list ',' cast_expression
    1328                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     1308        | WAITFOR '(' cast_expression ',' argument_expression_list ')'
     1309                { $$ = (ExpressionNode *)$3->set_last( $5 ); }
    13291310        ;
    13301311
     
    14371418        asm_operand
    14381419        | asm_operands_list ',' asm_operand
    1439                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     1420                { $$ = (ExpressionNode *)$1->set_last( $3 ); }
    14401421        ;
    14411422
     
    14531434                { $$ = new ExpressionNode( $1 ); }
    14541435        | asm_clobbers_list_opt ',' string_literal
    1455                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
     1436                // set_last returns ParseNode *
     1437                { $$ = (ExpressionNode *)$1->set_last( new ExpressionNode( $3 ) ); }
    14561438        ;
    14571439
     
    16041586                // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
    16051587                // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
    1606         cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
     1588        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
    16071589                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    1608                 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
    1609         | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    1610                 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); }
     1590                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
     1591        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
     1592                { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ); }
    16111593        ;
    16121594
     
    20772059
    20782060aggregate_key:
    2079         aggregate_data
    2080         | aggregate_control
    2081         ;
    2082 
    2083 aggregate_data:
    20842061        STRUCT
    2085                 { yyy = true; $$ = AggregateDecl::Struct; }
     2062                { yyy = true; $$ = DeclarationNode::Struct; }
    20862063        | UNION
    2087                 { yyy = true; $$ = AggregateDecl::Union; }
    2088         | EXCEPTION                                                                                     // CFA
    2089                 { yyy = true; $$ = AggregateDecl::Exception; }
    2090         ;
    2091 
    2092 aggregate_control:                                                                              // CFA
    2093         GENERATOR
    2094                 { yyy = true; $$ = AggregateDecl::Generator; }
    2095         | MONITOR GENERATOR
    2096                 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2064                { yyy = true; $$ = DeclarationNode::Union; }
     2065        | EXCEPTION
     2066                { yyy = true; $$ = DeclarationNode::Exception; }
     2067        | GENERATOR
     2068                { yyy = true; $$ = DeclarationNode::Coroutine; }
    20972069        | COROUTINE
    2098                 { yyy = true; $$ = AggregateDecl::Coroutine; }
     2070                { yyy = true; $$ = DeclarationNode::Coroutine; }
    20992071        | MONITOR
    2100                 { yyy = true; $$ = AggregateDecl::Monitor; }
    2101         | MONITOR COROUTINE
    2102                 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2072                { yyy = true; $$ = DeclarationNode::Monitor; }
    21032073        | THREAD
    2104                 { yyy = true; $$ = AggregateDecl::Thread; }
    2105         | MONITOR THREAD
    2106                 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2074                { yyy = true; $$ = DeclarationNode::Thread; }
    21072075        ;
    21082076
     
    21282096                        distInl( $3 );
    21292097                }
    2130         | INLINE aggregate_control ';'                                          // CFA
    2131                 { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
    21322098        | typedef_declaration ';'                                                       // CFA
    21332099        | cfa_field_declaring_list ';'                                          // CFA, new style field declaration
     
    23822348        | initializer_list_opt ',' initializer          { $$ = (InitializerNode *)( $1->set_last( $3 ) ); }
    23832349        | initializer_list_opt ',' designation initializer
    2384                 { $$ = (InitializerNode *)($1->set_last( $4->set_designators( $3 ) )); }
     2350                { $$ = (InitializerNode *)( $1->set_last( $4->set_designators( $3 ) ) ); }
    23852351        ;
    23862352
     
    24042370        designator
    24052371        | designator_list designator
    2406                 { $$ = (ExpressionNode *)($1->set_last( $2 )); }
     2372                { $$ = (ExpressionNode *)( $1->set_last( $2 ) ); }
    24072373        //| designator_list designator                                          { $$ = new ExpressionNode( $1, $2 ); }
    24082374        ;
     
    24602426        | type_specifier identifier_parameter_declarator
    24612427        | assertion_list
    2462                 { $$ = DeclarationNode::newTypeParam( TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
     2428                { $$ = DeclarationNode::newTypeParam( DeclarationNode::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
    24632429        ;
    24642430
    24652431type_class:                                                                                             // CFA
    24662432        OTYPE
    2467                 { $$ = TypeDecl::Otype; }
     2433                { $$ = DeclarationNode::Otype; }
    24682434        | DTYPE
    2469                 { $$ = TypeDecl::Dtype; }
     2435                { $$ = DeclarationNode::Dtype; }
    24702436        | FTYPE
    2471                 { $$ = TypeDecl::Ftype; }
     2437                { $$ = DeclarationNode::Ftype; }
    24722438        | TTYPE
    2473                 { $$ = TypeDecl::Ttype; }
     2439                { $$ = DeclarationNode::Ttype; }
    24742440        ;
    24752441
     
    25012467                { SemanticError( yylloc, toString("Expression generic parameters are currently unimplemented: ", $1->build()) ); $$ = nullptr; }
    25022468        | type_list ',' type
    2503                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
     2469                { $$ = (ExpressionNode *)( $1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) ) ); }
    25042470        | type_list ',' assignment_expression
    25052471                { SemanticError( yylloc, toString("Expression generic parameters are currently unimplemented: ", $3->build()) ); $$ = nullptr; }
     
    26122578                {
    26132579                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    2614                         linkage = LinkageSpec::update( yylloc, linkage, $2 );
     2580                        linkage = LinkageSpec::linkageUpdate( yylloc, linkage, $2 );
    26152581                }
    26162582          '{' up external_definition_list_opt down '}'
  • src/ResolvExpr/AdjustExprType.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sat May 16 23:41:42 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:43:56 2019
    13 // Update Count     : 6
     12// Last Modified On : Wed Mar  2 17:34:53 2016
     13// Update Count     : 4
    1414//
    1515
     
    134134                        // replace known function-type-variables with pointer-to-function
    135135                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
    136                                 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
     136                                if ( eqvClass->data.kind == ast::TypeVar::Ftype ) {
    137137                                        return new ast::PointerType{ inst };
    138138                                }
    139139                        } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
    140140                                if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
    141                                         if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
     141                                        if ( tyDecl->kind == ast::TypeVar::Ftype ) {
    142142                                                return new ast::PointerType{ inst };
    143143                                        }
  • src/ResolvExpr/AlternativeFinder.cc

    r7030dab r71d6bd8  
    6969                void postvisit( CastExpr * castExpr );
    7070                void postvisit( VirtualCastExpr * castExpr );
    71                 void postvisit( KeywordCastExpr * castExpr );
    7271                void postvisit( UntypedMemberExpr * memberExpr );
    7372                void postvisit( MemberExpr * memberExpr );
     
    12561255        }
    12571256
    1258         void AlternativeFinder::Finder::postvisit( KeywordCastExpr * castExpr ) {
    1259                 assertf( castExpr->get_result(), "Cast target should have been set in Validate." );
    1260                 auto ref = dynamic_cast<ReferenceType*>(castExpr->get_result());
    1261                 assert(ref);
    1262                 auto inst = dynamic_cast<StructInstType*>(ref->base);
    1263                 assert(inst);
    1264                 auto target = inst->baseStruct;
    1265 
    1266                 AlternativeFinder finder( indexer, env );
    1267 
    1268                 auto pick_alternatives = [target, this](AltList & found, bool expect_ref) {
    1269                         for(auto & alt : found) {
    1270                                 Type * expr = alt.expr->get_result();
    1271                                 if(expect_ref) {
    1272                                         auto res = dynamic_cast<ReferenceType*>(expr);
    1273                                         if(!res) { continue; }
    1274                                         expr = res->base;
    1275                                 }
    1276 
    1277                                 if(auto insttype = dynamic_cast<TypeInstType*>(expr)) {
    1278                                         auto td = alt.env.lookup(insttype->name);
    1279                                         if(!td) { continue; }
    1280                                         expr = td->type;
    1281                                 }
    1282 
    1283                                 if(auto base = dynamic_cast<StructInstType*>(expr)) {
    1284                                         if(base->baseStruct == target) {
    1285                                                 alternatives.push_back(
    1286                                                         std::move(alt)
    1287                                                 );
    1288                                         }
    1289                                 }
    1290                         }
    1291                 };
    1292 
    1293                 try {
    1294                         // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd
    1295                         // Clone is purely for memory management
    1296                         std::unique_ptr<Expression> tech1 { new UntypedMemberExpr(new NameExpr(castExpr->concrete_target.field), castExpr->arg->clone()) };
    1297 
    1298                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1299                         finder.findWithoutPrune( tech1.get() );
    1300                         pick_alternatives(finder.alternatives, false);
    1301 
    1302                         return;
    1303                 } catch(SemanticErrorException & ) {}
    1304 
    1305                 // Fallback : turn (thread&)X into ($thread&)get_thread(X)
    1306                 std::unique_ptr<Expression> fallback { UntypedExpr::createDeref( new UntypedExpr(new NameExpr(castExpr->concrete_target.getter), { castExpr->arg->clone() })) };
    1307                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1308                 finder.findWithoutPrune( fallback.get() );
    1309 
    1310                 pick_alternatives(finder.alternatives, true);
    1311 
    1312                 // Whatever happens here, we have no more fallbacks
    1313         }
    1314 
    13151257        namespace {
    13161258                /// Gets name from untyped member expression (member must be NameExpr)
  • src/ResolvExpr/PtrsCastable.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sun May 17 11:48:00 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:48:33 2019
    13 // Update Count     : 9
     12// Last Modified On : Wed Mar  2 17:36:18 2016
     13// Update Count     : 8
    1414//
    1515
     
    176176                        if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
    177177                                if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( named ) ) {
    178                                         if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
     178                                        if ( tyDecl->kind == ast::TypeVar::Ftype ) {
    179179                                                return -1;
    180180                                        }
    181181                                }
    182182                        } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
    183                                 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
     183                                if ( eqvClass->data.kind == ast::TypeVar::Ftype ) {
    184184                                        return -1;
    185185                                }
  • src/ResolvExpr/Resolver.cc

    r7030dab r71d6bd8  
    99// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 27 11:58:00 2020
    13 // Update Count     : 242
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed May 29 11:00:00 2019
     13// Update Count     : 241
    1414//
    1515
     
    8484                void previsit( ThrowStmt * throwStmt );
    8585                void previsit( CatchStmt * catchStmt );
    86                 void postvisit( CatchStmt * catchStmt );
    8786                void previsit( WaitForStmt * stmt );
    8887
     
    560559                // TODO: Replace *exception type with &exception type.
    561560                if ( throwStmt->get_expr() ) {
    562                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
     561                        const StructDecl * exception_decl = indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" );
    563562                        assert( exception_decl );
    564563                        Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
     
    568567
    569568        void Resolver_old::previsit( CatchStmt * catchStmt ) {
    570                 // Until we are very sure this invarent (ifs that move between passes have thenPart)
    571                 // holds, check it. This allows a check for when to decode the mangling.
    572                 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
    573                         assert( ifStmt->thenPart );
    574                 }
    575                 // Encode the catchStmt so the condition can see the declaration.
    576569                if ( catchStmt->cond ) {
    577                         IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
    578                         catchStmt->cond = nullptr;
    579                         catchStmt->body = ifStmt;
    580                 }
    581         }
    582 
    583         void Resolver_old::postvisit( CatchStmt * catchStmt ) {
    584                 // Decode the catchStmt so everything is stored properly.
    585                 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
    586                 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
    587                         assert( ifStmt->condition );
    588                         assert( ifStmt->elsePart );
    589                         catchStmt->cond = ifStmt->condition;
    590                         catchStmt->body = ifStmt->elsePart;
    591                         ifStmt->condition = nullptr;
    592                         ifStmt->elsePart = nullptr;
    593                         delete ifStmt;
     570                        findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer );
    594571                }
    595572        }
     
    14771454                if ( throwStmt->expr ) {
    14781455                        const ast::StructDecl * exceptionDecl =
    1479                                 symtab.lookupStruct( "__cfaehm_base_exception_t" );
     1456                                symtab.lookupStruct( "__cfaabi_ehm__base_exception_t" );
    14801457                        assert( exceptionDecl );
    14811458                        ast::ptr< ast::Type > exceptType =
     
    14891466
    14901467        const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
    1491                 // TODO: This will need a fix for the decl/cond scoping problem.
    14921468                if ( catchStmt->cond ) {
    14931469                        ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool };
  • src/ResolvExpr/Unify.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:27:10 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:43:05 2019
    13 // Update Count     : 46
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Sep  4 10:00:00 2019
     13// Update Count     : 44
    1414//
    1515
     
    3434#include "Common/PassVisitor.h"     // for PassVisitor
    3535#include "FindOpenVars.h"           // for findOpenVars
    36 #include "SynTree/LinkageSpec.h"    // for C
     36#include "Parser/LinkageSpec.h"     // for C
    3737#include "SynTree/Constant.h"       // for Constant
    3838#include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
     
    771771                                if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
    772772                                        // expand ttype parameter into its actual type
    773                                         if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     773                                        if ( clz->data.kind == ast::TypeVar::Ttype && clz->bound ) {
    774774                                                return clz->bound;
    775775                                        }
  • src/SymTab/Autogen.h

    r7030dab r71d6bd8  
    1010// Created On       : Sun May 17 21:53:34 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 16:38:06 2019
    13 // Update Count     : 16
     12// Last Modified On : Sat Jul 22 09:50:25 2017
     13// Update Count     : 15
    1414//
    1515
     
    3535#include "SynTree/Expression.h"   // for NameExpr, ConstantExpr, UntypedExpr...
    3636#include "SynTree/Type.h"         // for Type, ArrayType, Type::Qualifiers
    37 #include "SynTree/Statement.h"    // for CompoundStmt, DeclStmt, ExprStmt
    3837
    3938class CompoundStmt;
  • src/SymTab/Demangle.cc

    r7030dab r71d6bd8  
    1010// Created On       : Thu Jul 19 12:52:41 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 11 15:09:18 2020
    13 // Update Count     : 10
     12// Last Modified On : Tue Jul 30 13:46:33 2019
     13// Update Count     : 3
    1414//
    1515
     
    1919#include "CodeGen/GenType.h"
    2020#include "Common/PassVisitor.h"
    21 #include "Common/utility.h"                                                             // isPrefix
    2221#include "Mangler.h"
    2322#include "SynTree/Type.h"
     
    367366                                // type variable types
    368367                                for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) {
    369                                         static const std::string typeVariableNames[] = { "DT", "OT", "FT", "TT", };
     368                                        static const std::string typeVariableNames[] = { "DT", "FT", "TT", };
    370369                                        static_assert(
    371370                                                sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS,
     
    417416
    418417                        bool StringView::isPrefix(const std::string & pref) {
    419                                 // if ( pref.size() > str.size()-idx ) return false;
    420                                 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
    421                                 // if (its.first == pref.end()) {
    422                                 //      idx += pref.size();
    423                                 //      return true;
    424                                 // }
    425 
    426                                 // This update is untested because there are no tests for this code.
    427                                 if ( ::isPrefix( str, pref, idx ) ) {
     418                                if ( pref.size() > str.size()-idx ) return false;
     419                                auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
     420                                if (its.first == pref.end()) {
    428421                                        idx += pref.size();
    429422                                        return true;
     
    436429                                PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
    437430                                if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
    438                                 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
     431                                if (! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back())) return false;
    439432
    440433                                // get name
  • src/SymTab/Indexer.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:43:19 2019
    13 // Update Count     : 22
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 21
    1414//
    1515
     
    3131#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3232#include "Mangler.h"               // for Mangler
     33#include "Parser/LinkageSpec.h"    // for isMangled, isOverridable, Spec
    3334#include "ResolvExpr/typeops.h"    // for typesCompatible
    34 #include "SynTree/LinkageSpec.h"   // for isMangled, isOverridable, Spec
    3535#include "SynTree/Constant.h"      // for Constant
    3636#include "SynTree/Declaration.h"   // for DeclarationWithType, FunctionDecl
  • src/SymTab/Mangler.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sun May 17 21:40:29 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 13:55:12 2020
    13 // Update Count     : 33
     12// Last Modified On : Tue Jul 30 13:46:10 2019
     13// Update Count     : 26
    1414//
    1515#include "Mangler.h"
     
    2626#include "Common/SemanticError.h"        // for SemanticError
    2727#include "Common/utility.h"              // for toString
     28#include "Parser/LinkageSpec.h"          // for Spec, isOverridable, AutoGen, Int...
    2829#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    29 #include "SynTree/LinkageSpec.h"         // for Spec, isOverridable, AutoGen, Int...
    3030#include "SynTree/Declaration.h"         // for TypeDecl, DeclarationWithType
    3131#include "SynTree/Expression.h"          // for TypeExpr, Expression, operator<<
     
    128128                                } // if
    129129                                mangleName << Encoding::manglePrefix;
    130                                 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
    131                                 if ( opInfo ) {
    132                                         mangleName << opInfo->outputName.size() << opInfo->outputName;
     130                                CodeGen::OperatorInfo opInfo;
     131                                if ( operatorLookup( declaration->get_name(), opInfo ) ) {
     132                                        mangleName << opInfo.outputName.size() << opInfo.outputName;
    133133                                } else {
    134134                                        mangleName << declaration->name.size() << declaration->name;
     
    471471                        } // if
    472472                        mangleName << Encoding::manglePrefix;
    473                         const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
    474                         if ( opInfo ) {
    475                                 mangleName << opInfo->outputName.size() << opInfo->outputName;
     473                        CodeGen::OperatorInfo opInfo;
     474                        if ( operatorLookup( decl->name, opInfo ) ) {
     475                                mangleName << opInfo.outputName.size() << opInfo.outputName;
    476476                        } else {
    477477                                mangleName << decl->name.size() << decl->name;
     
    654654                        // aside from the assert false.
    655655                        assertf(false, "Mangler_new should not visit typedecl: %s", toCString(decl));
    656                         assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
     656                        assertf( decl->kind < ast::TypeVar::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    657657                        mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) << decl->name;
    658658                }
     
    674674                                        for ( const ast::TypeDecl * decl : ptype->forall ) {
    675675                                                switch ( decl->kind ) {
    676                                                 case ast::TypeDecl::Kind::Dtype:
     676                                                case ast::TypeVar::Kind::Dtype:
    677677                                                        dcount++;
    678678                                                        break;
    679                                                 case ast::TypeDecl::Kind::Ftype:
     679                                                case ast::TypeVar::Kind::Ftype:
    680680                                                        fcount++;
    681681                                                        break;
    682                                                 case ast::TypeDecl::Kind::Ttype:
     682                                                case ast::TypeVar::Kind::Ttype:
    683683                                                        vcount++;
    684684                                                        break;
  • src/SymTab/ManglerCommon.cc

    r7030dab r71d6bd8  
    1010// Created On       : Sun May 17 21:44:03 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 14:54:38 2019
    13 // Update Count     : 28
     12// Last Modified On : Thu Feb 14 17:06:37 2019
     13// Update Count     : 26
    1414//
    1515
     
    104104                        const std::string typeVariables[] = {
    105105                                "BD", // dtype
    106                                 "BO", // otype
    107106                                "BF", // ftype
    108107                                "BT", // ttype
  • src/SymTab/Validate.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:50:04 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:43:34 2019
    13 // Update Count     : 363
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Aug  7 6:42:00 2019
     13// Update Count     : 360
    1414//
    1515
     
    6969#include "InitTweak/GenInit.h"         // for fixReturnStatements
    7070#include "InitTweak/InitTweak.h"       // for isCtorDtorAssign
     71#include "Parser/LinkageSpec.h"        // for C
    7172#include "ResolvExpr/typeops.h"        // for typesCompatible
    7273#include "ResolvExpr/Resolver.h"       // for findSingleExpression
    7374#include "ResolvExpr/ResolveTypeof.h"  // for resolveTypeof
    7475#include "SymTab/Autogen.h"            // for SizeType
    75 #include "SynTree/LinkageSpec.h"       // for C
    7676#include "SynTree/Attribute.h"         // for noAttributes, Attribute
    7777#include "SynTree/Constant.h"          // for Constant
     
    311311                        Stats::Heap::newPass("validate-A");
    312312                        Stats::Time::BlockGuard guard("validate-A");
    313                         VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    314313                        acceptAll( translationUnit, hoistDecls );
    315314                        ReplaceTypedef::replaceTypedef( translationUnit );
     
    337336                        Stats::Time::BlockGuard guard("validate-C");
    338337                        acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes_old
     338                        VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    339339                        ReturnChecker::checkFunctionReturns( translationUnit );
    340340                        InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen
     
    375375                        Stats::Heap::newPass("validate-F");
    376376                        Stats::Time::BlockGuard guard("validate-F");
    377                         Stats::Time::TimeCall("Fix Object Type",
    378                                 FixObjectType::fix, translationUnit);
    379                         Stats::Time::TimeCall("Array Length",
    380                                 ArrayLength::computeLength, translationUnit);
    381                         Stats::Time::TimeCall("Find Special Declarations",
    382                                 Validate::findSpecialDecls, translationUnit);
    383                         Stats::Time::TimeCall("Fix Label Address",
    384                                 mutateAll<LabelAddressFixer>, translationUnit, labelAddrFixer);
    385                         Stats::Time::TimeCall("Handle Attributes",
    386                                 Validate::handleAttributes, translationUnit);
     377                        Stats::Time::TimeBlock("Fix Object Type", [&]() {
     378                                FixObjectType::fix( translationUnit );
     379                        });
     380                        Stats::Time::TimeBlock("Array Length", [&]() {
     381                                ArrayLength::computeLength( translationUnit );
     382                        });
     383                        Stats::Time::TimeBlock("Find Special Declarations", [&]() {
     384                                Validate::findSpecialDecls( translationUnit );
     385                        });
     386                        Stats::Time::TimeBlock("Fix Label Address", [&]() {
     387                                mutateAll( translationUnit, labelAddrFixer );
     388                        });
     389                        Stats::Time::TimeBlock("Handle Attributes", [&]() {
     390                                Validate::handleAttributes( translationUnit );
     391                        });
    387392                }
    388393        }
     
    10441049                Type * designatorType = tyDecl->base->stripDeclarator();
    10451050                if ( StructInstType * aggDecl = dynamic_cast< StructInstType * >( designatorType ) ) {
    1046                         declsToAddBefore.push_back( new StructDecl( aggDecl->name, AggregateDecl::Struct, noAttributes, tyDecl->linkage ) );
     1051                        declsToAddBefore.push_back( new StructDecl( aggDecl->name, DeclarationNode::Struct, noAttributes, tyDecl->linkage ) );
    10471052                } else if ( UnionInstType * aggDecl = dynamic_cast< UnionInstType * >( designatorType ) ) {
    10481053                        declsToAddBefore.push_back( new UnionDecl( aggDecl->name, noAttributes, tyDecl->linkage ) );
     
    11821187                if ( CodeGen::isCtorDtorAssign( funcDecl->get_name() ) ) { // TODO: also check /=, etc.
    11831188                        if ( params.size() == 0 ) {
    1184                                 SemanticError( funcDecl->location, "Constructors, destructors, and assignment functions require at least one parameter." );
     1189                                SemanticError( funcDecl, "Constructors, destructors, and assignment functions require at least one parameter " );
    11851190                        }
    11861191                        ReferenceType * refType = dynamic_cast< ReferenceType * >( params.front()->get_type() );
    11871192                        if ( ! refType ) {
    1188                                 SemanticError( funcDecl->location, "First parameter of a constructor, destructor, or assignment function must be a reference." );
     1193                                SemanticError( funcDecl, "First parameter of a constructor, destructor, or assignment function must be a reference " );
    11891194                        }
    11901195                        if ( CodeGen::isCtorDtor( funcDecl->get_name() ) && returnVals.size() != 0 ) {
    1191                                 if(!returnVals.front()->get_type()->isVoid()) {
    1192                                         SemanticError( funcDecl->location, "Constructors and destructors cannot have explicit return values." );
    1193                                 }
     1196                                SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " );
    11941197                        }
    11951198                }
  • src/SynTree/AggregateDecl.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 23:56:39 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:07:20 2019
    13 // Update Count     : 31
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Aug  4 14:22:00 2017
     13// Update Count     : 22
    1414//
    1515
     
    2121#include "Common/utility.h"      // for printAll, cloneAll, deleteAll
    2222#include "Declaration.h"         // for AggregateDecl, TypeDecl, Declaration
    23 #include "Initializer.h"
    24 #include "LinkageSpec.h"         // for Spec, linkageName, Cforall
     23#include "Parser/LinkageSpec.h"  // for Spec, linkageName, Cforall
    2524#include "Type.h"                // for Type, Type::StorageClasses
    2625
    27 
    28 // These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
    29 static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
    30 
    31 const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
    32         return aggregateNames[aggr];
    33 }
    3426
    3527AggregateDecl::AggregateDecl( const std::string &name, const std::list< Attribute * > & attributes, LinkageSpec::Spec linkage ) : Parent( name, Type::StorageClasses(), linkage ), body( false ), attributes( attributes ) {
     
    5547        os << typeString() << " " << name << ":";
    5648        if ( get_linkage() != LinkageSpec::Cforall ) {
    57                 os << " " << LinkageSpec::name( linkage );
     49                os << " " << LinkageSpec::linkageName( linkage );
    5850        } // if
    5951        os << " with body " << has_body();
     
    8678}
    8779
    88 const char * StructDecl::typeString() const { return aggrString( kind ); }
     80std::string StructDecl::typeString() const { return "struct"; }
    8981
    90 const char * UnionDecl::typeString() const { return aggrString( Union ); }
     82std::string UnionDecl::typeString() const { return "union"; }
    9183
    92 const char * EnumDecl::typeString() const { return aggrString( Enum ); }
     84std::string EnumDecl::typeString() const { return "enum"; }
    9385
    94 const char * TraitDecl::typeString() const { return aggrString( Trait ); }
     86std::string TraitDecl::typeString() const { return "trait"; }
    9587
    9688bool EnumDecl::valueOf( Declaration * enumerator, long long int & value ) {
  • src/SynTree/Attribute.h

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 13 21:34:08 2020
    13 // Update Count     : 40
     12// Last Modified On : Sat Jul 22 09:54:14 2017
     13// Update Count     : 39
    1414//
    1515
     
    3838        virtual ~Attribute();
    3939
    40         const std::string & get_name() const { return name; }
     40        std::string get_name() const { return name; }
    4141        void set_name( const std::string & newValue ) { name = newValue; }
    4242        std::list< Expression * > & get_parameters() { return parameters; }
  • src/SynTree/Declaration.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 16:39:56 2019
    13 // Update Count     : 36
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Aug  9 14:38:00 2017
     13// Update Count     : 25
    1414//
    1515
     
    2424#include "SynTree/Statement.h"       // for AsmStmt
    2525#include "SynTree/SynTree.h"         // for UniqueId
    26 #include "SynTree/Expression.h"
    2726#include "Type.h"                    // for Type, Type::StorageClasses
    2827
    29 // To canonicalize declarations
    3028static UniqueId lastUniqueId = 0;
    3129
  • src/SynTree/Declaration.h

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:11:22 2019
    13 // Update Count     : 157
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May  2 10:47:00 2019
     13// Update Count     : 135
    1414//
    1515
     
    2424#include "BaseSyntaxNode.h"      // for BaseSyntaxNode
    2525#include "Mutator.h"             // for Mutator
    26 #include "LinkageSpec.h"         // for Spec, Cforall
     26#include "Parser/LinkageSpec.h"  // for Spec, Cforall
     27#include "Parser/ParseNode.h"    // for DeclarationNode, DeclarationNode::Ag...
    2728#include "SynTree.h"             // for UniqueId
    2829#include "SynTree/Type.h"        // for Type, Type::StorageClasses, Type::Fu...
     
    4344        bool extension = false;
    4445
    45         Declaration( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage );
    46         Declaration( const Declaration & other );
     46        Declaration( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage );
     47        Declaration( const Declaration &other );
    4748        virtual ~Declaration();
    4849
    49         const std::string & get_name() const { return name; }
     50        const std::string &get_name() const { return name; }
    5051        void set_name( std::string newValue ) { name = newValue; }
    5152
     
    5859
    5960        bool get_extension() const { return extension; }
    60         Declaration * set_extension( bool exten ) { extension = exten; return this; }
     61        Declaration *set_extension( bool exten ) { extension = exten; return this; }
    6162
    6263        void fixUniqueId( void );
    63         virtual Declaration * clone() const override = 0;
     64        virtual Declaration *clone() const override = 0;
    6465        virtual void accept( Visitor & v ) override = 0;
    6566        virtual void accept( Visitor & v ) const override = 0;
    66         virtual Declaration * acceptMutator( Mutator & m ) override = 0;
    67         virtual void print( std::ostream & os, Indenter indent = {} ) const override = 0;
    68         virtual void printShort( std::ostream & os, Indenter indent = {} ) const = 0;
     67        virtual Declaration *acceptMutator( Mutator &m ) override = 0;
     68        virtual void print( std::ostream &os, Indenter indent = {} ) const override = 0;
     69        virtual void printShort( std::ostream &os, Indenter indent = {} ) const = 0;
    6970
    7071        UniqueId uniqueId;
     
    8081        int scopeLevel = 0;
    8182
    82         Expression * asmName;
     83        Expression *asmName;
    8384        std::list< Attribute * > attributes;
    8485        bool isDeleted = false;
    8586
    86         DeclarationWithType( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage, const std::list< Attribute * > & attributes, Type::FuncSpecifiers fs );
    87         DeclarationWithType( const DeclarationWithType & other );
     87        DeclarationWithType( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage, const std::list< Attribute * > & attributes, Type::FuncSpecifiers fs );
     88        DeclarationWithType( const DeclarationWithType &other );
    8889        virtual ~DeclarationWithType();
    8990
     
    9697        DeclarationWithType * set_scopeLevel( int newValue ) { scopeLevel = newValue; return this; }
    9798
    98         Expression * get_asmName() const { return asmName; }
    99         DeclarationWithType * set_asmName( Expression * newValue ) { asmName = newValue; return this; }
     99        Expression *get_asmName() const { return asmName; }
     100        DeclarationWithType * set_asmName( Expression *newValue ) { asmName = newValue; return this; }
    100101
    101102        std::list< Attribute * >& get_attributes() { return attributes; }
     
    105106        //void set_functionSpecifiers( Type::FuncSpecifiers newValue ) { fs = newValue; }
    106107
    107         virtual DeclarationWithType * clone() const override = 0;
    108         virtual DeclarationWithType * acceptMutator( Mutator & m )  override = 0;
     108        virtual DeclarationWithType *clone() const override = 0;
     109        virtual DeclarationWithType *acceptMutator( Mutator &m )  override = 0;
    109110
    110111        virtual Type * get_type() const = 0;
     
    118119        typedef DeclarationWithType Parent;
    119120  public:
    120         Type * type;
    121         Initializer * init;
    122         Expression * bitfieldWidth;
    123 
    124         ObjectDecl( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage, Expression * bitfieldWidth, Type * type, Initializer * init,
     121        Type *type;
     122        Initializer *init;
     123        Expression *bitfieldWidth;
     124
     125        ObjectDecl( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage, Expression *bitfieldWidth, Type *type, Initializer *init,
    125126                                const std::list< Attribute * > attributes = std::list< Attribute * >(), Type::FuncSpecifiers fs = Type::FuncSpecifiers() );
    126         ObjectDecl( const ObjectDecl & other );
     127        ObjectDecl( const ObjectDecl &other );
    127128        virtual ~ObjectDecl();
    128129
    129130        virtual Type * get_type() const override { return type; }
    130         virtual void set_type(Type * newType) override { type = newType; }
    131 
    132         Initializer * get_init() const { return init; }
    133         void set_init( Initializer * newValue ) { init = newValue; }
    134 
    135         Expression * get_bitfieldWidth() const { return bitfieldWidth; }
    136         void set_bitfieldWidth( Expression * newValue ) { bitfieldWidth = newValue; }
     131        virtual void set_type(Type *newType) override { type = newType; }
     132
     133        Initializer *get_init() const { return init; }
     134        void set_init( Initializer *newValue ) { init = newValue; }
     135
     136        Expression *get_bitfieldWidth() const { return bitfieldWidth; }
     137        void set_bitfieldWidth( Expression *newValue ) { bitfieldWidth = newValue; }
    137138
    138139        static ObjectDecl * newObject( const std::string & name, Type * type, Initializer * init );
    139140
    140         virtual ObjectDecl * clone() const override { return new ObjectDecl( *this ); }
    141         virtual void accept( Visitor & v ) override { v.visit( this ); }
    142         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    143         virtual DeclarationWithType * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    144         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    145         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     141        virtual ObjectDecl *clone() const override { return new ObjectDecl( *this ); }
     142        virtual void accept( Visitor & v ) override { v.visit( this ); }
     143        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     144        virtual DeclarationWithType *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     145        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     146        virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
    146147};
    147148
     
    149150        typedef DeclarationWithType Parent;
    150151  public:
    151         FunctionType * type;
    152         CompoundStmt * statements;
     152        FunctionType *type;
     153        CompoundStmt *statements;
    153154        std::list< Expression * > withExprs;
    154155
    155         FunctionDecl( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage, FunctionType * type, CompoundStmt * statements,
     156        FunctionDecl( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage, FunctionType *type, CompoundStmt *statements,
    156157                                  const std::list< Attribute * > attributes = std::list< Attribute * >(), Type::FuncSpecifiers fs = Type::FuncSpecifiers() );
    157         FunctionDecl( const FunctionDecl & other );
     158        FunctionDecl( const FunctionDecl &other );
    158159        virtual ~FunctionDecl();
    159160
     
    162163
    163164        FunctionType * get_functionType() const { return type; }
    164         void set_functionType( FunctionType * newValue ) { type = newValue; }
    165         CompoundStmt * get_statements() const { return statements; }
    166         void set_statements( CompoundStmt * newValue ) { statements = newValue; }
     165        void set_functionType( FunctionType *newValue ) { type = newValue; }
     166        CompoundStmt *get_statements() const { return statements; }
     167        void set_statements( CompoundStmt *newValue ) { statements = newValue; }
    167168        bool has_body() const { return NULL != statements; }
    168169
    169170        static FunctionDecl * newFunction( const std::string & name, FunctionType * type, CompoundStmt * statements );
    170171
    171         virtual FunctionDecl * clone() const override { return new FunctionDecl( *this ); }
    172         virtual void accept( Visitor & v ) override { v.visit( this ); }
    173         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    174         virtual DeclarationWithType * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    175         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    176         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     172        virtual FunctionDecl *clone() const override { return new FunctionDecl( *this ); }
     173        virtual void accept( Visitor & v ) override { v.visit( this ); }
     174        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     175        virtual DeclarationWithType *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     176        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     177        virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
    177178};
    178179
     
    180181        typedef Declaration Parent;
    181182  public:
    182         Type * base;
    183         std::list< TypeDecl * > parameters;
    184         std::list< DeclarationWithType * > assertions;
    185 
    186         NamedTypeDecl( const std::string & name, Type::StorageClasses scs, Type * type );
    187         NamedTypeDecl( const NamedTypeDecl & other );
     183        Type *base;
     184        std::list< TypeDecl* > parameters;
     185        std::list< DeclarationWithType* > assertions;
     186
     187        NamedTypeDecl( const std::string &name, Type::StorageClasses scs, Type *type );
     188        NamedTypeDecl( const NamedTypeDecl &other );
    188189        virtual ~NamedTypeDecl();
    189190
    190         Type * get_base() const { return base; }
    191         void set_base( Type * newValue ) { base = newValue; }
    192         std::list< TypeDecl* > & get_parameters() { return parameters; }
    193         std::list< DeclarationWithType * >& get_assertions() { return assertions; }
    194 
    195         virtual const char * typeString() const = 0;
    196 
    197         virtual NamedTypeDecl * clone() const override = 0;
    198         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    199         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     191        Type *get_base() const { return base; }
     192        void set_base( Type *newValue ) { base = newValue; }
     193        std::list< TypeDecl* >& get_parameters() { return parameters; }
     194        std::list< DeclarationWithType* >& get_assertions() { return assertions; }
     195
     196        virtual std::string typeString() const = 0;
     197
     198        virtual NamedTypeDecl *clone() const override = 0;
     199        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     200        virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
    200201};
    201202
     
    203204        typedef NamedTypeDecl Parent;
    204205  public:
    205         enum Kind { Dtype, Otype, Ftype, Ttype, NUMBER_OF_KINDS };
    206 
    207         Kind kind;
     206        enum Kind { Dtype, Ftype, Ttype, NUMBER_OF_KINDS };
     207
     208        Type * init;
    208209        bool sized;
    209         Type * init;
    210210
    211211        /// Data extracted from a type decl
    212212        struct Data {
    213                 Kind kind;
     213                TypeDecl::Kind kind;
    214214                bool isComplete;
    215215
    216                 Data() : kind( NUMBER_OF_KINDS ), isComplete( false ) {}
    217                 Data( const TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
     216                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
     217                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    218218                Data( Kind kind, bool isComplete ) : kind( kind ), isComplete( isComplete ) {}
    219                 Data( const Data & d1, const Data & d2 )
    220                         : kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
    221 
    222                 bool operator==( const Data & other ) const { return kind == other.kind && isComplete == other.isComplete; }
    223                 bool operator!=( const Data & other ) const { return !(*this == other);}
     219                Data( const Data& d1, const Data& d2 )
     220                : kind( d1.kind ), isComplete ( d1.isComplete || d2.isComplete ) {}
     221
     222                bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; }
     223                bool operator!=(const Data & other) const { return !(*this == other);}
    224224        };
    225225
    226         TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init = nullptr );
    227         TypeDecl( const TypeDecl & other );
     226        TypeDecl( const std::string &name, Type::StorageClasses scs, Type *type, Kind kind, bool sized, Type * init = nullptr );
     227        TypeDecl( const TypeDecl &other );
    228228        virtual ~TypeDecl();
    229229
     
    237237        TypeDecl * set_sized( bool newValue ) { sized = newValue; return this; }
    238238
    239         virtual const char * typeString() const override;
    240         virtual const char * genTypeString() const;
    241 
    242         virtual TypeDecl * clone() const override { return new TypeDecl( *this ); }
    243         virtual void accept( Visitor & v ) override { v.visit( this ); }
    244         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    245         virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    246         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     239        virtual std::string typeString() const override;
     240        virtual std::string genTypeString() const;
     241
     242        virtual TypeDecl *clone() const override { return new TypeDecl( *this ); }
     243        virtual void accept( Visitor & v ) override { v.visit( this ); }
     244        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     245        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     246        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     247
     248        Kind kind;
    247249};
    248250
     
    250252        typedef NamedTypeDecl Parent;
    251253  public:
    252         TypedefDecl( const std::string & name, CodeLocation location, Type::StorageClasses scs, Type * type, LinkageSpec::Spec spec = LinkageSpec::Cforall )
     254        TypedefDecl( const std::string &name, CodeLocation location, Type::StorageClasses scs, Type *type, LinkageSpec::Spec spec = LinkageSpec::Cforall )
    253255                : Parent( name, scs, type ) { set_linkage( spec ); this->location = location; }
    254256
    255         TypedefDecl( const TypedefDecl & other ) : Parent( other ) {}
    256 
    257         virtual const char * typeString() const override;
    258 
    259         virtual TypedefDecl * clone() const override { return new TypedefDecl( *this ); }
    260         virtual void accept( Visitor & v ) override { v.visit( this ); }
    261         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    262         virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     257        TypedefDecl( const TypedefDecl &other ) : Parent( other ) {}
     258
     259        virtual std::string typeString() const override;
     260
     261        virtual TypedefDecl *clone() const override { return new TypedefDecl( *this ); }
     262        virtual void accept( Visitor & v ) override { v.visit( this ); }
     263        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     264        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    263265  private:
    264266};
     
    267269        typedef Declaration Parent;
    268270  public:
    269         enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
    270         static const char * aggrString( Aggregate aggr );
    271 
    272271        std::list<Declaration*> members;
    273272        std::list<TypeDecl*> parameters;
     
    276275        AggregateDecl * parent = nullptr;
    277276
    278         AggregateDecl( const std::string & name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall );
    279         AggregateDecl( const AggregateDecl & other );
     277        AggregateDecl( const std::string &name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall );
     278        AggregateDecl( const AggregateDecl &other );
    280279        virtual ~AggregateDecl();
    281280
     
    289288        AggregateDecl * set_body( bool body ) { AggregateDecl::body = body; return this; }
    290289
    291         virtual void print( std::ostream & os, Indenter indent = {} ) const override final;
    292         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     290        virtual void print( std::ostream &os, Indenter indent = {} ) const override final;
     291        virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
    293292  protected:
    294         virtual const char * typeString() const = 0;
     293        virtual std::string typeString() const = 0;
    295294};
    296295
     
    298297        typedef AggregateDecl Parent;
    299298  public:
    300         StructDecl( const std::string & name, Aggregate kind = Struct, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ), kind( kind ) {}
    301         StructDecl( const StructDecl & other ) : Parent( other ), kind( other.kind ) {}
    302 
    303         bool is_coroutine() { return kind == Coroutine; }
    304         bool is_generator() { return kind == Generator; }
    305         bool is_monitor  () { return kind == Monitor  ; }
    306         bool is_thread   () { return kind == Thread   ; }
    307 
    308         virtual StructDecl * clone() const override { return new StructDecl( *this ); }
    309         virtual void accept( Visitor & v ) override { v.visit( this ); }
    310         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    311         virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    312         Aggregate kind;
    313   private:
    314         virtual const char * typeString() const override;
     299        StructDecl( const std::string &name, DeclarationNode::Aggregate kind = DeclarationNode::Struct, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ), kind( kind ) {}
     300        StructDecl( const StructDecl &other ) : Parent( other ), kind( other.kind ) {}
     301
     302        bool is_coroutine() { return kind == DeclarationNode::Coroutine; }
     303        bool is_monitor() { return kind == DeclarationNode::Monitor; }
     304        bool is_thread() { return kind == DeclarationNode::Thread; }
     305
     306        virtual StructDecl *clone() const override { return new StructDecl( *this ); }
     307        virtual void accept( Visitor & v ) override { v.visit( this ); }
     308        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     309        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     310        DeclarationNode::Aggregate kind;
     311  private:
     312        virtual std::string typeString() const override;
    315313};
    316314
     
    318316        typedef AggregateDecl Parent;
    319317  public:
    320         UnionDecl( const std::string & name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ) {}
    321         UnionDecl( const UnionDecl & other ) : Parent( other ) {}
    322 
    323         virtual UnionDecl * clone() const override { return new UnionDecl( *this ); }
    324         virtual void accept( Visitor & v ) override { v.visit( this ); }
    325         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    326         virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    327   private:
    328         virtual const char * typeString() const override;
     318        UnionDecl( const std::string &name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ) {}
     319        UnionDecl( const UnionDecl &other ) : Parent( other ) {}
     320
     321        virtual UnionDecl *clone() const override { return new UnionDecl( *this ); }
     322        virtual void accept( Visitor & v ) override { v.visit( this ); }
     323        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     324        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     325  private:
     326        virtual std::string typeString() const override;
    329327};
    330328
     
    332330        typedef AggregateDecl Parent;
    333331  public:
    334         EnumDecl( const std::string & name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ) {}
    335         EnumDecl( const EnumDecl & other ) : Parent( other ) {}
     332        EnumDecl( const std::string &name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ) {}
     333        EnumDecl( const EnumDecl &other ) : Parent( other ) {}
    336334
    337335        bool valueOf( Declaration * enumerator, long long int & value );
    338336
    339         virtual EnumDecl * clone() const override { return new EnumDecl( *this ); }
    340         virtual void accept( Visitor & v ) override { v.visit( this ); }
    341         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    342         virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     337        virtual EnumDecl *clone() const override { return new EnumDecl( *this ); }
     338        virtual void accept( Visitor & v ) override { v.visit( this ); }
     339        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     340        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    343341  private:
    344342        std::unordered_map< std::string, long long int > enumValues;
    345         virtual const char * typeString() const override;
     343        virtual std::string typeString() const override;
    346344};
    347345
     
    349347        typedef AggregateDecl Parent;
    350348  public:
    351         TraitDecl( const std::string & name, const std::list< Attribute * > & attributes, LinkageSpec::Spec linkage ) : Parent( name, attributes, linkage ) {
     349        TraitDecl( const std::string &name, const std::list< Attribute * > & attributes, LinkageSpec::Spec linkage ) : Parent( name, attributes, linkage ) {
    352350                assertf( attributes.empty(), "attribute unsupported for traits" );
    353351        }
    354         TraitDecl( const TraitDecl & other ) : Parent( other ) {}
    355 
    356         virtual TraitDecl * clone() const override { return new TraitDecl( *this ); }
    357         virtual void accept( Visitor & v ) override { v.visit( this ); }
    358         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    359         virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    360   private:
    361         virtual const char * typeString() const override;
     352        TraitDecl( const TraitDecl &other ) : Parent( other ) {}
     353
     354        virtual TraitDecl *clone() const override { return new TraitDecl( *this ); }
     355        virtual void accept( Visitor & v ) override { v.visit( this ); }
     356        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     357        virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     358  private:
     359        virtual std::string typeString() const override;
    362360};
    363361
     
    381379class AsmDecl : public Declaration {
    382380  public:
    383         AsmStmt * stmt;
    384 
    385         AsmDecl( AsmStmt * stmt );
    386         AsmDecl( const AsmDecl & other );
     381        AsmStmt *stmt;
     382
     383        AsmDecl( AsmStmt *stmt );
     384        AsmDecl( const AsmDecl &other );
    387385        virtual ~AsmDecl();
    388386
    389         AsmStmt * get_stmt() { return stmt; }
    390         void set_stmt( AsmStmt * newValue ) { stmt = newValue; }
    391 
    392         virtual AsmDecl * clone() const override { return new AsmDecl( *this ); }
    393         virtual void accept( Visitor & v ) override { v.visit( this ); }
    394         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    395         virtual AsmDecl * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    396         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    397         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     387        AsmStmt *get_stmt() { return stmt; }
     388        void set_stmt( AsmStmt *newValue ) { stmt = newValue; }
     389
     390        virtual AsmDecl *clone() const override { return new AsmDecl( *this ); }
     391        virtual void accept( Visitor & v ) override { v.visit( this ); }
     392        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     393        virtual AsmDecl *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     394        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     395        virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
    398396};
    399397
     
    410408        virtual void accept( Visitor & v ) override { v.visit( this ); }
    411409        virtual void accept( Visitor & v ) const override { v.visit( this ); }
    412         virtual StaticAssertDecl * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    413         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    414         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     410        virtual StaticAssertDecl * acceptMutator( Mutator &m )  override { return m.mutate( this ); }
     411        virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     412        virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
    415413};
    416414
  • src/SynTree/DeclarationWithType.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:45:16 2019
    13 // Update Count     : 26
     12// Last Modified On : Thu Mar 16 08:34:35 2017
     13// Update Count     : 25
    1414//
    1515
     
    2020#include "Common/utility.h"      // for cloneAll, deleteAll, maybeClone
    2121#include "Declaration.h"         // for DeclarationWithType, Declaration
    22 #include "LinkageSpec.h"         // for Spec
    23 #include "Expression.h"          // for ConstantExpr
     22#include "Parser/LinkageSpec.h"  // for Spec
     23#include "SynTree/Expression.h"  // for ConstantExpr
    2424#include "Type.h"                // for Type, Type::FuncSpecifiers, Type::St...
    2525
  • src/SynTree/Expression.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 07:55:15 2019
    13 // Update Count     : 70
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Aug 15 13:43:00 2019
     13// Update Count     : 64
    1414//
    1515
     
    2222
    2323#include "Common/utility.h"          // for maybeClone, cloneAll, deleteAll
     24#include "Declaration.h"             // for ObjectDecl, DeclarationWithType
    2425#include "Expression.h"              // for Expression, ImplicitCopyCtorExpr
    2526#include "InitTweak/InitTweak.h"     // for getCallArg, getPointerBase
     
    293294}
    294295
    295 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {
     296KeywordCastExpr::KeywordCastExpr( Expression * arg, Target target ) : Expression(), arg(arg), target( target ) {
    296297}
    297298
     
    303304}
    304305
    305 const char * KeywordCastExpr::targetString() const {
    306         return AggregateDecl::aggrString( target );
     306const std::string & KeywordCastExpr::targetString() const {
     307        static const std::string targetStrs[] = {
     308                "coroutine", "thread", "monitor"
     309        };
     310        static_assert(
     311                (sizeof(targetStrs) / sizeof(targetStrs[0])) == ((unsigned long)NUMBER_OF_TARGETS),
     312                "Each KeywordCastExpr::Target should have a corresponding string representation"
     313        );
     314        return targetStrs[(unsigned long)target];
    307315}
    308316
  • src/SynTree/Expression.h

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 16:50:19 2019
    13 // Update Count     : 60
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Aug 15 13:46:00 2019
     13// Update Count     : 54
    1414//
    1515
     
    2828#include "Label.h"                // for Label
    2929#include "Mutator.h"              // for Mutator
    30 #include "Declaration.h"          // for Aggregate
    3130#include "SynTree.h"              // for UniqueId
    3231#include "Visitor.h"              // for Visitor
     
    230229public:
    231230        Expression * arg;
    232         struct Concrete {
    233                 std::string field;
    234                 std::string getter;
    235         };
    236         AggregateDecl::Aggregate target;
    237         Concrete concrete_target;
    238 
    239         KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target );
     231        enum Target {
     232                Coroutine, Thread, Monitor, NUMBER_OF_TARGETS
     233        } target;
     234
     235        KeywordCastExpr( Expression * arg, Target target );
    240236        KeywordCastExpr( const KeywordCastExpr & other );
    241237        virtual ~KeywordCastExpr();
    242238
    243         const char * targetString() const;
     239        const std::string & targetString() const;
    244240
    245241        virtual KeywordCastExpr * clone() const override { return new KeywordCastExpr( * this ); }
  • src/SynTree/FunctionDecl.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:11:20 2019
    13 // Update Count     : 77
     12// Last Modified On : Thu Mar 16 08:33:41 2017
     13// Update Count     : 74
    1414//
    1515
     
    2323#include "Common/utility.h"      // for maybeClone, printAll
    2424#include "Declaration.h"         // for FunctionDecl, FunctionDecl::Parent
    25 #include "Expression.h"
    26 #include "LinkageSpec.h"         // for Spec, linkageName, Cforall
     25#include "Parser/LinkageSpec.h"  // for Spec, linkageName, Cforall
    2726#include "Statement.h"           // for CompoundStmt
    2827#include "Type.h"                // for Type, FunctionType, Type::FuncSpecif...
     
    7372        } // if
    7473        if ( linkage != LinkageSpec::Cforall ) {
    75                 os << LinkageSpec::name( linkage ) << " ";
     74                os << LinkageSpec::linkageName( linkage ) << " ";
    7675        } // if
    7776
  • src/SynTree/Mutator.h

    r7030dab r71d6bd8  
    5151        virtual Statement * mutate( CatchStmt * catchStmt ) = 0;
    5252        virtual Statement * mutate( FinallyStmt * catchStmt ) = 0;
    53         virtual Statement * mutate( SuspendStmt * suspendStmt ) = 0;
    5453        virtual Statement * mutate( WaitForStmt * waitforStmt ) = 0;
    5554        virtual Declaration * mutate( WithStmt * withStmt ) = 0;
  • src/SynTree/NamedTypeDecl.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:11:40 2019
    13 // Update Count     : 17
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Aug  9 13:28:00 2017
     13// Update Count     : 14
    1414//
    1515
     
    2020#include "Common/utility.h"      // for printAll, cloneAll, deleteAll, maybe...
    2121#include "Declaration.h"         // for NamedTypeDecl, DeclarationWithType
    22 #include "LinkageSpec.h"         // for Spec, Cforall, linkageName
     22#include "Parser/LinkageSpec.h"  // for Spec, Cforall, linkageName
    2323#include "Type.h"                // for Type, Type::StorageClasses
    2424
     
    4444
    4545        if ( linkage != LinkageSpec::Cforall ) {
    46                 os << LinkageSpec::name( linkage ) << " ";
     46                os << LinkageSpec::linkageName( linkage ) << " ";
    4747        } // if
    4848        get_storageClasses().print( os );
     
    7878}
    7979
    80 const char * TypedefDecl::typeString() const { return "typedef"; }
     80std::string TypedefDecl::typeString() const { return "typedef"; }
    8181
    8282// Local Variables: //
  • src/SynTree/ObjectDecl.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:12:03 2019
    13 // Update Count     : 61
     12// Last Modified On : Thu Mar 16 08:34:27 2017
     13// Update Count     : 59
    1414//
    1515
     
    2323#include "Expression.h"          // for Expression
    2424#include "Initializer.h"         // for Initializer
    25 #include "LinkageSpec.h"         // for Spec, linkageName, Cforall
     25#include "Parser/LinkageSpec.h"  // for Spec, linkageName, Cforall
    2626#include "Type.h"                // for Type, Type::StorageClasses, Type::Fu...
    2727
     
    4848
    4949        if ( linkage != LinkageSpec::Cforall ) {
    50                 os << LinkageSpec::name( linkage ) << " ";
     50                os << LinkageSpec::linkageName( linkage ) << " ";
    5151        } // if
    5252
  • src/SynTree/Statement.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jan 20 16:03:00 2020
    13 // Update Count     : 71
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Sep  3 20:46:44 2017
     13// Update Count     : 68
    1414//
    1515
     
    4646Statement::~Statement() {}
    4747
    48 ExprStmt::ExprStmt( Expression * expr ) : Statement(), expr( expr ) {}
    49 
    50 ExprStmt::ExprStmt( const ExprStmt & other ) : Statement( other ), expr( maybeClone( other.expr ) ) {}
     48ExprStmt::ExprStmt( Expression *expr ) : Statement(), expr( expr ) {}
     49
     50ExprStmt::ExprStmt( const ExprStmt &other ) : Statement( other ), expr( maybeClone( other.expr ) ) {}
    5151
    5252ExprStmt::~ExprStmt() {
     
    5454}
    5555
    56 void ExprStmt::print( std::ostream & os, Indenter indent ) const {
     56void ExprStmt::print( std::ostream &os, Indenter indent ) const {
    5757        os << "Expression Statement:" << endl << indent+1;
    5858        expr->print( os, indent+1 );
     
    6060
    6161
    62 AsmStmt::AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels ) : Statement(), voltile( voltile ), instruction( instruction ), output( output ), input( input ), clobber( clobber ), gotolabels( gotolabels ) {}
     62AsmStmt::AsmStmt( bool voltile, Expression *instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels ) : Statement(), voltile( voltile ), instruction( instruction ), output( output ), input( input ), clobber( clobber ), gotolabels( gotolabels ) {}
    6363
    6464AsmStmt::AsmStmt( const AsmStmt & other ) : Statement( other ), voltile( other.voltile ), instruction( maybeClone( other.instruction ) ), gotolabels( other.gotolabels ) {
     
    7575}
    7676
    77 void AsmStmt::print( std::ostream & os, Indenter indent ) const {
     77void AsmStmt::print( std::ostream &os, Indenter indent ) const {
    7878        os << "Assembler Statement:" << endl;
    7979        os << indent+1 << "instruction: " << endl << indent;
     
    9696DirectiveStmt::DirectiveStmt( const std::string & directive ) : Statement(), directive( directive ) {}
    9797
    98 void DirectiveStmt::print( std::ostream & os, Indenter ) const {
     98void DirectiveStmt::print( std::ostream &os, Indenter ) const {
    9999        os << "GCC Directive:" << directive << endl;
    100100}
    101101
    102102
    103 const char * BranchStmt::brType[] = {
    104         "Goto", "Break", "Continue", "Fall Through", "Fall Through Default",
    105 };
     103const char *BranchStmt::brType[] = { "Goto", "Break", "Continue" };
    106104
    107105BranchStmt::BranchStmt( Label target, Type type ) throw ( SemanticErrorException ) :
     
    113111}
    114112
    115 BranchStmt::BranchStmt( Expression * computedTarget, Type type ) throw ( SemanticErrorException ) :
     113BranchStmt::BranchStmt( Expression *computedTarget, Type type ) throw ( SemanticErrorException ) :
    116114        Statement(), computedTarget( computedTarget ), type( type ) {
    117115        if ( type != BranchStmt::Goto || computedTarget == nullptr ) {
     
    120118}
    121119
    122 void BranchStmt::print( std::ostream & os, Indenter indent ) const {
    123         assert(type < 5);
     120void BranchStmt::print( std::ostream &os, Indenter indent ) const {
    124121        os << "Branch (" << brType[type] << ")" << endl ;
    125122        if ( target != "" ) os << indent+1 << "with target: " << target << endl;
     
    128125}
    129126
    130 ReturnStmt::ReturnStmt( Expression * expr ) : Statement(), expr( expr ) {}
     127ReturnStmt::ReturnStmt( Expression *expr ) : Statement(), expr( expr ) {}
    131128
    132129ReturnStmt::ReturnStmt( const ReturnStmt & other ) : Statement( other ), expr( maybeClone( other.expr ) ) {}
     
    136133}
    137134
    138 void ReturnStmt::print( std::ostream & os, Indenter indent ) const {
     135void ReturnStmt::print( std::ostream &os, Indenter indent ) const {
    139136        os << "Return Statement, returning: ";
    140137        if ( expr != nullptr ) {
     
    145142}
    146143
    147 IfStmt::IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart, std::list<Statement *> initialization ):
     144IfStmt::IfStmt( Expression *condition, Statement *thenPart, Statement *elsePart, std::list<Statement *> initialization ):
    148145        Statement(), condition( condition ), thenPart( thenPart ), elsePart( elsePart ), initialization( initialization ) {}
    149146
     
    160157}
    161158
    162 void IfStmt::print( std::ostream & os, Indenter indent ) const {
     159void IfStmt::print( std::ostream &os, Indenter indent ) const {
    163160        os << "If on condition: " << endl;
    164161        os << indent+1;
     
    179176        thenPart->print( os, indent+1 );
    180177
    181         if ( elsePart != nullptr ) {
     178        if ( elsePart != 0 ) {
    182179                os << indent << "... else: " << endl;
    183180                os << indent+1;
     
    186183}
    187184
    188 SwitchStmt::SwitchStmt( Expression * condition, const std::list<Statement *> & statements ):
     185SwitchStmt::SwitchStmt( Expression * condition, const std::list<Statement *> &statements ):
    189186        Statement(), condition( condition ), statements( statements ) {
    190187}
     
    201198}
    202199
    203 void SwitchStmt::print( std::ostream & os, Indenter indent ) const {
     200void SwitchStmt::print( std::ostream &os, Indenter indent ) const {
    204201        os << "Switch on condition: ";
    205202        condition->print( os );
     
    211208}
    212209
    213 CaseStmt::CaseStmt( Expression * condition, const std::list<Statement *> & statements, bool deflt ) throw ( SemanticErrorException ) :
     210CaseStmt::CaseStmt( Expression *condition, const std::list<Statement *> &statements, bool deflt ) throw ( SemanticErrorException ) :
    214211        Statement(), condition( condition ), stmts( statements ), _isDefault( deflt ) {
    215         if ( isDefault() && condition != nullptr ) SemanticError( condition, "default case with condition: " );
     212        if ( isDefault() && condition != 0 ) SemanticError( condition, "default case with condition: " );
    216213}
    217214
     
    232229}
    233230
    234 void CaseStmt::print( std::ostream & os, Indenter indent ) const {
     231void CaseStmt::print( std::ostream &os, Indenter indent ) const {
    235232        if ( isDefault() ) os << indent << "Default ";
    236233        else {
     
    246243}
    247244
    248 WhileStmt::WhileStmt( Expression * condition, Statement * body, std::list< Statement * > & initialization, bool isDoWhile ):
     245WhileStmt::WhileStmt( Expression *condition, Statement *body, std::list< Statement * > & initialization, bool isDoWhile ):
    249246        Statement(), condition( condition), body( body), initialization( initialization ), isDoWhile( isDoWhile) {
    250247}
     
    259256}
    260257
    261 void WhileStmt::print( std::ostream & os, Indenter indent ) const {
     258void WhileStmt::print( std::ostream &os, Indenter indent ) const {
    262259        os << "While on condition: " << endl ;
    263260        condition->print( os, indent+1 );
     
    265262        os << indent << "... with body: " << endl;
    266263
    267         if ( body != nullptr ) body->print( os, indent+1 );
    268 }
    269 
    270 ForStmt::ForStmt( std::list<Statement *> initialization, Expression * condition, Expression * increment, Statement * body ):
     264        if ( body != 0 ) body->print( os, indent+1 );
     265}
     266
     267ForStmt::ForStmt( std::list<Statement *> initialization, Expression *condition, Expression *increment, Statement *body ):
    271268        Statement(), initialization( initialization ), condition( condition ), increment( increment ), body( body ) {
    272269}
     
    285282}
    286283
    287 void ForStmt::print( std::ostream & os, Indenter indent ) const {
     284void ForStmt::print( std::ostream &os, Indenter indent ) const {
    288285        Statement::print( os, indent ); // print labels
    289286
     
    308305        }
    309306
    310         if ( body != nullptr ) {
     307        if ( body != 0 ) {
    311308                os << "\n" << indent << "... with body: \n" << indent+1;
    312309                body->print( os, indent+1 );
     
    320317}
    321318
    322 ThrowStmt::ThrowStmt( const ThrowStmt & other ) :
     319ThrowStmt::ThrowStmt( const ThrowStmt &other ) :
    323320        Statement ( other ), kind( other.kind ), expr( maybeClone( other.expr ) ), target( maybeClone( other.target ) ) {
    324321}
     
    329326}
    330327
    331 void ThrowStmt::print( std::ostream & os, Indenter indent) const {
     328void ThrowStmt::print( std::ostream &os, Indenter indent) const {
    332329        if ( target ) os << "Non-Local ";
    333330        os << "Throw Statement, raising: ";
     
    339336}
    340337
    341 TryStmt::TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock ) :
     338TryStmt::TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock ) :
    342339        Statement(), block( tryBlock ),  handlers( handlers ), finallyBlock( finallyBlock ) {
    343340}
    344341
    345 TryStmt::TryStmt( const TryStmt & other ) : Statement( other ), block( maybeClone( other.block ) ), finallyBlock( maybeClone( other.finallyBlock ) ) {
     342TryStmt::TryStmt( const TryStmt &other ) : Statement( other ), block( maybeClone( other.block ) ), finallyBlock( maybeClone( other.finallyBlock ) ) {
    346343        cloneAll( other.handlers, handlers );
    347344}
     
    353350}
    354351
    355 void TryStmt::print( std::ostream & os, Indenter indent ) const {
     352void TryStmt::print( std::ostream &os, Indenter indent ) const {
    356353        os << "Try Statement" << endl;
    357354        os << indent << "... with block:" << endl << indent+1;
     
    366363
    367364        // finally block
    368         if ( finallyBlock != nullptr ) {
     365        if ( finallyBlock != 0 ) {
    369366                os << indent << "... and finally:" << endl << indent+1;
    370367                finallyBlock->print( os, indent+1 );
     
    372369}
    373370
    374 CatchStmt::CatchStmt( Kind kind, Declaration * decl, Expression * cond, Statement * body ) :
     371CatchStmt::CatchStmt( Kind kind, Declaration *decl, Expression *cond, Statement *body ) :
    375372        Statement(), kind ( kind ), decl ( decl ), cond ( cond ), body( body ) {
    376373                assertf( decl, "Catch clause must have a declaration." );
     
    386383}
    387384
    388 void CatchStmt::print( std::ostream & os, Indenter indent ) const {
     385void CatchStmt::print( std::ostream &os, Indenter indent ) const {
    389386        os << "Catch " << ((Terminate == kind) ? "Terminate" : "Resume") << " Statement" << endl;
    390387
     
    404401
    405402
    406 FinallyStmt::FinallyStmt( CompoundStmt * block ) : Statement(), block( block ) {
     403FinallyStmt::FinallyStmt( CompoundStmt *block ) : Statement(), block( block ) {
    407404}
    408405
     
    414411}
    415412
    416 void FinallyStmt::print( std::ostream & os, Indenter indent ) const {
     413void FinallyStmt::print( std::ostream &os, Indenter indent ) const {
    417414        os << "Finally Statement" << endl;
    418415        os << indent << "... with block:" << endl << indent+1;
    419416        block->print( os, indent+1 );
    420 }
    421 
    422 SuspendStmt::SuspendStmt( const SuspendStmt & other )
    423         : Statement( other )
    424         , then( maybeClone(other.then) )
    425 {}
    426 
    427 SuspendStmt::~SuspendStmt() {
    428         delete then;
    429 }
    430 
    431 void SuspendStmt::print( std::ostream & os, Indenter indent ) const {
    432         os << "Suspend Statement";
    433         switch (type) {
    434                 case None     : os << " with implicit target"; break;
    435                 case Generator: os << " for generator"       ; break;
    436                 case Coroutine: os << " for coroutine"       ; break;
    437         }
    438         os << endl;
    439         indent += 1;
    440 
    441         if(then) {
    442                 os << indent << " with post statement :" << endl;
    443                 then->print( os, indent + 1);
    444         }
    445417}
    446418
     
    486458}
    487459
    488 void WaitForStmt::print( std::ostream & os, Indenter indent ) const {
     460void WaitForStmt::print( std::ostream &os, Indenter indent ) const {
    489461        os << "Waitfor Statement" << endl;
    490462        indent += 1;
     
    542514}
    543515
    544 void NullStmt::print( std::ostream & os, Indenter indent ) const {
     516void NullStmt::print( std::ostream &os, Indenter indent ) const {
    545517        os << "Null Statement" << endl;
    546518        Statement::print( os, indent );
     
    558530}
    559531
    560 void ImplicitCtorDtorStmt::print( std::ostream & os, Indenter indent ) const {
     532void ImplicitCtorDtorStmt::print( std::ostream &os, Indenter indent ) const {
    561533        os << "Implicit Ctor Dtor Statement" << endl;
    562534        os << indent << "... with Ctor/Dtor: ";
  • src/SynTree/Statement.h

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jan 10 14:13:24 2020
    13 // Update Count     : 85
     12// Last Modified On : Tue Mar 12 09:01:53 2019
     13// Update Count     : 83
    1414//
    1515
     
    257257        Statement * body;
    258258
    259         ForStmt( std::list<Statement *> initialization, Expression * condition = nullptr, Expression * increment = nullptr, Statement * body = nullptr );
     259        ForStmt( std::list<Statement *> initialization, Expression * condition = 0, Expression * increment = 0, Statement * body = 0 );
    260260        ForStmt( const ForStmt & other );
    261261        virtual ~ForStmt();
     
    357357        FinallyStmt * finallyBlock;
    358358
    359         TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = nullptr );
     359        TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 );
    360360        TryStmt( const TryStmt & other );
    361361        virtual ~TryStmt();
     
    422422};
    423423
    424 class SuspendStmt : public Statement {
    425   public:
    426         CompoundStmt * then = nullptr;
    427         enum Type { None, Coroutine, Generator } type = None;
    428 
    429         SuspendStmt() = default;
    430         SuspendStmt( const SuspendStmt & );
    431         virtual ~SuspendStmt();
    432 
    433         virtual SuspendStmt * clone() const override { return new SuspendStmt( *this ); }
    434         virtual void accept( Visitor & v ) override { v.visit( this ); }
    435         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    436         virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    437         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    438 };
    439 
    440424class WaitForStmt : public Statement {
    441425  public:
  • src/SynTree/SynTree.h

    r7030dab r71d6bd8  
    5454class CatchStmt;
    5555class FinallyStmt;
    56 class SuspendStmt;
    5756class WaitForStmt;
    5857class WithStmt;
  • src/SynTree/TupleType.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:44:38 2019
    13 // Update Count     : 4
     12// Last Modified On : Wed Feb  1 17:10:58 2017
     13// Update Count     : 3
    1414//
    1515
     
    2020#include "Declaration.h"         // for Declaration, ObjectDecl
    2121#include "Initializer.h"         // for ListInit
    22 #include "LinkageSpec.h"         // for Cforall
     22#include "Parser/LinkageSpec.h"  // for Cforall
    2323#include "Type.h"                // for TupleType, Type, Type::Qualifiers
    2424
  • src/SynTree/Type.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 15 16:52:37 2019
    13 // Update Count     : 49
     12// Last Modified On : Sun Aug  4 21:05:07 2019
     13// Update Count     : 45
    1414//
    1515#include "Type.h"
     
    2424using namespace std;
    2525
    26 // GENERATED START, DO NOT EDIT
    27 // GENERATED BY BasicTypes-gen.cc
    2826const char * BasicType::typeNames[] = {
    2927        "_Bool",
     
    4745        "float",
    4846        "float _Complex",
     47        //"float _Imaginary",
    4948        "_Float32x",
    5049        "_Float32x _Complex",
     
    5352        "double",
    5453        "double _Complex",
     54        //"double _Imaginary",
    5555        "_Float64x",
    5656        "_Float64x _Complex",
     
    6161        "long double",
    6262        "long double _Complex",
     63        //"long double _Imaginary",
    6364        "_Float128x",
    6465        "_Float128x _Complex",
    6566};
    66 // GENERATED END
     67static_assert(
     68        sizeof(BasicType::typeNames) / sizeof(BasicType::typeNames[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
     69        "Each basic type name should have a corresponding kind enum value"
     70);
    6771
    6872Type::Type( const Qualifiers &tq, const std::list< Attribute * > & attributes ) : tq( tq ), attributes( attributes ) {}
  • src/SynTree/TypeDecl.cc

    r7030dab r71d6bd8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 15:26:14 2019
    13 // Update Count     : 21
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Aug  9 14:35:00 2017
     13// Update Count     : 6
    1414//
    1515
     
    2121#include "Type.h"            // for Type, Type::StorageClasses
    2222
    23 TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) : Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) {
     23TypeDecl::TypeDecl( const std::string &name, Type::StorageClasses scs, Type *type, Kind kind, bool sized, Type * init ) : Parent( name, scs, type ), init( init ), sized( kind == Ttype || sized ), kind( kind ) {
    2424}
    2525
    26 TypeDecl::TypeDecl( const TypeDecl & other ) : Parent( other ), kind( other.kind ), sized( other.sized ), init( maybeClone( other.init ) ) {
     26TypeDecl::TypeDecl( const TypeDecl &other ) : Parent( other ), init( maybeClone( other.init ) ), sized( other.sized ), kind( other.kind ) {
    2727}
    2828
    2929TypeDecl::~TypeDecl() {
    30         delete init;
     30  delete init;
    3131}
    3232
    33 const char * TypeDecl::typeString() const {
    34         static const char * kindNames[] = { "sized data type", "sized object type", "sized function type", "sized tuple type" };
    35         static_assert( sizeof(kindNames)/sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." );
    36         assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
    37         return isComplete() ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
     33std::string TypeDecl::typeString() const {
     34        static const std::string kindNames[] = { "object type", "function type", "tuple type" };
     35        assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1, "typeString: kindNames is out of sync." );
     36        assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
     37        return (isComplete() ? "sized " : "") + kindNames[ kind ];
    3838}
    3939
    40 const char * TypeDecl::genTypeString() const {
    41         static const char * kindNames[] = { "dtype", "otype", "ftype", "ttype" };
    42         static_assert( sizeof(kindNames)/sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "genTypeString: kindNames is out of sync." );
    43         assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
     40std::string TypeDecl::genTypeString() const {
     41        static const std::string kindNames[] = { "dtype", "ftype", "ttype" };
     42        assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1, "genTypeString: kindNames is out of sync." );
     43        assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
    4444        return kindNames[ kind ];
    4545}
    4646
    4747void TypeDecl::print( std::ostream &os, Indenter indent ) const {
    48         NamedTypeDecl::print( os, indent );
    49         if ( init ) {
    50                 os << std::endl << indent << "with type initializer: ";
    51                 init->print( os, indent + 1 );
    52         } // if
     48  NamedTypeDecl::print( os, indent );
     49  if ( init ) {
     50    os << std::endl << indent << "with type initializer: ";
     51    init->print( os, indent + 1 );
     52  }
    5353}
    5454
     55
    5556std::ostream & operator<<( std::ostream & os, const TypeDecl::Data & data ) {
    56         return os << data.kind << ", " << data.isComplete;
     57  return os << data.kind << ", " << data.isComplete;
    5758}
    5859
  • src/SynTree/Visitor.h

    r7030dab r71d6bd8  
    7878        virtual void visit( FinallyStmt * node ) { visit( const_cast<const FinallyStmt *>(node) ); }
    7979        virtual void visit( const FinallyStmt * finallyStmt ) = 0;
    80         virtual void visit( SuspendStmt * node ) { visit( const_cast<const SuspendStmt *>(node) ); }
    81         virtual void visit( const SuspendStmt * suspendStmt ) = 0;
    8280        virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); }
    8381        virtual void visit( const WaitForStmt * waitforStmt ) = 0;
  • src/SynTree/module.mk

    r7030dab r71d6bd8  
    1111## Created On       : Mon Jun  1 17:49:17 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Dec 14 07:26:43 2019
    14 ## Update Count     : 2
     13## Last Modified On : Mon Jun  1 17:54:09 2015
     14## Update Count     : 1
    1515###############################################################################
    1616
    1717SRC_SYNTREE = \
     18      SynTree/Type.cc \
     19      SynTree/VoidType.cc \
     20      SynTree/BasicType.cc \
     21      SynTree/PointerType.cc \
     22      SynTree/ArrayType.cc \
     23      SynTree/ReferenceType.cc \
     24      SynTree/FunctionType.cc \
     25      SynTree/ReferenceToType.cc \
     26      SynTree/TupleType.cc \
     27      SynTree/TypeofType.cc \
     28      SynTree/AttrType.cc \
     29      SynTree/VarArgsType.cc \
     30      SynTree/ZeroOneType.cc \
     31      SynTree/Constant.cc \
     32      SynTree/Expression.cc \
     33      SynTree/TupleExpr.cc \
     34      SynTree/CommaExpr.cc \
     35      SynTree/TypeExpr.cc \
     36      SynTree/ApplicationExpr.cc \
    1837      SynTree/AddressExpr.cc \
    19       SynTree/AggregateDecl.cc \
    20       SynTree/ApplicationExpr.cc \
    21       SynTree/ArrayType.cc \
    22       SynTree/AttrType.cc \
    23       SynTree/Attribute.cc \
    24       SynTree/BasicType.cc \
    25       SynTree/CommaExpr.cc \
     38      SynTree/Statement.cc \
    2639      SynTree/CompoundStmt.cc \
    27       SynTree/Constant.cc \
    28       SynTree/DeclReplacer.cc \
    2940      SynTree/DeclStmt.cc \
    3041      SynTree/Declaration.cc \
    3142      SynTree/DeclarationWithType.cc \
    32       SynTree/Expression.cc \
     43      SynTree/ObjectDecl.cc \
    3344      SynTree/FunctionDecl.cc \
    34       SynTree/FunctionType.cc \
     45      SynTree/AggregateDecl.cc \
     46      SynTree/NamedTypeDecl.cc \
     47      SynTree/TypeDecl.cc \
    3548      SynTree/Initializer.cc \
    36       SynTree/LinkageSpec.cc \
    37       SynTree/NamedTypeDecl.cc \
    38       SynTree/ObjectDecl.cc \
    39       SynTree/PointerType.cc \
    40       SynTree/ReferenceToType.cc \
    41       SynTree/ReferenceType.cc \
    42       SynTree/Statement.cc \
    43       SynTree/TupleExpr.cc \
    44       SynTree/TupleType.cc \
    45       SynTree/Type.cc \
    46       SynTree/TypeDecl.cc \
    47       SynTree/TypeExpr.cc \
    4849      SynTree/TypeSubstitution.cc \
    49       SynTree/TypeofType.cc \
    50       SynTree/VarArgsType.cc \
    51       SynTree/VoidType.cc \
    52       SynTree/ZeroOneType.cc
     50      SynTree/Attribute.cc \
     51      SynTree/DeclReplacer.cc
    5352
    5453SRC += $(SRC_SYNTREE)
  • src/Tuples/TupleAssignment.cc

    r7030dab r71d6bd8  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:45:33 2019
    13 // Update Count     : 9
     12// Last Modified On : Fri Mar 17 09:43:03 2017
     13// Update Count     : 8
    1414//
    1515
     
    3434#include "InitTweak/GenInit.h"             // for genCtorInit
    3535#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
     36#include "Parser/LinkageSpec.h"            // for Cforall
    3637#include "ResolvExpr/Alternative.h"        // for AltList, Alternative
    3738#include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
     
    4041#include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    4142#include "ResolvExpr/typeops.h"            // for combos
    42 #include "SynTree/LinkageSpec.h"           // for Cforall
    4343#include "SynTree/Declaration.h"           // for ObjectDecl
    4444#include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
  • src/Tuples/TupleExpansion.cc

    r7030dab r71d6bd8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:45:51 2019
    13 // Update Count     : 24
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct  4 15:38:00 2019
     13// Update Count     : 23
    1414//
    1515
     
    2727#include "Common/utility.h"       // for CodeLocation
    2828#include "InitTweak/InitTweak.h"  // for getFunction
    29 #include "SynTree/LinkageSpec.h"  // for Spec, C, Intrinsic
     29#include "Parser/LinkageSpec.h"   // for Spec, C, Intrinsic
    3030#include "SynTree/Constant.h"     // for Constant
    3131#include "SynTree/Declaration.h"  // for StructDecl, DeclarationWithType
     
    361361        const ast::TypeInstType * isTtype( const ast::Type * type ) {
    362362                if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
    363                         if ( inst->base && inst->base->kind == ast::TypeDecl::Ttype ) {
     363                        if ( inst->base && inst->base->kind == ast::TypeVar::Ttype ) {
    364364                                return inst;
    365365                        }
  • src/cfa.make

    r7030dab r71d6bd8  
     1
     2
    13CFACOMPILE = $(CFACC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) $(AM_CFLAGS) $(CFLAGS)
    24LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    35        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
    4         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
     6        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
     7        $(AM_CFLAGS) $(CFLAGS)
    58
    69AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    1922        $(am__mv) $$depbase.Tpo $$depbase.Plo
    2023
     24AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     25am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     26am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     27am__v_JAVAC_1 =
     28
     29AM_V_GOC = $(am__v_GOC_@AM_V@)
     30am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     31am__v_GOC_0 = @echo "  GOC     " $@;
     32am__v_GOC_1 =
     33
    2134UPPCC = u++
    2235UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    2639am__v_UPP_0 = @echo "  UPP     " $@;
    2740am__v_UPP_1 =
    28 
    29 AM_V_GOC = $(am__v_GOC_@AM_V@)
    30 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    31 am__v_GOC_0 = @echo "  GOC     " $@;
    32 am__v_GOC_1 =
    33 
    34 AM_V_PY = $(am__v_PY_@AM_V@)
    35 am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
    36 am__v_PY_0 = @echo "  PYTHON  " $@;
    37 am__v_PY_1 =
    38 
    39 AM_V_RUST = $(am__v_RUST_@AM_V@)
    40 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
    41 am__v_RUST_0 = @echo "  RUST    " $@;
    42 am__v_RUST_1 =
    43 
    44 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
    45 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
    46 am__v_NODEJS_0 = @echo "  NODEJS  " $@;
    47 am__v_NODEJS_1 =
    48 
    49 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    50 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    51 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    52 am__v_JAVAC_1 =
  • src/main.cc

    r7030dab r71d6bd8  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb  8 08:33:50 2020
    13 // Update Count     : 633
     12// Last Modified On : Fri Aug 23 06:50:08 2019
     13// Update Count     : 607
    1414//
    1515
     
    2020#include <cstdio>                           // for fopen, FILE, fclose, stdin
    2121#include <cstdlib>                          // for exit, free, abort, EXIT_F...
    22 #include <csignal>                          // for signal, SIGABRT, SIGSEGV
     22#include <csignal>                         // for signal, SIGABRT, SIGSEGV
    2323#include <cstring>                          // for index
    2424#include <fstream>                          // for ofstream
     
    2828#include <list>                             // for list
    2929#include <string>                           // for char_traits, operator<<
    30 
    31 using namespace std;
    3230
    3331#include "AST/Convert.hpp"
     
    5654#include "InitTweak/GenInit.h"              // for genInit
    5755#include "MakeLibCfa.h"                     // for makeLibCfa
     56#include "Parser/LinkageSpec.h"             // for Spec, Cforall, Intrinsic
    5857#include "Parser/ParseNode.h"               // for DeclarationNode, buildList
    5958#include "Parser/TypedefTable.h"            // for TypedefTable
     
    6160#include "ResolvExpr/Resolver.h"            // for resolve
    6261#include "SymTab/Validate.h"                // for validate
    63 #include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    6462#include "SynTree/Declaration.h"            // for Declaration
    6563#include "SynTree/Visitor.h"                // for acceptAll
     
    6765#include "Virtual/ExpandCasts.h"            // for expandCasts
    6866
     67
     68using namespace std;
    6969
    7070static void NewPass( const char * const name ) {
     
    9898static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
    9999
    100 static string PreludeDirector = "";
     100static std::string PreludeDirector = "";
    101101
    102102static void parse_cmdline( int argc, char *argv[] );
     
    105105
    106106static void backtrace( int start ) {                                    // skip first N stack frames
    107         enum { Frames = 50, };                                                          // maximum number of stack frames
     107        enum { Frames = 50 };
    108108        void * array[Frames];
    109         size_t size = ::backtrace( array, Frames );
     109        int size = ::backtrace( array, Frames );
    110110        char ** messages = ::backtrace_symbols( array, size ); // does not demangle names
    111111
     
    114114
    115115        // skip last 2 stack frames after main
    116         for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
     116        for ( int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
    117117                char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr;
    118 
    119                 for ( char * p = messages[i]; *p; p += 1 ) {    // find parantheses and +offset
     118                for ( char *p = messages[i]; *p; ++p ) {        // find parantheses and +offset
    120119                        if ( *p == '(' ) {
    121120                                mangled_name = p;
     
    155154} // backtrace
    156155
    157 #define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused ))
    158 
    159 static void Signal( int sig, void (*handler)(SIGPARMS), int flags ) {
    160         struct sigaction act;
    161 
    162         act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
    163         act.sa_flags = flags;
    164 
    165         if ( sigaction( sig, &act, nullptr ) == -1 ) {
    166             cerr << "*CFA runtime error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
    167             _exit( EXIT_FAILURE );
    168         } // if
    169 } // Signal
    170 
    171 static void sigSegvBusHandler( SIGPARMS ) {
    172         if ( sfp->si_addr == nullptr ) {
    173                 cerr << "Null pointer (nullptr) dereference." << endl;
    174         } else {
    175                 cerr << (sig == SIGSEGV ? "Segment fault" : "Bus error") << " at memory location " << sfp->si_addr << "." << endl
    176                          << "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript." << endl;
    177         } // if
     156static void sigSegvBusHandler( int sig_num ) {
     157        cerr << "*CFA runtime error* program cfa-cpp terminated with "
     158                 <<     (sig_num == SIGSEGV ? "segment fault" : "bus error")
     159                 << "." << endl;
    178160        backtrace( 2 );                                                                         // skip first 2 stack frames
     161        //_exit( EXIT_FAILURE );
    179162        abort();                                                                                        // cause core dump for debugging
    180163} // sigSegvBusHandler
    181164
    182 static void sigFpeHandler( SIGPARMS ) {
    183         const char * msg;
    184 
    185         switch ( sfp->si_code ) {
    186           case FPE_INTDIV: case FPE_FLTDIV: msg = "divide by zero"; break;
    187           case FPE_FLTOVF: msg = "overflow"; break;
    188           case FPE_FLTUND: msg = "underflow"; break;
    189           case FPE_FLTRES: msg = "inexact result"; break;
    190           case FPE_FLTINV: msg = "invalid operation"; break;
    191           default: msg = "unknown";
    192         } // choose
    193         cerr << "Computation error " << msg << " at location " << sfp->si_addr << endl
    194                  << "Possible cause is constant-expression evaluation invalid." << endl;
    195         backtrace( 2 );                                                                         // skip first 2 stack frames
    196         abort();                                                                                        // cause core dump for debugging
    197 } // sigFpeHandler
    198 
    199 static void sigAbortHandler( SIGPARMS ) {
     165static void sigAbortHandler( __attribute__((unused)) int sig_num ) {
    200166        backtrace( 6 );                                                                         // skip first 6 stack frames
    201         Signal( SIGABRT, (void (*)(SIGPARMS))SIG_DFL, SA_SIGINFO );     // reset default signal handler
     167        signal( SIGABRT, SIG_DFL);                                                      // reset default signal handler
    202168        raise( SIGABRT );                                                                       // reraise SIGABRT
    203169} // sigAbortHandler
     
    208174        list< Declaration * > translationUnit;
    209175
    210         Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO );
    211         Signal( SIGBUS, sigSegvBusHandler, SA_SIGINFO );
    212         Signal( SIGFPE, sigFpeHandler, SA_SIGINFO );
    213         Signal( SIGABRT, sigAbortHandler, SA_SIGINFO );
    214 
    215         // cout << "main" << endl;
     176        signal( SIGSEGV, sigSegvBusHandler );
     177        signal( SIGBUS, sigSegvBusHandler );
     178        signal( SIGABRT, sigAbortHandler );
     179
     180        // std::cout << "main" << std::endl;
    216181        // for ( int i = 0; i < argc; i += 1 ) {
    217         //      cout << '\t' << argv[i] << endl;
     182        //      std::cout << '\t' << argv[i] << std::endl;
    218183        // } // for
    219184
     
    222187
    223188        if ( waiting_for_gdb ) {
    224                 cerr << "Waiting for gdb" << endl;
    225                 cerr << "run :" << endl;
    226                 cerr << "  gdb attach " << getpid() << endl;
     189                std::cerr << "Waiting for gdb" << std::endl;
     190                std::cerr << "run :" << std::endl;
     191                std::cerr << "  gdb attach " << getpid() << std::endl;
    227192                raise(SIGSTOP);
    228193        } // if
     
    430395                return EXIT_FAILURE;
    431396        } catch ( ... ) {
    432                 exception_ptr eptr = current_exception();
     397                std::exception_ptr eptr = std::current_exception();
    433398                try {
    434399                        if (eptr) {
    435                                 rethrow_exception(eptr);
     400                                std::rethrow_exception(eptr);
    436401                        } else {
    437                                 cerr << "Exception Uncaught and Unknown" << endl;
    438                         } // if
    439                 } catch(const exception& e) {
    440                         cerr << "Uncaught Exception \"" << e.what() << "\"\n";
     402                                std::cerr << "Exception Uncaught and Unknown" << std::endl;
     403                        } // if
     404                } catch(const std::exception& e) {
     405                        std::cerr << "Uncaught Exception \"" << e.what() << "\"\n";
    441406                } // try
    442407                return EXIT_FAILURE;
     
    449414
    450415
    451 static const char optstring[] = ":c:ghlLmNnpP:S:twW:D:";
     416static const char optstring[] = ":hlLmNnpP:S:tgwW:D:";
    452417
    453418enum { PreludeDir = 128 };
    454419static struct option long_opts[] = {
    455         { "colors", required_argument, nullptr, 'c' },
    456         { "gdb", no_argument, nullptr, 'g' },
    457420        { "help", no_argument, nullptr, 'h' },
    458421        { "libcfa", no_argument, nullptr, 'l' },
     
    466429        { "statistics", required_argument, nullptr, 'S' },
    467430        { "tree", no_argument, nullptr, 't' },
     431        { "gdb", no_argument, nullptr, 'g' },
    468432        { "", no_argument, nullptr, 0 },                                        // -w
    469433        { "", no_argument, nullptr, 0 },                                        // -W
     
    473437
    474438static const char * description[] = {
    475         "diagnostic color: never, always, or auto.",          // -c
    476         "wait for gdb to attach",                             // -g
    477         "print help message",                                 // -h
    478         "generate libcfa.c",                                  // -l
    479         "generate line marks",                                // -L
    480         "do not replace main",                                // -m
    481         "do not generate line marks",                         // -N
    482         "do not read prelude",                                // -n
     439        "print help message",                                                           // -h
     440        "generate libcfa.c",                                                            // -l
     441        "generate line marks",                                                          // -L
     442        "do not replace main",                                                          // -m
     443        "do not generate line marks",                                           // -N
     444        "do not read prelude",                                                          // -n
    483445        "generate prototypes for prelude functions",            // -p
    484         "print",                                              // -P
     446        "print",                                                                                        // -P
    485447        "<directory> prelude directory for debug/nodebug",      // no flag
    486448        "<option-list> enable profiling information:\n          counters,heap,time,all,none", // -S
    487         "building cfa standard lib",                          // -t
    488         "",                                                   // -w
    489         "",                                                   // -W
    490         "",                                                   // -D
     449        "building cfa standard lib",                                                                    // -t
     450        "wait for gdb to attach",                                                                       // -g
     451        "",                                                                                                     // -w
     452        "",                                                                                                     // -W
     453        "",                                                                                                     // -D
    491454}; // description
    492455
     
    556519        while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
    557520                switch ( c ) {
    558                   case 'c':                                                                             // diagnostic colors
    559                         if ( strcmp( optarg, "always" ) == 0 ) {
    560                                 ErrorHelpers::colors = ErrorHelpers::Colors::Always;
    561                         } else if ( strcmp( optarg, "never" ) == 0 ) {
    562                                 ErrorHelpers::colors = ErrorHelpers::Colors::Never;
    563                         } else if ( strcmp( optarg, "auto" ) == 0 ) {
    564                                 ErrorHelpers::colors = ErrorHelpers::Colors::Auto;
    565                         } // if
    566                         break;
    567521                  case 'h':                                                                             // help message
    568522                        usage( argv );                                                          // no return
  • tests/.expect/alloc-ERROR.txt

    r7030dab r71d6bd8  
    1 alloc.cfa:362:1 error: No reasonable alternatives for expression Applying untyped:
     1alloc.cfa:311:1 error: No reasonable alternatives for expression Applying untyped:
    22  Name: ?=?
    33...to:
    4   Name: ip
     4  Name: p
    55  Applying untyped:
    66    Name: realloc
     
    1919
    2020
    21 alloc.cfa:363:1 error: No reasonable alternatives for expression Applying untyped:
     21alloc.cfa:312:1 error: No reasonable alternatives for expression Applying untyped:
    2222  Name: ?=?
    2323...to:
    24   Name: ip
     24  Name: p
     25  Applying untyped:
     26    Name: alloc
     27  ...to:
     28    Name: stp
     29    Applying untyped:
     30      Name: ?*?
     31    ...to:
     32      Name: dim
     33      Sizeof Expression on: Applying untyped:
     34          Name: *?
     35        ...to:
     36          Name: stp
     37
     38
     39
     40
     41alloc.cfa:313:1 error: No reasonable alternatives for expression Applying untyped:
     42  Name: ?=?
     43...to:
     44  Name: p
    2545  Applying untyped:
    2646    Name: memset
     
    3050
    3151
    32 alloc.cfa:364:1 error: No reasonable alternatives for expression Applying untyped:
     52alloc.cfa:314:1 error: No reasonable alternatives for expression Applying untyped:
    3353  Name: ?=?
    3454...to:
    35   Name: ip
     55  Name: p
    3656  Applying untyped:
    3757    Name: memcpy
  • tests/.expect/alloc.txt

    r7030dab r71d6bd8  
    22CFA malloc 0xdeadbeef
    33CFA alloc 0xdeadbeef
     4CFA array alloc, fill 0xde
    45CFA alloc, fill dededede
    56CFA alloc, fill 3
     
    23240xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
    2425
    25 CFA realloc array alloc
     26CFA resize array alloc
    26270xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    27 CFA realloc array alloc
     28CFA resize array alloc
    28290xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
    29 CFA realloc array alloc
     30CFA resize array alloc
    30310xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    31 CFA realloc array alloc, fill
     32CFA resize array alloc, fill
    32330xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    33 CFA realloc array alloc, fill
     34CFA resize array alloc, fill
    34350xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    35 CFA realloc array alloc, fill
    36 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    37 CFA realloc array alloc, 5
    38 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    39 CFA realloc array alloc, 5
    40 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    41 CFA realloc array alloc, 5
    42 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff
     36CFA resize array alloc, fill
     370xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede
    4338
    4439C   memalign 42 42.5
  • tests/.expect/loopctrl.txt

    r7030dab r71d6bd8  
    66A
    77A A A A A A A A A A
    8 A A A A A A A A A A A
    98B B B B B
    109C C C C C
     
    1312
    14130 1 2 3 4 5 6 7 8 9
    15 0 1 2 3 4 5 6 7 8 9 10
    16141 3 5 7 9
    171510 8 6 4 2
     
    3028N N N N N N N N N N
    31290 1 2 3 4 5 6 7 8 9
    32 0 1 2 3 4 5 6 7 8 9 10
    333010 9 8 7 6 5 4 3 2 1
    3431
  • tests/.expect/nested-types-ERR1.txt

    r7030dab r71d6bd8  
    1 nested-types.cfa:83:1 error: Use of undefined type T
     1nested-types.cfa:70:1 error: Use of undefined type T
  • tests/.expect/nested-types-ERR2.txt

    r7030dab r71d6bd8  
    1 nested-types.cfa:86:1 error: Use of undefined global type Z
    2 nested-types.cfa:87:1 error: Qualified type requires an aggregate on the left, but has: signed int
    3 nested-types.cfa:88:1 error: Undefined type in qualified type: Qualified Type:
     1nested-types.cfa:73:1 error: Use of undefined global type Z
     2nested-types.cfa:74:1 error: Qualified type requires an aggregate on the left, but has: signed int
     3nested-types.cfa:75:1 error: Undefined type in qualified type: Qualified Type:
    44  instance of struct S with body 1
    55  instance of type Z (not function type)
  • tests/.expect/rational.txt

    r7030dab r71d6bd8  
    11constructor
    2 3/1 4/1 0/1 0/1 1/1
     23/1 4/1 0/1
    331/2 5/7
    442/3 -3/2
  • tests/.expect/references.txt

    r7030dab r71d6bd8  
    36363
    37373 9 { 1., 7. }, [1, 2, 3]
    38 4
    3938Destructing a Y
    4039Destructing a Y
  • tests/.expect/time.txt

    r7030dab r71d6bd8  
    1818Dividing that by 2 gives 2403.5 seconds
    19194807 seconds is 1 hours, 20 minutes, 7 seconds
    20 2020 Jan  5 14:01:40 (GMT)
    21 1970 Jan  5 14:00:00 (GMT)
    22 1973 Jan  2 06:59:00 (GMT)
  • tests/Makefile.am

    r7030dab r71d6bd8  
    4646
    4747# adjust CC to current flags
    48 CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     48CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    4949CFACC = $(CC)
    5050
     
    5353
    5454# adjusted CC but without the actual distcc call
    55 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     55CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    5656
    5757PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
  • tests/Makefile.in

    r7030dab r71d6bd8  
    214214
    215215# adjust CC to current flags
    216 CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     216CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    217217CCAS = @CCAS@
    218218CCASDEPMODE = @CCASDEPMODE@
     
    358358LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    359359        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
    360         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
     360        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
     361        $(AM_CFLAGS) $(CFLAGS)
    361362
    362363AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    364365am__v_CFA_0 = @echo "  CFA     " $@;
    365366am__v_CFA_1 =
     367AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     368am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     369am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     370am__v_JAVAC_1 =
     371AM_V_GOC = $(am__v_GOC_@AM_V@)
     372am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     373am__v_GOC_0 = @echo "  GOC     " $@;
     374am__v_GOC_1 =
    366375UPPCC = u++
    367376UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    370379am__v_UPP_0 = @echo "  UPP     " $@;
    371380am__v_UPP_1 =
    372 AM_V_GOC = $(am__v_GOC_@AM_V@)
    373 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    374 am__v_GOC_0 = @echo "  GOC     " $@;
    375 am__v_GOC_1 =
    376 AM_V_PY = $(am__v_PY_@AM_V@)
    377 am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
    378 am__v_PY_0 = @echo "  PYTHON  " $@;
    379 am__v_PY_1 =
    380 AM_V_RUST = $(am__v_RUST_@AM_V@)
    381 am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
    382 am__v_RUST_0 = @echo "  RUST    " $@;
    383 am__v_RUST_1 =
    384 AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
    385 am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
    386 am__v_NODEJS_0 = @echo "  NODEJS  " $@;
    387 am__v_NODEJS_1 =
    388 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    389 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    390 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    391 am__v_JAVAC_1 =
    392381debug = yes
    393382installed = no
     
    416405
    417406# adjusted CC but without the actual distcc call
    418 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     407CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    419408PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    420409avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
  • tests/alloc.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr  1 10:58:35 2020
    13 // Update Count     : 424
     12// Last Modified On : Sun Oct 20 21:45:21 2019
     13// Update Count     : 391
    1414//
    1515
     
    2828        size_t dim = 10;
    2929        char fill = '\xde';
    30         int * ip, * ip1;
     30        int * p, * p1;
    3131
    3232        // allocation, non-array types
    3333
    34         ip = (int *)malloc( sizeof(*ip) );                                      // C malloc, type unsafe
    35         *ip = 0xdeadbeef;
    36         printf( "C   malloc %#x\n", *ip );
    37         free( ip );
    38 
    39         ip = malloc();                                                                          // CFA malloc, type safe
    40         *ip = 0xdeadbeef;
    41         printf( "CFA malloc %#x\n", *ip );
    42         free( ip );
    43 
    44         ip = alloc();                                                                           // CFA alloc, type safe
    45         *ip = 0xdeadbeef;
    46         printf( "CFA alloc %#x\n", *ip );
    47         free( ip );
    48 
    49         ip = alloc_set( fill );                                                         // CFA alloc, fill
    50         printf( "CFA alloc, fill %08x\n", *ip );
    51         free( ip );
    52 
    53         ip = alloc_set( 3 );                                                            // CFA alloc, fill
    54         printf( "CFA alloc, fill %d\n", *ip );
    55         free( ip );
     34        p = (int *)malloc( sizeof(*p) );                                        // C malloc, type unsafe
     35        *p = 0xdeadbeef;
     36        printf( "C   malloc %#x\n", *p );
     37        free( p );
     38
     39        p = malloc();                                       // CFA malloc, type safe
     40        *p = 0xdeadbeef;
     41        printf( "CFA malloc %#x\n", *p );
     42        free( p );
     43
     44        p = alloc();                                        // CFA alloc, type safe
     45        *p = 0xdeadbeef;
     46        printf( "CFA alloc %#x\n", *p );
     47        free( p );
     48
     49        p = alloc_set( fill );                                                          // CFA alloc, fill
     50        printf( "CFA array alloc, fill %#hhx\n", fill );
     51        printf( "CFA alloc, fill %08x\n", *p );
     52        free( p );
     53
     54        p = alloc_set( 3 );                                                                     // CFA alloc, fill
     55        printf( "CFA alloc, fill %d\n", *p );
     56        free( p );
    5657
    5758
     
    5960        printf( "\n" );
    6061
    61         ip = (int *)calloc( dim, sizeof( *ip ) );                       // C array calloc, type unsafe
     62        p = (int *)calloc( dim, sizeof( *p ) );                         // C array calloc, type unsafe
    6263        printf( "C   array calloc, fill 0\n" );
    63         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    64         printf( "\n" );
    65         free( ip );
    66 
    67         ip = calloc( dim );                                                                     // CFA array calloc, type safe
     64        for ( i; dim ) { printf( "%#x ", p[i] ); }
     65        printf( "\n" );
     66        free( p );
     67
     68        p = calloc( dim );                                  // CFA array calloc, type safe
    6869        printf( "CFA array calloc, fill 0\n" );
    69         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    70         printf( "\n" );
    71         free( ip );
    72 
    73         ip = alloc( dim );                                                                      // CFA array alloc, type safe
    74         for ( i; dim ) { ip[i] = 0xdeadbeef; }
     70        for ( i; dim ) { printf( "%#x ", p[i] ); }
     71        printf( "\n" );
     72        free( p );
     73
     74        p = alloc( dim );                                   // CFA array alloc, type safe
     75        for ( i; dim ) { p[i] = 0xdeadbeef; }
    7576        printf( "CFA array alloc, no fill\n" );
    76         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    77         printf( "\n" );
    78         free( ip );
    79 
    80         ip = alloc_set( 2 * dim, fill );                                        // CFA array alloc, fill
     77        for ( i; dim ) { printf( "%#x ", p[i] ); }
     78        printf( "\n" );
     79        free( p );
     80
     81        p = alloc_set( 2 * dim, fill );                                         // CFA array alloc, fill
    8182        printf( "CFA array alloc, fill %#hhx\n", fill );
    82         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    83         printf( "\n" );
    84         free( ip );
    85 
    86         ip = alloc_set( 2 * dim, 0xdeadbeef );                          // CFA array alloc, fill
     83        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     84        printf( "\n" );
     85        free( p );
     86
     87        p = alloc_set( 2 * dim, 0xdeadbeef );                           // CFA array alloc, fill
    8788        printf( "CFA array alloc, fill %#hhx\n", 0xdeadbeef );
    88         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    89         printf( "\n" );
    90         // do not free
    91 
    92         ip1 = alloc_set( 2 * dim, ip );                                         // CFA array alloc, fill
     89        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     90        printf( "\n" );
     91        // do not free
     92
     93        p1 = alloc_set( 2 * dim, p );                                           // CFA array alloc, fill
    9394        printf( "CFA array alloc, fill from array\n" );
    94         for ( i; 2 * dim ) { printf( "%#x %#x, ", ip[i], ip1[i] ); }
    95         free( ip1 );
    96         printf( "\n" );
    97 
    98 
    99         // realloc, non-array types
    100         printf( "\n" );
    101 
    102         ip = (int *)realloc( ip, dim * sizeof(*ip) );           // C realloc
     95        for ( i; 2 * dim ) { printf( "%#x %#x, ", p[i], p1[i] ); }
     96        free( p1 );
     97        printf( "\n" );
     98
     99
     100        // resize, non-array types
     101        printf( "\n" );
     102
     103        p = (int *)realloc( p, dim * sizeof(*p) );                      // C realloc
    103104        printf( "C realloc\n" );
    104         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    105         printf( "\n" );
    106         // do not free
    107 
    108         ip = realloc( ip, 2 * dim * sizeof(*ip) );                      // CFA realloc
    109         for ( i; dim ~ 2 * dim ) { ip[i] = 0x1010101; }
     105        for ( i; dim ) { printf( "%#x ", p[i] ); }
     106        printf( "\n" );
     107        // do not free
     108
     109        p = realloc( p, 2 * dim * sizeof(*p) );             // CFA realloc
     110        for ( i; dim ~ 2 * dim ) { p[i] = 0x1010101; }
    110111        printf( "CFA realloc\n" );
    111         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    112         printf( "\n" );
    113         // do not free
    114 
    115 
    116         // realloc, array types
    117         printf( "\n" );
    118 
    119         ip = alloc( ip, dim );                                                          // CFA realloc array alloc
    120         for ( i; dim ) { ip[i] = 0xdeadbeef; }
    121         printf( "CFA realloc array alloc\n" );
    122         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    123         printf( "\n" );
    124         // do not free
    125 
    126         ip = alloc( ip, 2 * dim );                                                      // CFA realloc array alloc
    127         for ( i; dim ~ 2 * dim ) { ip[i] = 0x1010101; }         // fill upper part
    128         printf( "CFA realloc array alloc\n" );
    129         for ( i; 2 * dim ) { printf( "%#x ", ip[i] ); }
    130         printf( "\n" );
    131         // do not free
    132 
    133         ip = alloc( ip, dim );                                                          // CFA realloc array alloc
    134         printf( "CFA realloc array alloc\n" );
    135         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    136         printf( "\n" );
    137         // do not free
    138 
    139         ip = alloc_set( ip, 3 * dim, fill );                            // CFA realloc array alloc, fill
    140         printf( "CFA realloc array alloc, fill\n" );
    141         for ( i; 3 * dim ) { printf( "%#x ", ip[i] ); }
    142         printf( "\n" );
    143         // do not free
    144 
    145         ip = alloc_set( ip, dim, fill );                                        // CFA realloc array alloc, fill
    146         printf( "CFA realloc array alloc, fill\n" );
    147         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    148         printf( "\n" );
    149         // do not free
    150 
    151         ip = alloc_set( ip, 3 * dim, fill );                            // CFA realloc array alloc, fill
    152         printf( "CFA realloc array alloc, fill\n" );
    153         for ( i; 3 * dim ) { printf( "%#x ", ip[i] );; }
    154         printf( "\n" );
    155         // do not free
    156 
    157         ip = alloc_set( ip, 3 * dim, 5 );                                       // CFA realloc array alloc, 5
    158         printf( "CFA realloc array alloc, 5\n" );
    159         for ( i; 3 * dim ) { printf( "%#x ", ip[i] ); }
    160         printf( "\n" );
    161         // do not free
    162 
    163         ip = alloc_set( ip, dim, 5 );                                           // CFA realloc array alloc, 5
    164         printf( "CFA realloc array alloc, 5\n" );
    165         for ( i; dim ) { printf( "%#x ", ip[i] ); }
    166         printf( "\n" );
    167         // do not free
    168 
    169         ip = alloc_set( ip, 3 * dim, 5 );                                       // CFA realloc array alloc, 5
    170         printf( "CFA realloc array alloc, 5\n" );
    171         for ( i; 3 * dim ) { printf( "%#x ", ip[i] );; }
    172         printf( "\n" );
    173         free( ip );
    174 
    175 
    176         // resize, non-array types
    177 
    178         struct S {
    179                 int a[5];
    180         };
    181 
    182     ip = alloc();
    183         *ip = 5;
    184     double * dp = alloc( ip );
    185         *dp = 5.5;
    186     S * sp = alloc( dp );
    187         *sp = (S){ {0, 1, 2, 3, 4} };
    188     ip = alloc( sp );
    189         *ip = 3;
    190     free( ip );
     112        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     113        printf( "\n" );
     114        // do not free
    191115
    192116
    193117        // resize, array types
    194 
    195     ip = alloc( 5 );
    196         for ( i; 5 ) { ip[i] = 5; }
    197     dp = alloc( ip, 5 );
    198         for ( i; 5 ) { dp[i] = 5.5; }
    199     sp = alloc( dp, 5 );
    200         for ( i; 5 ) { sp[i] = (S){ {0, 1, 2, 3, 4} }; }
    201     ip = alloc( sp, 3 );
    202         for ( i; 3 ) { ip[i] = 3; }
    203     ip = alloc( ip, 7 );
    204         for ( i; 7 ) { ip[i] = 7; }
    205     ip = alloc( ip, 7, false );
    206         for ( i; 7 ) { ip[i] = 7; }
    207     free( ip );
     118        printf( "\n" );
     119
     120        p = alloc( p, dim );                                // CFA resize array alloc
     121        for ( i; dim ) { p[i] = 0xdeadbeef; }
     122        printf( "CFA resize array alloc\n" );
     123        for ( i; dim ) { printf( "%#x ", p[i] ); }
     124        printf( "\n" );
     125        // do not free
     126
     127        p = alloc( p, 2 * dim );                            // CFA resize array alloc
     128        for ( i; dim ~ 2 * dim ) { p[i] = 0x1010101; }
     129        printf( "CFA resize array alloc\n" );
     130        for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
     131        printf( "\n" );
     132        // do not free
     133
     134        p = alloc( p, dim );                                // CFA resize array alloc
     135        printf( "CFA resize array alloc\n" );
     136        for ( i; dim ) { printf( "%#x ", p[i] ); }
     137        printf( "\n" );
     138        // do not free
     139
     140        p = alloc_set( p, 3 * dim, fill );                                      // CFA resize array alloc, fill
     141        printf( "CFA resize array alloc, fill\n" );
     142        for ( i; 3 * dim ) { printf( "%#x ", p[i] ); }
     143        printf( "\n" );
     144        // do not free
     145
     146        p = alloc_set( p, dim, fill );                                          // CFA resize array alloc, fill
     147        printf( "CFA resize array alloc, fill\n" );
     148        for ( i; dim ) { printf( "%#x ", p[i] ); }
     149        printf( "\n" );
     150        // do not free
     151
     152        p = alloc_set( p, 3 * dim, fill );                                      // CFA resize array alloc, fill
     153        printf( "CFA resize array alloc, fill\n" );
     154        for ( i; 3 * dim ) { printf( "%#x ", p[i] );; }
     155        printf( "\n" );
     156        free( p );
    208157
    209158
     
    220169        free( stp );
    221170
    222         stp = &(*memalign( Alignment )){ 42, 42.5 };            // CFA memalign
     171        stp = &(*memalign( Alignment )){ 42, 42.5 };          // CFA memalign
    223172        assert( (uintptr_t)stp % Alignment == 0 );
    224173        printf( "CFA memalign %d %g\n", stp->x, stp->y );
     
    352301        free( fp - 1 );
    353302
    354         ip = foo( bar( baz( malloc(), 0 ), 0 ), 0 );
    355         *ip = 0xdeadbeef;
    356         printf( "CFA deep malloc %#x\n", *ip );
    357         free( ip );
     303        p = foo( bar( baz( malloc(), 0 ), 0 ), 0 );
     304        *p = 0xdeadbeef;
     305        printf( "CFA deep malloc %#x\n", *p );
     306        free( p );
    358307
    359308#ifdef ERR1
    360309        stp = malloc();
    361310        printf( "\nSHOULD FAIL\n" );
    362         ip = realloc( stp, dim * sizeof( *stp ) );
    363         ip = memset( stp, 10 );
    364         ip = memcpy( &st1, &st );
     311        p = realloc( stp, dim * sizeof( *stp ) );
     312        p = alloc( stp, dim * sizeof( *stp ) );
     313        p = memset( stp, 10 );
     314        p = memcpy( &st1, &st );
    365315#endif
    366316} // main
  • tests/builtins/sync.cfa

    r7030dab r71d6bd8  
    44void foo() {
    55        volatile _Bool * vpB = 0; _Bool vB = 0;
    6         volatile char * vpc = 0; char * rpc = 0; char vc = 0;
    7         volatile short * vps = 0; short * rps = 0; short vs = 0;
    8         volatile int * vpi = 0; int * rpi = 0; int vi = 0;
    9         volatile long int * vpl = 0; long int * rpl = 0; long int vl = 0;
    10         volatile long long int * vpll = 0; long long int * rpll = 0; long long int vll = 0;
    11         #if defined(__SIZEOF_INT128__)
    12         volatile __int128 * vplll = 0; __int128 * rplll = 0; __int128 vlll = 0;
     6        volatile char * vp1 = 0; char * rp1 = 0; char v1 = 0;
     7        volatile short * vp2 = 0; short * rp2 = 0; short v2 = 0;
     8        volatile int * vp4 = 0; int * rp4 = 0; int v4 = 0;
     9        volatile long long int * vp8 = 0; long long int * rp8 = 0; long long int v8 = 0;
     10        #if defined(__SIZEOF_INT128__)
     11        volatile __int128 * vp16 = 0; __int128 * rp16 = 0; __int128 v16 = 0;
    1312        #endif
    1413        struct type * volatile * vpp = 0; struct type ** rpp = 0; struct type * vp = 0;
    1514
    16         { char ret; ret = __sync_fetch_and_add(vpc, vc); }
    17         { short ret; ret = __sync_fetch_and_add(vps, vs); }
    18         { int ret; ret = __sync_fetch_and_add(vpi, vi); }
    19         { long int ret; ret = __sync_fetch_and_add(vpl, vl); }
    20         { long long int ret; ret = __sync_fetch_and_add(vpll, vll); }
    21         #if defined(__SIZEOF_INT128__)
    22         { __int128 ret; ret = __sync_fetch_and_add(vplll, vlll); }
    23         #endif
    24 
    25         { char ret; ret = __sync_fetch_and_sub(vpc, vc); }
    26         { short ret; ret = __sync_fetch_and_sub(vps, vs); }
    27         { int ret; ret = __sync_fetch_and_sub(vpi, vi); }
    28         { long int ret; ret = __sync_fetch_and_sub(vpl, vl); }
    29         { long long int ret; ret = __sync_fetch_and_sub(vpll, vll); }
    30         #if defined(__SIZEOF_INT128__)
    31         { __int128 ret; ret = __sync_fetch_and_sub(vplll, vlll); }
    32         #endif
    33 
    34         { char ret; ret = __sync_fetch_and_or(vpc, vc); }
    35         { short ret; ret = __sync_fetch_and_or(vps, vs); }
    36         { int ret; ret = __sync_fetch_and_or(vpi, vi); }
    37         { long int ret; ret = __sync_fetch_and_or(vpl, vl); }
    38         { long long int ret; ret = __sync_fetch_and_or(vpll, vll); }
    39         #if defined(__SIZEOF_INT128__)
    40         { __int128 ret; ret = __sync_fetch_and_or(vplll, vlll); }
    41         #endif
    42 
    43         { char ret; ret = __sync_fetch_and_and(vpc, vc); }
    44         { short ret; ret = __sync_fetch_and_and(vps, vs); }
    45         { int ret; ret = __sync_fetch_and_and(vpi, vi); }
    46         { long int ret; ret = __sync_fetch_and_and(vpl, vl); }
    47         { long long int ret; ret = __sync_fetch_and_and(vpll, vll); }
    48         #if defined(__SIZEOF_INT128__)
    49         { __int128 ret; ret = __sync_fetch_and_and(vplll, vlll); }
    50         #endif
    51 
    52         { char ret; ret = __sync_fetch_and_xor(vpc, vc); }
    53         { short ret; ret = __sync_fetch_and_xor(vps, vs); }
    54         { int ret; ret = __sync_fetch_and_xor(vpi, vi); }
    55         { long int ret; ret = __sync_fetch_and_xor(vpl, vl); }
    56         { long long int ret; ret = __sync_fetch_and_xor(vpll, vll); }
    57         #if defined(__SIZEOF_INT128__)
    58         { __int128 ret; ret = __sync_fetch_and_xor(vplll, vlll); }
    59         #endif
    60 
    61         { char ret; ret = __sync_fetch_and_nand(vpc, vc); }
    62         { short ret; ret = __sync_fetch_and_nand(vps, vs); }
    63         { int ret; ret = __sync_fetch_and_nand(vpi, vi); }
    64         { long int ret; ret = __sync_fetch_and_nand(vpl, vl); }
    65         { long long int ret; ret = __sync_fetch_and_nand(vpll, vll); }
    66         #if defined(__SIZEOF_INT128__)
    67         { __int128 ret; ret = __sync_fetch_and_nand(vplll, vlll); }
    68         { __int128 ret; ret = __sync_fetch_and_nand_16(vplll, vlll); }
    69         #endif
    70 
    71         { char ret; ret = __sync_add_and_fetch(vpc, vc); }
    72         { short ret; ret = __sync_add_and_fetch(vps, vs); }
    73         { int ret; ret = __sync_add_and_fetch(vpi, vi); }
    74         { long int ret; ret = __sync_add_and_fetch(vpl, vl); }
    75         { long long int ret; ret = __sync_add_and_fetch(vpll, vll); }
    76         #if defined(__SIZEOF_INT128__)
    77         { __int128 ret; ret = __sync_add_and_fetch(vplll, vlll); }
    78         #endif
    79 
    80         { char ret; ret = __sync_sub_and_fetch(vpc, vc); }
    81         { short ret; ret = __sync_sub_and_fetch(vps, vs); }
    82         { int ret; ret = __sync_sub_and_fetch(vpi, vi); }
    83         { long int ret; ret = __sync_sub_and_fetch(vpl, vl); }
    84         { long long int ret; ret = __sync_sub_and_fetch(vpll, vll); }
    85         #if defined(__SIZEOF_INT128__)
    86         { __int128 ret; ret = __sync_sub_and_fetch(vplll, vlll); }
    87         #endif
    88 
    89         { char ret; ret = __sync_or_and_fetch(vpc, vc); }
    90         { short ret; ret = __sync_or_and_fetch(vps, vs); }
    91         { int ret; ret = __sync_or_and_fetch(vpi, vi); }
    92         { long int ret; ret = __sync_or_and_fetch(vpl, vl); }
    93         { long long int ret; ret = __sync_or_and_fetch(vpll, vll); }
    94         #if defined(__SIZEOF_INT128__)
    95         { __int128 ret; ret = __sync_or_and_fetch(vplll, vlll); }
    96         #endif
    97 
    98         { char ret; ret = __sync_and_and_fetch(vpc, vc); }
    99         { short ret; ret = __sync_and_and_fetch(vps, vs); }
    100         { int ret; ret = __sync_and_and_fetch(vpi, vi); }
    101         { long int ret; ret = __sync_and_and_fetch(vpl, vl); }
    102         { long long int ret; ret = __sync_and_and_fetch(vpll, vll); }
    103         #if defined(__SIZEOF_INT128__)
    104         { __int128 ret; ret = __sync_and_and_fetch(vplll, vlll); }
    105         #endif
    106 
    107         { char ret; ret = __sync_xor_and_fetch(vpc, vc); }
    108         { short ret; ret = __sync_xor_and_fetch(vps, vs); }
    109         { int ret; ret = __sync_xor_and_fetch(vpi, vi); }
    110         { long int ret; ret = __sync_xor_and_fetch(vpl, vl); }
    111         { long long int ret; ret = __sync_xor_and_fetch(vpll, vll); }
    112         #if defined(__SIZEOF_INT128__)
    113         { __int128 ret; ret = __sync_xor_and_fetch(vplll, vlll); }
    114         #endif
    115 
    116         { char ret; ret = __sync_nand_and_fetch(vpc, vc); }
    117         { short ret; ret = __sync_nand_and_fetch(vps, vs); }
    118         { int ret; ret = __sync_nand_and_fetch(vpi, vi); }
    119         { long int ret; ret = __sync_nand_and_fetch(vpl, vl); }
    120         { long long int ret; ret = __sync_nand_and_fetch(vpll, vll); }
    121         #if defined(__SIZEOF_INT128__)
    122         { __int128 ret; ret = __sync_nand_and_fetch(vplll, vlll); }
    123         #endif
    124 
    125         { _Bool ret; ret = __sync_bool_compare_and_swap(vpc, vc, vc); }
    126         { _Bool ret; ret = __sync_bool_compare_and_swap(vps, vs, vs); }
    127         { _Bool ret; ret = __sync_bool_compare_and_swap(vpi, vi, vi); }
    128         { _Bool ret; ret = __sync_bool_compare_and_swap(vpl, vl, vl); }
    129         { _Bool ret; ret = __sync_bool_compare_and_swap(vpll, vll, vll); }
    130         #if defined(__SIZEOF_INT128__)
    131         { _Bool ret; ret = __sync_bool_compare_and_swap(vplll, vlll, vlll); }
     15        { char ret; ret = __sync_fetch_and_add(vp1, v1); }
     16        { char ret; ret = __sync_fetch_and_add_1(vp1, v1); }
     17        { short ret; ret = __sync_fetch_and_add(vp2, v2); }
     18        { short ret; ret = __sync_fetch_and_add_2(vp2, v2); }
     19        { int ret; ret = __sync_fetch_and_add(vp4, v4); }
     20        { int ret; ret = __sync_fetch_and_add_4(vp4, v4); }
     21        { long long int ret; ret = __sync_fetch_and_add(vp8, v8); }
     22        { long long int ret; ret = __sync_fetch_and_add_8(vp8, v8); }
     23        #if defined(__SIZEOF_INT128__)
     24        { __int128 ret; ret = __sync_fetch_and_add(vp16, v16); }
     25        { __int128 ret; ret = __sync_fetch_and_add_16(vp16, v16); }
     26        #endif
     27
     28        { char ret; ret = __sync_fetch_and_sub(vp1, v1); }
     29        { char ret; ret = __sync_fetch_and_sub_1(vp1, v1); }
     30        { short ret; ret = __sync_fetch_and_sub(vp2, v2); }
     31        { short ret; ret = __sync_fetch_and_sub_2(vp2, v2); }
     32        { int ret; ret = __sync_fetch_and_sub(vp4, v4); }
     33        { int ret; ret = __sync_fetch_and_sub_4(vp4, v4); }
     34        { long long int ret; ret = __sync_fetch_and_sub(vp8, v8); }
     35        { long long int ret; ret = __sync_fetch_and_sub_8(vp8, v8); }
     36        #if defined(__SIZEOF_INT128__)
     37        { __int128 ret; ret = __sync_fetch_and_sub(vp16, v16); }
     38        { __int128 ret; ret = __sync_fetch_and_sub_16(vp16, v16); }
     39        #endif
     40
     41        { char ret; ret = __sync_fetch_and_or(vp1, v1); }
     42        { char ret; ret = __sync_fetch_and_or_1(vp1, v1); }
     43        { short ret; ret = __sync_fetch_and_or(vp2, v2); }
     44        { short ret; ret = __sync_fetch_and_or_2(vp2, v2); }
     45        { int ret; ret = __sync_fetch_and_or(vp4, v4); }
     46        { int ret; ret = __sync_fetch_and_or_4(vp4, v4); }
     47        { long long int ret; ret = __sync_fetch_and_or(vp8, v8); }
     48        { long long int ret; ret = __sync_fetch_and_or_8(vp8, v8); }
     49        #if defined(__SIZEOF_INT128__)
     50        { __int128 ret; ret = __sync_fetch_and_or(vp16, v16); }
     51        { __int128 ret; ret = __sync_fetch_and_or_16(vp16, v16); }
     52        #endif
     53
     54        { char ret; ret = __sync_fetch_and_and(vp1, v1); }
     55        { char ret; ret = __sync_fetch_and_and_1(vp1, v1); }
     56        { short ret; ret = __sync_fetch_and_and(vp2, v2); }
     57        { short ret; ret = __sync_fetch_and_and_2(vp2, v2); }
     58        { int ret; ret = __sync_fetch_and_and(vp4, v4); }
     59        { int ret; ret = __sync_fetch_and_and_4(vp4, v4); }
     60        { long long int ret; ret = __sync_fetch_and_and(vp8, v8); }
     61        { long long int ret; ret = __sync_fetch_and_and_8(vp8, v8); }
     62        #if defined(__SIZEOF_INT128__)
     63        { __int128 ret; ret = __sync_fetch_and_and(vp16, v16); }
     64        { __int128 ret; ret = __sync_fetch_and_and_16(vp16, v16); }
     65        #endif
     66
     67        { char ret; ret = __sync_fetch_and_xor(vp1, v1); }
     68        { char ret; ret = __sync_fetch_and_xor_1(vp1, v1); }
     69        { short ret; ret = __sync_fetch_and_xor(vp2, v2); }
     70        { short ret; ret = __sync_fetch_and_xor_2(vp2, v2); }
     71        { int ret; ret = __sync_fetch_and_xor(vp4, v4); }
     72        { int ret; ret = __sync_fetch_and_xor_4(vp4, v4); }
     73        { long long int ret; ret = __sync_fetch_and_xor(vp8, v8); }
     74        { long long int ret; ret = __sync_fetch_and_xor_8(vp8, v8); }
     75        #if defined(__SIZEOF_INT128__)
     76        { __int128 ret; ret = __sync_fetch_and_xor(vp16, v16); }
     77        { __int128 ret; ret = __sync_fetch_and_xor_16(vp16, v16); }
     78        #endif
     79
     80        { char ret; ret = __sync_fetch_and_nand(vp1, v1); }
     81        { char ret; ret = __sync_fetch_and_nand_1(vp1, v1); }
     82        { short ret; ret = __sync_fetch_and_nand(vp2, v2); }
     83        { short ret; ret = __sync_fetch_and_nand_2(vp2, v2); }
     84        { int ret; ret = __sync_fetch_and_nand(vp4, v4); }
     85        { int ret; ret = __sync_fetch_and_nand_4(vp4, v4); }
     86        { long long int ret; ret = __sync_fetch_and_nand(vp8, v8); }
     87        { long long int ret; ret = __sync_fetch_and_nand_8(vp8, v8); }
     88        #if defined(__SIZEOF_INT128__)
     89        { __int128 ret; ret = __sync_fetch_and_nand(vp16, v16); }
     90        { __int128 ret; ret = __sync_fetch_and_nand_16(vp16, v16); }
     91        #endif
     92
     93        { char ret; ret = __sync_add_and_fetch(vp1, v1); }
     94        { char ret; ret = __sync_add_and_fetch_1(vp1, v1); }
     95        { short ret; ret = __sync_add_and_fetch(vp2, v2); }
     96        { short ret; ret = __sync_add_and_fetch_2(vp2, v2); }
     97        { int ret; ret = __sync_add_and_fetch(vp4, v4); }
     98        { int ret; ret = __sync_add_and_fetch_4(vp4, v4); }
     99        { long long int ret; ret = __sync_add_and_fetch(vp8, v8); }
     100        { long long int ret; ret = __sync_add_and_fetch_8(vp8, v8); }
     101        #if defined(__SIZEOF_INT128__)
     102        { __int128 ret; ret = __sync_add_and_fetch(vp16, v16); }
     103        { __int128 ret; ret = __sync_add_and_fetch_16(vp16, v16); }
     104        #endif
     105
     106        { char ret; ret = __sync_sub_and_fetch(vp1, v1); }
     107        { char ret; ret = __sync_sub_and_fetch_1(vp1, v1); }
     108        { short ret; ret = __sync_sub_and_fetch(vp2, v2); }
     109        { short ret; ret = __sync_sub_and_fetch_2(vp2, v2); }
     110        { int ret; ret = __sync_sub_and_fetch(vp4, v4); }
     111        { int ret; ret = __sync_sub_and_fetch_4(vp4, v4); }
     112        { long long int ret; ret = __sync_sub_and_fetch(vp8, v8); }
     113        { long long int ret; ret = __sync_sub_and_fetch_8(vp8, v8); }
     114        #if defined(__SIZEOF_INT128__)
     115        { __int128 ret; ret = __sync_sub_and_fetch(vp16, v16); }
     116        { __int128 ret; ret = __sync_sub_and_fetch_16(vp16, v16); }
     117        #endif
     118
     119        { char ret; ret = __sync_or_and_fetch(vp1, v1); }
     120        { char ret; ret = __sync_or_and_fetch_1(vp1, v1); }
     121        { short ret; ret = __sync_or_and_fetch(vp2, v2); }
     122        { short ret; ret = __sync_or_and_fetch_2(vp2, v2); }
     123        { int ret; ret = __sync_or_and_fetch(vp4, v4); }
     124        { int ret; ret = __sync_or_and_fetch_4(vp4, v4); }
     125        { long long int ret; ret = __sync_or_and_fetch(vp8, v8); }
     126        { long long int ret; ret = __sync_or_and_fetch_8(vp8, v8); }
     127        #if defined(__SIZEOF_INT128__)
     128        { __int128 ret; ret = __sync_or_and_fetch(vp16, v16); }
     129        { __int128 ret; ret = __sync_or_and_fetch_16(vp16, v16); }
     130        #endif
     131
     132        { char ret; ret = __sync_and_and_fetch(vp1, v1); }
     133        { char ret; ret = __sync_and_and_fetch_1(vp1, v1); }
     134        { short ret; ret = __sync_and_and_fetch(vp2, v2); }
     135        { short ret; ret = __sync_and_and_fetch_2(vp2, v2); }
     136        { int ret; ret = __sync_and_and_fetch(vp4, v4); }
     137        { int ret; ret = __sync_and_and_fetch_4(vp4, v4); }
     138        { long long int ret; ret = __sync_and_and_fetch(vp8, v8); }
     139        { long long int ret; ret = __sync_and_and_fetch_8(vp8, v8); }
     140        #if defined(__SIZEOF_INT128__)
     141        { __int128 ret; ret = __sync_and_and_fetch(vp16, v16); }
     142        { __int128 ret; ret = __sync_and_and_fetch_16(vp16, v16); }
     143        #endif
     144
     145        { char ret; ret = __sync_xor_and_fetch(vp1, v1); }
     146        { char ret; ret = __sync_xor_and_fetch_1(vp1, v1); }
     147        { short ret; ret = __sync_xor_and_fetch(vp2, v2); }
     148        { short ret; ret = __sync_xor_and_fetch_2(vp2, v2); }
     149        { int ret; ret = __sync_xor_and_fetch(vp4, v4); }
     150        { int ret; ret = __sync_xor_and_fetch_4(vp4, v4); }
     151        { long long int ret; ret = __sync_xor_and_fetch(vp8, v8); }
     152        { long long int ret; ret = __sync_xor_and_fetch_8(vp8, v8); }
     153        #if defined(__SIZEOF_INT128__)
     154        { __int128 ret; ret = __sync_xor_and_fetch(vp16, v16); }
     155        { __int128 ret; ret = __sync_xor_and_fetch_16(vp16, v16); }
     156        #endif
     157
     158        { char ret; ret = __sync_nand_and_fetch(vp1, v1); }
     159        { char ret; ret = __sync_nand_and_fetch_1(vp1, v1); }
     160        { short ret; ret = __sync_nand_and_fetch(vp2, v2); }
     161        { short ret; ret = __sync_nand_and_fetch_2(vp2, v2); }
     162        { int ret; ret = __sync_nand_and_fetch(vp4, v4); }
     163        { int ret; ret = __sync_nand_and_fetch_4(vp4, v4); }
     164        { long long int ret; ret = __sync_nand_and_fetch(vp8, v8); }
     165        { long long int ret; ret = __sync_nand_and_fetch_8(vp8, v8); }
     166        #if defined(__SIZEOF_INT128__)
     167        { __int128 ret; ret = __sync_nand_and_fetch(vp16, v16); }
     168        { __int128 ret; ret = __sync_nand_and_fetch_16(vp16, v16); }
     169        #endif
     170
     171        { _Bool ret; ret = __sync_bool_compare_and_swap(vp1, v1, v1); }
     172        { _Bool ret; ret = __sync_bool_compare_and_swap_1(vp1, v1, v1); }
     173        { _Bool ret; ret = __sync_bool_compare_and_swap(vp2, v2, v2); }
     174        { _Bool ret; ret = __sync_bool_compare_and_swap_2(vp2, v2, v2); }
     175        { _Bool ret; ret = __sync_bool_compare_and_swap(vp4, v4, v4); }
     176        { _Bool ret; ret = __sync_bool_compare_and_swap_4(vp4, v4, v4); }
     177        { _Bool ret; ret = __sync_bool_compare_and_swap(vp8, v8, v8); }
     178        { _Bool ret; ret = __sync_bool_compare_and_swap_8(vp8, v8, v8); }
     179        #if defined(__SIZEOF_INT128__)
     180        { _Bool ret; ret = __sync_bool_compare_and_swap(vp16, v16, v16); }
     181        { _Bool ret; ret = __sync_bool_compare_and_swap_16(vp16, v16,v16); }
    132182        #endif
    133183        { _Bool ret; ret = __sync_bool_compare_and_swap(vpp, vp, vp); }
    134184
    135         { char ret; ret = __sync_val_compare_and_swap(vpc, vc, vc); }
    136         { short ret; ret = __sync_val_compare_and_swap(vps, vs, vs); }
    137         { int ret; ret = __sync_val_compare_and_swap(vpi, vi, vi); }
    138         { long int ret; ret = __sync_val_compare_and_swap(vpl, vl, vl); }
    139         { long long int ret; ret = __sync_val_compare_and_swap(vpll, vll, vll); }
    140         #if defined(__SIZEOF_INT128__)
    141         { __int128 ret; ret = __sync_val_compare_and_swap(vplll, vlll, vlll); }
     185        { char ret; ret = __sync_val_compare_and_swap(vp1, v1, v1); }
     186        { char ret; ret = __sync_val_compare_and_swap_1(vp1, v1, v1); }
     187        { short ret; ret = __sync_val_compare_and_swap(vp2, v2, v2); }
     188        { short ret; ret = __sync_val_compare_and_swap_2(vp2, v2, v2); }
     189        { int ret; ret = __sync_val_compare_and_swap(vp4, v4, v4); }
     190        { int ret; ret = __sync_val_compare_and_swap_4(vp4, v4, v4); }
     191        { long long int ret; ret = __sync_val_compare_and_swap(vp8, v8, v8); }
     192        { long long int ret; ret = __sync_val_compare_and_swap_8(vp8, v8, v8); }
     193        #if defined(__SIZEOF_INT128__)
     194        { __int128 ret; ret = __sync_val_compare_and_swap(vp16, v16, v16); }
     195        { __int128 ret; ret = __sync_val_compare_and_swap_16(vp16, v16,v16); }
    142196        #endif
    143197        { struct type * ret; ret = __sync_val_compare_and_swap(vpp, vp, vp); }
    144198
    145199
    146         { char ret; ret = __sync_lock_test_and_set(vpc, vc); }
    147         { short ret; ret = __sync_lock_test_and_set(vps, vs); }
    148         { int ret; ret = __sync_lock_test_and_set(vpi, vi); }
    149         { long int ret; ret = __sync_lock_test_and_set(vpl, vl); }
    150         { long long int ret; ret = __sync_lock_test_and_set(vpll, vll); }
    151         #if defined(__SIZEOF_INT128__)
    152         { __int128 ret; ret = __sync_lock_test_and_set(vplll, vlll); }
    153         #endif
    154 
    155         { __sync_lock_release(vpc); }
    156         { __sync_lock_release(vps); }
    157         { __sync_lock_release(vpi); }
    158         { __sync_lock_release(vpl); }
    159         { __sync_lock_release(vpll); }
    160         #if defined(__SIZEOF_INT128__)
    161         { __sync_lock_release(vplll); }
     200        { char ret; ret = __sync_lock_test_and_set(vp1, v1); }
     201        { char ret; ret = __sync_lock_test_and_set_1(vp1, v1); }
     202        { short ret; ret = __sync_lock_test_and_set(vp2, v2); }
     203        { short ret; ret = __sync_lock_test_and_set_2(vp2, v2); }
     204        { int ret; ret = __sync_lock_test_and_set(vp4, v4); }
     205        { int ret; ret = __sync_lock_test_and_set_4(vp4, v4); }
     206        { long long int ret; ret = __sync_lock_test_and_set(vp8, v8); }
     207        { long long int ret; ret = __sync_lock_test_and_set_8(vp8, v8); }
     208        #if defined(__SIZEOF_INT128__)
     209        { __int128 ret; ret = __sync_lock_test_and_set(vp16, v16); }
     210        { __int128 ret; ret = __sync_lock_test_and_set_16(vp16, v16); }
     211        #endif
     212
     213        { __sync_lock_release(vp1); }
     214        { __sync_lock_release_1(vp1); }
     215        { __sync_lock_release(vp2); }
     216        { __sync_lock_release_2(vp2); }
     217        { __sync_lock_release(vp4); }
     218        { __sync_lock_release_4(vp4); }
     219        { __sync_lock_release(vp8); }
     220        { __sync_lock_release_8(vp8); }
     221        #if defined(__SIZEOF_INT128__)
     222        { __sync_lock_release(vp16); }
     223        { __sync_lock_release_16(vp16); }
    162224        #endif
    163225
     
    168230
    169231        { _Bool ret; ret = __atomic_test_and_set(vpB, vB); }
    170         { _Bool ret; ret = __atomic_test_and_set(vpc, vc); }
     232        { _Bool ret; ret = __atomic_test_and_set(vp1, v1); }
    171233        { __atomic_clear(vpB, vB); }
    172         { __atomic_clear(vpc, vc); }
    173 
    174         { char ret; ret = __atomic_exchange_n(vpc, vc, __ATOMIC_SEQ_CST); }
    175         { char ret; __atomic_exchange(vpc, &vc, &ret, __ATOMIC_SEQ_CST); }
    176         { short ret; ret = __atomic_exchange_n(vps, vs, __ATOMIC_SEQ_CST); }
    177         { short ret; __atomic_exchange(vps, &vs, &ret, __ATOMIC_SEQ_CST); }
    178         { int ret; ret = __atomic_exchange_n(vpi, vi, __ATOMIC_SEQ_CST); }
    179         { int ret; __atomic_exchange(vpi, &vi, &ret, __ATOMIC_SEQ_CST); }
    180         { long int ret; ret = __atomic_exchange_n(vpl, vl, __ATOMIC_SEQ_CST); }
    181         { long int ret; __atomic_exchange(vpl, &vl, &ret, __ATOMIC_SEQ_CST); }
    182         { long long int ret; ret = __atomic_exchange_n(vpll, vll, __ATOMIC_SEQ_CST); }
    183         { long long int ret; __atomic_exchange(vpll, &vll, &ret, __ATOMIC_SEQ_CST); }
    184         #if defined(__SIZEOF_INT128__)
    185         { __int128 ret; ret = __atomic_exchange_n(vplll, vlll, __ATOMIC_SEQ_CST); }
    186         { __int128 ret; __atomic_exchange(vplll, &vlll, &ret, __ATOMIC_SEQ_CST); }
     234        { __atomic_clear(vp1, v1); }
     235
     236        { char ret; ret = __atomic_exchange_n(vp1, v1, __ATOMIC_SEQ_CST); }
     237        { char ret; ret = __atomic_exchange_1(vp1, v1, __ATOMIC_SEQ_CST); }
     238        { char ret; __atomic_exchange(vp1, &v1, &ret, __ATOMIC_SEQ_CST); }
     239        { short ret; ret = __atomic_exchange_n(vp2, v2, __ATOMIC_SEQ_CST); }
     240        { short ret; ret = __atomic_exchange_2(vp2, v2, __ATOMIC_SEQ_CST); }
     241        { short ret; __atomic_exchange(vp2, &v2, &ret, __ATOMIC_SEQ_CST); }
     242        { int ret; ret = __atomic_exchange_n(vp4, v4, __ATOMIC_SEQ_CST); }
     243        { int ret; ret = __atomic_exchange_4(vp4, v4, __ATOMIC_SEQ_CST); }
     244        { int ret; __atomic_exchange(vp4, &v4, &ret, __ATOMIC_SEQ_CST); }
     245        { long long int ret; ret = __atomic_exchange_n(vp8, v8, __ATOMIC_SEQ_CST); }
     246        { long long int ret; ret = __atomic_exchange_8(vp8, v8, __ATOMIC_SEQ_CST); }
     247        { long long int ret; __atomic_exchange(vp8, &v8, &ret, __ATOMIC_SEQ_CST); }
     248        #if defined(__SIZEOF_INT128__)
     249        { __int128 ret; ret = __atomic_exchange_n(vp16, v16, __ATOMIC_SEQ_CST); }
     250        { __int128 ret; ret = __atomic_exchange_16(vp16, v16, __ATOMIC_SEQ_CST); }
     251        { __int128 ret; __atomic_exchange(vp16, &v16, &ret, __ATOMIC_SEQ_CST); }
    187252        #endif
    188253        { struct type * ret; ret = __atomic_exchange_n(vpp, vp, __ATOMIC_SEQ_CST); }
    189254        { struct type * ret; __atomic_exchange(vpp, &vp, &ret, __ATOMIC_SEQ_CST); }
    190255
    191         { char ret; ret = __atomic_load_n(vpc, __ATOMIC_SEQ_CST); }
    192         { char ret; __atomic_load(vpc, &ret, __ATOMIC_SEQ_CST); }
    193         { short ret; ret = __atomic_load_n(vps, __ATOMIC_SEQ_CST); }
    194         { short ret; __atomic_load(vps, &ret, __ATOMIC_SEQ_CST); }
    195         { int ret; ret = __atomic_load_n(vpi, __ATOMIC_SEQ_CST); }
    196         { int ret; __atomic_load(vpi, &ret, __ATOMIC_SEQ_CST); }
    197         { long int ret; ret = __atomic_load_n(vpl, __ATOMIC_SEQ_CST); }
    198         { long int ret; __atomic_load(vpl, &ret, __ATOMIC_SEQ_CST); }
    199         { long long int ret; ret = __atomic_load_n(vpll, __ATOMIC_SEQ_CST); }
    200         { long long int ret; __atomic_load(vpll, &ret, __ATOMIC_SEQ_CST); }
    201         #if defined(__SIZEOF_INT128__)
    202         { __int128 ret; ret = __atomic_load_n(vplll, __ATOMIC_SEQ_CST); }
    203         { __int128 ret; __atomic_load(vplll, &ret, __ATOMIC_SEQ_CST); }
     256        { char ret; ret = __atomic_load_n(vp1, __ATOMIC_SEQ_CST); }
     257        { char ret; ret = __atomic_load_1(vp1, __ATOMIC_SEQ_CST); }
     258        { char ret; __atomic_load(vp1, &ret, __ATOMIC_SEQ_CST); }
     259        { short ret; ret = __atomic_load_n(vp2, __ATOMIC_SEQ_CST); }
     260        { short ret; ret = __atomic_load_2(vp2, __ATOMIC_SEQ_CST); }
     261        { short ret; __atomic_load(vp2, &ret, __ATOMIC_SEQ_CST); }
     262        { int ret; ret = __atomic_load_n(vp4, __ATOMIC_SEQ_CST); }
     263        { int ret; ret = __atomic_load_4(vp4, __ATOMIC_SEQ_CST); }
     264        { int ret; __atomic_load(vp4, &ret, __ATOMIC_SEQ_CST); }
     265        { long long int ret; ret = __atomic_load_n(vp8, __ATOMIC_SEQ_CST); }
     266        { long long int ret; ret = __atomic_load_8(vp8, __ATOMIC_SEQ_CST); }
     267        { long long int ret; __atomic_load(vp8, &ret, __ATOMIC_SEQ_CST); }
     268        #if defined(__SIZEOF_INT128__)
     269        { __int128 ret; ret = __atomic_load_n(vp16, __ATOMIC_SEQ_CST); }
     270        { __int128 ret; ret = __atomic_load_16(vp16, __ATOMIC_SEQ_CST); }
     271        { __int128 ret; __atomic_load(vp16, &ret, __ATOMIC_SEQ_CST); }
    204272        #endif
    205273        { struct type * ret; ret = __atomic_load_n(vpp, __ATOMIC_SEQ_CST); }
    206274        { struct type * ret; __atomic_load(vpp, &ret, __ATOMIC_SEQ_CST); }
    207275
    208         { _Bool ret; ret = __atomic_compare_exchange_n(vpc, rpc, vc, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    209         { _Bool ret; ret = __atomic_compare_exchange(vpc, rpc, &vc, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    210         { _Bool ret; ret = __atomic_compare_exchange_n(vps, rps, vs, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    211         { _Bool ret; ret = __atomic_compare_exchange(vps, rps, &vs, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    212         { _Bool ret; ret = __atomic_compare_exchange_n(vpi, rpi, vi, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    213         { _Bool ret; ret = __atomic_compare_exchange(vpi, rpi, &vi, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    214         { _Bool ret; ret = __atomic_compare_exchange_n(vpl, rpl, vl, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    215         { _Bool ret; ret = __atomic_compare_exchange(vpl, rpl, &vl, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    216         { _Bool ret; ret = __atomic_compare_exchange_n(vpll, rpll, vll, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    217         { _Bool ret; ret = __atomic_compare_exchange(vpll, rpll, &vll, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    218         #if defined(__SIZEOF_INT128__)
    219         { _Bool ret; ret = __atomic_compare_exchange_n(vplll, rplll, vlll, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    220         { _Bool ret; ret = __atomic_compare_exchange(vplll, rplll, &vlll, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     276        { _Bool ret; ret = __atomic_compare_exchange_n(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     277        { _Bool ret; ret = __atomic_compare_exchange_1(vp1, rp1, v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     278        { _Bool ret; ret = __atomic_compare_exchange(vp1, rp1, &v1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     279        { _Bool ret; ret = __atomic_compare_exchange_n(vp2, rp2, v2, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     280        { _Bool ret; ret = __atomic_compare_exchange_2(vp2, rp2, v2, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     281        { _Bool ret; ret = __atomic_compare_exchange(vp2, rp2, &v2, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     282        { _Bool ret; ret = __atomic_compare_exchange_n(vp4, rp4, v4, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     283        { _Bool ret; ret = __atomic_compare_exchange_4(vp4, rp4, v4, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     284        { _Bool ret; ret = __atomic_compare_exchange(vp4, rp4, &v4, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     285        { _Bool ret; ret = __atomic_compare_exchange_n(vp8, rp8, v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     286        { _Bool ret; ret = __atomic_compare_exchange_8(vp8, rp8, v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     287        { _Bool ret; ret = __atomic_compare_exchange(vp8, rp8, &v8, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     288        #if defined(__SIZEOF_INT128__)
     289        { _Bool ret; ret = __atomic_compare_exchange_n(vp16, rp16, v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     290        { _Bool ret; ret = __atomic_compare_exchange_16(vp16, rp16, v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
     291        { _Bool ret; ret = __atomic_compare_exchange(vp16, rp16, &v16, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    221292        #endif
    222293        { _Bool ret; ret = __atomic_compare_exchange_n(vpp, rpp, vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    223294        { _Bool ret; ret = __atomic_compare_exchange(vpp, rpp, &vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    224295
    225         { __atomic_store_n(vpc, vc, __ATOMIC_SEQ_CST); }
    226         { __atomic_store(vpc, &vc, __ATOMIC_SEQ_CST); }
    227         { __atomic_store_n(vps, vs, __ATOMIC_SEQ_CST); }
    228         { __atomic_store(vps, &vs, __ATOMIC_SEQ_CST); }
    229         { __atomic_store_n(vpi, vi, __ATOMIC_SEQ_CST); }
    230         { __atomic_store(vpi, &vi, __ATOMIC_SEQ_CST); }
    231         { __atomic_store_n(vpl, vl, __ATOMIC_SEQ_CST); }
    232         { __atomic_store(vpl, &vl, __ATOMIC_SEQ_CST); }
    233         { __atomic_store_n(vpll, vll, __ATOMIC_SEQ_CST); }
    234         { __atomic_store(vpll, &vll, __ATOMIC_SEQ_CST); }
    235         #if defined(__SIZEOF_INT128__)
    236         { __atomic_store_n(vplll, vlll, __ATOMIC_SEQ_CST); }
    237         { __atomic_store(vplll, &vlll, __ATOMIC_SEQ_CST); }
     296        { __atomic_store_n(vp1, v1, __ATOMIC_SEQ_CST); }
     297        { __atomic_store_1(vp1, v1, __ATOMIC_SEQ_CST); }
     298        { __atomic_store(vp1, &v1, __ATOMIC_SEQ_CST); }
     299        { __atomic_store_n(vp2, v2, __ATOMIC_SEQ_CST); }
     300        { __atomic_store_2(vp2, v2, __ATOMIC_SEQ_CST); }
     301        { __atomic_store(vp2, &v2, __ATOMIC_SEQ_CST); }
     302        { __atomic_store_n(vp4, v4, __ATOMIC_SEQ_CST); }
     303        { __atomic_store_4(vp4, v4, __ATOMIC_SEQ_CST); }
     304        { __atomic_store(vp4, &v4, __ATOMIC_SEQ_CST); }
     305        { __atomic_store_n(vp8, v8, __ATOMIC_SEQ_CST); }
     306        { __atomic_store_8(vp8, v8, __ATOMIC_SEQ_CST); }
     307        { __atomic_store(vp8, &v8, __ATOMIC_SEQ_CST); }
     308        #if defined(__SIZEOF_INT128__)
     309        { __atomic_store_n(vp16, v16, __ATOMIC_SEQ_CST); }
     310        { __atomic_store_16(vp16, v16, __ATOMIC_SEQ_CST); }
     311        { __atomic_store(vp16, &v16, __ATOMIC_SEQ_CST); }
    238312        #endif
    239313        { __atomic_store_n(vpp, vp, __ATOMIC_SEQ_CST); }
    240314        { __atomic_store(vpp, &vp, __ATOMIC_SEQ_CST); }
    241315
    242         { char ret; ret = __atomic_add_fetch(vpc, vc, __ATOMIC_SEQ_CST); }
    243         { short ret; ret = __atomic_add_fetch(vps, vs, __ATOMIC_SEQ_CST); }
    244         { int ret; ret = __atomic_add_fetch(vpi, vi, __ATOMIC_SEQ_CST); }
    245         { long int ret; ret = __atomic_add_fetch(vpl, vl, __ATOMIC_SEQ_CST); }
    246         { long long int ret; ret = __atomic_add_fetch(vpll, vll, __ATOMIC_SEQ_CST); }
    247         #if defined(__SIZEOF_INT128__)
    248         { __int128 ret; ret = __atomic_add_fetch(vplll, vlll, __ATOMIC_SEQ_CST); }
    249         #endif
    250 
    251         { char ret; ret = __atomic_sub_fetch(vpc, vc, __ATOMIC_SEQ_CST); }
    252         { short ret; ret = __atomic_sub_fetch(vps, vs, __ATOMIC_SEQ_CST); }
    253         { int ret; ret = __atomic_sub_fetch(vpi, vi, __ATOMIC_SEQ_CST); }
    254         { long int ret; ret = __atomic_sub_fetch(vpl, vl, __ATOMIC_SEQ_CST); }
    255         { long long int ret; ret = __atomic_sub_fetch(vpll, vll, __ATOMIC_SEQ_CST); }
    256         #if defined(__SIZEOF_INT128__)
    257         { __int128 ret; ret = __atomic_sub_fetch(vplll, vlll, __ATOMIC_SEQ_CST); }
    258         #endif
    259 
    260         { char ret; ret = __atomic_and_fetch(vpc, vc, __ATOMIC_SEQ_CST); }
    261         { short ret; ret = __atomic_and_fetch(vps, vs, __ATOMIC_SEQ_CST); }
    262         { int ret; ret = __atomic_and_fetch(vpi, vi, __ATOMIC_SEQ_CST); }
    263         { long int ret; ret = __atomic_and_fetch(vpl, vl, __ATOMIC_SEQ_CST); }
    264         { long long int ret; ret = __atomic_and_fetch(vpll, vll, __ATOMIC_SEQ_CST); }
    265         #if defined(__SIZEOF_INT128__)
    266         { __int128 ret; ret = __atomic_and_fetch(vplll, vlll, __ATOMIC_SEQ_CST); }
    267         #endif
    268 
    269         { char ret; ret = __atomic_nand_fetch(vpc, vc, __ATOMIC_SEQ_CST); }
    270         { short ret; ret = __atomic_nand_fetch(vps, vs, __ATOMIC_SEQ_CST); }
    271         { int ret; ret = __atomic_nand_fetch(vpi, vi, __ATOMIC_SEQ_CST); }
    272         { long int ret; ret = __atomic_nand_fetch(vpl, vl, __ATOMIC_SEQ_CST); }
    273         { long long int ret; ret = __atomic_nand_fetch(vpll, vll, __ATOMIC_SEQ_CST); }
    274         #if defined(__SIZEOF_INT128__)
    275         { __int128 ret; ret = __atomic_nand_fetch(vplll, vlll, __ATOMIC_SEQ_CST); }
    276         #endif
    277 
    278         { char ret; ret = __atomic_xor_fetch(vpc, vc, __ATOMIC_SEQ_CST); }
    279         { short ret; ret = __atomic_xor_fetch(vps, vs, __ATOMIC_SEQ_CST); }
    280         { int ret; ret = __atomic_xor_fetch(vpi, vi, __ATOMIC_SEQ_CST); }
    281         { long int ret; ret = __atomic_xor_fetch(vpl, vl, __ATOMIC_SEQ_CST); }
    282         { long long int ret; ret = __atomic_xor_fetch(vpll, vll, __ATOMIC_SEQ_CST); }
    283         #if defined(__SIZEOF_INT128__)
    284         { __int128 ret; ret = __atomic_xor_fetch(vplll, vlll, __ATOMIC_SEQ_CST); }
    285         #endif
    286 
    287         { char ret; ret = __atomic_or_fetch(vpc, vc, __ATOMIC_SEQ_CST); }
    288         { short ret; ret = __atomic_or_fetch(vps, vs, __ATOMIC_SEQ_CST); }
    289         { int ret; ret = __atomic_or_fetch(vpi, vi, __ATOMIC_SEQ_CST); }
    290         { long int ret; ret = __atomic_or_fetch(vpl, vl, __ATOMIC_SEQ_CST); }
    291         { long long int ret; ret = __atomic_or_fetch(vpll, vll, __ATOMIC_SEQ_CST); }
    292         #if defined(__SIZEOF_INT128__)
    293         { __int128 ret; ret = __atomic_or_fetch(vplll, vlll, __ATOMIC_SEQ_CST); }
    294         #endif
    295 
    296         { char ret; ret = __atomic_fetch_add(vpc, vc, __ATOMIC_SEQ_CST); }
    297         { short ret; ret = __atomic_fetch_add(vps, vs, __ATOMIC_SEQ_CST); }
    298         { int ret; ret = __atomic_fetch_add(vpi, vi, __ATOMIC_SEQ_CST); }
    299         { long int ret; ret = __atomic_fetch_add(vpl, vl, __ATOMIC_SEQ_CST); }
    300         { long long int ret; ret = __atomic_fetch_add(vpll, vll, __ATOMIC_SEQ_CST); }
    301         #if defined(__SIZEOF_INT128__)
    302         { __int128 ret; ret = __atomic_fetch_add(vplll, vlll, __ATOMIC_SEQ_CST); }
    303         #endif
    304 
    305         { char ret; ret = __atomic_fetch_sub(vpc, vc, __ATOMIC_SEQ_CST); }
    306         { short ret; ret = __atomic_fetch_sub(vps, vs, __ATOMIC_SEQ_CST); }
    307         { int ret; ret = __atomic_fetch_sub(vpi, vi, __ATOMIC_SEQ_CST); }
    308         { long int ret; ret = __atomic_fetch_sub(vpl, vl, __ATOMIC_SEQ_CST); }
    309         { long long int ret; ret = __atomic_fetch_sub(vpll, vll, __ATOMIC_SEQ_CST); }
    310         #if defined(__SIZEOF_INT128__)
    311         { __int128 ret; ret = __atomic_fetch_sub(vplll, vlll, __ATOMIC_SEQ_CST); }
    312         #endif
    313 
    314         { char ret; ret = __atomic_fetch_and(vpc, vc, __ATOMIC_SEQ_CST); }
    315         { short ret; ret = __atomic_fetch_and(vps, vs, __ATOMIC_SEQ_CST); }
    316         { int ret; ret = __atomic_fetch_and(vpi, vi, __ATOMIC_SEQ_CST); }
    317         { long int ret; ret = __atomic_fetch_and(vpl, vl, __ATOMIC_SEQ_CST); }
    318         { long long int ret; ret = __atomic_fetch_and(vpll, vll, __ATOMIC_SEQ_CST); }
    319         #if defined(__SIZEOF_INT128__)
    320         { __int128 ret; ret = __atomic_fetch_and(vplll, vlll, __ATOMIC_SEQ_CST); }
    321         #endif
    322 
    323         { char ret; ret = __atomic_fetch_nand(vpc, vc, __ATOMIC_SEQ_CST); }
    324         { short ret; ret = __atomic_fetch_nand(vps, vs, __ATOMIC_SEQ_CST); }
    325         { int ret; ret = __atomic_fetch_nand(vpi, vi, __ATOMIC_SEQ_CST); }
    326         { long int ret; ret = __atomic_fetch_nand(vpl, vl, __ATOMIC_SEQ_CST); }
    327         { long long int ret; ret = __atomic_fetch_nand(vpll, vll, __ATOMIC_SEQ_CST); }
    328         #if defined(__SIZEOF_INT128__)
    329         { __int128 ret; ret = __atomic_fetch_nand(vplll, vlll, __ATOMIC_SEQ_CST); }
    330         #endif
    331 
    332         { char ret; ret = __atomic_fetch_xor(vpc, vc, __ATOMIC_SEQ_CST); }
    333         { short ret; ret = __atomic_fetch_xor(vps, vs, __ATOMIC_SEQ_CST); }
    334         { int ret; ret = __atomic_fetch_xor(vpi, vi, __ATOMIC_SEQ_CST); }
    335         { long int ret; ret = __atomic_fetch_xor(vpl, vl, __ATOMIC_SEQ_CST); }
    336         { long long int ret; ret = __atomic_fetch_xor(vpll, vll, __ATOMIC_SEQ_CST); }
    337         #if defined(__SIZEOF_INT128__)
    338         { __int128 ret; ret = __atomic_fetch_xor(vplll, vlll, __ATOMIC_SEQ_CST); }
    339         #endif
    340 
    341         { char ret; ret = __atomic_fetch_or(vpc, vc, __ATOMIC_SEQ_CST); }
    342         { short ret; ret = __atomic_fetch_or(vps, vs, __ATOMIC_SEQ_CST); }
    343         { int ret; ret = __atomic_fetch_or(vpi, vi, __ATOMIC_SEQ_CST); }
    344         { long int ret; ret = __atomic_fetch_or(vpl, vl, __ATOMIC_SEQ_CST); }
    345         { long long int ret; ret = __atomic_fetch_or(vpll, vll, __ATOMIC_SEQ_CST); }
    346         #if defined(__SIZEOF_INT128__)
    347         { __int128 ret; ret = __atomic_fetch_or(vplll, vlll, __ATOMIC_SEQ_CST); }
    348         #endif
    349 
    350         { _Bool ret; ret = __atomic_always_lock_free(sizeof(int), vpi); }
    351         { _Bool ret; ret = __atomic_is_lock_free(sizeof(int), vpi); }
     316        { char ret; ret = __atomic_add_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
     317        { char ret; ret = __atomic_add_fetch_1(vp1, v1, __ATOMIC_SEQ_CST); }
     318        { short ret; ret = __atomic_add_fetch(vp2, v2, __ATOMIC_SEQ_CST); }
     319        { short ret; ret = __atomic_add_fetch_2(vp2, v2, __ATOMIC_SEQ_CST); }
     320        { int ret; ret = __atomic_add_fetch(vp4, v4, __ATOMIC_SEQ_CST); }
     321        { int ret; ret = __atomic_add_fetch_4(vp4, v4, __ATOMIC_SEQ_CST); }
     322        { long long int ret; ret = __atomic_add_fetch(vp8, v8, __ATOMIC_SEQ_CST); }
     323        { long long int ret; ret = __atomic_add_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); }
     324        #if defined(__SIZEOF_INT128__)
     325        { __int128 ret; ret = __atomic_add_fetch(vp16, v16, __ATOMIC_SEQ_CST); }
     326        { __int128 ret; ret = __atomic_add_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); }
     327        #endif
     328
     329        { char ret; ret = __atomic_sub_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
     330        { char ret; ret = __atomic_sub_fetch_1(vp1, v1, __ATOMIC_SEQ_CST); }
     331        { short ret; ret = __atomic_sub_fetch(vp2, v2, __ATOMIC_SEQ_CST); }
     332        { short ret; ret = __atomic_sub_fetch_2(vp2, v2, __ATOMIC_SEQ_CST); }
     333        { int ret; ret = __atomic_sub_fetch(vp4, v4, __ATOMIC_SEQ_CST); }
     334        { int ret; ret = __atomic_sub_fetch_4(vp4, v4, __ATOMIC_SEQ_CST); }
     335        { long long int ret; ret = __atomic_sub_fetch(vp8, v8, __ATOMIC_SEQ_CST); }
     336        { long long int ret; ret = __atomic_sub_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); }
     337        #if defined(__SIZEOF_INT128__)
     338        { __int128 ret; ret = __atomic_sub_fetch(vp16, v16, __ATOMIC_SEQ_CST); }
     339        { __int128 ret; ret = __atomic_sub_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); }
     340        #endif
     341
     342        { char ret; ret = __atomic_and_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
     343        { char ret; ret = __atomic_and_fetch_1(vp1, v1, __ATOMIC_SEQ_CST); }
     344        { short ret; ret = __atomic_and_fetch(vp2, v2, __ATOMIC_SEQ_CST); }
     345        { short ret; ret = __atomic_and_fetch_2(vp2, v2, __ATOMIC_SEQ_CST); }
     346        { int ret; ret = __atomic_and_fetch(vp4, v4, __ATOMIC_SEQ_CST); }
     347        { int ret; ret = __atomic_and_fetch_4(vp4, v4, __ATOMIC_SEQ_CST); }
     348        { long long int ret; ret = __atomic_and_fetch(vp8, v8, __ATOMIC_SEQ_CST); }
     349        { long long int ret; ret = __atomic_and_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); }
     350        #if defined(__SIZEOF_INT128__)
     351        { __int128 ret; ret = __atomic_and_fetch(vp16, v16, __ATOMIC_SEQ_CST); }
     352        { __int128 ret; ret = __atomic_and_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); }
     353        #endif
     354
     355        { char ret; ret = __atomic_nand_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
     356        { char ret; ret = __atomic_nand_fetch_1(vp1, v1, __ATOMIC_SEQ_CST); }
     357        { short ret; ret = __atomic_nand_fetch(vp2, v2, __ATOMIC_SEQ_CST); }
     358        { short ret; ret = __atomic_nand_fetch_2(vp2, v2, __ATOMIC_SEQ_CST); }
     359        { int ret; ret = __atomic_nand_fetch(vp4, v4, __ATOMIC_SEQ_CST); }
     360        { int ret; ret = __atomic_nand_fetch_4(vp4, v4, __ATOMIC_SEQ_CST); }
     361        { long long int ret; ret = __atomic_nand_fetch(vp8, v8, __ATOMIC_SEQ_CST); }
     362        { long long int ret; ret = __atomic_nand_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); }
     363        #if defined(__SIZEOF_INT128__)
     364        { __int128 ret; ret = __atomic_nand_fetch(vp16, v16, __ATOMIC_SEQ_CST); }
     365        { __int128 ret; ret = __atomic_nand_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); }
     366        #endif
     367
     368        { char ret; ret = __atomic_xor_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
     369        { char ret; ret = __atomic_xor_fetch_1(vp1, v1, __ATOMIC_SEQ_CST); }
     370        { short ret; ret = __atomic_xor_fetch(vp2, v2, __ATOMIC_SEQ_CST); }
     371        { short ret; ret = __atomic_xor_fetch_2(vp2, v2, __ATOMIC_SEQ_CST); }
     372        { int ret; ret = __atomic_xor_fetch(vp4, v4, __ATOMIC_SEQ_CST); }
     373        { int ret; ret = __atomic_xor_fetch_4(vp4, v4, __ATOMIC_SEQ_CST); }
     374        { long long int ret; ret = __atomic_xor_fetch(vp8, v8, __ATOMIC_SEQ_CST); }
     375        { long long int ret; ret = __atomic_xor_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); }
     376        #if defined(__SIZEOF_INT128__)
     377        { __int128 ret; ret = __atomic_xor_fetch(vp16, v16, __ATOMIC_SEQ_CST); }
     378        { __int128 ret; ret = __atomic_xor_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); }
     379        #endif
     380
     381        { char ret; ret = __atomic_or_fetch(vp1, v1, __ATOMIC_SEQ_CST); }
     382        { char ret; ret = __atomic_or_fetch_1(vp1, v1, __ATOMIC_SEQ_CST); }
     383        { short ret; ret = __atomic_or_fetch(vp2, v2, __ATOMIC_SEQ_CST); }
     384        { short ret; ret = __atomic_or_fetch_2(vp2, v2, __ATOMIC_SEQ_CST); }
     385        { int ret; ret = __atomic_or_fetch(vp4, v4, __ATOMIC_SEQ_CST); }
     386        { int ret; ret = __atomic_or_fetch_4(vp4, v4, __ATOMIC_SEQ_CST); }
     387        { long long int ret; ret = __atomic_or_fetch(vp8, v8, __ATOMIC_SEQ_CST); }
     388        { long long int ret; ret = __atomic_or_fetch_8(vp8, v8, __ATOMIC_SEQ_CST); }
     389        #if defined(__SIZEOF_INT128__)
     390        { __int128 ret; ret = __atomic_or_fetch(vp16, v16, __ATOMIC_SEQ_CST); }
     391        { __int128 ret; ret = __atomic_or_fetch_16(vp16, v16, __ATOMIC_SEQ_CST); }
     392        #endif
     393
     394        { char ret; ret = __atomic_fetch_add(vp1, v1, __ATOMIC_SEQ_CST); }
     395        { char ret; ret = __atomic_fetch_add_1(vp1, v1, __ATOMIC_SEQ_CST); }
     396        { short ret; ret = __atomic_fetch_add(vp2, v2, __ATOMIC_SEQ_CST); }
     397        { short ret; ret = __atomic_fetch_add_2(vp2, v2, __ATOMIC_SEQ_CST); }
     398        { int ret; ret = __atomic_fetch_add(vp4, v4, __ATOMIC_SEQ_CST); }
     399        { int ret; ret = __atomic_fetch_add_4(vp4, v4, __ATOMIC_SEQ_CST); }
     400        { long long int ret; ret = __atomic_fetch_add(vp8, v8, __ATOMIC_SEQ_CST); }
     401        { long long int ret; ret = __atomic_fetch_add_8(vp8, v8, __ATOMIC_SEQ_CST); }
     402        #if defined(__SIZEOF_INT128__)
     403        { __int128 ret; ret = __atomic_fetch_add(vp16, v16, __ATOMIC_SEQ_CST); }
     404        { __int128 ret; ret = __atomic_fetch_add_16(vp16, v16, __ATOMIC_SEQ_CST); }
     405        #endif
     406
     407        { char ret; ret = __atomic_fetch_sub(vp1, v1, __ATOMIC_SEQ_CST); }
     408        { char ret; ret = __atomic_fetch_sub_1(vp1, v1, __ATOMIC_SEQ_CST); }
     409        { short ret; ret = __atomic_fetch_sub(vp2, v2, __ATOMIC_SEQ_CST); }
     410        { short ret; ret = __atomic_fetch_sub_2(vp2, v2, __ATOMIC_SEQ_CST); }
     411        { int ret; ret = __atomic_fetch_sub(vp4, v4, __ATOMIC_SEQ_CST); }
     412        { int ret; ret = __atomic_fetch_sub_4(vp4, v4, __ATOMIC_SEQ_CST); }
     413        { long long int ret; ret = __atomic_fetch_sub(vp8, v8, __ATOMIC_SEQ_CST); }
     414        { long long int ret; ret = __atomic_fetch_sub_8(vp8, v8, __ATOMIC_SEQ_CST); }
     415        #if defined(__SIZEOF_INT128__)
     416        { __int128 ret; ret = __atomic_fetch_sub(vp16, v16, __ATOMIC_SEQ_CST); }
     417        { __int128 ret; ret = __atomic_fetch_sub_16(vp16, v16, __ATOMIC_SEQ_CST); }
     418        #endif
     419
     420        { char ret; ret = __atomic_fetch_and(vp1, v1, __ATOMIC_SEQ_CST); }
     421        { char ret; ret = __atomic_fetch_and_1(vp1, v1, __ATOMIC_SEQ_CST); }
     422        { short ret; ret = __atomic_fetch_and(vp2, v2, __ATOMIC_SEQ_CST); }
     423        { short ret; ret = __atomic_fetch_and_2(vp2, v2, __ATOMIC_SEQ_CST); }
     424        { int ret; ret = __atomic_fetch_and(vp4, v4, __ATOMIC_SEQ_CST); }
     425        { int ret; ret = __atomic_fetch_and_4(vp4, v4, __ATOMIC_SEQ_CST); }
     426        { long long int ret; ret = __atomic_fetch_and(vp8, v8, __ATOMIC_SEQ_CST); }
     427        { long long int ret; ret = __atomic_fetch_and_8(vp8, v8, __ATOMIC_SEQ_CST); }
     428        #if defined(__SIZEOF_INT128__)
     429        { __int128 ret; ret = __atomic_fetch_and(vp16, v16, __ATOMIC_SEQ_CST); }
     430        { __int128 ret; ret = __atomic_fetch_and_16(vp16, v16, __ATOMIC_SEQ_CST); }
     431        #endif
     432
     433        { char ret; ret = __atomic_fetch_nand(vp1, v1, __ATOMIC_SEQ_CST); }
     434        { char ret; ret = __atomic_fetch_nand_1(vp1, v1, __ATOMIC_SEQ_CST); }
     435        { short ret; ret = __atomic_fetch_nand(vp2, v2, __ATOMIC_SEQ_CST); }
     436        { short ret; ret = __atomic_fetch_nand_2(vp2, v2, __ATOMIC_SEQ_CST); }
     437        { int ret; ret = __atomic_fetch_nand(vp4, v4, __ATOMIC_SEQ_CST); }
     438        { int ret; ret = __atomic_fetch_nand_4(vp4, v4, __ATOMIC_SEQ_CST); }
     439        { long long int ret; ret = __atomic_fetch_nand(vp8, v8, __ATOMIC_SEQ_CST); }
     440        { long long int ret; ret = __atomic_fetch_nand_8(vp8, v8, __ATOMIC_SEQ_CST); }
     441        #if defined(__SIZEOF_INT128__)
     442        { __int128 ret; ret = __atomic_fetch_nand(vp16, v16, __ATOMIC_SEQ_CST); }
     443        { __int128 ret; ret = __atomic_fetch_nand_16(vp16, v16, __ATOMIC_SEQ_CST); }
     444        #endif
     445
     446        { char ret; ret = __atomic_fetch_xor(vp1, v1, __ATOMIC_SEQ_CST); }
     447        { char ret; ret = __atomic_fetch_xor_1(vp1, v1, __ATOMIC_SEQ_CST); }
     448        { short ret; ret = __atomic_fetch_xor(vp2, v2, __ATOMIC_SEQ_CST); }
     449        { short ret; ret = __atomic_fetch_xor_2(vp2, v2, __ATOMIC_SEQ_CST); }
     450        { int ret; ret = __atomic_fetch_xor(vp4, v4, __ATOMIC_SEQ_CST); }
     451        { int ret; ret = __atomic_fetch_xor_4(vp4, v4, __ATOMIC_SEQ_CST); }
     452        { long long int ret; ret = __atomic_fetch_xor(vp8, v8, __ATOMIC_SEQ_CST); }
     453        { long long int ret; ret = __atomic_fetch_xor_8(vp8, v8, __ATOMIC_SEQ_CST); }
     454        #if defined(__SIZEOF_INT128__)
     455        { __int128 ret; ret = __atomic_fetch_xor(vp16, v16, __ATOMIC_SEQ_CST); }
     456        { __int128 ret; ret = __atomic_fetch_xor_16(vp16, v16, __ATOMIC_SEQ_CST); }
     457        #endif
     458
     459        { char ret; ret = __atomic_fetch_or(vp1, v1, __ATOMIC_SEQ_CST); }
     460        { char ret; ret = __atomic_fetch_or_1(vp1, v1, __ATOMIC_SEQ_CST); }
     461        { short ret; ret = __atomic_fetch_or(vp2, v2, __ATOMIC_SEQ_CST); }
     462        { short ret; ret = __atomic_fetch_or_2(vp2, v2, __ATOMIC_SEQ_CST); }
     463        { int ret; ret = __atomic_fetch_or(vp4, v4, __ATOMIC_SEQ_CST); }
     464        { int ret; ret = __atomic_fetch_or_4(vp4, v4, __ATOMIC_SEQ_CST); }
     465        { long long int ret; ret = __atomic_fetch_or(vp8, v8, __ATOMIC_SEQ_CST); }
     466        { long long int ret; ret = __atomic_fetch_or_8(vp8, v8, __ATOMIC_SEQ_CST); }
     467        #if defined(__SIZEOF_INT128__)
     468        { __int128 ret; ret = __atomic_fetch_or(vp16, v16, __ATOMIC_SEQ_CST); }
     469        { __int128 ret; ret = __atomic_fetch_or_16(vp16, v16, __ATOMIC_SEQ_CST); }
     470        #endif
     471
     472        { _Bool ret; ret = __atomic_always_lock_free(sizeof(int), vp4); }
     473        { _Bool ret; ret = __atomic_is_lock_free(sizeof(int), vp4); }
    352474        { __atomic_thread_fence(__ATOMIC_SEQ_CST); }
    353475        { __atomic_signal_fence(__ATOMIC_SEQ_CST); }
  • tests/concurrent/coroutineYield.cfa

    r7030dab r71d6bd8  
    3333                        sout | "Coroutine 2";
    3434                #endif
    35                 suspend;
     35                suspend();
    3636        }
    3737}
  • tests/concurrent/examples/.expect/datingService.txt

    r7030dab r71d6bd8  
     1Girl:17 is dating Boy at 2 with ccode 17
     2 Boy:2 is dating Girl 17 with ccode 17
     3 Boy:14 is dating Girl 5 with ccode 5
     4Girl:5 is dating Boy at 14 with ccode 5
     5 Boy:9 is dating Girl 10 with ccode 10
     6Girl:10 is dating Boy at 9 with ccode 10
     7 Boy:1 is dating Girl 18 with ccode 18
     8Girl:18 is dating Boy at 1 with ccode 18
     9 Boy:16 is dating Girl 3 with ccode 3
     10Girl:3 is dating Boy at 16 with ccode 3
     11 Boy:5 is dating Girl 14 with ccode 14
     12Girl:14 is dating Boy at 5 with ccode 14
     13 Boy:15 is dating Girl 4 with ccode 4
     14Girl:4 is dating Boy at 15 with ccode 4
     15Girl:0 is dating Boy at 19 with ccode 0
     16 Boy:19 is dating Girl 0 with ccode 0
     17Girl:9 is dating Boy at 10 with ccode 9
     18 Boy:10 is dating Girl 9 with ccode 9
     19Girl:11 is dating Boy at 8 with ccode 11
     20 Boy:8 is dating Girl 11 with ccode 11
     21 Boy:12 is dating Girl 7 with ccode 7
     22Girl:7 is dating Boy at 12 with ccode 7
     23 Boy:11 is dating Girl 8 with ccode 8
     24Girl:8 is dating Boy at 11 with ccode 8
     25Girl:16 is dating Boy at 3 with ccode 16
     26 Boy:3 is dating Girl 16 with ccode 16
     27Girl:15 is dating Boy at 4 with ccode 15
     28 Boy:4 is dating Girl 15 with ccode 15
     29Girl:19 is dating Boy at 0 with ccode 19
     30 Boy:0 is dating Girl 19 with ccode 19
     31Girl:2 is dating Boy at 17 with ccode 2
     32 Boy:17 is dating Girl 2 with ccode 2
     33 Boy:13 is dating Girl 6 with ccode 6
     34Girl:6 is dating Boy at 13 with ccode 6
     35 Boy:7 is dating Girl 12 with ccode 12
     36Girl:12 is dating Boy at 7 with ccode 12
     37Girl:13 is dating Boy at 6 with ccode 13
     38 Boy:6 is dating Girl 13 with ccode 13
     39Girl:1 is dating Boy at 18 with ccode 1
     40 Boy:18 is dating Girl 1 with ccode 1
  • tests/concurrent/examples/boundedBufferEXT.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 16 22:36:34 2020
    13 // Update Count     : 15
     12// Last Modified On : Fri Jun 21 08:19:20 2019
     13// Update Count     : 14
    1414//
    1515
     
    3737
    3838        void insert( Buffer(T) & mutex buffer, T elem ) with( buffer ) {
    39                 if ( count == BufferSize ) waitfor( remove : buffer );
     39                if ( count == BufferSize ) waitfor( remove, buffer );
    4040                elements[back] = elem;
    4141                back = ( back + 1 ) % BufferSize;
     
    4444
    4545        T remove( Buffer(T) & mutex buffer ) with( buffer ) {
    46                 if ( count == 0 ) waitfor( insert : buffer );
     46                if ( count == 0 ) waitfor( insert, buffer );
    4747                T elem = elements[front];
    4848                front = ( front + 1 ) % BufferSize;
  • tests/concurrent/examples/boundedBufferTHREAD.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 16 23:09:43 2020
    13 // Update Count     : 25
     12// Last Modified On : Fri Jun 21 11:50:12 2019
     13// Update Count     : 24
    1414//
    1515
     
    4444        void main( Buffer & buffer ) with( buffer ) {
    4545                for () {
    46                         waitfor( ^?{} : buffer ) {
     46                        waitfor( ^?{}, buffer ) {
    4747                                break;
    48                         } or when ( count != 20 ) waitfor( insert : buffer ) {
     48                        } or when ( count != 20 ) waitfor( insert, buffer ) {
    4949                                back = (back + 1) % 20;
    5050                                count += 1;
    51                         } or when ( count != 0 ) waitfor( remove : buffer ) {
     51                        } or when ( count != 0 ) waitfor( remove, buffer ) {
    5252                                front = (front + 1) % 20;
    5353                                count -= 1;
  • tests/concurrent/examples/datingService.cfa

    r7030dab r71d6bd8  
    11//
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    3 //
     3// 
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
     
    3535                signal_block( Boys[ccode] );                                    // restart boy to set phone number
    3636        } // if
    37         //sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;
     37        sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;
    3838        return BoyPhoneNo;
    3939} // DatingService girl
     
    4747                signal_block( Girls[ccode] );                                   // restart girl to set phone number
    4848        } // if
    49         //sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;
     49        sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;
    5050        return GirlPhoneNo;
    5151} // DatingService boy
  • tests/concurrent/examples/gortn.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Feb 20 08:02:37 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 16 22:43:40 2020
    13 // Update Count     : 5
     12// Last Modified On : Fri Jun 21 08:25:03 2019
     13// Update Count     : 4
    1414//
    1515
     
    2626void main( GoRtn & gortn ) with( gortn ) {
    2727        for () {
    28                 waitfor( mem1 : gortn ) sout | i;
    29                 or waitfor( mem2 : gortn ) sout | f;
    30                 or waitfor( mem3 : gortn ) sout | m.i | m.j;
    31                 or waitfor( ^?{} : gortn ) break;
     28                waitfor( mem1, gortn ) sout | i;
     29                or waitfor( mem2, gortn ) sout | f;
     30                or waitfor( mem3, gortn ) sout | m.i | m.j;
     31                or waitfor( ^?{}, gortn ) break;
    3232        }
    3333}
  • tests/concurrent/examples/quickSort.cfa

    r7030dab r71d6bd8  
    1111// Created On       : Wed Dec  6 12:15:52 2017
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Feb 12 18:24:47 2020
    14 // Update Count     : 177
     13// Last Modified On : Thu Oct 10 13:58:18 2019
     14// Update Count     : 176
    1515//
    1616
     
    2727
    2828void ?{}( Quicksort & qs, int values[], int size, int depth ) {
    29         qs.[values, low, high, depth] = [values, 0, size, depth];
     29        qs.values = values;  qs.low = 0;  qs.high = size;  qs.depth = depth;
    3030} // Quicksort
    3131
     
    167167                        values[counter] = size - counter;                       // descending values
    168168                } // for
    169                 for ( i; 200 ) {                                                                // random shuffle a few values
     169                for ( int i = 0; i < 200; i +=1 ) {                             // random shuffle a few values
    170170                        swap( values[rand() % size], values[rand() % size] );
    171171                } // for
  • tests/concurrent/multi-monitor.cfa

    r7030dab r71d6bd8  
    1111
    1212void increment( monitor_t & mutex p1, monitor_t & mutex p2, int & value ) {
    13         assert(active_thread() == get_monitor(p1)->owner);
    14         assert(active_thread() == get_monitor(p2)->owner);
    1513        value += 1;
    16         assert(active_thread() == get_monitor(p1)->owner);
    17         assert(active_thread() == get_monitor(p2)->owner);
    1814}
    1915
  • tests/concurrent/preempt.cfa

    r7030dab r71d6bd8  
    3636                if( (counter % 7) == this.value ) {
    3737                        __cfaabi_check_preemption();
    38                         int next = __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
     38                        int next = __atomic_add_fetch_4(&counter, 1, __ATOMIC_SEQ_CST);
    3939                        __cfaabi_check_preemption();
    4040                        if( (next % 100) == 0 ) printf("%d\n", (int)next);
  • tests/concurrent/signal/block.cfa

    r7030dab r71d6bd8  
    3333
    3434monitor global_data_t {
    35         $thread * last_thread;
    36         $thread * last_signaller;
     35        thread_desc * last_thread;
     36        thread_desc * last_signaller;
    3737};
    3838
     
    8282        if( !is_empty( cond ) ) {
    8383
    84                 $thread * next = front( cond );
     84                thread_desc * next = front( cond );
    8585
    8686                if( ! signal_block( cond ) ) {
  • tests/concurrent/signal/wait.cfa

    r7030dab r71d6bd8  
    9898        }
    9999
    100         __atomic_fetch_sub( &waiter_left, 1,  __ATOMIC_SEQ_CST );
     100        __sync_fetch_and_sub_4( &waiter_left, 1);
    101101}
    102102
     
    109109        }
    110110
    111         __atomic_fetch_sub( &waiter_left, 1,  __ATOMIC_SEQ_CST );
     111        __sync_fetch_and_sub_4( &waiter_left, 1);
    112112}
    113113
     
    120120        }
    121121
    122         __atomic_fetch_sub( &waiter_left, 1,  __ATOMIC_SEQ_CST );
     122        __sync_fetch_and_sub_4( &waiter_left, 1);
    123123}
    124124
     
    131131        }
    132132
    133         __atomic_fetch_sub( &waiter_left, 1,  __ATOMIC_SEQ_CST );
     133        __sync_fetch_and_sub_4( &waiter_left, 1);
    134134}
    135135
  • tests/concurrent/thread.cfa

    r7030dab r71d6bd8  
    77thread Second { semaphore* lock; };
    88
    9 void ?{}( First  & this, semaphore & lock ) { ((thread&)this){ "Thread 1" }; this.lock = &lock; }
    10 void ?{}( Second & this, semaphore & lock ) { ((thread&)this){ "Thread 2" }; this.lock = &lock; }
     9void ?{}( First  & this, semaphore & lock ) { ((thread&)this){"Thread 1"}; this.lock = &lock; }
     10void ?{}( Second & this, semaphore & lock ) { ((thread&)this){"Thread 2"}; this.lock = &lock; }
    1111
    1212void main(First& this) {
  • tests/concurrent/waitfor/barge.cfa

    r7030dab r71d6bd8  
    6565                yield(random( 10 ));
    6666                this.state = WAITFOR;
    67                 waitfor(do_call : this) {
     67                waitfor(do_call, this) {
    6868                        sout | i;
    6969                }
  • tests/concurrent/waitfor/dtor.cfa

    r7030dab r71d6bd8  
    4747        yield(random( 10 ));
    4848        set_state( this, MAIN );
    49         waitfor( ^?{} : this ) {
     49        waitfor( ^?{}, this ) {
    5050                set_state( this, AFTER );
    5151        }
  • tests/concurrent/waitfor/else.cfa

    r7030dab r71d6bd8  
    1414        sout | "Starting";
    1515
    16         when( false ) waitfor( notcalled : m );
     16        when( false ) waitfor( notcalled, m );
    1717
    1818        sout | "Step" | i++;
    1919
    20         waitfor( notcalled : m ); or else {
     20        waitfor( notcalled, m ); or else {
    2121                sout | "else called";
    2222        }
     
    2424        sout | "Step" | i++;
    2525
    26         when( true ) waitfor( notcalled : m ); or when( true ) else {
     26        when( true ) waitfor( notcalled, m ); or when( true ) else {
    2727                sout | "else called";
    2828        }
     
    3030        sout | "Step" | i++;
    3131
    32         when( false ) waitfor( notcalled : m ); or when( true ) else {
     32        when( false ) waitfor( notcalled, m ); or when( true ) else {
    3333                sout | "else called";
    3434        }
     
    3636        sout | "Step" | i++;
    3737
    38         when( false ) waitfor( notcalled : m ); or when( false ) else {
     38        when( false ) waitfor( notcalled, m ); or when( false ) else {
    3939                sout | "else called";
    4040        }
  • tests/concurrent/waitfor/parse.cfa

    r7030dab r71d6bd8  
    2424
    2525        //---------------------------------------
    26         waitfor( f1 : a ) {
     26        waitfor( f1, a ) {
    2727                1;
    2828        }
    2929
    3030        //---------------------------------------
    31         waitfor( f1 : a ) {
     31        waitfor( f1, a ) {
    3232                2;
    3333        }
    34         waitfor( f2 : a ) {
     34        waitfor( f2, a ) {
    3535                3;
    3636        }
    3737
    3838        //---------------------------------------
    39         when( 1 < 3 ) waitfor( f2 : a, a ) {
     39        when( 1 < 3 ) waitfor( f2, a, a ) {
    4040                4;
    4141        }
     
    4545
    4646        //---------------------------------------
    47         when( 2 < 3 ) waitfor( f3 : a ) {
     47        when( 2 < 3 ) waitfor( f3, a ) {
    4848                5;
    4949        }
     
    5353
    5454        //---------------------------------------
    55         when( 3 < 3 ) waitfor( f3 : a, a ) {
     55        when( 3 < 3 ) waitfor( f3, a, a ) {
    5656                7;
    5757        }
     
    6464
    6565        //---------------------------------------
    66         when( 6 < 3 ) waitfor( f3 : a, a, a ) {
     66        when( 6 < 3 ) waitfor( f3, a, a, a ) {
    6767                10;
    6868        }
    69         or when( 7 < 3 ) waitfor( f1 : a  ) {
     69        or when( 7 < 3 ) waitfor( f1, a  ) {
    7070                11;
    7171        }
     
    7575
    7676        //---------------------------------------
    77         when( 8 < 3 ) waitfor( f3 : a, a ) {
     77        when( 8 < 3 ) waitfor( f3, a, a ) {
    7878                13;
    7979        }
    80         or waitfor( f1 : a  ) {
     80        or waitfor( f1, a  ) {
    8181                14;
    8282        }
     
    8686
    8787        //---------------------------------------
    88         when( 10 < 3 ) waitfor( f1 : a ) {
     88        when( 10 < 3 ) waitfor( f1, a ) {
    8989                16;
    9090        }
    91         or waitfor( f2 : a, a ) {
     91        or waitfor( f2, a, a ) {
    9292                17;
    9393        }
     
    100100}
    101101
    102 int main() {}
     102int main() {
     103
     104}
  • tests/concurrent/waitfor/parse2.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Aug 30 17:53:29 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 16 23:13:37 2020
    13 // Update Count     : 6
     12// Last Modified On : Fri Mar 22 13:42:11 2019
     13// Update Count     : 3
    1414//
    1515
     
    2626        }
    2727
    28         waitfor( x : z ) {
     28        waitfor( x, z ) {
    2929        }
    3030
     
    3737        or waitfor( y );
    3838
    39         waitfor( x : z );
     39        waitfor( x, z );
    4040        or waitfor( y );
    4141
     
    4343        or when( true ) waitfor( y );
    4444
    45         when( true ) waitfor( x : z );
     45        when( true ) waitfor( x, z );
    4646        or when( true ) waitfor( y );
    4747
     
    5050        }
    5151
    52         waitfor( x : z ) {
     52        waitfor( x, z ) {
    5353        } or waitfor( y ) {
    5454        }
     
    8080        or else;
    8181
    82         when( true ) waitfor( x : z );
     82        when( true ) waitfor( x, z );
    8383        or else;
    8484
     
    9999        }
    100100
    101         when( true ) waitfor( x : z );
     101        when( true ) waitfor( x, z );
    102102        or else {
    103103        }
     
    115115        or when( true ) else;
    116116
    117         when( true ) waitfor( x : z );
     117        when( true ) waitfor( x, z );
    118118        or when( true ) else;
    119119
     
    134134        }
    135135
    136         when( true ) waitfor( x : z );
     136        when( true ) waitfor( x, z );
    137137        or when( true ) else {
    138138        }
     
    149149        or timeout( 3 );
    150150
    151         waitfor( x : z );
     151        waitfor( x, z );
    152152        or timeout( 3 );
    153153
     
    163163        }
    164164
    165         when( true ) waitfor( x : z ) {
     165        when( true ) waitfor( x, z ) {
    166166        } or timeout( 3 ) {
    167167        }
     
    171171        }
    172172
    173         when( true ) waitfor( x : z ) {
     173        when( true ) waitfor( x, z ) {
    174174        } or when ( true ) timeout( 3 ) {
    175175        }
     
    229229
    230230        int or, timeout;
    231         waitfor( timeout : 7 ) 3;
    232         waitfor( timeout : 7 ) 3; or waitfor( timeout : 7 ) 3;
    233         when( or ) waitfor( or : ) { 4; } or timeout( 1 ) 3;
    234         when( 3 ) waitfor( or : 2 ) 4; or else 4;
    235         when( 3 ) waitfor( or : 3 ) 4; or when( or ) timeout( or ) 4; or when( or ) else timeout;
    236         when( 3 ) waitfor( or : or ) 3; or when( or ) waitfor( or : timeout ) 4; or else 4;
    237         when( 3 ) waitfor( or : or ) 3; or waitfor( or : 9 ) 4; or when( or ) timeout( timeout ) 4;
    238         when( 3 ) waitfor( or : 3 ) 3; or waitfor( or : 7 ) or; or timeout( 1 ) or; or when( 3 ) else or;
     231        waitfor( timeout, 7 ) 3;
     232        waitfor( timeout, 7 ) 3; or waitfor( timeout, 7 ) 3;
     233        when( or ) waitfor( or, ) { 4; } or timeout( 1 ) 3;
     234        when( 3 ) waitfor( or, 2 ) 4; or else 4;
     235        when( 3 ) waitfor( or, 3 ) 4; or when( or ) timeout( or ) 4; or when( or ) else timeout;
     236        when( 3 ) waitfor( or, or ) 3; or when( or ) waitfor( or, timeout ) 4; or else 4;
     237        when( 3 ) waitfor( or, or ) 3; or waitfor( or, 9 ) 4; or when( or ) timeout( timeout ) 4;
     238        when( 3 ) waitfor( or, 3 ) 3; or waitfor( or, 7 ) or; or timeout( 1 ) or; or when( 3 ) else or;
    239239
    240240        // test else selection
  • tests/concurrent/waitfor/recurse.cfa

    r7030dab r71d6bd8  
    6666
    6767        rand_yield();
    68         waitfor( call4 : this );
     68        waitfor( call4, this );
    6969        rand_yield();
    7070
     
    7878
    7979        rand_yield();
    80         waitfor( call3 : this );
     80        waitfor( call3, this );
    8181        rand_yield();
    8282
     
    9292
    9393        rand_yield();
    94         waitfor( call2 : this );
     94        waitfor( call2, this );
    9595        rand_yield();
    9696
  • tests/concurrent/waitfor/statment.cfa

    r7030dab r71d6bd8  
    101101
    102102        while( !done ) {
    103                    waitfor( get_index : this );
    104                 or waitfor( call1 : this ) { sout | "Statement"; if( this.last_val != 1 ) { serr | "Incorrect index: expected" | 1 | "got" | this.last_val; } }
    105                 or waitfor( call2 : this ) { sout | "Statement"; if( this.last_val != 2 ) { serr | "Incorrect index: expected" | 2 | "got" | this.last_val; } }
    106                 or waitfor( call3 : this ) { sout | "Statement"; if( this.last_val != 3 ) { serr | "Incorrect index: expected" | 3 | "got" | this.last_val; } }
    107                 or waitfor( call4 : this ) { sout | "Statement"; if( this.last_val != 4 ) { serr | "Incorrect index: expected" | 4 | "got" | this.last_val; } }
    108                 or waitfor( call5 : this ) { sout | "Statement"; if( this.last_val != 5 ) { serr | "Incorrect index: expected" | 5 | "got" | this.last_val; } }
    109                 or waitfor( call6 : this ) { sout | "Statement"; if( this.last_val != 6 ) { serr | "Incorrect index: expected" | 6 | "got" | this.last_val; } }
    110                 or waitfor( call7 : this ) { sout | "Statement"; if( this.last_val != 7 ) { serr | "Incorrect index: expected" | 7 | "got" | this.last_val; } }
     103                   waitfor( get_index, this );
     104                or waitfor( call1, this ) { sout | "Statement"; if( this.last_val != 1 ) { serr | "Incorrect index: expected" | 1 | "got" | this.last_val; } }
     105                or waitfor( call2, this ) { sout | "Statement"; if( this.last_val != 2 ) { serr | "Incorrect index: expected" | 2 | "got" | this.last_val; } }
     106                or waitfor( call3, this ) { sout | "Statement"; if( this.last_val != 3 ) { serr | "Incorrect index: expected" | 3 | "got" | this.last_val; } }
     107                or waitfor( call4, this ) { sout | "Statement"; if( this.last_val != 4 ) { serr | "Incorrect index: expected" | 4 | "got" | this.last_val; } }
     108                or waitfor( call5, this ) { sout | "Statement"; if( this.last_val != 5 ) { serr | "Incorrect index: expected" | 5 | "got" | this.last_val; } }
     109                or waitfor( call6, this ) { sout | "Statement"; if( this.last_val != 6 ) { serr | "Incorrect index: expected" | 6 | "got" | this.last_val; } }
     110                or waitfor( call7, this ) { sout | "Statement"; if( this.last_val != 7 ) { serr | "Incorrect index: expected" | 7 | "got" | this.last_val; } }
    111111
    112112                done = true;
  • tests/concurrent/waitfor/when.cfa

    r7030dab r71d6bd8  
    5858void arbiter( global_t & mutex this ) {
    5959        for( int i = 0; i < N; i++ ) {
    60                    when( this.last_call == 6 ) waitfor( call1 : this ) { if( this.last_call != 1) { serr | "Expected last_call to be 1 got" | this.last_call; } }
    61                 or when( this.last_call == 1 ) waitfor( call2 : this ) { if( this.last_call != 2) { serr | "Expected last_call to be 2 got" | this.last_call; } }
    62                 or when( this.last_call == 2 ) waitfor( call3 : this ) { if( this.last_call != 3) { serr | "Expected last_call to be 3 got" | this.last_call; } }
    63                 or when( this.last_call == 3 ) waitfor( call4 : this ) { if( this.last_call != 4) { serr | "Expected last_call to be 4 got" | this.last_call; } }
    64                 or when( this.last_call == 4 ) waitfor( call5 : this ) { if( this.last_call != 5) { serr | "Expected last_call to be 5 got" | this.last_call; } }
    65                 or when( this.last_call == 5 ) waitfor( call6 : this ) { if( this.last_call != 6) { serr | "Expected last_call to be 6 got" | this.last_call; } }
     60                   when( this.last_call == 6 ) waitfor( call1, this ) { if( this.last_call != 1) { serr | "Expected last_call to be 1 got" | this.last_call; } }
     61                or when( this.last_call == 1 ) waitfor( call2, this ) { if( this.last_call != 2) { serr | "Expected last_call to be 2 got" | this.last_call; } }
     62                or when( this.last_call == 2 ) waitfor( call3, this ) { if( this.last_call != 3) { serr | "Expected last_call to be 3 got" | this.last_call; } }
     63                or when( this.last_call == 3 ) waitfor( call4, this ) { if( this.last_call != 4) { serr | "Expected last_call to be 4 got" | this.last_call; } }
     64                or when( this.last_call == 4 ) waitfor( call5, this ) { if( this.last_call != 5) { serr | "Expected last_call to be 5 got" | this.last_call; } }
     65                or when( this.last_call == 5 ) waitfor( call6, this ) { if( this.last_call != 6) { serr | "Expected last_call to be 6 got" | this.last_call; } }
    6666
    6767                sout | this.last_call;
  • tests/coroutine/.expect/fmtLines.txt

    r7030dab r71d6bd8  
    4848{                                                         // f  or n  ewli 
    4949ne c  hara  cter  s                                     su 
    50 spen  d;                                        i  f (   fmt. 
    51 ch !  = '\  n' )   bre  ak;      
    52         //   igno  re n  ewli  ne                
    53                 }   // f  or                            so  ut | 
    54  fmt  .ch;                                                      /  / pr 
    55 int   char  acte  r                       } // 
    56  for                    s  out   | "    ";       
    57                                                         /  / pr  int   bloc 
    58 k se  para  tor         } /  / fo 
    59 r               s  out   | nl  ;                                                         
    60                 //   pri  nt g  roup   sep 
    61 arat  or        }   //   for}   //  
    62 main  void   prt  ( Fo  rmat 
    63  & f  mt,   char   ch   ) {   
    64    f  mt.c  h =   ch;      r 
    65 esum  e( f  mt )  ;} /  / pr 
    66 tint   mai  n()   {     Fo  rmat 
    67  fmt  ; ch  ar c  h;    f  or ( 
    68  ;;   ) {               sin   | c  h;            
    69                                                                   // r  ead   one  
    70 char  acte  r       if (   eof 
    71 ( si  n )   ) br  eak;                                   
    72                         /  / eo  f ?            prt  ( fm 
    73 t, c  h );      } /  / fo  r} / 
    74 / ma  in//   Loc  al V  aria 
    75 bles  : //  // t  ab-w  idth 
    76 : 4   ////   com  pile  -com 
    77 mand  : "c  fa f  mtLi  nes. 
    78 cfa"   ///  / En  d: /  /
     50spen  d();                                      if   ( fm 
     51t.ch   !=   '\n'   ) b  reak 
     52;               /  / ig  nore   new  line 
     53                                  } //   for                              sout 
     54 | f  mt.c  h;                                                  //  
     55prin  t ch  arac  ter                   }  
     56// f  or                        sou  t |   "  " 
     57;                                                               //   prin  t bl 
     58ock   sepa  rato  r             }   //  
     59for             sou  t |   nl;                                   
     60                                  // p  rint   gro  up s 
     61epar  ator      } /  / fo  r} / 
     62/ ma  invo  id p  rt(   Form 
     63at &   fmt  , ch  ar c  h )   
     64{      fmt  .ch   = ch  ;    
     65 res  ume(   fmt   );}   //  
     66prti  nt m  ain(  ) {     Form 
     67at f  mt;         char   ch;    for 
     68 ( ;  ; )   {           s  in |   ch; 
     69                                                                                //   rea  d on 
     70e ch  arac  ter     if   ( e 
     71of(   sin   ) )   brea  k;               
     72                                        //   eof   ?            p  rt(  
     73fmt,   ch   );  }   //   for} 
     74 //   main  // L  ocal   Var 
     75iabl  es:   ////   tab  -wid 
     76th:   4 //  // c  ompi  le-c 
     77omma  nd:   "cfa   fmt  Line 
     78s.cf  a" /  ///   End:   //
  • tests/coroutine/.in/fmtLines.txt

    r7030dab r71d6bd8  
    3535                        for ( fmt.b = 0; fmt.b < 4; fmt.b += 1 ) {      // blocks of 4 characters
    3636                                for ( ;; ) {                                                    // for newline characters
    37                                         suspend;
     37                                        suspend();
    3838                                        if ( fmt.ch != '\n' ) break;            // ignore newline
    3939                                } // for
  • tests/coroutine/cntparens.cfa

    r7030dab r71d6bd8  
    1 //
     1// 
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 //
     6// 
    77// cntparens.cfa -- match left/right parenthesis
    8 //
     8// 
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Apr 20 11:04:45 2019
     
    1212// Last Modified On : Sat Apr 20 11:06:21 2019
    1313// Update Count     : 1
    14 //
     14// 
    1515
    1616#include <fstream.hfa>
     
    2626void main( CntParens & cpns ) with( cpns ) {
    2727        for ( ; ch == '('; cnt += 1 ) {                                         // left parenthesis
    28                 suspend;
     28                suspend();
    2929        }
    3030        for ( ; ch == ')' && cnt > 1; cnt -= 1 ) {                      // right parenthesis
    31                 suspend;
     31                suspend();
    3232        }
    3333        status = ch == ')' ? Match : Error;
    3434} // main
    35 
     35       
    3636void ?{}( CntParens & cpns ) with( cpns ) { status = Cont; cnt = 0; }
    3737
  • tests/coroutine/devicedriver.cfa

    r7030dab r71d6bd8  
    1 //
     1// 
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 //
    7 // devicedriver.cfa --
    8 //
     6// 
     7// devicedriver.cfa -- 
     8// 
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Mar 16 15:30:34 2019
     
    1212// Last Modified On : Sat Apr 20 09:07:19 2019
    1313// Update Count     : 90
    14 //
     14// 
    1515
    1616#include <fstream.hfa>
     
    2929
    3030void checkCRC( Driver & d, unsigned int sum ) with( d ) {
    31         suspend;
     31        suspend();
    3232        unsigned short int crc = byte << 8;                                     // sign extension over written
    33         suspend;
     33        suspend();
    3434        // prevent sign extension for signed char
    3535        status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
     
    4141                status = CONT;
    4242                unsigned int lnth = 0, sum = 0;
    43                 while ( byte != STX ) suspend;
     43                while ( byte != STX ) suspend();
    4444          emsg: for () {
    45                         suspend;
     45                        suspend();
    4646                        choose ( byte ) {                                                       // process byte
    4747                          case STX:
    48                                 status = ESTX; suspend; continue msg;
     48                                status = ESTX; suspend(); continue msg;
    4949                          case ETX:
    5050                                break emsg;
    5151                          case ESC:
    52                                 suspend;
     52                                suspend();
    5353                        } // choose
    5454                        if ( lnth >= MaxMsg ) {                                         // buffer full ?
    55                                 status = ELNTH; suspend; continue msg;
     55                                status = ELNTH; suspend(); continue msg;
    5656                        } // if
    5757                        msg[lnth++] = byte;
     
    6060                msg[lnth] = '\0';                                                               // terminate string
    6161                checkCRC( d, sum );                                                             // refactor CRC check
    62                 suspend;
     62                suspend();
    6363        } // for
    6464} // main
  • tests/coroutine/fibonacci.cfa

    r7030dab r71d6bd8  
    2222        int fn1, fn2;                                                                           // retained between resumes
    2323        fn = 0;  fn1 = fn;                                                                      // 1st case
    24         suspend;                                                                                        // restart last resume
     24        suspend();                                                                                      // restart last resume
    2525        fn = 1;  fn2 = fn1;  fn1 = fn;                                          // 2nd case
    26         suspend;                                                                                        // restart last resume
     26        suspend();                                                                                      // restart last resume
    2727        for () {
    2828                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    29                 suspend;                                                                                // restart last resume
     29                suspend();                                                                              // restart last resume
    3030        } // for
    3131}
  • tests/coroutine/fibonacci_1.cfa

    r7030dab r71d6bd8  
    1212// Last Modified On : Thu Mar 21 08:10:45 2019
    1313// Update Count     : 25
    14 //
     14// 
    1515
    1616#include <fstream.hfa>
     
    2323        [fn1, fn] = [0, 1];                                                                     // precompute first two states
    2424        for () {
    25                 suspend;                                                                                // restart last resume
     25                suspend();                                                                              // restart last resume
    2626                [fn1, fn] = [fn, fn1 + fn];                                             // general case
    2727        } // for
  • tests/coroutine/fmtLines.cfa

    r7030dab r71d6bd8  
    2727                        for ( b = 0; b < 4; b += 1 ) {                          // blocks of 4 characters
    2828                                for () {                                                                // for newline characters
    29                                         suspend;
     29                                        suspend();
    3030                                  if ( ch != '\n' ) break;                              // ignore newline
    3131                                } // for
  • tests/coroutine/raii.cfa

    r7030dab r71d6bd8  
    3939        Raii raii = { "Coroutine" };
    4040        sout | "Before Suspend";
    41         suspend;
     41        suspend();
    4242        sout | "After Suspend";
    4343}
  • tests/coroutine/runningTotal.cfa

    r7030dab r71d6bd8  
    2525void update( RunTotal & rntl, int input ) with( rntl ) { // helper
    2626        total += input;                                                                         // remember between activations
    27         suspend;                                                                                        // inactivate on stack
     27        suspend();                                                                                      // inactivate on stack
    2828}
    2929
  • tests/coroutine/suspend_then.cfa

    r7030dab r71d6bd8  
    1515
    1616#include <fstream.hfa>
     17#include <coroutine.hfa>
    1718
    18 generator Fibonacci {
    19         int fn;                                                                         // used for communication
    20         int fn1, fn2;                                                           // retained between resumes
    21 };
     19void then() {
     20        sout | "Then!";
     21}
     22
     23coroutine Fibonacci { int fn; };                                                // used for communication
    2224
    2325void main( Fibonacci & fib ) with( fib ) {                              // called on first resume
     26        int fn1, fn2;                                                           // retained between resumes
    2427        fn = 0;  fn1 = fn;                                                      // 1st case
    25         suspend { sout | "Then!"; }                                             // restart last resume
     28        suspend_then(then);                                                     // restart last resume
    2629        fn = 1;  fn2 = fn1;  fn1 = fn;                                  // 2nd case
    27         suspend { sout | "Then!"; }                                             // restart last resume
     30        suspend_then(then);                                                     // restart last resume
    2831        for () {
    2932                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    30                 suspend { sout | "Then!"; }                                     // restart last resume
     33                suspend_then(then);                                             // restart last resume
    3134        } // for
    3235}
  • tests/expression.cfa

    r7030dab r71d6bd8  
    1 struct S { int i; };
    2 void ?{}( S & s, int i ) { s.i = i; }
    3 int ?`mary( int );
    4 int ?`mary( S );
    5 [int] ?`mary( [int, int] );
    6 int & ?`jane( int & );
    7 int jack( int );
    8 
    91int main() {
    10     int a[3] = { 0, 0, 0 };
    11     S s = { 3 }, * ps = &s;
    12     [int] t = { 3 };
    13     * [int] pt = &t;
    14     int i = 1, j = 2;
     2    struct s { int i; } x, *p = &x;
     3    int i = 3;
    154
    165    // operators
    176
    18     !i;
     7    ! i;
    198    ~i;
    209    +i;
    2110    -i;
    22     *ps;
    23     ++ps;
    24     --ps;
    25     ps++;
    26     ps--;
     11    *p;
     12    ++p;
     13    --p;
     14    p++;
     15    p--;
    2716
    28     i + j;
    29     i - j;
    30     i * j;
     17    i+i;
     18    i-i;
     19    i*i;
    3120
    32     i / j;
    33     i % j;
    34     i ^ j;
    35     i & j;
    36     i | j;
    37     i < j;
    38     i > j;
    39     i = j;
     21    i/i;
     22    i%i;
     23    i^i;
     24    i&i;
     25    i|i;
     26    i<i;
     27    i>i;
     28    i=i;
    4029
    41     i == j;
    42     i != j;
    43     i << j;
    44     i >> j;
    45     i <= j;
    46     i >= j;
    47     i && j;
    48     i || j;
    49     ps->i;
     30    i==i;
     31    i!=i;
     32    i<<i;
     33    i>>i;
     34    i<=i;
     35    i>=i;
     36    i&&i;
     37    i||i;
     38    p->i;
     39    i*=i;
     40    i/=i;
     41    i%=i;
     42    i+=i;
     43    i-=i;
     44    i&=i;
     45    i|=i;
     46    i^=i;
     47    i<<=i;
     48    i>>=i;
    5049
    51     i *= j;
    52     i /= j;
    53     i %= j;
    54     i += j;
    55     i -= j;
    56     i &= j;
    57     i |= j;
    58     i ^= j;
    59     i <<= j;
    60     i >>= j;
    61 
    62     i ? i : j;
    63 
    64     // postfix function call
    65 
    66     (3 + 4)`mary;
    67     ({3 + 4;})`mary;
    68     [3, 4]`mary;
    69     3`mary;
    70     a[0]`mary;
    71     a[0]`mary`mary;
    72     s{0}`mary;
    73     a[3]`jane++;
    74     jack(3)`mary;
    75     s.i`mary;
    76     t.0`mary;
    77     s.[i]`mary;
    78     ps->i`mary;
    79     pt->0`mary;
    80     ps->[i]`mary;
    81     i++`mary;
    82     i--`mary;
    83     (S){2}`mary;
    84     (S)@{2}`mary;
     50    i?i:i;
    8551} // main
  • tests/heap.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Nov  6 17:54:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Nov 24 12:34:51 2019
    13 // Update Count     : 28
     12// Last Modified On : Fri Jul 19 08:22:34 2019
     13// Update Count     : 19
    1414//
    1515
     
    3838        enum { NoOfAllocs = 5000, NoOfMmaps = 10 };
    3939        char * locns[NoOfAllocs];
    40         size_t amount;
    41         enum { limit = 64 * 1024 };                                                     // check alignments up to here
     40        int i;
    4241
    4342        // check alloc/free
     
    7574                size_t s = (i + 1) * 20;
    7675                char * area = (char *)malloc( s );
    77                 if ( area == 0p ) abort( "malloc/free out of memory" );
     76                if ( area == 0 ) abort( "malloc/free out of memory" );
    7877                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
    7978                area[malloc_usable_size( area ) - 1] = '\345';  // fill ultimate byte
     
    8483                size_t s = i + 1;                                                               // +1 to make initialization simpler
    8584                locns[i] = (char *)malloc( s );
    86                 if ( locns[i] == 0p ) abort( "malloc/free out of memory" );
     85                if ( locns[i] == 0 ) abort( "malloc/free out of memory" );
    8786                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
    8887                locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
     
    10099                size_t s = i + default_mmap_start();                    // cross over point
    101100                char * area = (char *)malloc( s );
    102                 if ( area == 0p ) abort( "malloc/free out of memory" );
     101                if ( area == 0 ) abort( "malloc/free out of memory" );
    103102                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
    104103                area[malloc_usable_size( area ) - 1] = '\345';  // fill ultimate byte
     
    109108                size_t s = i + default_mmap_start();                    // cross over point
    110109                locns[i] = (char *)malloc( s );
    111                 if ( locns[i] == 0p ) abort( "malloc/free out of memory" );
     110                if ( locns[i] == 0 ) abort( "malloc/free out of memory" );
    112111                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
    113112                locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
     
    125124                size_t s = (i + 1) * 20;
    126125                char * area = (char *)calloc( 5, s );
    127                 if ( area == 0p ) abort( "calloc/free out of memory" );
     126                if ( area == 0 ) abort( "calloc/free out of memory" );
    128127                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    129128                         area[malloc_usable_size( area ) - 1] != '\0' ||
     
    137136                size_t s = i + 1;
    138137                locns[i] = (char *)calloc( 5, s );
    139                 if ( locns[i] == 0p ) abort( "calloc/free out of memory" );
     138                if ( locns[i] == 0 ) abort( "calloc/free out of memory" );
    140139                if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
    141140                         locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
     
    156155                size_t s = i + default_mmap_start();                    // cross over point
    157156                char * area = (char *)calloc( 1, s );
    158                 if ( area == 0p ) abort( "calloc/free out of memory" );
     157                if ( area == 0 ) abort( "calloc/free out of memory" );
    159158                if ( area[0] != '\0' || area[s - 1] != '\0' ) abort( "calloc/free corrupt storage4.1" );
    160159                if ( area[malloc_usable_size( area ) - 1] != '\0' ) abort( "calloc/free corrupt storage4.2" );
     
    168167                size_t s = i + default_mmap_start();                    // cross over point
    169168                locns[i] = (char *)calloc( 1, s );
    170                 if ( locns[i] == 0p ) abort( "calloc/free out of memory" );
     169                if ( locns[i] == 0 ) abort( "calloc/free out of memory" );
    171170                if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
    172171                         locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
     
    184183        // check memalign/free (sbrk)
    185184
     185        enum { limit = 64 * 1024 };                                                     // check alignments up to here
     186
    186187        for ( a; libAlign() ~= limit ~ a ) {                            // generate powers of 2
    187188                //sout | alignments[a];
    188189                for ( s; 1 ~ NoOfAllocs ) {                                             // allocation of size 0 can return null
    189190                        char * area = (char *)memalign( a, s );
    190                         if ( area == 0p ) abort( "memalign/free out of memory" );
    191                         //sout | i | area;
     191                        if ( area == 0 ) abort( "memalign/free out of memory" );
     192                        //sout | i | " " | area;
    192193                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    193194                                abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, s, area );
    194195                        } // if
    195                         area[0] = '\345'; area[s - 1] = '\345';         // fill first/last byte
     196                        area[0] = '\345'; area[s - 1] = '\345'; // fill first/last byte
    196197                        area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte
    197198                        free( area );
     
    206207                        size_t s = i + default_mmap_start();            // cross over point
    207208                        char * area = (char *)memalign( a, s );
    208                         if ( area == 0p ) abort( "memalign/free out of memory" );
    209                         //sout | i | area;
     209                        if ( area == 0 ) abort( "memalign/free out of memory" );
     210                        //sout | i | " " | area;
    210211                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    211212                                abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)s, area );
     
    222223                // initial N byte allocation
    223224                char * area = (char *)calloc( 5, i );
    224                 if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
     225                if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
    225226                if ( area[0] != '\0' || area[i - 1] != '\0' ||
    226227                         area[malloc_usable_size( area ) - 1] != '\0' ||
     
    230231                for ( s; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    231232                        area = (char *)realloc( area, s );                      // attempt to reuse storage
    232                         if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
     233                        if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
    233234                        if ( area[0] != '\0' || area[s - 1] != '\0' ||
    234235                                 area[malloc_usable_size( area ) - 1] != '\0' ||
     
    244245                size_t s = i + default_mmap_start();                    // cross over point
    245246                char * area = (char *)calloc( 1, s );
    246                 if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
     247                if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
    247248                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    248249                         area[malloc_usable_size( area ) - 1] != '\0' ||
     
    252253                for ( r; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    253254                        area = (char *)realloc( area, r );                      // attempt to reuse storage
    254                         if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
     255                        if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
    255256                        if ( area[0] != '\0' || area[r - 1] != '\0' ||
    256257                                 area[malloc_usable_size( area ) - 1] != '\0' ||
     
    262263        // check memalign/realloc/free
    263264
    264         amount = 2;
     265        size_t amount = 2;
    265266        for ( a; libAlign() ~= limit ~ a ) {                            // generate powers of 2
    266267                // initial N byte allocation
    267268                char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
    268                 if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    269                 //sout | alignments[a] | area;
     269                if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ?
     270                //sout | alignments[a] | " " | area;
    270271                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    271272                        abort( "memalign/realloc/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area );
     
    277278                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );
    278279                        area = (char *)realloc( area, s );                      // attempt to reuse storage
    279                         if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    280                         //sout | i | area;
     280                        if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ?
     281                        //sout | i | " " | area;
    281282                        if ( (size_t)area % a != 0 ) {                          // check for initial alignment
    282283                                abort( "memalign/realloc/free bad alignment %p", area );
     
    293294                for ( s; 1 ~ limit ) {                                                  // allocation of size 0 can return null
    294295                        char * area = (char *)cmemalign( a, 1, s );
    295                         if ( area == 0p ) abort( "cmemalign/free out of memory" );
    296                         //sout | i | area;
     296                        if ( area == 0 ) abort( "cmemalign/free out of memory" );
     297                        //sout | i | " " | area;
    297298                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    298299                                abort( "cmemalign/free bad alignment : cmemalign(%d,%d) = %p", (int)a, s, area );
     
    312313                // initial N byte allocation
    313314                char * area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation
    314                 if ( area == 0p ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
    315                 //sout | alignments[a] | area;
     315                if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
     316                //sout | alignments[a] | " " | area;
    316317                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    317318                        abort( "cmemalign/realloc/free bad alignment : cmemalign(%d,%d) = %p", (int)a, (int)amount, area );
     
    326327                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc/free corrupt storage2" );
    327328                        area = (char *)realloc( area, s );                      // attempt to reuse storage
    328                         if ( area == 0p ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
    329                         //sout | i | area;
     329                        if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
     330                        //sout | i | " " | area;
    330331                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    331332                                abort( "cmemalign/realloc/free bad alignment %p", area );
     
    338339                free( area );
    339340        } // for
    340 
    341         // check memalign/realloc with align/free
    342 
    343         amount = 2;
    344         for ( a; libAlign() ~= limit ~ a ) {                            // generate powers of 2
    345                 // initial N byte allocation
    346                 char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
    347                 if ( area == 0p ) abort( "memalign/realloc with align/free out of memory" ); // no storage ?
    348                 //sout | alignments[a] | area | endl;
    349                 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    350                         abort( "memalign/realloc with align/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area );
    351                 } // if
    352                 area[0] = '\345'; area[amount - 2] = '\345';    // fill first/penultimate byte
    353 
    354                 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    355                 for ( s; amount ~ 256 * 1024 ) {                                // start at initial memory request
    356                         if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );
    357                         area = (char *)realloc( area, a * 2, s );       // attempt to reuse storage
    358                         if ( area == 0p ) abort( "memalign/realloc with align/free out of memory" ); // no storage ?
    359                         //sout | i | area | endl;
    360                         if ( (size_t)area % a * 2 != 0 ) {                      // check for initial alignment
    361                                 abort( "memalign/realloc with align/free bad alignment %p", area );
    362                         } // if
    363                         area[s - 1] = '\345';                                           // fill last byte
    364                 } // for
    365                 free( area );
    366         } // for
    367 
    368         // check cmemalign/realloc with align/free
    369 
    370         amount = 2;
    371         for ( size_t a = libAlign() + libAlign(); a <= limit; a += a ) { // generate powers of 2
    372                 // initial N byte allocation
    373                 char *area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation
    374                 if ( area == 0p ) abort( "cmemalign/realloc with align/free out of memory" ); // no storage ?
    375                 //sout | alignments[a] | area | endl;
    376                 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    377                         abort( "cmemalign/realloc with align/free bad alignment : cmemalign(%d,%d) = %p", (int)a, (int)amount, area );
    378                 } // if
    379                 if ( area[0] != '\0' || area[amount - 1] != '\0' ||
    380                          area[malloc_usable_size( area ) - 1] != '\0' ||
    381                          ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc with align/free corrupt storage1" );
    382                 area[0] = '\345'; area[amount - 2] = '\345';    // fill first/penultimate byte
    383 
    384                 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    385                 for ( int s = amount; s < 256 * 1024; s += 1 ) { // start at initial memory request
    386                         if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc with align/free corrupt storage2" );
    387                         area = (char *)realloc( area, a * 2, s );       // attempt to reuse storage
    388                         if ( area == 0p ) abort( "cmemalign/realloc with align/free out of memory" ); // no storage ?
    389                         //sout | i | area | endl;
    390                         if ( (size_t)area % a * 2 != 0 || malloc_alignment( area ) != a * 2 ) { // check for initial alignment
    391                                 abort( "cmemalign/realloc with align/free bad alignment %p %jd %jd", area, malloc_alignment( area ), a * 2 );
    392                         } // if
    393                         if ( area[s - 1] != '\0' || area[s - 1] != '\0' ||
    394                                  area[malloc_usable_size( area ) - 1] != '\0' ||
    395                                  ! malloc_zero_fill( area ) ) abort( "cmemalign/realloc/free corrupt storage3" );
    396                         area[s - 1] = '\345';                                           // fill last byte
    397                 } // for
    398                 free( area );
    399         } // for
    400 
    401341        //sout | "worker" | thisTask() | "successful completion";
    402342} // Worker main
  • tests/labelledExit.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Aug 10 07:29:39 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  5 16:49:48 2020
    13 // Update Count     : 9
     12// Last Modified On : Fri Oct 25 17:41:51 2019
     13// Update Count     : 7
    1414//
    1515
     
    162162
    163163        // computed goto
    164         {
    165                 void *array[] = { &&foo, &&bar, &&hack };
    166           foo: bar: hack:
    167                 &&foo;
    168                 &&bar;
    169                 goto *array[i];
    170         }
     164        // {
     165        //      void *array[] = { &&foo, &&bar, &&hack };
     166        //   foo: bar: hack:
     167        //      &&foo;
     168        //      &&bar;
     169        //      goto *array[i];
     170        // }
    171171
    172172  Q: if ( i > 5 ) {
  • tests/linking/withthreads.cfa

    r7030dab r71d6bd8  
    3434// Local Variables: //
    3535// tab-width: 4 //
    36 // compile-command: "cfa withthreads.cfa" //
     36// compile-command: "cfa nothreads.cfa" //
    3737// End: //
  • tests/loopctrl.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed Aug  8 18:32:59 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Dec 12 17:55:26 2019
    13 // Update Count     : 108
     12// Last Modified On : Fri Jul 12 12:05:05 2019
     13// Update Count     : 106
    1414//
    1515
     
    4343        for ( 1 ) { sout | "A"; }                                                       sout | nl;
    4444        for ( 10 ) { sout | "A"; }                                                      sout | nl;
    45         for ( = 10 ) { sout | "A"; }                                            sout | nl;
    4645        for ( 1 ~= 10 ~ 2 ) { sout | "B"; }                                     sout | nl;
    4746        for ( 10 -~= 1 ~ 2 ) { sout | "C"; }                            sout | nl;
     
    5049
    5150        for ( i; 10 ) { sout | i; }                                                     sout | nl;
    52         for ( i; = 10 ) { sout | i; }                                           sout | nl;
    5351        for ( i; 1 ~= 10 ~ 2 ) { sout | i; }                            sout | nl;
    5452        for ( i; 10 -~= 1 ~ 2 ) { sout | i; }                           sout | nl;
     
    8987        for ( N ) { sout | "N"; }                                                       sout | nl;
    9088        for ( i; N ) { sout | i; }                                                      sout | nl;
    91         for ( i; = N ) { sout | i; }                                            sout | nl;
    9289        for ( i; N -~ 0 ) { sout | i; }                                         sout | nl | nl;
    9390
  • tests/nested-types.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Jul 9 10:20:03 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 12 18:21:15 2020
    13 // Update Count     : 3
     12// Last Modified On : Tue Nov  6 17:59:40 2018
     13// Update Count     : 2
    1414//
    1515
     
    5050//   double d;
    5151// };
    52 
    53 // struct S {
    54 //     enum C { R, G, B };
    55 //     int i;
    56 //     struct T {
    57 //      int i;
    58 //     };
    59 //     T t;
    60 // };
    61 
    62 // S s;
    63 // S.C c;
    64 // S.T t;
    6552
    6653int main() {
  • tests/pybin/settings.py

    r7030dab r71d6bd8  
    7777                        print("updated to %s" % self.target)
    7878
    79         def filter(self, tests):
    80                 return [test for test in tests if not test.arch or self.target == test.arch]
     79        def match(self, arch):
    8180                return True if not arch else self.target == arch
    8281
     
    114113
    115114def init( options ):
    116         global all_arch
    117         global all_debug
    118         global all_install
    119115        global arch
    120116        global archive
    121         global continue_
    122117        global debug
     118        global distcc
    123119        global dry_run
    124120        global generating
     
    127123        global output_width
    128124        global timeout
    129         global timeout2gdb
    130125
    131         all_arch     = [Architecture(o) for o in list(dict.fromkeys(options.arch   ))]
    132         all_debug    = [Debug(o)        for o in list(dict.fromkeys(options.debug  ))]
    133         all_install  = [Install(o)      for o in list(dict.fromkeys(options.install))]
     126        arch         = Architecture(options.arch)
    134127        archive      = os.path.abspath(os.path.join(original_path, options.archive_errors)) if options.archive_errors else None
    135         continue_    = options.continue_
     128        debug        = Debug(options.debug)
    136129        dry_run      = options.dry_run # must be called before tools.config_hash()
     130        distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
    137131        generating   = options.regenerate_expected
     132        install      = Install(options.install)
    138133        make         = ['make']
    139134        output_width = 24
    140135        timeout      = Timeouts(options.timeout, options.global_timeout)
    141         timeout2gdb  = options.timeout_with_gdb
    142136
    143137        # if we distribute, distcc errors will fail tests, use log file for distcc
     
    152146
    153147def validate():
    154         """Validate the current configuration and update globals"""
    155 
    156         global distcc
    157         distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
    158148        errf = os.path.join(BUILDDIR, ".validate.err")
    159149        make_ret, out = tools.make( ".validate", error_file = errf, output_file=subprocess.DEVNULL, error=subprocess.DEVNULL )
  • tests/pybin/tools.py

    r7030dab r71d6bd8  
    7575                                        return proc.returncode, out.decode("utf-8") if out else None
    7676                                except subprocess.TimeoutExpired:
    77                                         if settings.timeout2gdb:
    78                                                 print("Process {} timeout".format(proc.pid))
    79                                                 proc.communicate()
    80                                                 return 124, str(None)
    81                                         else:
    82                                                 proc.send_signal(signal.SIGABRT)
    83                                                 proc.communicate()
    84                                                 return 124, str(None)
     77                                        proc.send_signal(signal.SIGABRT)
     78                                        proc.communicate()
     79                                        return 124, str(None)
    8580
    8681        except Exception as ex:
     
    180175
    181176def which(program):
    182         fpath, fname = os.path.split(program)
    183         if fpath:
    184                 if is_exe(program):
    185                         return program
    186         else:
    187                 for path in os.environ["PATH"].split(os.pathsep):
    188                         exe_file = os.path.join(path, program)
    189                         if is_exe(exe_file):
    190                                 return exe_file
    191         return None
     177    fpath, fname = os.path.split(program)
     178    if fpath:
     179        if is_exe(program):
     180            return program
     181    else:
     182        for path in os.environ["PATH"].split(os.pathsep):
     183            exe_file = os.path.join(path, program)
     184            if is_exe(exe_file):
     185                return exe_file
     186
     187    return None
    192188
    193189@contextlib.contextmanager
     
    327323        raise argparse.ArgumentTypeError(msg)
    328324
    329 # Convert a function that converts a string to one that converts comma separated string.
    330 def comma_separated(elements):
    331     return lambda string: [elements(part) for part in string.split(',')]
    332 
    333325def fancy_print(text):
    334326        column = which('column')
     
    373365
    374366class Timed:
    375         def __enter__(self):
    376                 self.start = time.time()
    377                 return self
    378 
    379         def __exit__(self, *args):
    380                 self.end = time.time()
    381                 self.duration = self.end - self.start
     367    def __enter__(self):
     368        self.start = time.time()
     369        return self
     370
     371    def __exit__(self, *args):
     372        self.end = time.time()
     373        self.duration = self.end - self.start
    382374
    383375def timed(src, timeout):
    384376        expire = time.time() + timeout
    385377        i = iter(src)
    386         with contextlib.suppress(StopIteration):
    387                 while True:
    388                         yield i.next(max(expire - time.time(), 0))
     378        while True:
     379                yield i.next(max(expire - time.time(), 0))
  • tests/quotedKeyword.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 19:07:07 2020
    13 // Update Count     : 25
     12// Last Modified On : Tue Dec  4 21:45:53 2018
     13// Update Count     : 23
    1414//
    1515
     
    1717
    1818struct {
    19         int ``otype;
    20         int ``struct;
     19        int `otype`;
     20        int `struct`;
    2121} st = { 10, 10 };
    2222
    23 typedef int ``forall;
    24 ``forall xxx = 10;
     23typedef int `forall`;
     24`forall` xxx = 10;
    2525
    26 int ``_Alignas, ``_Alignof, ``__alignof, ``__alignof__, ``asm, ``__asm, ``__asm__, ``_At, ``_Atomic, ``__attribute,
    27         ``__attribute__, ``auto, ``_Bool, ``break, ``case, ``catch, ``catchResume, ``char, ``choose, ``_Complex, ``__complex,
    28         ``__complex__, ``const, ``__const, ``__const__, ``continue, ``default, ``disable, ``do, ``double, ``dtype, ``else,
    29         ``enable, ``enum, ``__extension__, ``extern, ``fallthru, ``finally, ``float, ``__float128, ``for, ``forall, ``fortran,
    30         ``ftype, ``_Generic, ``goto, ``if, ``_Imaginary, ``__imag, ``__imag__, ``inline, ``__inline, ``__inline__, ``int,
    31         ``__int128, ``__label__, ``long, ``lvalue, ``_Noreturn, ``__builtin_offsetof, ``otype, ``register, ``restrict,
    32         ``__restrict, ``__restrict__, ``return, ``short, ``signed, ``__signed, ``__signed__, ``sizeof, ``static,
    33         ``_Static_assert, ``struct, ``switch, ``_Thread_local, ``throw, ``throwResume, ``trait, ``try, ``typedef,
    34         ``typeof, ``__typeof, ``__typeof__, ``union, ``unsigned, ``__builtin_va_list, ``void, ``volatile, ``__volatile,
    35         ``__volatile__, ``while;
     26int `_Alignas`, `_Alignof`, `__alignof`, `__alignof__`, `asm`, `__asm`, `__asm__`, `_At`, `_Atomic`, `__attribute`,
     27        `__attribute__`, `auto`, `_Bool`, `break`, `case`, `catch`, `catchResume`, `char`, `choose`, `_Complex`, `__complex`,
     28        `__complex__`, `const`, `__const`, `__const__`, `continue`, `default`, `disable`, `do`, `double`, `dtype`, `else`,
     29        `enable`, `enum`, `__extension__`, `extern`, `fallthru`, `finally`, `float`, `__float128`, `for`, `forall`, `fortran`,
     30        `ftype`, `_Generic`, `goto`, `if`, `_Imaginary`, `__imag`, `__imag__`, `inline`, `__inline`, `__inline__`, `int`,
     31        `__int128`, `__label__`, `long`, `lvalue`, `_Noreturn`, `__builtin_offsetof`, `otype`, `register`, `restrict`,
     32        `__restrict`, `__restrict__`, `return`, `short`, `signed`, `__signed`, `__signed__`, `sizeof`, `static`,
     33        `_Static_assert`, `struct`, `switch`, `_Thread_local`, `throw`, `throwResume`, `trait`, `try`, `typedef`,
     34        `typeof`, `__typeof`, `__typeof__`, `union`, `unsigned`, `__builtin_va_list`, `void`, `volatile`, `__volatile`,
     35        `__volatile__`, `while`;
    3636
    3737int main() {
    38         int ``if = 0;
    39         ``catch = 1;
    40         st.``otype = 2;
    41         st.``struct = 3;
    42         ``throw = 4;
    43         sout | ``catch + st.``otype + st.``struct + ``throw;
     38        int `if` = 0;
     39        `catch` = 1;
     40        st.`otype` = 2;
     41        st.`struct` = 3;
     42        `throw` = 4;
     43        sout | `catch` + st.`otype` + st.`struct` + `throw`;
    4444}
    4545
  • tests/raii/dtor-early-exit.cfa

    r7030dab r71d6bd8  
    217217}
    218218
    219 void i() {
    220         // potential loop
    221         for() {
    222                 if(true) continue;
    223                 int t = 0;
    224         }
    225 }
    226 
    227219// TODO: implement __label__ and uncomment these lines
    228220void computedGoto() {
  • tests/rational.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Mon Mar 28 08:43:12 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb  8 18:46:23 2020
    13 // Update Count     : 86
     12// Last Modified On : Wed Mar 27 07:37:17 2019
     13// Update Count     : 80
    1414//
    1515
     
    1919#include <fstream.hfa>
    2020
    21 typedef Rational(int) RatInt;
    22 double convert( int i ) { return (double)i; }                   // used by narrow/widen
     21double convert( int i ) { return (double)i; }
    2322int convert( double d ) { return (int)d; }
    2423
    2524int main() {
    2625        sout | "constructor";
    27         RatInt a = { 3 }, b = { 4 }, c, d = 0, e = 1;
    28         sout | a | b | c | d | e;
     26        Rational(int) a = { 3 }, b = { 4 }, c;
     27        sout | a | b | c;
    2928
    30         a = (RatInt){ 4, 8 };
    31         b = (RatInt){ 5, 7 };
     29        a = (Rational(int)){ 4, 8 };
     30        b = (Rational(int)){ 5, 7 };
    3231        sout | a | b;
    33         a = (RatInt){ -2, -3 };
    34         b = (RatInt){ 3, -2 };
     32        a = (Rational(int)){ -2, -3 };
     33        b = (Rational(int)){ 3, -2 };
    3534        sout | a | b;
    36         a = (RatInt){ -2, 3 };
    37         b = (RatInt){ 3, 2 };
     35        a = (Rational(int)){ -2, 3 };
     36        b = (Rational(int)){ 3, 2 };
    3837        sout | a | b;
    3938
    4039        sout | "logical";
    41         a = (RatInt){ -2 };
    42         b = (RatInt){ -3, 2 };
     40        a = (Rational(int)){ -2 };
     41        b = (Rational(int)){ -3, 2 };
    4342        sout | a | b;
    4443//      sout | a == 1; // FIX ME
     
    5958
    6059        sout | "conversion";
    61         a = (RatInt){ 3, 4 };
     60        a = (Rational(int)){ 3, 4 };
    6261        sout | widen( a );
    63         a = (RatInt){ 1, 7 };
     62        a = (Rational(int)){ 1, 7 };
    6463        sout | widen( a );
    65         a = (RatInt){ 355, 113 };
     64        a = (Rational(int)){ 355, 113 };
    6665        sout | widen( a );
    6766        sout | narrow( 0.75, 4 );
     
    7574
    7675        sout | "more tests";
    77         RatInt x = { 1, 2 }, y = { 2 };
     76        Rational(int) x = { 1, 2 }, y = { 2 };
    7877        sout | x - y;
    7978        sout | x > y;
     
    8180        sout | y | denominator( y, -2 ) | y;
    8281
    83         RatInt z = { 0, 5 };
     82        Rational(int) z = { 0, 5 };
    8483        sout | z;
    8584
    8685        sout | x | numerator( x, 0 ) | x;
    8786
    88         x = (RatInt){ 1, MAX } + (RatInt){ 1, MAX };
     87        x = (Rational(int)){ 1, MAX } + (Rational(int)){ 1, MAX };
    8988        sout | x;
    90         x = (RatInt){ 3, MAX } + (RatInt){ 2, MAX };
     89        x = (Rational(int)){ 3, MAX } + (Rational(int)){ 2, MAX };
    9190        sout | x;
    9291
  • tests/references.cfa

    r7030dab r71d6bd8  
    119119                f( 3, a + b, (S){ 1.0, 7.0 }, (int [3]){ 1, 2, 3 } ); // two rvalue to reference
    120120        }
    121 
    122         {
    123                 int a = 3;
    124                 int *p = &a;
    125                 asm (
    126                         "incl %[p]\n\t"
    127                         : [p] "+m" (*p)
    128                 );
    129                 printf("%d\n", a);
    130         }
    131121}
    132122
  • tests/test.py

    r7030dab r71d6bd8  
    66
    77import argparse
    8 import itertools
    98import re
    109import sys
    1110import tempfile
    1211import time
    13 
    14 import os
    15 import psutil
    16 import signal
    1712
    1813################################################################################
     
    3025                        test.path = match.group(1)
    3126                        test.arch = match.group(3)[1:] if match.group(3) else None
    32                         expected.append(test)
     27                        if settings.arch.match(test.arch):
     28                                expected.append(test)
    3329
    3430        path_walk( match_test )
     
    5248                        x.target().startswith( tuple(excludes) )
    5349                ]
    54 
    55         # sort the test alphabetically for convenience
    56         test_list.sort(key=lambda t: ('~' if t.arch else '') + t.target() + (t.arch if t.arch else ''))
    5750
    5851        return test_list
     
    7972
    8073                        if test :
    81                                 tests.extend( test )
     74                                tests.append( test[0] )
    8275                        else :
    8376                                print('ERROR: No expected file for test %s, ignoring it' % testname, file=sys.stderr)
     
    8982        # create a parser with the arguments for the tests script
    9083        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
    91         parser.add_argument('--debug', help='Run all tests in debug or release', type=comma_separated(yes_no), default='yes')
    92         parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    93         parser.add_argument('--arch', help='Test for specific architecture', type=comma_separated(str), default='')
    94         parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
     84        parser.add_argument('--debug', help='Run all tests in debug or release', type=yes_no, default='yes')
     85        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=yes_no, default='no')
     86        parser.add_argument('--arch', help='Test for specific architecture', type=str, default='')
    9587        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=60)
    9688        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
    97         parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no")
    9889        parser.add_argument('--dry-run', help='Don\'t run the tests, only output the commands', action='store_true')
    9990        parser.add_argument('--list', help='List all test available', action='store_true')
     
    157148        # run everything in a temp directory to make sure core file are handled properly
    158149        with tempdir():
    159                 # if the make command succeeds continue otherwise skip to diff
     150                # if the make command succeds continue otherwise skip to diff
    160151                if success(make_ret):
    161152                        with Timed() as run_dur:
     
    230221        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    231222
    232         # since python prints stacks by default on a interrupt, redo the interrupt handling to be silent
    233         def worker_init():
    234                 def sig_int(signal_num, frame):
    235                         pass
    236 
    237                 signal.signal(signal.SIGINT, sig_int)
    238 
    239223        # create the executor for our jobs and handle the signal properly
    240         pool = multiprocessing.Pool(jobs, worker_init)
     224        pool = multiprocessing.Pool(jobs)
    241225
    242226        failed = False
    243 
    244         def stop(x, y):
    245                 print("Tests interrupted by user", file=sys.stderr)
    246                 sys.exit(1)
    247         signal.signal(signal.SIGINT, stop)
    248227
    249228        # for each test to run
     
    283262        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    284263
    285         return failed
     264        return 1 if failed else 0
    286265
    287266
     
    297276        settings.init( options )
    298277
     278        # fetch the liest of all valid tests
     279        all_tests = list_tests( options.include, options.exclude )
     280
     281
     282        # if user wants all tests than no other treatement of the test list is required
     283        if options.all or options.list or options.list_comp or options.include :
     284                tests = all_tests
     285
     286        #otherwise we need to validate that the test list that was entered is valid
     287        else :
     288                tests = valid_tests( options )
     289
     290        # make sure we have at least some test to run
     291        if not tests :
     292                print('ERROR: No valid test to run', file=sys.stderr)
     293                sys.exit(1)
     294
     295
     296        # sort the test alphabetically for convenience
     297        tests.sort(key=lambda t: (t.arch if t.arch else '') + t.target())
     298
    299299        # users may want to simply list the tests
    300300        if options.list_comp :
    301                 # fetch the liest of all valid tests
    302                 tests = list_tests( None, None )
    303 
    304                 # print the possible options
    305                 print("-h --help --debug --dry-run --list --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout --timeout-with-gdb -j --jobs -I --include -E --exclude --continue ", end='')
     301                print("-h --help --debug --dry-run --list --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout -j --jobs ", end='')
    306302                print(" ".join(map(lambda t: "%s" % (t.target()), tests)))
    307303
    308304        elif options.list :
    309                 # fetch the liest of all valid tests
    310                 tests = list_tests( options.include, options.exclude )
    311 
    312                 # print the available tests
     305                print("Listing for %s:%s"% (settings.arch.string, settings.debug.string))
    313306                fancy_print("\n".join(map(lambda t: t.toString(), tests)))
    314307
    315308        else :
    316                 # fetch the liest of all valid tests
    317                 all_tests = list_tests( options.include, options.exclude )
    318 
    319                 # if user wants all tests than no other treatement of the test list is required
    320                 if options.all or options.include :
    321                         tests = all_tests
    322 
    323                 #otherwise we need to validate that the test list that was entered is valid
    324                 else :
    325                         tests = valid_tests( options )
    326 
    327                 # make sure we have at least some test to run
    328                 if not tests :
    329                         print('ERROR: No valid test to run', file=sys.stderr)
    330                         sys.exit(1)
    331 
    332                 # prep invariants
     309                # check the build configuration works
    333310                settings.prep_output(tests)
    334                 failed = 0
    335 
    336                 # for each build configurations, run the test
    337                 for arch, debug, install in itertools.product(settings.all_arch, settings.all_debug, settings.all_install):
    338                         settings.arch    = arch
    339                         settings.debug   = debug
    340                         settings.install = install
    341 
    342                         # filter out the tests for a different architecture
    343                         # tests are the same across debug/install
    344                         local_tests = settings.arch.filter( tests )
    345                         options.jobs, forceJobs = job_count( options, local_tests )
    346                         settings.update_make_cmd(forceJobs, options.jobs)
    347 
    348                         # check the build configuration works
    349                         settings.validate()
    350 
    351                         # print configuration
    352                         print('%s %i tests on %i cores (%s:%s)' % (
    353                                 'Regenerating' if settings.generating else 'Running',
    354                                 len(local_tests),
    355                                 options.jobs,
    356                                 settings.arch.string,
    357                                 settings.debug.string
    358                         ))
    359 
    360                         # otherwise run all tests and make sure to return the correct error code
    361                         failed = run_tests(local_tests, options.jobs)
    362                         if failed:
    363                                 result = 1
    364                                 if not settings.continue_:
    365                                         break
    366 
    367 
    368                 sys.exit( failed )
     311                settings.validate()
     312
     313                options.jobs, forceJobs = job_count( options, tests )
     314                settings.update_make_cmd(forceJobs, options.jobs)
     315
     316                print('%s %i tests on %i cores (%s:%s)' % (
     317                        'Regenerating' if settings.generating else 'Running',
     318                        len(tests),
     319                        options.jobs,
     320                        settings.arch.string,
     321                        settings.debug.string
     322                ))
     323
     324                # otherwise run all tests and make sure to return the correct error code
     325                sys.exit( run_tests(tests, options.jobs) )
  • tests/time.cfa

    r7030dab r71d6bd8  
    1010// Created On       : Tue Mar 27 17:24:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jan  5 18:27:37 2020
    13 // Update Count     : 34
     12// Last Modified On : Thu Dec 20 23:09:21 2018
     13// Update Count     : 23
    1414//
    1515
     
    2020        Duration d1 = 3`h, d2 = 2`s, d3 = 3.375`s, d4 = 12`s, d5 = 1`s + 10_000`ns;
    2121        sout | d1 | d2 | d3 | d4 | d5;
     22        int i;
    2223        d1 = 0;
    2324        sout | d1 | d2 | d3;
     
    3435        sout | t;
    3536        t = t + d1;
    36         sout | t | t`ns;
     37        sout | t | t.tv;
    3738        Time t1 = (timespec){ 104_414, 10_000_000 };
    38         sout | t1 | t1`ns;
    39         sout | t - t  | t + d5 | t`ns;
    40         char buf[64];
     39        sout | t1 | t1.tv;
     40        sout | t - t  | t + d5 | t.tv;
     41        char buf[16];
    4142        sout | "yy/mm/dd" | [t, buf]`ymd | nonl;                        // shared buf => separate calls
    4243        sout | "mm/dd/yy" | mm_dd_yy( t, buf ) | nonl;
     
    4546        sout | "dd/yy/mm" | [t, buf]`dmy;
    4647        Time t2 = { 2001, 7, 4, 0, 0, 1, 0 }, t3 = (timeval){ 994_219_201 };
    47         sout | t2 | t2`ns | nl | t3 | t3`ns;
     48        sout | t2 | t2.tv | nl | t3 | t3.tv;
    4849        sout | nl;
    4950
     
    6263        sout | "Dividing that by 2 gives" | s / 2 | "seconds";
    6364        sout | s | "seconds is" | s`h | "hours," | (s % 1`h)`m | "minutes," | (s % 1`m)`s | "seconds";
    64 
    65     t1 = (Time){ 2020, 1, 5, 9, 0, 0, 100000000000LL };
    66     t2 = (Time){ 1969, 13, 5, 9 };
    67     t3 = (Time){ 1970, 25, 366, 48, 120, -120, 60000000000LL };
    68     strftime( buf, 128, "%Y %b %e %H:%M:%S (GMT)", t1 );
    69     sout | buf;
    70     strftime( buf, 128, "%Y %b %e %H:%M:%S (GMT)", t2 );
    71     sout | buf;
    72     strftime( buf, 128, "%Y %b %e %H:%M:%S (GMT)", t3 );
    73     sout | buf;
    7465} // main
    7566
  • tests/userLiterals.cfa

    r7030dab r71d6bd8  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // userLiterals.cfa --
     7// user_literals.cfa --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Wed Sep  6 21:40:50 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 19 07:48:45 2020
    13 // Update Count     : 74
     12// Last Modified On : Tue Dec  4 22:03:10 2018
     13// Update Count     : 56
    1414//
    1515
     
    2424int ?`__thingy_( int x ) { sout | "_thingy_" | x; return x; }
    2525
    26 int ?`s( const char * s ) { sout | "s" | s; return 0; }
    27 int ?`m( const char16_t * m ) { sout | "m" | m; return 0;}
    28 int ?`h( const char32_t * h ) { sout | "h" | h; return 0; }
     26int ?`s( const char * s ) { sout | "secs" | s; return 0; }
     27int ?`m( const char16_t * m ) { sout | "mins" | m; return 0;}
     28int ?`h( const char32_t * h ) { sout | "hours" | h; return 0; }
    2929int ?`_A_( const wchar_t * str ) { sout | "_A_" | str; return 0; }
    3030int ?`__thingy_( const char * str ) { sout | "_thingy_" | str; return 0; }
     
    3737        return (Weight){ l.stones + r.stones };
    3838}
    39 ofstream & ?|?( ofstream & os, Weight w ) { return os | wd(1,1, w.stones); }
    40 void ?|?( ofstream & os, Weight w ) { (ofstream)(os | w); ends( os ); }
     39ofstream & ?|?( ofstream & os, Weight w ) { return os | w.stones; }
    4140
    4241Weight ?`st( double w ) { return (Weight){ w }; }               // backquote for user literals
     
    6160        sout | w;
    6261
    63         0`s;
     62//      0`secs;
    6463        1`s;
    6564        23`s;
     
    8382
    8483        "abc"`s;
    85         // FIX ME: requires char16_t, char32_t, and wchar_t be unique types
    86         // u"abc"`m;
    87         // U_"abc"`h;
    88         // L"abc"`_A_;
     84//      u"abc"`m;
     85//      U_"abc"`h;
     86//      L"abc"`_A_;
    8987        u8_"abc"`__thingy_;
    9088} // main
     
    9290// Local Variables: //
    9391// tab-width: 4 //
    94 // compile-command: "cfa userLiterals.cfa" //
     92// compile-command: "cfa user_literals.cfa" //
    9593// End: //
  • tools/catchsig.c

    r7030dab r71d6bd8  
    2121        printf("Starting...\n");
    2222        sig(SIGHUP);
    23         sig(SIGINT);
    24         sig(SIGQUIT);
    25         sig(SIGILL);
    26         sig(SIGABRT);
    27         sig(SIGFPE);
    28         sig(SIGSEGV);
    29         sig(SIGPIPE);
    30         sig(SIGALRM);
    31         sig(SIGTERM);
    32         sig(SIGUSR1);
    33         sig(SIGUSR2);
    34         sig(SIGCHLD);
    35         sig(SIGCONT);
    36         sig(SIGTSTP);
    37         sig(SIGTTIN);
    38         sig(SIGTTOU);
     23      sig(SIGINT);
     24      sig(SIGQUIT);
     25      sig(SIGILL);
     26      sig(SIGABRT);
     27      sig(SIGFPE);
     28      sig(SIGSEGV);
     29      sig(SIGPIPE);
     30      sig(SIGALRM);
     31      sig(SIGTERM);
     32      sig(SIGUSR1);
     33      sig(SIGUSR2);
     34      sig(SIGCHLD);
     35      sig(SIGCONT);
     36      sig(SIGTSTP);
     37      sig(SIGTTIN);
     38      sig(SIGTTOU);
    3939        while(1);
    4040        return 0;
  • tools/cfa.nanorc

    r7030dab r71d6bd8  
    1414
    1515# Declarations
    16 color brightgreen "\<(struct|union|typedef|trait|coroutine|generator)\>"
    17 color brightgreen "\<(monitor|thread|with)\>"
     16color brightgreen "\<(struct|union|typedef|trait|coroutine|monitor|thread)\>"
     17color brightgreen "\<(with)\>"
    1818
    1919# Control Flow Structures
    2020color brightyellow "\<(if|else|while|do|for|switch|choose|case|default)\>"
    21 color brightyellow "\<(disable|enable|waitfor|when|timeout|suspend)\>"
     21color brightyellow "\<(disable|enable|waitfor|when|timeout)\>"
    2222color brightyellow "\<(try|catch(Resume)?|finally)\>"
    2323
     
    2626
    2727# Escaped Keywords, now Identifiers.
    28 color white "``\w+"
     28color white "`\w+`"
    2929
    3030# Operator Names
     
    3737## Update/Redistribute
    3838# GCC builtins
    39 color cyan "__attribute__[[:space:]]*\(\(([^)]|[^)]\))*\)\)"
     39color cyan "__attribute__[[:space:]]*\(\([^()]*(\([^()]*\)[^()]*)*\)\)"
    4040##color cyan "__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__"
    4141
  • tools/stat.py

    r7030dab r71d6bd8  
    1717                avg = numpy.mean  (content)
    1818                std = numpy.std   (content)
    19                 print "median {0:.1f} avg {1:.1f} stddev {2:.1f}".format( med, avg, std )
     19                print "median {0:.1f} avg {1:.1f} stddev {2:.2f}".format( med, avg, std )
    2020
    2121
  • tools/vscode/uwaterloo.cforall-0.1.0/package.json

    r7030dab r71d6bd8  
    22        "name": "cforall",
    33        "version": "0.1.0",
    4         "displayName": "Cāˆ€ (C-for-all) Language Support",
     4        "displayName": "Cforall Language Support",
    55        "description": "Cforall - colorizer, grammar and snippets.",
    66        "publisher": "uwaterloo",
     
    99                "vscode": "^1.5.0"
    1010        },
    11         "icon": "images/icon.png",
     11        "icon": "images/icon.svg",
    1212        "categories": [
    13                 "Programming Languages",
     13                "Languages",
    1414                "Linters",
    1515                "Other"
    1616        ],
    17         "activationEvents": [
    18                 "onLanguage:cforall"
    19         ],
    20         "main": "./client/main.js",
    2117        "contributes": {
    2218                "languages": [
     
    2521                                "aliases": [
    2622                                        "Cāˆ€",
     23                                        "Cforall",
    2724                                        "CForAll",
    28                                         "Cforall",
    2925                                        "cforall"
    3026                                ],
    3127                                "extensions": [
    32                                         ".cfa",
    33                                         ".hfa",
    34                                         ".ifa"
     28                                        ".cf"
    3529                                ],
    3630                                "configuration": "./cforall.configuration.json"
     
    4034                        {
    4135                                "language": "cforall",
    42                                 "scopeName": "source.cfa",
    43                                 "path": "./syntaxes/cfa.tmLanguage.json"
     36                                "scopeName": "source.cf",
     37                                "path": "./syntaxes/cfa.tmLanguage"
    4438                        }
    45                 ],
    46                 "configuration": {
    47                         "type": "object",
    48                         "title": "Example configuration",
    49                         "properties": {
    50                                 "cforall.maxNumberOfProblems": {
    51                                         "scope": "resource",
    52                                         "type": "number",
    53                                         "default": 100,
    54                                         "description": "Controls the maximum number of problems produced by the server."
    55                                 },
    56                                 "cforall.trace.server": {
    57                                         "scope": "window",
    58                                         "type": "string",
    59                                         "enum": [
    60                                                 "off",
    61                                                 "messages",
    62                                                 "verbose"
    63                                         ],
    64                                         "default": "off",
    65                                         "description": "Traces the communication between VS Code and the language server."
    66                                 }
    67                         }
    68                 }
    69         },
    70         "dependencies": {
    71                 "vscode-languageclient": "^4.1.4"
    72         },
    73         "devDependencies": {
    74                 "vscode-languageclient": "^4.1.4"
     39                ]
    7540        }
    7641}
Note: See TracChangeset for help on using the changeset viewer.