Changes in / [71d6bd8:7030dab]


Ignore:
Files:
151 added
35 deleted
291 edited

Legend:

Unmodified
Added
Removed
  • Jenkinsfile_disabled

    r71d6bd8 r7030dab  
    126126                        }
    127127
    128                         sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet"
     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}"
    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"
    157164                }
    158165        }
     
    179186                echo "Archiving core dumps"
    180187                dir (BuildDir) {
    181                         archiveArtifacts artifacts: "tests/crashes/**/*", fingerprint: true
     188                        archiveArtifacts artifacts: "tests/crashes/**/*,lib/**/lib*.so*", fingerprint: true
    182189                }
    183190                throw err
     
    215222
    216223                //Then publish the results
    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)')
     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)')
    225232        }
    226233}
     
    325332        public String CXX
    326333        public String CC
    327 
    328         CC_Desc(String name, String CXX, String CC) {
     334        public String lto
     335
     336        CC_Desc(String name, String CXX, String CC, String lto) {
    329337                this.name = name
    330338                this.CXX = CXX
    331                 this.CC = CC
     339                this.CC  = CC
     340                this.lto = lto
    332341        }
    333342}
     
    364373                switch( param.Compiler ) {
    365374                        case 'gcc-9':
    366                                 this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9')
     375                                this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9', '-flto=auto')
    367376                        break
    368377                        case 'gcc-8':
    369                                 this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8')
     378                                this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8', '-flto=auto')
    370379                        break
    371380                        case 'gcc-7':
    372                                 this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7')
     381                                this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
    373382                        break
    374383                        case 'gcc-6':
    375                                 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6')
     384                                this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
    376385                        break
    377386                        case 'gcc-5':
    378                                 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5')
     387                                this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
    379388                        break
    380389                        case 'gcc-4.9':
    381                                 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9')
     390                                this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
    382391                        break
    383392                        case 'clang':
    384                                 this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6')
     393                                this.Compiler = new CC_Desc('clang', 'clang++-6.0', 'gcc-6', '-flto=thin -flto-jobs=0')
    385394                        break
    386395                        default :
     
    439448        // prepare the properties
    440449        properties ([                                                                                                   \
     450                buildDiscarder(logRotator(                                                                              \
     451                        artifactDaysToKeepStr: '',                                                                      \
     452                        artifactNumToKeepStr: '',                                                                       \
     453                        daysToKeepStr: '730',                                                                           \
     454                        numToKeepStr: '1000'                                                                            \
     455                )),                                                                                                             \
    441456                [$class: 'ParametersDefinitionProperty',                                                                \
    442457                        parameterDefinitions: [                                                                         \
  • benchmark/Makefile.am

    r71d6bd8 r7030dab  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Jul 29 18:02:19 2019
    14 ## Update Count     : 54
     13## Last Modified On : Tue Mar 10 11:41:18 2020
     14## Update Count     : 258
    1515###############################################################################
    1616
     
    2828BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
    2929BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
     30BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    3031BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
     32BENCH_V_PY = $(__bench_v_PY_$(__quiet))
     33BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
     34BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
    3135BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    32 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    3336
    3437__quiet = verbose
     
    3639__bench_v_CFA_quiet = @
    3740__bench_v_CXX_quiet = @
     41__bench_v_UPP_quiet = @
    3842__bench_v_GOC_quiet = @
     43__bench_v_RUSTC_quiet = @
    3944__bench_v_JAVAC_quiet = @
    40 __bench_v_UPP_quiet = @
    4145__bench_v_CC_verbose = $(AM_V_CC)
    4246__bench_v_CFA_verbose = $(AM_V_CFA)
    4347__bench_v_CXX_verbose = $(AM_V_CXX)
     48__bench_v_UPP_verbose = $(AM_V_UPP)
    4449__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)
    4553__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    46 __bench_v_UPP_verbose = $(AM_V_UPP)
    4754
    4855
     
    5158STATS    = ${abs_top_srcdir}/tools/stat.py
    5259# NEED AT LEAST 4 DATA VALUES FOR BENCHMARKS BECAUSE THE MAX AND MIN VALUES ARE REMOVED
    53 repeats  = 5 # 31 for benchmarks
     60repeats  = 13 # 31 for benchmarks
    5461arch     = x64
    5562skipcompile = no
     
    6269
    6370dummyC.c:
    64         @echo "int main() { return 0; }" > ${@}
     71        echo "int main() { return 0; }" > ${@}
    6572
    6673dummyCXX.cpp:
    67         @echo "int main() { return 0; }" > ${@}
    68 
     74        echo "int main() { return 0; }" > ${@}
     75
     76.SILENT:                # do not print recipe
    6977.NOTPARALLEL:
    70 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
    71 
    72 ## =========================================================================================================
    73 all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
     78.PHONY: jenkins cleancsv
     79
     80## =========================================================================================================
     81
     82all : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
     83
     84basic_loop_DURATION = 15000000000
     85basic_function_DURATION = 10000000000
     86basic_tls_fetch_add_DURATION = 10000000000
     87basic_DURATION = 250000000
     88
     89ctxswitch_pthread_DURATION = 25000000
     90ctxswitch_rust_thread_DURATION = $(ctxswitch_pthread_DURATION)
     91ctxswitch_cfa_generator_DURATION = 5000000000
     92ctxswitch_nodejs_await_DURATION = 5000000
     93ctxswitch_DURATION = 100000000
     94
     95#mutex_java_DURATION = 10000000
     96mutex_DURATION = 50000000
     97
     98schedint_pthread_DURATION = 1000000
     99schedint_java_DURATION = $(schedint_pthread_DURATION)
     100schedint_rust_DURATION = $(schedint_pthread_DURATION)
     101schedint_DURATION = 10000000
     102
     103schedext_DURATION = 10000000
     104
     105creation_pthread_DURATION = 250000
     106creation_rust_thread_DURATION = ${creation_pthread_DURATION}
     107creation_java_thread_DURATION = ${creation_pthread_DURATION}
     108creation_cfa_coroutine_DURATION = 100000000
     109creation_cfa_coroutine_eager_DURATION = 10000000
     110creation_cfa_generator_DURATION = 1000000000
     111creation_upp_coroutine_DURATION = ${creation_cfa_coroutine_eager_DURATION}
     112creation_cfa_thread_DURATION = 10000000
     113creation_upp_thread_DURATION = ${creation_cfa_thread_DURATION}
     114creation_DURATION = 10000000
    74115
    75116%.run : %$(EXEEXT) ${REPEAT}
    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
     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
    83129
    84130%.runquiet :
    85         @+make $(basename $@) CFLAGS="-w" __quiet=quiet
    86         @taskset -c 1 ./a.out
    87         @rm -f a.out
     131        +make $(basename $@) CFLAGS="-w" __quiet=quiet
     132        taskset -c 1 ./a.out
     133        rm -f a.out
    88134
    89135%.make :
    90         @printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
    91         @+/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
     136        printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
     137        +/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
    92138
    93139${REPEAT} :
    94         @+make -C ${abs_top_builddir}/tools repeat
     140        +make -C ${abs_top_builddir}/tools repeat
    95141
    96142## =========================================================================================================
     
    98144FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    99145
    100 jenkins$(EXEEXT):
     146cleancsv:
     147        rm -f compile.csv basic.csv ctxswitch.csv mutex.csv scheduling.csv
     148
     149jenkins$(EXEEXT): cleancsv
    101150@DOifskipcompile@
    102         @+make compile.csv
    103         @-+make compile.diff.csv
     151        +make compile.csv
     152        -+make compile.diff.csv
    104153@DOendif@
    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
     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
    111160@DOifskipcompile@
    112161        cat compile.csv
     
    117166        cat mutex.csv
    118167        -cat mutex.diff.csv
    119         cat signal.csv
    120         -cat signal.diff.csv
     168        cat scheduling.csv
     169        -cat scheduling.diff.csv
    121170
    122171compile.csv:
    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 $@
     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 $@
    133183
    134184ctxswitch.csv:
    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 $@
     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 $@
    140191
    141192mutex.csv:
    142         @echo "1-monitor,2-monitor" > $@
    143         @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
    144         @+make mutex-cfa2.runquiet >> $@
    145         @$(srcdir)/fixcsv.sh $@
    146 
    147 signal.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 $@
     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
     199scheduling.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 $@
    154207
    155208%.diff.csv: %.csv
    156         @test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
    157         @$(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
    158 
    159 
    160 ## =========================================================================================================
    161 loop$(EXEEXT):
    162         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
    163 
    164 function$(EXEEXT):
    165         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
    166 
    167 fetch_add$(EXEEXT):
    168         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    169 
    170 ttst_lock$(EXEEXT):
    171         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/ttst_lock.c
    172 
    173 tls-fetch_add$(EXEEXT):
    174         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
    175 
    176 ## =========================================================================================================
    177 CTXSWITCH_DEPEND  =                 \
    178         loop.run                                \
    179         function.run                    \
    180         fetch_add.run                   \
    181         ttst_lock.run                   \
    182         tls-fetch_add.run                       \
    183         ctxswitch-pthread.run           \
     209        test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
     210        $(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
     211
     212## =========================================================================================================
     213
     214BASIC_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
     221basic-loop$(EXEEXT):
     222        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/loop.c
     223
     224basic-function$(EXEEXT):
     225        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/function.c
     226
     227basic-fetch_add$(EXEEXT):
     228        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/fetch_add.c
     229
     230basic-ttst_lock$(EXEEXT):
     231        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/ttst_lock.c
     232
     233basic-tls-fetch_add$(EXEEXT):
     234        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/tls_fetch_add.c
     235
     236basic$(EXEEXT): $(BASIC_DEPEND)
     237
     238## =========================================================================================================
     239
     240CTXSWITCH_DEPEND  =                     \
    184241        ctxswitch-cfa_generator.run     \
    185242        ctxswitch-cfa_coroutine.run     \
     
    188245        ctxswitch-upp_coroutine.run     \
    189246        ctxswitch-upp_thread.run        \
    190         ctxswitch-goroutine.run         \
    191         ctxswitch-java_thread.run
    192 
     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
    193255
    194256if WITH_LIBFIBRE
    195 CTXSWITCH_DEPEND  +=           \
    196         ctxswitch-kos_fibre.run  \
     257CTXSWITCH_DEPEND  +=                    \
     258        ctxswitch-kos_fibre.run         \
    197259        ctxswitch-kos_fibre2.run
    198 
    199260
    200261ctxswitch-kos_fibre$(EXEEXT):
     
    207268ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND)
    208269
    209 ctxswitch-pthread$(EXEEXT):
    210         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
    211 
    212270ctxswitch-cfa_generator$(EXEEXT):
    213         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa
     271        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_gen.cfa
    214272
    215273ctxswitch-cfa_coroutine$(EXEEXT):
    216         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
     274        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_cor.cfa
    217275
    218276ctxswitch-cfa_thread$(EXEEXT):
    219         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
     277        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd.cfa
    220278
    221279ctxswitch-cfa_thread2$(EXEEXT):
    222         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
     280        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd2.cfa
    223281
    224282ctxswitch-upp_coroutine$(EXEEXT):
    225         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
     283        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_cor.cc
    226284
    227285ctxswitch-upp_thread$(EXEEXT):
    228         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
    229 
    230 ctxswitch-goroutine$(EXEEXT):
     286        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_thrd.cc
     287
     288ctxswitch-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
     293ctxswitch-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
     298ctxswitch-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
     303ctxswitch-goroutine_thread$(EXEEXT):
    231304        $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
     305
     306ctxswitch-rust_thread$(EXEEXT):
     307        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/ctxswitch/rust_thrd.rs
    232308
    233309ctxswitch-java_thread$(EXEEXT):
    234310        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    235         @echo "#!/bin/sh" > a.out
    236         @echo "java JavaThread" >> a.out
    237         @chmod a+x a.out
    238 
    239 ## =========================================================================================================
    240 mutex$(EXEEXT) :\
    241         loop.run                        \
    242         function.run            \
    243         fetch_add.run           \
    244         mutex-pthread_lock.run  \
    245         mutex-upp.run           \
     311        echo "#!/bin/sh" > a.out
     312        echo "java JavaThread" >> a.out
     313        chmod a+x a.out
     314
     315ctxswitch-pthread$(EXEEXT):
     316        $(BENCH_V_CC)$(COMPILE) $(srcdir)/ctxswitch/pthreads.c
     317
     318## =========================================================================================================
     319
     320mutex$(EXEEXT) :                \
    246321        mutex-cfa1.run          \
    247322        mutex-cfa2.run          \
    248323        mutex-cfa4.run          \
    249         mutex-java_thread.run
    250 
    251 mutex-pthread_lock$(EXEEXT):
    252         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     324        mutex-upp.run           \
     325        mutex-go.run            \
     326        mutex-rust.run          \
     327        mutex-java.run          \
     328        mutex-pthread.run
     329
     330mutex-pthread$(EXEEXT):
     331        $(BENCH_V_CC)$(COMPILE) $(srcdir)/mutex/pthreads.c
     332
     333mutex-cfa1$(EXEEXT):
     334        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa1.cfa
     335
     336mutex-cfa2$(EXEEXT):
     337        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa2.cfa
     338
     339mutex-cfa4$(EXEEXT):
     340        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa4.cfa
    253341
    254342mutex-upp$(EXEEXT):
    255         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    256 
    257 mutex-cfa1$(EXEEXT):
    258         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    259 
    260 mutex-cfa2$(EXEEXT):
    261         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    262 
    263 mutex-cfa4$(EXEEXT):
    264         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
    265 
    266 mutex-java_thread$(EXEEXT):
     343        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/mutex/upp.cc
     344
     345mutex-go$(EXEEXT):
     346        $(BENCH_V_GOC)go build -o a.out $(srcdir)/mutex/goroutine.go
     347
     348mutex-rust$(EXEEXT):
     349        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/mutex/rust.rs
     350
     351mutex-java$(EXEEXT):
    267352        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    268         @echo "#!/bin/sh" > a.out
    269         @echo "java JavaThread" >> a.out
    270         @chmod a+x a.out
    271 
    272 ## =========================================================================================================
    273 signal$(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 
    281 signal-pthread_cond$(EXEEXT):
    282         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
    283 
    284 signal-upp$(EXEEXT):
    285         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
    286 
    287 signal-cfa1$(EXEEXT):
    288         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
    289 
    290 signal-cfa2$(EXEEXT):
    291         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
    292 
    293 signal-cfa4$(EXEEXT):
    294         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
    295 
    296 signal-java_thread$(EXEEXT):
     353        echo "#!/bin/sh" > a.out
     354        echo "java JavaThread" >> a.out
     355        chmod a+x a.out
     356
     357## =========================================================================================================
     358
     359schedint$(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
     368schedint-cfa1$(EXEEXT):
     369        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa1.cfa
     370
     371schedint-cfa2$(EXEEXT):
     372        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa2.cfa
     373
     374schedint-cfa4$(EXEEXT):
     375        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa4.cfa
     376
     377schedint-upp$(EXEEXT):
     378        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedint/upp.cc
     379
     380schedint-rust$(EXEEXT):
     381        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/schedint/rust.rs
     382
     383schedint-java$(EXEEXT):
    297384        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    298         @echo "#!/bin/sh" > a.out
    299         @echo "java JavaThread" >> a.out
    300         @chmod a+x a.out
    301 
    302 
    303 ## =========================================================================================================
    304 waitfor$(EXEEXT) :\
    305         waitfor-upp.run         \
    306         waitfor-cfa1.run                \
    307         waitfor-cfa2.run                \
    308         waitfor-cfa4.run
    309 
    310 waitfor-upp$(EXEEXT):
    311         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
    312 
    313 waitfor-cfa1$(EXEEXT):
    314         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
    315 
    316 waitfor-cfa2$(EXEEXT):
    317         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
    318 
    319 waitfor-cfa4$(EXEEXT):
    320         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
    321 
    322 ## =========================================================================================================
    323 creation$(EXEEXT) :\
    324         creation-pthread.run                    \
     385        echo "#!/bin/sh" > a.out
     386        echo "java JavaThread" >> a.out
     387        chmod a+x a.out
     388
     389schedint-pthread$(EXEEXT):
     390        $(BENCH_V_CC)$(COMPILE) $(srcdir)/schedint/pthreads.c
     391
     392## =========================================================================================================
     393
     394schedext$(EXEEXT) :             \
     395        schedext-cfa1.run       \
     396        schedext-cfa2.run       \
     397        schedext-cfa4.run       \
     398        schedext-upp.run        \
     399        schedext-goroutine.run
     400
     401schedext-cfa1$(EXEEXT):
     402        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa1.cfa
     403
     404schedext-cfa2$(EXEEXT):
     405        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa2.cfa
     406
     407schedext-cfa4$(EXEEXT):
     408        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa4.cfa
     409
     410schedext-upp$(EXEEXT):
     411        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedext/upp.cc
     412
     413schedext-goroutine$(EXEEXT):
     414        $(BENCH_V_GOC)go build -o a.out $(srcdir)/schedext/goroutine.go
     415
     416
     417## =========================================================================================================
     418
     419creation$(EXEEXT) :                             \
     420        creation-cfa_generator.run              \
    325421        creation-cfa_coroutine.run              \
    326422        creation-cfa_coroutine_eager.run        \
     
    328424        creation-upp_coroutine.run              \
    329425        creation-upp_thread.run                 \
    330         creation-goroutine.run                  \
    331         creation-java_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
     433creation-cfa_generator$(EXEEXT):
     434        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_gen.cfa
    332435
    333436creation-cfa_coroutine$(EXEEXT):
    334         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
     437        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa
    335438
    336439creation-cfa_coroutine_eager$(EXEEXT):
    337         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     440        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    338441
    339442creation-cfa_thread$(EXEEXT):
    340         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
     443        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_thrd.cfa
    341444
    342445creation-upp_coroutine$(EXEEXT):
    343         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
     446        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_cor.cc
    344447
    345448creation-upp_thread$(EXEEXT):
    346         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
    347 
    348 creation-pthread$(EXEEXT):
    349         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
    350 
    351 creation-goroutine$(EXEEXT):
     449        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_thrd.cc
     450
     451creation-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
     456creation-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
     461creation-goroutine_thread$(EXEEXT):
    352462        $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
     463
     464creation-rust_thread$(EXEEXT):
     465        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/creation/rust_thrd.rs
    353466
    354467creation-java_thread$(EXEEXT):
    355468        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    356         @echo "#!/bin/sh" > a.out
    357         @echo "java JavaThread" >> a.out
    358         @chmod a+x a.out
    359 
    360 ## =========================================================================================================
    361 
    362 compile$(EXEEXT) :\
     469        echo "#!/bin/sh" > a.out
     470        echo "java JavaThread" >> a.out
     471        chmod a+x a.out
     472
     473creation-pthread$(EXEEXT):
     474        $(BENCH_V_CC)$(COMPILE) $(srcdir)/creation/pthreads.c
     475
     476## =========================================================================================================
     477
     478compile$(EXEEXT) :              \
    363479        compile-array.make      \
    364480        compile-attributes.make \
     
    370486        compile-typeof.make
    371487
    372 
    373488testdir = $(top_srcdir)/tests
    374489
    375490compile-array$(EXEEXT):
    376         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     491        $(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    377492
    378493compile-attributes$(EXEEXT):
    379         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     494        $(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    380495
    381496compile-empty$(EXEEXT):
    382         @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     497        $(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    383498
    384499compile-expression$(EXEEXT):
    385         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     500        $(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    386501
    387502compile-io$(EXEEXT):
    388         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     503        $(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    389504
    390505compile-monitor$(EXEEXT):
    391         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     506        $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    392507
    393508compile-operators$(EXEEXT):
    394         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     509        $(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    395510
    396511compile-thread$(EXEEXT):
    397         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     512        $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    398513
    399514compile-typeof$(EXEEXT):
    400         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     515        $(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     516
     517## =========================================================================================================
     518
     519size$(EXEEXT) : size-cfa.runquiet
     520
     521size-cfa$(EXEEXT):
     522        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/size/size.cfa
  • benchmark/Makefile.in

    r71d6bd8 r7030dab  
    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) $(CFAFLAGS) \
    355         $(AM_CFLAGS) $(CFLAGS)
     354        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
    356355
    357356AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    359358am__v_CFA_0 = @echo "  CFA     " $@;
    360359am__v_CFA_1 =
    361 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    362 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    363 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    364 am__v_JAVAC_1 =
    365 AM_V_GOC = $(am__v_GOC_@AM_V@)
    366 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    367 am__v_GOC_0 = @echo "  GOC     " $@;
    368 am__v_GOC_1 =
    369360UPPCC = u++
    370361UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    373364am__v_UPP_0 = @echo "  UPP     " $@;
    374365am__v_UPP_1 =
     366AM_V_GOC = $(am__v_GOC_@AM_V@)
     367am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     368am__v_GOC_0 = @echo "  GOC     " $@;
     369am__v_GOC_1 =
     370AM_V_PY = $(am__v_PY_@AM_V@)
     371am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
     372am__v_PY_0 = @echo "  PYTHON  " $@;
     373am__v_PY_1 =
     374AM_V_RUST = $(am__v_RUST_@AM_V@)
     375am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
     376am__v_RUST_0 = @echo "  RUST    " $@;
     377am__v_RUST_1 =
     378AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
     379am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
     380am__v_NODEJS_0 = @echo "  NODEJS  " $@;
     381am__v_NODEJS_1 =
     382AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     383am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     384am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     385am__v_JAVAC_1 =
    375386
    376387# applies to both programs
     
    381392BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
    382393BENCH_V_CXX = $(__bench_v_CXX_$(__quiet))
     394BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    383395BENCH_V_GOC = $(__bench_v_GOC_$(__quiet))
     396BENCH_V_PY = $(__bench_v_PY_$(__quiet))
     397BENCH_V_RUSTC = $(__bench_v_RUSTC_$(__quiet))
     398BENCH_V_NODEJS = $(__bench_v_NODEJS_$(__quiet))
    384399BENCH_V_JAVAC = $(__bench_v_JAVAC_$(__quiet))
    385 BENCH_V_UPP = $(__bench_v_UPP_$(__quiet))
    386400__quiet = verbose
    387401__bench_v_CC_quiet = @
    388402__bench_v_CFA_quiet = @
    389403__bench_v_CXX_quiet = @
     404__bench_v_UPP_quiet = @
    390405__bench_v_GOC_quiet = @
     406__bench_v_RUSTC_quiet = @
    391407__bench_v_JAVAC_quiet = @
    392 __bench_v_UPP_quiet = @
    393408__bench_v_CC_verbose = $(AM_V_CC)
    394409__bench_v_CFA_verbose = $(AM_V_CFA)
    395410__bench_v_CXX_verbose = $(AM_V_CXX)
     411__bench_v_UPP_verbose = $(AM_V_UPP)
    396412__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)
    397416__bench_v_JAVAC_verbose = $(AM_V_JAVAC)
    398 __bench_v_UPP_verbose = $(AM_V_UPP)
    399417TOOLSDIR = ${abs_top_builddir}/tools/
    400418REPEAT = ${abs_top_builddir}/tools/repeat
    401419STATS = ${abs_top_srcdir}/tools/stat.py
    402420# NEED AT LEAST 4 DATA VALUES FOR BENCHMARKS BECAUSE THE MAX AND MIN VALUES ARE REMOVED
    403 repeats = 5 # 31 for benchmarks
     421repeats = 13 # 31 for benchmarks
    404422arch = x64
    405423skipcompile = no
     
    407425PRINT_FORMAT = %20s: #Comments needed for spacing
    408426dummy_SOURCES = dummyC.c dummyCXX.cpp
     427basic_loop_DURATION = 15000000000
     428basic_function_DURATION = 10000000000
     429basic_tls_fetch_add_DURATION = 10000000000
     430basic_DURATION = 250000000
     431ctxswitch_pthread_DURATION = 25000000
     432ctxswitch_rust_thread_DURATION = $(ctxswitch_pthread_DURATION)
     433ctxswitch_cfa_generator_DURATION = 5000000000
     434ctxswitch_nodejs_await_DURATION = 5000000
     435ctxswitch_DURATION = 100000000
     436
     437#mutex_java_DURATION = 10000000
     438mutex_DURATION = 50000000
     439schedint_pthread_DURATION = 1000000
     440schedint_java_DURATION = $(schedint_pthread_DURATION)
     441schedint_rust_DURATION = $(schedint_pthread_DURATION)
     442schedint_DURATION = 10000000
     443schedext_DURATION = 10000000
     444creation_pthread_DURATION = 250000
     445creation_rust_thread_DURATION = ${creation_pthread_DURATION}
     446creation_java_thread_DURATION = ${creation_pthread_DURATION}
     447creation_cfa_coroutine_DURATION = 100000000
     448creation_cfa_coroutine_eager_DURATION = 10000000
     449creation_cfa_generator_DURATION = 1000000000
     450creation_upp_coroutine_DURATION = ${creation_cfa_coroutine_eager_DURATION}
     451creation_cfa_thread_DURATION = 10000000
     452creation_upp_thread_DURATION = ${creation_cfa_thread_DURATION}
     453creation_DURATION = 10000000
    409454FIX_NEW_LINES = cat $@ | tr "\n" "\t" | sed -r 's/\t,/,/' | tr "\t" "\n" > $@
    410 CTXSWITCH_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)
     455BASIC_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
     462CTXSWITCH_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)
    417470testdir = $(top_srcdir)/tests
    418471all: all-am
     
    733786
    734787dummyC.c:
    735         @echo "int main() { return 0; }" > ${@}
     788        echo "int main() { return 0; }" > ${@}
    736789
    737790dummyCXX.cpp:
    738         @echo "int main() { return 0; }" > ${@}
    739 
     791        echo "int main() { return 0; }" > ${@}
     792
     793.SILENT:                # do not print recipe
    740794.NOTPARALLEL:
    741 .PHONY: compile.csv ctxswitch.csv mutex.csv signal.csv
    742 
    743 all : ctxswitch$(EXEEXT) mutex$(EXEEXT) signal$(EXEEXT) waitfor$(EXEEXT) creation$(EXEEXT)
     795.PHONY: jenkins cleancsv
     796
     797all : basic$(EXEEXT) ctxswitch$(EXEEXT) mutex$(EXEEXT) schedint$(EXEEXT) schedext$(EXEEXT) creation$(EXEEXT)
    744798
    745799%.run : %$(EXEEXT) ${REPEAT}
    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
     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
    753812
    754813%.runquiet :
    755         @+make $(basename $@) CFLAGS="-w" __quiet=quiet
    756         @taskset -c 1 ./a.out
    757         @rm -f a.out
     814        +make $(basename $@) CFLAGS="-w" __quiet=quiet
     815        taskset -c 1 ./a.out
     816        rm -f a.out
    758817
    759818%.make :
    760         @printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
    761         @+/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
     819        printf "${PRINT_FORMAT}" $(basename $(subst compile-,,$@))
     820        +/usr/bin/time -f ${TIME_FORMAT} make $(basename $@) 2>&1
    762821
    763822${REPEAT} :
    764         @+make -C ${abs_top_builddir}/tools repeat
    765 
    766 jenkins$(EXEEXT):
     823        +make -C ${abs_top_builddir}/tools repeat
     824
     825cleancsv:
     826        rm -f compile.csv basic.csv ctxswitch.csv mutex.csv scheduling.csv
     827
     828jenkins$(EXEEXT): cleancsv
    767829@DOifskipcompile@
    768         @+make compile.csv
    769         @-+make compile.diff.csv
     830        +make compile.csv
     831        -+make compile.diff.csv
    770832@DOendif@
    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
     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
    777839@DOifskipcompile@
    778840        cat compile.csv
     
    783845        cat mutex.csv
    784846        -cat mutex.diff.csv
    785         cat signal.csv
    786         -cat signal.diff.csv
     847        cat scheduling.csv
     848        -cat scheduling.diff.csv
    787849
    788850compile.csv:
    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 $@
     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 $@
    799862
    800863ctxswitch.csv:
    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 $@
     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 $@
    806870
    807871mutex.csv:
    808         @echo "1-monitor,2-monitor" > $@
    809         @+make mutex-cfa1.runquiet >> $@ && echo -n ',' >> $@
    810         @+make mutex-cfa2.runquiet >> $@
    811         @$(srcdir)/fixcsv.sh $@
    812 
    813 signal.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 $@
     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
     878scheduling.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 $@
    820886
    821887%.diff.csv: %.csv
    822         @test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
    823         @$(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
    824 
    825 loop$(EXEEXT):
    826         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/loop.c
    827 
    828 function$(EXEEXT):
    829         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=5000000000 $(srcdir)/function.c
    830 
    831 fetch_add$(EXEEXT):
    832         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    833 
    834 ttst_lock$(EXEEXT):
    835         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/ttst_lock.c
    836 
    837 tls-fetch_add$(EXEEXT):
    838         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     888        test -e $(srcdir)/baselines/$(arch)/$< || (echo "Error : Missing baseline for ${<}" && false)
     889        $(srcdir)/baselines/calc.py $(srcdir)/baselines/$(arch)/$(<) $(<) > $@
     890
     891basic-loop$(EXEEXT):
     892        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/loop.c
     893
     894basic-function$(EXEEXT):
     895        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/function.c
     896
     897basic-fetch_add$(EXEEXT):
     898        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/fetch_add.c
     899
     900basic-ttst_lock$(EXEEXT):
     901        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/ttst_lock.c
     902
     903basic-tls-fetch_add$(EXEEXT):
     904        $(BENCH_V_CC)$(COMPILE) $(srcdir)/basic/tls_fetch_add.c
     905
     906basic$(EXEEXT): $(BASIC_DEPEND)
    839907
    840908@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT):
     
    846914ctxswitch$(EXEEXT): $(CTXSWITCH_DEPEND)
    847915
    848 ctxswitch-pthread$(EXEEXT):
    849         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/ctxswitch/pthreads.c
    850 
    851916ctxswitch-cfa_generator$(EXEEXT):
    852         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_gen.cfa
     917        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_gen.cfa
    853918
    854919ctxswitch-cfa_coroutine$(EXEEXT):
    855         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_cor.cfa
     920        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_cor.cfa
    856921
    857922ctxswitch-cfa_thread$(EXEEXT):
    858         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd.cfa
     923        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd.cfa
    859924
    860925ctxswitch-cfa_thread2$(EXEEXT):
    861         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/cfa_thrd2.cfa
     926        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/ctxswitch/cfa_thrd2.cfa
    862927
    863928ctxswitch-upp_coroutine$(EXEEXT):
    864         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_cor.cc
     929        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_cor.cc
    865930
    866931ctxswitch-upp_thread$(EXEEXT):
    867         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/upp_thrd.cc
    868 
    869 ctxswitch-goroutine$(EXEEXT):
     932        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/ctxswitch/upp_thrd.cc
     933
     934ctxswitch-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
     939ctxswitch-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
     944ctxswitch-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
     949ctxswitch-goroutine_thread$(EXEEXT):
    870950        $(BENCH_V_GOC)go build -o a.out $(srcdir)/ctxswitch/goroutine.go
     951
     952ctxswitch-rust_thread$(EXEEXT):
     953        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/ctxswitch/rust_thrd.rs
    871954
    872955ctxswitch-java_thread$(EXEEXT):
    873956        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/ctxswitch/JavaThread.java
    874         @echo "#!/bin/sh" > a.out
    875         @echo "java JavaThread" >> a.out
    876         @chmod a+x a.out
    877 
    878 mutex$(EXEEXT) :\
    879         loop.run                        \
    880         function.run            \
    881         fetch_add.run           \
    882         mutex-pthread_lock.run  \
    883         mutex-upp.run           \
     957        echo "#!/bin/sh" > a.out
     958        echo "java JavaThread" >> a.out
     959        chmod a+x a.out
     960
     961ctxswitch-pthread$(EXEEXT):
     962        $(BENCH_V_CC)$(COMPILE) $(srcdir)/ctxswitch/pthreads.c
     963
     964mutex$(EXEEXT) :                \
    884965        mutex-cfa1.run          \
    885966        mutex-cfa2.run          \
    886967        mutex-cfa4.run          \
    887         mutex-java_thread.run
    888 
    889 mutex-pthread_lock$(EXEEXT):
    890         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=50000000 $(srcdir)/mutex/pthreads.c
     968        mutex-upp.run           \
     969        mutex-go.run            \
     970        mutex-rust.run          \
     971        mutex-java.run          \
     972        mutex-pthread.run
     973
     974mutex-pthread$(EXEEXT):
     975        $(BENCH_V_CC)$(COMPILE) $(srcdir)/mutex/pthreads.c
     976
     977mutex-cfa1$(EXEEXT):
     978        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa1.cfa
     979
     980mutex-cfa2$(EXEEXT):
     981        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa2.cfa
     982
     983mutex-cfa4$(EXEEXT):
     984        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutex/cfa4.cfa
    891985
    892986mutex-upp$(EXEEXT):
    893         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/mutex/upp.cc
    894 
    895 mutex-cfa1$(EXEEXT):
    896         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa1.cfa
    897 
    898 mutex-cfa2$(EXEEXT):
    899         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa2.cfa
    900 
    901 mutex-cfa4$(EXEEXT):
    902         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=5000000  $(srcdir)/mutex/cfa4.cfa
    903 
    904 mutex-java_thread$(EXEEXT):
     987        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/mutex/upp.cc
     988
     989mutex-go$(EXEEXT):
     990        $(BENCH_V_GOC)go build -o a.out $(srcdir)/mutex/goroutine.go
     991
     992mutex-rust$(EXEEXT):
     993        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/mutex/rust.rs
     994
     995mutex-java$(EXEEXT):
    905996        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutex/JavaThread.java
    906         @echo "#!/bin/sh" > a.out
    907         @echo "java JavaThread" >> a.out
    908         @chmod a+x a.out
    909 
    910 signal$(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 
    918 signal-pthread_cond$(EXEEXT):
    919         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=500000  $(srcdir)/schedint/pthreads.c
    920 
    921 signal-upp$(EXEEXT):
    922         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedint/upp.cc
    923 
    924 signal-cfa1$(EXEEXT):
    925         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa1.cfa
    926 
    927 signal-cfa2$(EXEEXT):
    928         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa2.cfa
    929 
    930 signal-cfa4$(EXEEXT):
    931         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedint/cfa4.cfa
    932 
    933 signal-java_thread$(EXEEXT):
     997        echo "#!/bin/sh" > a.out
     998        echo "java JavaThread" >> a.out
     999        chmod a+x a.out
     1000
     1001schedint$(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
     1010schedint-cfa1$(EXEEXT):
     1011        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa1.cfa
     1012
     1013schedint-cfa2$(EXEEXT):
     1014        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa2.cfa
     1015
     1016schedint-cfa4$(EXEEXT):
     1017        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedint/cfa4.cfa
     1018
     1019schedint-upp$(EXEEXT):
     1020        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedint/upp.cc
     1021
     1022schedint-rust$(EXEEXT):
     1023        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/schedint/rust.rs
     1024
     1025schedint-java$(EXEEXT):
    9341026        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/schedint/JavaThread.java
    935         @echo "#!/bin/sh" > a.out
    936         @echo "java JavaThread" >> a.out
    937         @chmod a+x a.out
    938 
    939 waitfor$(EXEEXT) :\
    940         waitfor-upp.run         \
    941         waitfor-cfa1.run                \
    942         waitfor-cfa2.run                \
    943         waitfor-cfa4.run
    944 
    945 waitfor-upp$(EXEEXT):
    946         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=5000000 $(srcdir)/schedext/upp.cc
    947 
    948 waitfor-cfa1$(EXEEXT):
    949         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa1.cfa
    950 
    951 waitfor-cfa2$(EXEEXT):
    952         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa2.cfa
    953 
    954 waitfor-cfa4$(EXEEXT):
    955         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=500000  $(srcdir)/schedext/cfa4.cfa
    956 
    957 creation$(EXEEXT) :\
    958         creation-pthread.run                    \
     1027        echo "#!/bin/sh" > a.out
     1028        echo "java JavaThread" >> a.out
     1029        chmod a+x a.out
     1030
     1031schedint-pthread$(EXEEXT):
     1032        $(BENCH_V_CC)$(COMPILE) $(srcdir)/schedint/pthreads.c
     1033
     1034schedext$(EXEEXT) :             \
     1035        schedext-cfa1.run       \
     1036        schedext-cfa2.run       \
     1037        schedext-cfa4.run       \
     1038        schedext-upp.run        \
     1039        schedext-goroutine.run
     1040
     1041schedext-cfa1$(EXEEXT):
     1042        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa1.cfa
     1043
     1044schedext-cfa2$(EXEEXT):
     1045        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa2.cfa
     1046
     1047schedext-cfa4$(EXEEXT):
     1048        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/schedext/cfa4.cfa
     1049
     1050schedext-upp$(EXEEXT):
     1051        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/schedext/upp.cc
     1052
     1053schedext-goroutine$(EXEEXT):
     1054        $(BENCH_V_GOC)go build -o a.out $(srcdir)/schedext/goroutine.go
     1055
     1056creation$(EXEEXT) :                             \
     1057        creation-cfa_generator.run              \
    9591058        creation-cfa_coroutine.run              \
    9601059        creation-cfa_coroutine_eager.run        \
     
    9621061        creation-upp_coroutine.run              \
    9631062        creation-upp_thread.run                 \
    964         creation-goroutine.run                  \
    965         creation-java_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
     1070creation-cfa_generator$(EXEEXT):
     1071        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_gen.cfa
    9661072
    9671073creation-cfa_coroutine$(EXEEXT):
    968         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa
     1074        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa
    9691075
    9701076creation-cfa_coroutine_eager$(EXEEXT):
    971         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_cor.cfa  -DEAGER
     1077        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_cor.cfa  -DEAGER
    9721078
    9731079creation-cfa_thread$(EXEEXT):
    974         $(BENCH_V_CFA)$(CFACOMPILE) -DBENCH_N=10000000 $(srcdir)/creation/cfa_thrd.cfa
     1080        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/creation/cfa_thrd.cfa
    9751081
    9761082creation-upp_coroutine$(EXEEXT):
    977         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_cor.cc
     1083        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_cor.cc
    9781084
    9791085creation-upp_thread$(EXEEXT):
    980         $(BENCH_V_UPP)$(UPPCOMPILE) -DBENCH_N=50000000 $(srcdir)/creation/upp_thrd.cc
    981 
    982 creation-pthread$(EXEEXT):
    983         $(BENCH_V_CC)$(COMPILE)    -DBENCH_N=250000   $(srcdir)/creation/pthreads.c
    984 
    985 creation-goroutine$(EXEEXT):
     1086        $(BENCH_V_UPP)$(UPPCOMPILE) $(srcdir)/creation/upp_thrd.cc
     1087
     1088creation-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
     1093creation-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
     1098creation-goroutine_thread$(EXEEXT):
    9861099        $(BENCH_V_GOC)go build -o a.out $(srcdir)/creation/goroutine.go
     1100
     1101creation-rust_thread$(EXEEXT):
     1102        $(BENCH_V_RUSTC)rustc -C opt-level=3 -o a.out $(srcdir)/creation/rust_thrd.rs
    9871103
    9881104creation-java_thread$(EXEEXT):
    9891105        $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/creation/JavaThread.java
    990         @echo "#!/bin/sh" > a.out
    991         @echo "java JavaThread" >> a.out
    992         @chmod a+x a.out
    993 
    994 compile$(EXEEXT) :\
     1106        echo "#!/bin/sh" > a.out
     1107        echo "java JavaThread" >> a.out
     1108        chmod a+x a.out
     1109
     1110creation-pthread$(EXEEXT):
     1111        $(BENCH_V_CC)$(COMPILE) $(srcdir)/creation/pthreads.c
     1112
     1113compile$(EXEEXT) :              \
    9951114        compile-array.make      \
    9961115        compile-attributes.make \
     
    10031122
    10041123compile-array$(EXEEXT):
    1005         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
     1124        $(CFACOMPILE) -fsyntax-only -w $(testdir)/array.cfa
    10061125
    10071126compile-attributes$(EXEEXT):
    1008         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
     1127        $(CFACOMPILE) -fsyntax-only -w $(testdir)/attributes.cfa
    10091128
    10101129compile-empty$(EXEEXT):
    1011         @$(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
     1130        $(CFACOMPILE) -fsyntax-only -w $(srcdir)/compile/empty.cfa
    10121131
    10131132compile-expression$(EXEEXT):
    1014         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
     1133        $(CFACOMPILE) -fsyntax-only -w $(testdir)/expression.cfa
    10151134
    10161135compile-io$(EXEEXT):
    1017         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
     1136        $(CFACOMPILE) -fsyntax-only -w $(testdir)/io1.cfa
    10181137
    10191138compile-monitor$(EXEEXT):
    1020         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
     1139        $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/monitor.cfa
    10211140
    10221141compile-operators$(EXEEXT):
    1023         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
     1142        $(CFACOMPILE) -fsyntax-only -w $(testdir)/operators.cfa
    10241143
    10251144compile-thread$(EXEEXT):
    1026         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
     1145        $(CFACOMPILE) -fsyntax-only -w $(testdir)/concurrent/thread.cfa
    10271146
    10281147compile-typeof$(EXEEXT):
    1029         @$(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     1148        $(CFACOMPILE) -fsyntax-only -w $(testdir)/typeof.cfa
     1149
     1150size$(EXEEXT) : size-cfa.runquiet
     1151
     1152size-cfa$(EXEEXT):
     1153        $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/size/size.cfa
    10301154
    10311155# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • benchmark/bench.h

    r71d6bd8 r7030dab  
    55#endif
    66        #include <stdlib.h>
    7         #include <unistd.h>                                     // sysconf
     7        #include <stdint.h>                             // uint64_t
     8        #include <unistd.h>                             // sysconf
    89#if ! defined(__cforall)
    910        #include <time.h>
     
    1516
    1617
    17 static 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
     18static 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
    3223
    3324#ifndef BENCH_N
    34 #define BENCH_N 500 //10000000
     25#define BENCH_N 10000000
    3526#endif
    3627
     28size_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
    3736#define BENCH(statement, output)                \
    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;       \
     37        uint64_t StartTime, EndTime;            \
    4438        StartTime = bench_time();               \
    45         statement;                                      \
     39        statement;                              \
    4640        EndTime = bench_time();                 \
    47         double output =         \
    48             (double)( EndTime - StartTime ) / n;
     41        double output = (double)( EndTime - StartTime ) / times;
     42
    4943
    5044#if defined(__cforall)
     
    5347}
    5448#endif
     49#if defined(__U_CPLUSPLUS__)
     50unsigned int uDefaultPreemption() {
     51        return 0;
     52}
     53#endif
  • benchmark/creation/JavaThread.java

    r71d6bd8 r7030dab  
    2626        static int x = 2;
    2727
    28         static private final int NoOfTimes = Integer.parseInt("10000") ;
     28        static private int times = 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 <= NoOfTimes; i += 1) {
     35                for(int i = 1; i <= times; i += 1) {
    3636                        MyThread m = new MyThread();
    3737                        x = nextRandom( x );
     
    4444                helper();
    4545                long end = System.nanoTime();
    46                 System.out.println( (end - start) / NoOfTimes );
     46                System.out.println( (end - start) / times );
    4747        }
    4848        public static void main(String[] args) throws InterruptedException {
    49                 for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
     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 ; ) {
    5053                        InnerMain();
    51                         Thread.sleep(2000);     // 2 seconds
     54                        Thread.sleep(2000);             // 2 seconds
    5255                        x = nextRandom(x);
    5356                }
     
    5558        }
    5659}
     60
     61// Local Variables: //
     62// tab-width: 4 //
     63// End: //
  • benchmark/creation/cfa_cor.cfa

    r71d6bd8 r7030dab  
    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[]) {
     14int main( int argc, char * argv[] ) {
     15        BENCH_START()
    1516        BENCH(
    16                 for ( i; n ) {
    17                         MyCoroutine m;
     17                for ( times ) {
     18                        MyCoroutine c;
    1819                },
    1920                result
    2021        )
     22        printf( "%g\n", result );
     23}
    2124
    22         printf("%g\n", result);
    23 }
     25// Local Variables: //
     26// tab-width: 4 //
     27// End: //
  • benchmark/creation/cfa_thrd.cfa

    r71d6bd8 r7030dab  
    77void main(MyThread &) {}
    88
    9 int main(int argc, char* argv[]) {
     9int main( int argc, char * argv[] ) {
     10        BENCH_START()
    1011        BENCH(
    11                 for ( i; n ) {
     12                for ( times ) {
    1213                        MyThread m;
    1314                },
    1415                result
    1516        )
     17        printf( "%g\n", result );
     18}
    1619
    17         printf("%g\n", result);
    18 }
     20// Local Variables: //
     21// tab-width: 4 //
     22// End: //
  • benchmark/creation/goroutine.go

    r71d6bd8 r7030dab  
    22
    33import (
    4     "fmt"
    5     "time"
     4        "fmt"
     5        "time"
     6        "os"
     7        "strconv"
    68)
    79
     
    1719
    1820func main() {
    19         const NoOfTimes = 500000
     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
    2025        start := time.Now()
    21         for i := 1; i <= NoOfTimes; i += 1 {
     26        for i := 1; i <= times; i += 1 {
    2227                go noop()               // creation
     28                <- shake                // wait for completion
    2329        }
    2430        end := time.Now()
    25         fmt.Printf("%d\n", end.Sub(start) / time.Duration(NoOfTimes))
    26         <- shake
     31        fmt.Printf( "%d\n", end.Sub(start) / time.Duration(times) )
    2732}
     33
     34// Local Variables: //
     35// tab-width: 4 //
     36// End: //
  • benchmark/creation/pthreads.c

    r71d6bd8 r7030dab  
    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[]) {
     10int main( int argc, char * argv[] ) {
     11        BENCH_START()
    1112        BENCH(
    12                 for (size_t i = 0; i < n; i++) {
     13                for (size_t i = 0; i < times; i++) {
    1314                        pthread_t thread;
    1415                        if (pthread_create(&thread, NULL, foo, NULL) < 0) {
     
    1617                                return 1;
    1718                        }
    18 
    1919                        if (pthread_join( thread, NULL) < 0) {
    2020                                perror( "failure" );
     
    2424                result
    2525        )
     26        printf( "%g\n", result );
     27}
    2628
    27         printf("%g\n", result);
    28 }
     29// Local Variables: //
     30// tab-width: 4 //
     31// End: //
  • benchmark/creation/upp_cor.cc

    r71d6bd8 r7030dab  
    55_Coroutine MyCor {
    66        void main() {}
     7  public:
     8        MyCor() { resume(); }
    79};
    810
    9 int main(int argc, char* argv[]) {
     11int main( int argc, char * argv[] ) {
     12        BENCH_START()
    1013        BENCH(
    11                 for (size_t i = 0; i < n; i++) {
     14                for (size_t i = 0; i < times; i++) {
    1215                        MyCor m;
    1316                },
    1417                result
    1518        )
     19        printf( "%g\n", result );
     20}
    1621
    17         printf("%g\n", result);
    18 }
     22// Local Variables: //
     23// tab-width: 4 //
     24// End: //
  • benchmark/creation/upp_thrd.cc

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

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

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

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

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

    r71d6bd8 r7030dab  
    33#include "bench.h"
    44
    5 int main(int argc, char* argv[]) {
     5int main( int argc, char * argv[] ) {
     6        BENCH_START()
    67        BENCH(
    7                 for ( i; n ) {
     8                for ( times ) {
    89                        yield();
    910                },
    1011                result
    1112        )
     13        printf( "%g\n", result );
     14}
    1215
    13         printf("%g\n", result);
    14 }
     16// Local Variables: //
     17// tab-width: 4 //
     18// End: //
  • benchmark/ctxswitch/cfa_thrd2.cfa

    r71d6bd8 r7030dab  
    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[]) {
     15int main( int argc, char * argv[] ) {
     16        BENCH_START()
    1617        Fibre f1;
    1718        BENCH(
    18                 for ( i; n ) {
     19                for ( times ) {
    1920                        yield();
    2021                },
    2122                result
    2223        )
     24        printf( "%g\n", result );
     25        done = true;
     26}
    2327
    24         printf("%g\n", result);
    25         done = true;
    26         return 0;
    27 }
     28// Local Variables: //
     29// tab-width: 4 //
     30// End: //
  • benchmark/ctxswitch/goroutine.go

    r71d6bd8 r7030dab  
    22
    33import (
    4     "fmt"
    5     "runtime"
    6     "time"
     4        "fmt"
     5        "time"
     6        "os"
     7        "strconv"
     8        "runtime"
    79)
    810
     
    2830
    2931func main() {
    30         const NoOfTimes = 10000000
    31         go ContextSwitch( NoOfTimes )           // context switch
     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
    3236        <- shake
    3337}
     38
     39// Local Variables: //
     40// tab-width: 4 //
     41// End: //
  • benchmark/ctxswitch/kos_fibre.cpp

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

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

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

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

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

    r71d6bd8 r7030dab  
    2626        static int x = 2;
    2727
    28         static private final int NoOfTimes = Integer.parseInt("100000000") ;
     28        static private int times = 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 <= NoOfTimes; i += 1) {
     37                for(int i = 1; i <= times; i += 1) {
    3838                        x = nextRandom(x);
    3939                        j.noop();
     
    4444                helper();
    4545                long end = System.nanoTime();
    46                 System.out.println( (end - start) / NoOfTimes );
     46                System.out.println( (end - start) / times );
    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
    4952                for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
    5053                        InnerMain();
     
    5558        }
    5659}
     60
     61// Local Variables: //
     62// tab-width: 4 //
     63// End: //
  • benchmark/mutex/cfa1.cfa

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

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

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

    r71d6bd8 r7030dab  
    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 
    13 int main(int argc, char* argv[]) {
     12int main( int argc, char * argv[] ) {
     13        BENCH_START()
    1414        BENCH(
    15                 for (size_t i = 0; i < n; i++) {
     15                for ( size_t i = 0; i < times; i++ ) {
    1616                        call();
    1717                },
    1818                result
    1919        )
     20        printf( "%g\n", result );
     21}
    2022
    21         printf("%g\n", result);
    22 }
     23// Local Variables: //
     24// tab-width: 4 //
     25// End: //
  • benchmark/mutex/upp.cc

    r71d6bd8 r7030dab  
    88};
    99
    10 int main(int argc, char* argv[]) {
     10int main( int argc, char * argv[] ) {
     11        BENCH_START()
    1112        MyMonitor m;
    1213        BENCH(
    13                 for (size_t i = 0; i < n; i++) {
     14                for ( size_t i = 0; i < times; i++ ) {
    1415                        m.call();
    1516                },
    1617                result
    1718        )
     19        printf( "%g\n", result );
     20}
    1821
    19         printf("%g\n", result);
    20 }
     22// Local Variables: //
     23// tab-width: 4 //
     24// End: //
  • benchmark/schedext/cfa1.cfa

    r71d6bd8 r7030dab  
    44#include <stdio.h>
    55
    6 #include "bench.h"
     6#include "../bench.h"
    77
    8 int argc;
    9 char** argv;
    10 volatile int go = 0;
     8monitor M {} m1;
    119
    12 monitor M {};
    13 M m1;
    14 
    15 void __attribute__((noinline)) call( M & mutex a1 ) {}
    16 
    17 int  __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;
     10void __attribute__((noinline)) call( M & mutex p1 ) {}
     11void __attribute__((noinline)) wait( M & mutex p1 ) {
     12        for ( times ) {
     13                waitfor( call : p1 );
     14        }
    2915}
    3016
    3117thread T {};
    32 void ^?{}( T & mutex this ) {}
    3318void main( T & ) {
    34         while(go == 0) { yield(); }
    35         while(go == 1) { call(m1); }
    36 
     19        BENCH(
     20                for ( times ) { call( m1 ); },
     21                result
     22        )
     23        printf( "%g\n", result );
    3724}
    3825
    39 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     26int main( int argc, char * argv[] ) {
     27        BENCH_START()
    4028        T t;
    41         return wait(m1);
     29        wait( m1 );
    4230}
     31
     32// Local Variables: //
     33// tab-width: 4 //
     34// End: //
  • benchmark/schedext/cfa2.cfa

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

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

    r71d6bd8 r7030dab  
    33#include "bench.h"
    44
    5 int argc;
    6 char** argv;
    7 volatile int go = 0;
    8 
    95_Monitor M {
    106public:
    117        void __attribute__((noinline)) call() {}
     8        void __attribute__((noinline)) wait() {
     9                for ( size_t i = 0; i < times; i++ ) {
     10                        _Accept(call);
     11                }
     12        }
     13} m;
    1214
    13         int __attribute__((noinline)) wait() {
    14                 go = 1;
     15_Task T {
     16        void main() {
    1517                BENCH(
    16                         for (size_t i = 0; i < n; i++) {
    17                                 _Accept(call);
     18                        for ( size_t i = 0; i < times; i++ ) {
     19                                m.call();
    1820                        },
    1921                        result
    2022                )
    21 
    22                 printf("%g\n", result);
    23                 go = 0;
    24                 return 0;
     23                printf( "%g\n", result );
    2524        }
    2625};
    2726
    28 M m;
     27int main( int argc, char * argv[] ) {
     28        BENCH_START()
     29        T t;
     30        m.wait();
     31}
    2932
    30 _Task T {
    31         void main() {
    32                 while(go == 0) { yield(); }
    33                 while(go == 1) { m.call(); }
    34 
    35         }
    36 };
    37 
    38 int main(int margc, char* margv[]) {
    39         argc = margc;
    40         argv = margv;
    41         T t;
    42         return m.wait();
    43 }
     33// Local Variables: //
     34// tab-width: 4 //
     35// End: //
  • benchmark/schedint/JavaThread.java

    r71d6bd8 r7030dab  
    4949        static int x = 2;
    5050
    51         static private final int NoOfTimes = Integer.parseInt("1000000") ;
     51        static private int times = Integer.parseInt("1000000");
    5252
    5353        public static void helper( Monitor m ) throws InterruptedException {
    54                 for(int i = 1; i <= NoOfTimes; i += 1) {
     54                for(int i = 1; i <= times; i += 1) {
    5555                        m.wait();               // relase monitor lock
    5656                        m.next = true;
     
    6363                synchronized(m) {
    6464                        s.start();
    65                         while( !Monitor.go ) {
     65                        while( ! Monitor.go ) { // waiter must start first
    6666                                Thread.yield();
    6767                        }
     
    7272                Monitor.go = false;
    7373                s.join();
    74                 System.out.println( (end - start) / NoOfTimes);
     74                System.out.println( (end - start) / times);
    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
    7780                for (int n = Integer.parseInt("5"); --n >= 0 ; ) {
    7881                        InnerMain();
     
    8386        }
    8487}
     88
     89// Local Variables: //
     90// tab-width: 4 //
     91// End: //
  • benchmark/schedint/cfa1.cfa

    r71d6bd8 r7030dab  
    44#include <stdio.h>
    55
    6 #include "bench.h"
     6#include "../bench.h"
    77
    8 int argc;
    9 char** argv;
    108volatile int go = 0;
    119
    1210condition c;
    13 monitor M {};
    14 M m1;
     11monitor M {} m1;
    1512
    16 void __attribute__((noinline)) call( M & mutex a1 ) {
    17         signal(c);
     13void __attribute__((noinline)) call( M & mutex p1 ) {
     14        signal( c );
    1815}
    19 
    20 int  __attribute__((noinline)) wait( M & mutex a1 ) {
     16void __attribute__((noinline)) wait( M & mutex p1 ) {
    2117        go = 1;
    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;
     18        for ( times ) {
     19                wait( c );
     20        }
    3221}
    3322
    3423thread T {};
    35 void ^?{}( T & mutex ) {}
    3624void main( T & ) {
    37         while(go == 0) { yield(); }
    38         while(go == 1) { call(m1); }
    39 
     25        while ( go == 0 ) { yield(); } // waiter must start first
     26        BENCH(
     27                for ( times ) { call( m1 ); },
     28                result
     29        )
     30        printf( "%g\n", result );
    4031}
    4132
    42 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     33int main( int argc, char * argv[] ) {
     34        BENCH_START()
    4335        T t;
    44         return wait(m1);
     36        wait( m1 );
    4537}
     38
     39// Local Variables: //
     40// tab-width: 4 //
     41// End: //
  • benchmark/schedint/cfa2.cfa

    r71d6bd8 r7030dab  
    44#include <stdio.h>
    55
    6 #include "bench.h"
     6#include "../bench.h"
    77
    8 int argc;
    9 char** argv;
    108volatile int go = 0;
    119
    1210condition c;
    13 monitor M {};
    14 M m1, m2;
     11monitor M {} m1, m2;
    1512
    16 void __attribute__((noinline)) call( M & mutex a1, M & mutex a2 ) {
    17         signal(c);
     13void __attribute__((noinline)) call( M & mutex p1, M & mutex p2 ) {
     14        signal( c );
    1815}
    19 
    20 int  __attribute__((noinline)) wait( M & mutex a1, M & mutex a2 ) {
     16void __attribute__((noinline)) wait( M & mutex p1, M & mutex p2 ) {
    2117        go = 1;
    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;
     18        for ( times ) {
     19                wait( c );
     20        }
    3221}
    3322
    3423thread T {};
    35 void ^?{}( T & mutex this ) {}
    3624void main( T & ) {
    37         while(go == 0) { yield(); }
    38         while(go == 1) { call(m1, m2); }
    39 
     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 );
    4031}
    4132
    42 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     33int main( int argc, char * argv[] ) {
     34        BENCH_START()
    4335        T t;
    44         return wait(m1, m2);
     36        wait( m1, m2 );
    4537}
     38
     39// Local Variables: //
     40// tab-width: 4 //
     41// End: //
  • benchmark/schedint/cfa4.cfa

    r71d6bd8 r7030dab  
    44#include <stdio.h>
    55
    6 #include "bench.h"
     6#include "../bench.h"
    77
    8 int argc;
    9 char** argv;
    108volatile int go = 0;
    119
    1210condition c;
    13 monitor M {};
    14 M m1, m2, m3, m4;
     11monitor M {} m1, m2, m3, m4;
    1512
    16 void __attribute__((noinline)) call( M & mutex a1, M & mutex a2, M & mutex a3, M & mutex a4 ) {
    17         signal(c);
     13void __attribute__((noinline)) call( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {
     14        signal( c );
    1815}
    19 
    20 int  __attribute__((noinline)) wait( M & mutex a1, M & mutex a2, M & mutex a3, M & mutex a4 ) {
     16void __attribute__((noinline)) wait( M & mutex p1, M & mutex p2, M & mutex p3, M & mutex p4 ) {
    2117        go = 1;
    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;
     18        for ( times ) {
     19                wait( c );
     20        }
    3221}
    3322
    3423thread T {};
    35 void ^?{}( T & mutex this ) {}
    3624void main( T & ) {
    37         while(go == 0) { yield(); }
    38         while(go == 1) { call(m1, m2, m3, m4); }
    39 
     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 );
    4031}
    4132
    42 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     33int main( int argc, char * argv[] ) {
     34        BENCH_START()
    4335        T t;
    44         return wait(m1, m2, m3, m4);
     36        wait( m1, m2, m3, m4 );
    4537}
     38
     39// Local Variables: //
     40// tab-width: 4 //
     41// End: //
  • benchmark/schedint/pthreads.c

    r71d6bd8 r7030dab  
    44#include "bench.h"
    55
    6 int argc;
    7 char** argv;
    86volatile int go = 0;
    97
     8pthread_mutex_t m;
    109pthread_cond_t c;
    11 pthread_mutex_t m;
    1210
    1311void __attribute__((noinline)) call() {
    14         pthread_mutex_lock(&m);
    15         pthread_cond_signal(&c);
    16         pthread_mutex_unlock(&m);
     12        pthread_mutex_lock( &m );
     13        pthread_cond_signal( &c );
     14        pthread_mutex_unlock( &m );
    1715}
    1816
    19 int __attribute__((noinline)) wait() {
     17void __attribute__((noinline)) wait() {
    2018        pthread_mutex_lock(&m);
    2119        go = 1;
     20        for ( size_t i = 0; i < times; i++ ) {
     21                pthread_cond_wait( &c, &m );
     22        }
     23        go = 0;
     24        pthread_mutex_unlock( &m );
     25}
     26
     27void * 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
    2230        BENCH(
    23                 for (size_t i = 0; i < n; i++) {
    24                         pthread_cond_wait(&c, &m);
    25                 },
     31                while ( go == 1 ) { call(); },
    2632                result
    2733        )
    28 
    29         printf("%g\n", result);
    30         go = 0;
    31         pthread_mutex_unlock(&m);
    32         return 0;
    33 }
    34 
    35 void* thread_main(__attribute__((unused)) void * arg ) {
    36         while(go == 0) { sched_yield(); }
    37         while(go == 1) { call(); }
     34        printf( "%g\n", result );
    3835        return NULL;
    3936}
    4037
    41 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
     38int main( int argc, char * argv[] ) {
     39        BENCH_START()
    4240        pthread_t thread;
    43         if (pthread_create(&thread, NULL, thread_main, NULL) < 0) {
     41        if ( pthread_create( &thread, NULL, thread_main, NULL ) < 0 ) {
    4442                perror( "failure" );
    4543                return 1;
    4644        }
    4745        wait();
    48         if (pthread_join( thread, NULL) < 0) {
     46        if ( pthread_join( thread, NULL ) < 0 ) {
    4947                perror( "failure" );
    5048                return 1;
    5149        }
    52         return 0;
    5350}
     51
     52// Local Variables: //
     53// tab-width: 4 //
     54// End: //
  • benchmark/schedint/upp.cc

    r71d6bd8 r7030dab  
    33#include "bench.h"
    44
    5 int argc;
    6 char** argv;
    75volatile int go = 0;
    86
     
    1311                cond.signal();
    1412        }
     13        void __attribute__((noinline)) wait() {
     14                go = 1;
     15                for ( size_t i = 0; i < times; i++ ) {
     16                        cond.wait();
     17                }
     18        }
     19} m;
    1520
    16         int __attribute__((noinline)) wait() {
    17                 go = 1;
     21_Task T {
     22        void main() {
     23                while ( go == 0 ) { yield(); } // waiter must start first
    1824                BENCH(
    19                         for (size_t i = 0; i < n; i++) {
    20                                 cond.wait();
     25                        for ( size_t i = 0; i < times; i++ ) {
     26                                m.call();
    2127                        },
    2228                        result
    2329                )
    24 
    25                 printf("%g\n", result);
    26                 go = 0;
    27                 return 0;
     30                printf( "%g\n", result );
    2831        }
    2932};
    3033
    31 M m;
     34int main( int argc, char * argv[] ) {
     35        BENCH_START()
     36        T t;
     37        m.wait();
     38}
    3239
    33 _Task T {
    34         void main() {
    35                 while(go == 0) { yield(); }
    36                 while(go == 1) { m.call(); }
    37 
    38         }
    39 };
    40 
    41 int main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[]) {
    42         T t;
    43         return m.wait();
    44 }
     40// Local Variables: //
     41// tab-width: 4 //
     42// End: //
  • configure

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

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

    r71d6bd8 r7030dab  
    99%    Predefined journal names:
    1010%  acmcs: Computing Surveys             acta: Acta Infomatica
    11 @string{acta="Acta Infomatica"}
    1211%  cacm: Communications of the ACM
    1312%  ibmjrd: IBM J. Research & Development ibmsj: IBM Systems Journal
     
    2221%  tcs: Theoretical Computer Science
    2322
     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},
    126156}
    127157
     
    398428    journal     = sigplan,
    399429    year        = 1981,
    400     month       = feb, volume = 16, number = 2, pages = {48-52},
     430    month       = feb,
     431    volume      = 16,
     432    number      = 2,
     433    pages       = {48-52},
    401434    comment     = {
    402435        A one-pass, top-down algorithm for overload resolution.  Input is a
     
    477510    title       = {An Alternative to Subclassing},
    478511    journal     = sigplan,
    479     volume      = {21},    number = {11},
     512    volume      = {21},
     513    number      = {11},
    480514    pages       = {424-428},
    481     month       = nov, year = 1986,
     515    month       = nov,
     516    year        = 1986,
    482517    comment     = {
    483518        The Smalltalk class hierarchy has three uses: factoring out code;
     
    533568    isbn        = {3-540-66538-2},
    534569    location    = {Toulouse, France},
    535     doi         = {http://doi.acm.org/10.1145/318773.319251},
    536570    publisher   = {Springer},
    537571    address     = {London, UK},
     
    631665    year        = 2010,
    632666    pages       = {39--50},
    633     numpages    = {12},
    634667    publisher   = {IEEE Computer Society},
    635668    address     = {Washington, DC, USA},
     
    922955}
    923956
     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
    924968@manual{C11,
    925969    keywords    = {ISO/IEC C 11},
     
    13051349    location    = {London, United Kingdom},
    13061350    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},
    13111351    publisher   = {ACM},
    13121352    address     = {New York, NY, USA},
     
    24082448    year        = 1993,
    24092449    pages       = {201--208},
    2410     url         = {http://doi.acm.org/10.1145/155360.155580},
    24112450    publisher   = {ACM},
    24122451    address     = {New York, NY, USA},
     
    26062645    location    = {Boulder, Colorado, USA},
    26072646    pages       = {91--97},
    2608     numpages    = {7},
    26092647    publisher   = {ACM},
    26102648    address     = {New York, NY, USA},
     
    26372675    issn        = {0004-5411},
    26382676    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},
    26432677    publisher   = {ACM},
    26442678    address     = {New York, NY, USA},
     
    27082742}
    27092743
     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
    27102756@misc{Turley99,
    27112757    keywords    = {embedded system, micrprocessor},
     
    27182764    howpublished= {\href{https://www.eetimes.com/author.asp?sectionid=36&doc_id=1287712}
    27192765                  {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},
    27202779}
    27212780
     
    31373196}
    31383197
     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
    31393213@article{Lamport87,
    31403214    keywords    = {software solutions, mutual exclusion, fast},
     
    32583332    issn        = {0001-0782},
    32593333    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},
    32643334    publisher   = {ACM},
    32653335    address     = {New York, NY, USA},
     
    36643734}
    36653735
     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
    36663745@article{katzenelson83b,
    36673746    contributer = {gjditchfield@plg},
     
    36973776    pages       = {115-138},
    36983777    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},
    36993789}
    37003790
     
    43654455}
    43664456
     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
    43674468@mastersthesis{Clarke90,
    43684469    keywords    = {concurrency, postponing requests},
     
    44574558
    44584559@article{Pierce00,
    4459     keywords    = {Scala},
     4560    keywords    = {Scala, polymorphism, subtyping, type inference},
    44604561    contributer = {a3moss@uwaterloo.ca},
    44614562    author      = {Pierce, Benjamin C. and Turner, David N.},
     
    44694570    issn        = {0164-0925},
    44704571    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},
    44754572    publisher   = {ACM},
    44764573    address     = {New York, NY, USA},
    4477     keywords    = {polymorphism, subtyping, type inference},
    44784574}
     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}
    44794590
    44804591@article{Sundell08,
     
    45544665    journal     = sigplan,
    45554666    year        = 1989,
    4556     month       = jun, volume = 24, number = 6, pages = {37-48},
     4667    month       = jun,
     4668    volume      = 24,
     4669    number      = 6,
     4670    pages       = {37-48},
    45574671    abstract    = {
    45584672        This paper describes a scheme we have used to manage a large
     
    49955109    year        = 1986,
    49965110    pages       = {313--326},
    4997     numpages    = {14},
    49985111    publisher   = {ACM},
    49995112    address     = {New York, NY, USA},
     
    50115124    year        = 1986,
    50125125    pages       = {327--348},
    5013     numpages    = {22},
    50145126    publisher   = {ACM},
    50155127    address     = {New York, NY, USA},
     
    52085320    year        = 2005,
    52095321    pages       = {146-196},
    5210     numpages    = {51},
    52115322    publisher   = {ACM},
    52125323    address     = {New York, NY, USA},
     
    53545465    year        = 2000,
    53555466    pages       = {29-46},
    5356     note        = {OOPSLA'00, Oct. 15--19, 2000, Minneapolis, Minnesota, U.S.A.},
     5467    note        = {OOPSLA'00, Oct. 15--19, 2000, Minneapolis, Minn., U.S.A.},
    53575468}
    53585469
     
    54685579    location    = {San Diego, California, USA},
    54695580    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},
    54745581    publisher   = {ACM},
    54755582    address     = {New York, NY, USA},
     
    55755682    issn        = {0362-1340},
    55765683    pages       = {30--42},
    5577     numpages    = {13},
    5578     url         = {http://doi.acm.org/10.1145/947586.947589},
    5579     doi         = {10.1145/947586.947589},
    55805684    publisher   = {ACM},
    55815685    address     = {New York, NY, USA}
     
    61126216    month       = 9,
    61136217    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},
    61146232}
    61156233
     
    64996617    issn        = {0164-0925},
    65006618    pages       = {429-475},
    6501     url         = {http://doi.acm.org/10.1145/1133651.1133653},
    6502     doi         = {10.1145/1133651.1133653},
    6503     acmid       = {1133653},
    65046619    publisher   = {ACM},
    65056620    address     = {New York, NY, USA},
     
    68796994    issn        = {0001-0782},
    68806995    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},
    68856996    publisher   = {ACM},
    68866997    address     = {New York, NY, USA}
     
    69007011    issn        = {0362-1340},
    69017012    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},
    69067013    publisher   = {ACM},
    69077014    address     = {New York, NY, USA},
     
    70067113    issn        = {0362-1340},
    70077114    pages       = {82--87},
    7008     numpages    = {6},
    7009     url         = {http://doi.acm.org/10.1145/947680.947688},
    7010     doi         = {10.1145/947680.947688},
    70117115    publisher   = {ACM},
    70127116    address     = {New York, NY, USA},
     
    71537257}
    71547258
     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
    71557272@article{Dijkstra65a,
    71567273    keywords    = {N-thread software-solution mutual exclusion},
     
    73637480    year        = 1974,
    73647481    pages       = {261-301},
    7365     issn        = {0360-0300},
    7366     doi         = {http://doi.acm.org/10.1145/356635.356640},
    73677482    publisher   = {ACM},
    73687483    address     = {New York, NY, USA},
     
    74547569    publisher   = {ACM Press},
    74557570    address     = {New York, NY, USA},
    7456     doi         = {http://doi.acm.org/10.1145/356586.356588},
    74577571}
    74587572
     
    77557869    howpublished= {\href{https://projects.eclipse.org/proposals/trace-compass}{https://\-projects.eclipse.org/\-proposals/\-trace-compass}},
    77567870}
    7757  
     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
    77587883@article{Leroy00,
    77597884    keywords    = {type-systems, exceptions},
     
    78057930    number      = {2},
    78067931    pages       = {204-214},
    7807     month       = apr, year = 1988,
     7932    month       = apr,
     7933    year        = 1988,
    78087934    comment     = {
    78097935        Extended record types add fields to their base record.  Assignment
     
    81108236    issn        = {0004-5411},
    81118237    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},
    81168238    publisher   = {ACM},
    81178239    address     = {New York, NY, USA},
     
    81268248    contributer = {pabuhr@plg},
    81278249    author      = {Boehm, Hans-J. and Adve, Sarita V.},
    8128     title       = {You Don'T Know Jack About Shared Variables or Memory Models},
     8250    title       = {You Don't Know Jack About Shared Variables or Memory Models},
    81298251    journal     = cacm,
    81308252    volume      = 55,
  • doc/papers/concurrency/Paper.tex

    r71d6bd8 r7030dab  
    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{.}{\protect\ETAL}%
    135                 {\protect\ETAL.\xspace}%
     134        \@ifnextchar{.}{\ETAL}%
     135                {\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, __restrict, __restrict__, __signed, __signed__, _Static_assert, thread,
     165                otype, restrict, resume, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, 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.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
     170        literate={-}{\makebox[1ex][c]{\raisebox{0.5ex}{\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]{`}{`},
    213199}
    214200
     
    241227{}
    242228\lstnewenvironment{uC++}[1][]
    243 {\lstset{#1}}
     229{\lstset{language=uC++,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    244230{}
    245231\lstnewenvironment{Go}[1][]
     
    262248}
    263249
    264 \newbox\myboxA
    265 \newbox\myboxB
    266 \newbox\myboxC
    267 \newbox\myboxD
     250\newsavebox{\myboxA}
     251\newsavebox{\myboxB}
     252\newsavebox{\myboxC}
     253\newsavebox{\myboxD}
    268254
    269255\title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
     
    282268\CFA is a polymorphic, non-object-oriented, concurrent, backwards-compatible extension of the C programming language.
    283269This paper discusses the design philosophy and implementation of its advanced control-flow and concurrent/parallel features, along with the supporting runtime written in \CFA.
    284 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 features like pthreads.
     270These 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.
    285271\CFA introduces modern language-level control-flow mechanisms, like generators, coroutines, user-level threading, and monitors for mutual exclusion and synchronization.
    286272% Library extension for executors, futures, and actors are built on these basic mechanisms.
     
    295281
    296282\begin{document}
    297 \linenumbers                                            % comment out to turn off line numbering
     283\linenumbers                            % comment out to turn off line numbering
    298284
    299285\maketitle
     
    302288\section{Introduction}
    303289
    304 This 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.
     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".
    307295However, 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.},
    308296backwards-compatible extension of the C programming language.
    309 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 allowing immediate dissemination.
    310 Within 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}.
    311 However, \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;
    312 no high-level language concurrency features are defined.
    313 Interestingly, 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).
    314 Finally, 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 
     297In 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{
     298The 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.}
     299allowing immediate dissemination.
     300This 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.
     301The \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
     306Call/return control-flow with argument/parameter passing appeared in the first programming languages.
     307Over 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).
     308While \CFA has mechanisms for dynamic call (algebraic effects) and exceptions\footnote{
     309\CFA exception handling will be presented in a separate paper.
     310The 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}.
     312Coroutining is sequential execution requiring direct handoff among coroutines, \ie only the programmer is controlling execution order.
     313If coroutines transfer to an internal event-engine for scheduling the next coroutines, the program transitions into the realm of concurrency~\cite[\S~3]{Buhr05a}.
     314Coroutines 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}
     317Interestingly, 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).
     318While 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.
    316319In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
    317320As multi-core hardware became available in the 1980/90s, both user and kernel threading were examined.
    318321Kernel 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}.
    319322Libraries like pthreads were developed for C, and the Solaris operating-system switched from user (JDK 1.1~\cite{JDK1.1}) to kernel threads.
    320 As 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.
    321 From 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}.
    322 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 encourage large numbers of threads performing medium work units to facilitate load balancing by the runtime~\cite{Verch12}.
     323As 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.
     324From 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}.
     325The 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}.
    323326As well, user-threading facilitates a simpler concurrency approach using thread objects that leverage sequential patterns versus events with call-backs~\cite{Adya02,vonBehren03}.
    324327Finally, 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.
    325328
    326 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, \ie some language features are unsafe in the presence of aggressive sequential optimizations~\cite{Buhr95a,Boehm05}.
     329A 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}.
    327330The 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.
    328331One solution is low-level qualifiers and functions (\eg @volatile@ and atomics) allowing \emph{programmers} to explicitly write safe (race-free~\cite{Boehm12}) programs.
    329 A safer solution is high-level language constructs so the \emph{compiler} knows the optimization boundaries, and hence, provides implicit safety.
    330 This 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.
    332 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++}
    333 } and coroutines.
    334 Finally, 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 
    336 Finally, it is important for a language to provide safety over performance \emph{as the default}, allowing careful reduction of safety for performance when necessary.
    337 Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~8]{Buhr05a}) and \emph{barging}\footnote{
    338 The 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.
     332A 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.
     333While the optimization problem is best known with respect to concurrency, it applies to other complex control-flow, like exceptions and coroutines.
     334As 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
     336Finally, 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.
     337Two concurrency violations of this philosophy are \emph{spurious wakeup} (random wakeup~\cite[\S~9]{Buhr05a}) and \emph{barging}\footnote{
     338Barging is competitive succession instead of direct handoff, \ie after a lock is released both arriving and preexisting waiter threads compete to acquire the lock.
     339Hence, 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.
    339340} (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.
    340 However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~8]{Buhr05a}, it is a performance design choice.
    341 Similarly, signals-as-hints are often a performance decision.
    342 We 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.)
    344 Clawing back performance, when local non-determinism is unimportant, should be an option not the default.
    345 
    346 \begin{comment}
    347 Most 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.
    348 As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
    349 While \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.
    350 Hence, 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.
    355 We 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.
     341(Author experience teaching concurrency is that students are confused by these semantics.)
     342However, spurious wakeup is \emph{not} a foundational concurrency property~\cite[\S~9]{Buhr05a};
     343it is a performance design choice.
     344We argue removing spurious wakeup and signals-as-hints make concurrent programming simpler and safer as there is less local non-determinism to manage.
     345If 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.
     348We 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.
    356349The main contributions of this work are:
    357 \begin{itemize}[topsep=3pt,itemsep=1pt]
     350\begin{itemize}[topsep=3pt,itemsep=0pt]
    358351\item
    359 language-level generators, coroutines and user-level threading, which respect the expectations of C programmers.
     352a set of fundamental execution properties that dictate which language-level control-flow features need to be supported,
     353
    360354\item
    361 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.
     355integration of these language-level control-flow features, while respecting the style and expectations of C programmers,
     356
    362357\item
    363 providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features.
     358monitor 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
     361providing statically type-safe interfaces that integrate with the \CFA polymorphic type-system and other language features,
     362
    364363% \item
    365364% library extensions for executors, futures, and actors built on the basic mechanisms.
     365
    366366\item
    367 a runtime system with no spurious wakeup.
     367a runtime system without spurious wake-up and no performance loss,
     368
    368369\item
    369 a dynamic partitioning mechanism to segregate the execution environment for specialized requirements.
     370a 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
    370372% \item
    371373% a non-blocking I/O library
     374
    372375\item
    373 experimental results showing comparable performance of the new features with similar mechanisms in other programming languages.
     376experimental results showing comparable performance of the \CFA features with similar mechanisms in other languages.
    374377\end{itemize}
    375378
    376 Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls, which produces constructs @generator@ and @coroutine@.
    377 Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread, which produces the @thread@ construct.
     379Section~\ref{s:FundamentalExecutionProperties} presents the compositional hierarchy of execution properties directing the design of control-flow features in \CFA.
     380Section~\ref{s:StatefulFunction} begins advanced control by introducing sequential functions that retain data and execution state between calls producing constructs @generator@ and @coroutine@.
     381Section~\ref{s:Concurrency} begins concurrency, or how to create (fork) and destroy (join) a thread producing the @thread@ construct.
    378382Section~\ref{s:MutualExclusionSynchronization} discusses the two mechanisms to restricted nondeterminism when controlling shared access to resources (mutual exclusion) and timing relationships among threads (synchronization).
    379383Section~\ref{s:Monitor} shows how both mutual exclusion and synchronization are safely embedded in the @monitor@ and @thread@ constructs.
    380384Section~\ref{s:CFARuntimeStructure} describes the large-scale mechanism to structure (cluster) threads and virtual processors (kernel threads).
    381 Section~\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.
     385Section~\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
     391The features in a programming language should be composed from a set of fundamental properties rather than an ad hoc collection chosen by the designers.
     392To 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++}).
     393The fundamental properties are execution state, thread, and mutual-exclusion/synchronization (MES).
     394These 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).
     395While 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.
     396As 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.
     397If a compositional feature is missing, a programmer has too few/many fundamental properties resulting in a complex and/or is inefficient solution.
     398
     399In detail, the fundamental properties are:
     400\begin{description}[leftmargin=\parindent,topsep=3pt,parsep=0pt]
     401\item[\newterm{execution state}:]
     402is the state information needed by a control-flow feature to initialize, manage compute data and execution location(s), and de-initialize.
     403State is retained in fixed-sized aggregate structures and dynamic-sized stack(s), often allocated in the heap(s) managed by the runtime system.
     404The 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.
     405Control-flow transfers among execution states occurs in multiple ways, such as function call, context switch, asynchronous await, etc.
     406Because 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}:]
     410is execution of code that occurs independently of other execution, \ie the execution resulting from a thread is sequential.
     411Multiple threads provide \emph{concurrent execution};
     412concurrent execution becomes parallel when run on multiple processing units (hyper-threading, cores, sockets).
     413There must be language mechanisms to create, block/unblock, and join with a thread.
     414
     415\item[\newterm{MES}:]
     416is the concurrency mechanisms to perform an action without interruption and establish timing relationships among multiple threads.
     417These two properties are independent, \ie mutual exclusion cannot provide synchronization and vice versa without introducing additional threads~\cite[\S~4]{Buhr05a}.
     418Limiting 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}
     420These 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
     425Table~\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.)
     427Note, basic von Neumann execution requires at least one thread and an execution state providing some form of call stack.
     428For table entries missing these minimal components, the property is borrowed from the invoker (caller).
     429
     430Case 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.
     431Case 2 is case 1 with access to shared state so callers are restricted during update (mutual exclusion) and scheduling for other threads (synchronization).
     432Case 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.
     433Note, stackless functions still borrow the caller's stack and thread, where the stack is used to preserve state across its callees.
     434Case 4 is cases 2 and 3 with protection to shared state for stackless functions.
     435Cases 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.
     436Cases 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.
     437Cases 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.
     438Hence, once started, this kind of thread must execute to completion, \ie computation only, which severely restricts runtime management.
     439Cases 11 and 12 have a stackful thread with and without safe access to shared state.
     440Execution 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
     451stateful                        & thread        & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\
     452\hline   
     453\hline   
     454No                                      & No            & \textbf{1}\ \ \ function                              & \textbf{2}\ \ \ @monitor@ function    \\
     455\hline   
     456Yes (stackless)         & No            & \textbf{3}\ \ \ @generator@                   & \textbf{4}\ \ \ @monitor@ @generator@ \\
     457\hline   
     458Yes (stackful)          & No            & \textbf{5}\ \ \ @coroutine@                   & \textbf{6}\ \ \ @monitor@ @coroutine@ \\
     459\hline   
     460No                                      & Yes           & \textbf{7}\ \ \ {\color{red}rejected} & \textbf{8}\ \ \ {\color{red}rejected} \\
     461\hline   
     462Yes (stackless)         & Yes           & \textbf{9}\ \ \ {\color{red}rejected} & \textbf{10}\ \ \ {\color{red}rejected} \\
     463\hline   
     464Yes (stackful)          & Yes           & \textbf{11}\ \ \ @thread@                             & \textbf{12}\ \ @monitor@ @thread@             \\
     465\end{tabular}
     466\end{table}
     467
     468Given 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.
     469The answers define the optimal language feature need for implementing a programming problem.
     470The 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
     475The following design requirements largely stem from building \CFA on top of C.
     476\begin{itemize}[topsep=3pt,parsep=0pt]
     477\item
     478All communication must be statically type checkable for early detection of errors and efficient code generation.
     479This requirement is consistent with the fact that C is a statically-typed programming-language.
     480
     481\item
     482Direct interaction among language features must be possible allowing any feature to be selected without restricting comm\-unication.
     483For example, many concurrent languages do not provide direct communication (calls) among threads, \ie threads only communicate indirectly through monitors, channels, messages, and/or futures.
     484Indirect communication increases the number of objects, consuming more resources, and require additional synchronization and possibly data transfer.
     485
     486\item
     487All communication is performed using function calls, \ie data is transmitted from argument to parameter and results are returned from function calls.
     488Alternative 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
     491All stateful features must follow the same declaration scopes and lifetimes as other language data.
     492For C that means at program startup, during block and function activation, and on demand using dynamic allocation.
     493
     494\item
     495MES 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.
     496Furthermore, reducing synchronization scope by encapsulating it within language constructs further reduces errors in concurrent programs.
     497
     498\item
     499Both synchronous and asynchronous communication are needed.
     500However, 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
     503Synchronization 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.
     504Otherwise, certain concurrency problems are difficult, e.g.\ web server, disk scheduling, and the amount of concurrency is inhibited~\cite{Gentleman81}.
     505\end{itemize}
     506We 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
     512Asynchronous 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).
     513The caller detects the action's completion through a \newterm{future}/\newterm{promise}.
     514The benefit is asynchronous caller execution with respect to the callee until future resolution.
     515For 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.
     516When the caller needs the promise to be fulfilled, it executes @await@.
     517A promise-completion call-back can be part of the callee action or the caller is rescheduled;
     518in either case, the call back is executed after the promise is fulfilled.
     519While 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).
     520Specifically, 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.
     521Note, @async-await@ is just syntactic-sugar over the event engine so it does not solve these deficiencies.
     522For 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.
     523The problem is when concurrent work-units need to interact and/or block as this effects the executor, \eg stops threads.
     524While 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.
    382525
    383526
     
    385528\label{s:StatefulFunction}
    386529
    387 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.
    388 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.
    389 This capability is accomplished by retaining a data/execution \emph{closure} between invocations.
    390 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.
    391 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.
    392 Hence, refactoring a stackless coroutine may require changing it to stackful.
    393 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.
    394 As well, activating a stateful function is \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
    395 A fixed closure activated by modified call/return is faster than a variable closure activated by context switching.
    396 Additionally, any storage management for the closure (especially in unmanaged languages, \ie no garbage collection) must also be factored into design and performance.
    397 Therefore, selecting between stackless and stackful semantics is a tradeoff between programming requirements and performance, where stackless is faster and stackful is more general.
    398 Note, creation cost is amortized across usage, so activation cost is usually the dominant factor.
     530A \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).
     531A 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.
     532However, 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.
     533Hence, 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}.
     534For 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.
     535The 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.
     536Note, a subset of generator state is a function \emph{closure}, \ie the technique of capturing lexical references when returning a nested function.
     537A 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.
     538For 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
     540There are two styles of activating a stateful function, \emph{asymmetric} or \emph{symmetric}, identified by resume/suspend (no cycles) and resume/resume (cycles).
     541These 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.
     542Selecting 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.
     543Additionally, storage management for the closure/stack (especially in unmanaged languages, \ie no garbage collection) must be factored into design and performance.
     544Note, 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
     558For 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 ...
     566gen = Gen()
     567for 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(); }  `};`
     576Cycle c1, c2; c1.p=&c2; c2.p=&c1; c1.cycle();
     577\end{uC++}
     578&
     579\begin{cfa}
     580void * rtn( void * arg ) { ... }
     581int i = 3, rc;
     582pthread_t t; $\C{// thread id}$
     583$\LstCommentStyle{\color{red}// function pointer}$
     584rc=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.
     589Essentially, the generator/coroutine/thread function is semantically coupled with a generator/coroutine/thread custom type via the type's name.
     590The custom type solves several issues, while accessing the underlying mechanisms used by the custom types is still allowed for flexibility reasons.
     591Each custom type is discussed in detail in the following sections.
     592
     593
     594\subsection{Generator}
     595
     596Stackless 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.
     597The \CFA goal is to achieve this performance target, possibly at the cost of some semantic complexity.
     598A series of different kinds of generators and their implementation demonstrate how this goal is accomplished.\footnote{
     599The \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()|.
     600Operator \lstinline+|+ is overloaded for printing, like bit-shift \lstinline|<<| in \CC.
     601The \CFA \lstinline|with| clause opens an aggregate scope making its fields directly accessible, like Pascal \lstinline|with|, but using parallel semantics;
     602multiple 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}%
    399605
    400606\begin{figure}
     
    410616
    411617
     618
     619
    412620        int fn = f->fn; f->fn = f->fn1;
    413621                f->fn1 = f->fn + fn;
    414622        return fn;
    415 
    416623}
    417624int main() {
     
    432639void `main(Fib & fib)` with(fib) {
    433640
     641
    434642        [fn1, fn] = [1, 0];
    435643        for () {
     
    451659\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    452660typedef struct {
    453         int fn1, fn;  void * `next`;
     661        int `restart`, fn1, fn;
    454662} Fib;
    455 #define FibCtor { 1, 0, NULL }
     663#define FibCtor { `0`, 1, 0 }
    456664Fib * comain( Fib * f ) {
    457         if ( f->next ) goto *f->next;
    458         f->next = &&s1;
     665        `static void * states[] = {&&s0, &&s1};`
     666        `goto *states[f->restart];`
     667  s0: f->`restart` = 1;
    459668        for ( ;; ) {
    460669                return f;
    461670          s1:; int fn = f->fn + f->fn1;
    462                         f->fn1 = f->fn; f->fn = fn;
     671                f->fn1 = f->fn; f->fn = fn;
    463672        }
    464673}
     
    472681\end{lrbox}
    473682
    474 \subfloat[C asymmetric generator]{\label{f:CFibonacci}\usebox\myboxA}
     683\subfloat[C]{\label{f:CFibonacci}\usebox\myboxA}
    475684\hspace{3pt}
    476685\vrule
    477686\hspace{3pt}
    478 \subfloat[\CFA asymmetric generator]{\label{f:CFAFibonacciGen}\usebox\myboxB}
     687\subfloat[\CFA]{\label{f:CFAFibonacciGen}\usebox\myboxB}
    479688\hspace{3pt}
    480689\vrule
    481690\hspace{3pt}
    482 \subfloat[C generator implementation]{\label{f:CFibonacciSim}\usebox\myboxC}
     691\subfloat[C generated code for \CFA version]{\label{f:CFibonacciSim}\usebox\myboxC}
    483692\caption{Fibonacci (output) asymmetric generator}
    484693\label{f:FibonacciAsymmetricGenerator}
     
    493702};
    494703void ?{}( Fmt & fmt ) { `resume(fmt);` } // constructor
    495 void ^?{}( Fmt & f ) with(f) { $\C[1.75in]{// destructor}$
     704void ^?{}( Fmt & f ) with(f) { $\C[2.25in]{// destructor}$
    496705        if ( g != 0 || b != 0 ) sout | nl; }
    497706void `main( Fmt & f )` with(f) {
     
    499708                for ( ; g < 5; g += 1 ) { $\C{// groups}$
    500709                        for ( ; b < 4; b += 1 ) { $\C{// blocks}$
    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
     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}$
    506715        }
    507716}
     
    521730\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    522731typedef struct {
    523         void * next;
     732        int `restart`, g, b;
    524733        char ch;
    525         int g, b;
    526734} Fmt;
    527735void comain( Fmt * f ) {
    528         if ( f->next ) goto *f->next;
    529         f->next = &&s1;
     736        `static void * states[] = {&&s0, &&s1};`
     737        `goto *states[f->restart];`
     738  s0: f->`restart` = 1;
    530739        for ( ;; ) {
    531740                for ( f->g = 0; f->g < 5; f->g += 1 ) {
    532741                        for ( f->b = 0; f->b < 4; f->b += 1 ) {
    533                                 return;
    534                           s1:;  while ( f->ch == '\n' ) return;
     742                                do { return;  s1: ;
     743                                } while ( f->ch == '\n' );
    535744                                printf( "%c", f->ch );
    536745                        } printf( " " );
     
    539748}
    540749int main() {
    541         Fmt fmt = { NULL };  comain( &fmt ); // prime
     750        Fmt fmt = { `0` };  comain( &fmt ); // prime
    542751        for ( ;; ) {
    543752                scanf( "%c", &fmt.ch );
     
    550759\end{lrbox}
    551760
    552 \subfloat[\CFA asymmetric generator]{\label{f:CFAFormatGen}\usebox\myboxA}
    553 \hspace{3pt}
     761\subfloat[\CFA]{\label{f:CFAFormatGen}\usebox\myboxA}
     762\hspace{35pt}
    554763\vrule
    555764\hspace{3pt}
    556 \subfloat[C generator simulation]{\label{f:CFormatSim}\usebox\myboxB}
     765\subfloat[C generated code for \CFA version]{\label{f:CFormatGenImpl}\usebox\myboxB}
    557766\hspace{3pt}
    558767\caption{Formatter (input) asymmetric generator}
     
    560769\end{figure}
    561770
    562 Stateful functions appear as generators, coroutines, and threads, where presentations are based on function objects or pointers~\cite{Butenhof97, C++14, MS:VisualC++, BoostCoroutines15}.
    563 For example, Python presents generators as a function object:
    564 \begin{python}
    565 def Gen():
    566         ... `yield val` ...
    567 gen = Gen()
    568 for i in range( 10 ):
    569         print( next( gen ) )
    570 \end{python}
    571 Boost presents coroutines in terms of four functor object-types:
    572 \begin{cfa}
    573 asymmetric_coroutine<>::pull_type
    574 asymmetric_coroutine<>::push_type
    575 symmetric_coroutine<>::call_type
    576 symmetric_coroutine<>::yield_type
    577 \end{cfa}
    578 and 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}
    580 void * rtn( void * arg ) { ... }
    581 int i = 3, rc;
    582 pthread_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.
    595 Essentially, the generator/coroutine/thread function is semantically coupled with a generator/coroutine/thread custom type.
    596 The custom type solves several issues, while accessing the underlying mechanisms used by the custom types is still allowed.
    597 
    598 
    599 \subsection{Generator}
    600 
    601 Stackless generators have the potential to be very small and fast, \ie as small and fast as function call/return for both creation and execution.
    602 The \CFA goal is to achieve this performance target, possibly at the cost of some semantic complexity.
    603 A series of different kinds of generators and their implementation demonstrate how this goal is accomplished.
    604 
    605 Figure~\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.
     771Figure~\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.
    606772This generator is an \emph{output generator}, producing a new result on each resumption.
    607773To 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.
     
    611777The C version only has the middle execution state because the top execution state is declaration initialization.
    612778Figure~\ref{f:CFAFibonacciGen} shows the \CFA approach, which also has a manual closure, but replaces the structure with a custom \CFA @generator@ type.
    613 This generator type is then connected to a function that \emph{must be named \lstinline|main|},\footnote{
    614 The name \lstinline|main| has special meaning in C, specifically the function where a program starts execution.
    615 Hence, overloading this name for other starting points (generator/coroutine/thread) is a logical extension.}
    616 called a \emph{generator main},which takes as its only parameter a reference to the generator type.
     779Each 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.}
     783called 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.
    617784The generator main contains @suspend@ statements that suspend execution without ending the generator versus @return@.
    618 For the Fibonacci generator-main,\footnote{
    619 The \CFA \lstinline|with| opens an aggregate scope making its fields directly accessible, like Pascal \lstinline|with|, but using parallel semantics.
    620 Multiple aggregates may be opened.}
     785For the Fibonacci generator-main,
    621786the top initialization state appears at the start and the middle execution state is denoted by statement @suspend@.
    622787Any local variables in @main@ \emph{are not retained} between calls;
     
    627792Resuming an ended (returned) generator is undefined.
    628793Function @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.
    629 Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA generator only needs one additional field, @next@, to handle retention of execution state.
    630 The computed @goto@ at the start of the generator main, which branches after the previous suspend, adds very little cost to the resume call.
    631 Finally, an explicit generator type provides both design and performance benefits, such as multiple type-safe interface functions taking and returning arbitrary types.\footnote{
    632 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()|.
    633 }%
     794Figure~\ref{f:CFibonacciSim} shows the C implementation of the \CFA asymmetric generator.
     795Only one execution-state field, @restart@, is needed to subscript the suspension points in the generator.
     796At 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}).
     797Next, the computed @goto@ selects the last suspend point and branches to it.
     798The  cost of setting @restart@ and branching via the computed @goto@ adds very little cost to the suspend/resume calls.
     799
     800An advantage of the \CFA explicit generator type is the ability to allow multiple type-safe interface functions taking and returning arbitrary types.
    634801\begin{cfa}
    635802int ?()( Fib & fib ) { return `resume( fib )`.fn; } $\C[3.9in]{// function-call interface}$
    636 int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// use function-call interface to skip N values}$
    637 double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}\CRT$
    638 sout | (int)f1() | (double)f1() | f2( 2 ); // alternative interface, cast selects call based on return type, step 2 values
     803int ?()( Fib & fib, int N ) { for ( N - 1 ) `fib()`; return `fib()`; } $\C{// add parameter to skip N values}$
     804double ?()( Fib & fib ) { return (int)`fib()` / 3.14159; } $\C{// different return type, cast prevents recursive call}$
     805Fib f;  int i;  double d;
     806i = f();  i = f( 2 );  d = f();                                         $\C{// alternative interfaces}\CRT$
    639807\end{cfa}
    640808Now, the generator can be a separately compiled opaque-type only accessed through its interface functions.
    641809For 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.
    642810
    643 Having 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}.)
    645 This 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.
     811\begin{figure}
     812%\centering
     813\newbox\myboxA
     814\begin{lrbox}{\myboxA}
     815\begin{python}[aboveskip=0pt,belowskip=0pt]
     816def Fib():
     817        fn1, fn = 0, 1
     818        while True:
     819                `yield fn1`
     820                fn1, fn = fn, fn1 + fn
     821f1 = Fib()
     822f2 = Fib()
     823for 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]
     841def 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()
     856fmt = Fmt()
     857`next( fmt )`                                                   $\C{\# prime, next prewritten}$
     858for 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
     873Having 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}).
     874This 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.
    646875However, dynamic allocation significantly increases the cost of generator creation/destruction and is a showstopper for embedded real-time programming.
    647876But 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.
    648 With 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.
    649 Finally, 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.
     877With 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.
     878Our 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.
    650879As well, C programmers are not afraid of this kind of semantic programming requirement, if it results in very small, fast generators.
    651880
     
    669898The 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.
    670899The destructor provides a newline, if formatted text ends with a full line.
    671 Figure~\ref{f:CFormatSim} shows the C implementation of the \CFA input generator with one additional field and the computed @goto@.
    672 For contrast, Figure~\ref{f:PythonFormatter} shows the equivalent Python format generator with the same properties as the Fibonacci generator.
    673 
    674 Figure~\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}.
    675 Device drives follow the pattern of simple data state but complex execution state, \ie finite state-machine (FSM) parsing a protocol.
    676 For example, the following protocol:
     900Figure~\ref{f:CFormatGenImpl} shows the C implementation of the \CFA input generator with one additional field and the computed @goto@.
     901For 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
     905Figure~\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}
     906Swift \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;
     907however, the calls do not retain execution state, and hence always start from the top.
     908The alternative approach for implementing device drivers is using stack-ripping.
     909However, 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
     911As an example, the following protocol:
    677912\begin{center}
    678913\ldots\, STX \ldots\, message \ldots\, ESC ETX \ldots\, message \ldots\, ETX 2-byte crc \ldots
    679914\end{center}
    680 is a network message beginning with the control character STX, ending with an ETX, and followed by a 2-byte cyclic-redundancy check.
     915is for a simple network message beginning with the control character STX, ending with an ETX, and followed by a 2-byte cyclic-redundancy check.
    681916Control characters may appear in a message if preceded by an ESC.
    682917When 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.
    683 The 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.
    684 Hence, the device driver is an input/output generator.
    685 
    686 Note, 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.
    687 As 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.
    689 In contrast, the execution state is large, with one @resume@ and seven @suspend@s.
    690 Hence, 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.
    691 Because FSMs can be complex and frequently occur in important domains, direct generator support is important in a system programming language.
     918The 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.
     919Hence, 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.
     920The 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.
     921The conclusion is that FSMs are complex and occur in important domains, so direct generator support is important in a system programming language.
    692922
    693923\begin{figure}
    694924\centering
    695 \newbox\myboxA
    696 \begin{lrbox}{\myboxA}
    697 \begin{python}[aboveskip=0pt,belowskip=0pt]
    698 def Fib():
    699         fn1, fn = 0, 1
    700         while True:
    701                 `yield fn1`
    702                 fn1, fn = fn, fn1 + fn
    703 f1 = Fib()
    704 f2 = Fib()
    705 for 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]
    719 def 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()
    730 fmt = Fmt()
    731 `next( fmt )`                    # prime, next prewritten
    732 for 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 
    746925\begin{tabular}{@{}l|l@{}}
    747926\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     
    750929`generator` Driver {
    751930        Status status;
    752         unsigned char byte, * msg; // communication
    753         unsigned int lnth, sum;      // local state
    754         unsigned short int crc;
     931        char byte, * msg; // communication
     932        int lnth, sum;      // local state
     933        short int crc;
    755934};
    756935void ?{}( Driver & d, char * m ) { d.msg = m; }
     
    800979(The trivial cycle is a generator resuming itself.)
    801980This control flow is similar to recursion for functions but without stack growth.
    802 The steps for symmetric control-flow are creating, executing, and terminating the cycle.
     981Figure~\ref{f:PingPongFullCoroutineSteps} shows the steps for symmetric control-flow are creating, executing, and terminating the cycle.
    803982Constructing 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.
    804983(This issue occurs for any cyclic data structure.)
    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.
    807 Once 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).
     984The 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.)
     986Once 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).
    808987Terminating 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).
     988Note, the creator and starter may be different, \eg if the creator calls another function that starts the cycle.
    809989The starting stack-frame is below the last active generator because the resume/resume cycle does not grow the stack.
    810 Also, 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.
    811 Destructor cost occurs when the generator instance is deallocated, which is easily controlled by the programmer.
    812 
    813 Figure~\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.
    814 This 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.
    815 However, before the jump, the caller must reset its stack (and any registers) equivalent to a @return@, but subsequently jump forward.
    816 This semantics is basically a tail-call optimization, which compilers already perform.
    817 The example shows the assembly code to undo the generator's entry code before the direct jump.
    818 This assembly code depends on what entry code is generated, specifically if there are local variables and the level of optimization.
    819 To provide this new calling convention requires a mechanism built into the compiler, which is beyond the scope of \CFA at this time.
    820 Nevertheless, it is possible to hand generate any symmetric generators for proof of concept and performance testing.
    821 A 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@.
     990Also, 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.
     991Destructor cost occurs when the generator instance is deallocated by the creator.
    822992
    823993\begin{figure}
     
    826996\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    827997`generator PingPong` {
     998        int N, i;                               // local state
    828999        const char * name;
    829         int N;
    830         int i;                          // local state
    8311000        PingPong & partner; // rebindable reference
    8321001};
    8331002
    8341003void `main( PingPong & pp )` with(pp) {
     1004
     1005
    8351006        for ( ; i < N; i += 1 ) {
    8361007                sout | name | i;
     
    8501021\begin{cfa}[escapechar={},aboveskip=0pt,belowskip=0pt]
    8511022typedef struct PingPong {
     1023        int restart, N, i;
    8521024        const char * name;
    853         int N, i;
    8541025        struct PingPong * partner;
    855         void * next;
    8561026} PingPong;
    857 #define PPCtor(name, N) {name,N,0,NULL,NULL}
     1027#define PPCtor(name, N) {0, N, 0, name, NULL}
    8581028void comain( PingPong * pp ) {
    859         if ( pp->next ) goto *pp->next;
    860         pp->next = &&cycle;
     1029        static void * states[] = {&&s0, &&s1};
     1030        goto *states[pp->restart];
     1031  s0: pp->restart = 1;
    8611032        for ( ; pp->i < pp->N; pp->i += 1 ) {
    8621033                printf( "%s %d\n", pp->name, pp->i );
    8631034                asm( "mov  %0,%%rdi" : "=m" (pp->partner) );
    8641035                asm( "mov  %rdi,%rax" );
    865                 asm( "popq %rbx" );
     1036                asm( "add  $16, %rsp" );
     1037                asm( "popq %rbp" );
    8661038                asm( "jmp  comain" );
    867           cycle: ;
     1039          s1: ;
    8681040        }
    8691041}
     
    8811053\end{figure}
    8821054
    883 Finally, part of this generator work was inspired by the recent \CCtwenty generator proposal~\cite{C++20Coroutine19} (which they call coroutines).
     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
     1063Figure~\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.
     1064Before 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.
     1065The @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.
     1066While 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.
     1067However, this assembler code depends on what entry code is generated, specifically if there are local variables and the level of optimization.
     1068Hence, 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@.
     1069For 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
     1071Finally, 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.
    8841072Our work provides the same high-performance asymmetric generators as \CCtwenty, and extends their work with symmetric generators.
    8851073An 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:
     
    8961084\label{s:Coroutine}
    8971085
    898 Stackful coroutines extend generator semantics, \ie there is an implicit closure and @suspend@ may appear in a helper function called from the coroutine main.
     1086Stackful 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.
    8991087A coroutine is specified by replacing @generator@ with @coroutine@ for the type.
    900 Coroutine 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.
     1088Coroutine 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.
    9011089A series of different kinds of coroutines and their implementations demonstrate how coroutines extend generators.
    9021090
    9031091First, 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.
    904 \begin{description}
    905 \item[Fibonacci]
    906 Move the declaration of @fn1@ to the start of 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
    9071096\begin{cfa}[xleftmargin=0pt]
    908 void main( Fib & fib ) with(fib) {
     1097void main( Fib & fib ) ...
    9091098        `int fn1;`
    910 \end{cfa}
    911 \item[Formatter]
    912 Move the declaration of @g@ and @b@ to the for loops in the coroutine main.
     1099
     1100
     1101\end{cfa}
     1102&
    9131103\begin{cfa}[xleftmargin=0pt]
    9141104for ( `g`; 5 ) {
    9151105        for ( `b`; 4 ) {
    916 \end{cfa}
    917 \item[Device Driver]
    918 Move the declaration of @lnth@ and @sum@ to their points of initialization.
     1106
     1107
     1108\end{cfa}
     1109&
    9191110\begin{cfa}[xleftmargin=0pt]
    920         status = CONT;
    921         `unsigned int lnth = 0, sum = 0;`
    922         ...
    923         `unsigned short int crc = byte << 8;`
    924 \end{cfa}
    925 \item[PingPong]
    926 Move the declaration of @i@ to the for loop in the coroutine main.
     1111status = CONT;
     1112`int lnth = 0, sum = 0;`
     1113...
     1114`short int crc = byte << 8;`
     1115\end{cfa}
     1116&
    9271117\begin{cfa}[xleftmargin=0pt]
    928 void main( PingPong & pp ) with(pp) {
     1118void main( PingPong & pp ) ...
    9291119        for ( `i`; N ) {
    930 \end{cfa}
    931 \end{description}
     1120
     1121
     1122\end{cfa}
     1123\end{tabular}
     1124\end{center}
    9321125It 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.
    9331126\begin{cfa}
    934 unsigned int Crc() {
     1127int Crc() {
    9351128        `suspend;`
    936         unsigned short int crc = byte << 8;
     1129        short int crc = byte << 8;
    9371130        `suspend;`
    9381131        status = (crc | byte) == sum ? MSG : ECRC;
     
    9451138
    9461139\begin{comment}
    947 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 @next@.
     1140Figure~\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@.
    9481141Like 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.
    9491142The 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@.
    950 The interface function @next@, takes a Fibonacci instance and context switches to it using @resume@;
     1143The interface function @restart@, takes a Fibonacci instance and context switches to it using @resume@;
    9511144on restart, the Fibonacci field, @fn@, contains the next value in the sequence, which is returned.
    9521145The first @resume@ is special because it allocates the coroutine stack and cocalls its coroutine main on that stack;
     
    11141307\begin{figure}
    11151308\centering
    1116 \lstset{language=CFA,escapechar={},moredelim=**[is][\protect\color{red}]{`}{`}}% allow $
    11171309\begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
    11181310\begin{cfa}
    11191311`coroutine` Prod {
    1120         Cons & c;                       // communication
     1312        Cons & c;                       $\C[1.5in]{// communication}$
    11211313        int N, money, receipt;
    11221314};
    11231315void main( Prod & prod ) with( prod ) {
    1124         // 1st resume starts here
    1125         for ( i; N ) {
     1316        for ( i; N ) {          $\C{// 1st resume}\CRT$
    11261317                int p1 = random( 100 ), p2 = random( 100 );
    1127                 sout | p1 | " " | p2;
    11281318                int status = delivery( c, p1, p2 );
    1129                 sout | " $" | money | nl | status;
    11301319                receipt += 1;
    11311320        }
    11321321        stop( c );
    1133         sout | "prod stops";
    11341322}
    11351323int payment( Prod & prod, int money ) {
     
    11521340\begin{cfa}
    11531341`coroutine` Cons {
    1154         Prod & p;                       // communication
     1342        Prod & p;                       $\C[1.5in]{// communication}$
    11551343        int p1, p2, status;
    11561344        bool done;
    11571345};
    11581346void ?{}( Cons & cons, Prod & p ) {
    1159         &cons.p = &p; // reassignable reference
     1347        &cons.p = &p;           $\C{// reassignable reference}$
    11601348        cons.[status, done ] = [0, false];
    11611349}
    11621350void main( Cons & cons ) with( cons ) {
    1163         // 1st resume starts here
    1164         int money = 1, receipt;
     1351        int money = 1, receipt; $\C{// 1st resume}\CRT$
    11651352        for ( ; ! done; ) {
    1166                 sout | p1 | " " | p2 | nl | " $" | money;
    11671353                status += 1;
    11681354                receipt = payment( p, money );
    1169                 sout | " #" | receipt;
    11701355                money += 1;
    11711356        }
    1172         sout | "cons stops";
    11731357}
    11741358int delivery( Cons & cons, int p1, int p2 ) {
     
    11911375This example is illustrative because both producer/consumer have two interface functions with @resume@s that suspend execution in these interface (helper) functions.
    11921376The 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.
    1193 The 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 
     1377The 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.
    11961379The producer call to @delivery@ transfers values into the consumer's communication variables, resumes the consumer, and returns the consumer status.
    1197 On the first resume, @cons@'s stack is created and initialized, holding local-state variables retained between subsequent activations of the coroutine.
    1198 The 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).
    1199 The call from the consumer to @payment@ introduces the cycle between producer and consumer.
    1200 When @payment@ is called, the consumer copies values into the producer's communication variable and a resume is executed.
    1201 The 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.
    1203 The loop then repeats calling @delivery@, where each call resumes the consumer coroutine.
    1204 The context switch to the consumer continues in @payment@.
    1205 The consumer increments and returns the receipt to the call in @cons@'s coroutine main.
    1206 The loop then repeats calling @payment@, where each call resumes the producer coroutine.
     1380Similarly on the first resume, @cons@'s stack is created and initialized, holding local-state variables retained between subsequent activations of the coroutine.
     1381The symmetric coroutine cycle forms when the consumer calls the producer's @payment@ function, which resumes the producer in the consumer's delivery function.
     1382When the producer calls @delivery@ again, it resumes the consumer in the @payment@ function.
     1383Both interface function than return to the their corresponding coroutine-main functions for the next cycle.
    12071384Figure~\ref{f:ProdConsRuntimeStacks} shows the runtime stacks of the program main, and the coroutine mains for @prod@ and @cons@ during the cycling.
     1385As 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.
    12081386
    12091387\begin{figure}
     
    12141392\caption{Producer / consumer runtime stacks}
    12151393\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}
    12251394\end{figure}
    12261395
    12271396Terminating 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.
    1228 Furthermore, 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.
    1229 When a coroutine's main ends, its stack is already unwound so any stack allocated objects with destructors have been finalized.
     1397Furthermore, 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.
     1398In 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.)
     1400When the consumer's main ends, its stack is already unwound so any stack allocated objects with destructors are finalized.
     1401The question now is where does control continue?
     1402
    12301403The na\"{i}ve semantics for coroutine-cycle termination is to context switch to the last resumer, like executing a @suspend@/@return@ in a generator.
    12311404However, for coroutines, the last resumer is \emph{not} implicitly below the current stack frame, as for generators, because each coroutine's stack is independent.
    12321405Unfortunately, it is impossible to determine statically if a coroutine is in a cycle and unrealistic to check dynamically (graph-cycle problem).
    12331406Hence, a compromise solution is necessary that works for asymmetric (acyclic) and symmetric (cyclic) coroutines.
    1234 
    1235 Our solution is to context switch back to the first resumer (starter) once the coroutine ends.
     1407Our solution is to retain a coroutine's starter (first resumer), and context switch back to the starter when the coroutine ends.
     1408Hence, 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}).
    12361409This semantics works well for the most common asymmetric and symmetric coroutine usage patterns.
    1237 For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer.
    1238 All previous generators converted to coroutines have this property.
    1239 For symmetric coroutines, it is common for the cycle creator to persist for the lifetime of the cycle.
    1240 Hence, the starter coroutine is remembered on the first resume and ending the coroutine resumes the starter.
    1241 Figure~\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.
     1410For asymmetric coroutines, it is common for the first resumer (starter) coroutine to be the only resumer;
     1411for symmetric coroutines, it is common for the cycle creator to persist for the lifetime of the cycle.
    12421412For 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.
    12431413
    1244 The producer/consumer example does not illustrate the full power of the starter semantics because @cons@ always ends first.
    1245 Assume generator @PingPong@ is converted to a coroutine.
    1246 Figure~\ref{f:PingPongFullCoroutineSteps} shows the creation, starter, and cyclic execution steps of the coroutine version.
    1247 The program main creates (declares) coroutine instances @ping@ and @pong@.
    1248 Next, program main resumes @ping@, making it @ping@'s starter, and @ping@'s main resumes @pong@'s main, making it @pong@'s starter.
    1249 Execution forms a cycle when @pong@ resumes @ping@, and cycles $N$ times.
    1250 By adjusting $N$ for either @ping@/@pong@, it is possible to have either one finish first, instead of @pong@ always ending first.
    1251 If @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@.
    1252 If @ping@ ends first, it resumes its starter the program main in function @start@.
    1253 Regardless of the cycle complexity, the starter stack always leads back to the program main, but the stack can be entered at an arbitrary point.
    1254 Once back at the program main, coroutines @ping@ and @pong@ are deallocated.
    1255 For generators, deallocation runs the destructors for all objects in the generator type.
    1256 For 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.
    1257 Hence, 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.
    1258 So 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.
    1259 Explicitly 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 
    1261 Finally, there is an interesting effect for @suspend@ with symmetric coroutines.
    1262 A coroutine must retain its last resumer to suspend back because the resumer is on a different stack.
    1263 These reverse pointers allow @suspend@ to cycle \emph{backwards}, which may be useful in certain cases.
    1264 However, 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.
    1265 To prevent losing this information, a self-resume does not overwrite the last resumer.
     1414Note, the producer/consumer example does not illustrate the full power of the starter semantics because @cons@ always ends first.
     1415Assume generator @PingPong@ in Figure~\ref{f:PingPongSymmetricGenerator} is converted to a coroutine.
     1416Unlike generators, coroutines have a starter structure with multiple levels, where the program main starts @ping@ and @ping@ starts @pong@.
     1417By adjusting $N$ for either @ping@/@pong@, it is possible to have either finish first.
     1418If @pong@ ends first, it resumes its starter @ping@ in its coroutine main, then @ping@ ends and resumes its starter the program main on return;
     1419if @ping@ ends first, it resumes its starter the program main on return.
     1420Regardless of the cycle complexity, the starter structure always leads back to the program main, but the path can be entered at an arbitrary point.
     1421Once 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.
     1422Hence, 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.
    12661423
    12671424
     
    12941451Users wanting to extend custom types or build their own can only do so in ways offered by the language.
    12951452Furthermore, implementing custom types without language support may display the power of a programming language.
    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.
     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.
    12971454
    12981455Part 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.
     
    13041461forall( `dtype` T | is_coroutine(T) ) void $suspend$( T & ), resume( T & );
    13051462\end{cfa}
    1306 Note, copying generators/coroutines/threads is not meaningful.
    1307 For example, both the resumer and suspender descriptors can have bidirectional pointers;
    1308 copying these coroutines does not update the internal pointers so behaviour of both copies would be difficult to understand.
    1309 Furthermore, two coroutines cannot logically execute on the same stack.
    1310 A 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.
     1463Note, 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.
    13111464The \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).
    13121465The 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.
     
    13521505The 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.
    13531506
    1354 Figure~\ref{f:CoroutineMemoryLayout} shows different memory-layout options for a coroutine (where a task is similar).
     1507Figure~\ref{f:CoroutineMemoryLayout} shows different memory-layout options for a coroutine (where a thread is similar).
    13551508The coroutine handle is the @coroutine@ instance containing programmer specified type global/communication variables across interface functions.
    13561509The coroutine descriptor contains all implicit declarations needed by the runtime, \eg @suspend@/@resume@, and can be part of the coroutine handle or separate.
    13571510The coroutine stack can appear in a number of locations and be fixed or variable sized.
    1358 Hence, the coroutine's stack could be a VLS\footnote{
    1359 We are examining variable-sized structures (VLS), where fields can be variable-sized structures or arrays.
     1511Hence, the coroutine's stack could be a variable-length structure (VLS)\footnote{
     1512We are examining VLSs, where fields can be variable-sized structures or arrays.
    13601513Once allocated, a VLS is fixed sized.}
    13611514on the allocating stack, provided the allocating stack is large enough.
    13621515For a VLS stack allocation/deallocation is an inexpensive adjustment of the stack pointer, modulo any stack constructor costs (\eg initial frame setup).
    1363 For heap stack allocation, allocation/deallocation is an expensive heap allocation (where the heap can be a shared resource), modulo any stack constructor costs.
    1364 With 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.
     1516For stack allocation in the heap, allocation/deallocation is an expensive allocation, where the heap can be a shared resource, modulo any stack constructor costs.
     1517It 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.
    13651518Currently, \CFA supports stack/heap allocated descriptors but only fixed-sized heap allocated stacks.
    13661519In \CFA debug-mode, the fixed-sized stack is terminated with a write-only page, which catches most stack overflows.
    13671520Experience teaching concurrency with \uC~\cite{CS343} shows fixed-sized stacks are rarely an issue for students.
    1368 Split-stack allocation is under development but requires recompilation of legacy code, which may be impossible.
     1521Split-stack allocation is under development but requires recompilation of legacy code, which is not always possible.
    13691522
    13701523\begin{figure}
     
    13801533
    13811534Concurrency is nondeterministic scheduling of independent sequential execution paths (threads), where each thread has its own stack.
    1382 A single thread with multiple call stacks, \newterm{coroutining}~\cite{Conway63,Marlin80}, does \emph{not} imply concurrency~\cite[\S~2]{Buhr05a}.
    1383 In coroutining, coroutines self-schedule the thread across stacks so execution is deterministic.
     1535A single thread with multiple stacks, \ie coroutining, does \emph{not} imply concurrency~\cite[\S~3]{Buhr05a}.
     1536Coroutining self-schedule the thread across stacks so execution is deterministic.
    13841537(It is \emph{impossible} to generate a concurrency error when coroutining.)
    1385 However, coroutines are a stepping stone towards concurrency.
    1386 
    1387 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}.
     1538
     1539The 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}.
    13881540Therefore, a minimal concurrency system requires coroutines \emph{in conjunction with a nondeterministic scheduler}.
    1389 The resulting execution system now follows a cooperative threading model~\cite{Adya02,libdill}, called \newterm{non-preemptive scheduling}.
    1390 Adding \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}.
    1391 While a scheduler introduces uncertain execution among explicit context switches, preemption introduces uncertainty by introducing implicit context switches.
     1541The 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.
     1542Adding \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.
    13921543Uncertainty gives the illusion of parallelism on a single processor and provides a mechanism to access and increase performance on multiple processors.
    13931544The reason is that the scheduler/runtime have complete knowledge about resources and how to best utilized them.
    1394 However, the introduction of unrestricted nondeterminism results in the need for \newterm{mutual exclusion} and \newterm{synchronization}, which restrict nondeterminism for correctness;
     1545However, 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;
    13951546otherwise, it is impossible to write meaningful concurrent programs.
    13961547Optimal concurrent performance is often obtained by having as much nondeterminism as mutual exclusion and synchronization correctness allow.
    13971548
    1398 A scheduler can either be a stackless or stackful.
     1549A scheduler can also be stackless or stackful.
    13991550For 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.
    14001551For 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.
     
    14051556\label{s:threads}
    14061557
    1407 Threading needs the ability to start a thread and wait for its completion.
     1558Threading (Table~\ref{t:ExecutionPropertyComposition} case 11) needs the ability to start a thread and wait for its completion.
    14081559A common API for this ability is @fork@ and @join@.
    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}
    1413 class MyTask extends Thread {...}
    1414 mytask t = new MyTask(...);
     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}
     1566class MyThread extends Thread {...}
     1567mythread t = new MyThread(...);
    14151568`t.start();` // start
    14161569// concurrency
     
    14191572&
    14201573\begin{cfa}
    1421 class MyTask { ... } // functor
    1422 MyTask mytask;
    1423 `thread t( mytask, ... );` // start
     1574class MyThread { ... } // functor
     1575MyThread mythread;
     1576`thread t( mythread, ... );` // start
    14241577// concurrency
    14251578`t.join();` // wait
     
    14341587\end{cfa}
    14351588\end{tabular}
    1436 \end{cquote}
     1589\vspace{1pt}
     1590\par\noindent
    14371591\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.
    14381592\begin{cfa}
    1439 thread MyTask {};
    1440 void main( MyTask & this ) { ... }
     1593thread MyThread {};
     1594void main( MyThread & this ) { ... }
    14411595int main() {
    1442         MyTask team`[10]`; $\C[2.5in]{// allocate stack-based threads, implicit start after construction}$
     1596        MyThread team`[10]`; $\C[2.5in]{// allocate stack-based threads, implicit start after construction}$
    14431597        // concurrency
    14441598} $\C{// deallocate stack-based threads, implicit joins before destruction}$
     
    14481602Arbitrary topologies are possible using dynamic allocation, allowing threads to outlive their declaration scope, identical to normal dynamic allocation.
    14491603\begin{cfa}
    1450 MyTask * factory( int N ) { ... return `anew( N )`; } $\C{// allocate heap-based threads, implicit start after construction}$
     1604MyThread * factory( int N ) { ... return `anew( N )`; } $\C{// allocate heap-based threads, implicit start after construction}$
    14511605int main() {
    1452         MyTask * team = factory( 10 );
     1606        MyThread * team = factory( 10 );
    14531607        // concurrency
    14541608        `delete( team );` $\C{// deallocate heap-based threads, implicit joins before destruction}\CRT$
     
    14961650
    14971651Threads 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.
    1498 Like coroutines, and for the same design reasons, \CFA provides a custom @thread@ type and a @trait@ to enforce and restrict the task-interface functions.
     1652Like coroutines, and for the same design reasons, \CFA provides a custom @thread@ type and a @trait@ to enforce and restrict the thread-interface functions.
    14991653\begin{cquote}
    15001654\begin{tabular}{@{}c@{\hspace{3\parindentlnth}}c@{}}
     
    15271681\label{s:MutualExclusionSynchronization}
    15281682
    1529 Unrestricted nondeterminism is meaningless as there is no way to know when the result is completed without synchronization.
     1683Unrestricted nondeterminism is meaningless as there is no way to know when a result is completed and safe to access.
    15301684To 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}.
    1531 Some 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).
     1685The 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}).
     1686Without 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.
     1687Preventing or detecting barging is a challenge with low-level locks, but made easier through higher-level constructs.
     1688This challenge is often split into two different approaches: barging \emph{avoidance} and \emph{prevention}.
     1689Approaches 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;
     1690approaches that conditionally hold locks during synchronization, \eg baton-passing~\cite{Andrews89}, prevent barging completely.
     1691
     1692At 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}.
     1693However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}.
     1694A significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
     1695Easing composability is another feature higher-level mutual-exclusion mechanisms can offer.
     1696Some 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).
    15321697However, these approaches introduce a new communication mechanism for concurrency different from the standard communication using function call/return.
    15331698Hence, a programmer must learn and manipulate two sets of design/programming patterns.
    15341699While this distinction can be hidden away in library code, effective use of the library still has to take both paradigms into account.
    1535 In contrast, approaches based on stateful models more closely resemble the standard call/return programming model, resulting in a single programming paradigm.
    1536 
    1537 At 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}.
    1538 However, for productivity it is always desirable to use the highest-level construct that provides the necessary efficiency~\cite{Hochstein05}.
    1539 A newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}.
    1540 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 to be the main concurrency paradigm for system languages, which is why it is rejected as the core paradigm for concurrency in \CFA.
    1541 
    1542 One of the most natural, elegant, and efficient mechanisms for mutual exclusion and synchronization for shared-memory systems is the \emph{monitor}.
    1543 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}.
    1544 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 simulate monitors.
    1545 For 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 
    1550 A 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}.
    1551 The 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.
    1552 The 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 
    1554 However, many solutions exist for mutual exclusion, which vary in terms of performance, flexibility and ease of use.
    1555 Methods 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.
    1556 Ease 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.
    1557 For 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.
    1558 However, a significant challenge with locks is composability because it takes careful organization for multiple locks to be used while preventing deadlock.
    1559 Easing composability is another feature higher-level mutual-exclusion mechanisms can offer.
    1560 
    1561 
    1562 \subsection{Synchronization}
    1563 
    1564 Synchronization enforces relative ordering of execution, and synchronization tools provide numerous mechanisms to establish these timing relationships.
    1565 Low-level synchronization primitives offer good performance and flexibility at the cost of ease of use;
    1566 higher-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.
    1567 Often 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.
    1568 If the calling reader is scheduled before the waiting writer, the reader has barged.
    1569 Barging 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).
    1570 Preventing or detecting barging is an involved challenge with low-level locks, which is made easier through higher-level constructs.
    1571 This challenge is often split into two different approaches: barging avoidance and prevention.
    1572 Algorithms that unconditionally releasing a lock for competing threads to acquire use barging avoidance during synchronization to force a barging thread to wait;
    1573 algorithms that conditionally hold locks during synchronization, \eg baton-passing~\cite{Andrews89}, prevent barging completely.
     1700In contrast, approaches based on shared-state models more closely resemble the standard call/return programming model, resulting in a single programming paradigm.
     1701Finally, a newer approach for restricting non-determinism is transactional memory~\cite{Herlihy93}.
     1702While 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.
    15741703
    15751704
     
    15771706\label{s:Monitor}
    15781707
    1579 A \textbf{monitor} is a set of functions that ensure mutual exclusion when accessing shared state.
    1580 More 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).
     1708One 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).
     1709First 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}.
     1710In 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.
     1711For these reasons, \CFA selected monitors as the core high-level concurrency construct, upon which higher-level approaches can be easily constructed.
     1712
     1713Specifically, a \textbf{monitor} is a set of functions that ensure mutual exclusion when accessing shared state.
     1714More 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).
    15811715Restricting acquire/release points eases programming, comprehension, and maintenance, at a slight cost in flexibility and efficiency.
    15821716\CFA uses a custom @monitor@ type and leverages declaration semantics (deallocation) to protect active or waiting threads in a monitor.
    15831717
    15841718The following is a \CFA monitor implementation of an atomic counter.
    1585 \begin{cfa}[morekeywords=nomutex]
     1719\begin{cfa}
    15861720`monitor` Aint { int cnt; }; $\C[4.25in]{// atomic integer counter}$
    1587 int ++?( Aint & `mutex`$\(_{opt}\)$ this ) with( this ) { return ++cnt; } $\C{// increment}$
    1588 int ?=?( Aint & `mutex`$\(_{opt}\)$ lhs, int rhs ) with( lhs ) { cnt = rhs; } $\C{// conversions with int}\CRT$
    1589 int ?=?( 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.)
    1593 The 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.
    1594 The assignment operators provide bidirectional conversion between an atomic and normal integer without accessing field @cnt@;
    1595 these operations only need @mutex@, if reading/writing the implementation type is not atomic.
    1596 The atomic counter is used without any explicit mutual-exclusion and provides thread-safe semantics, which is similar to the \CC template @std::atomic@.
     1721int ++?( Aint & `mutex` this ) with( this ) { return ++cnt; } $\C{// increment}$
     1722int ?=?( Aint & `mutex` lhs, int rhs ) with( lhs ) { cnt = rhs; } $\C{// conversions with int, mutex optional}\CRT$
     1723int ?=?( int & lhs, Aint & `mutex` rhs ) with( rhs ) { lhs = cnt; }
     1724\end{cfa}
     1725The operators use the parameter-only declaration type-qualifier @mutex@ to mark which parameters require locking during function execution to protect from race conditions.
     1726The 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.)
     1728The atomic counter is used without any explicit mutual-exclusion and provides thread-safe semantics.
    15971729\begin{cfa}
    15981730int i = 0, j = 0, k = 5;
     
    16021734i = x; j = y; k = z;
    16031735\end{cfa}
     1736Note, 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@.
    16041737
    16051738\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
    16061740\begin{cfa}
    16071741monitor M { ... } m;
     
    16121746\end{cfa}
    16131747\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.
    1614 Similar safety is offered by \emph{explicit} mechanisms like \CC RAII;
    1615 monitor \emph{implicit} safety ensures no programmer usage errors.
     1748Similar 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.
    16161749Furthermore, 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;
    16171750RAII is purely a mutual-exclusion mechanism (see Section~\ref{s:Scheduling}).
     
    16391772\end{cquote}
    16401773The @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.
    16431774Similarly, 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.
    16441775The custom monitor type also inserts any locks needed to implement the mutual exclusion semantics.
     
    16521783For example, a monitor may be passed through multiple helper functions before it is necessary to acquire the monitor's mutual exclusion.
    16531784
    1654 The benefit of mandatory monitor qualifiers is self-documentation, but requiring both @mutex@ and \lstinline[morekeywords=nomutex]@nomutex@ for all monitor parameters is redundant.
    1655 Instead, the semantics has one qualifier as the default and the other required.
    1656 For example, make the safe @mutex@ qualifier the default because assuming \lstinline[morekeywords=nomutex]@nomutex@ may cause subtle errors.
    1657 Alternatively, make the unsafe \lstinline[morekeywords=nomutex]@nomutex@ qualifier the default because it is the \emph{normal} parameter semantics while @mutex@ parameters are rare.
    1658 Providing a default qualifier implies knowing whether a parameter is a monitor.
    1659 Since \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.
    1660 For 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@.
     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.
     1786Hence, @mutex@ parameters are documentation, at the function and its prototype, to both programmer and compiler, without other redundant keywords.
     1787Furthermore, \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.
    16611788
    16621789The next semantic decision is establishing which parameter \emph{types} may be qualified with @mutex@.
     
    16721799Function @f3@ has a multiple object matrix, and @f4@ a multiple object data structure.
    16731800While shown shortly, multiple object acquisition is possible, but the number of objects must be statically known.
    1674 Therefore, \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.
     1801Therefore, \CFA only acquires one monitor per parameter with exactly one level of indirection, and exclude pointer types to unknown sized arrays.
    16751802
    16761803For object-oriented monitors, \eg Java, calling a mutex member \emph{implicitly} acquires mutual exclusion of the receiver object, @`rec`.foo(...)@.
     
    16791806While object-oriented monitors can be extended with a mutex qualifier for multiple-monitor members, no prior example of this feature could be found.}
    16801807called \newterm{bulk acquire}.
    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.
     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.
    16821809Figure~\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.
    16831810A \CFA programmer only has to manage when to acquire mutual exclusion;
     
    16991826void transfer( BankAccount & `mutex` my,
    17001827        BankAccount & `mutex` your, int me2you ) {
    1701 
     1828        // bulk acquire
    17021829        deposit( my, -me2you ); // debit
    17031830        deposit( your, me2you ); // credit
     
    17291856void transfer( BankAccount & my,
    17301857                        BankAccount & your, int me2you ) {
    1731         `scoped_lock lock( my.m, your.m );`
     1858        `scoped_lock lock( my.m, your.m );` // bulk acquire
    17321859        deposit( my, -me2you ); // debit
    17331860        deposit( your, me2you ); // credit
     
    17571884\end{figure}
    17581885
    1759 Users can still force the acquiring order by using @mutex@/\lstinline[morekeywords=nomutex]@nomutex@.
     1886Users can still force the acquiring order by using or not using @mutex@.
    17601887\begin{cfa}
    17611888void foo( M & mutex m1, M & mutex m2 ); $\C{// acquire m1 and m2}$
    1762 void bar( M & mutex m1, M & /* nomutex */ m2 ) { $\C{// acquire m1}$
     1889void bar( M & mutex m1, M & m2 ) { $\C{// only acquire m1}$
    17631890        ... foo( m1, m2 ); ... $\C{// acquire m2}$
    17641891}
    1765 void baz( M & /* nomutex */ m1, M & mutex m2 ) { $\C{// acquire m2}$
     1892void baz( M & m1, M & mutex m2 ) { $\C{// only acquire m2}$
    17661893        ... foo( m1, m2 ); ... $\C{// acquire m1}$
    17671894}
     
    18061933% 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.
    18071934% 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.
    1808 This 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.)
    1809 While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer may be full/empty so produce/consumer threads must block.
    1810 Leaving the monitor and trying again (busy waiting) is impractical for high-level programming.
    1811 Monitors eliminate busy waiting by providing synchronization to schedule threads needing access to the shared data, where threads block versus spinning.
     1935This 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.)
     1936While 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.
     1937Leaving the monitor and retrying (busy waiting) is impractical for high-level programming.
     1938
     1939Monitors 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.
    18121940Synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling.
    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.
    1814 Finally, \CFA monitors do not allow calling threads to barge ahead of signalled threads, which simplifies synchronization among threads in the monitor and increases correctness.
    1815 If barging is allowed, synchronization between a signaller and signallee is difficult, often requiring additional flags and multiple unblock/block cycles.
    1816 In fact, signals-as-hints is completely opposite from that proposed by Hoare in the seminal paper on monitors~\cite[p.~550]{Hoare74}.
     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.
     1943Note, 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.
     1944For 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.
     1947A 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.
     1948Preventing barging comes directly from Hoare's semantics in the seminal paper on monitors~\cite[p.~550]{Hoare74}.
    18171949% \begin{cquote}
    18181950% 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.
    18191951% 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}
    18201952% \end{cquote}
    1821 Furthermore, \CFA concurrency has no spurious wakeup~\cite[\S~9]{Buhr05a}, which eliminates an implicit form of self barging.
    1822 Hence, a \CFA @wait@ statement is not enclosed in a @while@ loop retesting a blocking predicate, which can cause thread starvation due to barging.
    1823 
    1824 Figure~\ref{f:MonitorScheduling} shows general internal/external scheduling (for the bounded-buffer example in Figure~\ref{f:InternalExternalScheduling}).
    1825 External calling threads block on the calling queue, if the monitor is occupied, otherwise they enter in FIFO order.
    1826 Internal threads block on condition queues via @wait@ and reenter from the condition in FIFO order.
    1827 Alternatively, 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 
    1829 There are three signalling mechanisms to unblock waiting threads to enter the monitor.
    1830 Note, 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.
    1831 For internal scheduling, threads are unblocked from condition queues using @signal@, where the signallee is moved to urgent and the signaller continues (solid line).
    1832 Multiple signals move multiple signallees to urgent until the condition is empty.
    1833 When the signaller exits or waits, a thread blocked on urgent is processed before calling threads to prevent barging.
     1953Furthermore, \CFA concurrency has no spurious wakeup~\cite[\S~9]{Buhr05a}, which eliminates an implicit self barging.
     1954
     1955Monitor mutual-exclusion means signalling cannot have the signaller and signalled thread in the monitor simultaneously, so only the signaller or signallee can proceed.
     1956Figure~\ref{f:MonitorScheduling} shows internal/external scheduling for the bounded-buffer examples in Figure~\ref{f:GenericBoundedBuffer}.
     1957For 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).
     1958Multiple signals move multiple signallees to urgent until the condition queue is empty.
     1959When the signaller exits or waits, a thread is implicitly unblocked from urgent (if available) before unblocking a calling thread to prevent barging.
    18341960(Java conceptually moves the signalled thread to the calling queue, and hence, allows barging.)
    1835 The 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 
    1837 For external scheduling, the condition queues are not used;
    1838 instead 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)$.)
    1840 The @waitfor@ has the same semantics as @signal_block@, where the signalled thread executes before the signallee, which waits on urgent.
    1841 Executing multiple @waitfor@s from different signalled functions causes the calling threads to move to urgent.
    1842 External scheduling requires urgent to be a stack, because the signaller expects to execute immediately after the specified monitor call has exited or waited.
    1843 Internal 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.
    1844 If 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.
    1845 We tried both a stack for @waitfor@ and queue for signalling, but that resulted in complex semantics about which thread enters next.
    1846 Hence, \CFA uses a single urgent stack to correctly handle @waitfor@ and adequately support both forms of signalling.
     1961Signal 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.
     1962Specifically, the @wait@ function atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the function's parameter list.
     1963Signalling is unconditional because signalling an empty condition queue does nothing.
     1964It 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.
     1965In \CFA, a condition queue can be created/stored independently.
    18471966
    18481967\begin{figure}
     
    18621981\end{figure}
    18631982
    1864 Figure~\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@.
    1865 The @wait@ function atomically blocks the calling thread and implicitly releases the monitor lock(s) for all monitors in the function's parameter list.
    1866 The appropriate condition variable is signalled to unblock an opposite kind of thread after an element is inserted/removed from the buffer.
    1867 Signalling is unconditional, because signalling an empty condition variable does nothing.
    1868 It 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.
    1869 In \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 
    18841983\begin{figure}
    18851984\centering
     
    18931992                T elements[10];
    18941993        };
    1895         void ?{}( Buffer(T) & buffer ) with(buffer) {
     1994        void ?{}( Buffer(T) & buf ) with(buf) {
    18961995                front = back = count = 0;
    18971996        }
    1898         void insert( Buffer(T) & mutex buffer, T elem )
    1899                                 with(buffer) {
    1900                 if ( count == 10 ) `wait( empty )`;
    1901                 // insert elem into buffer
     1997
     1998        void insert(Buffer(T) & mutex buf, T elm) with(buf){
     1999                if ( count == 10 ) `wait( empty )`; // full ?
     2000                // insert elm into buf
    19022001                `signal( full )`;
    19032002        }
    1904         T remove( Buffer(T) & mutex buffer ) with(buffer) {
    1905                 if ( count == 0 ) `wait( full )`;
    1906                 // remove elem from buffer
     2003        T remove( Buffer(T) & mutex buf ) with(buf) {
     2004                if ( count == 0 ) `wait( full )`; // empty ?
     2005                // remove elm from buf
    19072006                `signal( empty )`;
    1908                 return elem;
     2007                return elm;
    19092008        }
    19102009}
    19112010\end{cfa}
    19122011\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}
    19422012
    19432013\newbox\myboxB
    19442014\begin{lrbox}{\myboxB}
    19452015\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     2016forall( 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
     2051The @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).
     2052Signal 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.
     2053Using @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
     2055External 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++}.
     2056While prior languages use external scheduling solely for thread interaction, \CFA generalizes it to both monitors and threads.
     2057External scheduling allows waiting for events from other threads while restricting unrelated events, that would otherwise have to wait on condition queues in the monitor.
     2058Scheduling 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.
     2059Specifically, 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)$.)
     2061Hence, 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.
     2062Now 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.
     2063For 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.
     2064Hence, this mechanism is done in terms of control flow, next call, versus in terms of data, channels, as in Go/Rust @select@.
     2065While both mechanisms have strengths and weaknesses, \CFA uses the control-flow mechanism to be consistent with other language features.
     2066
     2067Figure~\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.
     2068For 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.
     2069To 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@.
     2070An 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.
     2071For 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@.
     2072The writer does a similar action for each reader or writer using the resource.
     2073Note, 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]
     2080enum RW { READER, WRITER };
    19462081monitor ReadersWriter {
    1947         int rcnt, wcnt; // readers/writer using resource
     2082        int rcnt, wcnt; // readers/writer using resource
     2083        `condition RWers;`
    19482084};
    19492085void ?{}( ReadersWriter & rw ) with(rw) {
     
    19522088void EndRead( ReadersWriter & mutex rw ) with(rw) {
    19532089        rcnt -= 1;
     2090        if ( rcnt == 0 ) `signal( RWers )`;
    19542091}
    19552092void EndWrite( ReadersWriter & mutex rw ) with(rw) {
    19562093        wcnt = 0;
     2094        `signal( RWers );`
    19572095}
    19582096void StartRead( ReadersWriter & mutex rw ) with(rw) {
    1959         if ( wcnt > 0 ) `waitfor( EndWrite, rw );`
     2097        if ( wcnt !=0 || ! empty( RWers ) )
     2098                `wait( RWers, READER )`;
    19602099        rcnt += 1;
     2100        if ( ! empty(RWers) && `front(RWers) == READER` )
     2101                `signal( RWers )`;  // daisy-chain signalling
    19612102}
    19622103void StartWrite( ReadersWriter & mutex rw ) with(rw) {
    1963         if ( wcnt > 0 ) `waitfor( EndWrite, rw );`
    1964         else while ( rcnt > 0 ) `waitfor( EndRead, rw );`
     2104        if ( wcnt != 0 || rcnt != 0 ) `wait( RWers, WRITER )`;
     2105
    19652106        wcnt = 1;
    19662107}
    1967 
    19682108\end{cfa}
    19692109\end{lrbox}
    19702110
    1971 \subfloat[Generic bounded buffer, internal scheduling]{\label{f:BBInt}\usebox\myboxA}
    1972 \hspace{3pt}
     2111\newbox\myboxB
     2112\begin{lrbox}{\myboxB}
     2113\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     2114
     2115monitor ReadersWriter {
     2116        int rcnt, wcnt; // readers/writer using resource
     2117
     2118};
     2119void ?{}( ReadersWriter & rw ) with(rw) {
     2120        rcnt = wcnt = 0;
     2121}
     2122void EndRead( ReadersWriter & mutex rw ) with(rw) {
     2123        rcnt -= 1;
     2124
     2125}
     2126void EndWrite( ReadersWriter & mutex rw ) with(rw) {
     2127        wcnt = 0;
     2128
     2129}
     2130void StartRead( ReadersWriter & mutex rw ) with(rw) {
     2131        if ( wcnt > 0 ) `waitfor( EndWrite : rw );`
     2132
     2133        rcnt += 1;
     2134
     2135
     2136}
     2137void 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}
    19732147\vrule
    19742148\hspace{3pt}
    1975 \subfloat[Readers / writer lock, external scheduling]{\label{f:RWExt}\usebox\myboxB}
    1976 
    1977 \caption{Internal / external scheduling}
    1978 \label{f:InternalExternalScheduling}
     2149\subfloat[External scheduling]{\label{f:RWExt}\usebox\myboxB}
     2150
     2151\caption{Readers / writer lock}
     2152\label{f:ReadersWriterLock}
    19792153\end{figure}
    19802154
    1981 Figure~\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]
    1983 if ( count == 10 ) `waitfor( remove, buffer )`;       |      if ( count == 0 ) `waitfor( insert, buffer )`;
    1984 \end{cfa}
    1985 Here, 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.
    1986 External 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.
    1987 If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer.
    1988 Threads 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.
    1989 Figure~\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@.
    1990 The writer does a similar action for each reader or writer using the resource.
    1991 Note, no new calls to @StarRead@/@StartWrite@ may occur when waiting for the call to @EndRead@/@EndWrite@.
    1992 External scheduling allows waiting for events from other threads while restricting unrelated events, that would otherwise have to wait on conditions in the monitor.
    1993 The 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.
    1994 While 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 
    1997 Figure~\ref{f:DatingService} shows a dating service demonstrating non-blocking and blocking signalling.
    1998 The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
    1999 A thread blocks until an appropriate partner arrives.
    2000 The complexity is exchanging phone numbers in the monitor because of the mutual-exclusion property.
    2001 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.
    2002 For 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.
    2003 The 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;
    2004 as well, an arriving thread may not find a partner and must wait, which requires a condition variable, and condition variables imply internal scheduling.
    2005 Furthermore, 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.
    2006 Putting loops around the @wait@s does not correct the problem;
    2007 the simple solution must be restructured to account for barging.
     2155Finally, external scheduling requires urgent to be a stack, because the signaller expects to execute immediately after the specified monitor call has exited or waited.
     2156Internal schedulling performing multiple signalling results in unblocking from urgent in the reverse order from signalling.
     2157It is rare for the unblocking order to be important as an unblocked thread can be time-sliced immediately after leaving the monitor.
     2158If the unblocking order is important, multiple signalling can be restructured into daisy-chain signalling, where each thread signals the next thread.
     2159Hence, \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}.)
    20082161
    20092162\begin{figure}
     
    20192172};
    20202173int girl( DS & mutex ds, int phNo, int ccode ) {
    2021         if ( is_empty( Boys[ccode] ) ) {
     2174        if ( empty( Boys[ccode] ) ) {
    20222175                wait( Girls[ccode] );
    20232176                GirlPhNo = phNo;
     
    20462199};
    20472200int girl( DS & mutex ds, int phNo, int ccode ) {
    2048         if ( is_empty( Boys[ccode] ) ) { // no compatible
     2201        if ( empty( Boys[ccode] ) ) { // no compatible
    20492202                wait( Girls[ccode] ); // wait for boy
    20502203                GirlPhNo = phNo; // make phone number available
     
    20662219\qquad
    20672220\subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB}
    2068 \caption{Dating service}
    2069 \label{f:DatingService}
     2221\caption{Dating service Monitor}
     2222\label{f:DatingServiceMonitor}
    20702223\end{figure}
    20712224
    2072 In 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;
    2073 the 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.
    2074 The waiter unblocks next from the urgent queue, uses/takes the state, and exits the monitor.
    2075 Blocking signal is the reverse, where the waiter is providing the cooperation for the signalling thread;
    2076 the 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.
    2077 The waiter changes state and exits the monitor, and the signaller unblocks next from the urgent queue to use/take the state.
     2225Figure~\ref{f:DatingServiceMonitor} shows a dating service demonstrating non-blocking and blocking signalling.
     2226The dating service matches girl and boy threads with matching compatibility codes so they can exchange phone numbers.
     2227A thread blocks until an appropriate partner arrives.
     2228The complexity is exchanging phone numbers in the monitor because of the mutual-exclusion property.
     2229For 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.
     2230For 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
     2232The dating service is an important example of a monitor that cannot be written using external scheduling.
     2233First, because scheduling requires knowledge of calling parameters to make matching decisions, and parameters of calling threads are unavailable within the monitor.
     2234For 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.
     2235Second, 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.
     2236For example, if a girl thread could determine there is no calling boy with the same @ccode@, it must wait until a matching boy arrives.
     2237Finally, 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.
     2238This situation shows rechecking the waiting condition and waiting again (signals-as-hints) fails, requiring significant restructured to account for barging.
    20782239
    20792240Both internal and external scheduling extend to multiple monitors in a natural way.
    20802241\begin{cquote}
    2081 \begin{tabular}{@{}l@{\hspace{3\parindentlnth}}l@{}}
     2242\begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
    20822243\begin{cfa}
    20832244monitor M { `condition e`; ... };
     
    20902251&
    20912252\begin{cfa}
    2092 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 );
     2253void rtn$\(_1\)$( M & mutex m1, M & mutex m2 ); // overload rtn
    20932254void rtn$\(_2\)$( M & mutex m1 );
    20942255void bar( M & mutex m1, M & mutex m2 ) {
    2095         ... waitfor( `rtn` ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\), m1, m2 )}$
    2096         ... waitfor( `rtn, m1` ); ... // $\LstCommentStyle{waitfor( rtn\(_2\), m1 )}$
     2256        ... waitfor( `rtn`${\color{red}\(_1\)}$ ); ...       // $\LstCommentStyle{waitfor( rtn\(_1\) : m1, m2 )}$
     2257        ... waitfor( `rtn${\color{red}\(_2\)}$ : m1` ); ...
    20972258}
    20982259\end{cfa}
     
    21012262For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex parameters, \ie @wait( e, m1, m2 )@.
    21022263To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
    2103 Wait cannot statically verifies the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
    2104 While \CC supports bulk locking, @wait@ only accepts a single lock for a condition variable, so bulk locking with condition variables is asymmetric.
     2264Wait cannot statically verify the released monitors are the acquired mutex-parameters without disallowing separately compiled helper functions calling @wait@.
     2265While \CC supports bulk locking, @wait@ only accepts a single lock for a condition queue, so bulk locking with condition queues is asymmetric.
    21052266Finally, a signaller,
    21062267\begin{cfa}
     
    21112272must 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.
    21122273
    2113 Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn, m1, m2 )@.
    2114 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@.
     2274Similarly, for @waitfor( rtn )@, the default semantics is to atomically block the acceptor and release all acquired mutex parameters, \ie @waitfor( rtn : m1, m2 )@.
     2275To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn : m1 )@.
    21152276@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.
    21162277% When an overloaded function appears in an @waitfor@ statement, calls to any function with that name are accepted.
     
    21202281void rtn( M & mutex m );
    21212282`int` rtn( M & mutex m );
    2122 waitfor( (`int` (*)( M & mutex ))rtn, m );
    2123 \end{cfa}
    2124 
    2125 The ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock.
     2283waitfor( (`int` (*)( M & mutex ))rtn : m );
     2284\end{cfa}
     2285
     2286The 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
    21262288\begin{cfa}
    21272289void foo( M & mutex m1, M & mutex m2 ) {
    2128         ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired )}$
    2129 void bar( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2 )}$
     2290        ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired}$
     2291void bar( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2}$
    21302292        ... signal( `e` ); ...
    21312293\end{cfa}
    21322294The @wait@ only releases @m1@ so the signalling thread cannot acquire @m1@ and @m2@ to enter @bar@ and @signal@ the condition.
    2133 While deadlock can occur with multiple/nesting acquisition, this is a consequence of locks, and by extension monitors, not being perfectly composable.
    2134 
     2295While deadlock can occur with multiple/nesting acquisition, this is a consequence of locks, and by extension monitor locking is not perfectly composable.
    21352296
    21362297
    21372298\subsection{\texorpdfstring{Extended \protect\lstinline@waitfor@}{Extended waitfor}}
     2299\label{s:ExtendedWaitfor}
    21382300
    21392301Figure~\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.
     
    21462308Hence, the terminating @else@ clause allows a conditional attempt to accept a call without blocking.
    21472309If both @timeout@ and @else@ clause are present, the @else@ must be conditional, or the @timeout@ is never triggered.
    2148 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.
     2310There is also a traditional future wait queue (not shown) (\eg Microsoft @WaitForMultipleObjects@), to wait for a specified number of future elements in the queue.
     2311Finally, there is a shorthand for specifying multiple functions using the same set of monitors: @waitfor( f, g, h : m1, m2, m3 )@.
    21492312
    21502313\begin{figure}
     
    21732336The right example accepts either @mem1@ or @mem2@ if @C1@ and @C2@ are true.
    21742337
    2175 An 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@.
     2338An 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@.
    21762339\begin{cfa}
    21772340void main( Buffer(T) & buffer ) with(buffer) {
    21782341        for () {
    2179                 `waitfor( ^?{}, buffer )` break;
    2180                 or when ( count != 20 ) waitfor( insert, buffer ) { ... }
    2181                 or when ( count != 0 ) waitfor( remove, buffer ) { ... }
     2342                `waitfor( ^?{} : buffer )` break;
     2343                or when ( count != 20 ) waitfor( insert : buffer ) { ... }
     2344                or when ( count != 0 ) waitfor( remove : buffer ) { ... }
    21822345        }
    21832346        // clean up
     
    22712434To support this efficient semantics (and prevent barging), the implementation maintains a list of monitors acquired for each blocked thread.
    22722435When a signaller exits or waits in a monitor function/statement, the front waiter on urgent is unblocked if all its monitors are released.
    2273 Implementing a fast subset check for the necessary released monitors is important.
     2436Implementing a fast subset check for the necessary released monitors is important and discussed in the following sections.
    22742437% 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.
    22752438
    22762439
    2277 \subsection{Loose Object Definitions}
    2278 \label{s:LooseObjectDefinitions}
    2279 
    2280 In an object-oriented programming language, a class includes an exhaustive list of operations.
    2281 A 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.)
    2283 In 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 
    2285 However, 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
    2288 translation unit 1
    2289         void `f`( M & mutex m );
    2290         void g( M & mutex m ) { waitfor( `f`, m ); }
    2291 translation 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}
    2296 The @waitfor@ statements in each translation unit cannot form a unique bit-mask because the monitor type does not carry that information.
     2440\subsection{\texorpdfstring{\protect\lstinline@waitfor@ Implementation}{waitfor Implementation}}
     2441\label{s:waitforImplementation}
     2442
     2443In 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}).
     2444Knowing 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}$
     2468monitor M { ... }; // common type in .h file
     2469void `f`( M & mutex m, ... );
     2470void `g`( M & mutex m, ... );
     2471void w1( M & mutex m, ... ) { ... waitfor(`f`, `g` : m); ... }
     2472
     2473$\emph{translation unit 2}$
     2474// include M
     2475extern void `f`( M & mutex m, ... ); // import f but not g
     2476void `h`( M & mutex m ); // add
     2477void 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
     2491However, 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.
     2492(A possible way to construct a dense mapping is at link or load-time.)
    22972493Hence, function pointers are used to identify the functions listed in the @waitfor@ statement, stored in a variable-sized array.
    2298 Then, the same implementation approach used for the urgent stack is used for the calling queue.
    2299 Each 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.
    2300 (A possible way to construct a dense mapping is at link or load-time.)
     2494Then, the same implementation approach used for the urgent stack (see Section~\ref{s:Scheduling}) is used for the calling queue.
     2495Each 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.
    23012496
    23022497
     
    23132508The solution is for the programmer to disambiguate:
    23142509\begin{cfa}
    2315 waitfor( f, `m2` ); $\C{// wait for call to f with argument m2}$
     2510waitfor( f : `m2` ); $\C{// wait for call to f with argument m2}$
    23162511\end{cfa}
    23172512Both 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@.
     
    23202515monitor M { ... };
    23212516void f( M & mutex m1, M & mutex m2 );
    2322 void g( M & mutex m1, M & mutex m2 ) { waitfor( f, `m1, m2` ); $\C{// wait for call to f with arguments m1 and m2}$
     2517void g( M & mutex m1, M & mutex m2 ) { waitfor( f : `m1, m2` ); $\C{// wait for call to f with arguments m1 and m2}$
    23232518\end{cfa}
    23242519Again, the set of monitors passed to the @waitfor@ statement must be entirely contained in the set of monitors already acquired by the accepting function.
    2325 Also, the order of the monitors in a @waitfor@ statement is unimportant.
    2326 
    2327 Figure~\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.
    2328 For both examples, the set of monitors is disjoint so unblocking is impossible.
     2520% Also, the order of the monitors in a @waitfor@ statement must match the order of the mutex parameters.
     2521
     2522Figure~\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.
     2523In both cases, the set of monitors is disjoint so unblocking is impossible.
    23292524
    23302525\begin{figure}
     
    23552550}
    23562551void g( M1 & mutex m1, M2 & mutex m2 ) {
    2357         waitfor( f, m1, m2 );
     2552        waitfor( f : m1, m2 );
    23582553}
    23592554g( `m11`, m2 ); // block on accept
     
    23702565\end{figure}
    23712566
    2372 
    2373 \subsection{\texorpdfstring{\protect\lstinline@mutex@ Threads}{mutex Threads}}
    2374 
    2375 Threads 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.
    2376 Hence, all monitor features are available when using threads.
    2377 Figure~\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.)
    2379 The program main in both programs communicates directly with the other thread versus indirect communication where two threads interact through a passive monitor.
    2380 Both direct and indirection thread communication are valuable tools in structuring concurrent programs.
    2381 
    23822567\begin{figure}
    23832568\centering
     
    23862571
    23872572struct Msg { int i, j; };
    2388 thread GoRtn { int i;  float f;  Msg m; };
     2573monitor thread GoRtn { int i;  float f;  Msg m; };
    23892574void mem1( GoRtn & mutex gortn, int i ) { gortn.i = i; }
    23902575void mem2( GoRtn & mutex gortn, float f ) { gortn.f = f; }
     
    23962581        for () {
    23972582
    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;
     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
    24022587
    24032588        }
     
    24532638\hspace{3pt}
    24542639\subfloat[Go]{\label{f:Gochannel}\usebox\myboxB}
    2455 \caption{Direct communication}
    2456 \label{f:DirectCommunication}
     2640\caption{Direct versus indirect communication}
     2641\label{f:DirectCommunicationComparison}
     2642
     2643\medskip
     2644
     2645\begin{cfa}
     2646monitor thread DatingService {
     2647        condition Girls[CompCodes], Boys[CompCodes];
     2648        int girlPhoneNo, boyPhoneNo, ccode;
     2649};
     2650int 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}
     2655int 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}
     2660void 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}
    24572672\end{figure}
    24582673
     
    24692684void main( Ping & pi ) {
    24702685        for ( 10 ) {
    2471                 `waitfor( ping, pi );`
     2686                `waitfor( ping : pi );`
    24722687                `pong( po );`
    24732688        }
     
    24822697        for ( 10 ) {
    24832698                `ping( pi );`
    2484                 `waitfor( pong, po );`
     2699                `waitfor( pong : po );`
    24852700        }
    24862701}
     
    24972712
    24982713
    2499 \subsection{Execution Properties}
    2500 
    2501 Table~\ref{t:ObjectPropertyComposition} shows how the \CFA high-level constructs cover 3 fundamental execution properties: thread, stateful function, and mutual exclusion.
    2502 Case 1 is a basic object, with none of the new execution properties.
    2503 Case 2 allows @mutex@ calls to Case 1 to protect shared data.
    2504 Case 3 allows stateful functions to suspend/resume but restricts operations because the state is stackless.
    2505 Case 4 allows @mutex@ calls to Case 3 to protect shared data.
    2506 Cases 5 and 6 are the same as 3 and 4 without restriction because the state is stackful.
    2507 Cases 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.
    2508 Cases 9 and 10 have a stackful thread without and with @mutex@ calls.
    2509 For 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
    2520 thread  & stateful                              & \multicolumn{1}{c|}{No} & \multicolumn{1}{c}{Yes} \\
    2521 \hline
    2522 \hline
    2523 No              & No                                    & \textbf{1}\ \ \ aggregate type                & \textbf{2}\ \ \ @monitor@ aggregate type \\
    2524 \hline
    2525 No              & Yes (stackless)               & \textbf{3}\ \ \ @generator@                   & \textbf{4}\ \ \ @monitor@ @generator@ \\
    2526 \hline
    2527 No              & Yes (stackful)                & \textbf{5}\ \ \ @coroutine@                   & \textbf{6}\ \ \ @monitor@ @coroutine@ \\
    2528 \hline
    2529 Yes             & No / Yes (stackless)  & \textbf{7}\ \ \ {\color{red}rejected} & \textbf{8}\ \ \ {\color{red}rejected} \\
    2530 \hline
    2531 Yes             & Yes (stackful)                & \textbf{9}\ \ \ @thread@                              & \textbf{10}\ \ @monitor@ @thread@ \\
    2532 \end{tabular}
    2533 \end{table}
     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.
     2717All monitor features are available within these mutex functions.
     2718For 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}
     2720void fmt( Fmt & mutex fmt, char ch ) { fmt.ch = ch; resume( fmt ) }
     2721\end{cfa}
     2722multiple threads can safely pass characters for formatting.
     2723
     2724Figure~\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.)
     2726The 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.
     2727Communication by multiple threads is safe for the @gortn@ thread via mutex calls in \CFA or channel assignment in Go.
     2728
     2729Figure~\ref{f:DirectCommunicationDatingService} shows the dating-service problem in Figure~\ref{f:DatingServiceMonitor} extended from indirect monitor communication to direct thread communication.
     2730When 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.
     2731Notice, the dating server is postponing requests for an unspecified time while continuing to accept new requests.
     2732For complex servers (web-servers), there can be hundreds of lines of code in the thread main and safe interaction with clients can be complex.
    25342733
    25352734
     
    25372736
    25382737For 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.
    2539 Some of these low-level mechanism are used in the \CFA runtime, but we strongly advocate using high-level mechanisms whenever possible.
     2738Some of these low-level mechanism are used to build the \CFA runtime, but we always advocate using high-level mechanisms whenever possible.
    25402739
    25412740
     
    25802779\begin{cfa}
    25812780struct Adder {
    2582     int * row, cols;
     2781        int * row, cols;
    25832782};
    25842783int operator()() {
     
    26392838\label{s:RuntimeStructureCluster}
    26402839
    2641 A \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).
     2840A \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.
     2841The term \newterm{virtual processor} is introduced as a synonym for kernel thread to disambiguate between user and kernel thread.
     2842From the language perspective, a virtual processor is an actual processor (core).
     2843
    26422844The purpose of a cluster is to control the amount of parallelism that is possible among threads, plus scheduling and other execution defaults.
    26432845The default cluster-scheduler is single-queue multi-server, which provides automatic load-balancing of threads on processors.
     
    26582860Programs may use more virtual processors than hardware processors.
    26592861On a multiprocessor, kernel threads are distributed across the hardware processors resulting in virtual processors executing in parallel.
    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.)
     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
    26612863The \CFA runtime attempts to block unused processors and unblock processors as the system load increases;
    2662 balancing the workload with processors is difficult because it requires future knowledge, \ie what will the applicaton workload do next.
     2864balancing the workload with processors is difficult because it requires future knowledge, \ie what will the application workload do next.
    26632865Preemption occurs on virtual processors rather than user threads, via operating-system interrupts.
    26642866Thus virtual processors execute user threads, where preemption frequency applies to a virtual processor, so preemption occurs randomly across the executed user threads.
     
    26952897Nondeterministic 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.
    26962898This atomic reliance can fail on multi-core machines, because execution across cores is nondeterministic.
    2697 A 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).
     2899A 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).
    26982900Preemption is normally handled by setting a countdown timer on each virtual processor.
    2699 When 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.
     2901When 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.
    27002902Multiple signal handlers may be pending.
    27012903When 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.
    27022904The 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;
    27032905therefore, the same signal mask is required for all virtual processors in a cluster.
    2704 Because preemption frequency is usually long (1 millisecond) performance cost is negligible.
    2705 
    2706 Linux switched a decade ago from specific to arbitrary process signal-delivery for applications with multiple kernel threads.
    2707 \begin{cquote}
    2708 A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked.
    2709 If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which it will deliver the signal.
    2710 SIGNAL(7) - Linux Programmer's Manual
    2711 \end{cquote}
     2906Because preemption interval is usually long (1 millisecond) performance cost is negligible.
     2907
     2908Linux switched a decade ago from specific to arbitrary virtual-processor signal-delivery for applications with multiple kernel threads.
     2909In 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.
    27122910Hence, 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).
    27132911To 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.
     
    27272925\label{s:Performance}
    27282926
    2729 To 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.
     2927To 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.
    27302928For 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.
    2731 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 \CFA/\uC are compiled with gcc 6.5.
     2929The 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.
    27322930
    27332931All benchmarks are run using the following harness. (The Java harness is augmented to circumvent JIT issues.)
    27342932\begin{cfa}
    2735 unsigned int N = 10_000_000;
    2736 #define BENCH( `run` ) Time before = getTimeNsec();  `run;`  Duration result = (getTimeNsec() - before) / N;
    2737 \end{cfa}
    2738 The method used to get time is @clock_gettime( CLOCK_REALTIME )@.
    2739 Each benchmark is performed @N@ times, where @N@ varies depending on the benchmark;
    2740 the total time is divided by @N@ to obtain the average time for a benchmark.
    2741 Each benchmark experiment is run 31 times.
     2933#define BENCH( `run` ) uint64_t start = cputime_ns();  `run;`  double result = (double)(cputime_ns() - start) / N;
     2934\end{cfa}
     2935where CPU time in nanoseconds is from the appropriate language clock.
     2936Each 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.
     2937The total time is divided by @N@ to obtain the average time for a benchmark.
     2938Each benchmark experiment is run 13 times and the average appears in the table.
    27422939All omitted tests for other languages are functionally identical to the \CFA tests and available online~\cite{CforallBenchMarks}.
    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 
    2747 Object creation is measured by creating/deleting the specific kind of concurrent object.
    2748 Figure~\ref{f:creation} shows the code for \CFA, with results in Table~\ref{tab:creation}.
    2749 The 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 {};
    2755 void @main@( MyThread & ) {}
    2756 int 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          \\
    2777 Goroutine                               & 4068.0        & 4113.1        & 414.55        \\
    2778 Java Thread                             & 103848.5      & 104295.4      & 2637.57       \\
    2779 Pthreads                                & 33112.6       & 33127.1       & 165.90
    2780 \end{tabular}
    2781 \end{multicols}
    2782 
    2783 
    2784 \paragraph{Context-Switching}
     2940% tar --exclude-ignore=exclude -cvhf benchmark.tar benchmark
     2941
     2942\paragraph{Context Switching}
    27852943
    27862944In procedural programming, the cost of a function call is important as modularization (refactoring) increases.
    2787 (In many cases, a compiler inlines function calls to eliminate this cost.)
    2788 Similarly, when modularization extends to coroutines/tasks, the time for a context switch becomes a relevant factor.
     2945(In many cases, a compiler inlines function calls to increase the size and number of basic blocks for optimizing.)
     2946Similarly, when modularization extends to coroutines/threads, the time for a context switch becomes a relevant factor.
    27892947The 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.
     2949For 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@).
    27902950The thread test is using yield to enter and return from the runtime kernel, which is two context switches.
    27912951The difference in performance between coroutine and thread context-switch is the cost of scheduling for threads, whereas coroutines are self-scheduling.
    2792 Figure~\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}.
     2952Figure~\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.
    27932965
    27942966\begin{multicols}{2}
    27952967\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    27962968\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    2797 @coroutine@ C {} c;
    2798 void main( C & ) { for ( ;; ) { @suspend;@ } }
     2969@coroutine@ C {};
     2970void main( C & ) { for () { @suspend;@ } }
    27992971int main() { // coroutine test
     2972        C c;
    28002973        BENCH( for ( N ) { @resume( c );@ } )
    2801         sout | result`ns;
    2802 }
    2803 int main() { // task test
     2974        sout | result;
     2975}
     2976int main() { // thread test
    28042977        BENCH( for ( N ) { @yield();@ } )
    2805         sout | result`ns;
     2978        sout | result;
    28062979}
    28072980\end{cfa}
     
    28132986\vspace*{-16pt}
    28142987\captionof{table}{Context switch comparison (nanoseconds)}
    2815 \label{tab:ctx-switch}
     2988\label{t:ctx-switch}
    28162989\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    28172990\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    2818 C 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  \\
    2824 Goroutine               & 141.0 & 141.3 & 3.39  \\
    2825 Java Thread             & 374.0 & 375.8 & 10.38 \\
    2826 Pthreads Thread & 361.0 & 365.3 & 13.19
     2991C 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   \\
     2997Python generator        & 40.9          & 41.3          & 1.5   \\
     2998Node.js generator       & 32.6          & 32.2          & 1.0   \\
     2999Node.js await           & 1852.2        & 1854.7        & 16.4  \\
     3000Goroutine thread        & 143.0         & 143.3         & 1.1   \\
     3001Rust thread                     & 332.0         & 331.4         & 2.4   \\
     3002Java thread                     & 405.0         & 415.0         & 17.6  \\
     3003Pthreads thread         & 334.3         & 335.2         & 3.9
    28273004\end{tabular}
    28283005\end{multicols}
    28293006
    2830 
    2831 \paragraph{Mutual-Exclusion}
    2832 
    2833 Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section.
    2834 For monitors, entering and leaving a monitor function is measured.
    2835 To 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.
    2836 Figure~\ref{f:mutex} shows the code for \CFA with all results in Table~\ref{tab:mutex}.
     3007\paragraph{Internal Scheduling}
     3008
     3009Internal scheduling is measured using a cycle of two threads signalling and waiting.
     3010Figure~\ref{f:schedint} shows the code for \CFA, with results in Table~\ref{t:schedint}.
    28373011Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
     3012Java 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.
    28383013
    28393014\begin{multicols}{2}
    28403015\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    28413016\begin{cfa}
     3017volatile int go = 0;
     3018@condition c;@
    28423019@monitor@ M {} m1/*, m2, m3, m4*/;
    2843 void __attribute__((noinline))
    2844 do_call( M & @mutex m/*, m2, m3, m4*/@ ) {}
     3020void call( M & @mutex p1/*, p2, p3, p4*/@ ) {
     3021        @signal( c );@
     3022}
     3023void wait( M & @mutex p1/*, p2, p3, p4*/@ ) {
     3024        go = 1; // continue other thread
     3025        for ( N ) { @wait( c );@ } );
     3026}
     3027thread T {};
     3028void main( T & ) {
     3029        while ( go == 0 ) { yield(); } // waiter must start first
     3030        BENCH( for ( N ) { call( m1/*, m2, m3, m4*/ ); } )
     3031        sout | result;
     3032}
    28453033int main() {
    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}
     3034        T t;
     3035        wait( m1/*, m2, m3, m4*/ );
     3036}
     3037\end{cfa}
     3038\captionof{figure}{\CFA Internal-scheduling benchmark}
     3039\label{f:schedint}
    28543040
    28553041\columnbreak
    28563042
    28573043\vspace*{-16pt}
    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} \\
    2862 test 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  \\
    2867 Java synchronized method                & 31.0  & 31.1  & 0.50  \\
    2868 Pthreads Mutex Lock                             & 33.6  & 32.6  & 1.14
     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           \\
     3054Rust cond. variable                     & 7514.0        & 7437.4        & 397.2         \\
     3055Java @notify@ monitor           & 9623.0        & 9654.6        & 236.2         \\
     3056Pthreads cond. variable         & 5553.7        & 5576.1        & 345.6
    28693057\end{tabular}
    28703058\end{multicols}
     
    28743062
    28753063External scheduling is measured using a cycle of two threads calling and accepting the call using the @waitfor@ statement.
    2876 Figure~\ref{f:ext-sched} shows the code for \CFA, with results in Table~\ref{tab:ext-sched}.
     3064Figure~\ref{f:schedext} shows the code for \CFA with results in Table~\ref{t:schedext}.
    28773065Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
    28783066
     
    28813069\vspace*{-16pt}
    28823070\begin{cfa}
    2883 volatile int go = 0;
    2884 @monitor@ M {} m;
     3071@monitor@ M {} m1/*, m2, m3, m4*/;
     3072void call( M & @mutex p1/*, p2, p3, p4*/@ ) {}
     3073void wait( M & @mutex p1/*, p2, p3, p4*/@ ) {
     3074        for ( N ) { @waitfor( call : p1/*, p2, p3, p4*/ );@ }
     3075}
    28853076thread T {};
    2886 void __attribute__((noinline))
    2887 do_call( M & @mutex@ ) {}
    28883077void main( T & ) {
    2889         while ( go == 0 ) { yield(); }
    2890         while ( go == 1 ) { do_call( m ); }
    2891 }
    2892 int __attribute__((noinline))
    2893 do_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;
     3078        BENCH( for ( N ) { call( m1/*, m2, m3, m4*/ ); } )
     3079        sout | result;
    28983080}
    28993081int main() {
    29003082        T t;
    2901         do_wait( m );
     3083        wait( m1/*, m2, m3, m4*/ );
    29023084}
    29033085\end{cfa}
    29043086\captionof{figure}{\CFA external-scheduling benchmark}
    2905 \label{f:ext-sched}
     3087\label{f:schedext}
    29063088
    29073089\columnbreak
     
    29093091\vspace*{-16pt}
    29103092\captionof{table}{External-scheduling comparison (nanoseconds)}
    2911 \label{tab:ext-sched}
     3093\label{t:schedext}
    29123094\begin{tabular}{@{}r*{3}{D{.}{.}{3.2}}@{}}
    29133095\multicolumn{1}{@{}c}{} & \multicolumn{1}{c}{Median} &\multicolumn{1}{c}{Average} & \multicolumn{1}{c@{}}{Std Dev} \\
    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
     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   \\
     3100Go \lstinline[language=Golang]|select| channel  & 365.0 & 365.5 & 1.2
    29183101\end{tabular}
    29193102\end{multicols}
    29203103
    2921 
    2922 \paragraph{Internal Scheduling}
    2923 
    2924 Internal scheduling is measured using a cycle of two threads signalling and waiting.
    2925 Figure~\ref{f:int-sched} shows the code for \CFA, with results in Table~\ref{tab:int-sched}.
    2926 Note, the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
    2927 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.
     3104\paragraph{Mutual-Exclusion}
     3105
     3106Uncontented mutual exclusion, which frequently occurs, is measured by entering/leaving a critical section.
     3107For monitors, entering and leaving a monitor function is measured, otherwise the language-appropriate mutex-lock is measured.
     3108For comparison, a spinning (versus blocking) test-and-test-set lock is presented.
     3109Figure~\ref{f:mutex} shows the code for \CFA with results in Table~\ref{t:mutex}.
     3110Note the incremental cost of bulk acquire for \CFA, which is largely a fixed cost for small numbers of mutex objects.
    29283111
    29293112\begin{multicols}{2}
    29303113\lstset{language=CFA,moredelim=**[is][\color{red}]{@}{@},deletedelim=**[is][]{`}{`}}
    29313114\begin{cfa}
    2932 volatile int go = 0;
    2933 @monitor@ M { @condition c;@ } m;
    2934 void __attribute__((noinline))
    2935 do_call( M & @mutex@ a1 ) { @signal( c );@ }
    2936 thread T {};
    2937 void main( T & this ) {
    2938         while ( go == 0 ) { yield(); }
    2939         while ( go == 1 ) { do_call( m ); }
    2940 }
    2941 int  __attribute__((noinline))
    2942 do_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 }
     3115@monitor@ M {} m1/*, m2, m3, m4*/;
     3116call( M & @mutex p1/*, p2, p3, p4*/@ ) {}
    29483117int main() {
    2949         T t;
    2950         do_wait( m );
    2951 }
    2952 \end{cfa}
    2953 \captionof{figure}{\CFA Internal-scheduling benchmark}
    2954 \label{f:int-sched}
     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}
    29553124
    29563125\columnbreak
    29573126
    29583127\vspace*{-16pt}
    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          \\
    2969 Java @notify@                           & 10160.5       & 10169.4       & 267.71        \\
    2970 Pthreads Cond. Variable         & 4949.6        & 5065.2        & 363
     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} \\
     3132test-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   \\
     3137Goroutine mutex lock                    & 34.0  & 34.0  & 0.0   \\
     3138Rust mutex lock                                 & 33.0  & 33.2  & 0.8   \\
     3139Java synchronized method                & 31.0  & 31.0  & 0.0   \\
     3140Pthreads mutex Lock                             & 31.0  & 31.1  & 0.4
    29713141\end{tabular}
    29723142\end{multicols}
    29733143
     3144\paragraph{Creation}
     3145
     3146Creation is measured by creating/deleting a specific kind of control-flow object.
     3147Figure~\ref{f:creation} shows the code for \CFA with results in Table~\ref{t:creation}.
     3148Note, 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 {};
     3154void ?{}( MyCoroutine & this ) {
     3155#ifdef EAGER
     3156        resume( this );
     3157#endif
     3158}
     3159void main( MyCoroutine & ) {}
     3160int 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           \\
     3182Python generator                & 123.2         & 124.3         & 4.1           \\
     3183Node.js generator               & 32.3          & 32.2          & 0.3           \\
     3184Goroutine thread                & 751.0         & 750.5         & 3.1           \\
     3185Rust thread                             & 53801.0       & 53896.8       & 274.9         \\
     3186Java thread                             & 120274.0      & 120722.9      & 2356.7        \\
     3187Pthreads thread                 & 31465.5       & 31419.5       & 140.4
     3188\end{tabular}
     3189\end{multicols}
     3190
     3191
     3192\subsection{Discussion}
     3193
     3194Languages using 1:1 threading based on pthreads can at best meet or exceed (due to language overhead) the pthread results.
     3195Note, pthreads has a fast zero-contention mutex lock checked in user space.
     3196Languages with M:N threading have better performance than 1:1 because there is no operating-system interactions.
     3197Languages with stackful coroutines have higher cost than stackless coroutines because of stack allocation and context switching;
     3198however, stackful \uC and \CFA coroutines have approximately the same performance as stackless Python and Node.js generators.
     3199The \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
    29743201
    29753202\section{Conclusion}
     
    29773204Advanced control-flow will always be difficult, especially when there is temporal ordering and nondeterminism.
    29783205However, many systems exacerbate the difficulty through their presentation mechanisms.
    2979 This 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.
    2980 Eliminated 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@.
     3206This paper shows it is possible to understand high-level control-flow using three properties: statefulness, thread, mutual-exclusion/synchronization.
     3207Combining these properties creates a number of high-level, efficient, and maintainable control-flow types: generator, coroutine, thread, each of which can be a monitor.
     3208Eliminated 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@.
    29823210Extending these mechanisms to handle high-level deadlock-free bulk acquire across both mutual exclusion and synchronization is a unique contribution.
    29833211The \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.
    29843212The M:N model is judged to be efficient and provide greater flexibility than a 1:1 threading model.
    29853213These 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.
    2986 Performance 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.
    2987 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.
     3214Performance 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.
     3215C 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.
    29883216
    29893217
     
    30053233\label{futur:nbio}
    30063234
    3007 Many modern workloads are not bound by computation but IO operations, a common case being web servers and XaaS~\cite{XaaS} (anything as a service).
     3235Many modern workloads are not bound by computation but IO operations, common cases being web servers and XaaS~\cite{XaaS} (anything as a service).
    30083236These types of workloads require significant engineering to amortizing costs of blocking IO-operations.
    30093237At 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.
     
    30333261\section{Acknowledgements}
    30343262
    3035 The 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.
    3036 Funding 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.
     3263The 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.
     3264This 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.
    30373265
    30383266{%
    3039 \fontsize{9bp}{12bp}\selectfont%
     3267\fontsize{9bp}{11.5bp}\selectfont%
    30403268\bibliography{pl,local}
    30413269}%
  • doc/papers/concurrency/examples/Fib.py

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

    r71d6bd8 r7030dab  
    11#include <stdio.h>
    22
    3 void mary() {
    4         printf( "MARY\n" );
    5 }
    6 
    73#define FIB_INIT { 0 }
    8 typedef struct { int next; int fn1, fn2; } Fib;
     4typedef struct { int restart; int fn1, fn2; } Fib;
    95int fib( Fib * f ) {
    10         static void * states[] = { &&s1, &&s2, &&s3 };
    11         goto *states[f->next];
     6        static void * states[] = { &&s0, &&s1, &&s2 };
     7        goto *states[f->restart];
     8  s0:
     9        f->fn1 = 0;
     10        f->restart = 1;
     11        return f->fn1;
    1212  s1:
    13         mary();
    14         f->fn1 = 0;
    15         f->next = 1;
    16         return f->fn1;
    17   s2:
    18         mary();
    1913        f->fn2 = f->fn1;
    2014        f->fn1 = 1;
    21         f->next = 2;
     15        f->restart = 2;
    2216        return f->fn1;
    23   s3:;
    24         mary();
     17  s2:;
    2518        int fn = f->fn1 + f->fn2;
    2619        f->fn2 = f->fn1;
  • doc/papers/concurrency/examples/Fib2.py

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

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

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

    r71d6bd8 r7030dab  
    22
    33typedef struct {
    4         void * next;
     4        int restart, g, b;
    55        char ch;
    6         int g, b;
    76} Fmt;
    87
    98void comain( Fmt * f ) {
    10         if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
    11         f->next = &&s1;
     9        static void * states[] = {&&s0, &&s1};
     10        goto *states[f->restart];
     11  s0: f->restart = 1;
    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                                 return;
    16                           s1:;  while ( f->ch == '\n' ) return;         // ignore
     15                                do {
     16                                        return;  s1: ;
     17                                } while ( f->ch == '\n' );                              // ignore
    1718                                printf( "%c", f->ch );                                  // print character
    1819                        }
     
    2425
    2526int main() {
    26         Fmt fmt = { NULL };
     27        Fmt fmt = { 0 };
    2728        comain( &fmt );                                                                         // prime
    2829        for ( ;; ) {
  • doc/papers/concurrency/examples/Format.cc

    r71d6bd8 r7030dab  
    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 -nodebubg Format.cc" //
     33// compile-command: "u++-work -O2 -nodebug Format.cc" //
    3434// End: //
  • doc/papers/concurrency/examples/Format.cfa

    r71d6bd8 r7030dab  
    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

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

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

    r71d6bd8 r7030dab  
    22
    33typedef struct {
    4         void * next;
     4        int restart, g, b;
    55        char ch;
    6         int g, b;
    76} Fmt;
    87
    98void format( Fmt * f ) {
    10         if ( __builtin_expect(f->next != 0, 1) ) goto *f->next;
    11         f->next = &&s1;
     9        static void * states[] = {&&s0, &&s1};
     10        goto *states[f->restart];
     11  s0: f->restart = 1;
    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: ;
    17                                 if ( f->ch == '\0' ) goto fini;                 // EOF ?
     16                          s1: if ( f->ch == '\0' ) goto fini;           // EOF ?
    1817                                while ( f->ch == '\n' ) return;                 // ignore
    19                                 printf( "%c", f->ch );                                  // print character
     18//                              printf( "%c", f->ch );                                  // print character
    2019                        }
    21                         printf( " " );                                                          // block separator
     20//                      printf( " " );                                                          // block separator
    2221                }
    23                 printf( "\n" );                                                                 // group separator
     22//              printf( "\n" );                                                                 // group separator
    2423        }
    25   fini:
    26         if ( f->g != 0 || f->b != 0 ) printf( "\n" );
     24  fini:;
     25//      if ( f->g != 0 || f->b != 0 ) printf( "\n" );
    2726}
    2827
    2928int main() {
    30         Fmt fmt = { NULL };
     29        Fmt fmt = { 0 };
    3130        format( &fmt );                                                                         // prime
    32         for ( ;; ) {
    33                 scanf( "%c", &fmt.ch );                                                 // direct read into communication variable
    34           if ( feof( stdin ) ) break;
     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;
    3535                format( &fmt );
    3636        }
    37         fmt.ch = '\0';
     37        fmt.ch = '\0';                                                                          // sentential (EOF)
    3838        format( &fmt );
    3939}
  • doc/papers/concurrency/examples/PingPong.c

    r71d6bd8 r7030dab  
    22
    33typedef struct PingPong {
     4        int restart;                                                                            // style 1
     5        int N, i;
    46        const char * name;
    5         int N, i;
    67        struct PingPong * partner;
    7         void * next;
     8        void * next;                                                                            // style 2
    89} PingPong;
    9 #define PPCtor( name, N ) { name, N, 0, NULL, NULL }
     10#define PPCtor( name, N ) { 0, N, 0, name, NULL, NULL }
     11
    1012void comain( PingPong * pp ) __attribute__(( noinline ));
    1113void comain( PingPong * pp ) {
     14#if 0
    1215        if ( __builtin_expect(pp->next != 0, 1) ) goto *pp->next;
    13 #if 0
    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 
    3316        pp->next = &&cycle;
    3417        for ( ; pp->i < pp->N; pp->i += 1 ) {
     
    5336          cycle: ;
    5437        } // 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
    5566}
    5667
     
    7081// Local Variables: //
    7182// tab-width: 4 //
    72 // compile-command: "gcc-8 -g -DPRINT PingPong.c" //
     83// compile-command: "gcc-9 -g -DPRINT PingPong.c" //
    7384// End: //
  • doc/papers/concurrency/examples/Pingpong.py

    r71d6bd8 r7030dab  
    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         while True:
    12                 n = next( n )           # schedule coroutine
     10        n = yield                                       # starting coroutine
     11        try:
     12                while True:
     13                        n = next( n )           # schedule coroutine
     14        except StopIteration:
     15                pass
    1316
    1417pi = PingPong( "ping", 5 )
    1518po = PingPong( "pong", 5 )
    16 next( pi )                      # prime
    17 pi.send( po )                   # send partner
    18 next( po )                      # prime
    19 po.send( pi )                   # send partner
     19next( pi )                                              # prime
     20pi.send( po )                                   # send partner
     21next( po )                                              # prime
     22po.send( pi )                                   # send partner
    2023
    2124s = Scheduler();
    22 next( s )                       # prime
     25next( s )                                               # prime
    2326try:
    2427        s.send( pi )                            # start cycle
    25 except StopIteration:
    26         print( "scheduler stop" )
     28except StopIteration:                   # scheduler stopped
     29        pass
    2730print( "stop" )
    2831
    2932# Local Variables: #
    3033# tab-width: 4 #
    31 # compile-command: "python3.5 Pingpong.py" #
     34# compile-command: "python3.7 Pingpong.py" #
    3235# End: #
  • doc/papers/concurrency/examples/ProdCons.py

    r71d6bd8 r7030dab  
    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         while True:
    20                 n = next( n )           # schedule coroutine
     18        n = yield                                       # starting coroutine
     19        try:
     20                while True:
     21                        n = next( n )           # schedule coroutine
     22        except StopIteration:
     23                pass
    2124
    2225prod = Prod( 5 )
    2326cons = Cons( 5 )
    24 next( prod )                    # prime
    25 prod.send( cons )               # send cons
    26 next( cons )                    # prime
    27 cons.send( prod )               # send prod
     27next( prod )                                    # prime
     28prod.send( cons )                               # send cons
     29next( cons )                                    # prime
     30cons.send( prod )                               # send prod
    2831
    2932s = Scheduler();
    30 next( s )                       # prime
     33next( s )                                               # prime
    3134try:
    3235        s.send( prod )                          # start cycle
    33 except StopIteration:
    34         print( "scheduler stop" )
     36except StopIteration:                   # scheduler stopped
     37        pass
    3538print( "stop" )
    3639
    3740# Local Variables: #
    3841# tab-width: 4 #
    39 # compile-command: "python3.5 ProdCons.py" #
     42# compile-command: "python3.7 ProdCons.py" #
    4043# End: #
  • doc/papers/concurrency/examples/Refactor.py

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

    r71d6bd8 r7030dab  
    88-2
    991200 2
    10 5 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 4575.000 2437.500 4275 1875 4575 1800 4875 1875
     105 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 5175.000 2437.500 4875 1875 5175 1800 5475 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 4575.000 1537.500 4875 2100 4575 2175 4275 2100
     125 1 0 1 0 7 100 0 -1 0.000 0 0 1 0 5175.000 1537.500 5475 2100 5175 2175 4875 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 4207.500 1642.500 4125 1425 3975 1650 4200 1875
     145 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 4807.500 1642.500 4725 1425 4575 1650 4800 1875
    1515        1 1 1.00 45.00 90.00
     166 1575 1575 2700 2025
    16172 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    1718        1 1 1.00 45.00 90.00
     
    2021        1 1 1.00 45.00 90.00
    2122         2175 1575 2400 1800
     234 1 0 100 0 4 10 0.0000 2 165 300 1725 1950 ping\001
     244 1 0 100 0 4 10 0.0000 2 135 360 2475 1950 pong\001
     25-6
     266 3075 1575 4200 2025
     276 3075 1575 4200 2025
    22282 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    2329        1 1 1.00 45.00 90.00
    24          3300 1575 3300 1800
     30         3525 1575 3300 1800
    25312 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
    2632        1 1 1.00 45.00 90.00
    27          3300 2025 3300 2250
    28 4 1 0 100 0 0 10 0.0000 2 105 555 2100 1200 creation\001
    29 4 1 0 100 0 4 10 0.0000 2 165 300 1725 1950 ping\001
    30 4 1 0 100 0 4 10 0.0000 2 135 360 2475 1950 pong\001
    31 4 1 0 100 0 4 10 0.0000 2 165 300 3300 1950 ping\001
    32 4 1 0 100 0 4 10 0.0000 2 135 360 3300 2400 pong\001
    33 4 1 0 100 0 0 10 0.0000 2 105 675 4575 1200 execution\001
    34 4 1 0 100 0 4 10 0.0000 2 165 300 4275 2025 ping\001
    35 4 1 0 100 0 4 10 0.0000 2 135 360 4875 2025 pong\001
    36 4 1 0 100 0 0 10 0.0000 2 90 420 3300 1200 starter\001
     33         3675 1575 3900 1800
     344 1 0 100 0 4 10 0.0000 2 165 300 3225 1950 ping\001
     354 1 0 100 0 4 10 0.0000 2 135 360 3975 1950 pong\001
     36-6
     37-6
    37384 1 0 100 0 4 10 0.0000 2 165 705 2100 1500 pgm main\001
    38 4 1 0 100 0 4 10 0.0000 2 165 705 3300 1500 pgm main\001
    39 4 1 0 100 0 4 10 0.0000 2 165 705 4500 1500 pgm main\001
     394 1 0 100 0 4 10 0.0000 2 165 705 3600 1500 pgm main\001
     404 1 0 100 0 4 10 0.0000 2 165 300 4875 2025 ping\001
     414 1 0 100 0 4 10 0.0000 2 135 360 5475 2025 pong\001
     424 1 0 100 0 4 10 0.0000 2 165 705 5100 1500 pgm main\001
     434 1 0 100 0 2 10 0.0000 2 105 540 2100 1275 creator\001
     444 1 0 100 0 2 10 0.0000 2 105 495 3600 1275 starter\001
     454 1 0 100 0 2 10 0.0000 2 105 690 5175 1275 execution\001
  • doc/papers/concurrency/figures/RunTimeStructure.fig

    r71d6bd8 r7030dab  
    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 2175 4650 7050 4950
    39 1 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
    40 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4200 4800 150 75 4200 4800 4350 4875
    41 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3275 4800 100 100 3275 4800 3375 4800
     386 3225 4125 4650 4425
     396 4350 4200 4650 4350
     401 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4425 4275 15 15 4425 4275 4440 4290
     411 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4500 4275 15 15 4500 4275 4515 4290
     421 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 4575 4275 15 15 4575 4275 4590 4290
     43-6
     441 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3450 4275 225 150 3450 4275 3675 4425
     451 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 4275 225 150 4050 4275 4275 4425
     46-6
     476 6675 4125 7500 4425
     486 7200 4200 7500 4350
     491 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7275 4275 15 15 7275 4275 7290 4290
     501 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7350 4275 15 15 7350 4275 7365 4290
     511 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 7425 4275 15 15 7425 4275 7440 4290
     52-6
     531 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 6900 4275 225 150 6900 4275 7125 4425
     54-6
     556 6675 3525 8025 3975
     562 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
     592 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
    42622 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
    44 2 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
    46 4 0 -1 0 0 0 10 0.0000 2 105 450 6600 4875 cluster\001
    47 4 0 -1 0 0 0 10 0.0000 2 105 660 5475 4875 processor\001
    48 4 0 -1 0 0 0 10 0.0000 2 105 555 4425 4875 monitor\001
    49 4 0 -1 0 0 0 10 0.0000 2 120 270 3450 4875 task\001
    50 4 0 -1 0 0 0 10 0.0000 2 105 660 2325 4875 coroutine\001
    51 -6
    52 6 3450 1275 3750 1425
    53 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3525 1350 15 15 3525 1350 3540 1365
    54 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3600 1350 15 15 3600 1350 3615 1365
    55 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 3675 1350 15 15 3675 1350 3690 1365
    56 -6
    57 6 5550 1275 5850 1425
    58 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5625 1350 15 15 5625 1350 5640 1365
    59 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5700 1350 15 15 5700 1350 5715 1365
    60 1 3 0 1 -1 -1 0 0 20 0.000 1 0.0000 5775 1350 15 15 5775 1350 5790 1365
     63         7800 3975 7800 3525 7350 3525 7350 3975 7800 3975
     642 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
    6167-6
    62681 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5550 2625 150 150 5550 2625 5700 2625
     
    67731 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4425 2850 150 150 4425 2850 4575 2850
    68741 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 2475 150 150 4650 2475 4800 2475
    69 1 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
    70751 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 3600 150 150 3975 3600 4125 3600
    71761 3 0 1 0 0 0 0 0 0.000 1 0.0000 3525 3600 30 30 3525 3600 3555 3630
     
    74791 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3975 2850 150 150 3975 2850 4125 2850
    75801 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 7200 2775 150 150 7200 2775 7350 2775
    76 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 1350 225 150 4650 1350 4875 1500
    77 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 5250 1350 225 150 5250 1350 5475 1500
    78 1 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4050 1350 225 150 4050 1350 4275 1500
     811 3 0 1 0 0 0 0 0 0.000 1 0.0000 2250 4830 30 30 2250 4830 2280 4860
     821 3 0 1 0 0 0 0 0 0.000 1 0.0000 7200 2775 30 30 7200 2775 7230 2805
     831 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3525 3600 150 150 3525 3600 3675 3600
     841 3 0 1 -1 -1 0 0 -1 0.000 1 0.0000 3875 4800 100 100 3875 4800 3975 4800
     851 1 0 1 -1 -1 0 0 -1 0.000 1 0.0000 4650 4800 150 75 4650 4800 4800 4875
    79862 2 0 1 -1 -1 0 0 -1 0.000 0 0 0 0 0 5
    8087         2400 4200 2400 3750 1950 3750 1950 4200 2400 4200
     
    1401472 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 2
    141148        1 1 1.00 45.00 90.00
    142          6675 3975 6975 3975
    143 2 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
    145149         7050 2775 6825 2775
    1461502 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 0 0 2
    147          6825 2775 6825 3975
    148 2 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
    151 2 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
    153 2 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
     151         6825 2775 6825 3750
    1561522 1 0 1 -1 -1 0 0 -1 0.000 0 0 -1 1 0 4
    157153        1 1 1.00 45.00 90.00
    158          7875 3975 7875 2325 7200 2325 7200 2550
     154         7875 3750 7875 2325 7200 2325 7200 2550
     1552 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
     1572 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
    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
     1674 0 -1 0 0 0 10 0.0000 2 150 1290 2325 4875 genrator/coroutine\001
     1684 0 -1 0 0 0 10 0.0000 2 120 270 4050 4875 task\001
     1694 0 -1 0 0 0 10 0.0000 2 105 450 7050 4875 cluster\001
     1704 0 -1 0 0 0 10 0.0000 2 105 660 5925 4875 processor\001
     1714 0 -1 0 0 0 10 0.0000 2 105 555 4875 4875 monitor\001
  • doc/papers/concurrency/mail2

    r71d6bd8 r7030dab  
    2222Software: Practice and Experience Editorial Office
    2323
     24
     25
     26Date: Tue, 12 Nov 2019 22:25:17 +0000
     27From: Richard Jones <onbehalfof@manuscriptcentral.com>
     28Reply-To: R.E.Jones@kent.ac.uk
     29To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
     30Subject: Software: Practice and Experience - Decision on Manuscript ID
     31 SPE-19-0219
     32
     3312-Nov-2019
     34
     35Dear Dr Buhr,
     36
     37Many 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
     39The 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
     41A revised version of your manuscript that takes into account the comments of the referees will be reconsidered for publication.
     42
     43Please 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
     45You 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
     47You 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
     49When 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
     51If 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 
     53Once again, thank you for submitting your manuscript to Software: Practice and Experience and I look forward to receiving your revision.
     54
     55
     56Sincerely,
     57
     58Prof. Richard Jones
     59Software: Practice and Experience
     60R.E.Jones@kent.ac.uk
     61
     62
     63Referee(s)' Comments to Author:
     64
     65Reviewing: 1
     66
     67Comments to the Author
     68This article presents the design and rationale behind the various
     69threading and synchronization mechanisms of C-forall, a new low-level
     70programming language.  This paper is very similar to a companion paper
     71which I have also received: as the papers are similar, so will these
     72reviews be --- in particular any general comments from the other
     73review apply to this paper also.
     74
     75As far as I can tell, the article contains three main ideas: an
     76asynchronous execution / threading model; a model for monitors to
     77provide mutual exclusion; and an implementation.  The first two ideas
     78are drawn together in Table 1: unfortunately this is on page 25 of 30
     79pages of text. Implementation choices and descriptions are scattered
     80throughout the paper - and the sectioning of the paper seems almost
     81arbitrary.
     82
     83The article is about its contributions.  Simply adding feature X to
     84language Y isn't by itself a contribution, (when feature X isn't
     85already a contribution).  The contribution can be in the design: the
     86motivation, the space of potential design options, the particular
     87design chosen and the rationale for that choice, or the resulting
     88performance.  For example: why support two kinds of generators as well
     89as user-level threads?  Why support both low and high level
     90synchronization constructs?  Similarly I would have found the article
     91easier to follow if it was written top down, presenting the design
     92principles, present the space of language features, justify chosen
     93language features (and rationale) and those excluded, and then present
     94implementation, and performance.
     95
     96Then the writing of the article is often hard to follow, to say the
     97least. Two examples: section 3 "stateful functions" - I've some idea
     98what that is (a function with Algol's "own" or C's "static" variables?
     99but in fact the paper has a rather more specific idea than that. The
     100top 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
     103footnote "C" takes the time to explain what C's "main" function is?  I
     104cannot imagine a reader of this paper who doesn't know what "main" is
     105in C; especially if they understand the other concepts already
     106presented in the paper.  The start of section 3 then does the same
     107thing: putting up a whole lot of definitions, making distinctions and
     108comparisons, even talking about some runtime details, but the critical
     109definition of a monitor doesn't appear until three pages later, at the
     110start of section 5 on p15, lines 29-34 are a good, clear, description
     111of what a monitor actually is.  That needs to come first, rather than
     112being buried again after two sections of comparisons, discussions,
     113implementations, and options that are ungrounded because they haven't
     114told the reader what they are actually talking about.  First tell the
     115reader what something is, then how they might use it (as programmers:
     116what are the rules and restrictions) and only then start comparison
     117with other things, other approaches, other languages, or
     118implementations.
     119
     120The description of the implementation is similarly lost in the trees
     121without ever really seeing the wood. Figure 19 is crucial here, but
     122it's pretty much at the end of the paper, and comments about
     123implementations are threaded throughout the paper without the context
     124(fig 19) to understand what's going on.   The protocol for performance
     125testing may just about suffice for C (although is N constantly ten
     126million, or does it vary for each benchmark) but such evaluation isn't
     127appropriate for garbage-collected or JITTed languages like Java or Go.
     128
     129other comments working through the paper - these are mostly low level
     130and are certainly not comprehensive.
     131
     132p1 only a subset of C-forall extensions?
     133
     134p1 "has features often associated with object-oriented programming
     135languages, such as constructors, destructors, virtuals and simple
     136inheritance."   There's no need to quibble about this. Once a language
     137has inheritance, it's hard to claim it's not object-oriented.
     138
     139
     140p2 barging? signals-as-hints?
     141
     142p3 start your discussion of generations with a simple example of a
     143C-forall generator.  Fig 1(b) might do: but put it inline instead of
     144the python example - and explain the key rules and restrictions on the
     145construct.  Then don't even start to compare with coroutines until
     146you've presented, described and explained your coroutines...
     147p3 I'd probably leave out the various "C" versions unless there are
     148key points to make you can't make in C-forall. All the alternatives
     149are just confusing.
     150
     151
     152p4 but what's that "with" in Fig 1(B)
     153
     154p5 start with the high level features of C-forall generators...
     155
     156p5 why is the paper explaining networking protocols?
     157
     158p7 lines 1-9 (transforming generator to coroutine - why would I do any
     159of this? Why would I want one instead of the other (do not use "stack"
     160in your answer!)
     161
     162p10 last para "A coroutine must retain its last resumer to suspend
     163back because the resumer is on a different stack. These reverse
     164pointers allow suspend to cycle backwards, "  I've no idea what is
     165going on here?  why should I care?  Shouldn't I just be using threads
     166instead?  why not?
     167
     168p16 for the same reasons - what reasons?
     169
     170p17 if the multiple-monitor entry procedure really is novel, write a
     171paper about that, and only about that.
     172
     173p23 "Loose Object Definitions" - no idea what that means.  in that
     174section: you can't leave out JS-style dynamic properties.  Even in
     175OOLs 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
     177fixed definition.  Quite why the detail about bit mask implementation
     178is here anyway, I've no idea.
     179
     180p25 this cluster isn't a CLU cluster then?
     181
     182* conclusion should conclude the paper, not the related.
     183
     184
     185Reviewing: 2
     186
     187Comments to the Author
     188This 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
     190There 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
     192As 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
     194Unfortunately, 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
     196p2: 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
     198line 10: "medium work" -- "medium-sized work"?
     199
     200line 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
     202line 20: "knows the optimization boundaries" -- I found this vague. What's an example?
     203
     204line 31: this paragraph has made a lot of claims. Perhaps forward-reference to the parts of the paper that discuss each one.
     205
     206line 33: "so the reader can judge if" -- this reads rather passive-aggressively. Perhaps better: "... to support our argument that..."
     207
     208line 41: "a dynamic partitioning mechanism" -- I couldn't tell what this meant
     209
     210p3. 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
     212line 2: "an old idea that is new again" -- this is too oblique
     213
     214lines 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
     216Continuing 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
     218lines 24--27: without explaining what the boost functor types mean, I don't think the point here comes across.
     219
     220line 34: "semantically coupled" -- I wasn't surew hat this meant
     221
     222p4: 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
     224It'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
     226p5 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
     228line 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
     230p6 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
     232line 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
     234line 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
     236p8 / Figure 5 (B) -- the GNU C extension of unary "&&" needs to be explained. The whole figure needs a better explanation, in fact.
     237
     238p9, 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
     240p10: 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
     242line 32: "a self-resume does not overwrite the last resumer" -- is this a hack or a defensible principled decision?
     243
     244p11: "a common source of errors" -- among beginners or among production code? Presumably the former.
     245
     246line 23: "with builtin and library" -- not sure what this means
     247
     248lines 31--36: these can be much briefer. The only important point here seems to be that coroutines cannot be copied.
     249
     250p12: line 1: what is a "task"? Does it matter?
     251
     252line 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
     254line 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
     256line 27: "mutual exclusion and synchronization" -- the former is a kind of the latter, so I suggest "and other forms of synchronization".
     257
     258line 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
     260An 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
     262page 13: line 23: it seems a distraction to mention the Python feature here.
     263
     264p14 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
     266line 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
     268line 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
     270p15: 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
     272line 31: "acquire/release" -- misses an opportunity to contrast the monitor's "enter/exit" abstraction with the less structured acquire/release of locks.
     273
     274p16 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
     276line 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
     278p17: 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
     280line 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
     284p18: 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
     286p19: 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
     288line 6: "... can be transformed into external scheduling..." -- OK, but give some motivation.
     289
     290p20: line 6: "mechnaism"
     291
     292lines 16--20: this is dense and can probably only be made clear with an example
     293
     294p21 line 21: clarify that nested monitor deadlock was describe earlier (in 5.2). (Is the repetition necessary?)
     295
     296line 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
     298p22 line 2: should say "restructured"
     299
     300line 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
     302p23: line 3: "dynamic member adding, eg, JavaScript" -- needs to say "as permitted in JavaScript", and "dynamically adding members" is stylistically better
     303
     304p23: line 18: "urgent stack" -- back-reference to where this was explained before
     305
     306p24 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
     308line 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
     310p25 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
     312Table 1: what does "No / Yes" mean?
     313
     314p26 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
     316line 20: "Microsoft runtime" -- means Windows?
     317
     318lines 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
     320p27 line 3: "frequency is usually long" -- that's a "time period" or "interval", not a frequency
     321
     322line 5: the lengthy quotation is not really necessary; just paraphrase the first sentence and move on.
     323
     324line 20: "to verify the implementation" -- I don't think that means what is intended
     325
     326Tables in section 7 -- too many significant figures. How many overall runs are described? What is N in each case?
     327
     328p29 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
     330line 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
     332p30 line 15: "a common case being web servers and XaaS" -- that's two cases
     333
     334
     335Reviewing: 3
     336
     337Comments to the Author
     338# Cforall review
     339
     340Overall, 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
     355In 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
     361In 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
     363In 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
     369There 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
     371While 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
     375Cforall 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
     377I 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
     379I 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
     383I 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
     385To 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
     387Later, 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
     389On 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
     391On 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
     393I 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
     395I 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
     401The 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
     405In 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
     407Another 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
     409That 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
     413I'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
     424Subject: Re: manuscript SPE-19-0219
     425To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
     426From: Richard Jones <R.E.Jones@kent.ac.uk>
     427Date: Tue, 12 Nov 2019 22:43:55 +0000
     428
     429Dear Dr Buhr
     430
     431Your should have received a decision letter on this today. I am sorry that this
     432has taken so long. Unfortunately SP&E receives a lot of submissions and getting
     433reviewers is a perennial problem.
     434
     435Regards
     436Richard
     437
     438Peter 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
     462Date: Mon, 13 Jan 2020 05:33:15 +0000
     463From: Richard Jones <onbehalfof@manuscriptcentral.com>
     464Reply-To: R.E.Jones@kent.ac.uk
     465To: pabuhr@uwaterloo.ca
     466Subject: Revision reminder - SPE-19-0219
     467
     46813-Jan-2020
     469Dear Dr Buhr
     470SPE-19-0219
     471
     472This is a reminder that your opportunity to revise and re-submit your
     473manuscript will expire 28 days from now. If you require more time please
     474contact me directly and I may grant an extension to this deadline, otherwise
     475the option to submit a revision online, will not be available.
     476
     477I look forward to receiving your revision.
     478
     479Sincerely,
     480
     481Prof. Richard Jones
     482Editor, Software: Practice and Experience
     483https://mc.manuscriptcentral.com/spe
     484
     485
     486
     487Date: Wed, 5 Feb 2020 04:22:18 +0000
     488From: Aaron Thomas <onbehalfof@manuscriptcentral.com>
     489Reply-To: speoffice@wiley.com
     490To: tdelisle@uwaterloo.ca, pabuhr@uwaterloo.ca
     491Subject: SPE-19-0219.R1 successfully submitted
     492
     49304-Feb-2020
     494
     495Dear Dr Buhr,
     496
     497Your manuscript entitled "Advanced Control-flow and Concurrency in Cforall" has
     498been successfully submitted online and is presently being given full
     499consideration for publication in Software: Practice and Experience.
     500
     501Your manuscript number is SPE-19-0219.R1.  Please mention this number in all
     502future correspondence regarding this submission.
     503
     504You can view the status of your manuscript at any time by checking your Author
     505Center after logging into https://mc.manuscriptcentral.com/spe.  If you have
     506difficulty using this site, please click the 'Get Help Now' link at the top
     507right corner of the site.
     508
     509Thank you for submitting your manuscript to Software: Practice and Experience.
     510
     511Sincerely,
     512Software: Practice and Experience Editorial Office
     513
  • doc/theses/thierry_delisle_PhD/code/relaxed_list.cpp

    r71d6bd8 r7030dab  
    99#include <vector>
    1010
     11#include <getopt.h>
    1112#include <unistd.h>
    1213#include <sys/sysinfo.h>
     
    2122
    2223        int value;
    23         Node(int value): value(value) {
    24                 creates++;
    25         }
    26 
    27         ~Node() {
    28                 destroys++;
    29         }
     24        int id;
     25
     26        Node() { creates++; }
     27        Node(int value): value(value) { creates++; }
     28        ~Node() { destroys++; }
    3029};
    3130
     
    3332std::atomic_size_t Node::destroys = { 0 };
    3433
    35 static const constexpr int nodes_per_threads = 128;
    36 struct NodeArray {
    37         __attribute__((aligned(64))) Node * array[nodes_per_threads];
    38         __attribute__((aligned(64))) char pad;
    39 };
    40 
    4134bool enable_stats = false;
     35
     36template<>
     37thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
     38
     39template<>
     40relaxed_list<Node> * relaxed_list<Node>::head = nullptr;
     41
     42#ifndef NO_STATS
     43template<>
     44relaxed_list<Node>::GlobalStats relaxed_list<Node>::global_stats = {};
     45#endif
     46
     47// ================================================================================================
     48//                        UTILS
     49// ================================================================================================
    4250
    4351struct local_stat_t {
     
    4755        size_t crc_in  = 0;
    4856        size_t crc_out = 0;
     57        size_t valmax = 0;
     58        size_t valmin = 100000000ul;
    4959};
    5060
    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 
    77 void 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 
     61struct 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
     71void 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
     80void 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
     89void 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
     104void waitfor(double & duration, barrier_t & barrier, std::atomic_bool & done) {
    177105        std::cout << "Starting" << std::endl;
    178106        auto before = Clock::now();
     
    196124        duration = durr.count();
    197125        std::cout << "\rClosing down" << std::endl;
    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 
     126}
     127
     128void 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
     150void print_stats(double duration, unsigned nthread, global_stat_t & global) {
    211151        assert(Node::creates == Node::destroys);
    212152        assert(global.crc_in == global.crc_out);
     
    224164        std::cout << "Ops/sec       : " << ops_sec << "\n";
    225165        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        }
    226170        #ifndef NO_STATS
    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";
     171                relaxed_list<Node>::stats_print(std::cout);
    231172        #endif
    232173}
    233174
    234 void usage(char * argv[]) {
    235         std::cerr << argv[0] << ": [DURATION (FLOAT:SEC)] [NTHREADS] [NQUEUES] [FILL]" << std::endl;;
    236         std::exit(1);
     175void 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
     209void 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
     341void 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
     451void 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
     528bool 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                      });
    237535}
    238536
     
    241539        double duration   = 5.0;
    242540        unsigned nthreads = 2;
    243         unsigned nqueues  = 2;
    244         unsigned fill     = 100;
     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;
    245552
    246553        std::cout.imbue(std::locale(""));
    247554
    248         switch (argc)
    249         {
     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:
     712
     713        check_cache_line_size();
     714
     715        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        }
     729        return 0;
     730}
     731
     732const char * __my_progname = "Relaxed List";
     733
     734struct 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
     740struct 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
     746rgb_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;
    250793        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:
     794        default:
     795                out.r = in.v;
     796                out.g = p;
     797                out.b = q;
    267798                break;
    268         default:
    269                 usage(argv);
    270                 break;
    271         }
    272 
    273         check_cache_line_size();
    274 
    275         std::cout << "Running " << nthreads << " threads (" << (nthreads * nqueues) << " queues) for " << duration << " seconds" << std::endl;
    276         run(nthreads, nqueues, fill, duration);
    277 
    278         return 0;
    279 }
    280 
    281 template<>
    282 thread_local relaxed_list<Node>::TLS relaxed_list<Node>::tls = {};
    283 
    284 template<>
    285 relaxed_list<Node>::intrusive_queue_t::stat::Dif relaxed_list<Node>::intrusive_queue_t::stat::dif = {};
    286 
    287 const char * __my_progname = "Relaxed List";
     799        }
     800        return out;
     801}
     802
     803void 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/*
     833void 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

    r71d6bd8 r7030dab  
    3737};
    3838
     39static 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
     55static 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}
    3970
    4071extern bool enable_stats;
     
    4879                size_t attempt = 0;
    4980                size_t success = 0;
     81                size_t mask_attempt = 0;
     82        } pop;
     83};
     84
     85struct 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;
    5093        } pop;
    5194};
     
    62105        static_assert(std::is_same<decltype(node_t::_links), _LinksFields_t<node_t>>::value, "Node must have a links field");
    63106
    64 
    65107public:
    66108        relaxed_list(unsigned numLists)
    67                 : numNonEmpty{0}
    68                 , lists(new intrusive_queue_t[numLists])
     109                : lists(new intrusive_queue_t[numLists])
    69110                , numLists(numLists)
    70         {}
     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
     116                #ifndef NO_STATS
     117                        if(head) this->next = head;
     118                        head = this;
     119                #endif
     120        }
    71121
    72122        ~relaxed_list() {
     123                std::cout << "Destroying Relaxed List" << std::endl;
    73124                lists.reset();
    74                 #ifndef NO_STATS
    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;
    78                 #endif
    79125        }
    80126
     
    84130                while(true) {
    85131                        // Pick a random list
    86                         int i = tls.rng.next() % numLists;
     132                        unsigned i = tls.rng.next() % numLists;
    87133
    88134                        #ifndef NO_STATS
     
    93139                        if( !lists[i].lock.try_lock() ) continue;
    94140
     141                        __attribute__((unused)) int num = numNonEmpty;
     142
    95143                        // Actually push it
    96                         lists[i].push(node, numNonEmpty);
     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                        }
    97153                        assert(numNonEmpty <= (int)numLists);
    98154
     
    102158                        #ifndef NO_STATS
    103159                                tls.pick.push.success++;
     160                                tls.empty.push.value += num;
     161                                tls.empty.push.count += 1;
    104162                        #endif
    105163                        return;
     
    108166
    109167        __attribute__((noinline, hot)) node_t * pop() {
    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                 }
     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
    150228
    151229                return nullptr;
    152230        }
     231
     232private:
     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        }
    153285
    154286private:
     
    162294                struct stat {
    163295                        ssize_t diff = 0;
    164 
    165                         static struct Dif {
    166                                 ssize_t value = 0;
    167                                 size_t  num   = 0;
    168                                 ssize_t max   = 0;
    169                         } dif;
     296                        size_t  push = 0;
     297                        size_t  pop  = 0;
     298                        // size_t value = 0;
     299                        // size_t count = 0;
    170300                };
    171301
     
    178308                sentinel_t before;
    179309                sentinel_t after;
    180                 stat s;
    181 
     310                #ifndef NO_STATS
     311                        stat s;
     312                #endif
     313
     314#pragma GCC diagnostic push
     315#pragma GCC diagnostic ignored "-Winvalid-offsetof"
    182316                static constexpr auto fields_offset = offsetof( node_t, _links );
     317#pragma GCC diagnostic pop
    183318        public:
    184319                intrusive_queue_t()
     
    186321                        , after {{ head(), nullptr }}
    187322                {
    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                 }
     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;
    205334
    206335                inline node_t * head() const {
     
    220349                }
    221350
    222                 inline void push(node_t * node, std::atomic_int & nonEmpty) {
     351                inline bool push(node_t * node) {
    223352                        assert(lock);
    224353                        assert(node->_links.ts != 0);
     
    232361                        prev->_links.next = node;
    233362                        tail->_links.prev = node;
     363                        #ifndef NO_STATS
     364                                if(enable_stats) {
     365                                        s.diff++;
     366                                        s.push++;
     367                                }
     368                        #endif
    234369                        if(before._links.ts == 0l) {
    235                                 nonEmpty += 1;
    236370                                before._links.ts = node->_links.ts;
    237                         }
    238                         #ifndef NO_STATS
    239                                 if(enable_stats) s.diff++;
    240                         #endif
    241                 }
    242 
    243                 inline node_t * pop(std::atomic_int & nonEmpty) {
     371                                assert(node->_links.prev == this->head());
     372                                return true;
     373                        }
     374                        return false;
     375                }
     376
     377                inline std::pair<node_t *, bool> pop() {
    244378                        assert(lock);
    245379                        node_t * head = this->head();
     
    248382                        node_t * node = head->_links.next;
    249383                        node_t * next = node->_links.next;
    250                         if(node == tail) return nullptr;
     384                        if(node == tail) return {nullptr, false};
    251385
    252386                        head->_links.next = next;
    253387                        next->_links.prev = head;
    254388
     389                        #ifndef NO_STATS
     390                                if(enable_stats) {
     391                                        s.diff--;
     392                                        s.pop ++;
     393                                }
     394                        #endif
    255395                        if(next == tail) {
    256396                                before._links.ts = 0l;
    257                                 nonEmpty -= 1;
     397                                return {node, true};
    258398                        }
    259399                        else {
     
    261401                                before._links.ts = next->_links.ts;
    262402                                assert(before._links.ts != 0);
    263                         }
    264                         #ifndef NO_STATS
    265                                 if(enable_stats) s.diff--;
    266                         #endif
    267                         return node;
     403                                return {node, false};
     404                        }
    268405                }
    269406
     
    277414
    278415        static __attribute__((aligned(128))) thread_local struct TLS {
    279                 Random    rng = { int(rdtscl()) };
    280                 pick_stat pick;
     416                Random     rng = { int(rdtscl()) };
     417                pick_stat  pick;
     418                empty_stat empty;
    281419        } tls;
    282420
     421public:
     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
    283424private:
    284         std::atomic_int numNonEmpty; // number of non-empty lists
    285425        __attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t []> lists;
    286426        const unsigned numLists;
     
    288428public:
    289429        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
     453private:
     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
    290519};
  • doc/theses/thierry_delisle_PhD/code/utils.hpp

    r71d6bd8 r7030dab  
    1010#include <unistd.h>
    1111#include <sys/sysinfo.h>
     12
     13#include <x86intrin.h>
    1214
    1315// Barrier from
     
    5658}
    5759
    58 void affinity(int tid) {
     60static inline void affinity(int tid) {
    5961        static int cpus = get_nprocs();
    6062
     
    7072
    7173static const constexpr std::size_t cache_line_size = 64;
    72 void check_cache_line_size() {
     74static inline void check_cache_line_size() {
    7375        std::cout << "Checking cache line size" << std::endl;
    7476        const std::string cache_file = "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size";
     
    103105        return std::chrono::duration_cast<std::chrono::duration<T, Ratio>>(std::chrono::duration<T>(seconds)).count();
    104106}
     107
     108static 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

    r71d6bd8 r7030dab  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sat Jul 13 18:36:18 2019
    14 %% Update Count     : 3876
     13%% Last Modified On : Fri Mar  6 13:34:52 2020
     14%% Update Count     : 3924
    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 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.
    214 The top 3 rankings over the past 30 years are:
     213The 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.
     214The top 4 rankings over the past 35 years are:
    215215\begin{center}
    216216\setlength{\tabcolsep}{10pt}
    217 \begin{tabular}{@{}rccccccc@{}}
    218                 & 2018  & 2013  & 2008  & 2003  & 1998  & 1993  & 1988  \\ \hline
    219 Java    & 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             \\
     217\begin{tabular}{@{}rcccccccc@{}}
     218                & 2020  & 2015  & 2010  & 2005  & 2000  & 1995  & 1990  & 1985  \\ \hline
     219Java    & 1             & 2             & 1             & 2             & 3             & -             & -             & -             \\
     220\R{C}   & \R{2} & \R{1} & \R{2} & \R{1} & \R{1} & \R{2} & \R{1} & \R{1} \\
     221Python  & 3             & 7             & 6             & 6             & 22    & 21    & -             & -             \\
     222\CC             & 4             & 4             & 4             & 3             & 2             & 1             & 2             & 12    \\
    222223\end{tabular}
    223224\end{center}
     
    512513Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
    513514\begin{cfa}
    514 int Ā®`Ā®otypeĀ®`Ā® = 3; §\C{// make keyword an identifier}§
    515 double Ā®`Ā®forallĀ®`Ā® = 3.5;
     515int Ā®``Ā®otype = 3; §\C{// make keyword an identifier}§
     516double Ā®``Ā®forall = 3.5;
    516517\end{cfa}
    517518
     
    524525// include file uses the CFA keyword "with".
    525526#if ! defined( with ) §\C{// nesting ?}§
    526 #define with Ā®`Ā®withĀ®`Ā® §\C{// make keyword an identifier}§
     527#define with Ā®``Ā®with §\C{// make keyword an identifier}§
    527528#define __CFA_BFD_H__
    528529#endif
    529 
    530 Ā®#include_next <bfdlink.h> §\C{// must have internal check for multiple expansion}§
    531 Ā®
     530§{\color{red}\#\textbf{include\_next} <bfdlink.h>}§ §\C{// must have internal check for multiple expansion}§
    532531#if defined( with ) && defined( __CFA_BFD_H__ ) §\C{// reset only if set}§
    533532#undef with
     
    576575\section{Exponentiation Operator}
    577576
    578 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}, 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$.
     577C, \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$.
    580579The 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)©.
    581580
    582 As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
     581There are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    583582Integral 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).
    584 Overflow from large exponents or negative exponents return zero.
     583Overflow for a large exponent or negative exponent returns zero.
    585584Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    586585\begin{cfa}
     
    5895881 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
    590589\end{cfa}
    591 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.
     590Note, Ā©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.
    592591Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    593592The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
     
    598597OT ?Ā®\Ā®?( OT ep, unsigned long int y );
    599598\end{cfa}
    600 The user type Ā©TĀ© must define multiplication, one, Ā©1Ā©, and, Ā©*Ā©.
     599The user type Ā©TĀ© must define multiplication, one (Ā©1Ā©), and Ā©*Ā©.
    601600
    602601
     
    626625
    627626
    628 \subsection{Loop Control}
    629 
    630 The Ā©forĀ©/Ā©whileĀ©/Ā©do-whileĀ© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
    631 \begin{itemize}
    632 \item
    633 An empty conditional implies Ā©1Ā©.
    634 \item
    635 The up-to range Ā©~Ā©\index{~@Ā©~Ā©} means exclusive range [M,N).
    636 \item
    637 The up-to range Ā©~=Ā©\index{~=@Ā©~=Ā©} means inclusive range [M,N].
    638 \item
    639 The down-to range Ā©-~Ā©\index{-~@Ā©-~Ā©} means exclusive range [N,M).
    640 \item
    641 The 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
    649 The up-to range uses Ā©+=Ā© for increment;
    650 \item
    651 The down-to range uses Ā©-=Ā© for decrement.
    652 \item
    653 The 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}
     627%\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
     628\subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}}
     629
     630C restricts the Ā©caseĀ© clause of a Ā©switchĀ© statement to a single value.
     631For multiple Ā©caseĀ© clauses associated with the same statement, it is necessary to have multiple Ā©caseĀ© clauses rather than multiple values.
     632Requiring a Ā©caseĀ© clause for each value does not seem to be in the spirit of brevity normally associated with C.
     633Therefore, the Ā©caseĀ© clause is extended with a list of values, as in:
    657634\begin{cquote}
    658 \begin{tabular}{@{}l|l@{}}
    659 \multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    660 \hline
    661 \begin{cfa}
    662 sout | nlOff;
    663 while Ā®()Ā® { sout | "empty"; break; } sout | nl;
    664 do { sout | "empty"; break; } while Ā®()Ā®; sout | nl;
    665 for Ā®()Ā® { sout | "empty"; break; } sout | nl;
    666 for ( Ā®0Ā® ) { sout | "A"; } sout | "zero" | nl;
    667 for ( Ā®1Ā® ) { sout | "A"; } sout | nl;
    668 for ( Ā®10Ā® ) { sout | "A"; } sout | nl;
    669 for ( Ā®1 ~= 10 ~ 2Ā® ) { sout | "B"; } sout | nl;
    670 for ( Ā®10 -~= 1 ~ 2Ā® ) { sout | "C"; } sout | nl;
    671 for ( Ā®0.5 ~ 5.5Ā® ) { sout | "D"; } sout | nl;
    672 for ( Ā®5.5 -~ 0.5Ā® ) { sout | "E"; } sout | nl;
    673 for ( Ā®i; 10Ā® ) { sout | i; } sout | nl;
    674 for ( Ā®i; 1 ~= 10 ~ 2Ā® ) { sout | i; } sout | nl;
    675 for ( Ā®i; 10 -~= 1 ~ 2Ā® ) { sout | i; } sout | nl;
    676 for ( Ā®i; 0.5 ~ 5.5Ā® ) { sout | i; } sout | nl;
    677 for ( Ā®i; 5.5 -~ 0.5Ā® ) { sout | i; } sout | nl;
    678 for ( Ā®ui; 2u ~= 10u ~ 2uĀ® ) { sout | ui; } sout | nl;
    679 for ( Ā®ui; 10u -~= 2u ~ 2uĀ® ) { sout | ui; } sout | nl;
    680 enum { N = 10 };
    681 for ( Ā®NĀ® ) { sout | "N"; } sout | nl;
    682 for ( Ā®i; NĀ® ) { sout | i; } sout | nl;
    683 for ( Ā®i; N -~ 0Ā® ) { sout | i; } sout | nl;
    684 const int start = 3, comp = 10, inc = 2;
    685 for ( Ā®i; start ~ comp ~ inc + 1Ā® ) { sout | i; } sout | nl;
    686 for ( Ā®i; 1 ~ @Ā® ) { if ( i > 10 ) break;
    687         sout | i; } sout | nl;
    688 for ( Ā®i; 10 -~ @Ā® ) { if ( i < 0 ) break;
    689         sout | i; } sout | nl;
    690 for ( Ā®i; 2 ~ @ ~ 2Ā® ) { if ( i > 10 ) break;
    691         sout | i; } sout | nl;
    692 for ( Ā®i; 2.1 ~ @ ~ @Ā® ) { if ( i > 10.5 ) break;
    693         sout | i; i += 1.7; } sout | nl;
    694 for ( Ā®i; 10 -~ @ ~ 2Ā® ) { if ( i < 0 ) break;
    695         sout | i; } sout | nl;
    696 for ( Ā®i; 12.1 ~ @ ~ @Ā® ) { if ( i < 2.5 ) break;
    697         sout | i; i -= 1.7; } sout | nl;
    698 for ( Ā®i; 5 : j; -5 ~ @Ā® ) { sout | i | j; } sout | nl;
    699 for ( Ā®i; 5 : j; -5 -~ @Ā® ) { sout | i | j; } sout | nl;
    700 for ( Ā®i; 5 : j; -5 ~ @ ~ 2Ā® ) { sout | i | j; } sout | nl;
    701 for ( Ā®i; 5 : j; -5 -~ @ ~ 2Ā® ) { sout | i | j; } sout | nl;
    702 for ( Ā®j; -5 ~ @ : i; 5Ā® ) { sout | i | j; } sout | nl;
    703 for ( Ā®j; -5 -~ @ : i; 5Ā® ) { sout | i | j; } sout | nl;
    704 for ( Ā®j; -5 ~ @ ~ 2 : i; 5Ā® ) { sout | i | j; } sout | nl;
    705 for ( Ā®j; -5 -~ @ ~ 2 : i; 5Ā® ) { sout | i | j; } sout | nl;
    706 for ( Ā®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @Ā® ) {
    707         sout | i | j | k; } sout | nl;
    708 for ( Ā®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5Ā® ) {
    709         sout | i | j | k; } sout | nl;
    710 for ( Ā®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5Ā® ) {
    711         sout | i | j | k; } sout | nl;
     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}
     638switch ( i ) {
     639  case Ā®1, 3, 5Ā®:
     640        ...
     641  case Ā®2, 4, 6Ā®:
     642        ...
     643}
    712644\end{cfa}
    713645&
    714646\begin{cfa}
    715 
    716 empty
    717 empty
    718 empty
    719 zero
    720 A
    721 A A A A A A A A A A
    722 B B B B B
    723 C C C C C
    724 D D D D D
    725 E E E E E
    726 0 1 2 3 4 5 6 7 8 9
    727 1 3 5 7 9
    728 10 8 6 4 2
    729 0.5 1.5 2.5 3.5 4.5
    730 5.5 4.5 3.5 2.5 1.5
    731 2 4 6 8 10
    732 10 8 6 4 2
    733 
    734 N N N N N N N N N N
    735 0 1 2 3 4 5 6 7 8 9
    736 10 9 8 7 6 5 4 3 2 1
    737 
    738 3 6 9
    739 
    740 1 2 3 4 5 6 7 8 9 10
    741 
    742 10 9 8 7 6 5 4 3 2 1 0
    743 
    744 2 4 6 8 10
    745 
    746 2.1 3.8 5.5 7.2 8.9
    747 
    748 10 8 6 4 2 0
    749 
    750 12.1 10.4 8.7 7 5.3 3.6
    751 0 -5 1 -4 2 -3 3 -2 4 -1
    752 0 -5 1 -6 2 -7 3 -8 4 -9
    753 0 -5 1 -3 2 -1 3 1 4 3
    754 0 -5 1 -7 2 -9 3 -11 4 -13
    755 0 -5 1 -4 2 -3 3 -2 4 -1
    756 0 -5 1 -6 2 -7 3 -8 4 -9
    757 0 -5 1 -3 2 -1 3 1 4 3
    758 0 -5 1 -7 2 -9 3 -11 4 -13
    759 
    760 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    761 
    762 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    763 
    764 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     647switch ( 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
    765662\end{cfa}
    766663\end{tabular}
    767664\end{cquote}
    768 \caption{Loop Control Examples}
    769 \label{f:LoopControlExamples}
    770 \end{figure}
     665In addition, subranges are allowed to specify case values.\footnote{
     666gcc 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}
     668switch ( 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}
     675Lists of subranges are also allowed.
     676\begin{cfa}
     677case Ā®1~5, 12~21, 35~42Ā®:
     678\end{cfa}
    771679
    772680
     
    977885
    978886
    979 %\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
    980 \subsection{\texorpdfstring{\LstKeywordStyle{case} Statement}{case Statement}}
    981 
    982 C restricts the Ā©caseĀ© clause of a Ā©switchĀ© statement to a single value.
    983 For multiple Ā©caseĀ© clauses associated with the same statement, it is necessary to have multiple Ā©caseĀ© clauses rather than multiple values.
    984 Requiring a Ā©caseĀ© clause for each value does not seem to be in the spirit of brevity normally associated with C.
    985 Therefore, 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}
    990 switch ( i ) {
    991   case Ā®1, 3, 5Ā®:
     887\subsection{Non-terminating and Labelled \texorpdfstring{\LstKeywordStyle{fallthrough}}{Non-terminating and Labelled fallthrough}}
     888
     889The Ā©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}
     893choose ( ... ) {
     894  case 3:
     895        if ( ... ) {
     896                ... Ā®fallthru;Ā® // goto case 4
     897        } else {
     898                ...
     899        }
     900        // implicit break
     901  case 4:
     902
     903
     904
     905
     906\end{cfa}
     907&
     908\begin{cfa}
     909choose ( ... ) {
     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
     922\end{cfa}
     923&
     924\begin{cfa}
     925choose ( ... ) {
     926  case 3:
     927        choose ( ... ) {
     928          case 4:
     929                for ( ... ) {
     930                        // multi-level transfer
     931                        ... Ā®fallthru common;Ā®
     932                }
     933                ...
     934        }
    992935        ...
    993   case Ā®2, 4, 6Ā®:
    994         ...
    995 }
     936  Ā®common:Ā® // below fallthrough
     937                          // at case-clause level
     938\end{cfa}
     939\end{tabular}
     940\end{center}
     941The target label must be below the Ā©fallthroughĀ© and may not be nested in a control structure, and
     942the target label must be at the same or higher level as the containing Ā©caseĀ© clause and located at
     943the same level as a Ā©caseĀ© clause; the target label may be case Ā©defaultĀ©, but only associated
     944with the current Ā©switchĀ©/Ā©chooseĀ© statement.
     945
     946
     947\subsection{Loop Control}
     948
     949The Ā©forĀ©/Ā©whileĀ©/Ā©do-whileĀ© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
     950\begin{itemize}
     951\item
     952The 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
     954An empty conditional implies comparison value of Ā©1Ā© (true).
     955\item
     956A comparison N is implicit up-to exclusive range [0,N©®)®©.
     957\item
     958A comparison Ā©=Ā© N is implicit up-to inclusive range [0,N©®]®©.
     959\item
     960The up-to range M Ā©~Ā©\index{~@Ā©~Ā©} N means exclusive range [M,N©®)®©.
     961\item
     962The up-to range M Ā©~=Ā©\index{~=@Ā©~=Ā©} N means inclusive range [M,N©®]®©.
     963\item
     964The down-to range M Ā©-~Ā©\index{-~@Ā©-~Ā©} N means exclusive range [N,M©®)®©.
     965\item
     966The 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
     972The up-to range uses operator Ā©+=Ā© for increment;
     973\item
     974The 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]
     986while Ā®()Ā® { sout | "empty"; break; }
     987do { sout | "empty"; break; } while Ā®()Ā®;
     988for Ā®()Ā® { sout | "empty"; break; }
     989for ( Ā®0Ā® ) { sout | "A"; } sout | "zero";
     990for ( Ā®1Ā® ) { sout | "A"; }
     991for ( Ā®10Ā® ) { sout | "A"; }
     992for ( Ā®= 10Ā® ) { sout | "A"; }
     993for ( Ā®1 ~= 10 ~ 2Ā® ) { sout | "B"; }
     994for ( Ā®10 -~= 1 ~ 2Ā® ) { sout | "C"; }
     995for ( Ā®0.5 ~ 5.5Ā® ) { sout | "D"; }
     996for ( Ā®5.5 -~ 0.5Ā® ) { sout | "E"; }
     997for ( Ā®i; 10Ā® ) { sout | i; }
     998for ( Ā®i; = 10Ā® ) { sout | i; }
     999for ( Ā®i; 1 ~= 10 ~ 2Ā® ) { sout | i; }
     1000for ( Ā®i; 10 -~= 1 ~ 2Ā® ) { sout | i; }
     1001for ( Ā®i; 0.5 ~ 5.5Ā® ) { sout | i; }
     1002for ( Ā®i; 5.5 -~ 0.5Ā® ) { sout | i; }
     1003for ( Ā®ui; 2u ~= 10u ~ 2uĀ® ) { sout | ui; }
     1004for ( Ā®ui; 10u -~= 2u ~ 2uĀ® ) { sout | ui; }
     1005enum { N = 10 };
     1006for ( Ā®NĀ® ) { sout | "N"; }
     1007for ( Ā®i; NĀ® ) { sout | i; }
     1008for ( Ā®i; N -~ 0Ā® ) { sout | i; }
     1009const int start = 3, comp = 10, inc = 2;
     1010for ( Ā®i; start ~ comp ~ inc + 1Ā® ) { sout | i; }
     1011for ( i; 1 ~ Ā®@Ā® ) { if ( i > 10 ) break; sout | i; }
     1012for ( i; 10 -~ Ā®@Ā® ) { if ( i < 0 ) break; sout | i; }
     1013for ( i; 2 ~ Ā®@Ā® ~ 2 ) { if ( i > 10 ) break; sout | i; }
     1014for ( i; 2.1 ~ Ā®@Ā® ~ Ā®@Ā® ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
     1015for ( i; 10 -~ Ā®@Ā® ~ 2 ) { if ( i < 0 ) break; sout | i; }
     1016for ( i; 12.1 ~ Ā®@Ā® ~ Ā®@Ā® ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
     1017for ( i; 5 Ā®:Ā® j; -5 ~ @ ) { sout | i | j; }
     1018for ( i; 5 Ā®:Ā® j; -5 -~ @ ) { sout | i | j; }
     1019for ( i; 5 Ā®:Ā® j; -5 ~ @ ~ 2 ) { sout | i | j; }
     1020for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j; }
     1021for ( i; 5 Ā®:Ā® j; -5 ~ @ ) { sout | i | j; }
     1022for ( i; 5 Ā®:Ā® j; -5 -~ @ ) { sout | i | j; }
     1023for ( i; 5 Ā®:Ā® j; -5 ~ @ ~ 2 ) { sout | i | j; }
     1024for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j; }
     1025for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 Ā®:Ā® k; 1.5 ~ @ ) { sout | i | j | k; }
     1026for ( i; 5 Ā®:Ā® j; -5 -~ @ ~ 2 Ā®:Ā® k; 1.5 ~ @ ) { sout | i | j | k; }
     1027for ( i; 5 Ā®:Ā® k; 1.5 ~ @ Ā®:Ā® j; -5 -~ @ ~ 2 ) { sout | i | j | k; }
    9961028\end{cfa}
    9971029&
    9981030\begin{cfa}
    999 switch ( i ) {
    1000   case 1: case 3 : case 5:
    1001         ...
    1002   case 2: case 4 : case 6:
    1003         ...
    1004 }
    1005 \end{cfa}
    1006 &
    1007 \begin{cfa}
    1008 
    1009 // odd values
    1010 
    1011 // even values
    1012 
    1013 
     1031empty
     1032empty
     1033empty
     1034zero
     1035A
     1036A A A A A A A A A A
     1037A A A A A A A A A A A
     1038B B B B B
     1039C C C C C
     1040D D D D D
     1041E E E E E
     10420 1 2 3 4 5 6 7 8 9
     10430 1 2 3 4 5 6 7 8 9 10
     10441 3 5 7 9
     104510 8 6 4 2
     10460.5 1.5 2.5 3.5 4.5
     10475.5 4.5 3.5 2.5 1.5
     10482 4 6 8 10
     104910 8 6 4 2
     1050
     1051N N N N N N N N N N
     10520 1 2 3 4 5 6 7 8 9
     105310 9 8 7 6 5 4 3 2 1
     1054
     10553 6 9
     10561 2 3 4 5 6 7 8 9 10
     105710 9 8 7 6 5 4 3 2 1 0
     10582 4 6 8 10
     10592.1 3.8 5.5 7.2 8.9
     106010 8 6 4 2 0
     106112.1 10.4 8.7 7. 5.3 3.6
     10620 -5 1 -4 2 -3 3 -2 4 -1
     10630 -5 1 -6 2 -7 3 -8 4 -9
     10640 -5 1 -3 2 -1 3 1 4 3
     10650 -5 1 -7 2 -9 3 -11 4 -13
     10660 -5 1 -4 2 -3 3 -2 4 -1
     10670 -5 1 -6 2 -7 3 -8 4 -9
     10680 -5 1 -3 2 -1 3 1 4 3
     10690 -5 1 -7 2 -9 3 -11 4 -13
     10700 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     10710 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     10720 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    10141073\end{cfa}
    10151074\end{tabular}
    1016 \end{cquote}
    1017 In addition, subranges are allowed to specify case values.\footnote{
    1018 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.}
    1019 \begin{cfa}
    1020 switch ( i ) {
    1021   case Ā®1~5:Ā® §\C{// 1, 2, 3, 4, 5}§
    1022         ...
    1023   case Ā®10~15:Ā® §\C{// 10, 11, 12, 13, 14, 15}§
    1024         ...
    1025 }
    1026 \end{cfa}
    1027 Lists of subranges are also allowed.
    1028 \begin{cfa}
    1029 case Ā®1~5, 12~21, 35~42Ā®:
    1030 \end{cfa}
    1031 
     1075\caption{Loop Control Examples}
     1076\label{f:LoopControlExamples}
     1077\end{figure}
    10321078
    10331079% for ()  => for ( ;; )
     
    65476593hence, names in these include files are not mangled\index{mangling!name} (see~\VRef{s:Interoperability}).
    65486594All other C header files must be explicitly wrapped in ©extern "C"© to prevent name mangling.
    6549 For \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.
     6595This 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.
    65506596
    65516597
     
    65616607The 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.
    65626608
    6563 Storage management provides the following capabilities:
     6609C storage management provides the following capabilities:
    65646610\begin{description}
    6565 \item[fill]
    6566 after allocation the storage is filled with a specified character.
     6611\item[filled]
     6612after allocation with a specified character or value.
    65676613\item[resize]
    6568 an existing allocation is decreased or increased in size.
    6569 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.
     6614an existing allocation to decreased or increased its size.
     6615In 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.
    65706616For an increase in storage size, new storage after the copied data may be filled.
    6571 \item[alignment]
    6572 an allocation starts on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
     6617\item[align]
     6618an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    65736619\item[array]
    65746620the allocation size is scaled to the specified number of array elements.
    65756621An array may be filled, resized, or aligned.
    65766622\end{description}
    6577 The table shows allocation routines supporting different combinations of storage-management capabilities:
    6578 \begin{center}
    6579 \begin{tabular}{@{}r|r|l|l|l|l@{}}
     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@{}}
    65806628\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
    65816629\hline
    65826630C               & Ā©mallocĀ©                      & no                    & no            & no            & no    \\
    65836631                & Ā©callocĀ©                      & yes (0 only)  & no            & no            & yes   \\
    6584                 & Ā©reallocĀ©                     & no/copy               & yes           & no            & no    \\
     6632                & Ā©reallocĀ©                     & copy                  & yes           & no            & no    \\
    65856633                & Ā©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    \\
    65866636                & Ā©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   \\
    65876640\hline
    6588 C11             & Ā©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   \\
     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   \\
    65926647\end{tabular}
    6593 \end{center}
    6594 It 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.
     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.
     6654Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
     6655\begin{cfa}
     6656int * ip = (int *)malloc( sizeof(int) );                §\C{// C}§
     6657int * ip = malloc();                                                    §\C{// \CFA type-safe version of C malloc}§
     6658int * ip = alloc();                                                             Ā§\C{// \CFA type-safe uniform alloc}§
     6659\end{cfa}
     6660the 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}
     6664struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
     6665S * sp = malloc();                                                              §\C{// honour type alignment}§
     6666\end{cfa}
     6667the storage allocation is implicitly aligned to 128 rather than the default 16.
     6668The 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}.
     6671Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
     6672For 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.
     6673Without 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}
     6677struct S { int i; };                                                    §\C{// cache-line aglinment}§
     6678void ?{}( S & s, int i ) { s.i = i; }
     6679// assume ?|? operator for printing an S
     6680
     6681S & sp = *Ā®newĀ®( 3 );                                                   Ā§\C{// call constructor after allocation}§
     6682sout | sp.i;
     6683Ā®deleteĀ®( &sp );
     6684
     6685S * spa = Ā®anewĀ®( 10, 5 );                                              §\C{// allocate array and initialize each array element}§
     6686for ( i; 10 ) sout | spa[i] | nonl;
     6687sout | nl;
     6688Ā®adeleteĀ®( 10, spa );
     6689\end{cfa}
     6690Allocation routines Ā©newĀ©/Ā©anewĀ© allocate a variable/array and initialize storage using the allocated type's constructor.
     6691Note, the matching deallocation routines Ā©deleteĀ©/Ā©adeleteĀ©.
    65956692
    65966693\leavevmode
    65976694\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    6598 // C unsafe allocation
    65996695extern "C" {
    6600 void * malloc( size_t size );§\indexc{memset}§
    6601 void * calloc( size_t dim, size_t size );§\indexc{calloc}§
    6602 void * realloc( void * ptr, size_t size );§\indexc{realloc}§
    6603 void * memalign( size_t align, size_t size );§\indexc{memalign}§
    6604 int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
    6605 
    6606 // C unsafe initialization/copy
    6607 void * memset( void * dest, int c, size_t size );
    6608 void * memcpy( void * dest, const void * src, size_t size );
    6609 }
     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
     6710void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
    66106711
    66116712forall( dtype T | sized(T) ) {
    6612 // §\CFA§ safe equivalents, i.e., implicit size specification
     6713        // §\CFA§ safe equivalents, i.e., implicit size specification
    66136714        T * malloc( void );
    66146715        T * calloc( size_t dim );
    66156716        T * realloc( T * ptr, size_t size );
    66166717        T * memalign( size_t align );
     6718        T * cmemalign( size_t align, size_t dim  );
    66176719        T * aligned_alloc( size_t align );
    66186720        int posix_memalign( T ** ptr, size_t align );
    66196721
    6620 // §\CFA§ safe general allocation, fill, resize, array
     6722        // §\CFA§ safe general allocation, fill, resize, alignment, array
    66216723        T * alloc( void );§\indexc{alloc}§
    6622         T * alloc( char fill );
    66236724        T * alloc( size_t dim );
    6624         T * alloc( size_t dim, char fill );
    66256725        T * alloc( T ptr[], size_t dim );
    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}§
     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}§
    66366746        T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
    66376747
    6638 // §\CFA§ safe initialization/copy array
    6639         T * amemset( T dest[], char c, size_t dim );
     6748        // §\CFA§ safe initialization/copy, i.e., implicit size specification, array types
     6749        T * amemset( T dest[], char fill, size_t dim );
    66406750        T * amemcpy( T dest[], const T src[], size_t dim );
    66416751}
    66426752
    6643 // §\CFA§ allocation/deallocation and constructor/destructor
    6644 forall( dtype T | sized(T), ttype Params | { void ?{}( T *, Params ); } ) T * new( Params p );§\indexc{new}§
    6645 forall( dtype T | { void ^?{}( T * ); } ) void delete( T * ptr );§\indexc{delete}§
    6646 forall( dtype T, ttype Params | { void ^?{}( T * ); void delete( Params ); } )
     6753// §\CFA§ allocation/deallocation and constructor/destructor, non-array types
     6754forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
     6755forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
     6756forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
    66476757  void delete( T * ptr, Params rest );
    66486758
    6649 // §\CFA§ allocation/deallocation and constructor/destructor, array
    6650 forall( dtype T | sized(T), ttype Params | { void ?{}( T *, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
    6651 forall( dtype T | sized(T) | { void ^?{}( T * ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
    6652 forall( dtype T | sized(T) | { void ^?{}( T * ); }, ttype Params | { void adelete( Params ); } )
     6759// §\CFA§ allocation/deallocation and constructor/destructor, array types
     6760forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
     6761forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
     6762forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
    66536763  void adelete( size_t dim, T arr[], Params rest );
    66546764\end{cfa}
  • driver/cc1.cc

    r71d6bd8 r7030dab  
    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
    337345        // process all the arguments
    338346
     
    341349                if ( prefix( arg, "-" ) ) {
    342350                        // 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                        }
    343360
    344361                        if ( arg == "-quiet" || arg == "-version" || arg == "-fpreprocessed" ||
     
    440457                        cargs[ncargs++] = cfa_cpp_out.c_str();
    441458                } // if
     459
     460                cargs[ncargs++] = color_names[color_arg];
     461
    442462                cargs[ncargs] = nullptr;                                                // terminate argument list
    443463
  • driver/cfa.cc

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

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

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

    r71d6bd8 r7030dab  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Wed Dec 14 15:00:35 2016
    14 ## Update Count     : 205
     13## Last Modified On : Mon Feb  3 21:27:18 2020
     14## Update Count     : 208
    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
    3839
    3940# create forward declarations for gcc builtins
  • libcfa/prelude/Makefile.in

    r71d6bd8 r7030dab  
    1 # Makefile.in generated by automake 1.15 from Makefile.am.
     1# Makefile.in generated by automake 1.16.1 from Makefile.am.
    22# @configure_input@
    33
    4 # Copyright (C) 1994-2014 Free Software Foundation, Inc.
     4# Copyright (C) 1994-2018 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__depfiles_maybe)'; \
    334             cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
     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);; \
    335335        esac;
    336336
     
    377377
    378378
    379 distdir: $(DISTFILES)
     379distdir: $(BUILT_SOURCES)
     380        $(MAKE) $(AM_MAKEFLAGS) distdir-am
     381
     382distdir-am: $(DISTFILES)
    380383        @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
    381384        topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
     
    540543extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
    541544        ${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
    542546
    543547# create forward declarations for gcc builtins
  • libcfa/prelude/builtins.c

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

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

    r71d6bd8 r7030dab  
    1010# Created On       : Sat May 16 07:57:37 2015
    1111# Last Modified By : Peter A. Buhr
    12 # Last Modified On : Thu Jun  6 20:46:28 2019
    13 # Update Count     : 34
     12# Last Modified On : Sat Feb  8 09:46:58 2020
     13# Update Count     : 36
    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++) {
    87           if( match($i, "BT_FN") != 0 ) {
    88                 prototypes[$i] = $i
    89           }
     86        for (i = 1; i <= NF; i += 1 ) {
     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
    108           } # if
     105                # printf( "//\"%s\"\n", prototype )
     106                if ( index( "BT_LAST", prototype ) == 1 ) {
     107                        continue
     108                } # if
    109109
    110           printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
     110                printf( "#define %s(NAME) FUNC_SIMPLE(", prototype )
    111111
    112           if ( sub( "BT_FN_", "", prototype ) == 0 ) {
    113                 printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
    114                 exit 0
    115           } # if
     112                if ( sub( "BT_FN_", "", prototype ) == 0 ) {
     113                        printf( "\n********** BAD MACRO NAME \"%s\" **********\n", prototype )
     114                        exit 0
     115                } # if
    116116
    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;
     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
     125                } # 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
    124146                } # if
    125           } # 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" )
     147                printf( ")\n" )
    148148        } # for
    149149
  • libcfa/prelude/sync-builtins.cf

    r71d6bd8 r7030dab  
    11char __sync_fetch_and_add(volatile char *, char,...);
    2 char __sync_fetch_and_add_1(volatile char *, char,...);
    32signed char __sync_fetch_and_add(volatile signed char *, signed char,...);
    4 signed char __sync_fetch_and_add_1(volatile signed char *, signed char,...);
    53unsigned char __sync_fetch_and_add(volatile unsigned char *, unsigned char,...);
    6 unsigned char __sync_fetch_and_add_1(volatile unsigned char *, unsigned char,...);
    74signed short __sync_fetch_and_add(volatile signed short *, signed short,...);
    8 signed short __sync_fetch_and_add_2(volatile signed short *, signed short,...);
    95unsigned short __sync_fetch_and_add(volatile unsigned short *, unsigned short,...);
    10 unsigned short __sync_fetch_and_add_2(volatile unsigned short *, unsigned short,...);
    116signed int __sync_fetch_and_add(volatile signed int *, signed int,...);
    12 signed int __sync_fetch_and_add_4(volatile signed int *, signed int,...);
    137unsigned int __sync_fetch_and_add(volatile unsigned int *, unsigned int,...);
    14 unsigned int __sync_fetch_and_add_4(volatile unsigned int *, unsigned int,...);
     8signed long int __sync_fetch_and_add(volatile signed long int *, signed long int,...);
     9unsigned long int __sync_fetch_and_add(volatile unsigned long int *, unsigned long int,...);
    1510signed long long int __sync_fetch_and_add(volatile signed long long int *, signed long long int,...);
    16 signed long long int __sync_fetch_and_add_8(volatile signed long long int *, signed long long int,...);
    1711unsigned long long int __sync_fetch_and_add(volatile unsigned long long int *, unsigned long long int,...);
    18 unsigned long long int __sync_fetch_and_add_8(volatile unsigned long long int *, unsigned long long int,...);
    1912#if defined(__SIZEOF_INT128__)
    2013signed __int128 __sync_fetch_and_add(volatile signed __int128 *, signed __int128,...);
    21 signed __int128 __sync_fetch_and_add_16(volatile signed __int128 *, signed __int128,...);
    2214unsigned __int128 __sync_fetch_and_add(volatile unsigned __int128 *, unsigned __int128,...);
    23 unsigned __int128 __sync_fetch_and_add_16(volatile unsigned __int128 *, unsigned __int128,...);
    2415#endif
    2516
    2617char __sync_fetch_and_sub(volatile char *, char,...);
    27 char __sync_fetch_and_sub_1(volatile char *, char,...);
    2818signed char __sync_fetch_and_sub(volatile signed char *, signed char,...);
    29 signed char __sync_fetch_and_sub_1(volatile signed char *, signed char,...);
    3019unsigned char __sync_fetch_and_sub(volatile unsigned char *, unsigned char,...);
    31 unsigned char __sync_fetch_and_sub_1(volatile unsigned char *, unsigned char,...);
    3220signed short __sync_fetch_and_sub(volatile signed short *, signed short,...);
    33 signed short __sync_fetch_and_sub_2(volatile signed short *, signed short,...);
    3421unsigned short __sync_fetch_and_sub(volatile unsigned short *, unsigned short,...);
    35 unsigned short __sync_fetch_and_sub_2(volatile unsigned short *, unsigned short,...);
    3622signed int __sync_fetch_and_sub(volatile signed int *, signed int,...);
    37 signed int __sync_fetch_and_sub_4(volatile signed int *, signed int,...);
    3823unsigned int __sync_fetch_and_sub(volatile unsigned int *, unsigned int,...);
    39 unsigned int __sync_fetch_and_sub_4(volatile unsigned int *, unsigned int,...);
     24signed long int __sync_fetch_and_sub(volatile signed long int *, signed long int,...);
     25unsigned long int __sync_fetch_and_sub(volatile unsigned long int *, unsigned long int,...);
    4026signed long long int __sync_fetch_and_sub(volatile signed long long int *, signed long long int,...);
    41 signed long long int __sync_fetch_and_sub_8(volatile signed long long int *, signed long long int,...);
    4227unsigned long long int __sync_fetch_and_sub(volatile unsigned long long int *, unsigned long long int,...);
    43 unsigned long long int __sync_fetch_and_sub_8(volatile unsigned long long int *, unsigned long long int,...);
    4428#if defined(__SIZEOF_INT128__)
    4529signed __int128 __sync_fetch_and_sub(volatile signed __int128 *, signed __int128,...);
    46 signed __int128 __sync_fetch_and_sub_16(volatile signed __int128 *, signed __int128,...);
    4730unsigned __int128 __sync_fetch_and_sub(volatile unsigned __int128 *, unsigned __int128,...);
    48 unsigned __int128 __sync_fetch_and_sub_16(volatile unsigned __int128 *, unsigned __int128,...);
    4931#endif
    5032
    5133char __sync_fetch_and_or(volatile char *, char,...);
    52 char __sync_fetch_and_or_1(volatile char *, char,...);
    5334signed char __sync_fetch_and_or(volatile signed char *, signed char,...);
    54 signed char __sync_fetch_and_or_1(volatile signed char *, signed char,...);
    5535unsigned char __sync_fetch_and_or(volatile unsigned char *, unsigned char,...);
    56 unsigned char __sync_fetch_and_or_1(volatile unsigned char *, unsigned char,...);
    5736signed short __sync_fetch_and_or(volatile signed short *, signed short,...);
    58 signed short __sync_fetch_and_or_2(volatile signed short *, signed short,...);
    5937unsigned short __sync_fetch_and_or(volatile unsigned short *, unsigned short,...);
    60 unsigned short __sync_fetch_and_or_2(volatile unsigned short *, unsigned short,...);
    6138signed int __sync_fetch_and_or(volatile signed int *, signed int,...);
    62 signed int __sync_fetch_and_or_4(volatile signed int *, signed int,...);
    6339unsigned int __sync_fetch_and_or(volatile unsigned int *, unsigned int,...);
    64 unsigned int __sync_fetch_and_or_4(volatile unsigned int *, unsigned int,...);
     40signed long int __sync_fetch_and_or(volatile signed long int *, signed long int,...);
     41unsigned long int __sync_fetch_and_or(volatile unsigned long int *, unsigned long int,...);
    6542signed long long int __sync_fetch_and_or(volatile signed long long int *, signed long long int,...);
    66 signed long long int __sync_fetch_and_or_8(volatile signed long long int *, signed long long int,...);
    6743unsigned long long int __sync_fetch_and_or(volatile unsigned long long int *, unsigned long long int,...);
    68 unsigned long long int __sync_fetch_and_or_8(volatile unsigned long long int *, unsigned long long int,...);
    6944#if defined(__SIZEOF_INT128__)
    7045signed __int128 __sync_fetch_and_or(volatile signed __int128 *, signed __int128,...);
    71 signed __int128 __sync_fetch_and_or_16(volatile signed __int128 *, signed __int128,...);
    7246unsigned __int128 __sync_fetch_and_or(volatile unsigned __int128 *, unsigned __int128,...);
    73 unsigned __int128 __sync_fetch_and_or_16(volatile unsigned __int128 *, unsigned __int128,...);
    7447#endif
    7548
    7649char __sync_fetch_and_and(volatile char *, char,...);
    77 char __sync_fetch_and_and_1(volatile char *, char,...);
    7850signed char __sync_fetch_and_and(volatile signed char *, signed char,...);
    79 signed char __sync_fetch_and_and_1(volatile signed char *, signed char,...);
    8051unsigned char __sync_fetch_and_and(volatile unsigned char *, unsigned char,...);
    81 unsigned char __sync_fetch_and_and_1(volatile unsigned char *, unsigned char,...);
    8252signed short __sync_fetch_and_and(volatile signed short *, signed short,...);
    83 signed short __sync_fetch_and_and_2(volatile signed short *, signed short,...);
    8453unsigned short __sync_fetch_and_and(volatile unsigned short *, unsigned short,...);
    85 unsigned short __sync_fetch_and_and_2(volatile unsigned short *, unsigned short,...);
    8654signed int __sync_fetch_and_and(volatile signed int *, signed int,...);
    87 signed int __sync_fetch_and_and_4(volatile signed int *, signed int,...);
    8855unsigned int __sync_fetch_and_and(volatile unsigned int *, unsigned int,...);
    89 unsigned int __sync_fetch_and_and_4(volatile unsigned int *, unsigned int,...);
     56signed long int __sync_fetch_and_and(volatile signed long int *, signed long int,...);
     57unsigned long int __sync_fetch_and_and(volatile unsigned long int *, unsigned long int,...);
    9058signed long long int __sync_fetch_and_and(volatile signed long long int *, signed long long int,...);
    91 signed long long int __sync_fetch_and_and_8(volatile signed long long int *, signed long long int,...);
    9259unsigned long long int __sync_fetch_and_and(volatile unsigned long long int *, unsigned long long int,...);
    93 unsigned long long int __sync_fetch_and_and_8(volatile unsigned long long int *, unsigned long long int,...);
    9460#if defined(__SIZEOF_INT128__)
    9561signed __int128 __sync_fetch_and_and(volatile signed __int128 *, signed __int128,...);
    96 signed __int128 __sync_fetch_and_and_16(volatile signed __int128 *, signed __int128,...);
    9762unsigned __int128 __sync_fetch_and_and(volatile unsigned __int128 *, unsigned __int128,...);
    98 unsigned __int128 __sync_fetch_and_and_16(volatile unsigned __int128 *, unsigned __int128,...);
    9963#endif
    10064
    10165char __sync_fetch_and_xor(volatile char *, char,...);
    102 char __sync_fetch_and_xor_1(volatile char *, char,...);
    10366signed char __sync_fetch_and_xor(volatile signed char *, signed char,...);
    104 signed char __sync_fetch_and_xor_1(volatile signed char *, signed char,...);
    10567unsigned char __sync_fetch_and_xor(volatile unsigned char *, unsigned char,...);
    106 unsigned char __sync_fetch_and_xor_1(volatile unsigned char *, unsigned char,...);
    10768signed short __sync_fetch_and_xor(volatile signed short *, signed short,...);
    108 signed short __sync_fetch_and_xor_2(volatile signed short *, signed short,...);
    10969unsigned short __sync_fetch_and_xor(volatile unsigned short *, unsigned short,...);
    110 unsigned short __sync_fetch_and_xor_2(volatile unsigned short *, unsigned short,...);
    11170signed int __sync_fetch_and_xor(volatile signed int *, signed int,...);
    112 signed int __sync_fetch_and_xor_4(volatile signed int *, signed int,...);
    11371unsigned int __sync_fetch_and_xor(volatile unsigned int *, unsigned int,...);
    114 unsigned int __sync_fetch_and_xor_4(volatile unsigned int *, unsigned int,...);
     72signed long int __sync_fetch_and_xor(volatile signed long int *, signed long int,...);
     73unsigned long int __sync_fetch_and_xor(volatile unsigned long int *, unsigned long int,...);
    11574signed long long int __sync_fetch_and_xor(volatile signed long long int *, signed long long int,...);
    116 signed long long int __sync_fetch_and_xor_8(volatile signed long long int *, signed long long int,...);
    11775unsigned long long int __sync_fetch_and_xor(volatile unsigned long long int *, unsigned long long int,...);
    118 unsigned long long int __sync_fetch_and_xor_8(volatile unsigned long long int *, unsigned long long int,...);
    11976#if defined(__SIZEOF_INT128__)
    12077signed __int128 __sync_fetch_and_xor(volatile signed __int128 *, signed __int128,...);
    121 signed __int128 __sync_fetch_and_xor_16(volatile signed __int128 *, signed __int128,...);
    12278unsigned __int128 __sync_fetch_and_xor(volatile unsigned __int128 *, unsigned __int128,...);
    123 unsigned __int128 __sync_fetch_and_xor_16(volatile unsigned __int128 *, unsigned __int128,...);
    12479#endif
    12580
    12681char __sync_fetch_and_nand(volatile char *, char,...);
    127 char __sync_fetch_and_nand_1(volatile char *, char,...);
    12882signed char __sync_fetch_and_nand(volatile signed char *, signed char,...);
    129 signed char __sync_fetch_and_nand_1(volatile signed char *, signed char,...);
    13083unsigned char __sync_fetch_and_nand(volatile unsigned char *, unsigned char,...);
    131 unsigned char __sync_fetch_and_nand_1(volatile unsigned char *, unsigned char,...);
    13284signed short __sync_fetch_and_nand(volatile signed short *, signed short,...);
    133 signed short __sync_fetch_and_nand_2(volatile signed short *, signed short,...);
    13485unsigned short __sync_fetch_and_nand(volatile unsigned short *, unsigned short,...);
    135 unsigned short __sync_fetch_and_nand_2(volatile unsigned short *, unsigned short,...);
    13686signed int __sync_fetch_and_nand(volatile signed int *, signed int,...);
    137 signed int __sync_fetch_and_nand_4(volatile signed int *, signed int,...);
    13887unsigned int __sync_fetch_and_nand(volatile unsigned int *, unsigned int,...);
    139 unsigned int __sync_fetch_and_nand_4(volatile unsigned int *, unsigned int,...);
     88signed long int __sync_fetch_and_nand(volatile signed long int *, signed long int,...);
     89unsigned long int __sync_fetch_and_nand(volatile unsigned long int *, unsigned long int,...);
    14090signed long long int __sync_fetch_and_nand(volatile signed long long int *, signed long long int,...);
    141 signed long long int __sync_fetch_and_nand_8(volatile signed long long int *, signed long long int,...);
    14291unsigned long long int __sync_fetch_and_nand(volatile unsigned long long int *, unsigned long long int,...);
    143 unsigned long long int __sync_fetch_and_nand_8(volatile unsigned long long int *, unsigned long long int,...);
    14492#if defined(__SIZEOF_INT128__)
    14593signed __int128 __sync_fetch_and_nand(volatile signed __int128 *, signed __int128,...);
    146 signed __int128 __sync_fetch_and_nand_16(volatile signed __int128 *, signed __int128,...);
    14794unsigned __int128 __sync_fetch_and_nand(volatile unsigned __int128 *, unsigned __int128,...);
    148 unsigned __int128 __sync_fetch_and_nand_16(volatile unsigned __int128 *, unsigned __int128,...);
    14995#endif
    15096
    15197char __sync_add_and_fetch(volatile char *, char,...);
    152 char __sync_add_and_fetch_1(volatile char *, char,...);
    15398signed char __sync_add_and_fetch(volatile signed char *, signed char,...);
    154 signed char __sync_add_and_fetch_1(volatile signed char *, signed char,...);
    15599unsigned char __sync_add_and_fetch(volatile unsigned char *, unsigned char,...);
    156 unsigned char __sync_add_and_fetch_1(volatile unsigned char *, unsigned char,...);
    157100signed short __sync_add_and_fetch(volatile signed short *, signed short,...);
    158 signed short __sync_add_and_fetch_2(volatile signed short *, signed short,...);
    159101unsigned short __sync_add_and_fetch(volatile unsigned short *, unsigned short,...);
    160 unsigned short __sync_add_and_fetch_2(volatile unsigned short *, unsigned short,...);
    161102signed int __sync_add_and_fetch(volatile signed int *, signed int,...);
    162 signed int __sync_add_and_fetch_4(volatile signed int *, signed int,...);
    163103signed int __sync_add_and_fetch(volatile signed int *, signed int,...);
    164 signed int __sync_add_and_fetch_4(volatile signed int *, signed int,...);
     104signed long int __sync_add_and_fetch(volatile signed long int *, signed long int,...);
     105unsigned long int __sync_add_and_fetch(volatile unsigned long int *, unsigned long int,...);
    165106signed long long int __sync_add_and_fetch(volatile signed long long int *, signed long long int,...);
    166 signed long long int __sync_add_and_fetch_8(volatile signed long long int *, signed long long int,...);
    167107unsigned long long int __sync_add_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
    168 unsigned long long int __sync_add_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    169108#if defined(__SIZEOF_INT128__)
    170109signed __int128 __sync_add_and_fetch(volatile signed __int128 *, signed __int128,...);
    171 signed __int128 __sync_add_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    172110unsigned __int128 __sync_add_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
    173 unsigned __int128 __sync_add_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    174111#endif
    175112
    176113char __sync_sub_and_fetch(volatile char *, char,...);
    177 char __sync_sub_and_fetch_1(volatile char *, char,...);
    178114signed char __sync_sub_and_fetch(volatile signed char *, signed char,...);
    179 signed char __sync_sub_and_fetch_1(volatile signed char *, signed char,...);
    180115unsigned char __sync_sub_and_fetch(volatile unsigned char *, unsigned char,...);
    181 unsigned char __sync_sub_and_fetch_1(volatile unsigned char *, unsigned char,...);
    182116signed short __sync_sub_and_fetch(volatile signed short *, signed short,...);
    183 signed short __sync_sub_and_fetch_2(volatile signed short *, signed short,...);
    184117unsigned short __sync_sub_and_fetch(volatile unsigned short *, unsigned short,...);
    185 unsigned short __sync_sub_and_fetch_2(volatile unsigned short *, unsigned short,...);
    186118signed int __sync_sub_and_fetch(volatile signed int *, signed int,...);
    187 signed int __sync_sub_and_fetch_4(volatile signed int *, signed int,...);
    188119unsigned int __sync_sub_and_fetch(volatile unsigned int *, unsigned int,...);
    189 unsigned int __sync_sub_and_fetch_4(volatile unsigned int *, unsigned int,...);
     120signed long int __sync_sub_and_fetch(volatile signed long int *, signed long int,...);
     121unsigned long int __sync_sub_and_fetch(volatile unsigned long int *, unsigned long int,...);
    190122signed long long int __sync_sub_and_fetch(volatile signed long long int *, signed long long int,...);
    191 signed long long int __sync_sub_and_fetch_8(volatile signed long long int *, signed long long int,...);
    192123unsigned long long int __sync_sub_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
    193 unsigned long long int __sync_sub_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    194124#if defined(__SIZEOF_INT128__)
    195125signed __int128 __sync_sub_and_fetch(volatile signed __int128 *, signed __int128,...);
    196 signed __int128 __sync_sub_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    197126unsigned __int128 __sync_sub_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
    198 unsigned __int128 __sync_sub_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    199127#endif
    200128
    201129char __sync_or_and_fetch(volatile char *, char,...);
    202 char __sync_or_and_fetch_1(volatile char *, char,...);
    203130signed char __sync_or_and_fetch(volatile signed char *, signed char,...);
    204 signed char __sync_or_and_fetch_1(volatile signed char *, signed char,...);
    205131unsigned char __sync_or_and_fetch(volatile unsigned char *, unsigned char,...);
    206 unsigned char __sync_or_and_fetch_1(volatile unsigned char *, unsigned char,...);
    207132signed short __sync_or_and_fetch(volatile signed short *, signed short,...);
    208 signed short __sync_or_and_fetch_2(volatile signed short *, signed short,...);
    209133unsigned short __sync_or_and_fetch(volatile unsigned short *, unsigned short,...);
    210 unsigned short __sync_or_and_fetch_2(volatile unsigned short *, unsigned short,...);
    211134signed int __sync_or_and_fetch(volatile signed int *, signed int,...);
    212 signed int __sync_or_and_fetch_4(volatile signed int *, signed int,...);
    213135unsigned int __sync_or_and_fetch(volatile unsigned int *, unsigned int,...);
    214 unsigned int __sync_or_and_fetch_4(volatile unsigned int *, unsigned int,...);
     136signed long int __sync_or_and_fetch(volatile signed long int *, signed long int,...);
     137unsigned long int __sync_or_and_fetch(volatile unsigned long int *, unsigned long int,...);
    215138signed long long int __sync_or_and_fetch(volatile signed long long int *, signed long long int,...);
    216 signed long long int __sync_or_and_fetch_8(volatile signed long long int *, signed long long int,...);
    217139unsigned long long int __sync_or_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
    218 unsigned long long int __sync_or_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    219140#if defined(__SIZEOF_INT128__)
    220141signed __int128 __sync_or_and_fetch(volatile signed __int128 *, signed __int128,...);
    221 signed __int128 __sync_or_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    222142unsigned __int128 __sync_or_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
    223 unsigned __int128 __sync_or_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    224143#endif
    225144
    226145char __sync_and_and_fetch(volatile char *, char,...);
    227 char __sync_and_and_fetch_1(volatile char *, char,...);
    228146signed char __sync_and_and_fetch(volatile signed char *, signed char,...);
    229 signed char __sync_and_and_fetch_1(volatile signed char *, signed char,...);
    230147unsigned char __sync_and_and_fetch(volatile unsigned char *, unsigned char,...);
    231 unsigned char __sync_and_and_fetch_1(volatile unsigned char *, unsigned char,...);
    232148signed short __sync_and_and_fetch(volatile signed short *, signed short,...);
    233 signed short __sync_and_and_fetch_2(volatile signed short *, signed short,...);
    234149unsigned short __sync_and_and_fetch(volatile unsigned short *, unsigned short,...);
    235 unsigned short __sync_and_and_fetch_2(volatile unsigned short *, unsigned short,...);
    236150signed int __sync_and_and_fetch(volatile signed int *, signed int,...);
    237 signed int __sync_and_and_fetch_4(volatile signed int *, signed int,...);
    238151unsigned int __sync_and_and_fetch(volatile unsigned int *, unsigned int,...);
    239 unsigned int __sync_and_and_fetch_4(volatile unsigned int *, unsigned int,...);
     152signed long int __sync_and_and_fetch(volatile signed long int *, signed long int,...);
     153unsigned long int __sync_and_and_fetch(volatile unsigned long int *, unsigned long int,...);
    240154signed long long int __sync_and_and_fetch(volatile signed long long int *, signed long long int,...);
    241 signed long long int __sync_and_and_fetch_8(volatile signed long long int *, signed long long int,...);
    242155unsigned long long int __sync_and_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
    243 unsigned long long int __sync_and_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    244156#if defined(__SIZEOF_INT128__)
    245157signed __int128 __sync_and_and_fetch(volatile signed __int128 *, signed __int128,...);
    246 signed __int128 __sync_and_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    247158unsigned __int128 __sync_and_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
    248 unsigned __int128 __sync_and_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    249159#endif
    250160
    251161char __sync_xor_and_fetch(volatile char *, char,...);
    252 char __sync_xor_and_fetch_1(volatile char *, char,...);
    253162signed char __sync_xor_and_fetch(volatile signed char *, signed char,...);
    254 signed char __sync_xor_and_fetch_1(volatile signed char *, signed char,...);
    255163unsigned char __sync_xor_and_fetch(volatile unsigned char *, unsigned char,...);
    256 unsigned char __sync_xor_and_fetch_1(volatile unsigned char *, unsigned char,...);
    257164signed short __sync_xor_and_fetch(volatile signed short *, signed short,...);
    258 signed short __sync_xor_and_fetch_2(volatile signed short *, signed short,...);
    259165unsigned short __sync_xor_and_fetch(volatile unsigned short *, unsigned short,...);
    260 unsigned short __sync_xor_and_fetch_2(volatile unsigned short *, unsigned short,...);
    261166signed int __sync_xor_and_fetch(volatile signed int *, signed int,...);
    262 signed int __sync_xor_and_fetch_4(volatile signed int *, signed int,...);
    263167unsigned int __sync_xor_and_fetch(volatile unsigned int *, unsigned int,...);
    264 unsigned int __sync_xor_and_fetch_4(volatile unsigned int *, unsigned int,...);
     168signed long int __sync_xor_and_fetch(volatile signed long int *, signed long int,...);
     169unsigned long int __sync_xor_and_fetch(volatile unsigned long int *, unsigned long int,...);
    265170signed long long int __sync_xor_and_fetch(volatile signed long long int *, signed long long int,...);
    266 signed long long int __sync_xor_and_fetch_8(volatile signed long long int *, signed long long int,...);
    267171unsigned long long int __sync_xor_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
    268 unsigned long long int __sync_xor_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    269172#if defined(__SIZEOF_INT128__)
    270173signed __int128 __sync_xor_and_fetch(volatile signed __int128 *, signed __int128,...);
    271 signed __int128 __sync_xor_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    272174unsigned __int128 __sync_xor_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
    273 unsigned __int128 __sync_xor_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    274175#endif
    275176
    276177char __sync_nand_and_fetch(volatile char *, char,...);
    277 char __sync_nand_and_fetch_1(volatile char *, char,...);
    278178signed char __sync_nand_and_fetch(volatile signed char *, signed char,...);
    279 signed char __sync_nand_and_fetch_1(volatile signed char *, signed char,...);
    280179unsigned char __sync_nand_and_fetch(volatile unsigned char *, unsigned char,...);
    281 unsigned char __sync_nand_and_fetch_1(volatile unsigned char *, unsigned char,...);
    282180signed short __sync_nand_and_fetch(volatile signed short *, signed short,...);
    283 signed short __sync_nand_and_fetch_2(volatile signed short *, signed short,...);
    284181unsigned short __sync_nand_and_fetch(volatile unsigned short *, unsigned short,...);
    285 unsigned short __sync_nand_and_fetch_2(volatile unsigned short *, unsigned short,...);
    286182signed int __sync_nand_and_fetch(volatile signed int *, signed int,...);
    287 signed int __sync_nand_and_fetch_4(volatile signed int *, signed int,...);
    288183unsigned int __sync_nand_and_fetch(volatile unsigned int *, unsigned int,...);
    289 unsigned int __sync_nand_and_fetch_4(volatile unsigned int *, unsigned int,...);
     184signed long int __sync_nand_and_fetch(volatile signed long int *, signed long int,...);
     185unsigned long int __sync_nand_and_fetch(volatile unsigned long int *, unsigned long int,...);
    290186signed long long int __sync_nand_and_fetch(volatile signed long long int *, signed long long int,...);
    291 signed long long int __sync_nand_and_fetch_8(volatile signed long long int *, signed long long int,...);
    292187unsigned long long int __sync_nand_and_fetch(volatile unsigned long long int *, unsigned long long int,...);
    293 unsigned long long int __sync_nand_and_fetch_8(volatile unsigned long long int *, unsigned long long int,...);
    294188#if defined(__SIZEOF_INT128__)
    295189signed __int128 __sync_nand_and_fetch(volatile signed __int128 *, signed __int128,...);
    296 signed __int128 __sync_nand_and_fetch_16(volatile signed __int128 *, signed __int128,...);
    297190unsigned __int128 __sync_nand_and_fetch(volatile unsigned __int128 *, unsigned __int128,...);
    298 unsigned __int128 __sync_nand_and_fetch_16(volatile unsigned __int128 *, unsigned __int128,...);
    299191#endif
    300192
    301193_Bool __sync_bool_compare_and_swap(volatile char *, char, char,...);
    302 _Bool __sync_bool_compare_and_swap_1(volatile char *, char, char,...);
    303194_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,...);
    305195_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,...);
    307196_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,...);
    309197_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,...);
    311198_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,...);
    313199_Bool __sync_bool_compare_and_swap(volatile unsigned int *, unsigned int, unsigned int,...);
    314 _Bool __sync_bool_compare_and_swap_4(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,...);
    315202_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,...);
    317203_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,...);
    319204#if defined(__SIZEOF_INT128__)
    320205_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,...);
    322206_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,...);
    324207#endif
    325208forall(dtype T) _Bool __sync_bool_compare_and_swap(T * volatile *, T *, T*, ...);
    326209
    327210char __sync_val_compare_and_swap(volatile char *, char, char,...);
    328 char __sync_val_compare_and_swap_1(volatile char *, char, char,...);
    329211signed char __sync_val_compare_and_swap(volatile signed char *, signed char, signed char,...);
    330 signed char __sync_val_compare_and_swap_1(volatile signed char *, signed char, signed char,...);
    331212unsigned char __sync_val_compare_and_swap(volatile unsigned char *, unsigned char, unsigned char,...);
    332 unsigned char __sync_val_compare_and_swap_1(volatile unsigned char *, unsigned char, unsigned char,...);
    333213signed short __sync_val_compare_and_swap(volatile signed short *, signed short, signed short,...);
    334 signed short __sync_val_compare_and_swap_2(volatile signed short *, signed short, signed short,...);
    335214unsigned short __sync_val_compare_and_swap(volatile unsigned short *, unsigned short, unsigned short,...);
    336 unsigned short __sync_val_compare_and_swap_2(volatile unsigned short *, unsigned short, unsigned short,...);
    337215signed int __sync_val_compare_and_swap(volatile signed int *, signed int, signed int,...);
    338 signed int __sync_val_compare_and_swap_4(volatile signed int *, signed int, signed int,...);
    339216unsigned int __sync_val_compare_and_swap(volatile unsigned int *, unsigned int, unsigned int,...);
    340 unsigned int __sync_val_compare_and_swap_4(volatile unsigned int *, unsigned int, unsigned int,...);
     217signed long int __sync_val_compare_and_swap(volatile signed long int *, signed long int, signed long int,...);
     218unsigned long int __sync_val_compare_and_swap(volatile unsigned long int *, unsigned long int, unsigned long int,...);
    341219signed long long int __sync_val_compare_and_swap(volatile signed long long int *, signed long long int, signed long long int,...);
    342 signed long long int __sync_val_compare_and_swap_8(volatile signed long long int *, signed long long int, signed long long int,...);
    343220unsigned long long int __sync_val_compare_and_swap(volatile unsigned long long int *, unsigned long long int, unsigned long long int,...);
    344 unsigned long long int __sync_val_compare_and_swap_8(volatile unsigned long long int *, unsigned long long int, unsigned long long int,...);
    345221#if defined(__SIZEOF_INT128__)
    346222signed __int128 __sync_val_compare_and_swap(volatile signed __int128 *, signed __int128, signed __int128,...);
    347 signed __int128 __sync_val_compare_and_swap_16(volatile signed __int128 *, signed __int128, signed __int128,...);
    348223unsigned __int128 __sync_val_compare_and_swap(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    349 unsigned __int128 __sync_val_compare_and_swap_16(volatile unsigned __int128 *, unsigned __int128, unsigned __int128,...);
    350224#endif
    351225forall(dtype T) T * __sync_val_compare_and_swap(T * volatile *, T *, T*,...);
    352226
    353227char __sync_lock_test_and_set(volatile char *, char,...);
    354 char __sync_lock_test_and_set_1(volatile char *, char,...);
    355228signed char __sync_lock_test_and_set(volatile signed char *, signed char,...);
    356 signed char __sync_lock_test_and_set_1(volatile signed char *, signed char,...);
    357229unsigned char __sync_lock_test_and_set(volatile unsigned char *, unsigned char,...);
    358 unsigned char __sync_lock_test_and_set_1(volatile unsigned char *, unsigned char,...);
    359230signed short __sync_lock_test_and_set(volatile signed short *, signed short,...);
    360 signed short __sync_lock_test_and_set_2(volatile signed short *, signed short,...);
    361231unsigned short __sync_lock_test_and_set(volatile unsigned short *, unsigned short,...);
    362 unsigned short __sync_lock_test_and_set_2(volatile unsigned short *, unsigned short,...);
    363232signed int __sync_lock_test_and_set(volatile signed int *, signed int,...);
    364 signed int __sync_lock_test_and_set_4(volatile signed int *, signed int,...);
    365233unsigned int __sync_lock_test_and_set(volatile unsigned int *, unsigned int,...);
    366 unsigned int __sync_lock_test_and_set_4(volatile unsigned int *, unsigned int,...);
     234signed long int __sync_lock_test_and_set(volatile signed long int *, signed long int,...);
     235unsigned long int __sync_lock_test_and_set(volatile unsigned long int *, unsigned long int,...);
    367236signed long long int __sync_lock_test_and_set(volatile signed long long int *, signed long long int,...);
    368 signed long long int __sync_lock_test_and_set_8(volatile signed long long int *, signed long long int,...);
    369237unsigned long long int __sync_lock_test_and_set(volatile unsigned long long int *, unsigned long long int,...);
    370 unsigned long long int __sync_lock_test_and_set_8(volatile unsigned long long int *, unsigned long long int,...);
    371238#if defined(__SIZEOF_INT128__)
    372239signed __int128 __sync_lock_test_and_set(volatile signed __int128 *, signed __int128,...);
    373 signed __int128 __sync_lock_test_and_set_16(volatile signed __int128 *, signed __int128,...);
    374240unsigned __int128 __sync_lock_test_and_set(volatile unsigned __int128 *, unsigned __int128,...);
    375 unsigned __int128 __sync_lock_test_and_set_16(volatile unsigned __int128 *, unsigned __int128,...);
    376241#endif
    377242
    378243void __sync_lock_release(volatile char *,...);
    379 void __sync_lock_release_1(volatile char *,...);
    380244void __sync_lock_release(volatile signed char *,...);
    381 void __sync_lock_release_1(volatile signed char *,...);
    382245void __sync_lock_release(volatile unsigned char *,...);
    383 void __sync_lock_release_1(volatile unsigned char *,...);
    384246void __sync_lock_release(volatile signed short *,...);
    385 void __sync_lock_release_2(volatile signed short *,...);
    386247void __sync_lock_release(volatile unsigned short *,...);
    387 void __sync_lock_release_2(volatile unsigned short *,...);
    388248void __sync_lock_release(volatile signed int *,...);
    389 void __sync_lock_release_4(volatile signed int *,...);
    390249void __sync_lock_release(volatile unsigned int *,...);
    391 void __sync_lock_release_4(volatile unsigned int *,...);
     250void __sync_lock_release(volatile signed long int *,...);
     251void __sync_lock_release(volatile unsigned long int *,...);
    392252void __sync_lock_release(volatile signed long long int *,...);
    393 void __sync_lock_release_8(volatile signed long long int *,...);
    394253void __sync_lock_release(volatile unsigned long long int *,...);
    395 void __sync_lock_release_8(volatile unsigned long long int *,...);
    396254#if defined(__SIZEOF_INT128__)
    397255void __sync_lock_release(volatile signed __int128 *,...);
    398 void __sync_lock_release_16(volatile signed __int128 *,...);
    399256void __sync_lock_release(volatile unsigned __int128 *,...);
    400 void __sync_lock_release_16(volatile unsigned __int128 *,...);
    401257#endif
    402258
     
    414270_Bool __atomic_test_and_set(volatile signed int *, int);
    415271_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);
    416274_Bool __atomic_test_and_set(volatile signed long long int *, int);
    417275_Bool __atomic_test_and_set(volatile unsigned long long int *, int);
     
    429287void __atomic_clear(volatile signed int *, int);
    430288void __atomic_clear(volatile unsigned int *, int);
     289void __atomic_clear(volatile signed long int *, int);
     290void __atomic_clear(volatile unsigned long int *, int);
    431291void __atomic_clear(volatile signed long long int *, int);
    432292void __atomic_clear(volatile unsigned long long int *, int);
     
    436296#endif
    437297
     298_Bool __atomic_exchange_n(volatile _Bool *, _Bool, int);
     299void __atomic_exchange(volatile _Bool *, volatile _Bool *, volatile _Bool *, int);
    438300char __atomic_exchange_n(volatile char *, char, int);
    439 char __atomic_exchange_1(volatile char *, char, int);
    440301void __atomic_exchange(volatile char *, volatile char *, volatile char *, int);
    441302signed char __atomic_exchange_n(volatile signed char *, signed char, int);
    442 signed char __atomic_exchange_1(volatile signed char *, signed char, int);
    443303void __atomic_exchange(volatile signed char *, volatile signed char *, volatile signed char *, int);
    444304unsigned char __atomic_exchange_n(volatile unsigned char *, unsigned char, int);
    445 unsigned char __atomic_exchange_1(volatile unsigned char *, unsigned char, int);
    446305void __atomic_exchange(volatile unsigned char *, volatile unsigned char *, volatile unsigned char *, int);
    447306signed short __atomic_exchange_n(volatile signed short *, signed short, int);
    448 signed short __atomic_exchange_2(volatile signed short *, signed short, int);
    449307void __atomic_exchange(volatile signed short *, volatile signed short *, volatile signed short *, int);
    450308unsigned short __atomic_exchange_n(volatile unsigned short *, unsigned short, int);
    451 unsigned short __atomic_exchange_2(volatile unsigned short *, unsigned short, int);
    452309void __atomic_exchange(volatile unsigned short *, volatile unsigned short *, volatile unsigned short *, int);
    453310signed int __atomic_exchange_n(volatile signed int *, signed int, int);
    454 signed int __atomic_exchange_4(volatile signed int *, signed int, int);
    455311void __atomic_exchange(volatile signed int *, volatile signed int *, volatile signed int *, int);
    456312unsigned int __atomic_exchange_n(volatile unsigned int *, unsigned int, int);
    457 unsigned int __atomic_exchange_4(volatile unsigned int *, unsigned int, int);
    458313void __atomic_exchange(volatile unsigned int *, volatile unsigned int *, volatile unsigned int *, int);
     314signed long int __atomic_exchange_n(volatile signed long int *, signed long int, int);
     315void __atomic_exchange(volatile signed long int *, volatile signed long int *, volatile signed long int *, int);
     316unsigned long int __atomic_exchange_n(volatile unsigned long int *, unsigned long int, int);
     317void __atomic_exchange(volatile unsigned long int *, volatile unsigned long int *, volatile unsigned long int *, int);
    459318signed long long int __atomic_exchange_n(volatile signed long long int *, signed long long int, int);
    460 signed long long int __atomic_exchange_8(volatile signed long long int *, signed long long int, int);
    461319void __atomic_exchange(volatile signed long long int *, volatile signed long long int *, volatile signed long long int *, int);
    462320unsigned long long int __atomic_exchange_n(volatile unsigned long long int *, unsigned long long int, int);
    463 unsigned long long int __atomic_exchange_8(volatile unsigned long long int *, unsigned long long int, int);
    464321void __atomic_exchange(volatile unsigned long long int *, volatile unsigned long long int *, volatile unsigned long long int *, int);
    465322#if defined(__SIZEOF_INT128__)
    466323signed __int128 __atomic_exchange_n(volatile signed __int128 *, signed __int128, int);
    467 signed __int128 __atomic_exchange_16(volatile signed __int128 *, signed __int128, int);
    468324void __atomic_exchange(volatile signed __int128 *, volatile signed __int128 *, volatile signed __int128 *, int);
    469325unsigned __int128 __atomic_exchange_n(volatile unsigned __int128 *, unsigned __int128, int);
    470 unsigned __int128 __atomic_exchange_16(volatile unsigned __int128 *, unsigned __int128, int);
    471326void __atomic_exchange(volatile unsigned __int128 *, volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    472327#endif
     
    477332void __atomic_load(const volatile _Bool *, volatile _Bool *, int);
    478333char __atomic_load_n(const volatile char *, int);
    479 char __atomic_load_1(const volatile char *, int);
    480334void __atomic_load(const volatile char *, volatile char *, int);
    481335signed char __atomic_load_n(const volatile signed char *, int);
    482 signed char __atomic_load_1(const volatile signed char *, int);
    483336void __atomic_load(const volatile signed char *, volatile signed char *, int);
    484337unsigned char __atomic_load_n(const volatile unsigned char *, int);
    485 unsigned char __atomic_load_1(const volatile unsigned char *, int);
    486338void __atomic_load(const volatile unsigned char *, volatile unsigned char *, int);
    487339signed short __atomic_load_n(const volatile signed short *, int);
    488 signed short __atomic_load_2(const volatile signed short *, int);
    489340void __atomic_load(const volatile signed short *, volatile signed short *, int);
    490341unsigned short __atomic_load_n(const volatile unsigned short *, int);
    491 unsigned short __atomic_load_2(const volatile unsigned short *, int);
    492342void __atomic_load(const volatile unsigned short *, volatile unsigned short *, int);
    493343signed int __atomic_load_n(const volatile signed int *, int);
    494 signed int __atomic_load_4(const volatile signed int *, int);
    495344void __atomic_load(const volatile signed int *, volatile signed int *, int);
    496345unsigned int __atomic_load_n(const volatile unsigned int *, int);
    497 unsigned int __atomic_load_4(const volatile unsigned int *, int);
    498346void __atomic_load(const volatile unsigned int *, volatile unsigned int *, int);
     347signed long int __atomic_load_n(const volatile signed long int *, int);
     348void __atomic_load(const volatile signed long int *, volatile signed long int *, int);
     349unsigned long int __atomic_load_n(const volatile unsigned long int *, int);
     350void __atomic_load(const volatile unsigned long int *, volatile unsigned long int *, int);
    499351signed long long int __atomic_load_n(const volatile signed long long int *, int);
    500 signed long long int __atomic_load_8(const volatile signed long long int *, int);
    501352void __atomic_load(const volatile signed long long int *, volatile signed long long int *, int);
    502353unsigned long long int __atomic_load_n(const volatile unsigned long long int *, int);
    503 unsigned long long int __atomic_load_8(const volatile unsigned long long int *, int);
    504354void __atomic_load(const volatile unsigned long long int *, volatile unsigned long long int *, int);
    505355#if defined(__SIZEOF_INT128__)
    506356signed __int128 __atomic_load_n(const volatile signed __int128 *, int);
    507 signed __int128 __atomic_load_16(const volatile signed __int128 *, int);
    508357void __atomic_load(const volatile signed __int128 *, volatile signed __int128 *, int);
    509358unsigned __int128 __atomic_load_n(const volatile unsigned __int128 *, int);
    510 unsigned __int128 __atomic_load_16(const volatile unsigned __int128 *, int);
    511359void __atomic_load(const volatile unsigned __int128 *, volatile unsigned __int128 *, int);
    512360#endif
     
    515363
    516364_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);
    518365_Bool __atomic_compare_exchange  (volatile char *, char *, char *, _Bool, int, int);
    519366_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);
    521367_Bool __atomic_compare_exchange  (volatile signed char *, signed char *, signed char *, _Bool, int, int);
    522368_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);
    524369_Bool __atomic_compare_exchange  (volatile unsigned char *, unsigned char *, unsigned char *, _Bool, int, int);
    525370_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);
    527371_Bool __atomic_compare_exchange  (volatile signed short *, signed short *, signed short *, _Bool, int, int);
    528372_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);
    530373_Bool __atomic_compare_exchange  (volatile unsigned short *, unsigned short *, unsigned short *, _Bool, int, int);
    531374_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);
    533375_Bool __atomic_compare_exchange  (volatile signed int *, signed int *, signed int *, _Bool, int, int);
    534376_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);
    536377_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);
    537382_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);
    539383_Bool __atomic_compare_exchange  (volatile signed long long int *, signed long long int *, signed long long int *, _Bool, int, int);
    540384_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);
    542385_Bool __atomic_compare_exchange  (volatile unsigned long long int *, unsigned long long int *, unsigned long long int *, _Bool, int, int);
    543386#if defined(__SIZEOF_INT128__)
    544387_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);
    546388_Bool __atomic_compare_exchange   (volatile signed __int128 *, signed __int128 *, signed __int128 *, _Bool, int, int);
    547389_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);
    549390_Bool __atomic_compare_exchange   (volatile unsigned __int128 *, unsigned __int128 *, unsigned __int128 *, _Bool, int, int);
    550391#endif
     
    555396void __atomic_store(volatile _Bool *, _Bool *, int);
    556397void __atomic_store_n(volatile char *, char, int);
    557 void __atomic_store_1(volatile char *, char, int);
    558398void __atomic_store(volatile char *, char *, int);
    559399void __atomic_store_n(volatile signed char *, signed char, int);
    560 void __atomic_store_1(volatile signed char *, signed char, int);
    561400void __atomic_store(volatile signed char *, signed char *, int);
    562401void __atomic_store_n(volatile unsigned char *, unsigned char, int);
    563 void __atomic_store_1(volatile unsigned char *, unsigned char, int);
    564402void __atomic_store(volatile unsigned char *, unsigned char *, int);
    565403void __atomic_store_n(volatile signed short *, signed short, int);
    566 void __atomic_store_2(volatile signed short *, signed short, int);
    567404void __atomic_store(volatile signed short *, signed short *, int);
    568405void __atomic_store_n(volatile unsigned short *, unsigned short, int);
    569 void __atomic_store_2(volatile unsigned short *, unsigned short, int);
    570406void __atomic_store(volatile unsigned short *, unsigned short *, int);
    571407void __atomic_store_n(volatile signed int *, signed int, int);
    572 void __atomic_store_4(volatile signed int *, signed int, int);
    573408void __atomic_store(volatile signed int *, signed int *, int);
    574409void __atomic_store_n(volatile unsigned int *, unsigned int, int);
    575 void __atomic_store_4(volatile unsigned int *, unsigned int, int);
    576410void __atomic_store(volatile unsigned int *, unsigned int *, int);
     411void __atomic_store_n(volatile signed long int *, signed long int, int);
     412void __atomic_store(volatile signed long int *, signed long int *, int);
     413void __atomic_store_n(volatile unsigned long int *, unsigned long int, int);
     414void __atomic_store(volatile unsigned long int *, unsigned long int *, int);
    577415void __atomic_store_n(volatile signed long long int *, signed long long int, int);
    578 void __atomic_store_8(volatile signed long long int *, signed long long int, int);
    579416void __atomic_store(volatile signed long long int *, signed long long int *, int);
    580417void __atomic_store_n(volatile unsigned long long int *, unsigned long long int, int);
    581 void __atomic_store_8(volatile unsigned long long int *, unsigned long long int, int);
    582418void __atomic_store(volatile unsigned long long int *, unsigned long long int *, int);
    583419#if defined(__SIZEOF_INT128__)
    584420void __atomic_store_n(volatile signed __int128 *, signed __int128, int);
    585 void __atomic_store_16(volatile signed __int128 *, signed __int128, int);
    586421void __atomic_store(volatile signed __int128 *, signed __int128 *, int);
    587422void __atomic_store_n(volatile unsigned __int128 *, unsigned __int128, int);
    588 void __atomic_store_16(volatile unsigned __int128 *, unsigned __int128, int);
    589423void __atomic_store(volatile unsigned __int128 *, unsigned __int128 *, int);
    590424#endif
     
    593427
    594428char __atomic_add_fetch  (volatile char *, char, int);
    595 char __atomic_add_fetch_1(volatile char *, char, int);
    596429signed char __atomic_add_fetch  (volatile signed char *, signed char, int);
    597 signed char __atomic_add_fetch_1(volatile signed char *, signed char, int);
    598430unsigned char __atomic_add_fetch  (volatile unsigned char *, unsigned char, int);
    599 unsigned char __atomic_add_fetch_1(volatile unsigned char *, unsigned char, int);
    600431signed short __atomic_add_fetch  (volatile signed short *, signed short, int);
    601 signed short __atomic_add_fetch_2(volatile signed short *, signed short, int);
    602432unsigned short __atomic_add_fetch  (volatile unsigned short *, unsigned short, int);
    603 unsigned short __atomic_add_fetch_2(volatile unsigned short *, unsigned short, int);
    604433signed int __atomic_add_fetch  (volatile signed int *, signed int, int);
    605 signed int __atomic_add_fetch_4(volatile signed int *, signed int, int);
    606434unsigned int __atomic_add_fetch  (volatile unsigned int *, unsigned int, int);
    607 unsigned int __atomic_add_fetch_4(volatile unsigned int *, unsigned int, int);
     435signed long int __atomic_add_fetch  (volatile signed long int *, signed long int, int);
     436unsigned long int __atomic_add_fetch  (volatile unsigned long int *, unsigned long int, int);
    608437signed long long int __atomic_add_fetch  (volatile signed long long int *, signed long long int, int);
    609 signed long long int __atomic_add_fetch_8(volatile signed long long int *, signed long long int, int);
    610438unsigned long long int __atomic_add_fetch  (volatile unsigned long long int *, unsigned long long int, int);
    611 unsigned long long int __atomic_add_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    612439#if defined(__SIZEOF_INT128__)
    613440signed __int128 __atomic_add_fetch   (volatile signed __int128 *, signed __int128, int);
    614 signed __int128 __atomic_add_fetch_16(volatile signed __int128 *, signed __int128, int);
    615441unsigned __int128 __atomic_add_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
    616 unsigned __int128 __atomic_add_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    617442#endif
    618443
    619444char __atomic_sub_fetch  (volatile char *, char, int);
    620 char __atomic_sub_fetch_1(volatile char *, char, int);
    621445signed char __atomic_sub_fetch  (volatile signed char *, signed char, int);
    622 signed char __atomic_sub_fetch_1(volatile signed char *, signed char, int);
    623446unsigned char __atomic_sub_fetch  (volatile unsigned char *, unsigned char, int);
    624 unsigned char __atomic_sub_fetch_1(volatile unsigned char *, unsigned char, int);
    625447signed short __atomic_sub_fetch  (volatile signed short *, signed short, int);
    626 signed short __atomic_sub_fetch_2(volatile signed short *, signed short, int);
    627448unsigned short __atomic_sub_fetch  (volatile unsigned short *, unsigned short, int);
    628 unsigned short __atomic_sub_fetch_2(volatile unsigned short *, unsigned short, int);
    629449signed int __atomic_sub_fetch  (volatile signed int *, signed int, int);
    630 signed int __atomic_sub_fetch_4(volatile signed int *, signed int, int);
    631450unsigned int __atomic_sub_fetch  (volatile unsigned int *, unsigned int, int);
    632 unsigned int __atomic_sub_fetch_4(volatile unsigned int *, unsigned int, int);
     451signed long long int __atomic_sub_fetch  (volatile signed long int *, signed long int, int);
     452unsigned long long int __atomic_sub_fetch  (volatile unsigned long int *, unsigned long int, int);
    633453signed long long int __atomic_sub_fetch  (volatile signed long long int *, signed long long int, int);
    634 signed long long int __atomic_sub_fetch_8(volatile signed long long int *, signed long long int, int);
    635454unsigned long long int __atomic_sub_fetch  (volatile unsigned long long int *, unsigned long long int, int);
    636 unsigned long long int __atomic_sub_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    637455#if defined(__SIZEOF_INT128__)
    638456signed __int128 __atomic_sub_fetch   (volatile signed __int128 *, signed __int128, int);
    639 signed __int128 __atomic_sub_fetch_16(volatile signed __int128 *, signed __int128, int);
    640457unsigned __int128 __atomic_sub_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
    641 unsigned __int128 __atomic_sub_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    642458#endif
    643459
    644460char __atomic_and_fetch  (volatile char *, char, int);
    645 char __atomic_and_fetch_1(volatile char *, char, int);
    646461signed char __atomic_and_fetch  (volatile signed char *, signed char, int);
    647 signed char __atomic_and_fetch_1(volatile signed char *, signed char, int);
    648462unsigned char __atomic_and_fetch  (volatile unsigned char *, unsigned char, int);
    649 unsigned char __atomic_and_fetch_1(volatile unsigned char *, unsigned char, int);
    650463signed short __atomic_and_fetch  (volatile signed short *, signed short, int);
    651 signed short __atomic_and_fetch_2(volatile signed short *, signed short, int);
    652464unsigned short __atomic_and_fetch  (volatile unsigned short *, unsigned short, int);
    653 unsigned short __atomic_and_fetch_2(volatile unsigned short *, unsigned short, int);
    654465signed int __atomic_and_fetch  (volatile signed int *, signed int, int);
    655 signed int __atomic_and_fetch_4(volatile signed int *, signed int, int);
    656466unsigned int __atomic_and_fetch  (volatile unsigned int *, unsigned int, int);
    657 unsigned int __atomic_and_fetch_4(volatile unsigned int *, unsigned int, int);
     467signed long int __atomic_and_fetch  (volatile signed long int *, signed long int, int);
     468unsigned long int __atomic_and_fetch  (volatile unsigned long int *, unsigned long int, int);
    658469signed long long int __atomic_and_fetch  (volatile signed long long int *, signed long long int, int);
    659 signed long long int __atomic_and_fetch_8(volatile signed long long int *, signed long long int, int);
    660470unsigned long long int __atomic_and_fetch  (volatile unsigned long long int *, unsigned long long int, int);
    661 unsigned long long int __atomic_and_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    662471#if defined(__SIZEOF_INT128__)
    663472signed __int128 __atomic_and_fetch   (volatile signed __int128 *, signed __int128, int);
    664 signed __int128 __atomic_and_fetch_16(volatile signed __int128 *, signed __int128, int);
    665473unsigned __int128 __atomic_and_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
    666 unsigned __int128 __atomic_and_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    667474#endif
    668475
    669476char __atomic_nand_fetch  (volatile char *, char, int);
    670 char __atomic_nand_fetch_1(volatile char *, char, int);
    671477signed char __atomic_nand_fetch  (volatile signed char *, signed char, int);
    672 signed char __atomic_nand_fetch_1(volatile signed char *, signed char, int);
    673478unsigned char __atomic_nand_fetch  (volatile unsigned char *, unsigned char, int);
    674 unsigned char __atomic_nand_fetch_1(volatile unsigned char *, unsigned char, int);
    675479signed short __atomic_nand_fetch  (volatile signed short *, signed short, int);
    676 signed short __atomic_nand_fetch_2(volatile signed short *, signed short, int);
    677480unsigned short __atomic_nand_fetch  (volatile unsigned short *, unsigned short, int);
    678 unsigned short __atomic_nand_fetch_2(volatile unsigned short *, unsigned short, int);
    679481signed int __atomic_nand_fetch  (volatile signed int *, signed int, int);
    680 signed int __atomic_nand_fetch_4(volatile signed int *, signed int, int);
    681482unsigned int __atomic_nand_fetch  (volatile unsigned int *, unsigned int, int);
    682 unsigned int __atomic_nand_fetch_4(volatile unsigned int *, unsigned int, int);
     483signed long int __atomic_nand_fetch  (volatile signed long int *, signed long int, int);
     484unsigned long int __atomic_nand_fetch  (volatile unsigned long int *, unsigned long int, int);
    683485signed long long int __atomic_nand_fetch  (volatile signed long long int *, signed long long int, int);
    684 signed long long int __atomic_nand_fetch_8(volatile signed long long int *, signed long long int, int);
    685486unsigned long long int __atomic_nand_fetch  (volatile unsigned long long int *, unsigned long long int, int);
    686 unsigned long long int __atomic_nand_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    687487#if defined(__SIZEOF_INT128__)
    688488signed __int128 __atomic_nand_fetch   (volatile signed __int128 *, signed __int128, int);
    689 signed __int128 __atomic_nand_fetch_16(volatile signed __int128 *, signed __int128, int);
    690489unsigned __int128 __atomic_nand_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
    691 unsigned __int128 __atomic_nand_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    692490#endif
    693491
    694492char __atomic_xor_fetch  (volatile char *, char, int);
    695 char __atomic_xor_fetch_1(volatile char *, char, int);
    696493signed char __atomic_xor_fetch  (volatile signed char *, signed char, int);
    697 signed char __atomic_xor_fetch_1(volatile signed char *, signed char, int);
    698494unsigned char __atomic_xor_fetch  (volatile unsigned char *, unsigned char, int);
    699 unsigned char __atomic_xor_fetch_1(volatile unsigned char *, unsigned char, int);
    700495signed short __atomic_xor_fetch  (volatile signed short *, signed short, int);
    701 signed short __atomic_xor_fetch_2(volatile signed short *, signed short, int);
    702496unsigned short __atomic_xor_fetch  (volatile unsigned short *, unsigned short, int);
    703 unsigned short __atomic_xor_fetch_2(volatile unsigned short *, unsigned short, int);
    704497signed int __atomic_xor_fetch  (volatile signed int *, signed int, int);
    705 signed int __atomic_xor_fetch_4(volatile signed int *, signed int, int);
    706498unsigned int __atomic_xor_fetch  (volatile unsigned int *, unsigned int, int);
    707 unsigned int __atomic_xor_fetch_4(volatile unsigned int *, unsigned int, int);
     499signed long int __atomic_xor_fetch  (volatile signed long int *, signed long int, int);
     500unsigned long int __atomic_xor_fetch  (volatile unsigned long int *, unsigned long int, int);
    708501signed long long int __atomic_xor_fetch  (volatile signed long long int *, signed long long int, int);
    709 signed long long int __atomic_xor_fetch_8(volatile signed long long int *, signed long long int, int);
    710502unsigned long long int __atomic_xor_fetch  (volatile unsigned long long int *, unsigned long long int, int);
    711 unsigned long long int __atomic_xor_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    712503#if defined(__SIZEOF_INT128__)
    713504signed __int128 __atomic_xor_fetch   (volatile signed __int128 *, signed __int128, int);
    714 signed __int128 __atomic_xor_fetch_16(volatile signed __int128 *, signed __int128, int);
    715505unsigned __int128 __atomic_xor_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
    716 unsigned __int128 __atomic_xor_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    717506#endif
    718507
    719508char __atomic_or_fetch  (volatile char *, char, int);
    720 char __atomic_or_fetch_1(volatile char *, char, int);
    721509signed char __atomic_or_fetch  (volatile signed char *, signed char, int);
    722 signed char __atomic_or_fetch_1(volatile signed char *, signed char, int);
    723510unsigned char __atomic_or_fetch  (volatile unsigned char *, unsigned char, int);
    724 unsigned char __atomic_or_fetch_1(volatile unsigned char *, unsigned char, int);
    725511signed short __atomic_or_fetch  (volatile signed short *, signed short, int);
    726 signed short __atomic_or_fetch_2(volatile signed short *, signed short, int);
    727512unsigned short __atomic_or_fetch  (volatile unsigned short *, unsigned short, int);
    728 unsigned short __atomic_or_fetch_2(volatile unsigned short *, unsigned short, int);
    729513signed int __atomic_or_fetch  (volatile signed int *, signed int, int);
    730 signed int __atomic_or_fetch_4(volatile signed int *, signed int, int);
    731514unsigned int __atomic_or_fetch  (volatile unsigned int *, unsigned int, int);
    732 unsigned int __atomic_or_fetch_4(volatile unsigned int *, unsigned int, int);
     515signed long int __atomic_or_fetch  (volatile signed long int *, signed long int, int);
     516unsigned long int __atomic_or_fetch  (volatile unsigned long int *, unsigned long int, int);
    733517signed long long int __atomic_or_fetch  (volatile signed long long int *, signed long long int, int);
    734 signed long long int __atomic_or_fetch_8(volatile signed long long int *, signed long long int, int);
    735518unsigned long long int __atomic_or_fetch  (volatile unsigned long long int *, unsigned long long int, int);
    736 unsigned long long int __atomic_or_fetch_8(volatile unsigned long long int *, unsigned long long int, int);
    737519#if defined(__SIZEOF_INT128__)
    738520signed __int128 __atomic_or_fetch   (volatile signed __int128 *, signed __int128, int);
    739 signed __int128 __atomic_or_fetch_16(volatile signed __int128 *, signed __int128, int);
    740521unsigned __int128 __atomic_or_fetch   (volatile unsigned __int128 *, unsigned __int128, int);
    741 unsigned __int128 __atomic_or_fetch_16(volatile unsigned __int128 *, unsigned __int128, int);
    742522#endif
    743523
    744524char __atomic_fetch_add  (volatile char *, char, int);
    745 char __atomic_fetch_add_1(volatile char *, char, int);
    746525signed char __atomic_fetch_add  (volatile signed char *, signed char, int);
    747 signed char __atomic_fetch_add_1(volatile signed char *, signed char, int);
    748526unsigned char __atomic_fetch_add  (volatile unsigned char *, unsigned char, int);
    749 unsigned char __atomic_fetch_add_1(volatile unsigned char *, unsigned char, int);
    750527signed short __atomic_fetch_add  (volatile signed short *, signed short, int);
    751 signed short __atomic_fetch_add_2(volatile signed short *, signed short, int);
    752528unsigned short __atomic_fetch_add  (volatile unsigned short *, unsigned short, int);
    753 unsigned short __atomic_fetch_add_2(volatile unsigned short *, unsigned short, int);
    754529signed int __atomic_fetch_add  (volatile signed int *, signed int, int);
    755 signed int __atomic_fetch_add_4(volatile signed int *, signed int, int);
    756530unsigned int __atomic_fetch_add  (volatile unsigned int *, unsigned int, int);
    757 unsigned int __atomic_fetch_add_4(volatile unsigned int *, unsigned int, int);
     531signed long int __atomic_fetch_add  (volatile signed long int *, signed long int, int);
     532unsigned long int __atomic_fetch_add  (volatile unsigned long int *, unsigned long int, int);
    758533signed long long int __atomic_fetch_add  (volatile signed long long int *, signed long long int, int);
    759 signed long long int __atomic_fetch_add_8(volatile signed long long int *, signed long long int, int);
    760534unsigned long long int __atomic_fetch_add  (volatile unsigned long long int *, unsigned long long int, int);
    761 unsigned long long int __atomic_fetch_add_8(volatile unsigned long long int *, unsigned long long int, int);
    762535#if defined(__SIZEOF_INT128__)
    763536signed __int128 __atomic_fetch_add   (volatile signed __int128 *, signed __int128, int);
    764 signed __int128 __atomic_fetch_add_16(volatile signed __int128 *, signed __int128, int);
    765537unsigned __int128 __atomic_fetch_add   (volatile unsigned __int128 *, unsigned __int128, int);
    766 unsigned __int128 __atomic_fetch_add_16(volatile unsigned __int128 *, unsigned __int128, int);
    767538#endif
    768539
    769540char __atomic_fetch_sub  (volatile char *, char, int);
    770 char __atomic_fetch_sub_1(volatile char *, char, int);
    771541signed char __atomic_fetch_sub  (volatile signed char *, signed char, int);
    772 signed char __atomic_fetch_sub_1(volatile signed char *, signed char, int);
    773542unsigned char __atomic_fetch_sub  (volatile unsigned char *, unsigned char, int);
    774 unsigned char __atomic_fetch_sub_1(volatile unsigned char *, unsigned char, int);
    775543signed short __atomic_fetch_sub  (volatile signed short *, signed short, int);
    776 signed short __atomic_fetch_sub_2(volatile signed short *, signed short, int);
    777544unsigned short __atomic_fetch_sub  (volatile unsigned short *, unsigned short, int);
    778 unsigned short __atomic_fetch_sub_2(volatile unsigned short *, unsigned short, int);
    779545signed int __atomic_fetch_sub  (volatile signed int *, signed int, int);
    780 signed int __atomic_fetch_sub_4(volatile signed int *, signed int, int);
    781546unsigned int __atomic_fetch_sub  (volatile unsigned int *, unsigned int, int);
    782 unsigned int __atomic_fetch_sub_4(volatile unsigned int *, unsigned int, int);
     547signed long int __atomic_fetch_sub  (volatile signed long int *, signed long int, int);
     548unsigned long int __atomic_fetch_sub  (volatile unsigned long int *, unsigned long int, int);
    783549signed long long int __atomic_fetch_sub  (volatile signed long long int *, signed long long int, int);
    784 signed long long int __atomic_fetch_sub_8(volatile signed long long int *, signed long long int, int);
    785550unsigned long long int __atomic_fetch_sub  (volatile unsigned long long int *, unsigned long long int, int);
    786 unsigned long long int __atomic_fetch_sub_8(volatile unsigned long long int *, unsigned long long int, int);
    787551#if defined(__SIZEOF_INT128__)
    788552signed __int128 __atomic_fetch_sub   (volatile signed  __int128 *, signed __int128, int);
    789 signed __int128 __atomic_fetch_sub_16(volatile signed  __int128 *, signed __int128, int);
    790553unsigned __int128 __atomic_fetch_sub   (volatile unsigned  __int128 *, unsigned __int128, int);
    791 unsigned __int128 __atomic_fetch_sub_16(volatile unsigned  __int128 *, unsigned __int128, int);
    792554#endif
    793555
    794556char __atomic_fetch_and  (volatile char *, char, int);
    795 char __atomic_fetch_and_1(volatile char *, char, int);
    796557signed char __atomic_fetch_and  (volatile signed char *, signed char, int);
    797 signed char __atomic_fetch_and_1(volatile signed char *, signed char, int);
    798558unsigned char __atomic_fetch_and  (volatile unsigned char *, unsigned char, int);
    799 unsigned char __atomic_fetch_and_1(volatile unsigned char *, unsigned char, int);
    800559signed short __atomic_fetch_and  (volatile signed short *, signed short, int);
    801 signed short __atomic_fetch_and_2(volatile signed short *, signed short, int);
    802560unsigned short __atomic_fetch_and  (volatile unsigned short *, unsigned short, int);
    803 unsigned short __atomic_fetch_and_2(volatile unsigned short *, unsigned short, int);
    804561signed int __atomic_fetch_and  (volatile signed int *, signed int, int);
    805 signed int __atomic_fetch_and_4(volatile signed int *, signed int, int);
    806562unsigned int __atomic_fetch_and  (volatile unsigned int *, unsigned int, int);
    807 unsigned int __atomic_fetch_and_4(volatile unsigned int *, unsigned int, int);
     563signed long int __atomic_fetch_and  (volatile signed long int *, signed long int, int);
     564unsigned long int __atomic_fetch_and  (volatile unsigned long int *, unsigned long int, int);
    808565signed long long int __atomic_fetch_and  (volatile signed long long int *, signed long long int, int);
    809 signed long long int __atomic_fetch_and_8(volatile signed long long int *, signed long long int, int);
    810566unsigned long long int __atomic_fetch_and  (volatile unsigned long long int *, unsigned long long int, int);
    811 unsigned long long int __atomic_fetch_and_8(volatile unsigned long long int *, unsigned long long int, int);
    812567#if defined(__SIZEOF_INT128__)
    813568signed __int128 __atomic_fetch_and   (volatile signed __int128 *, signed __int128, int);
    814 signed __int128 __atomic_fetch_and_16(volatile signed __int128 *, signed __int128, int);
    815569unsigned __int128 __atomic_fetch_and   (volatile unsigned __int128 *, unsigned __int128, int);
    816 unsigned __int128 __atomic_fetch_and_16(volatile unsigned __int128 *, unsigned __int128, int);
    817570#endif
    818571
    819572char __atomic_fetch_nand  (volatile char *, char, int);
    820 char __atomic_fetch_nand_1(volatile char *, char, int);
    821573signed char __atomic_fetch_nand  (volatile signed char *, signed char, int);
    822 signed char __atomic_fetch_nand_1(volatile signed char *, signed char, int);
    823574unsigned char __atomic_fetch_nand  (volatile unsigned char *, unsigned char, int);
    824 unsigned char __atomic_fetch_nand_1(volatile unsigned char *, unsigned char, int);
    825575signed short __atomic_fetch_nand  (volatile signed short *, signed short, int);
    826 signed short __atomic_fetch_nand_2(volatile signed short *, signed short, int);
    827576unsigned short __atomic_fetch_nand  (volatile unsigned short *, unsigned short, int);
    828 unsigned short __atomic_fetch_nand_2(volatile unsigned short *, unsigned short, int);
    829577signed int __atomic_fetch_nand  (volatile signed int *, signed int, int);
    830 signed int __atomic_fetch_nand_4(volatile signed int *, signed int, int);
    831578unsigned int __atomic_fetch_nand  (volatile unsigned int *, unsigned int, int);
    832 unsigned int __atomic_fetch_nand_4(volatile unsigned int *, unsigned int, int);
     579signed long int __atomic_fetch_nand  (volatile signed long int *, signed long int, int);
     580unsigned long int __atomic_fetch_nand  (volatile unsigned long int *, unsigned long int, int);
    833581signed long long int __atomic_fetch_nand  (volatile signed long long int *, signed long long int, int);
    834 signed long long int __atomic_fetch_nand_8(volatile signed long long int *, signed long long int, int);
    835582unsigned long long int __atomic_fetch_nand  (volatile unsigned long long int *, unsigned long long int, int);
    836 unsigned long long int __atomic_fetch_nand_8(volatile unsigned long long int *, unsigned long long int, int);
    837583#if defined(__SIZEOF_INT128__)
    838584signed __int128 __atomic_fetch_nand   (volatile signed __int128 *, signed __int128, int);
    839 signed __int128 __atomic_fetch_nand_16(volatile signed __int128 *, signed __int128, int);
    840585unsigned __int128 __atomic_fetch_nand   (volatile unsigned __int128 *, unsigned __int128, int);
    841 unsigned __int128 __atomic_fetch_nand_16(volatile unsigned __int128 *, unsigned __int128, int);
    842586#endif
    843587
    844588char __atomic_fetch_xor  (volatile char *, char, int);
    845 char __atomic_fetch_xor_1(volatile char *, char, int);
    846589signed char __atomic_fetch_xor  (volatile signed char *, signed char, int);
    847 signed char __atomic_fetch_xor_1(volatile signed char *, signed char, int);
    848590unsigned char __atomic_fetch_xor  (volatile unsigned char *, unsigned char, int);
    849 unsigned char __atomic_fetch_xor_1(volatile unsigned char *, unsigned char, int);
    850591signed short __atomic_fetch_xor  (volatile signed short *, signed short, int);
    851 signed short __atomic_fetch_xor_2(volatile signed short *, signed short, int);
    852592unsigned short __atomic_fetch_xor  (volatile unsigned short *, unsigned short, int);
    853 unsigned short __atomic_fetch_xor_2(volatile unsigned short *, unsigned short, int);
    854593signed int __atomic_fetch_xor  (volatile signed int *, signed int, int);
    855 signed int __atomic_fetch_xor_4(volatile signed int *, signed int, int);
    856594unsigned int __atomic_fetch_xor  (volatile unsigned int *, unsigned int, int);
    857 unsigned int __atomic_fetch_xor_4(volatile unsigned int *, unsigned int, int);
     595signed long int __atomic_fetch_xor  (volatile signed long int *, signed long int, int);
     596unsigned long int __atomic_fetch_xor  (volatile unsigned long int *, unsigned long int, int);
    858597signed long long int __atomic_fetch_xor  (volatile signed long long int *, signed long long int, int);
    859 signed long long int __atomic_fetch_xor_8(volatile signed long long int *, signed long long int, int);
    860598unsigned long long int __atomic_fetch_xor  (volatile unsigned long long int *, unsigned long long int, int);
    861 unsigned long long int __atomic_fetch_xor_8(volatile unsigned long long int *, unsigned long long int, int);
    862599#if defined(__SIZEOF_INT128__)
    863600signed __int128 __atomic_fetch_xor   (volatile signed __int128 *, signed __int128, int);
    864 signed __int128 __atomic_fetch_xor_16(volatile signed __int128 *, signed __int128, int);
    865601unsigned __int128 __atomic_fetch_xor   (volatile unsigned __int128 *, unsigned __int128, int);
    866 unsigned __int128 __atomic_fetch_xor_16(volatile unsigned __int128 *, unsigned __int128, int);
    867602#endif
    868603
    869604char __atomic_fetch_or  (volatile char *, char, int);
    870 char __atomic_fetch_or_1(volatile char *, char, int);
    871605signed char __atomic_fetch_or  (volatile signed char *, signed char, int);
    872 signed char __atomic_fetch_or_1(volatile signed char *, signed char, int);
    873606unsigned char __atomic_fetch_or  (volatile unsigned char *, unsigned char, int);
    874 unsigned char __atomic_fetch_or_1(volatile unsigned char *, unsigned char, int);
    875607signed short __atomic_fetch_or  (volatile signed short *, signed short, int);
    876 signed short __atomic_fetch_or_2(volatile signed short *, signed short, int);
    877608unsigned short __atomic_fetch_or  (volatile unsigned short *, unsigned short, int);
    878 unsigned short __atomic_fetch_or_2(volatile unsigned short *, unsigned short, int);
    879609signed int __atomic_fetch_or  (volatile signed int *, signed int, int);
    880 signed int __atomic_fetch_or_4(volatile signed int *, signed int, int);
    881610unsigned int __atomic_fetch_or  (volatile unsigned int *, unsigned int, int);
    882 unsigned int __atomic_fetch_or_4(volatile unsigned int *, unsigned int, int);
     611signed long int __atomic_fetch_or  (volatile signed long int *, signed long int, int);
     612unsigned long int __atomic_fetch_or  (volatile unsigned long int *, unsigned long int, int);
    883613signed long long int __atomic_fetch_or  (volatile signed long long int *, signed long long int, int);
    884 signed long long int __atomic_fetch_or_8(volatile signed long long int *, signed long long int, int);
    885614unsigned long long int __atomic_fetch_or  (volatile unsigned long long int *, unsigned long long int, int);
    886 unsigned long long int __atomic_fetch_or_8(volatile unsigned long long int *, unsigned long long int, int);
    887615#if defined(__SIZEOF_INT128__)
    888616signed __int128 __atomic_fetch_or   (volatile signed __int128 *, signed __int128, int);
    889 signed __int128 __atomic_fetch_or_16(volatile signed __int128 *, signed __int128, int);
    890617unsigned __int128 __atomic_fetch_or   (volatile unsigned __int128 *, unsigned __int128, int);
    891 unsigned __int128 __atomic_fetch_or_16(volatile unsigned __int128 *, unsigned __int128, int);
    892618#endif
    893619
  • libcfa/src/Makefile.am

    r71d6bd8 r7030dab  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Jul 15 22:43:27 2019
    14 ## Update Count     : 241
     13## Last Modified On : Mon Mar 16 18:07:59 2020
     14## Update Count     : 242
    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 @ARCH_FLAGS@ @CONFIG_CFLAGS@
     35AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3636AM_CCASFLAGS = -g -Wall -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    3737CFACC = @CFACC@
     
    3939#----------------------------------------------------------------------------------------------------------------
    4040if BUILDLIB
    41 headers_nosrc = math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa
     41headers_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
    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

    r71d6bd8 r7030dab  
    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 math.hfa gmp.hfa time_t.hfa \
     239        containers/vector.hfa bitmanip.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) $(CFAFLAGS) \
    419         $(AM_CFLAGS) $(CFLAGS)
     418        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
    420419
    421420AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    423422am__v_CFA_0 = @echo "  CFA     " $@;
    424423am__v_CFA_1 =
    425 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    426 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    427 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    428 am__v_JAVAC_1 =
    429 AM_V_GOC = $(am__v_GOC_@AM_V@)
    430 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    431 am__v_GOC_0 = @echo "  GOC     " $@;
    432 am__v_GOC_1 =
    433424UPPCC = u++
    434425UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    437428am__v_UPP_0 = @echo "  UPP     " $@;
    438429am__v_UPP_1 =
     430AM_V_GOC = $(am__v_GOC_@AM_V@)
     431am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     432am__v_GOC_0 = @echo "  GOC     " $@;
     433am__v_GOC_1 =
     434AM_V_PY = $(am__v_PY_@AM_V@)
     435am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
     436am__v_PY_0 = @echo "  PYTHON  " $@;
     437am__v_PY_1 =
     438AM_V_RUST = $(am__v_RUST_@AM_V@)
     439am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
     440am__v_RUST_0 = @echo "  RUST    " $@;
     441am__v_RUST_1 =
     442AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
     443am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
     444am__v_NODEJS_0 = @echo "  NODEJS  " $@;
     445am__v_NODEJS_1 =
     446AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     447am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     448am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     449am__v_JAVAC_1 =
    439450lib_LTLIBRARIES = libcfa.la libcfathread.la
    440451gdbwaittarget = ""
     
    445456# The built sources must not depend on the installed headers
    446457AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@
    447 AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC @ARCH_FLAGS@ @CONFIG_CFLAGS@
     458AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@
    448459AM_CCASFLAGS = -g -Wall -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@
    449460@BUILDLIB_FALSE@headers_nosrc =
    450461
    451462#----------------------------------------------------------------------------------------------------------------
    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
     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
    453464@BUILDLIB_FALSE@headers =
    454465@BUILDLIB_TRUE@headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
  • libcfa/src/assert.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 20 15:10:26 2017
    13 // Update Count     : 2
     12// Last Modified On : Tue Feb  4 13:00:18 2020
     13// Update Count     : 6
    1414//
    1515
     
    1717#include <stdarg.h>                                                             // varargs
    1818#include <stdio.h>                                                              // fprintf
     19#include <unistd.h>                                                             // STDERR_FILENO
    1920#include "bits/debug.hfa"
    2021
     
    2526
    2627        // called by macro assert in assert.h
    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 );
     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 );
    2930                abort();
    3031        }
    3132
    3233        // called by macro assertf
    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 );
     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 );
    3637
    3738                va_list args;
    3839                va_start( args, fmt );
    39                 __cfaabi_dbg_bits_print_vararg( fmt, args );
     40                __cfaabi_bits_print_vararg( STDERR_FILENO, fmt, args );
    4041                va_end( args );
    4142
    42                 __cfaabi_dbg_bits_print_nolock( "\n" );
    43                 __cfaabi_dbg_bits_release();
     43                __cfaabi_bits_print_nolock( STDERR_FILENO, "\n" );
     44                __cfaabi_bits_release();
    4445                abort();
    4546        }
  • libcfa/src/bits/align.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 23:05:35 2017
    13 // Update Count     : 2
     12// Last Modified On : Sat Nov 16 18:58:22 2019
     13// Update Count     : 3
    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))
     35//#define libAlign() (sizeof(double))
     36// gcc-7 uses xmms instructions, which require 16 byte alignment.
     37#define libAlign() (16)
    3638
    3739// Check for power of 2
  • libcfa/src/bits/containers.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Oct 31 16:38:50 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 26 08:52:20 2019
    13 // Update Count     : 4
     12// Last Modified On : Wed Jan 15 07:42:35 2020
     13// Update Count     : 28
    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 ) {
     57                return ((typeof(this.data))this.data);
     58        }
     59
    5560        forall(dtype T | sized(T))
    56         static inline T* begin( const __small_array(T) & this ) {
    57                 return ((typeof(this.data))this.data);
    58         }
    59 
    60         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){ 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;
     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                }
    122121        }
    123122#endif
     
    145144
    146145#ifdef __cforall
    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;
    168                         }
    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;
     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;
     173                        }
     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                }
    195198        }
    196199#endif
     
    223226
    224227#ifdef __cforall
    225 
    226         forall(dtype T | sized(T))
     228        forall(dtype T )
    227229        static inline [void] ?{}( __dllist(T) & this, * [T * & next, T * & prev] ( T & ) __get ) {
    228                 this.head{ NULL };
     230                this.head{ 0p };
    229231                this.__get = __get;
    230232        }
     
    232234        #define next 0
    233235        #define prev 1
    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
     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
    241253                        // prevent code movement across barrier
    242254                        asm( "" : : : "memory" );
    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;
    263                         }
    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;
     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                                }
     266                        }
     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                }
    277281        }
    278282        #undef next
     
    286290
    287291#endif
     292
     293// Local Variables: //
     294// tab-width: 4 //
     295// End: //
  • libcfa/src/bits/debug.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Thu Mar 30 12:30:01 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jul 14 22:17:35 2019
    13 // Update Count     : 4
     12// Last Modified On : Tue Feb  4 13:03:16 2020
     13// Update Count     : 11
    1414//
    1515
     
    2727
    2828extern "C" {
    29 
    30         void __cfaabi_dbg_bits_write( const char *in_buffer, int len ) {
     29        void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) {
    3130                // ensure all data is written
    3231                for ( int count = 0, retcode; count < len; count += retcode ) {
     
    3433
    3534                        for ( ;; ) {
    36                                 retcode = write( STDERR_FILENO, in_buffer, len - count );
     35                                retcode = write( fd, in_buffer, len - count );
    3736
    3837                                // not a timer interrupt ?
     
    4443        }
    4544
    46         void __cfaabi_dbg_bits_acquire() __attribute__((__weak__)) {}
    47         void __cfaabi_dbg_bits_release() __attribute__((__weak__)) {}
     45        void __cfaabi_bits_acquire() __attribute__((__weak__)) {}
     46        void __cfaabi_bits_release() __attribute__((__weak__)) {}
    4847
    49         void __cfaabi_dbg_bits_print_safe  ( const char fmt[], ... ) __attribute__(( format(printf, 1, 2) )) {
     48        void __cfaabi_bits_print_safe  ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) {
    5049                va_list args;
    5150
    5251                va_start( args, fmt );
    53                 __cfaabi_dbg_bits_acquire();
     52                __cfaabi_bits_acquire();
    5453
    5554                int len = vsnprintf( buffer, buffer_size, fmt, args );
    56                 __cfaabi_dbg_bits_write( buffer, len );
     55                __cfaabi_bits_write( fd, buffer, len );
    5756
    58                 __cfaabi_dbg_bits_release();
     57                __cfaabi_bits_release();
    5958                va_end( args );
    6059        }
    6160
    62         void __cfaabi_dbg_bits_print_nolock( const char fmt[], ... ) __attribute__(( format(printf, 1, 2) )) {
     61        void __cfaabi_bits_print_nolock( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) {
    6362                va_list args;
    6463
     
    6665
    6766                int len = vsnprintf( buffer, buffer_size, fmt, args );
    68                 __cfaabi_dbg_bits_write( buffer, len );
     67                __cfaabi_bits_write( fd, buffer, len );
    6968
    7069                va_end( args );
    7170        }
    7271
    73         void __cfaabi_dbg_bits_print_vararg( const char fmt[], va_list args ) {
     72        void __cfaabi_bits_print_vararg( int fd, const char fmt[], va_list args ) {
    7473                int len = vsnprintf( buffer, buffer_size, fmt, args );
    75                 __cfaabi_dbg_bits_write( buffer, len );
     74                __cfaabi_bits_write( fd, buffer, len );
    7675        }
    7776
    78         void __cfaabi_dbg_bits_print_buffer( char in_buffer[], int in_buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 3, 4) )) {
     77        void __cfaabi_bits_print_buffer( int fd, char in_buffer[], int in_buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 4, 5) )) {
    7978                va_list args;
    8079
     
    8281
    8382                int len = vsnprintf( in_buffer, in_buffer_size, fmt, args );
    84                 __cfaabi_dbg_bits_write( in_buffer, len );
     83                __cfaabi_bits_write( fd, in_buffer, len );
    8584
    8685                va_end( args );
  • libcfa/src/bits/debug.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  8 12:35:19 2018
    13 // Update Count     : 2
     12// Last Modified On : Tue Feb  4 12:29:21 2020
     13// Update Count     : 9
    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
     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
    2527#else
    2628        #define __cfaabi_dbg_debug_do(...)
     
    3032        #define __cfaabi_dbg_ctx_param
    3133        #define __cfaabi_dbg_ctx_param2
     34        #define __cfaabi_dbg_ctx_fwd
     35        #define __cfaabi_dbg_ctx_fwd2
    3236#endif
    3337
     
    3842        #include <stdio.h>
    3943
    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) ));
     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) ));
    4751#ifdef __cforall
    4852}
     
    5054
    5155#ifdef __CFA_DEBUG_PRINT__
    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 );
     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 );
    6064#else
    6165        #define __cfaabi_dbg_write(...)               ((void)0)
  • libcfa/src/bits/defs.hfa

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

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

    r71d6bd8 r7030dab  
    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 );
    3949        act.sa_flags = flags;
    4050
    41         if ( sigaction( sig, &act, NULL ) == -1 ) {
     51        if ( sigaction( sig, &act, 0p ) == -1 ) {
    4252                __cfaabi_dbg_print_buffer_decl(
    4353                        " __cfaabi_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
     
    4555                );
    4656                _exit( EXIT_FAILURE );
    47         }
     57        } // if
    4858}
    49 
    50 // Sigaction wrapper : restore default handler
    51 static 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

    r71d6bd8 r7030dab  
    1010// Created On       : Thu Apr 12 14:36:06 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun 13 21:21:13 2019
    13 // Update Count     : 8
     12// Last Modified On : Mon Jan  6 12:49:58 2020
     13// Update Count     : 9
    1414//
    1515
    1616#include <time.hfa>
    17 
    1817
    1918//######################### C time #########################
     
    2625static inline tm * localtime_r( time_t tp, tm * result ) { return localtime_r( &tp, result ); }
    2726
    28 
    2927//######################### Clock #########################
    3028
    3129struct Clock {                                                                                  // private
    3230        Duration offset;                                                                        // for virtual clock: contains offset from real-time
    33         int clocktype;                                                                          // implementation only -1 (virtual), CLOCK_REALTIME
    3431};
    3532
    3633static inline {
    37         void resetClock( Clock & clk ) with( clk ) {
    38                 clocktype = CLOCK_REALTIME_COARSE;
    39         } // Clock::resetClock
    40 
    4134        void resetClock( Clock & clk, Duration adj ) with( clk ) {
    42                 clocktype = -1;
    4335                offset = adj + __timezone`s;                                    // timezone (global) is (UTC - local time) in seconds
    4436        } // resetClock
    4537
    46         void ?{}( Clock & clk ) { resetClock( clk ); }
    4738        void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
    4839
     
    8980                return ret;
    9081        } // getTime
     82
     83        Time getCPUTime() {
     84                timespec ts;
     85                clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
     86                return (Time){ ts };
     87    } // getCPUTime
    9188} // distribution
    9289
  • libcfa/src/concurrency/CtxSwitch-arm.S

    r71d6bd8 r7030dab  
    1313        .text
    1414        .align  2
    15         .global CtxSwitch
    16         .type   CtxSwitch, %function
     15        .global __cfactx_switch
     16        .type   __cfactx_switch, %function
    1717
    18 CtxSwitch:
     18__cfactx_switch:
    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 CtxInvokeStub
    58         .type   CtxInvokeStub, %function
     57        .global __cfactx_invoke_stub
     58        .type   __cfactx_invoke_stub, %function
    5959
    60 CtxInvokeStub:
     60__cfactx_invoke_stub:
    6161        ldmfd r13!, {r0-r1}
    6262        mov r15, r1
  • libcfa/src/concurrency/CtxSwitch-i386.S

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

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

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

    r71d6bd8 r7030dab  
    2323#include "time.hfa"
    2424
    25 struct thread_desc;
     25struct $thread;
    2626struct processor;
    2727
     
    4343
    4444        union {
    45                 thread_desc * thrd;     // thrd who created event
     45                $thread * 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_desc * thrd, Time alarm, Duration period );
     55void ?{}( alarm_node_t & this, $thread * 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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 30 17:20:57 2018
    13 // Update Count     : 9
     12// Last Modified On : Tue Feb  4 12:29:25 2020
     13// Update Count     : 16
    1414//
    1515
     
    3737
    3838extern "C" {
    39         void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
     39        void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct $coroutine *) __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_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
    92         (this.context){NULL, NULL};
     91void ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize ) with( this ) {
     92        (this.context){0p, 0p};
    9393        (this.stack){storage, storageSize};
    9494        this.name = name;
    9595        state = Start;
    96         starter = NULL;
    97         last = NULL;
    98         cancellation = NULL;
    99 }
    100 
    101 void ^?{}(coroutine_desc& this) {
     96        starter = 0p;
     97        last = 0p;
     98        cancellation = 0p;
     99}
     100
     101void ^?{}($coroutine& this) {
    102102        if(this.state != Halted && this.state != Start && this.state != Primed) {
    103                 coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    104                 coroutine_desc * dst = &this;
     103                $coroutine * src = TL_GET( this_thread )->curr_cor;
     104                $coroutine * dst = &this;
    105105
    106106                struct _Unwind_Exception storage;
     
    115115                }
    116116
    117                 CoroutineCtxSwitch( src, dst );
     117                $ctx_switch( src, dst );
    118118        }
    119119}
     
    123123forall(dtype T | is_coroutine(T))
    124124void prime(T& cor) {
    125         coroutine_desc* this = get_coroutine(cor);
     125        $coroutine* this = get_coroutine(cor);
    126126        assert(this->state == Start);
    127127
     
    131131
    132132[void *, size_t] __stack_alloc( size_t storageSize ) {
    133         static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
     133        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         static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment
     159        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 __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;
     189        void __cfactx_cor_leave( struct $coroutine * src ) {
     190                $coroutine * starter = src->cancellation != 0 ? src->last : src->starter;
    195191
    196192                src->state = Halted;
     
    205201                        src->name, src, starter->name, starter );
    206202
    207                 CoroutineCtxSwitch( src, starter );
     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;
    208216        }
    209217}
  • libcfa/src/concurrency/coroutine.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 21 17:49:39 2019
    13 // Update Count     : 9
     12// Last Modified On : Tue Feb  4 12:29:26 2020
     13// Update Count     : 11
    1414//
    1515
     
    2525trait is_coroutine(dtype T) {
    2626      void main(T & this);
    27       coroutine_desc * get_coroutine(T & this);
     27      $coroutine * get_coroutine(T & this);
    2828};
    2929
    30 #define DECL_COROUTINE(X) static inline coroutine_desc* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
     30#define DECL_COROUTINE(X) static inline $coroutine* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
    3131
    3232//-----------------------------------------------------------------------------
     
    3535// void ^?{}( coStack_t & this );
    3636
    37 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
    38 void ^?{}( coroutine_desc & this );
     37void  ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );
     38void ^?{}( $coroutine & this );
    3939
    40 static inline void ?{}( coroutine_desc & this)                                       { this{ "Anonymous Coroutine", NULL, 0 }; }
    41 static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", NULL, stackSize }; }
    42 static inline void ?{}( coroutine_desc & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
    43 static inline void ?{}( coroutine_desc & this, const char * name)                    { this{ name, NULL, 0 }; }
    44 static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, NULL, stackSize }; }
     40static inline void ?{}( $coroutine & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
     41static inline void ?{}( $coroutine & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
     42static inline void ?{}( $coroutine & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
     43static inline void ?{}( $coroutine & this, const char name[])                    { this{ name, 0p, 0 }; }
     44static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
    4545
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
    48 static inline void suspend(void);
    49 
    50 forall(dtype T | is_coroutine(T))
    51 static inline T & resume(T & cor);
    52 
    5348forall(dtype T | is_coroutine(T))
    5449void prime(T & cor);
    5550
    56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
     51static inline struct $coroutine * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    5752
    5853//-----------------------------------------------------------------------------
     
    6156// Start coroutine routines
    6257extern "C" {
    63       forall(dtype T | is_coroutine(T))
    64       void CtxInvokeCoroutine(T * this);
     58        void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
    6559
    66       forall(dtype T | is_coroutine(T))
    67       void CtxStart(T * this, void ( *invoke)(T *));
     60        forall(dtype T)
     61        void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
    6862
    69         extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
     63        extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
    7064
    71         extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
     65        extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
    7266}
    7367
    7468// Private wrappers for context switch and stack creation
    7569// Wrapper for co
    76 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
     70static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {
    7771        // set state of current coroutine to inactive
    78         src->state = src->state == Halted ? Halted : Inactive;
     72        src->state = src->state == Halted ? Halted : Blocked;
    7973
    8074        // set new coroutine that task is executing
     
    8377        // context switch to specified coroutine
    8478        verify( dst->context.SP );
    85         CtxSwitch( &src->context, &dst->context );
    86         // when CtxSwitch returns we are back in the src coroutine
     79        __cfactx_switch( &src->context, &dst->context );
     80        // when __cfactx_switch returns we are back in the src coroutine
    8781
    8882        // set state of new coroutine to active
    8983        src->state = Active;
    9084
    91         if( unlikely(src->cancellation != NULL) ) {
    92                 _CtxCoroutine_Unwind(src->cancellation, src);
     85        if( unlikely(src->cancellation != 0p) ) {
     86                __cfactx_coroutine_unwind(src->cancellation, src);
    9387        }
    9488}
     
    9791
    9892// Suspend implementation inlined for performance
    99 static 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;
     93extern "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;
    106101
    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 );
     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 );
    115110
    116         CoroutineCtxSwitch( src, src->last );
     111                $ctx_switch( src, src->last );
     112        }
    117113}
    118114
     
    125121        // will also migrate which means this value will
    126122        // stay in syn with the TLS
    127         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    128         coroutine_desc * dst = get_coroutine(cor);
     123        $coroutine * src = TL_GET( this_thread )->curr_cor;
     124        $coroutine * dst = get_coroutine(cor);
    129125
    130         if( unlikely(dst->context.SP == NULL) ) {
     126        if( unlikely(dst->context.SP == 0p) ) {
     127                TL_GET( this_thread )->curr_cor = dst;
    131128                __stack_prepare(&dst->stack, 65000);
    132                 CtxStart(&cor, CtxInvokeCoroutine);
     129                __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
     130                TL_GET( this_thread )->curr_cor = src;
    133131        }
    134132
     
    146144
    147145        // always done for performance testing
    148         CoroutineCtxSwitch( src, dst );
     146        $ctx_switch( src, dst );
    149147
    150148        return cor;
    151149}
    152150
    153 static inline void resume(coroutine_desc * dst) {
     151static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {
    154152        // optimization : read TLS once and reuse it
    155153        // Safety note: this is preemption safe since if
     
    157155        // will also migrate which means this value will
    158156        // stay in syn with the TLS
    159         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     157        $coroutine * src = TL_GET( this_thread )->curr_cor;
    160158
    161159        // not resuming self ?
     
    171169
    172170        // always done for performance testing
    173         CoroutineCtxSwitch( src, dst );
     171        $ctx_switch( src, dst );
    174172}
    175173
  • libcfa/src/concurrency/invoke.c

    r71d6bd8 r7030dab  
    2929// Called from the kernel when starting a coroutine or task so must switch back to user mode.
    3030
    31 extern void __suspend_internal(void);
    32 extern void __leave_coroutine( struct coroutine_desc * );
    33 extern void __finish_creation( struct thread_desc * );
    34 extern void __leave_thread_monitor( struct thread_desc * this );
     31extern struct $coroutine * __cfactx_cor_finish(void);
     32extern void __cfactx_cor_leave ( struct $coroutine * );
     33extern void __cfactx_thrd_leave();
     34
    3535extern void disable_interrupts() OPTIONAL_THREAD;
    3636extern void enable_interrupts( __cfaabi_dbg_ctx_param );
    3737
    38 void CtxInvokeCoroutine(
     38void __cfactx_invoke_coroutine(
    3939        void (*main)(void *),
    40         struct coroutine_desc *(*get_coroutine)(void *),
    4140        void *this
    4241) {
    43         struct coroutine_desc* cor = get_coroutine( this );
     42        // Finish setting up the coroutine by setting its state
     43        struct $coroutine * cor = __cfactx_cor_finish();
    4444
    45         if(cor->state == Primed) {
    46                 __suspend_internal();
    47         }
    48 
    49         cor->state = Active;
    50 
     45        // Call the main of the coroutine
    5146        main( this );
    5247
    5348        //Final suspend, should never return
    54         __leave_coroutine( cor );
     49        __cfactx_cor_leave( cor );
    5550        __cabi_abort( "Resumed dead coroutine" );
    5651}
    5752
    58 static _Unwind_Reason_Code _CtxCoroutine_UnwindStop(
     53static _Unwind_Reason_Code __cfactx_coroutine_unwindstop(
    5954        __attribute((__unused__)) int version,
    6055        _Unwind_Action actions,
     
    6762                // We finished unwinding the coroutine,
    6863                // leave it
    69                 __leave_coroutine( param );
     64                __cfactx_cor_leave( param );
    7065                __cabi_abort( "Resumed dead coroutine" );
    7166        }
     
    7570}
    7671
    77 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__));
    78 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) {
    79         _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor );
     72void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) __attribute__ ((__noreturn__));
     73void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) {
     74        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor );
    8075        printf("UNWIND ERROR %d after force unwind\n", ret);
    8176        abort();
    8277}
    8378
    84 void CtxInvokeThread(
    85         void (*dtor)(void *),
     79void __cfactx_invoke_thread(
    8680        void (*main)(void *),
    87         struct thread_desc *(*get_thread)(void *),
    8881        void *this
    8982) {
    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 
    9783        // Officially start the thread by enabling preemption
    9884        enable_interrupts( __cfaabi_dbg_ctx );
     
    10894        // The order of these 4 operations is very important
    10995        //Final suspend, should never return
    110         __leave_thread_monitor( thrd );
     96        __cfactx_thrd_leave();
    11197        __cabi_abort( "Resumed dead thread" );
    11298}
    11399
    114 
    115 void CtxStart(
     100void __cfactx_start(
    116101        void (*main)(void *),
    117         struct coroutine_desc *(*get_coroutine)(void *),
     102        struct $coroutine * cor,
    118103        void *this,
    119104        void (*invoke)(void *)
    120105) {
    121         struct coroutine_desc * cor = get_coroutine( this );
    122106        struct __stack_t * stack = cor->stack.storage;
    123107
     
    138122
    139123        fs->dummyReturn = NULL;
    140         fs->argument[0] = this;     // argument to invoke
     124        fs->argument[0] = main;     // argument to invoke
     125        fs->argument[1] = this;     // argument to invoke
    141126        fs->rturn = invoke;
    142127
     
    155140
    156141        fs->dummyReturn = NULL;
    157         fs->rturn = CtxInvokeStub;
    158         fs->fixedRegisters[0] = this;
    159         fs->fixedRegisters[1] = invoke;
     142        fs->rturn = __cfactx_invoke_stub;
     143        fs->fixedRegisters[0] = main;
     144        fs->fixedRegisters[1] = this;
     145        fs->fixedRegisters[2] = invoke;
    160146
    161147#elif defined( __ARM_ARCH )
    162 
     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)
    163149        struct FakeStack {
    164150                float fpRegs[16];                       // floating point registers
     
    172158        struct FakeStack *fs = (struct FakeStack *)cor->context.SP;
    173159
    174         fs->intRegs[8] = CtxInvokeStub;
     160        fs->intRegs[8] = __cfactx_invoke_stub;
    175161        fs->arg[0] = this;
    176162        fs->arg[1] = invoke;
  • libcfa/src/concurrency/invoke.h

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jun 22 18:19:13 2019
    13 // Update Count     : 40
     12// Last Modified On : Thu Dec  5 16:26:03 2019
     13// Update Count     : 44
    1414//
    1515
     
    4747        extern "Cforall" {
    4848                extern __attribute__((aligned(128))) thread_local struct KernelThreadData {
    49                         struct thread_desc    * volatile this_thread;
     49                        struct $thread    * volatile this_thread;
    5050                        struct processor      * volatile this_processor;
    5151
     
    9292        };
    9393
    94         enum coroutine_state { Halted, Start, Inactive, Active, Primed };
    95 
    96         struct coroutine_desc {
    97                 // context that is switch during a CtxSwitch
     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
    9899                struct __stack_context_t context;
    99100
     
    108109
    109110                // first coroutine to resume this one
    110                 struct coroutine_desc * starter;
     111                struct $coroutine * starter;
    111112
    112113                // last coroutine to resume this one
    113                 struct coroutine_desc * last;
     114                struct $coroutine * last;
    114115
    115116                // If non-null stack must be unwound with this exception
     
    117118
    118119        };
     120
     121        static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); }
    119122
    120123        // struct which calls the monitor is accepting
     
    127130        };
    128131
    129         struct monitor_desc {
     132        struct $monitor {
    130133                // spinlock to protect internal data
    131134                struct __spinlock_t lock;
    132135
    133136                // current owner of the monitor
    134                 struct thread_desc * owner;
     137                struct $thread * owner;
    135138
    136139                // queue of threads that are blocked waiting for the monitor
    137                 __queue_t(struct thread_desc) entry_queue;
     140                __queue_t(struct $thread) entry_queue;
    138141
    139142                // stack of conditions to run next once we exit the monitor
     
    152155        struct __monitor_group_t {
    153156                // currently held monitors
    154                 __cfa_anonymous_object( __small_array_t(monitor_desc*) );
     157                __cfa_anonymous_object( __small_array_t($monitor*) );
    155158
    156159                // last function that acquired monitors
     
    158161        };
    159162
    160         struct thread_desc {
     163        struct $thread {
    161164                // Core threading fields
    162                 // context that is switch during a CtxSwitch
     165                // context that is switch during a __cfactx_switch
    163166                struct __stack_context_t context;
    164167
    165168                // current execution status for coroutine
    166                 enum coroutine_state state;
     169                volatile int state;
     170                enum __Preemption_Reason preempted;
    167171
    168172                //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it
    169173
    170174                // coroutine body used to store context
    171                 struct coroutine_desc  self_cor;
     175                struct $coroutine  self_cor;
    172176
    173177                // current active context
    174                 struct coroutine_desc * curr_cor;
     178                struct $coroutine * curr_cor;
    175179
    176180                // monitor body used for mutual exclusion
    177                 struct monitor_desc    self_mon;
     181                struct $monitor    self_mon;
    178182
    179183                // pointer to monitor with sufficient lifetime for current monitors
    180                 struct monitor_desc *  self_mon_p;
     184                struct $monitor *  self_mon_p;
    181185
    182186                // pointer to the cluster on which the thread is running
     
    188192                // Link lists fields
    189193                // instrusive link field for threads
    190                 struct thread_desc * next;
     194                struct $thread * next;
    191195
    192196                struct {
    193                         struct thread_desc * next;
    194                         struct thread_desc * prev;
     197                        struct $thread * next;
     198                        struct $thread * prev;
    195199                } node;
    196         };
     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
    197217
    198218        #ifdef __cforall
    199219        extern "Cforall" {
    200                 static inline thread_desc *& get_next( thread_desc & this ) {
     220                static inline $thread *& get_next( $thread & this ) __attribute__((const)) {
    201221                        return this.next;
    202222                }
    203223
    204                 static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) {
     224                static inline [$thread *&, $thread *& ] __get( $thread & this ) __attribute__((const)) {
    205225                        return this.node.[next, prev];
    206226                }
    207227
    208228                static inline void ?{}(__monitor_group_t & this) {
    209                         (this.data){NULL};
     229                        (this.data){0p};
    210230                        (this.size){0};
    211231                        (this.func){NULL};
    212232                }
    213233
    214                 static inline void ?{}(__monitor_group_t & this, struct monitor_desc ** data, __lock_size_t size, fptr_t func) {
     234                static inline void ?{}(__monitor_group_t & this, struct $monitor ** data, __lock_size_t size, fptr_t func) {
    215235                        (this.data){data};
    216236                        (this.size){size};
     
    218238                }
    219239
    220                 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) {
     240                static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) __attribute__((const)) {
    221241                        if( (lhs.data != 0) != (rhs.data != 0) ) return false;
    222242                        if( lhs.size != rhs.size ) return false;
     
    252272
    253273        // assembler routines that performs the context switch
    254         extern void CtxInvokeStub( void );
    255         extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
     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");
    256276        // void CtxStore ( void * this ) asm ("CtxStore");
    257277        // void CtxRet   ( void * dst  ) asm ("CtxRet");
  • libcfa/src/concurrency/kernel.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun 20 17:21:23 2019
    13 // Update Count     : 25
     12// Last Modified On : Tue Feb  4 13:03:15 2020
     13// Update Count     : 58
    1414//
    1515
     
    2626#include <signal.h>
    2727#include <unistd.h>
     28#include <limits.h>                                                                             // PTHREAD_STACK_MIN
     29#include <sys/mman.h>                                                                   // mprotect
    2830}
    2931
     
    4042//-----------------------------------------------------------------------------
    4143// Some assembly required
    42 #if   defined( __i386 )
     44#if defined( __i386 )
    4345        #define CtxGet( ctx )        \
    4446                __asm__ volatile (     \
     
    108110//-----------------------------------------------------------------------------
    109111//Start and stop routine for the kernel, declared first to make sure they run first
    110 static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
    111 static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
     112static void __kernel_startup (void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     113static void __kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
     114
     115//-----------------------------------------------------------------------------
     116// Kernel Scheduling logic
     117static $thread * __next_thread(cluster * this);
     118static void __run_thread(processor * this, $thread * dst);
     119static $thread * __halt(processor * this);
     120static bool __wake_one(cluster * cltr, bool was_empty);
     121static bool __wake_proc(processor *);
    112122
    113123//-----------------------------------------------------------------------------
     
    115125KERNEL_STORAGE(cluster,         mainCluster);
    116126KERNEL_STORAGE(processor,       mainProcessor);
    117 KERNEL_STORAGE(thread_desc,     mainThread);
     127KERNEL_STORAGE($thread, mainThread);
    118128KERNEL_STORAGE(__stack_t,       mainThreadCtx);
    119129
    120130cluster     * mainCluster;
    121131processor   * mainProcessor;
    122 thread_desc * mainThread;
     132$thread * mainThread;
    123133
    124134extern "C" {
    125 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
     135        struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
    126136}
    127137
     
    131141// Global state
    132142thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = {
    133         NULL,
     143        NULL,                                                                                           // cannot use 0p
    134144        NULL,
    135145        { 1, false, false },
     
    140150// Struct to steal stack
    141151struct current_stack_info_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
     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
    146156};
    147157
     
    162172// Main thread construction
    163173
    164 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
     174void ?{}( $coroutine & this, current_stack_info_t * info) with( this ) {
    165175        stack.storage = info->storage;
    166176        with(*stack.storage) {
     
    172182        name = "Main Thread";
    173183        state = Start;
    174         starter = NULL;
    175         last = NULL;
    176         cancellation = NULL;
    177 }
    178 
    179 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
     184        starter = 0p;
     185        last = 0p;
     186        cancellation = 0p;
     187}
     188
     189void ?{}( $thread & this, current_stack_info_t * info) with( this ) {
    180190        state = Start;
    181191        self_cor{ info };
     
    185195        self_mon.recursion = 1;
    186196        self_mon_p = &self_mon;
    187         next = NULL;
    188 
    189         node.next = NULL;
    190         node.prev = NULL;
     197        next = 0p;
     198
     199        node.next = 0p;
     200        node.prev = 0p;
    191201        doregister(curr_cluster, this);
    192202
     
    206216}
    207217
    208 static void start(processor * this);
    209 void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
     218static void * __invoke_processor(void * arg);
     219
     220void ?{}(processor & this, const char name[], cluster & cltr) with( this ) {
    210221        this.name = name;
    211222        this.cltr = &cltr;
    212223        terminated{ 0 };
     224        destroyer = 0p;
    213225        do_terminate = false;
    214         preemption_alarm = NULL;
     226        preemption_alarm = 0p;
    215227        pending_preemption = false;
    216228        runner.proc = &this;
    217229
    218         idleLock{};
    219 
    220         start( &this );
     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);
    221237}
    222238
     
    226242
    227243                __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
    228                 wake( &this );
     244                __wake_proc( &this );
    229245
    230246                P( terminated );
     
    232248        }
    233249
    234         pthread_join( kernel_thread, NULL );
    235 }
    236 
    237 void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {
     250        pthread_join( kernel_thread, 0p );
     251        free( this.stack );
     252}
     253
     254void ?{}(cluster & this, const char name[], Duration preemption_rate) with( this ) {
    238255        this.name = name;
    239256        this.preemption_rate = preemption_rate;
     
    255272// Kernel Scheduling logic
    256273//=============================================================================================
    257 static void runThread(processor * this, thread_desc * dst);
    258 static void finishRunning(processor * this);
    259 static void halt(processor * this);
    260 
    261274//Main of the processor contexts
    262275void main(processorCtx_t & runner) {
     
    278291                __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
    279292
    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;
     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);
    297302                        }
    298                         else
    299                         {
    300                                 // spin(this, &spin_count);
    301                                 halt(this);
     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 );
    302314                        }
    303315                }
     
    311323
    312324        __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;
    313330}
    314331
     
    319336// runThread runs a thread by context switching
    320337// from the processor coroutine to the target thread
    321 static 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;
     338static void __run_thread(processor * this, $thread * thrd_dst) {
     339        $coroutine * proc_cor = get_coroutine(this->runner);
    326340
    327341        // Update global state
    328342        kernelTLS.this_thread = thrd_dst;
    329343
    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;
     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;
     356                }
     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;
     388                }
     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);
     413                }
     414        }
     415
     416        // Just before returning to the processor, set the processor coroutine to active
    341417        proc_cor->state = Active;
     418        kernelTLS.this_thread = 0p;
    342419}
    343420
    344421// KERNEL_ONLY
    345 static 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
    375 static 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] );
    390                 }
    391         case Release_Multi_Schedule:
    392                 for(int i = 0; i < lock_count; i++) {
    393                         unlock( *locks[i] );
    394                 }
    395                 for(int i = 0; i < thrd_count; i++) {
    396                         ScheduleThread( thrds[i] );
    397                 }
    398         case Callback:
    399                 callback();
    400         default:
    401                 abort("KERNEL ERROR: Unexpected action to run after thread");
    402         }
     422void 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 );
    403444}
    404445
     
    407448// This is the entry point for processors (kernel threads)
    408449// It effectively constructs a coroutine by stealing the pthread stack
    409 static void * CtxInvokeProcessor(void * arg) {
     450static void * __invoke_processor(void * arg) {
    410451        processor * proc = (processor *) arg;
    411452        kernelTLS.this_processor = proc;
    412         kernelTLS.this_thread    = NULL;
     453        kernelTLS.this_thread    = 0p;
    413454        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
    414455        // SKULLDUGGERY: We want to create a context for the processor coroutine
     
    423464
    424465        //Set global state
    425         kernelTLS.this_thread    = NULL;
     466        kernelTLS.this_thread = 0p;
    426467
    427468        //We now have a proper context from which to schedule threads
     
    439480        __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);
    440481
    441         return NULL;
    442 }
    443 
    444 static 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);
     482        return 0p;
     483}
     484
     485static 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
     491void * __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;
    450517}
    451518
    452519// KERNEL_ONLY
    453 void kernel_first_resume( processor * this ) {
    454         thread_desc * src = mainThread;
    455         coroutine_desc * dst = get_coroutine(this->runner);
     520static void __kernel_first_resume( processor * this ) {
     521        $thread * src = mainThread;
     522        $coroutine * dst = get_coroutine(this->runner);
    456523
    457524        verify( ! kernelTLS.preemption_state.enabled );
    458525
     526        kernelTLS.this_thread->curr_cor = dst;
    459527        __stack_prepare( &dst->stack, 65000 );
    460         CtxStart(&this->runner, CtxInvokeCoroutine);
     528        __cfactx_start(main, dst, this->runner, __cfactx_invoke_coroutine);
    461529
    462530        verify( ! kernelTLS.preemption_state.enabled );
     
    465533        dst->starter = dst->starter ? dst->starter : &src->self_cor;
    466534
    467         // set state of current coroutine to inactive
    468         src->state = src->state == Halted ? Halted : Inactive;
     535        // make sure the current state is still correct
     536        /* paranoid */ verify(src->state == Ready);
    469537
    470538        // context switch to specified coroutine
    471539        verify( dst->context.SP );
    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;
     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);
    477547
    478548        verify( ! kernelTLS.preemption_state.enabled );
     
    480550
    481551// KERNEL_ONLY
    482 void kernel_last_resume( processor * this ) {
    483         coroutine_desc * src = &mainThread->self_cor;
    484         coroutine_desc * dst = get_coroutine(this->runner);
     552static void __kernel_last_resume( processor * this ) {
     553        $coroutine * src = &mainThread->self_cor;
     554        $coroutine * dst = get_coroutine(this->runner);
    485555
    486556        verify( ! kernelTLS.preemption_state.enabled );
     
    488558        verify( dst->context.SP );
    489559
     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
    490572        // context switch to the processor
    491         CtxSwitch( &src->context, &dst->context );
     573        __cfactx_switch( &src->context, &dst->context );
    492574}
    493575
    494576//-----------------------------------------------------------------------------
    495577// Scheduler routines
    496 
    497578// KERNEL ONLY
    498 void 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 );
     579void __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 );
     594        unlock( ready_queue_lock );
     595
     596        __wake_one(thrd->curr_cluster, was_empty);
     597
     598        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    526599}
    527600
    528601// KERNEL ONLY
    529 thread_desc * nextThread(cluster * this) with( *this ) {
    530         verify( ! kernelTLS.preemption_state.enabled );
     602static $thread * __next_thread(cluster * this) with( *this ) {
     603        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     604
    531605        lock( ready_queue_lock __cfaabi_dbg_ctx2 );
    532         thread_desc * head = pop_head( ready_queue );
     606        $thread * head = pop_head( ready_queue );
    533607        unlock( ready_queue_lock );
    534         verify( ! kernelTLS.preemption_state.enabled );
     608
     609        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    535610        return head;
    536611}
    537612
    538 void BlockInternal() {
     613void unpark( $thread * thrd __cfaabi_dbg_ctx_param2 ) {
     614        if( !thrd ) return;
     615
    539616        disable_interrupts();
    540         verify( ! kernelTLS.preemption_state.enabled );
     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
     648void 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 );
     656
    541657        returnToKernel();
    542         verify( ! kernelTLS.preemption_state.enabled );
     658
     659        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    543660        enable_interrupts( __cfaabi_dbg_ctx );
    544 }
    545 
    546 void BlockInternal( __spinlock_t * lock ) {
     661        /* paranoid */ verify( kernelTLS.preemption_state.enabled );
     662
     663}
     664
     665// KERNEL ONLY
     666void __leave_thread() {
     667        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     668        returnToKernel();
     669        abort();
     670}
     671
     672// KERNEL ONLY
     673bool force_yield( __Preemption_Reason reason ) {
     674        /* paranoid */ verify( kernelTLS.preemption_state.enabled );
    547675        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 
    560 void 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 
    574 void 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 
    590 void 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 
    605 void 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 
    622 void 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 );
    634 }
    635 
    636 // KERNEL ONLY
    637 void 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         }
    644 
    645         returnToKernel();
     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;
    646697}
    647698
     
    651702//-----------------------------------------------------------------------------
    652703// Kernel boot procedures
    653 static void kernel_startup(void) {
     704static void __kernel_startup(void) {
    654705        verify( ! kernelTLS.preemption_state.enabled );
    655706        __cfaabi_dbg_print_safe("Kernel : Starting\n");
     
    669720        // SKULLDUGGERY: the mainThread steals the process main thread
    670721        // which will then be scheduled by the mainProcessor normally
    671         mainThread = (thread_desc *)&storage_mainThread;
     722        mainThread = ($thread *)&storage_mainThread;
    672723        current_stack_info_t info;
    673724        info.storage = (__stack_t*)&storage_mainThreadCtx;
     
    681732        void ?{}(processorCtx_t & this, processor * proc) {
    682733                (this.__cor){ "Processor" };
    683                 this.__cor.starter = NULL;
     734                this.__cor.starter = 0p;
    684735                this.proc = proc;
    685736        }
     
    690741                terminated{ 0 };
    691742                do_terminate = false;
    692                 preemption_alarm = NULL;
     743                preemption_alarm = 0p;
    693744                pending_preemption = false;
    694745                kernel_thread = pthread_self();
     
    712763        // Add the main thread to the ready queue
    713764        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    714         ScheduleThread(mainThread);
     765        __schedule_thread(mainThread);
    715766
    716767        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
    717         // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
     768        // context. Hence, the main thread does not begin through __cfactx_invoke_thread, like all other threads. The trick here is that
    718769        // mainThread is on the ready queue when this call is made.
    719         kernel_first_resume( kernelTLS.this_processor );
     770        __kernel_first_resume( kernelTLS.this_processor );
    720771
    721772
     
    729780}
    730781
    731 static void kernel_shutdown(void) {
     782static void __kernel_shutdown(void) {
    732783        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
    733784
    734         verify( TL_GET( preemption_state.enabled ) );
     785        /* paranoid */ verify( TL_GET( preemption_state.enabled ) );
    735786        disable_interrupts();
    736         verify( ! kernelTLS.preemption_state.enabled );
     787        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    737788
    738789        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
     
    740791        // which is currently here
    741792        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
    742         kernel_last_resume( kernelTLS.this_processor );
     793        __kernel_last_resume( kernelTLS.this_processor );
    743794        mainThread->self_cor.state = Halted;
    744795
     
    750801        // Destroy the main processor and its context in reverse order of construction
    751802        // These were manually constructed so we need manually destroy them
    752         ^(mainProcessor->runner){};
    753         ^(mainProcessor){};
     803        ^(*mainProcessor){};
    754804
    755805        // Final step, destroy the main thread since it is no longer needed
    756806        // Since we provided a stack to this taxk it will not destroy anything
    757         ^(mainThread){};
     807        /* paranoid */ verify(mainThread->self_cor.stack.storage == (__stack_t*)(((uintptr_t)&storage_mainThreadCtx)| 0x1));
     808        ^(*mainThread){};
    758809
    759810        ^(__cfa_dbg_global_clusters.list){};
     
    764815
    765816//=============================================================================================
    766 // Kernel Quiescing
     817// Kernel Idle Sleep
    767818//=============================================================================================
    768 static void halt(processor * this) with( *this ) {
    769         // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    770 
     819static $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
     838        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
     839        wait( idle );
     840
     841        // We have woken up
     842        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
     843
     844        // Get ourself off the idle list
    771845        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 
    778         __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
    779 
    780         wait( idleLock );
    781 
    782         __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
    783 
    784         with( *cltr ) {
    785                 lock      (proc_list_lock __cfaabi_dbg_ctx2);
    786                 remove    (idles, *this);
    787                 push_front(procs, *this);
    788                 unlock    (proc_list_lock);
    789         }
     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
     856static 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
     879static bool __wake_proc(processor * this) {
     880        return post( this->idle );
    790881}
    791882
     
    808899                sigemptyset( &mask );
    809900                sigaddset( &mask, SIGALRM );            // block SIGALRM signals
    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
     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
    812904        }
    813905        else {
     
    820912
    821913void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
    822         thread_desc * thrd = kernel_data;
     914        $thread * thrd = kernel_data;
    823915
    824916        if(thrd) {
    825917                int len = snprintf( abort_text, abort_text_size, "Error occurred while executing thread %.256s (%p)", thrd->self_cor.name, thrd );
    826                 __cfaabi_dbg_bits_write( abort_text, len );
     918                __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    827919
    828920                if ( &thrd->self_cor != thrd->curr_cor ) {
    829921                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
    830                         __cfaabi_dbg_bits_write( abort_text, len );
     922                        __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    831923                }
    832924                else {
    833                         __cfaabi_dbg_bits_write( ".\n", 2 );
     925                        __cfaabi_bits_write( STDERR_FILENO, ".\n", 2 );
    834926                }
    835927        }
    836928        else {
    837929                int len = snprintf( abort_text, abort_text_size, "Error occurred outside of any thread.\n" );
    838                 __cfaabi_dbg_bits_write( abort_text, len );
     930                __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
    839931        }
    840932}
     
    847939
    848940extern "C" {
    849         void __cfaabi_dbg_bits_acquire() {
     941        void __cfaabi_bits_acquire() {
    850942                lock( kernel_debug_lock __cfaabi_dbg_ctx2 );
    851943        }
    852944
    853         void __cfaabi_dbg_bits_release() {
     945        void __cfaabi_bits_release() {
    854946                unlock( kernel_debug_lock );
    855947        }
     
    876968
    877969                // atomically release spin lock and block
    878                 BlockInternal( &lock );
     970                unlock( lock );
     971                park( __cfaabi_dbg_ctx );
    879972        }
    880973        else {
     
    883976}
    884977
    885 void V(semaphore & this) with( this ) {
    886         thread_desc * thrd = NULL;
     978bool V(semaphore & this) with( this ) {
     979        $thread * thrd = 0p;
    887980        lock( lock __cfaabi_dbg_ctx2 );
    888981        count += 1;
     
    895988
    896989        // make new owner
    897         WakeThread( thrd );
     990        unpark( thrd __cfaabi_dbg_ctx2 );
     991
     992        return thrd != 0p;
    898993}
    899994
     
    9121007}
    9131008
    914 void doregister( cluster * cltr, thread_desc & thrd ) {
     1009void doregister( cluster * cltr, $thread & thrd ) {
    9151010        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    9161011        cltr->nthreads += 1;
     
    9191014}
    9201015
    921 void unregister( cluster * cltr, thread_desc & thrd ) {
     1016void unregister( cluster * cltr, $thread & thrd ) {
    9221017        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    9231018        remove(cltr->threads, thrd );
     
    9271022
    9281023void doregister( cluster * cltr, processor * proc ) {
    929         lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     1024        lock      (cltr->idle_lock __cfaabi_dbg_ctx2);
    9301025        cltr->nprocessors += 1;
    9311026        push_front(cltr->procs, *proc);
    932         unlock    (cltr->proc_list_lock);
     1027        unlock    (cltr->idle_lock);
    9331028}
    9341029
    9351030void unregister( cluster * cltr, processor * proc ) {
    936         lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     1031        lock  (cltr->idle_lock __cfaabi_dbg_ctx2);
    9371032        remove(cltr->procs, *proc );
    9381033        cltr->nprocessors -= 1;
    939         unlock(cltr->proc_list_lock);
     1034        unlock(cltr->idle_lock);
    9401035}
    9411036
     
    9441039__cfaabi_dbg_debug_do(
    9451040        extern "C" {
    946                 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
     1041                void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]) {
    9471042                        this.prev_name = prev_name;
    9481043                        this.prev_thrd = kernelTLS.this_thread;
    9491044                }
     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                }
    9501056        }
    9511057)
     
    9531059//-----------------------------------------------------------------------------
    9541060// Debug
    955 bool threading_enabled(void) {
     1061bool threading_enabled(void) __attribute__((const)) {
    9561062        return true;
    9571063}
  • libcfa/src/concurrency/kernel.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jun 22 11:39:17 2019
    13 // Update Count     : 16
     12// Last Modified On : Tue Feb  4 12:29:26 2020
     13// Update Count     : 22
    1414//
    1515
     
    2020#include "invoke.h"
    2121#include "time_t.hfa"
     22#include "coroutine.hfa"
    2223
    2324extern "C" {
     
    3132        __spinlock_t lock;
    3233        int count;
    33         __queue_t(thread_desc) waiting;
     34        __queue_t($thread) waiting;
    3435};
    3536
     
    3738void ^?{}(semaphore & this);
    3839void   P (semaphore & this);
    39 void   V (semaphore & this);
     40bool   V (semaphore & this);
    4041
    4142
     
    4344// Processor
    4445extern struct cluster * mainCluster;
    45 
    46 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback };
    47 
    48 typedef void (*__finish_callback_fptr_t)(void);
    49 
    50 //TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI)
    51 struct 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 };
    88 static inline void ?{}(FinishAction & this) {
    89         this.action_code = No_Action;
    90         this.thrd = NULL;
    91         this.lock = NULL;
    92 }
    93 static inline void ^?{}(FinishAction &) {}
    9446
    9547// Processor
     
    11567        // RunThread data
    11668        // Action to do after a thread is ran
    117         struct FinishAction finish;
     69        $thread * destroyer;
    11870
    11971        // Preemption data
     
    12476        bool pending_preemption;
    12577
    126         // Idle lock
    127         __bin_sem_t idleLock;
     78        // Idle lock (kernel semaphore)
     79        __bin_sem_t idle;
    12880
    12981        // Termination
     
    13183        volatile bool do_terminate;
    13284
    133         // Termination synchronisation
     85        // Termination synchronisation (user semaphore)
    13486        semaphore terminated;
     87
     88        // pthread Stack
     89        void * stack;
    13590
    13691        // Link lists fields
     
    146101};
    147102
    148 void  ?{}(processor & this, const char * name, struct cluster & cltr);
     103void  ?{}(processor & this, const char name[], struct cluster & cltr);
    149104void ^?{}(processor & this);
    150105
    151106static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
    152107static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
    153 static inline void  ?{}(processor & this, const char * name) { this{name, *mainCluster }; }
     108static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    154109
    155 static inline [processor *&, processor *& ] __get( processor & this ) {
    156         return this.node.[next, prev];
    157 }
     110static inline [processor *&, processor *& ] __get( processor & this ) __attribute__((const)) { return this.node.[next, prev]; }
    158111
    159112//-----------------------------------------------------------------------------
     
    164117
    165118        // Ready queue for threads
    166         __queue_t(thread_desc) ready_queue;
     119        __queue_t($thread) ready_queue;
    167120
    168121        // Name of the cluster
     
    173126
    174127        // List of processors
    175         __spinlock_t proc_list_lock;
     128        __spinlock_t idle_lock;
    176129        __dllist_t(struct processor) procs;
    177130        __dllist_t(struct processor) idles;
     
    180133        // List of threads
    181134        __spinlock_t thread_list_lock;
    182         __dllist_t(struct thread_desc) threads;
     135        __dllist_t(struct $thread) threads;
    183136        unsigned int nthreads;
    184137
     
    191144extern Duration default_preemption();
    192145
    193 void ?{} (cluster & this, const char * name, Duration preemption_rate);
     146void ?{} (cluster & this, const char name[], Duration preemption_rate);
    194147void ^?{}(cluster & this);
    195148
    196149static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
    197150static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
    198 static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
     151static inline void ?{} (cluster & this, const char name[])        { this{name, default_preemption()}; }
    199152
    200 static inline [cluster *&, cluster *& ] __get( cluster & this ) {
    201         return this.node.[next, prev];
    202 }
     153static inline [cluster *&, cluster *& ] __get( cluster & this ) __attribute__((const)) { return this.node.[next, prev]; }
    203154
    204155static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE
  • libcfa/src/concurrency/kernel_private.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Feb 13 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 29 14:06:40 2018
    13 // Update Count     : 3
     12// Last Modified On : Sat Nov 30 19:25:02 2019
     13// Update Count     : 8
    1414//
    1515
     
    3131}
    3232
    33 void ScheduleThread( thread_desc * );
    34 static 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 }
    43 thread_desc * nextThread(cluster * this);
     33void __schedule_thread( $thread * ) __attribute__((nonnull (1)));
    4434
    4535//Block current thread and release/wake-up the following resources
    46 void BlockInternal(void);
    47 void BlockInternal(__spinlock_t * lock);
    48 void BlockInternal(thread_desc * thrd);
    49 void BlockInternal(__spinlock_t * lock, thread_desc * thrd);
    50 void BlockInternal(__spinlock_t * locks [], unsigned short count);
    51 void BlockInternal(__spinlock_t * locks [], unsigned short count, thread_desc * thrds [], unsigned short thrd_count);
    52 void BlockInternal(__finish_callback_fptr_t callback);
    53 void LeaveThread(__spinlock_t * lock, thread_desc * thrd);
     36void __leave_thread() __attribute__((noreturn));
    5437
    5538//-----------------------------------------------------------------------------
     
    5740void main(processorCtx_t *);
    5841
    59 static inline void wake_fast(processor * this) {
    60         __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
    61         post( this->idleLock );
    62 }
     42void * __create_pthread( pthread_t *, void * (*)(void *), void * );
    6343
    64 static inline void wake(processor * this) {
    65         disable_interrupts();
    66         wake_fast(this);
    67         enable_interrupts( __cfaabi_dbg_ctx );
    68 }
     44
    6945
    7046struct event_kernel_t {
     
    8662// Threads
    8763extern "C" {
    88       forall(dtype T | is_thread(T))
    89       void CtxInvokeThread(T * this);
     64      void __cfactx_invoke_thread(void (*main)(void *), void * this);
    9065}
    9166
    92 extern void ThreadCtxSwitch(coroutine_desc * src, coroutine_desc * dst);
    93 
    9467__cfaabi_dbg_debug_do(
    95         extern void __cfaabi_dbg_thread_register  ( thread_desc * thrd );
    96         extern void __cfaabi_dbg_thread_unregister( thread_desc * thrd );
     68        extern void __cfaabi_dbg_thread_register  ( $thread * thrd );
     69        extern void __cfaabi_dbg_thread_unregister( $thread * thrd );
    9770)
    9871
     
    10174#define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)]
    10275
    103 static inline uint32_t tls_rand() {
     76static inline uint32_t __tls_rand() {
    10477        kernelTLS.rand_seed ^= kernelTLS.rand_seed << 6;
    10578        kernelTLS.rand_seed ^= kernelTLS.rand_seed >> 21;
     
    11285void unregister( struct cluster & cltr );
    11386
    114 void doregister( struct cluster * cltr, struct thread_desc & thrd );
    115 void unregister( struct cluster * cltr, struct thread_desc & thrd );
     87void doregister( struct cluster * cltr, struct $thread & thrd );
     88void unregister( struct cluster * cltr, struct $thread & thrd );
    11689
    11790void doregister( struct cluster * cltr, struct processor * proc );
  • libcfa/src/concurrency/monitor.cfa

    r71d6bd8 r7030dab  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // monitor_desc.c --
     7// $monitor.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 : Fri Mar 30 14:30:26 2018
    13 // Update Count     : 9
     12// Last Modified On : Wed Dec  4 07:55:14 2019
     13// Update Count     : 10
    1414//
    1515
     
    2727//-----------------------------------------------------------------------------
    2828// Forward declarations
    29 static inline void set_owner ( monitor_desc * this, thread_desc * owner );
    30 static inline void set_owner ( monitor_desc * storage [], __lock_size_t count, thread_desc * owner );
    31 static inline void set_mask  ( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask );
    32 static inline void reset_mask( monitor_desc * this );
    33 
    34 static inline thread_desc * next_thread( monitor_desc * this );
    35 static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & monitors );
     29static inline void __set_owner ( $monitor * this, $thread * owner );
     30static inline void __set_owner ( $monitor * storage [], __lock_size_t count, $thread * owner );
     31static inline void set_mask  ( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask );
     32static inline void reset_mask( $monitor * this );
     33
     34static inline $thread * next_thread( $monitor * this );
     35static inline bool is_accepted( $monitor * 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_desc * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count );
     38static inline void lock_all  ( $monitor * 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_desc * locks [], __lock_size_t count );
    41 
    42 static inline void save   ( monitor_desc * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );
    43 static inline void restore( monitor_desc * 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_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    46 static inline void init_push( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
    47 
    48 static inline thread_desc *        check_condition   ( __condition_criterion_t * );
     40static inline void unlock_all( $monitor * locks [], __lock_size_t count );
     41
     42static inline void save   ( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );
     43static inline void restore( $monitor * 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 * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     46static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );
     47
     48static inline $thread *        check_condition   ( __condition_criterion_t * );
    4949static inline void                 brand_condition   ( condition & );
    50 static inline [thread_desc *, int] search_entry_queue( const __waitfor_mask_t &, monitor_desc * monitors [], __lock_size_t count );
     50static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t &, $monitor * 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_desc * storage [], const __waitfor_mask_t & mask );
     55static inline __lock_size_t aggregate    ( $monitor * 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_desc ** monitors = mons;                          /* Save the targeted monitors                                                          */ \
     70        $monitor ** 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 
    83 
    84 extern "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                 }
     82// Enter single monitor
     83static 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 );
    128122
    129123                __cfaabi_dbg_print_safe( "Kernel : %10p Entered  mon %p\n", thrd, this);
    130124
    131                 // Release the lock and leave
     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
     139static 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
    132156                unlock( this->lock );
    133157                return;
    134158        }
    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;
     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
     182                unlock( this->lock );
     183
     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
     218void __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
     253void __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);
    153257                }
    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 );
     258                if( this->recursion != 1 ) {
     259                        abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
    158260                }
    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
    224                 unlock( this->lock );
    225 
    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 
     261        )
     262}
     263
     264extern "C" {
    242265        // Leave the thread monitor
    243266        // last routine called by a thread.
    244267        // Should never return
    245         void __leave_thread_monitor( thread_desc * thrd ) {
    246                 monitor_desc * this = &thrd->self_mon;
     268        void __cfactx_thrd_leave() {
     269                $thread * thrd = TL_GET( this_thread );
     270                $monitor * this = &thrd->self_mon;
    247271
    248272                // Lock the monitor now
     
    251275                disable_interrupts();
    252276
    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 );
     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 );
    256280
    257281                // Leaving a recursion level, decrement the counter
     
    263287
    264288                // Fetch the next thread, can be null
    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 );
     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();
    271304
    272305                // Control flow should never reach here!
     
    278311static inline void enter( __monitor_group_t monitors ) {
    279312        for( __lock_size_t i = 0; i < monitors.size; i++) {
    280                 __enter_monitor_desc( monitors[i], monitors );
     313                __enter( monitors[i], monitors );
    281314        }
    282315}
     
    284317// Leave multiple monitor
    285318// relies on the monitor array being sorted
    286 static inline void leave(monitor_desc * monitors [], __lock_size_t count) {
     319static inline void leave($monitor * monitors [], __lock_size_t count) {
    287320        for( __lock_size_t i = count - 1; i >= 0; i--) {
    288                 __leave_monitor_desc( monitors[i] );
     321                __leave( monitors[i] );
    289322        }
    290323}
     
    292325// Ctor for monitor guard
    293326// Sorts monitors before entering
    294 void ?{}( monitor_guard_t & this, monitor_desc * m [], __lock_size_t count, fptr_t func ) {
    295         thread_desc * thrd = TL_GET( this_thread );
     327void ?{}( monitor_guard_t & this, $monitor * m [], __lock_size_t count, fptr_t func ) {
     328        $thread * thrd = TL_GET( this_thread );
    296329
    297330        // Store current array
     
    333366// Ctor for monitor guard
    334367// Sorts monitors before entering
    335 void ?{}( monitor_dtor_guard_t & this, monitor_desc * m [], fptr_t func ) {
     368void ?{}( monitor_dtor_guard_t & this, $monitor * m [], fptr_t func ) {
    336369        // optimization
    337         thread_desc * thrd = TL_GET( this_thread );
     370        $thread * thrd = TL_GET( this_thread );
    338371
    339372        // Store current array
     
    346379        (thrd->monitors){m, 1, func};
    347380
    348         __enter_monitor_dtor( this.m, func );
     381        __dtor_enter( this.m, func );
    349382}
    350383
     
    352385void ^?{}( monitor_dtor_guard_t & this ) {
    353386        // Leave the monitors in order
    354         __leave_dtor_monitor_desc( this.m );
     387        __dtor_leave( this.m );
    355388
    356389        // Restore thread context
     
    360393//-----------------------------------------------------------------------------
    361394// Internal scheduling types
    362 void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
     395void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info ) {
    363396        this.waiting_thread = waiting_thread;
    364397        this.count = count;
    365         this.next = NULL;
     398        this.next = 0p;
    366399        this.user_info = user_info;
    367400}
     
    369402void ?{}(__condition_criterion_t & this ) with( this ) {
    370403        ready  = false;
    371         target = NULL;
    372         owner  = NULL;
    373         next   = NULL;
    374 }
    375 
    376 void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t & owner ) {
     404        target = 0p;
     405        owner  = 0p;
     406        next   = 0p;
     407}
     408
     409void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t & owner ) {
    377410        this.ready  = false;
    378411        this.target = target;
    379412        this.owner  = &owner;
    380         this.next   = NULL;
     413        this.next   = 0p;
    381414}
    382415
     
    387420
    388421        // Check that everything is as expected
    389         assertf( this.monitors != NULL, "Waiting with no monitors (%p)", this.monitors );
     422        assertf( this.monitors != 0p, "Waiting with no monitors (%p)", this.monitors );
    390423        verifyf( this.monitor_count != 0, "Waiting with 0 monitors (%"PRIiFAST16")", this.monitor_count );
    391424        verifyf( this.monitor_count < 32u, "Excessive monitor count (%"PRIiFAST16")", this.monitor_count );
     
    399432        // Append the current wait operation to the ones already queued on the condition
    400433        // We don't need locks for that since conditions must always be waited on inside monitor mutual exclusion
     434        /* paranoid */ verify( waiter.next == 0p );
    401435        append( this.blocked, &waiter );
     436        /* paranoid */ verify( waiter.next == 1p );
    402437
    403438        // Lock all monitors (aggregates the locks as well)
     
    406441        // Find the next thread(s) to run
    407442        __lock_size_t thread_count = 0;
    408         thread_desc * threads[ count ];
     443        $thread * threads[ count ];
    409444        __builtin_memset( threads, 0, sizeof( threads ) );
    410445
     
    414449        // Remove any duplicate threads
    415450        for( __lock_size_t i = 0; i < count; i++) {
    416                 thread_desc * new_owner = next_thread( monitors[i] );
     451                $thread * new_owner = next_thread( monitors[i] );
    417452                insert_unique( threads, thread_count, new_owner );
    418453        }
    419454
     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
    420465        // Everything is ready to go to sleep
    421         BlockInternal( locks, count, threads, thread_count );
     466        park( __cfaabi_dbg_ctx );
    422467
    423468        // We are back, restore the owners and recursions
     
    434479        //Some more checking in debug
    435480        __cfaabi_dbg_debug_do(
    436                 thread_desc * this_thrd = TL_GET( this_thread );
     481                $thread * this_thrd = TL_GET( this_thread );
    437482                if ( this.monitor_count != this_thrd->monitors.size ) {
    438483                        abort( "Signal on condition %p made with different number of monitor(s), expected %zi got %zi", &this, this.monitor_count, this_thrd->monitors.size );
     
    449494
    450495        // Lock all monitors
    451         lock_all( this.monitors, NULL, count );
     496        lock_all( this.monitors, 0p, count );
    452497
    453498        //Pop the head of the waiting queue
     
    471516
    472517        //Check that everything is as expected
    473         verifyf( this.monitors != NULL, "Waiting with no monitors (%p)", this.monitors );
     518        verifyf( this.monitors != 0p, "Waiting with no monitors (%p)", this.monitors );
    474519        verifyf( this.monitor_count != 0, "Waiting with 0 monitors (%"PRIiFAST16")", this.monitor_count );
    475520
     
    488533
    489534        //Find the thread to run
    490         thread_desc * signallee = pop_head( this.blocked )->waiting_thread;
    491         set_owner( monitors, count, signallee );
     535        $thread * signallee = pop_head( this.blocked )->waiting_thread;
     536        __set_owner( monitors, count, signallee );
    492537
    493538        __cfaabi_dbg_print_buffer_decl( "Kernel : signal_block condition %p (s: %p)\n", &this, signallee );
    494539
     540        // unlock all the monitors
     541        unlock_all( locks, count );
     542
     543        // unpark the thread we signalled
     544        unpark( signallee __cfaabi_dbg_ctx2 );
     545
    495546        //Everything is ready to go to sleep
    496         BlockInternal( locks, count, &signallee, 1 );
     547        park( __cfaabi_dbg_ctx );
    497548
    498549
     
    535586        // Create one!
    536587        __lock_size_t max = count_max( mask );
    537         monitor_desc * mon_storage[max];
     588        $monitor * mon_storage[max];
    538589        __builtin_memset( mon_storage, 0, sizeof( mon_storage ) );
    539590        __lock_size_t actual_count = aggregate( mon_storage, mask );
     
    553604        {
    554605                // Check if the entry queue
    555                 thread_desc * next; int index;
     606                $thread * next; int index;
    556607                [next, index] = search_entry_queue( mask, monitors, count );
    557608
     
    563614                                verifyf( accepted.size == 1,  "ERROR: Accepted dtor has more than 1 mutex parameter." );
    564615
    565                                 monitor_desc * mon2dtor = accepted[0];
     616                                $monitor * mon2dtor = accepted[0];
    566617                                verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." );
    567618
     
    589640
    590641                                // Set the owners to be the next thread
    591                                 set_owner( monitors, count, next );
    592 
    593                                 // Everything is ready to go to sleep
    594                                 BlockInternal( locks, count, &next, 1 );
     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 );
    595652
    596653                                // We are back, restore the owners and recursions
     
    630687        }
    631688
     689        // unlock all the monitors
     690        unlock_all( locks, count );
     691
    632692        //Everything is ready to go to sleep
    633         BlockInternal( locks, count );
     693        park( __cfaabi_dbg_ctx );
    634694
    635695
     
    648708// Utilities
    649709
    650 static 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 );
     710static inline void __set_owner( $monitor * this, $thread * owner ) {
     711        /* paranoid */ verify( this->lock.lock );
    652712
    653713        //Pass the monitor appropriately
     
    658718}
    659719
    660 static inline void set_owner( monitor_desc * monitors [], __lock_size_t count, thread_desc * owner ) {
    661         monitors[0]->owner     = owner;
    662         monitors[0]->recursion = 1;
     720static 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;
    663725        for( __lock_size_t i = 1; i < count; i++ ) {
    664                 monitors[i]->owner     = owner;
    665                 monitors[i]->recursion = 0;
    666         }
    667 }
    668 
    669 static inline void set_mask( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) {
     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
     733static inline void set_mask( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) {
    670734        for( __lock_size_t i = 0; i < count; i++) {
    671735                storage[i]->mask = mask;
     
    673737}
    674738
    675 static inline void reset_mask( monitor_desc * this ) {
    676         this->mask.accepted = NULL;
    677         this->mask.data = NULL;
     739static inline void reset_mask( $monitor * this ) {
     740        this->mask.accepted = 0p;
     741        this->mask.data = 0p;
    678742        this->mask.size = 0;
    679743}
    680744
    681 static inline thread_desc * next_thread( monitor_desc * this ) {
     745static inline $thread * next_thread( $monitor * this ) {
    682746        //Check the signaller stack
    683747        __cfaabi_dbg_print_safe( "Kernel :  mon %p AS-stack top %p\n", this, this->signal_stack.top);
     
    687751                //regardless of if we are ready to baton pass,
    688752                //we need to set the monitor as in use
    689                 set_owner( this,  urgent->owner->waiting_thread );
     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 );
    690755
    691756                return check_condition( urgent );
     
    694759        // No signaller thread
    695760        // Get the next thread in the entry_queue
    696         thread_desc * new_owner = pop_head( this->entry_queue );
    697         set_owner( this, new_owner );
     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 );
    698765
    699766        return new_owner;
    700767}
    701768
    702 static inline bool is_accepted( monitor_desc * this, const __monitor_group_t & group ) {
     769static inline bool is_accepted( $monitor * this, const __monitor_group_t & group ) {
    703770        __acceptable_t * it = this->mask.data; // Optim
    704771        __lock_size_t count = this->mask.size;
     
    722789}
    723790
    724 static inline void init( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
     791static inline void init( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
    725792        for( __lock_size_t i = 0; i < count; i++) {
    726793                (criteria[i]){ monitors[i], waiter };
     
    730797}
    731798
    732 static inline void init_push( __lock_size_t count, monitor_desc * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
     799static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {
    733800        for( __lock_size_t i = 0; i < count; i++) {
    734801                (criteria[i]){ monitors[i], waiter };
     
    746813}
    747814
    748 static inline void lock_all( monitor_desc * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {
     815static inline void lock_all( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {
    749816        for( __lock_size_t i = 0; i < count; i++ ) {
    750817                __spinlock_t * l = &source[i]->lock;
     
    760827}
    761828
    762 static inline void unlock_all( monitor_desc * locks [], __lock_size_t count ) {
     829static inline void unlock_all( $monitor * locks [], __lock_size_t count ) {
    763830        for( __lock_size_t i = 0; i < count; i++ ) {
    764831                unlock( locks[i]->lock );
     
    767834
    768835static inline void save(
    769         monitor_desc * ctx [],
     836        $monitor * ctx [],
    770837        __lock_size_t count,
    771838        __attribute((unused)) __spinlock_t * locks [],
     
    780847
    781848static inline void restore(
    782         monitor_desc * ctx [],
     849        $monitor * ctx [],
    783850        __lock_size_t count,
    784851        __spinlock_t * locks [],
     
    798865// 2 - Checks if all the monitors are ready to run
    799866//     if so return the thread to run
    800 static inline thread_desc * check_condition( __condition_criterion_t * target ) {
     867static inline $thread * check_condition( __condition_criterion_t * target ) {
    801868        __condition_node_t * node = target->owner;
    802869        unsigned short count = node->count;
     
    816883        }
    817884
    818         __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : NULL );
    819         return ready2run ? node->waiting_thread : NULL;
     885        __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : 0p );
     886        return ready2run ? node->waiting_thread : 0p;
    820887}
    821888
    822889static inline void brand_condition( condition & this ) {
    823         thread_desc * thrd = TL_GET( this_thread );
     890        $thread * thrd = TL_GET( this_thread );
    824891        if( !this.monitors ) {
    825892                // __cfaabi_dbg_print_safe( "Branding\n" );
    826                 assertf( thrd->monitors.data != NULL, "No current monitor to brand condition %p", thrd->monitors.data );
     893                assertf( thrd->monitors.data != 0p, "No current monitor to brand condition %p", thrd->monitors.data );
    827894                this.monitor_count = thrd->monitors.size;
    828895
    829                 this.monitors = (monitor_desc **)malloc( this.monitor_count * sizeof( *this.monitors ) );
     896                this.monitors = ($monitor **)malloc( this.monitor_count * sizeof( *this.monitors ) );
    830897                for( int i = 0; i < this.monitor_count; i++ ) {
    831898                        this.monitors[i] = thrd->monitors[i];
     
    834901}
    835902
    836 static 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;
     903static 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;
    839906
    840907        // For each thread in the entry-queue
    841         for(    thread_desc ** thrd_it = &entry_queue.head;
    842                 *thrd_it;
     908        for(    $thread ** thrd_it = &entry_queue.head;
     909                *thrd_it != 1p;
    843910                thrd_it = &(*thrd_it)->next
    844911        ) {
     
    883950}
    884951
    885 static inline __lock_size_t aggregate( monitor_desc * storage [], const __waitfor_mask_t & mask ) {
     952static inline __lock_size_t aggregate( $monitor * storage [], const __waitfor_mask_t & mask ) {
    886953        __lock_size_t size = 0;
    887954        for( __lock_size_t i = 0; i < mask.size; i++ ) {
  • libcfa/src/concurrency/monitor.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct  7 18:06:45 2017
    13 // Update Count     : 10
     12// Last Modified On : Wed Dec  4 07:55:32 2019
     13// Update Count     : 11
    1414//
    1515
     
    2323
    2424trait is_monitor(dtype T) {
    25         monitor_desc * get_monitor( T & );
     25        $monitor * get_monitor( T & );
    2626        void ^?{}( T & mutex );
    2727};
    2828
    29 static inline void ?{}(monitor_desc & this) with( this ) {
     29static inline void ?{}($monitor & this) with( this ) {
    3030        lock{};
    3131        entry_queue{};
    3232        signal_stack{};
    33         owner         = NULL;
     33        owner         = 0p;
    3434        recursion     = 0;
    35         mask.accepted = NULL;
    36         mask.data     = NULL;
     35        mask.accepted = 0p;
     36        mask.data     = 0p;
    3737        mask.size     = 0;
    38         dtor_node     = NULL;
     38        dtor_node     = 0p;
    3939}
    4040
     41static inline void ^?{}($monitor & ) {}
     42
    4143struct monitor_guard_t {
    42         monitor_desc **         m;
     44        $monitor **     m;
    4345        __lock_size_t           count;
    4446        __monitor_group_t prev;
    4547};
    4648
    47 void ?{}( monitor_guard_t & this, monitor_desc ** m, __lock_size_t count, void (*func)() );
     49void ?{}( monitor_guard_t & this, $monitor ** m, __lock_size_t count, void (*func)() );
    4850void ^?{}( monitor_guard_t & this );
    4951
    5052struct monitor_dtor_guard_t {
    51         monitor_desc *    m;
     53        $monitor *    m;
    5254        __monitor_group_t prev;
    5355};
    5456
    55 void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, void (*func)() );
     57void ?{}( monitor_dtor_guard_t & this, $monitor ** m, void (*func)() );
    5658void ^?{}( monitor_dtor_guard_t & this );
    5759
     
    7072
    7173        // The monitor this criterion concerns
    72         monitor_desc * target;
     74        $monitor * target;
    7375
    7476        // The parent node to which this criterion belongs
     
    8587struct __condition_node_t {
    8688        // Thread that needs to be woken when all criteria are met
    87         thread_desc * waiting_thread;
     89        $thread * waiting_thread;
    8890
    8991        // Array of criteria (Criterions are contiguous in memory)
     
    104106}
    105107
    106 void ?{}(__condition_node_t & this, thread_desc * waiting_thread, __lock_size_t count, uintptr_t user_info );
     108void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info );
    107109void ?{}(__condition_criterion_t & this );
    108 void ?{}(__condition_criterion_t & this, monitor_desc * target, __condition_node_t * owner );
     110void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t * owner );
    109111
    110112struct condition {
     
    113115
    114116        // Array of monitor pointers (Monitors are NOT contiguous in memory)
    115         monitor_desc ** monitors;
     117        $monitor ** monitors;
    116118
    117119        // Number of monitors in the array
     
    120122
    121123static inline void ?{}( condition & this ) {
    122         this.monitors = NULL;
     124        this.monitors = 0p;
    123125        this.monitor_count = 0;
    124126}
     
    131133              bool signal      ( condition & this );
    132134              bool signal_block( condition & this );
    133 static inline bool is_empty    ( condition & this ) { return !this.blocked.head; }
     135static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
    134136         uintptr_t front       ( condition & this );
    135137
  • libcfa/src/concurrency/mutex.cfa

    r71d6bd8 r7030dab  
    1111// Author           : Thierry Delisle
    1212// Created On       : Fri May 25 01:37:11 2018
    13 // Last Modified By : Thierry Delisle
    14 // Last Modified On : Fri May 25 01:37:51 2018
    15 // Update Count     : 0
     13// Last Modified By : Peter A. Buhr
     14// Last Modified On : Wed Dec  4 09:16:39 2019
     15// Update Count     : 1
    1616//
    1717
     
    4040        if( is_locked ) {
    4141                append( blocked_threads, kernelTLS.this_thread );
    42                 BlockInternal( &lock );
     42                unlock( lock );
     43                park( __cfaabi_dbg_ctx );
    4344        }
    4445        else {
     
    6263        lock( this.lock __cfaabi_dbg_ctx2 );
    6364        this.is_locked = (this.blocked_threads != 0);
    64         WakeThread(
    65                 pop_head( this.blocked_threads )
     65        unpark(
     66                pop_head( this.blocked_threads ) __cfaabi_dbg_ctx2
    6667        );
    6768        unlock( this.lock );
     
    7374        this.lock{};
    7475        this.blocked_threads{};
    75         this.owner = NULL;
     76        this.owner = 0p;
    7677        this.recursion_count = 0;
    7778}
     
    8384void lock(recursive_mutex_lock & this) with(this) {
    8485        lock( lock __cfaabi_dbg_ctx2 );
    85         if( owner == NULL ) {
     86        if( owner == 0p ) {
    8687                owner = kernelTLS.this_thread;
    8788                recursion_count = 1;
     
    9495        else {
    9596                append( blocked_threads, kernelTLS.this_thread );
    96                 BlockInternal( &lock );
     97                unlock( lock );
     98                park( __cfaabi_dbg_ctx );
    9799        }
    98100}
     
    101103        bool ret = false;
    102104        lock( lock __cfaabi_dbg_ctx2 );
    103         if( owner == NULL ) {
     105        if( owner == 0p ) {
    104106                owner = kernelTLS.this_thread;
    105107                recursion_count = 1;
     
    118120        recursion_count--;
    119121        if( recursion_count == 0 ) {
    120                 thread_desc * thrd = pop_head( blocked_threads );
     122                $thread * thrd = pop_head( blocked_threads );
    121123                owner = thrd;
    122124                recursion_count = (thrd ? 1 : 0);
    123                 WakeThread( thrd );
     125                unpark( thrd __cfaabi_dbg_ctx2 );
    124126        }
    125127        unlock( lock );
     
    138140void notify_one(condition_variable & this) with(this) {
    139141        lock( lock __cfaabi_dbg_ctx2 );
    140         WakeThread(
    141                 pop_head( this.blocked_threads )
     142        unpark(
     143                pop_head( this.blocked_threads ) __cfaabi_dbg_ctx2
    142144        );
    143145        unlock( lock );
     
    147149        lock( lock __cfaabi_dbg_ctx2 );
    148150        while(this.blocked_threads) {
    149                 WakeThread(
    150                         pop_head( this.blocked_threads )
     151                unpark(
     152                        pop_head( this.blocked_threads ) __cfaabi_dbg_ctx2
    151153                );
    152154        }
     
    157159        lock( this.lock __cfaabi_dbg_ctx2 );
    158160        append( this.blocked_threads, kernelTLS.this_thread );
    159         BlockInternal( &this.lock );
     161        unlock( this.lock );
     162        park( __cfaabi_dbg_ctx );
    160163}
    161164
     
    164167        lock( this.lock __cfaabi_dbg_ctx2 );
    165168        append( this.blocked_threads, kernelTLS.this_thread );
    166         void __unlock(void) {
    167                 unlock(l);
    168                 unlock(this.lock);
    169         }
    170         BlockInternal( __unlock );
     169        unlock(l);
     170        unlock(this.lock);
     171        park( __cfaabi_dbg_ctx );
    171172        lock(l);
    172173}
  • libcfa/src/concurrency/mutex.hfa

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jun  5 17:35:49 2018
    13 // Update Count     : 37
     12// Last Modified On : Thu Dec  5 16:34:05 2019
     13// Update Count     : 43
    1414//
    1515
     
    2424#include <string.h>
    2525#include <unistd.h>
     26#include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2627}
    2728
     
    3839// FwdDeclarations : timeout handlers
    3940static void preempt( processor   * this );
    40 static void timeout( thread_desc * this );
     41static void timeout( $thread * this );
    4142
    4243// FwdDeclarations : Signal handlers
     
    6465event_kernel_t * event_kernel;                        // kernel public handle to even kernel
    6566static pthread_t alarm_thread;                        // pthread handle to alarm thread
     67static void * alarm_stack;                                                        // pthread stack for alarm thread
    6668
    6769static void ?{}(event_kernel_t & this) with( this ) {
     
    8183// Get next expired node
    8284static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) {
    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
     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
    8688}
    8789
    8890// Tick one frame of the Discrete Event Simulation for alarms
    8991static void tick_preemption() {
    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"
     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"
    9395
    9496        //Loop throught every thing expired
     
    182184
    183185        // Enable interrupts by decrementing the counter
    184         // If counter reaches 0, execute any pending CtxSwitch
     186        // If counter reaches 0, execute any pending __cfactx_switch
    185187        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    186188                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
    188189
    189190                with( kernelTLS.preemption_state ){
     
    207208                                if( proc->pending_preemption ) {
    208209                                        proc->pending_preemption = false;
    209                                         BlockInternal( thrd );
     210                                        force_yield( __POLL_PREEMPTION );
    210211                                }
    211212                        }
     
    217218
    218219        // Disable interrupts by incrementint the counter
    219         // Don't execute any pending CtxSwitch even if counter reaches 0
     220        // Don't execute any pending __cfactx_switch even if counter reaches 0
    220221        void enable_interrupts_noPoll() {
    221222                unsigned short prev = kernelTLS.preemption_state.disable_count;
     
    243244        sigaddset( &mask, sig );
    244245
    245         if ( pthread_sigmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
     246        if ( pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {
    246247            abort( "internal error, pthread_sigmask" );
    247248        }
     
    254255        sigaddset( &mask, sig );
    255256
    256         if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
     257        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    257258            abort( "internal error, pthread_sigmask" );
    258259        }
     
    266267
    267268// reserved for future use
    268 static void timeout( thread_desc * this ) {
     269static void timeout( $thread * this ) {
    269270        //TODO : implement waking threads
    270271}
    271272
    272273// KERNEL ONLY
    273 // Check if a CtxSwitch signal handler shoud defer
     274// Check if a __cfactx_switch signal handler shoud defer
    274275// If true  : preemption is safe
    275276// If false : preemption is unsafe and marked as pending
     
    301302
    302303        // Setup proper signal handlers
    303         __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART );         // CtxSwitch handler
     304        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
    304305
    305306        signal_block( SIGALRM );
    306307
    307         pthread_create( &alarm_thread, NULL, alarm_loop, NULL );
     308        alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p );
    308309}
    309310
     
    316317        sigset_t mask;
    317318        sigfillset( &mask );
    318         sigprocmask( SIG_BLOCK, &mask, NULL );
     319        sigprocmask( SIG_BLOCK, &mask, 0p );
    319320
    320321        // Notify the alarm thread of the shutdown
     
    323324
    324325        // Wait for the preemption thread to finish
    325         pthread_join( alarm_thread, NULL );
     326
     327        pthread_join( alarm_thread, 0p );
     328        free( alarm_stack );
    326329
    327330        // Preemption is now fully stopped
     
    380383        static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" );
    381384        #endif
    382         if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), NULL ) == -1 ) {
     385        if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {
    383386                abort( "internal error, sigprocmask" );
    384387        }
     
    390393        // Preemption can occur here
    391394
    392         BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch
     395        force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch
    393396}
    394397
     
    399402        sigset_t mask;
    400403        sigfillset(&mask);
    401         if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
     404        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    402405            abort( "internal error, pthread_sigmask" );
    403406        }
     
    420423                                        {__cfaabi_dbg_print_buffer_decl( " KERNEL: Spurious wakeup %d.\n", err );}
    421424                                        continue;
    422                         case EINVAL :
     425                                case EINVAL :
    423426                                        abort( "Timeout was invalid." );
    424427                                default:
     
    453456EXIT:
    454457        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    455         return NULL;
     458        return 0p;
    456459}
    457460
     
    466469        sigset_t oldset;
    467470        int ret;
    468         ret = pthread_sigmask(0, NULL, &oldset);
     471        ret = pthread_sigmask(0, 0p, &oldset);
    469472        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    470473
  • libcfa/src/concurrency/thread.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 30 17:19:52 2018
    13 // Update Count     : 8
     12// Last Modified On : Wed Dec  4 09:17:49 2019
     13// Update Count     : 9
    1414//
    1515
     
    2323#include "invoke.h"
    2424
    25 extern "C" {
    26         #include <fenv.h>
    27         #include <stddef.h>
    28 }
    29 
    30 //extern volatile thread_local processor * this_processor;
    31 
    3225//-----------------------------------------------------------------------------
    3326// Thread ctors and dtors
    34 void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
    35         context{ NULL, NULL };
     27void ?{}($thread & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
     28        context{ 0p, 0p };
    3629        self_cor{ name, storage, storageSize };
    3730        state = Start;
     31        preempted = __NO_PREEMPTION;
    3832        curr_cor = &self_cor;
    3933        self_mon.owner = &this;
     
    4135        self_mon_p = &self_mon;
    4236        curr_cluster = &cl;
    43         next = NULL;
     37        next = 0p;
    4438
    45         node.next = NULL;
    46         node.prev = NULL;
     39        node.next = 0p;
     40        node.prev = 0p;
    4741        doregister(curr_cluster, this);
    4842
     
    5044}
    5145
    52 void ^?{}(thread_desc& this) with( this ) {
     46void ^?{}($thread& this) with( this ) {
    5347        unregister(curr_cluster, this);
    5448        ^self_cor{};
    5549}
    5650
     51//-----------------------------------------------------------------------------
     52// Starting and stopping threads
     53forall( dtype T | is_thread(T) )
     54void __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
    5769forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } )
    5870void ?{}( scoped(T)& this ) with( this ) {
    5971        handle{};
    60         __thrd_start(handle);
     72        __thrd_start(handle, main);
    6173}
    6274
     
    6476void ?{}( scoped(T)& this, P params ) with( this ) {
    6577        handle{ params };
    66         __thrd_start(handle);
     78        __thrd_start(handle, main);
    6779}
    6880
     
    7284}
    7385
    74 //-----------------------------------------------------------------------------
    75 // Starting and stopping threads
    76 forall( dtype T | is_thread(T) )
    77 void __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 
    91 extern "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 
    102 void 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 
    110 void yield( unsigned times ) {
    111         for( unsigned i = 0; i < times; i++ ) {
    112                 yield();
    113         }
    114 }
    115 
    11686// Local Variables: //
    11787// mode: c //
  • libcfa/src/concurrency/thread.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 21 17:51:33 2019
    13 // Update Count     : 5
     12// Last Modified On : Wed Dec  4 09:18:14 2019
     13// Update Count     : 6
    1414//
    1515
     
    2828      void ^?{}(T& mutex this);
    2929      void main(T& this);
    30       thread_desc* get_thread(T& this);
     30      $thread* get_thread(T& this);
    3131};
    3232
    33 #define DECL_THREAD(X) thread_desc* get_thread(X& this) { return &this.__thrd; } void main(X& this)
     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
     37forall( dtype T | is_thread(T) )
     38static inline $coroutine* get_coroutine(T & this) __attribute__((const)) { return &get_thread(this)->self_cor; }
    3439
    3540forall( dtype T | is_thread(T) )
    36 static inline coroutine_desc* get_coroutine(T & this) {
    37         return &get_thread(this)->self_cor;
    38 }
     41static inline $monitor  * get_monitor  (T & this) __attribute__((const)) { return &get_thread(this)->self_mon; }
    3942
    40 forall( dtype T | is_thread(T) )
    41 static inline monitor_desc* get_monitor(T & this) {
    42         return &get_thread(this)->self_mon;
    43 }
     43static inline $coroutine* get_coroutine($thread * this) __attribute__((const)) { return &this->self_cor; }
     44static inline $monitor  * get_monitor  ($thread * this) __attribute__((const)) { return &this->self_mon; }
    4445
    45 static inline coroutine_desc* get_coroutine(thread_desc * this) {
    46         return &this->self_cor;
    47 }
    48 
    49 static inline monitor_desc* get_monitor(thread_desc * this) {
    50         return &this->self_mon;
    51 }
    52 
     46//-----------------------------------------------------------------------------
     47// forward declarations needed for threads
    5348extern struct cluster * mainCluster;
    5449
    5550forall( dtype T | is_thread(T) )
    56 void __thrd_start( T & this );
     51void __thrd_start( T & this, void (*)(T &) );
    5752
    5853//-----------------------------------------------------------------------------
    5954// Ctors and dtors
    60 void ?{}(thread_desc & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );
    61 void ^?{}(thread_desc & this);
     55void ?{}($thread & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );
     56void ^?{}($thread & this);
    6257
    63 static inline void ?{}(thread_desc & this)                                                                  { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; }
    64 static inline void ?{}(thread_desc & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, NULL, stackSize }; }
    65 static inline void ?{}(thread_desc & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
    66 static inline void ?{}(thread_desc & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, NULL, 65000 }; }
    67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, NULL, stackSize }; }
    68 static inline void ?{}(thread_desc & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
    69 static inline void ?{}(thread_desc & this, const char * const name)                                         { this{ name, *mainCluster, NULL, 65000 }; }
    70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl )                   { this{ name, cl, NULL, 65000 }; }
    71 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, NULL, stackSize }; }
     58static inline void ?{}($thread & this)                                                                  { this{ "Anonymous Thread", *mainCluster, 0p, 65000 }; }
     59static inline void ?{}($thread & this, size_t stackSize )                                               { this{ "Anonymous Thread", *mainCluster, 0p, stackSize }; }
     60static inline void ?{}($thread & this, void * storage, size_t storageSize )                             { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; }
     61static inline void ?{}($thread & this, struct cluster & cl )                                            { this{ "Anonymous Thread", cl, 0p, 65000 }; }
     62static inline void ?{}($thread & this, struct cluster & cl, size_t stackSize )                          { this{ "Anonymous Thread", cl, 0p, stackSize }; }
     63static inline void ?{}($thread & this, struct cluster & cl, void * storage, size_t storageSize )        { this{ "Anonymous Thread", cl, storage, storageSize }; }
     64static inline void ?{}($thread & this, const char * const name)                                         { this{ name, *mainCluster, 0p, 65000 }; }
     65static inline void ?{}($thread & this, const char * const name, struct cluster & cl )                   { this{ name, cl, 0p, 65000 }; }
     66static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; }
    7267
    7368//-----------------------------------------------------------------------------
     
    8883void ^?{}( scoped(T)& this );
    8984
    90 void yield();
    91 void yield( unsigned times );
     85//-----------------------------------------------------------------------------
     86// Thread getters
     87static inline struct $thread * active_thread () { return TL_GET( this_thread ); }
    9288
    93 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); }
     89//-----------------------------------------------------------------------------
     90// Scheduler API
     91
     92//----------
     93// Park thread: block until corresponding call to unpark, won't block if unpark is already called
     94void 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
     99void unpark( $thread * this __cfaabi_dbg_ctx_param2 );
     100
     101forall( dtype T | is_thread(T) )
     102static 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
     106bool force_yield( enum __Preemption_Reason );
     107
     108static inline void yield() {
     109        force_yield(__MANUAL_PREEMPTION);
     110}
     111
     112// Yield: yield N times
     113static inline void yield( unsigned times ) {
     114        for( times ) {
     115                yield();
     116        }
     117}
    94118
    95119// Local Variables: //
  • libcfa/src/exception.c

    r71d6bd8 r7030dab  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:13:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 22 18:17:34 2018
    13 // Update Count     : 11
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Apr 03 11:57:00 2020
     13// Update Count     : 14
    1414//
    1515
     16// Normally we would get this from the CFA prelude.
    1617#include <stddef.h> // for size_t
    1718
    1819#include "exception.h"
    1920
    20 // Implementation of the secret header.
     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
    2125
    2226#include <stdlib.h>
     
    2731// FIX ME: temporary hack to keep ARM build working
    2832#ifndef _URC_FATAL_PHASE1_ERROR
    29 #define _URC_FATAL_PHASE1_ERROR 2
     33#define _URC_FATAL_PHASE1_ERROR 3
    3034#endif // ! _URC_FATAL_PHASE1_ERROR
    3135#ifndef _URC_FATAL_PHASE2_ERROR
     
    3539#include "lsda.h"
    3640
     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 */
     46const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    3747
    3848// Base exception vtable is abstract, you should not have base exceptions.
    39 struct __cfaabi_ehm__base_exception_t_vtable
    40                 ___cfaabi_ehm__base_exception_t_vtable_instance = {
     49struct __cfaehm_base_exception_t_vtable
     50                ___cfaehm_base_exception_t_vtable_instance = {
    4151        .parent = NULL,
    4252        .size = 0,
     
    4959// Temperary global exception context. Does not work with concurency.
    5060struct exception_context_t {
    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};
     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};
    5766
    5867// Get the current exception context.
     
    6271        return &shared_stack;
    6372}
    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))
    7673
    7774
    7875// RESUMPTION ================================================================
    7976
    80 void __cfaabi_ehm__throw_resume(exception_t * except) {
     77void __cfaehm_throw_resume(exception_t * except) {
     78        struct exception_context_t * context = this_exception_context();
    8179
    8280        __cfaabi_dbg_print_safe("Throwing resumption exception\n");
    8381
    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;
     82        struct __cfaehm_try_resume_node * original_head = context->top_resume;
     83        struct __cfaehm_try_resume_node * current = context->top_resume;
    8784
    8885        for ( ; current ; current = current->next) {
    89                 shared_stack.current_resume = current;
     86                context->top_resume = current->next;
    9087                if (current->handler(except)) {
    91                         shared_stack.current_resume = original_head;
     88                        context->top_resume = original_head;
    9289                        return;
    9390                }
     
    9592
    9693        __cfaabi_dbg_print_safe("Unhandled exception\n");
    97         shared_stack.current_resume = original_head;
     94        context->top_resume = original_head;
    9895
    9996        // Fall back to termination:
    100         __cfaabi_ehm__throw_terminate(except);
     97        __cfaehm_throw_terminate(except);
    10198        // TODO: Default handler for resumption.
    10299}
    103100
    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 
    107 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
     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
     105void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node,
    108106                        _Bool (*handler)(exception_t * except)) {
    109         node->next = shared_stack.top_resume;
     107        struct exception_context_t * context = this_exception_context();
     108        node->next = context->top_resume;
    110109        node->handler = handler;
    111         shared_stack.top_resume = node;
    112 }
    113 
    114 void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) {
    115         shared_stack.top_resume = node->next;
     110        context->top_resume = node;
     111}
     112
     113void __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;
    116116}
    117117
     
    122122// May have to move to cfa for constructors and destructors (references).
    123123
    124 struct __cfaabi_ehm__node {
    125         struct __cfaabi_ehm__node * next;
     124// How to clean up an exception in various situations.
     125static 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.
     140static struct _Unwind_Exception this_exception_storage;
     141
     142struct __cfaehm_node {
     143        struct __cfaehm_node * next;
    126144};
    127145
    128146#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    129 #define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1)
     147#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    130148
    131149// Creates a copy of the indicated exception and sets current_exception to it.
    132 static void __cfaabi_ehm__allocate_exception( exception_t * except ) {
     150static void __cfaehm_allocate_exception( exception_t * except ) {
    133151        struct exception_context_t * context = this_exception_context();
    134152
    135153        // Allocate memory for the exception.
    136         struct __cfaabi_ehm__node * store = malloc(
    137                 sizeof( struct __cfaabi_ehm__node ) + except->virtual_table->size );
     154        struct __cfaehm_node * store = malloc(
     155                sizeof( struct __cfaehm_node ) + except->virtual_table->size );
    138156
    139157        if ( ! store ) {
     
    148166        // Copy the exception to storage.
    149167        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;
    150172}
    151173
    152174// Delete the provided exception, unsetting current_exception if relivant.
    153 static void __cfaabi_ehm__delete_exception( exception_t * except ) {
     175static void __cfaehm_delete_exception( exception_t * except ) {
    154176        struct exception_context_t * context = this_exception_context();
    155177
     
    157179
    158180        // Remove the exception from the list.
    159         struct __cfaabi_ehm__node * to_free = EXCEPT_TO_NODE(except);
    160         struct __cfaabi_ehm__node * node;
     181        struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except);
     182        struct __cfaehm_node * node;
    161183
    162184        if ( context->current_exception == except ) {
     
    166188                node = EXCEPT_TO_NODE(context->current_exception);
    167189                // It may always be in the first or second position.
    168                 while( to_free != node->next ) {
     190                while ( to_free != node->next ) {
    169191                        node = node->next;
    170192                }
     
    178200
    179201// If this isn't a rethrow (*except==0), delete the provided exception.
    180 void __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
    186 struct _Unwind_Exception this_exception_storage;
     202void __cfaehm_cleanup_terminate( void * except ) {
     203        if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except );
     204}
    187205
    188206// Function needed by force unwind
     
    191209                int version,
    192210                _Unwind_Action actions,
    193                 _Unwind_Exception_Class exceptionClass,
     211                _Unwind_Exception_Class exception_class,
    194212                struct _Unwind_Exception * unwind_exception,
    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;
     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;
    199217
    200218        return _URC_FATAL_PHASE2_ERROR;
     
    202220
    203221// The exception that is being thrown must already be stored.
    204 __attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) {
     222static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) {
    205223        if ( ! this_exception_context()->current_exception ) {
    206224                printf("UNWIND ERROR missing exception in begin unwind\n");
     
    208226        }
    209227
    210 
    211228        // Call stdlibc to raise the exception
    212229        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    213230
    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.
     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.
    223241                printf("Uncaught exception %p\n", &this_exception_storage);
    224242
     
    228246        }
    229247
    230         // We did not simply reach the end of the stack without finding a handler.  Something wen't wrong
     248        // We did not simply reach the end of the stack without finding a handler. This is an error.
    231249        printf("UNWIND ERROR %d after raise exception\n", ret);
    232250        abort();
    233251}
    234252
    235 void __cfaabi_ehm__throw_terminate( exception_t * val ) {
     253void __cfaehm_throw_terminate( exception_t * val ) {
    236254        __cfaabi_dbg_print_safe("Throwing termination exception\n");
    237255
    238         __cfaabi_ehm__allocate_exception( val );
    239         __cfaabi_ehm__begin_unwind();
    240 }
    241 
    242 void __cfaabi_ehm__rethrow_terminate(void) {
     256        __cfaehm_allocate_exception( val );
     257        __cfaehm_begin_unwind();
     258}
     259
     260void __cfaehm_rethrow_terminate(void) {
    243261        __cfaabi_dbg_print_safe("Rethrowing termination exception\n");
    244262
    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))
    251 void __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)
     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)
    263275{
    264276
    265277        //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    266         __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
     278        __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
     279                        version, actions, exception_class, unwind_exception, unwind_context);
    267280
    268281        // If we've reached the end of the stack then there is nothing much we can do...
    269         if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
     282        if (actions & _UA_END_OF_STACK) return _URC_END_OF_STACK;
    270283
    271284        if (actions & _UA_SEARCH_PHASE) {
     
    282295
    283296        // Get a pointer to the language specific data from which we will read what we need
    284         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    285 
    286         if( !lsd ) {    //Nothing to do, keep unwinding
     297        const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context );
     298
     299        if ( !lsd ) {   //Nothing to do, keep unwinding
    287300                printf(" no LSD");
    288301                goto UNWIND;
     
    291304        // Get the instuction pointer and a reading pointer into the exception table
    292305        lsda_header_info lsd_info;
    293         const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
    294         _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
     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();
    295310
    296311        // Linearly search the table for stuff to do
    297         while( cur_ptr < lsd_info.action_table ) {
     312        while ( cur_ptr < lsd_info.action_table ) {
    298313                _Unwind_Ptr callsite_start;
    299314                _Unwind_Ptr callsite_len;
     
    302317
    303318                // Decode the common stuff we have in here
    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);
     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);
    308323
    309324                // Have we reach the correct frame info yet?
    310                 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     325                if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    311326#ifdef __CFA_DEBUG_PRINT__
    312327                        void * ls = (void*)lsd_info.Start;
     
    316331                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    317332                        void * ip = (void*)instruction_ptr;
    318                         __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
     333                        __cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
     334                                        bp, ep, ls, cs, cl, ip);
    319335#endif // __CFA_DEBUG_PRINT__
    320336                        continue;
    321337                }
    322338
    323                 // Have we gone too far
    324                 if( lsd_info.Start + callsite_start > instruction_ptr ) {
     339                // Have we gone too far?
     340                if ( lsd_info.Start + callsite_start > instruction_ptr ) {
    325341                        printf(" gone too far");
    326342                        break;
    327343                }
    328344
    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;
     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");
    373389                                }
    374 
    375                                 // This is only a cleanup handler, ignore it
    376                                 __cfaabi_dbg_print_safe(" no action");
     390                                return ret;
    377391                        }
    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;
     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;
    400403                        }
     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;
    401420                }
    402 
    403                 // Nothing to do, move along
    404                 __cfaabi_dbg_print_safe(" no landing pad");
    405421        }
    406422        // No handling found
     
    414430}
    415431
    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
     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
    418437__attribute__((noinline))
    419 void __cfaabi_ehm__try_terminate(void (*try_block)(),
     438void __cfaehm_try_terminate(void (*try_block)(),
    420439                void (*catch_block)(int index, exception_t * except),
    421440                __attribute__((unused)) int (*match_block)(exception_t * except)) {
     
    423442        //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy);
    424443
    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
     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
    431452        asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
    432         // Setup the exception table
    433453        asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
     454#endif
    434455
    435456        // Label which defines the start of the area for which the handler is setup.
     
    442463        asm volatile goto ("" : : : : CATCH );
    443464
    444         // Normal return
     465        // Normal return for when there is no throw.
    445466        return;
    446467
     
    449470        // Label which defines the end of the area for which the handler is setup.
    450471        asm volatile (".TRYEND:");
    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.
     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.
    454475        asm volatile (".CATCH:");
    455476
    456477        // Exception handler
    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 )
     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__
    465488asm (
    466         //HEADER
     489        // HEADER
    467490        ".LFECFA1:\n"
    468491        "       .globl  __gcfa_personality_v0\n"
    469492        "       .section        .gcc_except_table,\"a\",@progbits\n"
    470         ".LLSDACFA2:\n"                                                 //TABLE header
     493        // TABLE HEADER (important field is the BODY length at the end)
     494        ".LLSDACFA2:\n"
    471495        "       .byte   0xff\n"
    472496        "       .byte   0xff\n"
    473497        "       .byte   0x1\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"
     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"
     512);
     513
     514// Somehow this piece of helps with the resolution of debug symbols.
     515__attribute__((unused)) static const int dummy = 0;
     516
     517asm (
     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__
     534asm (
     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"
    484559        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    485 //      "       .section        .note.GNU-stack,\"x\",@progbits\n"
     560        "       .section        .note.GNU-stack,\"x\",@progbits\n"
    486561);
    487 #endif // __i386 || __x86_64
    488 #endif //PIC
     562#endif // __PIC__
     563
     564#pragma GCC pop_options
  • libcfa/src/exception.h

    r71d6bd8 r7030dab  
    99// Author           : Andrew Beach
    1010// Created On       : Mon Jun 26 15:11:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 22 18:11:15 2018
    13 // Update Count     : 8
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Mar 27 10:16:00 2020
     13// Update Count     : 9
    1414//
    1515
     
    2121#endif
    2222
    23 struct __cfaabi_ehm__base_exception_t;
    24 typedef struct __cfaabi_ehm__base_exception_t exception_t;
    25 struct __cfaabi_ehm__base_exception_t_vtable {
    26         const struct __cfaabi_ehm__base_exception_t_vtable * parent;
     23struct __cfaehm_base_exception_t;
     24typedef struct __cfaehm_base_exception_t exception_t;
     25struct __cfaehm_base_exception_t_vtable {
     26        const struct __cfaehm_base_exception_t_vtable * parent;
    2727        size_t size;
    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);
     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);
    3232};
    33 struct __cfaabi_ehm__base_exception_t {
    34         struct __cfaabi_ehm__base_exception_t_vtable const * virtual_table;
     33struct __cfaehm_base_exception_t {
     34        struct __cfaehm_base_exception_t_vtable const * virtual_table;
    3535};
    36 extern struct __cfaabi_ehm__base_exception_t_vtable
    37         ___cfaabi_ehm__base_exception_t_vtable_instance;
     36extern struct __cfaehm_base_exception_t_vtable
     37        ___cfaehm_base_exception_t_vtable_instance;
    3838
    3939
    4040// Used in throw statement translation.
    41 void __cfaabi_ehm__throw_terminate(exception_t * except) __attribute__((noreturn));
    42 void __cfaabi_ehm__rethrow_terminate() __attribute__((noreturn));
    43 void __cfaabi_ehm__throw_resume(exception_t * except);
     41void __cfaehm_throw_terminate(exception_t * except) __attribute__((noreturn));
     42void __cfaehm_rethrow_terminate() __attribute__((noreturn));
     43void __cfaehm_throw_resume(exception_t * except);
    4444
    4545// Function catches termination exceptions.
    46 void __cfaabi_ehm__try_terminate(
     46void __cfaehm_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 __cfaabi_ehm__cleanup_terminate(void * except);
     52void __cfaehm_cleanup_terminate(void * except);
    5353
    5454// Data structure creates a list of resume handlers.
    55 struct __cfaabi_ehm__try_resume_node {
    56     struct __cfaabi_ehm__try_resume_node * next;
     55struct __cfaehm_try_resume_node {
     56    struct __cfaehm_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 __cfaabi_ehm__try_resume_setup(
    62     struct __cfaabi_ehm__try_resume_node * node,
     61void __cfaehm_try_resume_setup(
     62    struct __cfaehm_try_resume_node * node,
    6363    _Bool (*handler)(exception_t * except));
    64 void __cfaabi_ehm__try_resume_cleanup(
    65     struct __cfaabi_ehm__try_resume_node * node);
     64void __cfaehm_try_resume_cleanup(
     65    struct __cfaehm_try_resume_node * node);
    6666
    6767// Check for a standard way to call fake deconstructors.
    68 struct __cfaabi_ehm__cleanup_hook {};
     68struct __cfaehm_cleanup_hook {};
    6969
    7070#ifdef __cforall
  • libcfa/src/executor.cfa

    r71d6bd8 r7030dab  
    88#include <stdio.h>
    99
    10 forall( 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 
     10forall( dtype T )
     11monitor Buffer {                                        // unbounded buffer
     12    __queue_t( T ) queue;                               // unbounded list of work requests
     13    condition delay;
     14}; // Buffer
     15forall( dtype T | is_node(T) ) {
    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 ) wait( delay );                   // no request to process ? => wait
    23         return pop_head( queue );
     22        if ( queue.head != 0 ) wait( delay );                   // no request to process ? => wait
     23//      return pop_head( queue );
    2424    } // remove
    2525} // distribution
  • libcfa/src/fstream.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Sep 10 22:19:56 2019
    13 // Update Count     : 354
     12// Last Modified On : Fri Feb  7 19:01:01 2020
     13// Update Count     : 363
    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;
     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 ) );
    4041        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 = 0; }
    59 
    60 void ?{}( ofstream & os, const char * name, const char * mode ) {
     58void ?{}( ofstream & os ) { os.$file = 0p; }
     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 sepOn( ofstream & os ) { os.sepOnOff = ! getNL( os ); }
    69 void sepOff( ofstream & os ) { os.sepOnOff = false; }
     68void ^?{}( ofstream & os ) {
     69        close( os );
     70} // ^?{}
     71
     72void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); }
     73void sepOff( ofstream & os ) { os.$sepOnOff = false; }
    7074
    7175bool sepDisable( ofstream & os ) {
    72         bool temp = os.sepDefault;
    73         os.sepDefault = false;
    74         sepReset( os );
     76        bool temp = os.$sepDefault;
     77        os.$sepDefault = false;
     78        $sepReset( os );
    7579        return temp;
    7680} // sepDisable
    7781
    7882bool sepEnable( ofstream & os ) {
    79         bool temp = os.sepDefault;
    80         os.sepDefault = true;
    81         if ( os.sepOnOff ) sepReset( os );                                      // start of line ?
     83        bool temp = os.$sepDefault;
     84        os.$sepDefault = true;
     85        if ( os.$sepOnOff ) $sepReset( os );                            // start of line ?
    8286        return temp;
    8387} // sepEnable
    8488
    85 void nlOn( ofstream & os ) { os.nlOnOff = true; }
    86 void nlOff( ofstream & os ) { os.nlOnOff = false; }
    87 
    88 const char * sepGet( ofstream & os ) { return os.separator; }
    89 void sepSet( ofstream & os, const char * s ) {
     89void nlOn( ofstream & os ) { os.$nlOnOff = true; }
     90void nlOff( ofstream & os ) { os.$nlOnOff = false; }
     91
     92const char * sepGet( ofstream & os ) { return os.$separator; }
     93void sepSet( ofstream & os, const char s[] ) {
    9094        assert( s );
    91         strncpy( os.separator, s, sepSize - 1 );
    92         os.separator[sepSize - 1] = '\0';
     95        strncpy( os.$separator, s, sepSize - 1 );
     96        os.$separator[sepSize - 1] = '\0';
    9397} // sepSet
    9498
    95 const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator; }
    96 void sepSetTuple( ofstream & os, const char * s ) {
     99const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; }
     100void sepSetTuple( ofstream & os, const char s[] ) {
    97101        assert( s );
    98         strncpy( os.tupleSeparator, s, sepSize - 1 );
    99         os.tupleSeparator[sepSize - 1] = '\0';
     102        strncpy( os.$tupleSeparator, s, sepSize - 1 );
     103        os.$tupleSeparator[sepSize - 1] = '\0';
    100104} // sepSet
    101105
    102106void ends( ofstream & os ) {
    103         if ( getANL( os ) ) nl( os );
    104         else setPrt( os, false );                                                       // turn off
     107        if ( $getANL( os ) ) nl( os );
     108        else $setPrt( os, false );                                                      // turn off
    105109        if ( &os == &exit ) exit( EXIT_FAILURE );
    106110        if ( &os == &abort ) abort();
     
    108112
    109113int fail( ofstream & os ) {
    110         return os.file == 0 || ferror( (FILE *)(os.file) );
     114        return os.$file == 0 || ferror( (FILE *)(os.$file) );
    111115} // fail
    112116
    113117int flush( ofstream & os ) {
    114         return fflush( (FILE *)(os.file) );
     118        return fflush( (FILE *)(os.$file) );
    115119} // flush
    116120
    117 void open( ofstream & os, const char * name, const char * mode ) {
     121void open( ofstream & os, const char name[], const char mode[] ) {
    118122        FILE * file = fopen( name, mode );
    119123        #ifdef __CFA_DEBUG__
    120         if ( file == 0 ) {
     124        if ( file == 0p ) {
    121125                abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
    122126        } // if
     
    125129} // open
    126130
    127 void open( ofstream & os, const char * name ) {
     131void open( ofstream & os, const char name[] ) {
    128132        open( os, name, "w" );
    129133} // open
    130134
    131135void close( ofstream & os ) {
    132         if ( (FILE *)(os.file) == stdout || (FILE *)(os.file) == stderr ) return;
    133 
    134         if ( fclose( (FILE *)(os.file) ) == EOF ) {
     136        if ( (FILE *)(os.$file) == stdout || (FILE *)(os.$file) == stderr ) return;
     137
     138        if ( fclose( (FILE *)(os.$file) ) == EOF ) {
    135139                abort | IO_MSG "close output" | nl | strerror( errno );
    136140        } // if
    137141} // close
    138142
    139 ofstream & write( ofstream & os, const char * data, size_t size ) {
     143ofstream & write( ofstream & os, const char data[], size_t size ) {
    140144        if ( fail( os ) ) {
    141145                abort | IO_MSG "attempt write I/O on failed stream";
    142146        } // if
    143147
    144         if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
     148        if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) {
    145149                abort | IO_MSG "write" | nl | strerror( errno );
    146150        } // if
     
    151155        va_list args;
    152156        va_start( args, format );
    153         int len = vfprintf( (FILE *)(os.file), format, args );
     157        int len = vfprintf( (FILE *)(os.$file), format, args );
    154158        if ( len == EOF ) {
    155                 if ( ferror( (FILE *)(os.file) ) ) {
     159                if ( ferror( (FILE *)(os.$file) ) ) {
    156160                        abort | IO_MSG "invalid write";
    157161                } // if
     
    159163        va_end( args );
    160164
    161         setPrt( os, true );                                                                     // called in output cascade
    162         sepReset( os );                                                                         // reset separator
     165        $setPrt( os, true );                                                            // called in output cascade
     166        $sepReset( os );                                                                        // reset separator
    163167        return len;
    164168} // fmt
     
    180184// private
    181185void ?{}( ifstream & is, void * file ) {
    182         is.file = file;
    183         is.nlOnOff = false;
     186        is.$file = file;
     187        is.$nlOnOff = false;
    184188} // ?{}
    185189
    186190// public
    187 void ?{}( ifstream & is ) {     is.file = 0; }
    188 
    189 void ?{}( ifstream & is, const char * name, const char * mode ) {
     191void ?{}( ifstream & is ) { is.$file = 0p; }
     192
     193void ?{}( ifstream & is, const char name[], const char mode[] ) {
    190194        open( is, name, mode );
    191195} // ?{}
    192196
    193 void ?{}( ifstream & is, const char * name ) {
     197void ?{}( ifstream & is, const char name[] ) {
    194198        open( is, name, "r" );
    195199} // ?{}
    196200
    197 void nlOn( ifstream & os ) { os.nlOnOff = true; }
    198 void nlOff( ifstream & os ) { os.nlOnOff = false; }
    199 bool getANL( ifstream & os ) { return os.nlOnOff; }
     201void ^?{}( ifstream & is ) {
     202        close( is );
     203} // ^?{}
     204
     205void nlOn( ifstream & os ) { os.$nlOnOff = true; }
     206void nlOff( ifstream & os ) { os.$nlOnOff = false; }
     207bool getANL( ifstream & os ) { return os.$nlOnOff; }
    200208
    201209int fail( ifstream & is ) {
    202         return is.file == 0 || ferror( (FILE *)(is.file) );
     210        return is.$file == 0p || ferror( (FILE *)(is.$file) );
    203211} // fail
    204212
    205213int eof( ifstream & is ) {
    206         return feof( (FILE *)(is.file) );
     214        return feof( (FILE *)(is.$file) );
    207215} // eof
    208216
    209 void open( ifstream & is, const char * name, const char * mode ) {
     217void open( ifstream & is, const char name[], const char mode[] ) {
    210218        FILE * file = fopen( name, mode );
    211219        #ifdef __CFA_DEBUG__
    212         if ( file == 0 ) {
     220        if ( file == 0p ) {
    213221                abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
    214222        } // if
    215223        #endif // __CFA_DEBUG__
    216         is.file = file;
    217 } // open
    218 
    219 void open( ifstream & is, const char * name ) {
     224        is.$file = file;
     225} // open
     226
     227void open( ifstream & is, const char name[] ) {
    220228        open( is, name, "r" );
    221229} // open
    222230
    223231void close( ifstream & is ) {
    224         if ( (FILE *)(is.file) == stdin ) return;
    225 
    226         if ( fclose( (FILE *)(is.file) ) == EOF ) {
     232        if ( (FILE *)(is.$file) == stdin ) return;
     233
     234        if ( fclose( (FILE *)(is.$file) ) == EOF ) {
    227235                abort | IO_MSG "close input" | nl | strerror( errno );
    228236        } // if
     
    234242        } // if
    235243
    236         if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
     244        if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) {
    237245                abort | IO_MSG "read" | nl | strerror( errno );
    238246        } // if
     
    245253        } // if
    246254
    247         if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
     255        if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) {
    248256                abort | IO_MSG "ungetc" | nl | strerror( errno );
    249257        } // if
     
    255263
    256264        va_start( args, format );
    257         int len = vfscanf( (FILE *)(is.file), format, args );
     265        int len = vfscanf( (FILE *)(is.$file), format, args );
    258266        if ( len == EOF ) {
    259                 if ( ferror( (FILE *)(is.file) ) ) {
     267                if ( ferror( (FILE *)(is.$file) ) ) {
    260268                        abort | IO_MSG "invalid read";
    261269                } // if
  • libcfa/src/fstream.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jul 15 18:10:23 2019
    13 // Update Count     : 167
     12// Last Modified On : Mon Feb 17 08:29:23 2020
     13// Update Count     : 175
    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[], ... );
     68ofstream & write( ofstream &, const char data[], size_t size );
     69int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    7070
    7171void ?{}( ofstream & os );
    72 void ?{}( ofstream & os, const char * name, const char * mode );
    73 void ?{}( ofstream & os, const char * name );
     72void ?{}( ofstream & os, const char name[], const char mode[] );
     73void ?{}( ofstream & os, const char name[] );
     74void ^?{}( ofstream & os );
    7475
    7576extern ofstream & sout, & stdout, & serr, & stderr;             // aliases
     
    8182
    8283struct ifstream {
    83         void * file;
    84         bool nlOnOff;
     84        void * $file;
     85        bool $nlOnOff;
    8586}; // ifstream
    8687
     
    9192int fail( ifstream & is );
    9293int eof( ifstream & is );
    93 void open( ifstream & is, const char * name, const char * mode );
    94 void open( ifstream & is, const char * name );
     94void open( ifstream & is, const char name[], const char mode[] );
     95void open( ifstream & is, const char name[] );
    9596void close( ifstream & is );
    9697ifstream & read( ifstream & is, char * data, size_t size );
    9798ifstream & ungetc( ifstream & is, char c );
    98 int fmt( ifstream &, const char format[], ... );
     99int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    99100
    100101void ?{}( ifstream & is );
    101 void ?{}( ifstream & is, const char * name, const char * mode );
    102 void ?{}( ifstream & is, const char * name );
     102void ?{}( ifstream & is, const char name[], const char mode[] );
     103void ?{}( ifstream & is, const char name[] );
     104void ^?{}( ifstream & is );
    103105
    104106extern ifstream & sin, & stdin;                                                 // aliases
  • libcfa/src/gmp.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 13 15:25:05 2019
    13 // Update Count     : 27
     12// Last Modified On : Sun Feb  9 09:56:54 2020
     13// Update Count     : 31
    1414//
    1515
     
    2424
    2525static inline {
    26         // constructor
     26        // constructor, zero_t/one_t are unnecessary because of relationship with signed/unsigned int
    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 ); }
    3129        void ?{}( Int & this, signed long int init ) { mpz_init_set_si( this.mpz, init ); }
    3230        void ?{}( Int & this, unsigned long int init ) { mpz_init_set_ui( this.mpz, init ); }
    33         void ?{}( Int & this, const char * val ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
     31        void ?{}( Int & this, const char val[] ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }
    3432        void ^?{}( Int & this ) { mpz_clear( this.mpz ); }
    3533
     
    3735        Int ?`mp( signed long int init ) { return (Int){ init }; }
    3836        Int ?`mp( unsigned long int init ) { return (Int){ init }; }
    39         Int ?`mp( const char * init ) { return (Int){ init }; }
     37        Int ?`mp( const char init[] ) { return (Int){ init }; }
    4038
    4139        // assignment
     
    4341        Int ?=?( Int & lhs, long int rhs ) { mpz_set_si( lhs.mpz, rhs ); return lhs; }
    4442        Int ?=?( Int & lhs, unsigned long int rhs ) { mpz_set_ui( lhs.mpz, rhs ); return lhs; }
    45         Int ?=?( Int & lhs, const char * rhs ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
     43        Int ?=?( Int & lhs, const char rhs[] ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }
    4644
    4745        char ?=?( char & lhs, Int rhs ) { char val = mpz_get_si( rhs.mpz ); lhs = val; return lhs; }
     
    265263        forall( dtype ostype | ostream( ostype ) ) {
    266264                ostype & ?|?( ostype & os, Int mp ) {
    267                         if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     265                        if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    268266                        gmp_printf( "%Zd", mp.mpz );
    269267                        sepOn( os );
  • libcfa/src/heap.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 18 07:42:09 2019
    13 // Update Count     : 556
     12// Last Modified On : Wed Apr  1 15:59:53 2020
     13// Update Count     : 692
    1414//
    1515
     
    1818#include <stdio.h>                                                                              // snprintf, fileno
    1919#include <errno.h>                                                                              // errno
     20#include <string.h>                                                                             // memset, memcpy
    2021extern "C" {
    2122#include <sys/mman.h>                                                                   // mmap, munmap
     
    2728#include "bits/locks.hfa"                                                               // __spinlock_t
    2829#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    29 #include "stdlib.hfa"                                                                   // bsearchl
     30//#include "stdlib.hfa"                                                                 // bsearchl
    3031#include "malloc.h"
    3132
     33#define MIN(x, y) (y > x ? x : y)
    3234
    3335static bool traceHeap = false;
    3436
    35 inline bool traceHeap() {
    36         return traceHeap;
    37 } // traceHeap
     37inline bool traceHeap() { return traceHeap; }
    3838
    3939bool traceHeapOn() {
     
    4949} // traceHeapOff
    5050
    51 
    52 static bool checkFree = false;
    53 
    54 inline bool checkFree() {
    55         return checkFree;
    56 } // checkFree
    57 
    58 bool checkFreeOn() {
    59         bool temp = checkFree;
    60         checkFree = true;
     51bool traceHeapTerm() { return false; }
     52
     53
     54static bool prtFree = false;
     55
     56inline bool prtFree() {
     57        return prtFree;
     58} // prtFree
     59
     60bool prtFreeOn() {
     61        bool temp = prtFree;
     62        prtFree = true;
    6163        return temp;
    62 } // checkFreeOn
    63 
    64 bool checkFreeOff() {
    65         bool temp = checkFree;
    66         checkFree = false;
     64} // prtFreeOn
     65
     66bool prtFreeOff() {
     67        bool temp = prtFree;
     68        prtFree = false;
    6769        return temp;
    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
     70} // prtFreeOff
    8871
    8972
    9073enum {
     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.
     76        __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.
    9180        __CFA_DEFAULT_MMAP_START__ = (512 * 1024 + 1),
    92         __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
    9381};
    9482
     
    10593static unsigned int allocFree;                                                  // running total of allocations minus frees
    10694
    107 static void checkUnfreed() {
     95static void prtUnfreed() {
    10896        if ( allocFree != 0 ) {
    10997                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    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
     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
    117105
    118106extern "C" {
     
    123111        void heapAppStop() {                                                            // called by __cfaabi_appready_startdown
    124112                fclose( stdin ); fclose( stdout );
    125                 checkUnfreed();
     113                prtUnfreed();
    126114        } // heapAppStop
    127115} // extern "C"
    128116#endif // __CFA_DEBUG__
     117
    129118
    130119// statically allocated variables => zero filled.
     
    134123static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    135124
    136 
    137 // #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa
    138 #define ALIGN 16
    139125
    140126#define SPINLOCK 0
     
    147133// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    148134// Break recusion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
    149 enum { NoBucketSizes = 93 };                                                    // number of buckets sizes
     135enum { NoBucketSizes = 91 };                                                    // number of buckets sizes
    150136
    151137struct HeapManager {
     
    164150                                                        union {
    165151//                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
     152                                                                // 2nd low-order bit => zero filled
    166153                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    167154                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     
    183170                                struct FakeHeader {
    184171                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    185                                         uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
     172                                        // 1st low-order bit => fake header & alignment
     173                                        uint32_t alignment;
    186174                                        #endif // __ORDER_LITTLE_ENDIAN__
    187175
     
    193181                                } fake; // FakeHeader
    194182                        } kind; // Kind
     183                        uint32_t dimension;                                                     // used by calloc-like to remember number of array elements
    195184                } header; // Header
    196                 char pad[ALIGN - sizeof( Header )];
     185                char pad[libAlign() - sizeof( Header )];
    197186                char data[0];                                                                   // storage
    198187        }; // Storage
    199188
    200         static_assert( ALIGN >= sizeof( Storage ), "ALIGN < sizeof( Storage )" );
     189        static_assert( libAlign() >= sizeof( Storage ), "libAlign() < sizeof( Storage )" );
    201190
    202191        struct FreeHeader {
     
    228217#define __STATISTICS__
    229218
     219// Bucket size must be multiple of 16.
    230220// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    231221static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    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)
     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
    245239};
    246240
     
    251245static unsigned char lookup[LookupSizes];                               // O(1) lookup for small sizes
    252246#endif // FASTLOOKUP
     247
    253248static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
    254 
    255 
    256249#ifdef __CFA_DEBUG__
    257250static bool heapBoot = 0;                                                               // detect recursion during boot
     
    259252static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    260253
    261 // #comment TD : The return type of this function should be commented
    262 static 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 
    274 static 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 
    300 static 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 
    310 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
    311 void 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 
    325 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
    326 void memory_shutdown( void ) {
    327         ^heapManager{};
    328 } // memory_shutdown
    329 
    330254
    331255#ifdef __STATISTICS__
    332 static unsigned long long int mmap_storage;                             // heap statistics counters
     256// Heap statistics counters.
     257static unsigned long long int mmap_storage;
    333258static unsigned int mmap_calls;
    334259static unsigned long long int munmap_storage;
     
    346271static unsigned long long int cmemalign_storage;
    347272static unsigned int cmemalign_calls;
     273static unsigned long long int resize_storage;
     274static unsigned int resize_calls;
    348275static unsigned long long int realloc_storage;
    349276static unsigned int realloc_calls;
    350 
    351 static int statfd;                                                                              // statistics file descriptor (changed by malloc_stats_fd)
    352 
     277// Statistics file descriptor (changed by malloc_stats_fd).
     278static int statfd = STDERR_FILENO;                                              // default stderr
    353279
    354280// Use "write" because streams may be shutdown when calls are made.
    355281static void printStats() {
    356282        char helpText[512];
    357         __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText),
     283        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    358284                                                                        "\nHeap statistics:\n"
    359285                                                                        "  malloc: calls %u / storage %llu\n"
     
    361287                                                                        "  memalign: calls %u / storage %llu\n"
    362288                                                                        "  cmemalign: calls %u / storage %llu\n"
     289                                                                        "  resize: calls %u / storage %llu\n"
    363290                                                                        "  realloc: calls %u / storage %llu\n"
    364291                                                                        "  free: calls %u / storage %llu\n"
     
    370297                                                                        memalign_calls, memalign_storage,
    371298                                                                        cmemalign_calls, cmemalign_storage,
     299                                                                        resize_calls, resize_storage,
    372300                                                                        realloc_calls, realloc_storage,
    373301                                                                        free_calls, free_storage,
     
    389317                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
    390318                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
     319                                                "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    391320                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    392321                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    399328                                                memalign_calls, memalign_storage,
    400329                                                cmemalign_calls, cmemalign_storage,
     330                                                resize_calls, resize_storage,
    401331                                                realloc_calls, realloc_storage,
    402332                                                free_calls, free_storage,
     
    405335                                                sbrk_calls, sbrk_storage
    406336                );
    407         return write( fileno( stream ), helpText, len );        // -1 => error
     337        __cfaabi_bits_write( fileno( stream ), helpText, len ); // ensures all bytes written or exit
     338        return len;
    408339} // printStatsXML
    409340#endif // __STATISTICS__
    410341
    411 // #comment TD : Is this the samething as Out-of-Memory?
    412 static 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 
    419 static 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
     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
    424348
    425349
     
    431355
    432356
    433 static 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
    443 static 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 
    457 static 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 
    492 static 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 
     357// thunk problem
    523358size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
    524359        size_t l = 0, m, h = dim;
     
    535370
    536371
     372static 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
     402static 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
     409static 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
     418static 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
     429static 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
     461static 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
    537492static inline void * doMalloc( size_t size ) with ( heapManager ) {
    538493        HeapManager.Storage * block;                                            // pointer to new block of storage
     
    541496        // along with the block and is a multiple of the alignment size.
    542497
    543   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0;
     498  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
    544499        size_t tsize = size + sizeof(HeapManager.Storage);
    545500        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    574529                block = freeElem->freeList.pop();
    575530                #endif // SPINLOCK
    576                 if ( unlikely( block == 0 ) ) {                                 // no free block ?
     531                if ( unlikely( block == 0p ) ) {                                // no free block ?
    577532                        #if defined( SPINLOCK )
    578533                        unlock( freeElem->lock );
     
    583538
    584539                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    585   if ( unlikely( block == 0 ) ) return 0;
    586                         #if defined( SPINLOCK )
     540  if ( unlikely( block == 0p ) ) return 0p;
     541                #if defined( SPINLOCK )
    587542                } else {
    588543                        freeElem->freeList = block->header.kind.real.next;
    589544                        unlock( freeElem->lock );
    590                         #endif // SPINLOCK
     545                #endif // SPINLOCK
    591546                } // if
    592547
    593548                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    594549        } else {                                                                                        // large size => mmap
    595   if ( unlikely( size > ~0ul - pageSize ) ) return 0;
     550  if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
    596551                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    597552                #ifdef __STATISTICS__
     
    611566        } // if
    612567
    613         void * area = &(block->data);                                           // adjust off header to user bytes
     568        void * addr = &(block->data);                                           // adjust off header to user bytes
    614569
    615570        #ifdef __CFA_DEBUG__
    616         assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?
     571        assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    617572        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    618573        if ( traceHeap() ) {
    619574                enum { BufferSize = 64 };
    620575                char helpText[BufferSize];
    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 );
     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
    624579        } // if
    625580        #endif // __CFA_DEBUG__
    626581
    627         return area;
     582        return addr;
    628583} // doMalloc
    629584
     
    631586static inline void doFree( void * addr ) with ( heapManager ) {
    632587        #ifdef __CFA_DEBUG__
    633         if ( unlikely( heapManager.heapBegin == 0 ) ) {
     588        if ( unlikely( heapManager.heapBegin == 0p ) ) {
    634589                abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
    635590        } // if
     
    677632                char helpText[BufferSize];
    678633                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    679                 __cfaabi_dbg_bits_write( helpText, len );
     634                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    680635        } // if
    681636        #endif // __CFA_DEBUG__
     
    683638
    684639
    685 size_t checkFree( HeapManager & manager ) with ( manager ) {
     640size_t prtFree( HeapManager & manager ) with ( manager ) {
    686641        size_t total = 0;
    687642        #ifdef __STATISTICS__
    688         __cfaabi_dbg_bits_acquire();
    689         __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" );
     643        __cfaabi_bits_acquire();
     644        __cfaabi_bits_print_nolock( STDERR_FILENO, "\nBin lists (bin size : free blocks on list)\n" );
    690645        #endif // __STATISTICS__
    691646        for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
     
    696651
    697652                #if defined( SPINLOCK )
    698                 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) {
     653                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    699654                #else
    700                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0; p = p->header.kind.real.next.top ) {
     655                for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
    701656                #endif // SPINLOCK
    702657                        total += size;
     
    707662
    708663                #ifdef __STATISTICS__
    709                 __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u  ", size, N );
    710                 if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" );
     664                __cfaabi_bits_print_nolock( STDERR_FILENO, "%7zu, %-7u  ", size, N );
     665                if ( (i + 1) % 8 == 0 ) __cfaabi_bits_print_nolock( STDERR_FILENO, "\n" );
    711666                #endif // __STATISTICS__
    712667        } // for
    713668        #ifdef __STATISTICS__
    714         __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );
    715         __cfaabi_dbg_bits_release();
     669        __cfaabi_bits_print_nolock( STDERR_FILENO, "\ntotal free blocks:%zu\n", total );
     670        __cfaabi_bits_release();
    716671        #endif // __STATISTICS__
    717672        return (char *)heapEnd - (char *)heapBegin - total;
    718 } // checkFree
     673} // prtFree
     674
     675
     676static 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
     702static 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
     712static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
     713void 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
     727static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
     728void memory_shutdown( void ) {
     729        ^heapManager{};
     730} // memory_shutdown
    719731
    720732
    721733static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    722734        //assert( heapManager.heapBegin != 0 );
    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;
     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;
    727739} // mallocNoStats
     740
     741
     742static 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
    728765
    729766
     
    745782        // subtract libAlign() because it is already the minimum alignment
    746783        // add sizeof(Storage) for fake header
    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;
     784        char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
     785  if ( unlikely( addr == 0p ) ) return addr;
    750786
    751787        // address in the block of the "next" alignment address
    752         char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment );
     788        char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    753789
    754790        // address of header from malloc
    755         HeapManager.Storage.Header * realHeader = headerAddr( area );
     791        HeapManager.Storage.Header * realHeader = headerAddr( addr );
    756792        // address of fake header * before* the alignment location
    757793        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    763799        return user;
    764800} // memalignNoStats
     801
     802
     803static 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
    765822
    766823
     
    775832
    776833extern "C" {
    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().
     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().
    780836        void * malloc( size_t size ) {
    781837                #ifdef __STATISTICS__
     
    787843        } // malloc
    788844
    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().
     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().
    792848        void * calloc( size_t noOfElems, size_t elemSize ) {
    793                 size_t size = noOfElems * elemSize;
    794849                #ifdef __STATISTICS__
    795850                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    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;
     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 );
    801871
    802872                HeapManager.Storage.Header * header;
    803873                HeapManager.FreeHeader * freeElem;
    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;
     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
    826903                HeapManager.Storage.Header * header;
    827904                HeapManager.FreeHeader * freeElem;
    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;
    864                 } // if
    865 
    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
     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;
     913                } // if
     914
     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
    873924                } else {
    874                         area = mallocNoStats( size );                           // create new area
    875                 } // if
    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;
     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
     930                } // 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;
    890939        } // realloc
    891940
    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.
     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)
    894943        void * memalign( size_t alignment, size_t size ) {
    895944                #ifdef __STATISTICS__
     
    898947                #endif // __STATISTICS__
    899948
    900                 void * area = memalignNoStats( alignment, size );
    901 
    902                 return area;
     949                return memalignNoStats( alignment, size );
    903950        } // memalign
    904951
    905         // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
    906         // multiple of alignment.
     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.
    907965        void * aligned_alloc( size_t alignment, size_t size ) {
    908966                return memalign( alignment, size );
     
    910968
    911969
    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).
     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).
    916974        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    917975          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    918976                * memptr = memalign( alignment, size );
    919           if ( unlikely( * memptr == 0 ) ) return ENOMEM;
     977          if ( unlikely( * memptr == 0p ) ) return ENOMEM;
    920978                return 0;
    921979        } // posix_memalign
    922980
    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).
     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).
    925983        void * valloc( size_t size ) {
    926984                return memalign( pageSize, size );
     
    928986
    929987
    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.
     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.
    933997        void free( void * addr ) {
    934998                #ifdef __STATISTICS__
     
    9361000                #endif // __STATISTICS__
    9371001
    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__
     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__
    9491010                        return;
    9501011                } // exit
     
    9531014        } // free
    9541015
    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.
     1016
     1017        // Returns the alignment of the allocation.
    9931018        size_t malloc_alignment( void * addr ) {
    994           if ( unlikely( addr == 0 ) ) return libAlign();       // minimum alignment
     1019          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    9951020                HeapManager.Storage.Header * header = headerAddr( addr );
    9961021                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    9971022                        return header->kind.fake.alignment & -2;        // remove flag from value
    9981023                } else {
    999                         return libAlign ();                                                     // minimum alignment
     1024                        return libAlign();                                                      // minimum alignment
    10001025                } // if
    10011026        } // malloc_alignment
    10021027
    10031028
    1004     // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
     1029        // Returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    10051030        bool malloc_zero_fill( void * addr ) {
    1006           if ( unlikely( addr == 0 ) ) return false;            // null allocation is not zero fill
     1031          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    10071032                HeapManager.Storage.Header * header = headerAddr( addr );
    10081033                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1009                         header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
     1034                        header = realHeader( header );                          // backup from fake to real header
    10101035                } // if
    10111036                return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
     
    10131038
    10141039
    1015     // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
    1016     // related functions.
     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.
    10171065        void malloc_stats( void ) {
    10181066                #ifdef __STATISTICS__
    10191067                printStats();
    1020                 if ( checkFree() ) checkFree( heapManager );
     1068                if ( prtFree() ) prtFree( heapManager );
    10211069                #endif // __STATISTICS__
    10221070        } // malloc_stats
    10231071
    1024         // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
    1025         int malloc_stats_fd( int fd ) {
     1072        // Changes the file descripter where malloc_stats() writes statistics.
     1073        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    10261074                #ifdef __STATISTICS__
    10271075                int temp = statfd;
     
    10331081        } // malloc_stats_fd
    10341082
    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)).
     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).
    10381105        int malloc_info( int options, FILE * stream ) {
     1106                if ( options != 0 ) { errno = EINVAL; return -1; }
    10391107                return printStatsXML( stream );
    10401108        } // malloc_info
    10411109
    10421110
    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.)
     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.)
    10471115        void * malloc_get_state( void ) {
    1048                 return 0;                                                                               // unsupported
     1116                return 0p;                                                                              // unsupported
    10491117        } // malloc_get_state
    10501118
    10511119
    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.
     1120        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
     1121        // structure pointed to by state.
    10541122        int malloc_set_state( void * ptr ) {
    10551123                return 0;                                                                               // unsupported
     
    10581126
    10591127
     1128// Must have CFA linkage to overload with C linkage realloc.
     1129void * 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
     1176void * 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
    10601223// Local Variables: //
    10611224// tab-width: 4 //
  • libcfa/src/interpose.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jul 14 22:57:16 2019
    13 // Update Count     : 116
     12// Last Modified On : Fri Mar 13 17:35:37 2020
     13// Update Count     : 178
    1414//
    1515
     
    2929#include "bits/signal.hfa"                                                              // sigHandler_?
    3030#include "startup.hfa"                                                                  // STARTUP_PRIORITY_CORE
     31#include <assert.h>
    3132
    3233//=============================================================================================
     
    4041
    4142typedef void (* generic_fptr_t)(void);
    42 generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
     43generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {
    4344        const char * error;
    4445
     
    9596        void __cfaabi_interpose_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));
    9697        void __cfaabi_interpose_startup( void ) {
    97                 const char *version = NULL;
     98                const char *version = 0p;
    9899
    99100                preload_libgcc();
     
    105106#pragma GCC diagnostic pop
    106107
     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
    107125                // Failure handler
    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 );
     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
    115134        }
    116135}
     
    123142void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    124143void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
     144void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
     145void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));
    125146
    126147extern "C" {
    127148        void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
    128                 abort( NULL );
     149                abort( false, "%s", "" );
    129150        }
    130151
     
    132153                va_list argp;
    133154                va_start( argp, fmt );
    134                 abort( fmt, argp );
     155                __abort( false, fmt, argp );
    135156                va_end( argp );
    136157        }
     
    141162}
    142163
    143 void * kernel_abort    ( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return NULL; }
    144 void   kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
     164void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; }
     165void 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.
    145167int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
    146168
    147169enum { abort_text_size = 1024 };
    148170static char abort_text[ abort_text_size ];
    149 static int abort_lastframe;
    150 
    151 void 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 
    159 void 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 
    184 static void __cfaabi_backtrace() {
    185         enum {
    186                 Frames = 50,                                                                    // maximum number of stack frames
    187                 Start = 8,                                                                              // skip first N stack frames
    188         };
     171
     172static 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
    189175
    190176        void * array[Frames];
    191177        size_t size = backtrace( array, Frames );
    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
     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);
    204188                        if ( *p == '(' ) {
    205189                                name = p;
     
    212196                }
    213197
    214                 // if line contains symbol print it
    215                 int frameNo = i - Start;
     198                // if line contains symbol, print it
     199                int frameNo = i - start;
    216200                if ( name && offset_begin && offset_end && name < offset_begin ) {
    217                         // delimit strings
    218                         *name++ = '\0';
     201                        *name++ = '\0';                                                         // delimit strings
    219202                        *offset_begin++ = '\0';
    220203                        *offset_end++ = '\0';
    221204
    222                         __cfaabi_dbg_bits_print_nolock( "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
     205                        __cfaabi_bits_print_nolock( STDERR_FILENO, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
    223206                } else {                                                                                // otherwise, print the whole line
    224                         __cfaabi_dbg_bits_print_nolock( "(%i) %s\n", frameNo, messages[i] );
     207                        __cfaabi_bits_print_nolock( STDERR_FILENO, "(%i) %s\n", frameNo, messages[i] );
    225208                }
    226209        }
     
    228211}
    229212
     213void 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.
     222void __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
     245void 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
     253void 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
    230261void sigHandler_segv( __CFA_SIGPARMS__ ) {
    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 );
     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                }
    234269}
    235270
    236271void sigHandler_ill( __CFA_SIGPARMS__ ) {
    237         abort( "Executing illegal instruction at location %p.\n"
     272        abort( true, "Executing illegal instruction at location %p.\n"
    238273                        "Possible cause is stack corruption.\n",
    239274                        sfp->si_addr );
     
    251286          default: msg = "unknown";
    252287        } // choose
    253         abort( "Computation error %s at location %p.\n", msg, sfp->si_addr );
    254 }
    255 
    256 void sigHandler_abrt( __CFA_SIGPARMS__ ) {
    257         __cfaabi_backtrace();
    258 
    259         // reset default signal handler
    260         __cfaabi_sigdefault( SIGABRT );
    261 
    262         raise( SIGABRT );
     288        abort( true, "Computation error %s at location %p.\n", msg, sfp->si_addr );
    263289}
    264290
    265291void sigHandler_term( __CFA_SIGPARMS__ ) {
    266         abort( "Application stopped by %s signal.", sig == SIGINT ? "an interrupt (SIGINT)" : "a terminate (SIGTERM)" );
     292        abort( true, "Application interrupted by signal: %s.\n", strsignal( sig ) );
    267293}
    268294
  • libcfa/src/iostream.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 13 08:07:59 2019
    13 // Update Count     : 821
     12// Last Modified On : Wed Mar 11 14:35:35 2020
     13// Update Count     : 860
    1414//
    1515
     
    1919#include <stdio.h>
    2020#include <stdbool.h>                                                                    // true/false
     21#include <stdint.h>                                                                             // UINT64_MAX
    2122//#include <string.h>                                                                   // strlen, strcmp
    2223extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
     
    3536forall( dtype ostype | ostream( ostype ) ) {
    3637        ostype & ?|?( ostype & os, zero_t ) {
    37                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     38                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    3839                fmt( os, "%d", 0n );
    3940                return os;
     
    4445
    4546        ostype & ?|?( ostype & os, one_t ) {
    46                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     47                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    4748                fmt( os, "%d", 1n );
    4849                return os;
     
    5354
    5455        ostype & ?|?( ostype & os, bool b ) {
    55                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     56                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    5657                fmt( os, "%s", b ? "true" : "false" );
    5758                return os;
     
    6364        ostype & ?|?( ostype & os, char c ) {
    6465                fmt( os, "%c", c );
    65                 if ( c == '\n' ) setNL( os, true );
     66                if ( c == '\n' ) $setNL( os, true );
    6667                return sepOff( os );
    6768        } // ?|?
     
    7172
    7273        ostype & ?|?( ostype & os, signed char sc ) {
    73                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     74                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    7475                fmt( os, "%hhd", sc );
    7576                return os;
     
    8081
    8182        ostype & ?|?( ostype & os, unsigned char usc ) {
    82                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     83                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    8384                fmt( os, "%hhu", usc );
    8485                return os;
     
    8990
    9091        ostype & ?|?( ostype & os, short int si ) {
    91                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     92                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    9293                fmt( os, "%hd", si );
    9394                return os;
     
    9899
    99100        ostype & ?|?( ostype & os, unsigned short int usi ) {
    100                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     101                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    101102                fmt( os, "%hu", usi );
    102103                return os;
     
    107108
    108109        ostype & ?|?( ostype & os, int i ) {
    109                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     110                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    110111                fmt( os, "%d", i );
    111112                return os;
     
    116117
    117118        ostype & ?|?( ostype & os, unsigned int ui ) {
    118                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     119                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    119120                fmt( os, "%u", ui );
    120121                return os;
     
    125126
    126127        ostype & ?|?( ostype & os, long int li ) {
    127                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     128                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    128129                fmt( os, "%ld", li );
    129130                return os;
     
    134135
    135136        ostype & ?|?( ostype & os, unsigned long int uli ) {
    136                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     137                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    137138                fmt( os, "%lu", uli );
    138139                return os;
     
    143144
    144145        ostype & ?|?( ostype & os, long long int lli ) {
    145                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     146                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    146147                fmt( os, "%lld", lli );
    147148                return os;
     
    152153
    153154        ostype & ?|?( ostype & os, unsigned long long int ulli ) {
    154                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     155                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    155156                fmt( os, "%llu", ulli );
    156157                return os;
     
    159160                (ostype &)(os | ulli); ends( os );
    160161        } // ?|?
     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__
    161202
    162203        #define PrintWithDP( os, format, val, ... ) \
     
    175216
    176217        ostype & ?|?( ostype & os, float f ) {
    177                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     218                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    178219                PrintWithDP( os, "%g", f );
    179220                return os;
     
    184225
    185226        ostype & ?|?( ostype & os, double d ) {
    186                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     227                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    187228                PrintWithDP( os, "%.*lg", d, DBL_DIG );
    188229                return os;
     
    193234
    194235        ostype & ?|?( ostype & os, long double ld ) {
    195                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     236                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    196237                PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
    197238                return os;
     
    202243
    203244        ostype & ?|?( ostype & os, float _Complex fc ) {
    204                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     245                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    205246//              os | crealf( fc ) | nonl;
    206247                PrintWithDP( os, "%g", crealf( fc ) );
     
    214255
    215256        ostype & ?|?( ostype & os, double _Complex dc ) {
    216                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     257                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    217258//              os | creal( dc ) | nonl;
    218259                PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG );
     
    226267
    227268        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    228                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     269                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    229270//              os | creall( ldc ) || nonl;
    230271                PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG );
     
    237278        } // ?|?
    238279
    239         ostype & ?|?( ostype & os, const char * str ) {
     280        ostype & ?|?( ostype & os, const char str[] ) {
    240281                enum { Open = 1, Close, OpenClose };
    241282                static const unsigned char mask[256] @= {
     
    257298                // first character IS NOT spacing or closing punctuation => add left separator
    258299                unsigned char ch = str[0];                                              // must make unsigned
    259                 if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
    260                         fmt( os, "%s", sepGetCur( os ) );
     300                if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
     301                        fmt( os, "%s", $sepGetCur( os ) );
    261302                } // if
    262303
    263304                // if string starts line, must reset to determine open state because separator is off
    264                 sepReset( os );                                                                 // reset separator
     305                $sepReset( os );                                                                // reset separator
    265306
    266307                // last character IS spacing or opening punctuation => turn off separator for next item
    267308                size_t len = strlen( str );
    268309                ch = str[len - 1];                                                              // must make unsigned
    269                 if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
     310                if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
    270311                        sepOn( os );
    271312                } else {
    272313                        sepOff( os );
    273314                } // if
    274                 if ( ch == '\n' ) setNL( os, true );                    // check *AFTER* sepPrt call above as it resets NL flag
     315                if ( ch == '\n' ) $setNL( os, true );                   // check *AFTER* $sepPrt call above as it resets NL flag
    275316                return write( os, str, len );
    276317        } // ?|?
    277         void ?|?( ostype & os, const char * str ) {
     318
     319        void ?|?( ostype & os, const char str[] ) {
    278320                (ostype &)(os | str); ends( os );
    279321        } // ?|?
    280322
    281323//      ostype & ?|?( ostype & os, const char16_t * str ) {
    282 //              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     324//              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    283325//              fmt( os, "%ls", str );
    284326//              return os;
     
    287329// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    288330//      ostype & ?|?( ostype & os, const char32_t * str ) {
    289 //              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     331//              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    290332//              fmt( os, "%ls", str );
    291333//              return os;
     
    294336
    295337//      ostype & ?|?( ostype & os, const wchar_t * str ) {
    296 //              if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     338//              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    297339//              fmt( os, "%ls", str );
    298340//              return os;
     
    300342
    301343        ostype & ?|?( ostype & os, const void * p ) {
    302                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     344                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    303345                fmt( os, "%p", p );
    304346                return os;
     
    315357        void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    316358                (ostype &)(manip( os ));
    317                 if ( getPrt( os ) ) ends( os );                                 // something printed ?
    318                 setPrt( os, false );                                                    // turn off
     359                if ( $getPrt( os ) ) ends( os );                                // something printed ?
     360                $setPrt( os, false );                                                   // turn off
    319361        } // ?|?
    320362
     
    329371        ostype & nl( ostype & os ) {
    330372                (ostype &)(os | '\n');
    331                 setPrt( os, false );                                                    // turn off
    332                 setNL( os, true );
     373                $setPrt( os, false );                                                   // turn off
     374                $setNL( os, true );
    333375                flush( os );
    334376                return sepOff( os );                                                    // prepare for next line
     
    336378
    337379        ostype & nonl( ostype & os ) {
    338                 setPrt( os, false );                                                    // turn off
     380                $setPrt( os, false );                                                   // turn off
    339381                return os;
    340382        } // nonl
     
    375417        ostype & ?|?( ostype & os, T arg, Params rest ) {
    376418                (ostype &)(os | arg);                                                   // print first argument
    377                 sepSetCur( os, sepGetTuple( os ) );                             // switch to tuple separator
     419                $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
    378420                (ostype &)(os | rest);                                                  // print remaining arguments
    379                 sepSetCur( os, sepGet( os ) );                                  // switch to regular separator
     421                $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
    380422                return os;
    381423        } // ?|?
     
    383425                // (ostype &)(?|?( os, arg, rest )); ends( os );
    384426                (ostype &)(os | arg);                                                   // print first argument
    385                 sepSetCur( os, sepGetTuple( os ) );                             // switch to tuple separator
     427                $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
    386428                (ostype &)(os | rest);                                                  // print remaining arguments
    387                 sepSetCur( os, sepGet( os ) );                                  // switch to regular separator
     429                $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
    388430                ends( os );
    389431        } // ?|?
     
    414456forall( dtype ostype | ostream( ostype ) ) { \
    415457        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    416                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
     458                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    417459\
    418460                if ( f.base == 'b' || f.base == 'B' ) {                 /* bespoke binary format */ \
     
    463505\
    464506                if ( ! f.flags.pc ) {                                                   /* no precision */ \
    465                         /* printf( "%s\n", &fmtstr[star] ); */ \
    466507                        fmtstr[sizeof(IFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
     508                        /* printf( "%s %c %c\n", &fmtstr[star], f.base, CODE ); */ \
    467509                        fmt( os, &fmtstr[star], f.wd, f.val ); \
    468510                } else {                                                                                /* precision */ \
    469511                        fmtstr[sizeof(IFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    470                         /* printf( "%s\n", &fmtstr[star] ); */ \
     512                        /* printf( "%s %c %c\n", &fmtstr[star], f.base, CODE ); */ \
    471513                        fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \
    472514                } /* if */ \
     
    486528IntegralFMTImpl( signed long long int, 'd', "%    *ll ", "%    *.*ll " )
    487529IntegralFMTImpl( 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 ) \
     535forall( dtype ostype | ostream( ostype ) ) \
     536static 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 */ \
     552forall( 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
     605IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
     606IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
     607#endif // __SIZEOF_INT128__
    488608
    489609//*********************************** floating point ***********************************
     
    513633forall( dtype ostype | ostream( ostype ) ) { \
    514634        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    515                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) ); \
     635                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    516636                char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
    517637                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
     
    536656                return os; \
    537657        } /* ?|? */ \
     658\
    538659        void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    539660} // distribution
     
    555676                } // if
    556677
    557                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     678                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    558679
    559680                #define CFMTNP "% * "
     
    571692                return os;
    572693        } // ?|?
     694
    573695        void ?|?( ostype & os, _Ostream_Manip(char) f ) { (ostype &)(os | f); ends( os ); }
    574696} // distribution
     
    592714                } // if
    593715
    594                 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );
     716                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    595717
    596718                #define SFMTNP "% * "
     
    616738                return os;
    617739        } // ?|?
     740
    618741        void ?|?( ostype & os, _Ostream_Manip(const char *) f ) { (ostype &)(os | f); ends( os ); }
    619742} // distribution
     
    735858        } // ?|?
    736859
    737         // istype & ?|?( istype & is, const char * fmt ) {
     860        // istype & ?|?( istype & is, const char fmt[] ) {
    738861        //      fmt( is, fmt, "" );
    739862        //      return is;
  • libcfa/src/iostream.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 12 12:08:38 2019
    13 // Update Count     : 334
     12// Last Modified On : Thu Feb 20 15:30:56 2020
     13// Update Count     : 337
    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__
    100106
    101107        ostype & ?|?( ostype &, float );
     
    113119        void ?|?( ostype &, long double _Complex );
    114120
    115         ostype & ?|?( ostype &, const char * );
    116         void ?|?( ostype &, const char * );
     121        ostype & ?|?( ostype &, const char [] );
     122        void ?|?( ostype &, const char [] );
    117123        // ostype & ?|?( ostype &, const char16_t * );
    118124#if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
     
    206212IntegralFMTDecl( signed long long int, 'd' )
    207213IntegralFMTDecl( unsigned long long int, 'u' )
     214#if defined( __SIZEOF_INT128__ )
     215IntegralFMTDecl( int128, 'd' )
     216IntegralFMTDecl( unsigned int128, 'u' )
     217#endif
    208218
    209219//*********************************** floating point ***********************************
     
    256266
    257267static inline {
    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 } }; }
     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 } }; }
    263273        _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
    264274        _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; }
     
    281291        int fail( istype & );
    282292        int eof( istype & );
    283         void open( istype & is, const char * name );
     293        void open( istype & is, const char name[] );
    284294        void close( istype & is );
    285295        istype & read( istype &, char *, size_t );
     
    316326        istype & ?|?( istype &, long double _Complex & );
    317327
    318 //      istype & ?|?( istype &, const char * );
     328//      istype & ?|?( istype &, const char [] );
    319329        istype & ?|?( istype &, char * );
    320330
     
    343353static inline {
    344354        _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
    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 } }; }
     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 } }; }
    351361        _Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; }
    352         _Istream_Cstr wdi( unsigned int w, char * s ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
     362        _Istream_Cstr wdi( unsigned int w, char s[] ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }
    353363        _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    354364} // distribution
  • libcfa/src/math.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Apr 18 23:37:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 13 11:02:15 2018
    13 // Update Count     : 116
     12// Last Modified On : Tue Feb  4 10:27:11 2020
     13// Update Count     : 117
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 12 18:12:08 2019
    13 // Update Count     : 184
     12// Last Modified On : Sat Feb  8 17:56:36 2020
     13// Update Count     : 187
    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
    5865
    5966        // getter for numerator/denominator
  • libcfa/src/startup.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jul 24 16:21:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 25 16:42:01 2018
    13 // Update Count     : 11
     12// Last Modified On : Tue Feb  4 13:03:18 2020
     13// Update Count     : 30
    1414//
    1515
     16#include <time.h>                                                                               // tzset
    1617#include "startup.hfa"
    17 #include <unistd.h>
    18 
    1918
    2019extern "C" {
    21     static void __cfaabi_appready_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_APPREADY ) ));
     20    void __cfaabi_appready_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_APPREADY ) ));
    2221    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     static void __cfaabi_appready_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_APPREADY ) ));
     29    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(struct __spinlock_t & this, const char * prev_name) __attribute__(( weak )) {}
     43        void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {}
    4444}
    4545
  • libcfa/src/stdhdr/assert.h

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jul 31 23:09:32 2017
    13 // Update Count     : 13
     12// Last Modified On : Tue Feb  4 12:58:49 2020
     13// Update Count     : 15
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jul 18 07:26:04 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jul 22 13:49:30 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Feb  7 19:05:08 2020
     13// Update Count     : 6
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jul 18 07:45:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jul 22 13:49:58 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Feb  7 19:05:18 2020
     13// Update Count     : 6
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Jul 18 07:55:44 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jul 22 13:50:24 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Feb  7 19:05:35 2020
     13// Update Count     : 6
    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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 22 18:16:07 2018
    13 // Update Count     : 13
     12// Last Modified On : Fri Feb  7 19:05:27 2020
     13// Update Count     : 15
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Thu Feb  8 23:48:16 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  8 23:50:44 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Feb  7 19:05:41 2020
     13// Update Count     : 6
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Oct 22 08:57:52 2019
    13 // Update Count     : 478
     12// Last Modified On : Tue Mar 31 13:26:46 2020
     13// Update Count     : 495
    1414//
    1515
     
    2020#define _XOPEN_SOURCE 600                                                               // posix_memalign, *rand48
    2121#include <string.h>                                                                             // memcpy, memset
    22 #include <malloc.h>                                                                             // malloc_usable_size
    2322//#include <math.h>                                                                             // fabsf, fabs, fabsl
    2423#include <complex.h>                                                                    // _Complex_I
     
    3029        T * alloc_set( T ptr[], size_t dim, char fill ) {       // realloc array with fill
    3130                size_t olen = malloc_usable_size( ptr );                // current allocation
    32                 char * nptr = (char *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
    33                 size_t nlen = malloc_usable_size( nptr );               // new allocation
    34                 if ( nlen > olen ) {                                                    // larger ?
    35                         memset( nptr + olen, (int)fill, nlen - olen ); // initialize added storage
     31                void * nptr = (void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     32                size_t nlen = malloc_usable_size( nptr );               // new allocation
     33                if ( nlen > olen ) {                                                    // larger ?
     34                        memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage
    3635                } // if
    3736                return (T *)nptr;
    3837        } // alloc_set
    3938
    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
     39        T * alloc_set( T ptr[], size_t dim, T fill ) { // realloc array with fill
     40                size_t olen = malloc_usable_size( ptr );                // current allocation
     41                void * nptr = (void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
     42                size_t nlen = malloc_usable_size( nptr );               // new allocation
     43                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
    7148
    7249        T * alloc_align_set( T ptr[], size_t align, char fill ) { // aligned realloc with fill
    7350                size_t olen = malloc_usable_size( ptr );                // current allocation
    74                 char * nptr = alloc_align( ptr, align );
    75                 size_t nlen = malloc_usable_size( nptr );               // new allocation
    76                 if ( nlen > olen ) {                                                    // larger ?
    77                         memset( nptr + olen, (int)fill, nlen - olen ); // initialize added storage
     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
    7867                } // if
    7968                return (T *)nptr;
     
    138127//---------------------------------------
    139128
    140 float _Complex strto( const char * sptr, char ** eptr ) {
     129float _Complex strto( const char sptr[], char ** eptr ) {
    141130        float re, im;
    142131        char * eeptr;
     
    149138} // strto
    150139
    151 double _Complex strto( const char * sptr, char ** eptr ) {
     140double _Complex strto( const char sptr[], char ** eptr ) {
    152141        double re, im;
    153142        char * eeptr;
     
    160149} // strto
    161150
    162 long double _Complex strto( const char * sptr, char ** eptr ) {
     151long double _Complex strto( const char sptr[], char ** eptr ) {
    163152        long double re, im;
    164153        char * eeptr;
  • libcfa/src/stdlib.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 20 22:57:33 2019
    13 // Update Count     : 390
     12// Last Modified On : Wed Apr  1 18:38:41 2020
     13// Update Count     : 429
    1414//
    1515
     
    2121#include <stdlib.h>                                                                             // *alloc, strto*, ato*
    2222
     23// Reduce includes by explicitly defining these routines.
    2324extern "C" {
    2425        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
    2528        void * memset( void * dest, int fill, size_t size ); // string.h
    2629        void * memcpy( void * dest, const void * src, size_t size ); // string.h
    27     void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap
     30        void * resize( void * oaddr, size_t size );                     // CFA heap
    2831} // extern "C"
     32
     33void * resize( void * oaddr, size_t nalign, size_t size ); // CFA heap
     34void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
    2935
    3036//---------------------------------------
     
    3844
    3945static inline forall( dtype T | sized(T) ) {
    40         // C dynamic allocation
     46        // Cforall safe equivalents, i.e., implicit size specification
    4147
    4248        T * malloc( void ) {
     
    5056        } // calloc
    5157
    52         T * realloc( T * ptr, size_t size ) {
    53                 if ( unlikely( ptr == 0 ) ) return malloc();
     58        T * realloc( T * ptr, size_t size ) {                           // CFA realloc, eliminate return-type cast
    5459                return (T *)(void *)realloc( (void *)ptr, size ); // C realloc
    5560        } // realloc
     
    5964        } // memalign
    6065
     66        T * cmemalign( size_t align, size_t dim  ) {
     67                return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign
     68        } // cmemalign
     69
    6170        T * aligned_alloc( size_t align ) {
    6271                return (T *)aligned_alloc( align, sizeof(T) );  // C aligned_alloc
     
    6675                return posix_memalign( (void **)ptr, align, sizeof(T) ); // C posix_memalign
    6776        } // posix_memalign
    68 
    69         // Cforall dynamic allocation
     77} // distribution
     78
     79static inline forall( dtype T | sized(T) ) {
     80        // Cforall safe general allocation, fill, resize, array
    7081
    7182        T * alloc( void ) {
     
    7889        } // alloc
    7990
    80         T * alloc( T ptr[], size_t dim ) {                                      // realloc
    81                 return realloc( ptr, dim * sizeof(T) );
     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
    82110        } // alloc
    83111
     
    107135forall( dtype T | sized(T) ) {
    108136        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
    109138} // distribution
    110139
     
    116145        T * alloc_align( size_t align, size_t dim ) {
    117146                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
    118160        } // alloc_align
    119161
     
    142184
    143185forall( dtype T | sized(T) ) {
    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
     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
    146188        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); // aligned realloc array with fill
    147 } // distribution
    148 
    149 static inline forall( dtype T | sized(T) ) {
    150         // data, non-array types
     189        T * alloc_align_set( T ptr[], size_t align, size_t dim, T fill ); // aligned realloc array with fill
     190} // distribution
     191
     192static inline forall( dtype T | sized(T) ) {
     193        // Cforall safe initialization/copy, i.e., implicit size specification, non-array types
    151194        T * memset( T * dest, char fill ) {
    152195                return (T *)memset( dest, fill, sizeof(T) );
     
    159202
    160203static inline forall( dtype T | sized(T) ) {
    161         // data, array types
     204        // Cforall safe initialization/copy, i.e., implicit size specification, array types
    162205        T * amemset( T dest[], char fill, size_t dim ) {
    163206                return (T *)(void *)memset( dest, fill, dim * sizeof(T) ); // C memset
     
    169212} // distribution
    170213
    171 // allocation/deallocation and constructor/destructor, non-array types
     214// Cforall allocation/deallocation and constructor/destructor, non-array types
    172215forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );
    173216forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );
    174217forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } ) void delete( T * ptr, Params rest );
    175218
    176 // allocation/deallocation and constructor/destructor, array types
     219// Cforall allocation/deallocation and constructor/destructor, array types
    177220forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );
    178221forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );
     
    182225
    183226static inline {
    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 
    196 float _Complex strto( const char * sptr, char ** eptr );
    197 double _Complex strto( const char * sptr, char ** eptr );
    198 long double _Complex strto( const char * sptr, char ** eptr );
     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
     239float _Complex strto( const char sptr[], char ** eptr );
     240double _Complex strto( const char sptr[], char ** eptr );
     241long double _Complex strto( const char sptr[], char ** eptr );
    199242
    200243static inline {
    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 ); }
     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 ); }
    215258} // distribution
    216259
  • libcfa/src/time.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Mar 27 13:33:14 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 13 08:41:55 2019
    13 // Update Count     : 65
     12// Last Modified On : Tue Feb  4 08:24:18 2020
     13// Update Count     : 70
    1414//
    1515
     
    3333forall( dtype ostype | ostream( ostype ) ) {
    3434        ostype & ?|?( ostype & os, Duration dur ) with( dur ) {
    35                 (ostype &)(os | tv / TIMEGRAN);                                 // print seconds
    36                 long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;   // compute nanoseconds
     35                (ostype &)(os | tn / TIMEGRAN);                                 // print seconds
     36                long int ns = (tn < 0 ? -tn : tn) % 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, int nsec ) {
     54static void tabort( int year, int month, int day, int hour, int min, int sec, int64_t 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 exceeds range 00:00:00 UTC, January 1, 1970 to 03:14:07 UTC, January 19, 2038.";
     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.";
    5757} // tabort
    5858#endif // __CFA_DEBUG__
    5959
    60 void ?{}( Time & time, int year, int month, int day, int hour, int min, int sec, int nsec ) with( time ) {
     60void ?{}( Time & time, int year, int month, int day, int hour, int min, int sec, int64_t nsec ) with( time ) {
    6161        tm tm;
    6262
    63         tm.tm_isdst = -1;                                                                       // let mktime determine if alternate timezone is in effect
     63        // Values can be in any range (+/-) but result must be in the epoch.
    6464        tm.tm_year = year - 1900;                                                       // mktime uses 1900 as its starting point
    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__
     65        // Make month in range 1-12 to match with day.
    7066        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__
    7667        tm.tm_mday = day;                                                                       // mktime uses range 1-31
    7768        tm.tm_hour = hour;
    7869        tm.tm_min = min;
    7970        tm.tm_sec = sec;
     71        tm.tm_isdst = -1;                                                                       // let mktime determine if alternate timezone is in effect
    8072        time_t epochsec = mktime( &tm );
    8173#ifdef __CFA_DEBUG__
    82         if ( epochsec == (time_t)-1 ) {
     74        if ( epochsec <= (time_t)-1 ) {                                         // MUST BE LESS THAN OR EQUAL!
    8375                tabort( year, month, day, hour, min, sec, nsec );
    8476        } // if
    8577#endif // __CFA_DEBUG__
    86         tv = (int64_t)(epochsec) * TIMEGRAN + nsec;                     // convert to nanoseconds
     78        tn = (int64_t)(epochsec) * TIMEGRAN + nsec;                     // convert to nanoseconds
    8779#ifdef __CFA_DEBUG__
    88         if ( tv > 2147483647LL * TIMEGRAN ) {                           // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
     80        if ( tn > 2147483647LL * TIMEGRAN ) {                           // between 00:00:00 UTC, January 1, 1970 and 03:14:07 UTC, January 19, 2038.
    8981                tabort( year, month, day, hour, min, sec, nsec );
    9082        } // if
     
    9385
    9486char * yy_mm_dd( Time time, char * buf ) with( time ) {
    95         time_t s = tv / TIMEGRAN;
     87        time_t s = tn / TIMEGRAN;
    9688        tm tm;
    9789        gmtime_r( &s, &tm );                                                            // tm_mon <= 11, tm_mday <= 31
     
    108100
    109101char * mm_dd_yy( Time time, char * buf ) with( time ) {
    110         time_t s = tv / TIMEGRAN;
     102        time_t s = tn / TIMEGRAN;
    111103        tm tm;
    112104        gmtime_r( &s, &tm );                                                            // tm_mon <= 11, tm_mday <= 31
     
    123115
    124116char * dd_mm_yy( Time time, char * buf ) with( time ) {
    125         time_t s = tv / TIMEGRAN;
     117        time_t s = tn / TIMEGRAN;
    126118        tm tm;
    127119        gmtime_r( &s, &tm );                                                            // tm_mon <= 11, tm_mday <= 31
     
    137129} // dd_mm_yy
    138130
    139 size_t strftime( char * buf, size_t size, const char * fmt, Time time ) with( time ) {
    140         time_t s = tv / TIMEGRAN;
     131size_t strftime( char buf[], size_t size, const char fmt[], Time time ) with( time ) {
     132        time_t s = tn / TIMEGRAN;
    141133        tm tm;
    142134        gmtime_r( &s, &tm );
     
    147139        ostype & ?|?( ostype & os, Time time ) with( time ) {
    148140                char buf[32];                                                                   // at least 26
    149                 time_t s = tv / TIMEGRAN;
     141                time_t s = tn / TIMEGRAN;
    150142                ctime_r( &s, (char *)&buf );                                    // 26 characters: "Wed Jun 30 21:49:08 1993\n"
    151143                buf[24] = '\0';                                                                 // remove trailing '\n'
    152                 long int ns = (tv < 0 ? -tv : tv) % TIMEGRAN;   // compute nanoseconds
     144                long int ns = (tn < 0 ? -tn : tn) % TIMEGRAN;   // compute nanoseconds
    153145                if ( ns == 0 ) {                                                                // none ?
    154146                        (ostype &)(os | buf);                                           // print date/time/year
  • libcfa/src/time.hfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Mar 14 23:18:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Sep 22 12:25:34 2018
    13 // Update Count     : 643
     12// Last Modified On : Tue Feb  4 08:24:32 2020
     13// Update Count     : 654
    1414//
    1515
     
    3232        Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
    3333
    34         Duration +?( Duration rhs ) with( rhs ) {       return (Duration)@{ +tv }; }
    35         Duration ?+?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tv + rhs.tv }; }
     34        Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
     35        Duration ?+?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tn + rhs.tn }; }
    3636        Duration ?+=?( Duration & lhs, Duration rhs ) { lhs = lhs + rhs; return lhs; }
    3737
    38         Duration -?( Duration rhs ) with( rhs ) { return (Duration)@{ -tv }; }
    39         Duration ?-?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tv - rhs.tv }; }
     38        Duration -?( Duration rhs ) with( rhs ) { return (Duration)@{ -tn }; }
     39        Duration ?-?( Duration & lhs, Duration rhs ) { return (Duration)@{ lhs.tn - rhs.tn }; }
    4040        Duration ?-=?( Duration & lhs, Duration rhs ) { lhs = lhs - rhs; return lhs; }
    4141
    42         Duration ?*?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv * rhs }; }
    43         Duration ?*?( int64_t lhs, Duration rhs ) { return (Duration)@{ lhs * rhs.tv }; }
     42        Duration ?*?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tn * rhs }; }
     43        Duration ?*?( int64_t lhs, Duration rhs ) { return (Duration)@{ lhs * rhs.tn }; }
    4444        Duration ?*=?( Duration & lhs, int64_t rhs ) { lhs = lhs * rhs; return lhs; }
    4545
    46         int64_t ?/?( Duration lhs, Duration rhs ) { return lhs.tv / rhs.tv; }
    47         Duration ?/?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tv / rhs }; }
     46        int64_t ?/?( Duration lhs, Duration rhs ) { return lhs.tn / rhs.tn; }
     47        Duration ?/?( Duration lhs, int64_t rhs ) { return (Duration)@{ lhs.tn / rhs }; }
    4848        Duration ?/=?( Duration & lhs, int64_t rhs ) { lhs = lhs / rhs; return lhs; }
    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 }; }
     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 }; }
    5252        Duration ?%=?( Duration & lhs, Duration rhs ) { lhs = lhs % rhs; return lhs; }
    5353
    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; }
     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; }
    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.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;}
     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;}
    9595} // distribution
    9696
     
    143143//######################### Time #########################
    144144
    145 void ?{}( Time & time, int year, int month = 0, int day = 0, int hour = 0, int min = 0, int sec = 0, int nsec = 0 );
     145void ?{}( Time & time, int year, int month = 1, int day = 1, int hour = 0, int min = 0, int sec = 0, int64_t nsec = 0 );
    146146static inline {
    147147        Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }
    148148
    149         void ?{}( Time & time, timeval t ) with( time ) { tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
     149        void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
    150150        Time ?=?( Time & time, timeval t ) with( time ) {
    151                 tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
     151                tn = (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 ) { tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
     155        void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    156156        Time ?=?( Time & time, timespec t ) with( time ) {
    157                 tv = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
     157                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
    158158                return time;
    159159        } // ?=?
    160160
    161         Time ?+?( Time & lhs, Duration rhs ) { return (Time)@{ lhs.tv + rhs.tv }; }
     161        Time ?+?( Time & lhs, Duration rhs ) { return (Time)@{ lhs.tn + rhs.tn }; }
    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.tv - rhs.tv }; }
    166         Time ?-?( Time lhs, Duration rhs ) { return (Time)@{ lhs.tv - rhs.tv }; }
     165        Duration ?-?( Time lhs, Time rhs ) { return (Duration)@{ lhs.tn - rhs.tn }; }
     166        Time ?-?( Time lhs, Duration rhs ) { return (Time)@{ lhs.tn - rhs.tn }; }
    167167        Time ?-=?( Time & lhs, Duration rhs ) { lhs = lhs - rhs; return lhs; }
    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; }
     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; }
    174176} // distribution
    175177
     
    189191} // dmy
    190192
    191 size_t strftime( char * buf, size_t size, const char * fmt, Time time );
     193size_t strftime( char buf[], size_t size, const char fmt[], Time time );
    192194
    193195//------------------------- timeval (cont) -------------------------
    194196
    195197static inline void ?{}( timeval & t, Time time ) with( t, time ) {
    196         tv_sec = tv / TIMEGRAN;                                                         // seconds
    197         tv_usec = tv % TIMEGRAN / (TIMEGRAN / 1_000_000LL);     // microseconds
     198        tv_sec = tn / TIMEGRAN;                                                         // seconds
     199        tv_usec = tn % TIMEGRAN / (TIMEGRAN / 1_000_000LL);     // microseconds
    198200} // ?{}
    199201
     
    201203
    202204static inline void ?{}( timespec & t, Time time ) with( t, time ) {
    203         tv_sec = tv / TIMEGRAN;                                                         // seconds
    204         tv_nsec = tv % TIMEGRAN;                                                        // nanoseconds
     205        tv_sec = tn / TIMEGRAN;                                                         // seconds
     206        tv_nsec = tn % TIMEGRAN;                                                        // nanoseconds
    205207} // ?{}
    206208
  • libcfa/src/time_t.hfa

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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Thu May 09 15::37::05 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:21:46 2019
    13 // Update Count     : 13
     12// Last Modified On : Wed Dec 11 21:39:32 2019
     13// Update Count     : 33
    1414//
    1515
     
    245245                auto decl = new StructDecl(
    246246                        node->name,
    247                         node->kind,
     247                        (AggregateDecl::Aggregate)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
    495507        const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    496508                if ( inCache( node ) ) return nullptr;
     
    686698
    687699        const ast::Expr * visit( const ast::KeywordCastExpr * node ) override final {
    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 );
     700                AggregateDecl::Aggregate castTarget = (AggregateDecl::Aggregate)node->target;
     701                assert( AggregateDecl::Generator <= castTarget && castTarget <= AggregateDecl::Thread );
    703702                auto expr = visitBaseExpr( node,
    704703                        new KeywordCastExpr(
     
    12471246                                cv( node ),
    12481247                                node->name,
    1249                                 node->kind == ast::TypeVar::Ftype,
     1248                                node->kind == ast::TypeDecl::Ftype,
    12501249                                get<Attribute>().acceptL( node->attributes )
    12511250                        };
     
    15151514                        old->location,
    15161515                        old->name,
    1517                         old->kind,
     1516                        (ast::AggregateDecl::Aggregate)old->kind,
    15181517                        GET_ACCEPT_V(attributes, Attribute),
    15191518                        { old->linkage.val }
     
    16021601                        { old->storageClasses.val },
    16031602                        GET_ACCEPT_1(base, Type),
    1604                         (ast::TypeVar::Kind)(unsigned)old->kind,
     1603                        (ast::TypeDecl::Kind)(unsigned)old->kind,
    16051604                        old->sized,
    16061605                        GET_ACCEPT_1(init, Type)
     
    18831882        }
    18841883
     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
    18851902        virtual void visit( const WaitForStmt * old ) override final {
    18861903                if ( inCache( old ) ) return;
     
    20562073        }
    20572074
    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 );
     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 );
    20742078                this->node = visitBaseExpr( old,
    20752079                        new ast::KeywordCastExpr(
     
    25992603                        ty = new ast::TypeInstType{
    26002604                                old->name,
    2601                                 old->isFtype ? ast::TypeVar::Ftype : ast::TypeVar::Dtype,
     2605                                old->isFtype ? ast::TypeDecl::Ftype : ast::TypeDecl::Dtype,
    26022606                                cv( old ),
    26032607                                GET_ACCEPT_V( attributes, Attribute )
  • src/AST/Decl.cpp

    r71d6bd8 r7030dab  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Thu May 9 10:00:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 16:23:15 2019
     13// Update Count     : 20
    1414//
    1515
     
    1818#include <cassert>             // for assert, strict_dynamic_cast
    1919#include <iostream>
    20 #include <string>
    2120#include <unordered_map>
    2221
     
    2726#include "Node.hpp"            // for readonly
    2827#include "Type.hpp"            // for readonly
    29 #include "Parser/ParseNode.h"  // for DeclarationNode
    3028
    3129namespace ast {
     
    5856// --- TypeDecl
    5957
    60 std::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 ];
     58const 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'
    6663}
    6764
    68 std::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." );
     65const 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." );
    7269        return kindNames[ kind ];
    7370}
     
    7572std::ostream & operator<< ( std::ostream & out, const TypeDecl::Data & data ) {
    7673        return out << data.kind << ", " << data.isComplete;
     74}
     75
     76// --- AggregateDecl
     77
     78// These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
     79static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
     80
     81const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
     82        return aggregateNames[aggr];
    7783}
    7884
  • src/AST/Decl.hpp

    r71d6bd8 r7030dab  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Thu May 9 10:00:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 17:38:33 2019
     13// Update Count     : 29
    1414//
    1515
     
    2020#include <unordered_map>
    2121#include <vector>
     22#include <algorithm>
    2223
    2324#include "FunctionSpec.hpp"
     
    2728#include "ParseNode.hpp"
    2829#include "StorageClasses.hpp"
    29 #include "TypeVar.hpp"
    3030#include "Visitor.hpp"
    31 #include "Parser/ParseNode.h"  // for DeclarationNode::Aggregate
     31#include "Common/utility.h"
     32#include "Common/SemanticError.h"                                               // error_str
    3233
    3334// Must be included in *all* AST classes; should be #undef'd at the end of the file
     
    127128        std::vector< ptr<Expr> > withExprs;
    128129
    129         FunctionDecl( const CodeLocation & loc, const std::string &name, FunctionType * type,
     130        FunctionDecl( const CodeLocation & loc, const std::string & name, FunctionType * type,
    130131                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    131132                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
     
    138139        bool has_body() const { return stmts; }
    139140
    140         const DeclWithType * accept( Visitor &v ) const override { return v.visit( this ); }
     141        const DeclWithType * accept( Visitor & v ) const override { return v.visit( this ); }
    141142private:
    142143        FunctionDecl * clone() const override { return new FunctionDecl( *this ); }
     
    151152        std::vector<ptr<DeclWithType>> assertions;
    152153
    153         NamedTypeDecl( 
     154        NamedTypeDecl(
    154155                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    155156                const Type * b, Linkage::Spec spec = Linkage::Cforall )
     
    157158
    158159        /// Produces a name for the kind of alias
    159         virtual std::string typeString() const = 0;
     160        virtual const char * typeString() const = 0;
    160161
    161162private:
     
    166167/// Cforall type variable: `dtype T`
    167168class TypeDecl final : public NamedTypeDecl {
    168 public:
    169         TypeVar::Kind kind;
     169  public:
     170        enum Kind { Dtype, Otype, Ftype, Ttype, NUMBER_OF_KINDS };
     171
     172        Kind kind;
    170173        bool sized;
    171174        ptr<Type> init;
     
    173176        /// Data extracted from a type decl
    174177        struct Data {
    175                 TypeVar::Kind kind;
     178                Kind kind;
    176179                bool isComplete;
    177180
    178                 Data() : kind( (TypeVar::Kind)-1 ), isComplete( false ) {}
     181                Data() : kind( NUMBER_OF_KINDS ), isComplete( false ) {}
    179182                Data( const TypeDecl * d ) : kind( d->kind ), isComplete( d->sized ) {}
    180                 Data( TypeVar::Kind k, bool c ) : kind( k ), isComplete( c ) {}
     183                Data( Kind k, bool c ) : kind( k ), isComplete( c ) {}
    181184                Data( const Data & d1, const Data & d2 )
    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); }
     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); }
    188189        };
    189190
    190         TypeDecl( 
    191                 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 
     191        TypeDecl(
     192                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
    192193                const Type * b, TypeVar::Kind k, bool s, const Type * i = nullptr )
    193194        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ),
    194195          init( i ) {}
    195196
    196         std::string typeString() const override;
     197        const char * typeString() const override;
    197198        /// Produces a name for generated code
    198         std::string genTypeString() const;
     199        const char * genTypeString() const;
    199200
    200201        /// convenience accessor to match Type::isComplete()
     
    202203
    203204        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    204 private:
     205  private:
    205206        TypeDecl * clone() const override { return new TypeDecl{ *this }; }
    206207        MUTATE_FRIEND
     
    216217        : NamedTypeDecl( loc, name, storage, b, spec ) {}
    217218
    218         std::string typeString() const override { return "typedef"; }
     219        const char * typeString() const override { return "typedef"; }
    219220
    220221        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    227228class AggregateDecl : public Decl {
    228229public:
     230        enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
     231        static const char * aggrString( Aggregate aggr );
     232
    229233        std::vector<ptr<Decl>> members;
    230234        std::vector<ptr<TypeDecl>> params;
     
    241245
    242246        /// Produces a name for the kind of aggregate
    243         virtual std::string typeString() const = 0;
     247        virtual const char * typeString() const = 0;
    244248
    245249private:
     
    251255class StructDecl final : public AggregateDecl {
    252256public:
    253         DeclarationNode::Aggregate kind;
     257        Aggregate kind;
    254258
    255259        StructDecl( const CodeLocation& loc, const std::string& name,
    256                 DeclarationNode::Aggregate kind = DeclarationNode::Struct,
     260                Aggregate kind = Struct,
    257261                std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
    258262        : AggregateDecl( loc, name, std::move(attrs), linkage ), kind( kind ) {}
    259263
    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"; }
     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 ); }
    267272
    268273private:
     
    280285        const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
    281286
    282         std::string typeString() const override { return "union"; }
     287        const char * typeString() const override { return aggrString( Union ); }
    283288
    284289private:
     
    299304        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    300305
    301         std::string typeString() const override { return "enum"; }
     306        const char * typeString() const override { return aggrString( Enum ); }
    302307
    303308private:
     
    318323        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
    319324
    320         std::string typeString() const override { return "trait"; }
     325        const char * typeString() const override { return "trait"; }
    321326
    322327private:
     
    344349        ptr<AsmStmt> stmt;
    345350
    346         AsmDecl( const CodeLocation & loc, AsmStmt *stmt )
     351        AsmDecl( const CodeLocation & loc, AsmStmt * stmt )
    347352        : Decl( loc, "", {}, {} ), stmt(stmt) {}
    348353
    349         const AsmDecl * accept( Visitor &v ) const override { return v.visit( this ); }
    350 private:
    351         AsmDecl *clone() const override { return new AsmDecl( *this ); }
     354        const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     355private:
     356        AsmDecl * clone() const override { return new AsmDecl( *this ); }
    352357        MUTATE_FRIEND
    353358};
     
    361366        : Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {}
    362367
    363         const StaticAssertDecl * accept( Visitor &v ) const override { return v.visit( this ); }
     368        const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); }
    364369private:
    365370        StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); }
  • src/AST/Expr.cpp

    r71d6bd8 r7030dab  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May 15 17:00:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Created On       : Fri Oct  4 15:34:00 2019
    13 // Update Count     : 4
     11// Last Modified By : Peter A. Buhr
     12// Created On       : Thr Jun 13 13:38:00 2019
     13// Update Count     : 6
    1414//
    1515
     
    163163// --- KeywordCastExpr
    164164
    165 const 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];
     165const char * KeywordCastExpr::targetString() const {
     166        return AggregateDecl::aggrString( target );
    174167}
    175168
  • src/AST/Expr.hpp

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

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

    r71d6bd8 r7030dab  
    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;
    116117        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    117118        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    r71d6bd8 r7030dab  
    838838
    839839//--------------------------------------------------------------------------
     840// FinallyStmt
     841template< typename pass_t >
     842const 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//--------------------------------------------------------------------------
    840853// WaitForStmt
    841854template< typename pass_t >
  • src/AST/Print.cpp

    r71d6bd8 r7030dab  
    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;
    676695
    677696                return node;
     
    13591378                preprint( node );
    13601379                os << "instance of type " << node->name
    1361                    << " (" << (node->kind == ast::TypeVar::Ftype ? "" : "not ") << "function type)";
     1380                   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
    13621381                print( node->params );
    13631382
  • src/AST/Stmt.hpp

    r71d6bd8 r7030dab  
    344344};
    345345
     346/// Suspend statement
     347class SuspendStmt final : public Stmt {
     348public:
     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 ); }
     356private:
     357        SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }
     358        MUTATE_FRIEND
     359};
     360
    346361/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
    347362class WaitForStmt final : public Stmt {
  • src/AST/Type.cpp

    r71d6bd8 r7030dab  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon May 13 15:00:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Dec 15 16:56:28 2019
     13// Update Count     : 4
    1414//
    1515
     
    5050// --- BasicType
    5151
    52 const char *BasicType::typeNames[] = {
     52// GENERATED START, DO NOT EDIT
     53// GENERATED BY BasicTypes-gen.cc
     54const char * BasicType::typeNames[] = {
    5355        "_Bool",
    5456        "char",
     
    8890        "_Float128x _Complex",
    8991};
    90 static_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 );
     92// GENERATED END
    9493
    9594// --- ParameterizedType
  • src/AST/Type.hpp

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

    r71d6bd8 r7030dab  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed May 29 11:00:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed May 29 11:00:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 21:49:13 2019
     13// Update Count     : 4
    1414//
    1515
     
    240240                return true;
    241241        } else if ( auto typeInst = dynamic_cast< const TypeInstType * >( type ) ) {
    242                 return typeInst->kind == TypeVar::Ftype;
     242                return typeInst->kind == TypeDecl::Ftype;
    243243        } else return false;
    244244}
     
    248248        bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) {
    249249                switch ( data.kind ) {
    250                   case TypeVar::Dtype:
     250                  case TypeDecl::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 TypeVar::Ftype:
     256                  case TypeDecl::Ftype:
    257257                        return isFtype( type );
    258                   case TypeVar::Ttype:
     258                  case TypeDecl::Ttype:
    259259                        // ttype unifies with any tuple type
    260260                        return dynamic_cast< const TupleType * >( type ) || Tuples::isTtype( type );
  • src/AST/TypeEnvironment.hpp

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

    r71d6bd8 r7030dab  
    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;
    4950    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5051    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
  • src/AST/module.mk

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

    r71d6bd8 r7030dab  
    273273
    274274
    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 );
     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 );
    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", Type );
    292         code << str.substr( start );
    293 
    294         output( file, Type, code );
     291        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );
     292        code << str.substr( start );
     293
     294        output( file, TypeH, code );
     295        // cout << code.str();
     296
     297
     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 );
    295316        // cout << code.str();
    296317
    297318
    298319        // TEMPORARY DURING CHANGE OVER
    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 );
     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 );
    303324        start += sizeof( STARTMK );                                                     // includes newline
    304325        code << str.substr( 0, start );
     
    313334        code << "\t";                                                                           // indentation for end marker
    314335
    315         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeAST );
    316         code << str.substr( start );
    317 
    318         output( file, TypeAST, code );
     336        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
     337        code << str.substr( start );
     338
     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 );
    319361        // cout << code.str();
    320362
  • src/CodeGen/CodeGenerator.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Oct 19 19:30:38 2019
    13 // Update Count     : 506
     12// Last Modified On : Sun Feb 16 08:32:48 2020
     13// Update Count     : 532
    1414//
    1515#include "CodeGenerator.h"
     
    2323#include "InitTweak/InitTweak.h"     // for getPointerBase
    2424#include "OperatorTable.h"           // for OperatorInfo, operatorLookup
    25 #include "Parser/LinkageSpec.h"      // for Spec, Intrinsic
     25#include "SynTree/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
    81          * within a node should become the method of formating.
    82          */
     80        // Using updateLocation at the beginning of a node and endl within a node should become the method of formating.
    8381        void CodeGenerator::updateLocation( CodeLocation const & to ) {
    8482                // skip if linemarks shouldn't appear or if codelocation is unset
     
    9593                } else {
    9694                        output << "\n# " << to.first_line << " \"" << to.filename
    97                                << "\"\n" << indent;
     95                                   << "\"\n" << indent;
    9896                        currentLocation = to;
    9997                }
     
    131129
    132130        void CodeGenerator::genAttributes( list< Attribute * > & attributes ) {
    133           if ( attributes.empty() ) return;
     131                if ( attributes.empty() ) return;
    134132                output << "__attribute__ ((";
    135133                for ( list< Attribute * >::iterator attr( attributes.begin() );; ) {
     
    140138                                output << ")";
    141139                        } // if
    142                   if ( ++attr == attributes.end() ) break;
     140                        if ( ++attr == attributes.end() ) break;
    143141                        output << ",";                                                          // separator
    144142                } // for
     
    165163                previsit( (BaseSyntaxNode *)node );
    166164                GuardAction( [this, node](){
    167                         if ( options.printExprTypes && node->result ) {
    168                                 output << " /* " << genType( node->result, "", options ) << " */ ";
    169                         }
    170                 } );
     165                                if ( options.printExprTypes && node->result ) {
     166                                        output << " /* " << genType( node->result, "", options ) << " */ ";
     167                                }
     168                        } );
    171169        }
    172170
     
    399397                extension( applicationExpr );
    400398                if ( VariableExpr * varExpr = dynamic_cast< VariableExpr* >( applicationExpr->get_function() ) ) {
    401                         OperatorInfo opInfo;
    402                         if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( varExpr->get_var()->get_name(), opInfo ) ) {
     399                        const OperatorInfo * opInfo;
     400                        if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && ( opInfo = operatorLookup( varExpr->get_var()->get_name() ) ) ) {
    403401                                std::list< Expression* >::iterator arg = applicationExpr->get_args().begin();
    404                                 switch ( opInfo.type ) {
     402                                switch ( opInfo->type ) {
    405403                                  case OT_INDEX:
    406404                                        assert( applicationExpr->get_args().size() == 2 );
     
    423421                                                output << "(";
    424422                                                (*arg++)->accept( *visitor );
    425                                                 output << ") /* " << opInfo.inputName << " */";
     423                                                output << ") /* " << opInfo->inputName << " */";
    426424                                        } else if ( applicationExpr->get_args().size() == 2 ) {
    427425                                                // intrinsic two parameter constructors are essentially bitwise assignment
    428426                                                output << "(";
    429427                                                (*arg++)->accept( *visitor );
    430                                                 output << opInfo.symbol;
     428                                                output << opInfo->symbol;
    431429                                                (*arg)->accept( *visitor );
    432                                                 output << ") /* " << opInfo.inputName << " */";
     430                                                output << ") /* " << opInfo->inputName << " */";
    433431                                        } else {
    434432                                                // no constructors with 0 or more than 2 parameters
     
    441439                                        assert( applicationExpr->get_args().size() == 1 );
    442440                                        output << "(";
    443                                         output << opInfo.symbol;
     441                                        output << opInfo->symbol;
    444442                                        (*arg)->accept( *visitor );
    445443                                        output << ")";
     
    450448                                        assert( applicationExpr->get_args().size() == 1 );
    451449                                        (*arg)->accept( *visitor );
    452                                         output << opInfo.symbol;
     450                                        output << opInfo->symbol;
    453451                                        break;
    454452
     
    459457                                        output << "(";
    460458                                        (*arg++)->accept( *visitor );
    461                                         output << opInfo.symbol;
     459                                        output << opInfo->symbol;
    462460                                        (*arg)->accept( *visitor );
    463461                                        output << ")";
     
    486484                extension( untypedExpr );
    487485                if ( NameExpr * nameExpr = dynamic_cast< NameExpr* >( untypedExpr->function ) ) {
    488                         OperatorInfo opInfo;
    489                         if ( operatorLookup( nameExpr->name, opInfo ) ) {
     486                        const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
     487                        if ( opInfo ) {
    490488                                std::list< Expression* >::iterator arg = untypedExpr->args.begin();
    491                                 switch ( opInfo.type ) {
     489                                switch ( opInfo->type ) {
    492490                                  case OT_INDEX:
    493491                                        assert( untypedExpr->args.size() == 2 );
     
    508506                                                output << "(";
    509507                                                (*arg++)->accept( *visitor );
    510                                                 output << ") /* " << opInfo.inputName << " */";
     508                                                output << ") /* " << opInfo->inputName << " */";
    511509                                        } else if ( untypedExpr->get_args().size() == 2 ) {
    512510                                                // intrinsic two parameter constructors are essentially bitwise assignment
    513511                                                output << "(";
    514512                                                (*arg++)->accept( *visitor );
    515                                                 output << opInfo.symbol;
     513                                                output << opInfo->symbol;
    516514                                                (*arg)->accept( *visitor );
    517                                                 output << ") /* " << opInfo.inputName << " */";
     515                                                output << ") /* " << opInfo->inputName << " */";
    518516                                        } else {
    519517                                                // no constructors with 0 or more than 2 parameters
     
    521519                                                output << "(";
    522520                                                (*arg++)->accept( *visitor );
    523                                                 output << opInfo.symbol << "{ ";
     521                                                output << opInfo->symbol << "{ ";
    524522                                                genCommaList( arg, untypedExpr->args.end() );
    525                                                 output << "}) /* " << opInfo.inputName << " */";
     523                                                output << "}) /* " << opInfo->inputName << " */";
    526524                                        } // if
    527525                                        break;
     
    532530                                        assert( untypedExpr->args.size() == 1 );
    533531                                        output << "(";
    534                                         output << opInfo.symbol;
     532                                        output << opInfo->symbol;
    535533                                        (*arg)->accept( *visitor );
    536534                                        output << ")";
     
    541539                                        assert( untypedExpr->args.size() == 1 );
    542540                                        (*arg)->accept( *visitor );
    543                                         output << opInfo.symbol;
     541                                        output << opInfo->symbol;
    544542                                        break;
    545543
     
    549547                                        output << "(";
    550548                                        (*arg++)->accept( *visitor );
    551                                         output << opInfo.symbol;
     549                                        output << opInfo->symbol;
    552550                                        (*arg)->accept( *visitor );
    553551                                        output << ")";
     
    581579        void CodeGenerator::postvisit( NameExpr * nameExpr ) {
    582580                extension( nameExpr );
    583                 OperatorInfo opInfo;
    584                 if ( operatorLookup( nameExpr->name, opInfo ) ) {
    585                         if ( opInfo.type == OT_CONSTANT ) {
    586                                 output << opInfo.symbol;
     581                const OperatorInfo * opInfo = operatorLookup( nameExpr->name );
     582                if ( opInfo ) {
     583                        if ( opInfo->type == OT_CONSTANT ) {
     584                                output << opInfo->symbol;
    587585                        } else {
    588                                 output << opInfo.outputName;
     586                                output << opInfo->outputName;
    589587                        }
    590588                } else {
     
    654652        void CodeGenerator::postvisit( VariableExpr * variableExpr ) {
    655653                extension( variableExpr );
    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;
     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;
    659657                } else {
    660658                        output << mangleName( variableExpr->get_var() );
     
    10111009                  case BranchStmt::FallThroughDefault:
    10121010                        assertf( ! options.genC, "fallthru should not reach code generation." );
    1013                   output << "fallthru";
     1011                        output << "fallthru";
    10141012                        break;
    10151013                } // switch
     
    10351033
    10361034                output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
    1037                            "throw" : "throwResume");
     1035                                   "throw" : "throwResume");
    10381036                if (throwStmt->get_expr()) {
    10391037                        output << " ";
     
    10501048
    10511049                output << ((stmt->get_kind() == CatchStmt::Terminate) ?
    1052                 "catch" : "catchResume");
     1050                                   "catch" : "catchResume");
    10531051                output << "( ";
    10541052                stmt->decl->accept( *visitor );
     
    11871185
    11881186        std::string genName( DeclarationWithType * decl ) {
    1189                 CodeGen::OperatorInfo opInfo;
    1190                 if ( operatorLookup( decl->get_name(), opInfo ) ) {
    1191                         return opInfo.outputName;
     1187                const OperatorInfo * opInfo = operatorLookup( decl->get_name() );
     1188                if ( opInfo ) {
     1189                        return opInfo->outputName;
    11921190                } else {
    11931191                        return decl->get_name();
  • src/CodeGen/CodeGenerator.h

    r71d6bd8 r7030dab  
    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 : Tue Apr 30 12:01:00 2019
    13 // Update Count     : 57
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Feb 16 03:58:31 2020
     13// Update Count     : 62
    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

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

    r71d6bd8 r7030dab  
    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 : Wed Jun 28 15:26:00 2017
    13 // Update Count     : 20
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:39:14 2019
     13// Update Count     : 21
    1414//
    1515
     
    2222#include "Common/SemanticError.h"  // for SemanticError
    2323#include "FixMain.h"               // for FixMain
    24 #include "Parser/LinkageSpec.h"    // for Cforall, isMangled
    2524#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

    r71d6bd8 r7030dab  
    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 : Tue Apr 30 11:47:00 2019
    13 // Update Count     : 3
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Feb 16 04:11:40 2020
     13// Update Count     : 5
    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

    r71d6bd8 r7030dab  
    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 : Fri Aug 18 15:39:00 2017
    13 // Update Count     : 7
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sun Feb 16 03:01:51 2020
     13// Update Count     : 9
    1414//
    1515#include "Generate.h"
     
    2222#include "GenType.h"                 // for genPrettyType
    2323#include "Common/PassVisitor.h"      // for PassVisitor
    24 #include "Parser/LinkageSpec.h"      // for isBuiltin, isGeneratable
     24#include "SynTree/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 << CodeGen::genPrettyType( type, "" );
     66                        os << genPrettyType( type, "" );
    6767                } else {
    6868                        PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
  • src/CodeGen/OperatorTable.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 15 17:12:22 2017
    13 // Update Count     : 15
     12// Last Modified On : Tue Feb 18 15:55:01 2020
     13// Update Count     : 55
    1414//
    1515
     
    1717#include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
    1818#include <utility>    // for pair
     19using namespace std;
    1920
    2021#include "OperatorTable.h"
     
    2223
    2324namespace CodeGen {
    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                 };
     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
    6970
    70                 const int numOps = sizeof( tableValues ) / sizeof( OperatorInfo );
     71        std::map< std::string, OperatorInfo > CodeGen::table;
    7172
    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
     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
    10278        }
    10379
    104         bool isOperator( const std::string & funcName ) {
    105                 OperatorInfo info;
    106                 return operatorLookup( funcName, info );
     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;
    10785        }
    10886
    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                 }
     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;
    116100                return false;
    117101        }
    118102
    119         bool isConstructor( const std::string & funcName ) {
    120                 static OperatorType types[] = { OT_CTOR };
    121                 return isOperatorType( funcName, std::begin(types), std::end(types) );
     103        bool isDestructor( const string & funcName ) {
     104                const OperatorInfo * info = operatorLookup( funcName );
     105                if ( info ) return info->type == OT_DTOR;
     106                return false;
    122107        }
    123108
    124         bool isDestructor( const std::string & funcName ) {
    125                 static OperatorType types[] = { OT_DTOR };
    126                 return isOperatorType( funcName, std::begin(types), std::end(types) );
     109        bool isCtorDtor( const string & funcName ) {
     110                const OperatorInfo * info = operatorLookup( funcName );
     111                if ( info ) return info->type <= OT_CONSTRUCTOR;
     112                return false;
    127113        }
    128114
    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) );
     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;
    132119        }
    133120
    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) );
     121        bool isCtorDtorAssign( const string & funcName ) {
     122                const OperatorInfo * info = operatorLookup( funcName );
     123                if ( info ) return info->type <= OT_ASSIGNMENT;
     124                return false;
    137125        }
    138126
    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         }
     127        CodeGen codegen;                                                                        // initialize singleton package
    143128} // namespace CodeGen
    144129
    145130// Local Variables: //
    146131// tab-width: 4 //
    147 // mode: c++ //
    148 // compile-command: "make install" //
    149132// End: //
  • src/CodeGen/OperatorTable.h

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 22:17:11 2017
    13 // Update Count     : 6
     12// Last Modified On : Sun Feb 16 08:13:34 2020
     13// Update Count     : 26
    1414//
    1515
     
    1717
    1818#include <string>
     19#include <map>
    1920
    2021namespace CodeGen {
    2122        enum OperatorType {
    22                 OT_INDEX,
    2323                OT_CTOR,
    2424                OT_DTOR,
    25                 OT_CALL,
    26                 OT_PREFIX,
    27                 OT_POSTFIX,
    28                 OT_INFIX,
     25                OT_CONSTRUCTOR = OT_DTOR,
    2926                OT_PREFIXASSIGN,
    3027                OT_POSTFIXASSIGN,
    3128                OT_INFIXASSIGN,
     29                OT_ASSIGNMENT = OT_INFIXASSIGN,
     30                OT_CALL,
     31                OT_PREFIX,
     32                OT_INFIX,
     33                OT_POSTFIX,
     34                OT_INDEX,
    3235                OT_LABELADDRESS,
    3336                OT_CONSTANT
     
    3841                std::string symbol;
    3942                std::string outputName;
     43                std::string friendlyName;
    4044                OperatorType type;
    4145        };
    4246
     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
    4356        bool isOperator( const std::string & funcName );
    44         bool operatorLookup( const std::string & funcName, OperatorInfo & info );
     57        const OperatorInfo * operatorLookup( const std::string & funcName );
     58        std::string operatorFriendlyName( const std::string & funcName );
    4559
    4660        bool isConstructor( const std::string & );
  • src/CodeGen/Options.h

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

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

    r71d6bd8 r7030dab  
    99// Author           : Aaron Moss
    1010// Created On       : Wed Jan 31 16:40:00 2016
    11 // Last Modified By : Aaron Moss
    12 // Last Modified On : Wed Jan 31 16:40:00 2016
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:39:33 2019
     13// Update Count     : 2
    1414//
    1515
     
    2626#include "Common/VectorMap.h"      // for VectorMap
    2727#include "GenPoly/GenPoly.h"       // for hasPolyBase
    28 #include "Parser/LinkageSpec.h"    // for ::NoOfSpecs, Spec
     28#include "SynTree/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

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

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

    r71d6bd8 r7030dab  
    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;
    112114        virtual void visit( WaitForStmt * waitforStmt ) override final;
    113115        virtual void visit( const WaitForStmt * waitforStmt ) override final;
     
    276278        virtual Statement * mutate( CatchStmt * catchStmt ) override final;
    277279        virtual Statement * mutate( FinallyStmt * finallyStmt ) override final;
     280        virtual Statement * mutate( SuspendStmt * suspendStmt ) override final;
    278281        virtual Statement * mutate( WaitForStmt * waitforStmt ) override final;
    279282        virtual Declaration * mutate( WithStmt * withStmt ) override final;
  • src/Common/PassVisitor.impl.h

    r71d6bd8 r7030dab  
    15221522
    15231523//--------------------------------------------------------------------------
     1524// SuspendStmt
     1525template< typename pass_type >
     1526void PassVisitor< pass_type >::visit( SuspendStmt * node ) {
     1527        VISIT_START( node );
     1528
     1529        maybeAccept_impl( node->then  , *this );
     1530
     1531        VISIT_END( node );
     1532}
     1533
     1534template< typename pass_type >
     1535void 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
     1543template< typename pass_type >
     1544Statement * 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//--------------------------------------------------------------------------
    15241553// WaitForStmt
    15251554template< typename pass_type >
     
    33023331        VISIT_START( node );
    33033332
    3304         indexerAddStruct( node->name );
     3333        indexerAddUnion( node->name );
    33053334
    33063335        {
     
    33173346        VISIT_START( node );
    33183347
    3319         indexerAddStruct( node->name );
     3348        indexerAddUnion( node->name );
    33203349
    33213350        {
     
    33323361        MUTATE_START( node );
    33333362
    3334         indexerAddStruct( node->name );
     3363        indexerAddUnion( node->name );
    33353364
    33363365        {
  • src/Common/SemanticError.cc

    r71d6bd8 r7030dab  
    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
    151157        const std::string & error_str() {
    152                 static std::string str = isatty( STDERR_FILENO ) ? "\e[31merror:\e[39m " : "error: ";
     158                static std::string str = with_colors() ? "\e[31merror:\e[39m " : "error: ";
    153159                return str;
    154160        }
    155161
    156162        const std::string & warning_str() {
    157                 static std::string str = isatty( STDERR_FILENO ) ? "\e[95mwarning:\e[39m " : "warning: ";
     163                static std::string str = with_colors() ? "\e[95mwarning:\e[39m " : "warning: ";
    158164                return str;
    159165        }
    160166
    161167        const std::string & bold_ttycode() {
    162                 static std::string str = isatty( STDERR_FILENO ) ? "\e[1m" : "";
     168                static std::string str = with_colors() ? "\e[1m" : "";
    163169                return str;
    164170        }
    165171
    166172        const std::string & reset_font_ttycode() {
    167                 static std::string str = isatty( STDERR_FILENO ) ? "\e[0m" : "";
     173                static std::string str = with_colors() ? "\e[0m" : "";
    168174                return str;
    169175        }
  • src/Common/SemanticError.h

    r71d6bd8 r7030dab  
    4949struct WarningData {
    5050        const char * const name;
     51        const Severity default_severity;
    5152        const char * const message;
    52         const Severity default_severity;
    5353};
    5454
    5555constexpr WarningData WarningFormats[] = {
    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},
     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" },
    6263};
    6364
     
    6970        SuperfluousDecl,
    7071        GccAttributes,
     72        CppCopy,
    7173        NUMBER_OF_WARNINGS, // This MUST be the last warning
    7274};
     
    9799// Helpers
    98100namespace ErrorHelpers {
     101        enum class Colors {
     102                Never = false,
     103                Always = true,
     104                Auto,
     105        };
     106
     107        extern Colors colors;
     108
    99109        const std::string & error_str();
    100110        const std::string & warning_str();
  • src/Common/Stats/Time.h

    r71d6bd8 r7030dab  
    99// Author           : Thierry Delisle
    1010// Created On       : Fri Mar 01 15:14:11 2019
    11 // Last Modified By :
     11// Last Modified By : Andrew Beach
    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                        }
    4349#               else
    4450                        void StartGlobal();
     
    5965                                func();
    6066                        }
     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                        }
    6174#               endif
    6275        }
  • src/Common/utility.h

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 24 14:28:19 2019
    13 // Update Count     : 41
     12// Last Modified On : Tue Feb 11 13:00:36 2020
     13// Update Count     : 50
    1414//
    1515
     
    2929#include <utility>
    3030#include <vector>
     31#include <cstring>                                                                              // memcmp
    3132
    3233#include "Common/Indenter.h"
     
    264265}
    265266
    266 /// determines if `pref` is a prefix of `str`
    267 static inline bool isPrefix( const std::string & str, const std::string & pref ) {
     267// determines if pref is a prefix of str
     268static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
    268269        if ( pref.size() > str.size() ) return false;
    269         auto its = std::mismatch( pref.begin(), pref.end(), str.begin() );
    270         return its.first == pref.end();
     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
    271272}
    272273
  • src/Concurrency/Keywords.cc

    r71d6bd8 r7030dab  
    1111// Last Modified By :
    1212// Last Modified On :
    13 // Update Count     : 5
     13// Update Count     : 10
    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 "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
     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
    3536
    3637class Attribute;
     
    5354          public:
    5455
    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 ) :
     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 ) :
    5657                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
    5758
     
    5960
    6061                Declaration * postmutate( StructDecl * decl );
     62                DeclarationWithType * postmutate( FunctionDecl * decl );
    6163
    6264                void handle( StructDecl * );
     
    7577                const std::string context_error;
    7678                bool needs_main;
    77                 KeywordCastExpr::Target cast_target;
    78 
    79                 StructDecl* type_decl = nullptr;
     79                AggregateDecl::Aggregate cast_target;
     80
     81                StructDecl   * type_decl = nullptr;
     82                FunctionDecl * dtor_decl = nullptr;
    8083        };
    8184
     
    8689        //      int data;                                  int data;
    8790        //      a_struct_t more_data;                      a_struct_t more_data;
    88         //                                =>             thread_desc __thrd_d;
     91        //                                =>             $thread __thrd_d;
    8992        // };                                        };
    90         //                                           static inline thread_desc * get_thread( MyThread * this ) { return &this->__thrd_d; }
     93        //                                           static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
    9194        //
    9295        class ThreadKeyword final : public ConcurrentSueKeyword {
     
    9497
    9598                ThreadKeyword() : ConcurrentSueKeyword(
    96                         "thread_desc",
     99                        "$thread",
    97100                        "__thrd",
    98101                        "get_thread",
    99                         "thread keyword requires threads to be in scope, add #include <thread.hfa>",
     102                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
    100103                        true,
    101                         KeywordCastExpr::Thread
     104                        AggregateDecl::Thread
    102105                )
    103106                {}
     
    118121        //      int data;                                  int data;
    119122        //      a_struct_t more_data;                      a_struct_t more_data;
    120         //                                =>             coroutine_desc __cor_d;
     123        //                                =>             $coroutine __cor_d;
    121124        // };                                        };
    122         //                                           static inline coroutine_desc * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
     125        //                                           static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
    123126        //
    124127        class CoroutineKeyword final : public ConcurrentSueKeyword {
     
    126129
    127130                CoroutineKeyword() : ConcurrentSueKeyword(
    128                         "coroutine_desc",
     131                        "$coroutine",
    129132                        "__cor",
    130133                        "get_coroutine",
    131                         "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>",
     134                        "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
    132135                        true,
    133                         KeywordCastExpr::Coroutine
     136                        AggregateDecl::Coroutine
    134137                )
    135138                {}
     
    144147                }
    145148        };
     149
     150
    146151
    147152        //-----------------------------------------------------------------------------
     
    150155        //      int data;                                  int data;
    151156        //      a_struct_t more_data;                      a_struct_t more_data;
    152         //                                =>             monitor_desc __mon_d;
     157        //                                =>             $monitor __mon_d;
    153158        // };                                        };
    154         //                                           static inline monitor_desc * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
     159        //                                           static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
    155160        //
    156161        class MonitorKeyword final : public ConcurrentSueKeyword {
     
    158163
    159164                MonitorKeyword() : ConcurrentSueKeyword(
    160                         "monitor_desc",
     165                        "$monitor",
    161166                        "__mon",
    162167                        "get_monitor",
    163                         "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>",
     168                        "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
    164169                        false,
    165                         KeywordCastExpr::Monitor
     170                        AggregateDecl::Monitor
    166171                )
    167172                {}
     
    178183
    179184        //-----------------------------------------------------------------------------
     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        //-----------------------------------------------------------------------------
    180256        //Handles mutex routines definitions :
    181257        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
    182         //                                                                       monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
     258        //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    183259        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
    184260        //    /*Some code*/                                       =>           /*Some code*/
     
    219295        //Handles mutex routines definitions :
    220296        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
    221         //                                                                       monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
     297        //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    222298        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
    223299        //    /*Some code*/                                       =>           /*Some code*/
     
    249325                CoroutineKeyword        ::implement( translationUnit );
    250326                MonitorKeyword  ::implement( translationUnit );
     327                GeneratorKeyword  ::implement( translationUnit );
     328                SuspendKeyword    ::implement( translationUnit );
    251329        }
    252330
     
    284362        }
    285363
     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
    286382        Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
    287383                if ( cast_target == cast->target ) {
    288                         // convert (thread &)t to (thread_desc &)*get_thread(t), etc.
     384                        // convert (thread &)t to ($thread &)*get_thread(t), etc.
    289385                        if( !type_decl ) SemanticError( cast, context_error );
    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                                 );
     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;
    301391                }
    302392                return cast;
     
    308398
    309399                if( !type_decl ) SemanticError( decl, context_error );
     400                if( !dtor_decl ) SemanticError( decl, context_error );
    310401
    311402                FunctionDecl * func = forwardDeclare( decl );
     
    362453                        get_type,
    363454                        nullptr,
    364                         noAttributes,
     455                        { new Attribute("const") },
    365456                        Type::Inline
    366457                );
     
    431522
    432523                declsToAddAfter.push_back( get_decl );
    433 
    434                 // get_decl->fixUniqueId();
    435         }
     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
    436756
    437757        //=============================================================================================
     
    501821        void MutexKeyword::postvisit(StructDecl* decl) {
    502822
    503                 if( decl->name == "monitor_desc" && decl->body ) {
     823                if( decl->name == "$monitor" && decl->body ) {
    504824                        assert( !monitor_decl );
    505825                        monitor_decl = decl;
     
    597917                );
    598918
    599                 //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
     919                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    600920                body->push_front( new DeclStmt( monitors) );
    601921        }
     
    658978                );
    659979
    660                 //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
     980                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    661981                body->push_front( new DeclStmt( monitors) );
    662982        }
     
    666986        //=============================================================================================
    667987        void ThreadStarter::previsit( StructDecl * decl ) {
    668                 if( decl->name == "thread_desc" && decl->body ) {
     988                if( decl->name == "$thread" && decl->body ) {
    669989                        assert( !thread_decl );
    670990                        thread_decl = decl;
     
    7011021                                new UntypedExpr(
    7021022                                        new NameExpr( "__thrd_start" ),
    703                                         { new VariableExpr( param ) }
     1023                                        { new VariableExpr( param ), new NameExpr("main") }
    7041024                                )
    7051025                        )
  • src/Concurrency/Waitfor.cc

    r71d6bd8 r7030dab  
    1111// Last Modified By :
    1212// Last Modified On :
    13 // Update Count     : 7
     13// Update Count     : 12
    1414//
    1515
     
    2323#include "Common/PassVisitor.h"    // for PassVisitor
    2424#include "Common/SemanticError.h"  // for SemanticError
     25#include "Common/UniqueName.h"     // for UniqueName
    2526#include "Common/utility.h"        // for deleteAll, map_range
    2627#include "CodeGen/OperatorTable.h" // for isConstructor
    2728#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
    3031#include "SynTree/Constant.h"      // for Constant
    3132#include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
     
    4142void foo() {
    4243        while( true ) {
    43                 when( a < 1 ) waitfor( f, a ) { bar(); }
     44                when( a < 1 ) waitfor( f : a ) { bar(); }
    4445                or timeout( swagl() );
    45                 or waitfor( g, a ) { baz(); }
    46                 or waitfor( ^?{}, a ) { break; }
     46                or waitfor( g : a ) { baz(); }
     47                or waitfor( ^?{} : a ) { break; }
    4748                or waitfor( ^?{} ) { break; }
    4849        }
     
    243244                        decl_mask = decl;
    244245                }
    245                 else if( decl->name == "monitor_desc" ) {
     246                else if( decl->name == "$monitor" ) {
    246247                        assert( !decl_monitor );
    247248                        decl_monitor = decl;
  • src/ControlStruct/ExceptTranslate.cc

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

    r71d6bd8 r7030dab  
    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 : Mon Mar 11 22:26:02 2019
    13 // Update Count     : 159
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Jan 21 10:32:00 2020
     13// Update Count     : 160
    1414//
    1515
     
    2121#include "ControlStruct/LabelGenerator.h"  // for LabelGenerator
    2222#include "LabelFixer.h"
    23 #include "MLEMutator.h"                    // for MLEMutator
     23#include "MLEMutator.h"                    // for MultiLevelExitMutator
    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<MLEMutator> mlemut( resolveJumps(), generator );
    47                 functionDecl->acceptMutator( mlemut );
     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 );
    4849        }
    4950
     
    7576
    7677
    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
     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.
    7980        Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {
    8081                assert( definition != 0 );
    8182                assert( llabel.size() > 0 );
    82 
    83                 Entry * e = new Entry( definition );
    8483
    8584                for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) {
     
    8786                        l.set_statement( definition ); // attach statement to the label to be used later
    8887                        if ( labelTable.find( l ) == labelTable.end() ) {
    89                                 // all labels on this statement need to use the same entry, so this should only be created once
     88                                // All labels on this statement need to use the same entry,
     89                                // so this should only be created once.
    9090                                // undefined and unused until now, add an entry
    91                                 labelTable[ l ] =  e;
     91                                labelTable[ l ] = new Entry( definition );
    9292                        } else if ( labelTable[ l ]->defined() ) {
    9393                                // defined twice, error
    94                                 SemanticError( l.get_statement()->location, "Duplicate definition of label: " + l.get_name() );
    95                         }       else {
     94                                SemanticError( l.get_statement()->location,
     95                                        "Duplicate definition of label: " + l.get_name() );
     96                        } else {
    9697                                // used previously, but undefined until now -> link with this entry
     98                                // Question: Is changing objects important?
    9799                                delete labelTable[ l ];
    98                                 labelTable[ l ] = e;
     100                                labelTable[ l ] = new Entry( definition );
    99101                        } // if
    100102                } // for
    101103
    102                 // produce one of the labels attached to this statement to be temporarily used as the canonical label
     104                // Produce one of the labels attached to this statement to be temporarily used as the
     105                // canonical label.
    103106                return labelTable[ llabel.front() ]->get_label();
    104107        }
  • src/ControlStruct/MLEMutator.cc

    r71d6bd8 r7030dab  
    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 : Tue Oct 22 17:22:44 2019
    13 // Update Count     : 220
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jan 22 11:50:00 2020
     13// Update Count     : 223
    1414//
    1515
     
    3333
    3434namespace ControlStruct {
    35         MLEMutator::~MLEMutator() {
     35        MultiLevelExitMutator::~MultiLevelExitMutator() {
    3636                delete targetTable;
    3737                targetTable = 0;
    3838        }
    3939        namespace {
    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 ); }
     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                }
    4761        } // namespace
     62
     63        void MultiLevelExitMutator::premutate( FunctionDecl * ) {
     64                visit_children = false;
     65        }
    4866
    4967        // break labels have to come after the statement they break out of, so mutate a statement, then if they inform us
    5068        // through the breakLabel field tha they need a place to jump to on a break statement, add the break label to the
    5169        // body of statements
    52         void MLEMutator::fixBlock( std::list< Statement * > &kids, bool caseClause ) {
     70        void MultiLevelExitMutator::fixBlock( std::list< Statement * > &kids, bool caseClause ) {
    5371                SemanticErrorException errors;
    5472
     
    8199        }
    82100
    83         void MLEMutator::premutate( CompoundStmt *cmpndStmt ) {
     101        void MultiLevelExitMutator::premutate( CompoundStmt *cmpndStmt ) {
    84102                visit_children = false;
    85103                bool labeledBlock = !(cmpndStmt->labels.empty());
     
    118136                        }
    119137                }
    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 ) {
     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 ) {
    125145                std::string originalTarget = branchStmt->originalTarget;
    126146
     
    230250        }
    231251
    232         Statement *MLEMutator::mutateLoop( Statement *bodyLoop, Entry &e ) {
     252        Statement *MultiLevelExitMutator::mutateLoop( Statement *bodyLoop, Entry &e ) {
     253                // only generate these when needed
     254                if( !e.isContUsed() && !e.isBreakUsed() ) return bodyLoop;
     255
    233256                // 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 
    240                 // only generate these when needed
     257                CompoundStmt * newBody = new CompoundStmt();
     258                newBody->get_kids().push_back( bodyLoop );
    241259
    242260                if ( e.isContUsed() ) {
     
    255273
    256274        template< typename LoopClass >
    257         void MLEMutator::prehandleLoopStmt( LoopClass * loopStmt ) {
     275        void MultiLevelExitMutator::prehandleLoopStmt( LoopClass * loopStmt ) {
    258276                // remember this as the most recent enclosing loop, then mutate the body of the loop -- this will determine
    259277                // whether brkLabel and contLabel are used with branch statements and will recursively do the same to nested
     
    266284
    267285        template< typename LoopClass >
    268         Statement * MLEMutator::posthandleLoopStmt( LoopClass * loopStmt ) {
     286        Statement * MultiLevelExitMutator::posthandleLoopStmt( LoopClass * loopStmt ) {
    269287                assert( ! enclosingControlStructures.empty() );
    270288                Entry &e = enclosingControlStructures.back();
     
    277295        }
    278296
    279         void MLEMutator::premutate( WhileStmt * whileStmt ) {
     297        void MultiLevelExitMutator::premutate( WhileStmt * whileStmt ) {
    280298                return prehandleLoopStmt( whileStmt );
    281299        }
    282300
    283         void MLEMutator::premutate( ForStmt * forStmt ) {
     301        void MultiLevelExitMutator::premutate( ForStmt * forStmt ) {
    284302                return prehandleLoopStmt( forStmt );
    285303        }
    286304
    287         Statement * MLEMutator::postmutate( WhileStmt * whileStmt ) {
     305        Statement * MultiLevelExitMutator::postmutate( WhileStmt * whileStmt ) {
    288306                return posthandleLoopStmt( whileStmt );
    289307        }
    290308
    291         Statement * MLEMutator::postmutate( ForStmt * forStmt ) {
     309        Statement * MultiLevelExitMutator::postmutate( ForStmt * forStmt ) {
    292310                return posthandleLoopStmt( forStmt );
    293311        }
    294312
    295         void MLEMutator::premutate( IfStmt * ifStmt ) {
     313        void MultiLevelExitMutator::premutate( IfStmt * ifStmt ) {
    296314                // generate a label for breaking out of a labeled if
    297315                bool labeledBlock = !(ifStmt->get_labels().empty());
     
    303321        }
    304322
    305         Statement * MLEMutator::postmutate( IfStmt * ifStmt ) {
     323        Statement * MultiLevelExitMutator::postmutate( IfStmt * ifStmt ) {
    306324                bool labeledBlock = !(ifStmt->get_labels().empty());
    307325                if ( labeledBlock ) {
     
    313331        }
    314332
    315         void MLEMutator::premutate( TryStmt * tryStmt ) {
     333        void MultiLevelExitMutator::premutate( TryStmt * tryStmt ) {
    316334                // generate a label for breaking out of a labeled if
    317335                bool labeledBlock = !(tryStmt->get_labels().empty());
     
    323341        }
    324342
    325         Statement * MLEMutator::postmutate( TryStmt * tryStmt ) {
     343        Statement * MultiLevelExitMutator::postmutate( TryStmt * tryStmt ) {
    326344                bool labeledBlock = !(tryStmt->get_labels().empty());
    327345                if ( labeledBlock ) {
     
    333351        }
    334352
    335         void MLEMutator::premutate( CaseStmt *caseStmt ) {
     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 ) {
    336369                visit_children = false;
    337370
     
    372405        }
    373406
    374         void MLEMutator::premutate( SwitchStmt *switchStmt ) {
     407        void MultiLevelExitMutator::premutate( SwitchStmt *switchStmt ) {
    375408                // generate a label for breaking out of a labeled switch
    376409                Label brkLabel = generator->newLabel("switchBreak", switchStmt);
     
    398431        }
    399432
    400         Statement * MLEMutator::postmutate( SwitchStmt * switchStmt ) {
     433        Statement * MultiLevelExitMutator::postmutate( SwitchStmt * switchStmt ) {
    401434                Entry &e = enclosingControlStructures.back();
    402435                assert ( e == switchStmt );
  • src/ControlStruct/MLEMutator.h

    r71d6bd8 r7030dab  
    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 : Tue Oct 22 17:22:47 2019
    13 // Update Count     : 45
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jan 22 11:50:00 2020
     13// Update Count     : 48
    1414//
    1515
     
    3030        class LabelGenerator;
    3131
    32         class MLEMutator : public WithVisitorRef<MLEMutator>, public WithShortCircuiting, public WithGuards {
     32        class MultiLevelExitMutator : public WithVisitorRef<MultiLevelExitMutator>,
     33                        public WithShortCircuiting, public WithGuards {
    3334          public:
    3435                class Entry;
    35                 MLEMutator( std::map<Label, Statement *> *t, LabelGenerator *gen = 0 ) : targetTable( t ), breakLabel(std::string("")), generator( gen ) {}
    36                 ~MLEMutator();
     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 * );
    3741
    3842                void premutate( CompoundStmt *cmpndStmt );
     
    4751                void premutate( SwitchStmt *switchStmt );
    4852                Statement * postmutate( SwitchStmt *switchStmt );
     53                void premutate( ReturnStmt *returnStmt );
    4954                void premutate( TryStmt *tryStmt );
    5055                Statement * postmutate( TryStmt *tryStmt );
     56                void premutate( FinallyStmt *finallyStmt );
    5157
    5258                Statement *mutateLoop( Statement *bodyLoop, Entry &e );
     
    110116                Label breakLabel;
    111117                LabelGenerator *generator;
     118                bool inFinally = false;
    112119
    113120                template< typename LoopClass >
  • src/ControlStruct/Mutate.cc

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 21 15:49:59 2017
    13 // Update Count     : 346
     12// Last Modified On : Fri Dec 13 23:40:34 2019
     13// Update Count     : 347
    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
    4039#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass
    4140#include "ResolvExpr/typeops.h"          // for typesCompatible
     
    4443#include "SymTab/Indexer.h"              // for Indexer
    4544#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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 17 09:11:18 2017
    13 // Update Count     : 5
     12// Last Modified On : Fri Dec 13 23:14:38 2019
     13// Update Count     : 7
    1414//
    1515
     
    1717#include <string>                        // for string
    1818
     19#include "Common/UniqueName.h"
    1920#include "Common/PassVisitor.h"
    2021#include "GenPoly.h"                     // for isPolyType
     
    2223
    2324#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
    2930#include "SynTree/Declaration.h"         // for Declaration, FunctionDecl
    3031#include "SynTree/Expression.h"          // for Expression, ConditionalExpr
     
    6061                }
    6162
    62                 struct ReferenceConversions final : public WithStmtsToAdd {
     63                struct ReferenceConversions final : public WithStmtsToAdd, public WithGuards {
    6364                        Expression * postmutate( CastExpr * castExpr );
    6465                        Expression * postmutate( AddressExpr * addrExpr );
     
    7172
    7273                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
    7384                        Expression * postmutate( ApplicationExpr * appExpr );
    7485                        void premutate( FunctionDecl * funcDecl );
     
    162173
    163174                Expression * FixIntrinsicResult::postmutate( ApplicationExpr * appExpr ) {
    164                         if ( isIntrinsicReference( appExpr ) ) {
     175                        if ( skip != SkipInProgress && isIntrinsicReference( appExpr ) ) {
    165176                                // eliminate reference types from intrinsic applications - now they return lvalues
    166177                                ReferenceType * result = strict_dynamic_cast< ReferenceType * >( appExpr->result );
  • src/GenPoly/Specialize.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 16 07:53:59 2017
    13 // Update Count     : 31
     12// Last Modified On : Fri Dec 13 23:40:49 2019
     13// Update Count     : 32
    1414//
    1515
     
    2727#include "GenPoly.h"                     // for getFunctionType
    2828#include "InitTweak/InitTweak.h"         // for isIntrinsicCallExpr
    29 #include "Parser/LinkageSpec.h"          // for C
    3029#include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
    3130#include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
    3231#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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Jan 13 16:29:30 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:15:56 2019
    13 // Update Count     : 76
     12// Last Modified On : Sun Feb 16 04:17:07 2020
     13// Update Count     : 82
    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
    4140#include "ResolvExpr/Resolver.h"       // for findVoidExpression
    4241#include "ResolvExpr/typeops.h"        // for typesCompatible
     
    4443#include "SymTab/Indexer.h"            // for Indexer
    4544#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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 17 09:12:36 2017
    13 // Update Count     : 183
     12// Last Modified On : Fri Dec 13 23:15:10 2019
     13// Update Count     : 184
    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
    3736#include "ResolvExpr/Resolver.h"
    3837#include "SymTab/Autogen.h"            // for genImplicitCall
    3938#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

    r71d6bd8 r7030dab  
    1010// Created On       : Fri May 13 11:26:36 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:21:48 2019
    13 // Update Count     : 7
     12// Last Modified On : Fri Dec 13 23:15:52 2019
     13// Update Count     : 8
    1414//
    1515
     
    3333#include "GenPoly/GenPoly.h"       // for getFunctionType
    3434#include "InitTweak.h"
    35 #include "Parser/LinkageSpec.h"    // for Spec, isBuiltin, Intrinsic
    3635#include "ResolvExpr/typeops.h"    // for typesCompatibleIgnoreQualifiers
    3736#include "SymTab/Autogen.h"
    3837#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

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 10:33:33 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 17 21:08:09 2019
    13 // Update Count     : 41
     12// Last Modified On : Sun Feb 16 03:49:49 2020
     13// Update Count     : 45
    1414//
    1515
     
    2323#include "Common/SemanticError.h"   // for SemanticError
    2424#include "Common/UniqueName.h"      // for UniqueName
    25 #include "Parser/LinkageSpec.h"     // for Spec, Intrinsic, C
     25#include "SynTree/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                         CodeGen::OperatorInfo opInfo;
    99                         bool lookResult = CodeGen::operatorLookup( funcDecl->get_name(), opInfo );
    100                         assert( lookResult );
     98                        const CodeGen::OperatorInfo * opInfo;
     99                        opInfo = CodeGen::operatorLookup( funcDecl->get_name() );
     100                        assert( opInfo );
    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

    r71d6bd8 r7030dab  
    213213        SymTab/Indexer.$(OBJEXT) SymTab/Mangler.$(OBJEXT) \
    214214        SymTab/ManglerCommon.$(OBJEXT) SymTab/Validate.$(OBJEXT)
    215 am__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) \
     215am__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) \
    227222        SynTree/Declaration.$(OBJEXT) \
    228223        SynTree/DeclarationWithType.$(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)
     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)
    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) Parser/LinkageSpec.$(OBJEXT) \
    240         $(am__objects_5) $(am__objects_6) SymTab/Demangle.$(OBJEXT) \
    241         $(am__objects_7) Tuples/TupleAssignment.$(OBJEXT) \
     239        InitTweak/InitTweak.$(OBJEXT) $(am__objects_5) \
     240        $(am__objects_6) SymTab/Demangle.$(OBJEXT) $(am__objects_7) \
     241        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/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) \
     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) \
    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/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 \
     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 \
    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 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 \
     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 \
    579578        Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
    580579MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
     
    665664
    666665SRC_SYNTREE = \
    667       SynTree/Type.cc \
    668       SynTree/VoidType.cc \
     666      SynTree/AddressExpr.cc \
     667      SynTree/AggregateDecl.cc \
     668      SynTree/ApplicationExpr.cc \
     669      SynTree/ArrayType.cc \
     670      SynTree/AttrType.cc \
     671      SynTree/Attribute.cc \
    669672      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 \
     673      SynTree/CommaExpr.cc \
     674      SynTree/CompoundStmt.cc \
    680675      SynTree/Constant.cc \
    681       SynTree/Expression.cc \
    682       SynTree/TupleExpr.cc \
    683       SynTree/CommaExpr.cc \
    684       SynTree/TypeExpr.cc \
    685       SynTree/ApplicationExpr.cc \
    686       SynTree/AddressExpr.cc \
    687       SynTree/Statement.cc \
    688       SynTree/CompoundStmt.cc \
     676      SynTree/DeclReplacer.cc \
    689677      SynTree/DeclStmt.cc \
    690678      SynTree/Declaration.cc \
    691679      SynTree/DeclarationWithType.cc \
     680      SynTree/Expression.cc \
     681      SynTree/FunctionDecl.cc \
     682      SynTree/FunctionType.cc \
     683      SynTree/Initializer.cc \
     684      SynTree/LinkageSpec.cc \
     685      SynTree/NamedTypeDecl.cc \
    692686      SynTree/ObjectDecl.cc \
    693       SynTree/FunctionDecl.cc \
    694       SynTree/AggregateDecl.cc \
    695       SynTree/NamedTypeDecl.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 \
    696694      SynTree/TypeDecl.cc \
    697       SynTree/Initializer.cc \
     695      SynTree/TypeExpr.cc \
    698696      SynTree/TypeSubstitution.cc \
    699       SynTree/Attribute.cc \
    700       SynTree/DeclReplacer.cc
     697      SynTree/TypeofType.cc \
     698      SynTree/VarArgsType.cc \
     699      SynTree/VoidType.cc \
     700      SynTree/ZeroOneType.cc
    701701
    702702
     
    873873InitTweak/InitTweak.$(OBJEXT): InitTweak/$(am__dirstamp) \
    874874        InitTweak/$(DEPDIR)/$(am__dirstamp)
    875 Parser/$(am__dirstamp):
    876         @$(MKDIR_P) Parser
    877         @: > Parser/$(am__dirstamp)
    878 Parser/$(DEPDIR)/$(am__dirstamp):
    879         @$(MKDIR_P) Parser/$(DEPDIR)
    880         @: > Parser/$(DEPDIR)/$(am__dirstamp)
    881 Parser/LinkageSpec.$(OBJEXT): Parser/$(am__dirstamp) \
    882         Parser/$(DEPDIR)/$(am__dirstamp)
    883875ResolvExpr/$(am__dirstamp):
    884876        @$(MKDIR_P) ResolvExpr
     
    961953        @$(MKDIR_P) SynTree/$(DEPDIR)
    962954        @: > SynTree/$(DEPDIR)/$(am__dirstamp)
     955SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     956        SynTree/$(DEPDIR)/$(am__dirstamp)
     957SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     958        SynTree/$(DEPDIR)/$(am__dirstamp)
     959SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     960        SynTree/$(DEPDIR)/$(am__dirstamp)
     961SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
     962        SynTree/$(DEPDIR)/$(am__dirstamp)
     963SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
     964        SynTree/$(DEPDIR)/$(am__dirstamp)
     965SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
     966        SynTree/$(DEPDIR)/$(am__dirstamp)
     967SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
     968        SynTree/$(DEPDIR)/$(am__dirstamp)
     969SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     970        SynTree/$(DEPDIR)/$(am__dirstamp)
     971SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     972        SynTree/$(DEPDIR)/$(am__dirstamp)
     973SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
     974        SynTree/$(DEPDIR)/$(am__dirstamp)
     975SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
     976        SynTree/$(DEPDIR)/$(am__dirstamp)
     977SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
     978        SynTree/$(DEPDIR)/$(am__dirstamp)
     979SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
     980        SynTree/$(DEPDIR)/$(am__dirstamp)
     981SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
     982        SynTree/$(DEPDIR)/$(am__dirstamp)
     983SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
     984        SynTree/$(DEPDIR)/$(am__dirstamp)
     985SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     986        SynTree/$(DEPDIR)/$(am__dirstamp)
     987SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
     988        SynTree/$(DEPDIR)/$(am__dirstamp)
     989SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
     990        SynTree/$(DEPDIR)/$(am__dirstamp)
     991SynTree/LinkageSpec.$(OBJEXT): SynTree/$(am__dirstamp) \
     992        SynTree/$(DEPDIR)/$(am__dirstamp)
     993SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     994        SynTree/$(DEPDIR)/$(am__dirstamp)
     995SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     996        SynTree/$(DEPDIR)/$(am__dirstamp)
     997SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
     998        SynTree/$(DEPDIR)/$(am__dirstamp)
     999SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1000        SynTree/$(DEPDIR)/$(am__dirstamp)
     1001SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1002        SynTree/$(DEPDIR)/$(am__dirstamp)
     1003SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
     1004        SynTree/$(DEPDIR)/$(am__dirstamp)
     1005SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     1006        SynTree/$(DEPDIR)/$(am__dirstamp)
     1007SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1008        SynTree/$(DEPDIR)/$(am__dirstamp)
    9631009SynTree/Type.$(OBJEXT): SynTree/$(am__dirstamp) \
    9641010        SynTree/$(DEPDIR)/$(am__dirstamp)
     1011SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
     1012        SynTree/$(DEPDIR)/$(am__dirstamp)
     1013SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
     1014        SynTree/$(DEPDIR)/$(am__dirstamp)
     1015SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
     1016        SynTree/$(DEPDIR)/$(am__dirstamp)
     1017SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1018        SynTree/$(DEPDIR)/$(am__dirstamp)
     1019SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
     1020        SynTree/$(DEPDIR)/$(am__dirstamp)
    9651021SynTree/VoidType.$(OBJEXT): SynTree/$(am__dirstamp) \
    9661022        SynTree/$(DEPDIR)/$(am__dirstamp)
    967 SynTree/BasicType.$(OBJEXT): SynTree/$(am__dirstamp) \
    968         SynTree/$(DEPDIR)/$(am__dirstamp)
    969 SynTree/PointerType.$(OBJEXT): SynTree/$(am__dirstamp) \
    970         SynTree/$(DEPDIR)/$(am__dirstamp)
    971 SynTree/ArrayType.$(OBJEXT): SynTree/$(am__dirstamp) \
    972         SynTree/$(DEPDIR)/$(am__dirstamp)
    973 SynTree/ReferenceType.$(OBJEXT): SynTree/$(am__dirstamp) \
    974         SynTree/$(DEPDIR)/$(am__dirstamp)
    975 SynTree/FunctionType.$(OBJEXT): SynTree/$(am__dirstamp) \
    976         SynTree/$(DEPDIR)/$(am__dirstamp)
    977 SynTree/ReferenceToType.$(OBJEXT): SynTree/$(am__dirstamp) \
    978         SynTree/$(DEPDIR)/$(am__dirstamp)
    979 SynTree/TupleType.$(OBJEXT): SynTree/$(am__dirstamp) \
    980         SynTree/$(DEPDIR)/$(am__dirstamp)
    981 SynTree/TypeofType.$(OBJEXT): SynTree/$(am__dirstamp) \
    982         SynTree/$(DEPDIR)/$(am__dirstamp)
    983 SynTree/AttrType.$(OBJEXT): SynTree/$(am__dirstamp) \
    984         SynTree/$(DEPDIR)/$(am__dirstamp)
    985 SynTree/VarArgsType.$(OBJEXT): SynTree/$(am__dirstamp) \
    986         SynTree/$(DEPDIR)/$(am__dirstamp)
    9871023SynTree/ZeroOneType.$(OBJEXT): SynTree/$(am__dirstamp) \
    988         SynTree/$(DEPDIR)/$(am__dirstamp)
    989 SynTree/Constant.$(OBJEXT): SynTree/$(am__dirstamp) \
    990         SynTree/$(DEPDIR)/$(am__dirstamp)
    991 SynTree/Expression.$(OBJEXT): SynTree/$(am__dirstamp) \
    992         SynTree/$(DEPDIR)/$(am__dirstamp)
    993 SynTree/TupleExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    994         SynTree/$(DEPDIR)/$(am__dirstamp)
    995 SynTree/CommaExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    996         SynTree/$(DEPDIR)/$(am__dirstamp)
    997 SynTree/TypeExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    998         SynTree/$(DEPDIR)/$(am__dirstamp)
    999 SynTree/ApplicationExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    1000         SynTree/$(DEPDIR)/$(am__dirstamp)
    1001 SynTree/AddressExpr.$(OBJEXT): SynTree/$(am__dirstamp) \
    1002         SynTree/$(DEPDIR)/$(am__dirstamp)
    1003 SynTree/Statement.$(OBJEXT): SynTree/$(am__dirstamp) \
    1004         SynTree/$(DEPDIR)/$(am__dirstamp)
    1005 SynTree/CompoundStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    1006         SynTree/$(DEPDIR)/$(am__dirstamp)
    1007 SynTree/DeclStmt.$(OBJEXT): SynTree/$(am__dirstamp) \
    1008         SynTree/$(DEPDIR)/$(am__dirstamp)
    1009 SynTree/Declaration.$(OBJEXT): SynTree/$(am__dirstamp) \
    1010         SynTree/$(DEPDIR)/$(am__dirstamp)
    1011 SynTree/DeclarationWithType.$(OBJEXT): SynTree/$(am__dirstamp) \
    1012         SynTree/$(DEPDIR)/$(am__dirstamp)
    1013 SynTree/ObjectDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    1014         SynTree/$(DEPDIR)/$(am__dirstamp)
    1015 SynTree/FunctionDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    1016         SynTree/$(DEPDIR)/$(am__dirstamp)
    1017 SynTree/AggregateDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    1018         SynTree/$(DEPDIR)/$(am__dirstamp)
    1019 SynTree/NamedTypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    1020         SynTree/$(DEPDIR)/$(am__dirstamp)
    1021 SynTree/TypeDecl.$(OBJEXT): SynTree/$(am__dirstamp) \
    1022         SynTree/$(DEPDIR)/$(am__dirstamp)
    1023 SynTree/Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
    1024         SynTree/$(DEPDIR)/$(am__dirstamp)
    1025 SynTree/TypeSubstitution.$(OBJEXT): SynTree/$(am__dirstamp) \
    1026         SynTree/$(DEPDIR)/$(am__dirstamp)
    1027 SynTree/Attribute.$(OBJEXT): SynTree/$(am__dirstamp) \
    1028         SynTree/$(DEPDIR)/$(am__dirstamp)
    1029 SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
    10301024        SynTree/$(DEPDIR)/$(am__dirstamp)
    10311025Tuples/$(am__dirstamp):
     
    11441138InitTweak/FixGlobalInit.$(OBJEXT): InitTweak/$(am__dirstamp) \
    11451139        InitTweak/$(DEPDIR)/$(am__dirstamp)
     1140Parser/$(am__dirstamp):
     1141        @$(MKDIR_P) Parser
     1142        @: > Parser/$(am__dirstamp)
     1143Parser/$(DEPDIR)/$(am__dirstamp):
     1144        @$(MKDIR_P) Parser/$(DEPDIR)
     1145        @: > Parser/$(DEPDIR)/$(am__dirstamp)
     1146Parser/DeclarationNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1147        Parser/$(DEPDIR)/$(am__dirstamp)
     1148Parser/ExpressionNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1149        Parser/$(DEPDIR)/$(am__dirstamp)
     1150Parser/InitializerNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1151        Parser/$(DEPDIR)/$(am__dirstamp)
     1152Parser/ParseNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1153        Parser/$(DEPDIR)/$(am__dirstamp)
     1154Parser/StatementNode.$(OBJEXT): Parser/$(am__dirstamp) \
     1155        Parser/$(DEPDIR)/$(am__dirstamp)
     1156Parser/TypeData.$(OBJEXT): Parser/$(am__dirstamp) \
     1157        Parser/$(DEPDIR)/$(am__dirstamp)
     1158Parser/TypedefTable.$(OBJEXT): Parser/$(am__dirstamp) \
     1159        Parser/$(DEPDIR)/$(am__dirstamp)
     1160Parser/lex.$(OBJEXT): Parser/$(am__dirstamp) \
     1161        Parser/$(DEPDIR)/$(am__dirstamp)
    11461162Parser/parser.hh: Parser/parser.cc
    11471163        @if test ! -f $@; then rm -f Parser/parser.cc; else :; fi
    11481164        @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) Parser/parser.cc; else :; fi
    11491165Parser/parser.$(OBJEXT): Parser/$(am__dirstamp) \
    1150         Parser/$(DEPDIR)/$(am__dirstamp)
    1151 Parser/lex.$(OBJEXT): Parser/$(am__dirstamp) \
    1152         Parser/$(DEPDIR)/$(am__dirstamp)
    1153 Parser/TypedefTable.$(OBJEXT): Parser/$(am__dirstamp) \
    1154         Parser/$(DEPDIR)/$(am__dirstamp)
    1155 Parser/ParseNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1156         Parser/$(DEPDIR)/$(am__dirstamp)
    1157 Parser/DeclarationNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1158         Parser/$(DEPDIR)/$(am__dirstamp)
    1159 Parser/ExpressionNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1160         Parser/$(DEPDIR)/$(am__dirstamp)
    1161 Parser/StatementNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1162         Parser/$(DEPDIR)/$(am__dirstamp)
    1163 Parser/InitializerNode.$(OBJEXT): Parser/$(am__dirstamp) \
    1164         Parser/$(DEPDIR)/$(am__dirstamp)
    1165 Parser/TypeData.$(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@
    12781277@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/ParseNode.Po@am__quote@
    12791278@AMDEP_TRUE@@am__include@ @am__quote@Parser/$(DEPDIR)/StatementNode.Po@am__quote@
     
    13341333@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/FunctionType.Po@am__quote@
    13351334@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

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:17:10 2019
    13 // Update Count     : 1116
     12// Last Modified On : Mon Dec 16 15:32:22 2019
     13// Update Count     : 1133
    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
    2726#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" };
    49 const char * DeclarationNode::aggregateNames[] = { "struct", "union", "trait", "coroutine", "monitor", "thread", "NoAggregateNames" };
    50 const char * DeclarationNode::typeClassNames[] = { "otype", "dtype", "ftype", "NoTypeClassNames" };
    5149const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" };
    5250
     
    5957
    6058//      variable.name = nullptr;
    61         variable.tyClass = NoTypeClass;
     59        variable.tyClass = TypeDecl::NUMBER_OF_KINDS;
    6260        variable.assertions = nullptr;
    6361        variable.initializer = nullptr;
     
    135133
    136134        if ( linkage != LinkageSpec::Cforall ) {
    137                 os << LinkageSpec::linkageName( linkage ) << " ";
     135                os << LinkageSpec::name( linkage ) << " ";
    138136        } // if
    139137
     
    267265}
    268266
    269 DeclarationNode * DeclarationNode::newAggregate( Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
     267DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
    270268        DeclarationNode * newnode = new DeclarationNode;
    271269        newnode->type = new TypeData( TypeData::Aggregate );
     
    313311} // DeclarationNode::newFromTypeGen
    314312
    315 DeclarationNode * DeclarationNode::newTypeParam( TypeClass tc, const string * name ) {
     313DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
    316314        DeclarationNode * newnode = new DeclarationNode;
    317315        newnode->type = nullptr;
     
    328326        newnode->type = new TypeData( TypeData::Aggregate );
    329327        newnode->type->aggregate.name = name;
    330         newnode->type->aggregate.kind = Trait;
     328        newnode->type->aggregate.kind = AggregateDecl::Trait;
    331329        newnode->type->aggregate.params = params;
    332330        newnode->type->aggregate.fields = asserts;
     
    338336        newnode->type = new TypeData( TypeData::AggregateInst );
    339337        newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
    340         newnode->type->aggInst.aggregate->aggregate.kind = Trait;
     338        newnode->type->aggInst.aggregate->aggregate.kind = AggregateDecl::Trait;
    341339        newnode->type->aggInst.aggregate->aggregate.name = name;
    342340        newnode->type->aggInst.params = params;
     
    671669
    672670DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
    673         if ( variable.tyClass != NoTypeClass ) {
     671        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
    674672                if ( variable.assertions ) {
    675673                        variable.assertions->appendList( assertions );
     
    876874
    877875DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
    878         assertf( variable.tyClass != NoTypeClass, "Called addTypeInitializer on something that isn't a type variable." );
     876        assertf( variable.tyClass != TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
    879877        variable.initializer = init;
    880878        return this;
     
    10751073        } // if
    10761074
    1077         if ( variable.tyClass != NoTypeClass ) {
     1075        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
    10781076                // otype is internally converted to dtype + otype parameters
    10791077                static const TypeDecl::Kind kindMap[] = { TypeDecl::Dtype, TypeDecl::Dtype, TypeDecl::Ftype, TypeDecl::Ttype };
    1080                 assertf( sizeof(kindMap)/sizeof(kindMap[0]) == NoTypeClass, "DeclarationNode::build: kindMap is out of sync." );
     1078                static_assert( sizeof(kindMap)/sizeof(kindMap[0]) == TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
    10811079                assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
    1082                 TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == Otype, variable.initializer ? variable.initializer->buildType() : nullptr );
     1080                TypeDecl * ret = new TypeDecl( *name, Type::StorageClasses(), nullptr, kindMap[ variable.tyClass ], variable.tyClass == TypeDecl::Otype, variable.initializer ? variable.initializer->buildType() : nullptr );
    10831081                buildList( variable.assertions, ret->get_assertions() );
    10841082                return ret;
  • src/Parser/ExpressionNode.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  4 20:57:55 2019
    13 // Update Count     : 978
     12// Last Modified On : Wed Dec 18 21:14:58 2019
     13// Update Count     : 981
    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::Kind)-1, (BasicType::Kind)-1, BasicType::uFloat16Complex, BasicType::uFloat32Complex, BasicType::uFloat32xComplex, BasicType::uFloat64Complex, BasicType::uFloat64xComplex, BasicType::uFloat128Complex, BasicType::uFloat128xComplex },
     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 },
    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( KeywordCastExpr::Target target, ExpressionNode * expr_node ) {
     436Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) {
    437437        return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target );
    438438}
  • src/Parser/ParseNode.h

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:17:10 2019
    13 // Update Count     : 876
     12// Last Modified On : Fri Feb  7 17:56:02 2020
     13// Update Count     : 891
    1414//
    1515
     
    2828#include "Common/UniqueName.h"     // for UniqueName
    2929#include "Common/utility.h"        // for maybeClone, maybeBuild
    30 #include "Parser/LinkageSpec.h"    // for Spec
     30#include "SynTree/LinkageSpec.h"   // for Spec
     31#include "SynTree/Declaration.h"   // for Aggregate
    3132#include "SynTree/Expression.h"    // for Expression, ConstantExpr (ptr only)
    3233#include "SynTree/Label.h"         // for Label
     
    184185
    185186Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
    186 Expression * build_keyword_cast( KeywordCastExpr::Target target, ExpressionNode * expr_node );
     187Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node );
    187188Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
    188189Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member );
     
    217218        enum Length { Short, Long, LongLong, NoLength };
    218219        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[];
    223220        enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
    224221        static const char * builtinTypeNames[];
     
    237234        static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
    238235        static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
    239         static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
     236        static DeclarationNode * newAggregate( AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
    240237        static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body );
    241238        static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
    242239        static DeclarationNode * newName( const std::string * );
    243240        static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );
    244         static DeclarationNode * newTypeParam( TypeClass, const std::string * );
     241        static DeclarationNode * newTypeParam( TypeDecl::Kind, const std::string * );
    245242        static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
    246243        static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
     
    312309        struct Variable_t {
    313310//              const std::string * name;
    314                 DeclarationNode::TypeClass tyClass;
     311                TypeDecl::Kind tyClass;
    315312                DeclarationNode * assertions;
    316313                DeclarationNode * initializer;
     
    431428Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    432429Statement * build_directive( std::string * directive );
     430SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
    433431WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
    434432WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
     
    452450                                * out++ = result;
    453451                        } else {
    454                                 assertf(false, "buildList unknown type");
     452                                SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
    455453                        } // if
    456454                } catch( SemanticErrorException & e ) {
  • src/Parser/ParserTypes.h

    r71d6bd8 r7030dab  
    1010// Created On       : Sat Sep 22 08:58:10 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:33:28 2017
    13 // Update Count     : 350
     12// Last Modified On : Sat Feb 15 11:04:40 2020
     13// Update Count     : 351
    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

    r71d6bd8 r7030dab  
    249249} // build_finally
    250250
     251SuspendStmt * 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
    251266WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    252267        auto node = new WaitForStmt();
  • src/Parser/TypeData.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 15:12:51 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 18:16:23 2019
    13 // Update Count     : 649
     12// Last Modified On : Mon Dec 16 07:56:46 2019
     13// Update Count     : 662
    1414//
    1515
     
    6767          case Aggregate:
    6868                // aggregate = new Aggregate_t;
    69                 aggregate.kind = DeclarationNode::NoAggregate;
     69                aggregate.kind = AggregateDecl::NoAggregate;
    7070                aggregate.name = nullptr;
    7171                aggregate.params = nullptr;
     
    345345                break;
    346346          case Aggregate:
    347                 os << DeclarationNode::aggregateNames[ aggregate.kind ] << ' ' << *aggregate.name << endl;
     347                os << AggregateDecl::aggrString( 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 == DeclarationNode::Otype ) {
     491                if ( n->variable.tyClass == TypeDecl::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                         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                         }
     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
    558557          case TypeData::GlobalScope:
    559                         return new GlobalScopeType();
    560                 case TypeData::Qualified:
    561                         return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
     558                return new GlobalScopeType();
     559          case TypeData::Qualified:
     560                return new QualifiedType( buildQualifiers( td ), typebuild( td->qualified.parent ), typebuild( td->qualified.child ) );
    562561          case TypeData::Symbolic:
    563562          case TypeData::Enum:
    564563          case TypeData::Aggregate:
    565                         assert( false );
     564                assert( false );
    566565        } // switch
    567566
     
    768767        AggregateDecl * at;
    769768        switch ( td->aggregate.kind ) {
    770           case DeclarationNode::Struct:
    771           case DeclarationNode::Coroutine:
    772           case DeclarationNode::Monitor:
    773           case DeclarationNode::Thread:
     769          case AggregateDecl::Struct:
     770          case AggregateDecl::Coroutine:
     771          case AggregateDecl::Generator:
     772          case AggregateDecl::Monitor:
     773          case AggregateDecl::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 DeclarationNode::Union:
     777          case AggregateDecl::Union:
    778778                at = new UnionDecl( *td->aggregate.name, attributes, linkage );
    779779                buildForall( td->aggregate.params, at->get_parameters() );
    780780                break;
    781           case DeclarationNode::Trait:
     781          case AggregateDecl::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 DeclarationNode::Struct:
    812                                 case DeclarationNode::Coroutine:
    813                                 case DeclarationNode::Monitor:
    814                                 case DeclarationNode::Thread:
     811                                case AggregateDecl::Struct:
     812                                case AggregateDecl::Coroutine:
     813                                case AggregateDecl::Monitor:
     814                                case AggregateDecl::Thread:
    815815                                  ret = new StructInstType( buildQualifiers( type ), (StructDecl *)typedecl );
    816816                                  break;
    817                                 case DeclarationNode::Union:
     817                                case AggregateDecl::Union:
    818818                                  ret = new UnionInstType( buildQualifiers( type ), (UnionDecl *)typedecl );
    819819                                  break;
    820                                 case DeclarationNode::Trait:
     820                                case AggregateDecl::Trait:
    821821                                  assert( false );
    822822                                  //ret = new TraitInstType( buildQualifiers( type ), (TraitDecl *)typedecl );
     
    827827                  } else {
    828828                          switch ( type->aggregate.kind ) {
    829                                 case DeclarationNode::Struct:
    830                                 case DeclarationNode::Coroutine:
    831                                 case DeclarationNode::Monitor:
    832                                 case DeclarationNode::Thread:
     829                                case AggregateDecl::Struct:
     830                                case AggregateDecl::Coroutine:
     831                                case AggregateDecl::Monitor:
     832                                case AggregateDecl::Thread:
    833833                                  ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
    834834                                  break;
    835                                 case DeclarationNode::Union:
     835                                case AggregateDecl::Union:
    836836                                  ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
    837837                                  break;
    838                                 case DeclarationNode::Trait:
     838                                case AggregateDecl::Trait:
    839839                                  ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
    840840                                  break;
     
    863863          case TypeData::Aggregate: {
    864864                  switch ( type->aggregate.kind ) {
    865                         case DeclarationNode::Struct:
    866                         case DeclarationNode::Coroutine:
    867                         case DeclarationNode::Monitor:
    868                         case DeclarationNode::Thread:
     865                        case AggregateDecl::Struct:
     866                        case AggregateDecl::Coroutine:
     867                        case AggregateDecl::Monitor:
     868                        case AggregateDecl::Thread:
    869869                          ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
    870870                          break;
    871                         case DeclarationNode::Union:
     871                        case AggregateDecl::Union:
    872872                          ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
    873873                          break;
    874                         case DeclarationNode::Trait:
     874                        case AggregateDecl::Trait:
    875875                          ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
    876876                          break;
  • src/Parser/TypeData.h

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 15:18:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Nov  1 20:56:46 2018
    13 // Update Count     : 196
     12// Last Modified On : Fri Dec 13 23:42:35 2019
     13// Update Count     : 199
    1414//
    1515
     
    2121
    2222#include "ParseNode.h"           // for DeclarationNode, DeclarationNode::Ag...
    23 #include "Parser/LinkageSpec.h" // for Spec
     23#include "SynTree/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                 DeclarationNode::Aggregate kind;
     32                AggregateDecl::Aggregate kind;
    3333                const std::string * name = nullptr;
    3434                DeclarationNode * params = nullptr;
  • src/Parser/TypedefTable.cc

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

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

    r71d6bd8 r7030dab  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Sun Aug  4 20:53:47 2019
    13  * Update Count     : 719
     12 * Last Modified On : Sat Feb 15 11:05:50 2020
     13 * Update Count     : 737
    1414 */
    1515
     
    4343#include "TypedefTable.h"
    4444
     45string * build_postfix_name( string * name );
     46
    4547char *yyfilename;
    4648string *strtext;                                                                                // accumulate parts of character and string constant value
     
    6365#define FLOATXX(v) KEYWORD_RETURN(v);
    6466#else
    65 #define FLOATXX(v) IDENTIFIER_RETURN(); 
     67#define FLOATXX(v) IDENTIFIER_RETURN();
    6668#endif // HAVE_KEYWORDS_FLOATXX
    6769
     
    299301_Static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C11
    300302struct                  { KEYWORD_RETURN(STRUCT); }
    301         /* suspend                      { KEYWORD_RETURN(SUSPEND); }                    // CFA */
     303suspend                 { KEYWORD_RETURN(SUSPEND); }                    // CFA
    302304switch                  { KEYWORD_RETURN(SWITCH); }
    303305thread                  { KEYWORD_RETURN(THREAD); }                             // C11
     
    330332                                /* identifier */
    331333{identifier}    { IDENTIFIER_RETURN(); }
    332 "`"{identifier}"`" {                                                                    // CFA
    333         yytext[yyleng - 1] = '\0'; yytext += 1;                         // SKULLDUGGERY: remove backquotes (ok to shorten?)
     334"``"{identifier} {                                                                              // CFA
     335        yytext[yyleng] = '\0'; yytext += 2;                                     // SKULLDUGGERY: remove backquotes (ok to shorten?)
    334336        IDENTIFIER_RETURN();
    335337}
     
    432434"?"({op_unary_pre_post}|"()"|"[?]"|"{}") { IDENTIFIER_RETURN(); }
    433435"^?{}"                  { IDENTIFIER_RETURN(); }
    434 "?`"{identifier} { IDENTIFIER_RETURN(); }                               // postfix operator
     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}
    435441"?"{op_binary_over}"?"  { IDENTIFIER_RETURN(); }                // binary
    436442        /*
  • src/Parser/module.mk

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

    r71d6bd8 r7030dab  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  4 21:48:23 2019
    13 // Update Count     : 4364
     12// Last Modified On : Fri Mar  6 17:26:45 2020
     13// Update Count     : 4474
    1414//
    1515
     
    5151using namespace std;
    5252
     53#include "SynTree/Declaration.h"
    5354#include "ParseNode.h"
    5455#include "TypedefTable.h"
    5556#include "TypeData.h"
    56 #include "LinkageSpec.h"
     57#include "SynTree/LinkageSpec.h"
    5758#include "Common/SemanticError.h"                                               // error_str
    5859#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     
    165166} // rebindForall
    166167
    167 NameExpr * build_postfix_name( const string * name ) {
    168         NameExpr * new_name = build_varref( new string( "?`" + *name ) );
    169         delete name;
    170         return new_name;
     168string * build_postfix_name( string * name ) {
     169        *name = string("__postfix_func_") + *name;
     170        return name;
    171171} // build_postfix_name
    172172
     
    210210        } // if
    211211} // forCtrl
    212 
    213212
    214213bool forall = false, yyy = false;                                               // aggregate have one or more forall qualifiers ?
     
    237236        ExpressionNode * en;
    238237        DeclarationNode * decl;
    239         DeclarationNode::Aggregate aggKey;
    240         DeclarationNode::TypeClass tclass;
     238        AggregateDecl::Aggregate aggKey;
     239        TypeDecl::Kind tclass;
    241240        StatementNode * sn;
    242241        WaitForStmt * wfs;
     
    279278%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    280279%token SIZEOF OFFSETOF
    281 // %token SUSPEND RESUME                                                                        // CFA
     280// %token RESUME                                                                        // CFA
     281%token SUSPEND                                                                  // 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                               exponential_expression          multiplicative_expression       additive_expression
     325%type<en> cast_expression_list                  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
     367%type<aggKey> aggregate_key aggregate_data aggregate_control
    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 ) ); }
    591581        | type_name '.' identifier                                                      // CFA, nested type
    592582                { SemanticError( yylloc, "Qualified name is currently unimplemented." ); $$ = nullptr; }
     
    642632        | postfix_expression '(' argument_expression_list ')'
    643633                { $$ = 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 ) ) ); }
    644640        | postfix_expression '.' identifier
    645641                { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); }
     
    650646        | postfix_expression '.' '[' field_name_list ']'        // CFA, tuple field selector
    651647                { $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
     648        | postfix_expression '.' aggregate_control
     649                { $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }
    652650        | postfix_expression ARROW identifier
    653651                { $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
     
    664662        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    665663                { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    666         | '^' primary_expression '{' argument_expression_list '}' // CFA
     664        | '^' primary_expression '{' argument_expression_list '}' // CFA, destructor call
    667665                {
    668666                        Token fn;
     
    677675        | argument_expression
    678676        | argument_expression_list ',' argument_expression
    679                 { $$ = (ExpressionNode *)( $1->set_last( $3 )); }
     677                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    680678        ;
    681679
     
    689687field_name_list:                                                                                // CFA, tuple field selector
    690688        field
    691         | field_name_list ',' field                                     { $$ = (ExpressionNode *)$1->set_last( $3 ); }
     689        | field_name_list ',' field                                     { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    692690        ;
    693691
     
    793791        | '(' type_no_function ')' cast_expression
    794792                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    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 ) ); }
     793        | '(' aggregate_control '&' ')' cast_expression         // CFA
     794                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    804795                // VIRTUAL cannot be opt because of look ahead issues
    805796        | '(' VIRTUAL ')' cast_expression                                       // CFA
     
    928919        conditional_expression
    929920        | unary_expression assignment_operator assignment_expression
    930                 { $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); }
     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                }
    931928        | unary_expression '=' '{' initializer_list_opt comma_opt '}'
    932929                { SemanticError( yylloc, "Initializer assignment is currently unimplemented." ); $$ = nullptr; }
     
    965962                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)(new ExpressionNode( nullptr ) )->set_last( $3 ) ) ); }
    966963        | '[' push assignment_expression pop ',' tuple_expression_list ']'
    967                 { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)$3->set_last( $6 ) ) ); }
     964                { $$ = new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $6 ) ) )); }
    968965        ;
    969966
     
    971968        assignment_expression_opt
    972969        | tuple_expression_list ',' assignment_expression_opt
    973                 { $$ = (ExpressionNode *)$1->set_last( $3 ); }
     970                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    974971        ;
    975972
     
    11951192                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11961193                                                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" ) ) ) ); }
    12041207        | comma_expression ';' comma_expression inclexcl comma_expression // CFA
    12051208                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    12631266        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    12641267                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    1265         // | SUSPEND ';'
    1266         //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
    1267         // | SUSPEND compound_statement ';'
    1268         //      { SemanticError( yylloc, "Suspend expression 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 ) ); }
    12691280        | THROW assignment_expression_opt ';'                           // handles rethrow
    12701281                { $$ = new StatementNode( build_throw( $2 ) ); }
     
    13061317        WAITFOR '(' cast_expression ')'
    13071318                { $$ = $3; }
    1308         | WAITFOR '(' cast_expression ',' argument_expression_list ')'
    1309                 { $$ = (ExpressionNode *)$3->set_last( $5 ); }
     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
     1325cast_expression_list:
     1326        cast_expression
     1327        | cast_expression_list ',' cast_expression
     1328                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    13101329        ;
    13111330
     
    14181437        asm_operand
    14191438        | asm_operands_list ',' asm_operand
    1420                 { $$ = (ExpressionNode *)$1->set_last( $3 ); }
     1439                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    14211440        ;
    14221441
     
    14341453                { $$ = new ExpressionNode( $1 ); }
    14351454        | asm_clobbers_list_opt ',' string_literal
    1436                 // set_last returns ParseNode *
    1437                 { $$ = (ExpressionNode *)$1->set_last( new ExpressionNode( $3 ) ); }
     1455                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
    14381456        ;
    14391457
     
    15861604                // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
    15871605                // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
    1588         cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
     1606        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    15891607                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    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 ); }
     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 ); }
    15931611        ;
    15941612
     
    20592077
    20602078aggregate_key:
     2079        aggregate_data
     2080        | aggregate_control
     2081        ;
     2082
     2083aggregate_data:
    20612084        STRUCT
    2062                 { yyy = true; $$ = DeclarationNode::Struct; }
     2085                { yyy = true; $$ = AggregateDecl::Struct; }
    20632086        | UNION
    2064                 { yyy = true; $$ = DeclarationNode::Union; }
    2065         | EXCEPTION
    2066                 { yyy = true; $$ = DeclarationNode::Exception; }
    2067         | GENERATOR
    2068                 { yyy = true; $$ = DeclarationNode::Coroutine; }
     2087                { yyy = true; $$ = AggregateDecl::Union; }
     2088        | EXCEPTION                                                                                     // CFA
     2089                { yyy = true; $$ = AggregateDecl::Exception; }
     2090        ;
     2091
     2092aggregate_control:                                                                              // CFA
     2093        GENERATOR
     2094                { yyy = true; $$ = AggregateDecl::Generator; }
     2095        | MONITOR GENERATOR
     2096                { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20692097        | COROUTINE
    2070                 { yyy = true; $$ = DeclarationNode::Coroutine; }
     2098                { yyy = true; $$ = AggregateDecl::Coroutine; }
    20712099        | MONITOR
    2072                 { yyy = true; $$ = DeclarationNode::Monitor; }
     2100                { yyy = true; $$ = AggregateDecl::Monitor; }
     2101        | MONITOR COROUTINE
     2102                { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20732103        | THREAD
    2074                 { yyy = true; $$ = DeclarationNode::Thread; }
     2104                { yyy = true; $$ = AggregateDecl::Thread; }
     2105        | MONITOR THREAD
     2106                { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20752107        ;
    20762108
     
    20962128                        distInl( $3 );
    20972129                }
     2130        | INLINE aggregate_control ';'                                          // CFA
     2131                { SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
    20982132        | typedef_declaration ';'                                                       // CFA
    20992133        | cfa_field_declaring_list ';'                                          // CFA, new style field declaration
     
    23482382        | initializer_list_opt ',' initializer          { $$ = (InitializerNode *)( $1->set_last( $3 ) ); }
    23492383        | initializer_list_opt ',' designation initializer
    2350                 { $$ = (InitializerNode *)( $1->set_last( $4->set_designators( $3 ) ) ); }
     2384                { $$ = (InitializerNode *)($1->set_last( $4->set_designators( $3 ) )); }
    23512385        ;
    23522386
     
    23702404        designator
    23712405        | designator_list designator
    2372                 { $$ = (ExpressionNode *)( $1->set_last( $2 ) ); }
     2406                { $$ = (ExpressionNode *)($1->set_last( $2 )); }
    23732407        //| designator_list designator                                          { $$ = new ExpressionNode( $1, $2 ); }
    23742408        ;
     
    24262460        | type_specifier identifier_parameter_declarator
    24272461        | assertion_list
    2428                 { $$ = DeclarationNode::newTypeParam( DeclarationNode::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
     2462                { $$ = DeclarationNode::newTypeParam( TypeDecl::Dtype, new string( DeclarationNode::anonymous.newName() ) )->addAssertions( $1 ); }
    24292463        ;
    24302464
    24312465type_class:                                                                                             // CFA
    24322466        OTYPE
    2433                 { $$ = DeclarationNode::Otype; }
     2467                { $$ = TypeDecl::Otype; }
    24342468        | DTYPE
    2435                 { $$ = DeclarationNode::Dtype; }
     2469                { $$ = TypeDecl::Dtype; }
    24362470        | FTYPE
    2437                 { $$ = DeclarationNode::Ftype; }
     2471                { $$ = TypeDecl::Ftype; }
    24382472        | TTYPE
    2439                 { $$ = DeclarationNode::Ttype; }
     2473                { $$ = TypeDecl::Ttype; }
    24402474        ;
    24412475
     
    24672501                { SemanticError( yylloc, toString("Expression generic parameters are currently unimplemented: ", $1->build()) ); $$ = nullptr; }
    24682502        | type_list ',' type
    2469                 { $$ = (ExpressionNode *)( $1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) ) ); }
     2503                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( new TypeExpr( maybeMoveBuildType( $3 ) ) ) )); }
    24702504        | type_list ',' assignment_expression
    24712505                { SemanticError( yylloc, toString("Expression generic parameters are currently unimplemented: ", $3->build()) ); $$ = nullptr; }
     
    25782612                {
    25792613                        linkageStack.push( linkage );                           // handle nested extern "C"/"Cforall"
    2580                         linkage = LinkageSpec::linkageUpdate( yylloc, linkage, $2 );
     2614                        linkage = LinkageSpec::update( yylloc, linkage, $2 );
    25812615                }
    25822616          '{' up external_definition_list_opt down '}'
  • src/ResolvExpr/AdjustExprType.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Sat May 16 23:41:42 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar  2 17:34:53 2016
    13 // Update Count     : 4
     12// Last Modified On : Wed Dec 11 21:43:56 2019
     13// Update Count     : 6
    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::TypeVar::Ftype ) {
     136                                if ( eqvClass->data.kind == ast::TypeDecl::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::TypeVar::Ftype ) {
     141                                        if ( tyDecl->kind == ast::TypeDecl::Ftype ) {
    142142                                                return new ast::PointerType{ inst };
    143143                                        }
  • src/ResolvExpr/AlternativeFinder.cc

    r71d6bd8 r7030dab  
    6969                void postvisit( CastExpr * castExpr );
    7070                void postvisit( VirtualCastExpr * castExpr );
     71                void postvisit( KeywordCastExpr * castExpr );
    7172                void postvisit( UntypedMemberExpr * memberExpr );
    7273                void postvisit( MemberExpr * memberExpr );
     
    12551256        }
    12561257
     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
    12571315        namespace {
    12581316                /// Gets name from untyped member expression (member must be NameExpr)
  • src/ResolvExpr/PtrsCastable.cc

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

    r71d6bd8 r7030dab  
    99// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed May 29 11:00:00 2019
    13 // Update Count     : 241
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Mar 27 11:58:00 2020
     13// Update Count     : 242
    1414//
    1515
     
    8484                void previsit( ThrowStmt * throwStmt );
    8585                void previsit( CatchStmt * catchStmt );
     86                void postvisit( CatchStmt * catchStmt );
    8687                void previsit( WaitForStmt * stmt );
    8788
     
    559560                // TODO: Replace *exception type with &exception type.
    560561                if ( throwStmt->get_expr() ) {
    561                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" );
     562                        const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
    562563                        assert( exception_decl );
    563564                        Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
     
    567568
    568569        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.
    569576                if ( catchStmt->cond ) {
    570                         findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer );
     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;
    571594                }
    572595        }
     
    14541477                if ( throwStmt->expr ) {
    14551478                        const ast::StructDecl * exceptionDecl =
    1456                                 symtab.lookupStruct( "__cfaabi_ehm__base_exception_t" );
     1479                                symtab.lookupStruct( "__cfaehm_base_exception_t" );
    14571480                        assert( exceptionDecl );
    14581481                        ast::ptr< ast::Type > exceptType =
     
    14661489
    14671490        const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
     1491                // TODO: This will need a fix for the decl/cond scoping problem.
    14681492                if ( catchStmt->cond ) {
    14691493                        ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool };
  • src/ResolvExpr/Unify.cc

    r71d6bd8 r7030dab  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:27:10 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Sep  4 10:00:00 2019
    13 // Update Count     : 44
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:43:05 2019
     13// Update Count     : 46
    1414//
    1515
     
    3434#include "Common/PassVisitor.h"     // for PassVisitor
    3535#include "FindOpenVars.h"           // for findOpenVars
    36 #include "Parser/LinkageSpec.h"     // for C
     36#include "SynTree/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::TypeVar::Ttype && clz->bound ) {
     773                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
    774774                                                return clz->bound;
    775775                                        }
  • src/SymTab/Autogen.h

    r71d6bd8 r7030dab  
    1010// Created On       : Sun May 17 21:53:34 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:50:25 2017
    13 // Update Count     : 15
     12// Last Modified On : Fri Dec 13 16:38:06 2019
     13// Update Count     : 16
    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
    3738
    3839class CompoundStmt;
  • src/SymTab/Demangle.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Thu Jul 19 12:52:41 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul 30 13:46:33 2019
    13 // Update Count     : 3
     12// Last Modified On : Tue Feb 11 15:09:18 2020
     13// Update Count     : 10
    1414//
    1515
     
    1919#include "CodeGen/GenType.h"
    2020#include "Common/PassVisitor.h"
     21#include "Common/utility.h"                                                             // isPrefix
    2122#include "Mangler.h"
    2223#include "SynTree/Type.h"
     
    366367                                // type variable types
    367368                                for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) {
    368                                         static const std::string typeVariableNames[] = { "DT", "FT", "TT", };
     369                                        static const std::string typeVariableNames[] = { "DT", "OT", "FT", "TT", };
    369370                                        static_assert(
    370371                                                sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS,
     
    416417
    417418                        bool StringView::isPrefix(const std::string & pref) {
    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()) {
     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 ) ) {
    421428                                        idx += pref.size();
    422429                                        return true;
     
    429436                                PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
    430437                                if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
    431                                 if (! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back())) return false;
     438                                if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
    432439
    433440                                // get name
  • src/SymTab/Indexer.cc

    r71d6bd8 r7030dab  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 21
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:43:19 2019
     13// Update Count     : 22
    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
    3433#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

    r71d6bd8 r7030dab  
    1010// Created On       : Sun May 17 21:40:29 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul 30 13:46:10 2019
    13 // Update Count     : 26
     12// Last Modified On : Sat Feb 15 13:55:12 2020
     13// Update Count     : 33
    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...
    2928#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                                 CodeGen::OperatorInfo opInfo;
    131                                 if ( operatorLookup( declaration->get_name(), opInfo ) ) {
    132                                         mangleName << opInfo.outputName.size() << opInfo.outputName;
     130                                const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
     131                                if ( opInfo ) {
     132                                        mangleName << opInfo->outputName.size() << opInfo->outputName;
    133133                                } else {
    134134                                        mangleName << declaration->name.size() << declaration->name;
     
    471471                        } // if
    472472                        mangleName << Encoding::manglePrefix;
    473                         CodeGen::OperatorInfo opInfo;
    474                         if ( operatorLookup( decl->name, opInfo ) ) {
    475                                 mangleName << opInfo.outputName.size() << opInfo.outputName;
     473                        const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
     474                        if ( 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::TypeVar::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
     656                        assertf( decl->kind < ast::TypeDecl::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::TypeVar::Kind::Dtype:
     676                                                case ast::TypeDecl::Kind::Dtype:
    677677                                                        dcount++;
    678678                                                        break;
    679                                                 case ast::TypeVar::Kind::Ftype:
     679                                                case ast::TypeDecl::Kind::Ftype:
    680680                                                        fcount++;
    681681                                                        break;
    682                                                 case ast::TypeVar::Kind::Ttype:
     682                                                case ast::TypeDecl::Kind::Ttype:
    683683                                                        vcount++;
    684684                                                        break;
  • src/SymTab/ManglerCommon.cc

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

    r71d6bd8 r7030dab  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:50:04 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Aug  7 6:42:00 2019
    13 // Update Count     : 360
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:43:34 2019
     13// Update Count     : 363
    1414//
    1515
     
    6969#include "InitTweak/GenInit.h"         // for fixReturnStatements
    7070#include "InitTweak/InitTweak.h"       // for isCtorDtorAssign
    71 #include "Parser/LinkageSpec.h"        // for C
    7271#include "ResolvExpr/typeops.h"        // for typesCompatible
    7372#include "ResolvExpr/Resolver.h"       // for findSingleExpression
    7473#include "ResolvExpr/ResolveTypeof.h"  // for resolveTypeof
    7574#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
    313314                        acceptAll( translationUnit, hoistDecls );
    314315                        ReplaceTypedef::replaceTypedef( translationUnit );
     
    336337                        Stats::Time::BlockGuard guard("validate-C");
    337338                        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::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                         });
     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);
    392387                }
    393388        }
     
    10491044                Type * designatorType = tyDecl->base->stripDeclarator();
    10501045                if ( StructInstType * aggDecl = dynamic_cast< StructInstType * >( designatorType ) ) {
    1051                         declsToAddBefore.push_back( new StructDecl( aggDecl->name, DeclarationNode::Struct, noAttributes, tyDecl->linkage ) );
     1046                        declsToAddBefore.push_back( new StructDecl( aggDecl->name, AggregateDecl::Struct, noAttributes, tyDecl->linkage ) );
    10521047                } else if ( UnionInstType * aggDecl = dynamic_cast< UnionInstType * >( designatorType ) ) {
    10531048                        declsToAddBefore.push_back( new UnionDecl( aggDecl->name, noAttributes, tyDecl->linkage ) );
     
    11871182                if ( CodeGen::isCtorDtorAssign( funcDecl->get_name() ) ) { // TODO: also check /=, etc.
    11881183                        if ( params.size() == 0 ) {
    1189                                 SemanticError( funcDecl, "Constructors, destructors, and assignment functions require at least one parameter " );
     1184                                SemanticError( funcDecl->location, "Constructors, destructors, and assignment functions require at least one parameter." );
    11901185                        }
    11911186                        ReferenceType * refType = dynamic_cast< ReferenceType * >( params.front()->get_type() );
    11921187                        if ( ! refType ) {
    1193                                 SemanticError( funcDecl, "First parameter of a constructor, destructor, or assignment function must be a reference " );
     1188                                SemanticError( funcDecl->location, "First parameter of a constructor, destructor, or assignment function must be a reference." );
    11941189                        }
    11951190                        if ( CodeGen::isCtorDtor( funcDecl->get_name() ) && returnVals.size() != 0 ) {
    1196                                 SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " );
     1191                                if(!returnVals.front()->get_type()->isVoid()) {
     1192                                        SemanticError( funcDecl->location, "Constructors and destructors cannot have explicit return values." );
     1193                                }
    11971194                        }
    11981195                }
  • src/SynTree/AggregateDecl.cc

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:54:14 2017
    13 // Update Count     : 39
     12// Last Modified On : Thu Feb 13 21:34:08 2020
     13// Update Count     : 40
    1414//
    1515
     
    3838        virtual ~Attribute();
    3939
    40         std::string get_name() const { return name; }
     40        const 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

    r71d6bd8 r7030dab  
    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 : Wed Aug  9 14:38:00 2017
    13 // Update Count     : 25
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 16:39:56 2019
     13// Update Count     : 36
    1414//
    1515
     
    2424#include "SynTree/Statement.h"       // for AsmStmt
    2525#include "SynTree/SynTree.h"         // for UniqueId
     26#include "SynTree/Expression.h"
    2627#include "Type.h"                    // for Type, Type::StorageClasses
    2728
     29// To canonicalize declarations
    2830static UniqueId lastUniqueId = 0;
    2931
  • src/SynTree/Declaration.h

    r71d6bd8 r7030dab  
    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 : Thr May  2 10:47:00 2019
    13 // Update Count     : 135
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:11:22 2019
     13// Update Count     : 157
    1414//
    1515
     
    2424#include "BaseSyntaxNode.h"      // for BaseSyntaxNode
    2525#include "Mutator.h"             // for Mutator
    26 #include "Parser/LinkageSpec.h"  // for Spec, Cforall
    27 #include "Parser/ParseNode.h"    // for DeclarationNode, DeclarationNode::Ag...
     26#include "LinkageSpec.h"         // for Spec, Cforall
    2827#include "SynTree.h"             // for UniqueId
    2928#include "SynTree/Type.h"        // for Type, Type::StorageClasses, Type::Fu...
     
    4443        bool extension = false;
    4544
    46         Declaration( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage );
    47         Declaration( const Declaration &other );
     45        Declaration( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage );
     46        Declaration( const Declaration & other );
    4847        virtual ~Declaration();
    4948
    50         const std::string &get_name() const { return name; }
     49        const std::string & get_name() const { return name; }
    5150        void set_name( std::string newValue ) { name = newValue; }
    5251
     
    5958
    6059        bool get_extension() const { return extension; }
    61         Declaration *set_extension( bool exten ) { extension = exten; return this; }
     60        Declaration * set_extension( bool exten ) { extension = exten; return this; }
    6261
    6362        void fixUniqueId( void );
    64         virtual Declaration *clone() const override = 0;
     63        virtual Declaration * clone() const override = 0;
    6564        virtual void accept( Visitor & v ) override = 0;
    6665        virtual void accept( Visitor & v ) const override = 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;
     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;
    7069
    7170        UniqueId uniqueId;
     
    8180        int scopeLevel = 0;
    8281
    83         Expression *asmName;
     82        Expression * asmName;
    8483        std::list< Attribute * > attributes;
    8584        bool isDeleted = false;
    8685
    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 );
     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 );
    8988        virtual ~DeclarationWithType();
    9089
     
    9796        DeclarationWithType * set_scopeLevel( int newValue ) { scopeLevel = newValue; return this; }
    9897
    99         Expression *get_asmName() const { return asmName; }
    100         DeclarationWithType * set_asmName( Expression *newValue ) { asmName = newValue; return this; }
     98        Expression * get_asmName() const { return asmName; }
     99        DeclarationWithType * set_asmName( Expression * newValue ) { asmName = newValue; return this; }
    101100
    102101        std::list< Attribute * >& get_attributes() { return attributes; }
     
    106105        //void set_functionSpecifiers( Type::FuncSpecifiers newValue ) { fs = newValue; }
    107106
    108         virtual DeclarationWithType *clone() const override = 0;
    109         virtual DeclarationWithType *acceptMutator( Mutator &m )  override = 0;
     107        virtual DeclarationWithType * clone() const override = 0;
     108        virtual DeclarationWithType * acceptMutator( Mutator & m )  override = 0;
    110109
    111110        virtual Type * get_type() const = 0;
     
    119118        typedef DeclarationWithType Parent;
    120119  public:
    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,
     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,
    126125                                const std::list< Attribute * > attributes = std::list< Attribute * >(), Type::FuncSpecifiers fs = Type::FuncSpecifiers() );
    127         ObjectDecl( const ObjectDecl &other );
     126        ObjectDecl( const ObjectDecl & other );
    128127        virtual ~ObjectDecl();
    129128
    130129        virtual Type * get_type() const override { return type; }
    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; }
     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; }
    138137
    139138        static ObjectDecl * newObject( const std::string & name, Type * type, Initializer * init );
    140139
    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;
     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;
    147146};
    148147
     
    150149        typedef DeclarationWithType Parent;
    151150  public:
    152         FunctionType *type;
    153         CompoundStmt *statements;
     151        FunctionType * type;
     152        CompoundStmt * statements;
    154153        std::list< Expression * > withExprs;
    155154
    156         FunctionDecl( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage, FunctionType *type, CompoundStmt *statements,
     155        FunctionDecl( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage, FunctionType * type, CompoundStmt * statements,
    157156                                  const std::list< Attribute * > attributes = std::list< Attribute * >(), Type::FuncSpecifiers fs = Type::FuncSpecifiers() );
    158         FunctionDecl( const FunctionDecl &other );
     157        FunctionDecl( const FunctionDecl & other );
    159158        virtual ~FunctionDecl();
    160159
     
    163162
    164163        FunctionType * get_functionType() const { return type; }
    165         void set_functionType( FunctionType *newValue ) { type = newValue; }
    166         CompoundStmt *get_statements() const { return statements; }
    167         void set_statements( CompoundStmt *newValue ) { statements = newValue; }
     164        void set_functionType( FunctionType * newValue ) { type = newValue; }
     165        CompoundStmt * get_statements() const { return statements; }
     166        void set_statements( CompoundStmt * newValue ) { statements = newValue; }
    168167        bool has_body() const { return NULL != statements; }
    169168
    170169        static FunctionDecl * newFunction( const std::string & name, FunctionType * type, CompoundStmt * statements );
    171170
    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;
     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;
    178177};
    179178
     
    181180        typedef Declaration Parent;
    182181  public:
    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 );
     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 );
    189188        virtual ~NamedTypeDecl();
    190189
    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;
     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;
    201200};
    202201
     
    204203        typedef NamedTypeDecl Parent;
    205204  public:
    206         enum Kind { Dtype, Ftype, Ttype, NUMBER_OF_KINDS };
    207 
     205        enum Kind { Dtype, Otype, Ftype, Ttype, NUMBER_OF_KINDS };
     206
     207        Kind kind;
     208        bool sized;
    208209        Type * init;
    209         bool sized;
    210210
    211211        /// Data extracted from a type decl
    212212        struct Data {
    213                 TypeDecl::Kind kind;
     213                Kind kind;
    214214                bool isComplete;
    215215
    216                 Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    217                 Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
     216                Data() : kind( NUMBER_OF_KINDS ), isComplete( false ) {}
     217                Data( const 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 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;
     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;
    249247};
    250248
     
    252250        typedef NamedTypeDecl Parent;
    253251  public:
    254         TypedefDecl( const std::string &name, CodeLocation location, Type::StorageClasses scs, Type *type, LinkageSpec::Spec spec = LinkageSpec::Cforall )
     252        TypedefDecl( const std::string & name, CodeLocation location, Type::StorageClasses scs, Type * type, LinkageSpec::Spec spec = LinkageSpec::Cforall )
    255253                : Parent( name, scs, type ) { set_linkage( spec ); this->location = location; }
    256254
    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 ); }
     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 ); }
    265263  private:
    266264};
     
    269267        typedef Declaration Parent;
    270268  public:
     269        enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
     270        static const char * aggrString( Aggregate aggr );
     271
    271272        std::list<Declaration*> members;
    272273        std::list<TypeDecl*> parameters;
     
    275276        AggregateDecl * parent = nullptr;
    276277
    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 );
     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 );
    279280        virtual ~AggregateDecl();
    280281
     
    288289        AggregateDecl * set_body( bool body ) { AggregateDecl::body = body; return this; }
    289290
    290         virtual void print( std::ostream &os, Indenter indent = {} ) const override final;
    291         virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
     291        virtual void print( std::ostream & os, Indenter indent = {} ) const override final;
     292        virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
    292293  protected:
    293         virtual std::string typeString() const = 0;
     294        virtual const char * typeString() const = 0;
    294295};
    295296
     
    297298        typedef AggregateDecl Parent;
    298299  public:
    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;
     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;
    313315};
    314316
     
    316318        typedef AggregateDecl Parent;
    317319  public:
    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;
     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;
    327329};
    328330
     
    330332        typedef AggregateDecl Parent;
    331333  public:
    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 ) {}
     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 ) {}
    334336
    335337        bool valueOf( Declaration * enumerator, long long int & value );
    336338
    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 ); }
     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 ); }
    341343  private:
    342344        std::unordered_map< std::string, long long int > enumValues;
    343         virtual std::string typeString() const override;
     345        virtual const char * typeString() const override;
    344346};
    345347
     
    347349        typedef AggregateDecl Parent;
    348350  public:
    349         TraitDecl( const std::string &name, const std::list< Attribute * > & attributes, LinkageSpec::Spec linkage ) : Parent( name, attributes, linkage ) {
     351        TraitDecl( const std::string & name, const std::list< Attribute * > & attributes, LinkageSpec::Spec linkage ) : Parent( name, attributes, linkage ) {
    350352                assertf( attributes.empty(), "attribute unsupported for traits" );
    351353        }
    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;
     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;
    360362};
    361363
     
    379381class AsmDecl : public Declaration {
    380382  public:
    381         AsmStmt *stmt;
    382 
    383         AsmDecl( AsmStmt *stmt );
    384         AsmDecl( const AsmDecl &other );
     383        AsmStmt * stmt;
     384
     385        AsmDecl( AsmStmt * stmt );
     386        AsmDecl( const AsmDecl & other );
    385387        virtual ~AsmDecl();
    386388
    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;
     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;
    396398};
    397399
     
    408410        virtual void accept( Visitor & v ) override { v.visit( this ); }
    409411        virtual void accept( Visitor & v ) const override { v.visit( this ); }
    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;
     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;
    413415};
    414416
  • src/SynTree/DeclarationWithType.cc

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

    r71d6bd8 r7030dab  
    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 : Thr Aug 15 13:43:00 2019
    13 // Update Count     : 64
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 07:55:15 2019
     13// Update Count     : 70
    1414//
    1515
     
    2222
    2323#include "Common/utility.h"          // for maybeClone, cloneAll, deleteAll
    24 #include "Declaration.h"             // for ObjectDecl, DeclarationWithType
    2524#include "Expression.h"              // for Expression, ImplicitCopyCtorExpr
    2625#include "InitTweak/InitTweak.h"     // for getCallArg, getPointerBase
     
    294293}
    295294
    296 KeywordCastExpr::KeywordCastExpr( Expression * arg, Target target ) : Expression(), arg(arg), target( target ) {
     295KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {
    297296}
    298297
     
    304303}
    305304
    306 const 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];
     305const char * KeywordCastExpr::targetString() const {
     306        return AggregateDecl::aggrString( target );
    315307}
    316308
  • src/SynTree/Expression.h

    r71d6bd8 r7030dab  
    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 : Thr Aug 15 13:46:00 2019
    13 // Update Count     : 54
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Dec 11 16:50:19 2019
     13// Update Count     : 60
    1414//
    1515
     
    2828#include "Label.h"                // for Label
    2929#include "Mutator.h"              // for Mutator
     30#include "Declaration.h"          // for Aggregate
    3031#include "SynTree.h"              // for UniqueId
    3132#include "Visitor.h"              // for Visitor
     
    229230public:
    230231        Expression * arg;
    231         enum Target {
    232                 Coroutine, Thread, Monitor, NUMBER_OF_TARGETS
    233         } target;
    234 
    235         KeywordCastExpr( Expression * arg, Target target );
     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 );
    236240        KeywordCastExpr( const KeywordCastExpr & other );
    237241        virtual ~KeywordCastExpr();
    238242
    239         const std::string & targetString() const;
     243        const char * targetString() const;
    240244
    241245        virtual KeywordCastExpr * clone() const override { return new KeywordCastExpr( * this ); }
  • src/SynTree/FunctionDecl.cc

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

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

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

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

    r71d6bd8 r7030dab  
    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 Sep  3 20:46:44 2017
    13 // Update Count     : 68
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Jan 20 16:03:00 2020
     13// Update Count     : 71
    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[] = { "Goto", "Break", "Continue" };
     103const char * BranchStmt::brType[] = {
     104        "Goto", "Break", "Continue", "Fall Through", "Fall Through Default",
     105};
    104106
    105107BranchStmt::BranchStmt( Label target, Type type ) throw ( SemanticErrorException ) :
     
    111113}
    112114
    113 BranchStmt::BranchStmt( Expression *computedTarget, Type type ) throw ( SemanticErrorException ) :
     115BranchStmt::BranchStmt( Expression * computedTarget, Type type ) throw ( SemanticErrorException ) :
    114116        Statement(), computedTarget( computedTarget ), type( type ) {
    115117        if ( type != BranchStmt::Goto || computedTarget == nullptr ) {
     
    118120}
    119121
    120 void BranchStmt::print( std::ostream &os, Indenter indent ) const {
     122void BranchStmt::print( std::ostream & os, Indenter indent ) const {
     123        assert(type < 5);
    121124        os << "Branch (" << brType[type] << ")" << endl ;
    122125        if ( target != "" ) os << indent+1 << "with target: " << target << endl;
     
    125128}
    126129
    127 ReturnStmt::ReturnStmt( Expression *expr ) : Statement(), expr( expr ) {}
     130ReturnStmt::ReturnStmt( Expression * expr ) : Statement(), expr( expr ) {}
    128131
    129132ReturnStmt::ReturnStmt( const ReturnStmt & other ) : Statement( other ), expr( maybeClone( other.expr ) ) {}
     
    133136}
    134137
    135 void ReturnStmt::print( std::ostream &os, Indenter indent ) const {
     138void ReturnStmt::print( std::ostream & os, Indenter indent ) const {
    136139        os << "Return Statement, returning: ";
    137140        if ( expr != nullptr ) {
     
    142145}
    143146
    144 IfStmt::IfStmt( Expression *condition, Statement *thenPart, Statement *elsePart, std::list<Statement *> initialization ):
     147IfStmt::IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart, std::list<Statement *> initialization ):
    145148        Statement(), condition( condition ), thenPart( thenPart ), elsePart( elsePart ), initialization( initialization ) {}
    146149
     
    157160}
    158161
    159 void IfStmt::print( std::ostream &os, Indenter indent ) const {
     162void IfStmt::print( std::ostream & os, Indenter indent ) const {
    160163        os << "If on condition: " << endl;
    161164        os << indent+1;
     
    176179        thenPart->print( os, indent+1 );
    177180
    178         if ( elsePart != 0 ) {
     181        if ( elsePart != nullptr ) {
    179182                os << indent << "... else: " << endl;
    180183                os << indent+1;
     
    183186}
    184187
    185 SwitchStmt::SwitchStmt( Expression * condition, const std::list<Statement *> &statements ):
     188SwitchStmt::SwitchStmt( Expression * condition, const std::list<Statement *> & statements ):
    186189        Statement(), condition( condition ), statements( statements ) {
    187190}
     
    198201}
    199202
    200 void SwitchStmt::print( std::ostream &os, Indenter indent ) const {
     203void SwitchStmt::print( std::ostream & os, Indenter indent ) const {
    201204        os << "Switch on condition: ";
    202205        condition->print( os );
     
    208211}
    209212
    210 CaseStmt::CaseStmt( Expression *condition, const std::list<Statement *> &statements, bool deflt ) throw ( SemanticErrorException ) :
     213CaseStmt::CaseStmt( Expression * condition, const std::list<Statement *> & statements, bool deflt ) throw ( SemanticErrorException ) :
    211214        Statement(), condition( condition ), stmts( statements ), _isDefault( deflt ) {
    212         if ( isDefault() && condition != 0 ) SemanticError( condition, "default case with condition: " );
     215        if ( isDefault() && condition != nullptr ) SemanticError( condition, "default case with condition: " );
    213216}
    214217
     
    229232}
    230233
    231 void CaseStmt::print( std::ostream &os, Indenter indent ) const {
     234void CaseStmt::print( std::ostream & os, Indenter indent ) const {
    232235        if ( isDefault() ) os << indent << "Default ";
    233236        else {
     
    243246}
    244247
    245 WhileStmt::WhileStmt( Expression *condition, Statement *body, std::list< Statement * > & initialization, bool isDoWhile ):
     248WhileStmt::WhileStmt( Expression * condition, Statement * body, std::list< Statement * > & initialization, bool isDoWhile ):
    246249        Statement(), condition( condition), body( body), initialization( initialization ), isDoWhile( isDoWhile) {
    247250}
     
    256259}
    257260
    258 void WhileStmt::print( std::ostream &os, Indenter indent ) const {
     261void WhileStmt::print( std::ostream & os, Indenter indent ) const {
    259262        os << "While on condition: " << endl ;
    260263        condition->print( os, indent+1 );
     
    262265        os << indent << "... with body: " << endl;
    263266
    264         if ( body != 0 ) body->print( os, indent+1 );
    265 }
    266 
    267 ForStmt::ForStmt( std::list<Statement *> initialization, Expression *condition, Expression *increment, Statement *body ):
     267        if ( body != nullptr ) body->print( os, indent+1 );
     268}
     269
     270ForStmt::ForStmt( std::list<Statement *> initialization, Expression * condition, Expression * increment, Statement * body ):
    268271        Statement(), initialization( initialization ), condition( condition ), increment( increment ), body( body ) {
    269272}
     
    282285}
    283286
    284 void ForStmt::print( std::ostream &os, Indenter indent ) const {
     287void ForStmt::print( std::ostream & os, Indenter indent ) const {
    285288        Statement::print( os, indent ); // print labels
    286289
     
    305308        }
    306309
    307         if ( body != 0 ) {
     310        if ( body != nullptr ) {
    308311                os << "\n" << indent << "... with body: \n" << indent+1;
    309312                body->print( os, indent+1 );
     
    317320}
    318321
    319 ThrowStmt::ThrowStmt( const ThrowStmt &other ) :
     322ThrowStmt::ThrowStmt( const ThrowStmt & other ) :
    320323        Statement ( other ), kind( other.kind ), expr( maybeClone( other.expr ) ), target( maybeClone( other.target ) ) {
    321324}
     
    326329}
    327330
    328 void ThrowStmt::print( std::ostream &os, Indenter indent) const {
     331void ThrowStmt::print( std::ostream & os, Indenter indent) const {
    329332        if ( target ) os << "Non-Local ";
    330333        os << "Throw Statement, raising: ";
     
    336339}
    337340
    338 TryStmt::TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock ) :
     341TryStmt::TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock ) :
    339342        Statement(), block( tryBlock ),  handlers( handlers ), finallyBlock( finallyBlock ) {
    340343}
    341344
    342 TryStmt::TryStmt( const TryStmt &other ) : Statement( other ), block( maybeClone( other.block ) ), finallyBlock( maybeClone( other.finallyBlock ) ) {
     345TryStmt::TryStmt( const TryStmt & other ) : Statement( other ), block( maybeClone( other.block ) ), finallyBlock( maybeClone( other.finallyBlock ) ) {
    343346        cloneAll( other.handlers, handlers );
    344347}
     
    350353}
    351354
    352 void TryStmt::print( std::ostream &os, Indenter indent ) const {
     355void TryStmt::print( std::ostream & os, Indenter indent ) const {
    353356        os << "Try Statement" << endl;
    354357        os << indent << "... with block:" << endl << indent+1;
     
    363366
    364367        // finally block
    365         if ( finallyBlock != 0 ) {
     368        if ( finallyBlock != nullptr ) {
    366369                os << indent << "... and finally:" << endl << indent+1;
    367370                finallyBlock->print( os, indent+1 );
     
    369372}
    370373
    371 CatchStmt::CatchStmt( Kind kind, Declaration *decl, Expression *cond, Statement *body ) :
     374CatchStmt::CatchStmt( Kind kind, Declaration * decl, Expression * cond, Statement * body ) :
    372375        Statement(), kind ( kind ), decl ( decl ), cond ( cond ), body( body ) {
    373376                assertf( decl, "Catch clause must have a declaration." );
     
    383386}
    384387
    385 void CatchStmt::print( std::ostream &os, Indenter indent ) const {
     388void CatchStmt::print( std::ostream & os, Indenter indent ) const {
    386389        os << "Catch " << ((Terminate == kind) ? "Terminate" : "Resume") << " Statement" << endl;
    387390
     
    401404
    402405
    403 FinallyStmt::FinallyStmt( CompoundStmt *block ) : Statement(), block( block ) {
     406FinallyStmt::FinallyStmt( CompoundStmt * block ) : Statement(), block( block ) {
    404407}
    405408
     
    411414}
    412415
    413 void FinallyStmt::print( std::ostream &os, Indenter indent ) const {
     416void FinallyStmt::print( std::ostream & os, Indenter indent ) const {
    414417        os << "Finally Statement" << endl;
    415418        os << indent << "... with block:" << endl << indent+1;
    416419        block->print( os, indent+1 );
     420}
     421
     422SuspendStmt::SuspendStmt( const SuspendStmt & other )
     423        : Statement( other )
     424        , then( maybeClone(other.then) )
     425{}
     426
     427SuspendStmt::~SuspendStmt() {
     428        delete then;
     429}
     430
     431void 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        }
    417445}
    418446
     
    458486}
    459487
    460 void WaitForStmt::print( std::ostream &os, Indenter indent ) const {
     488void WaitForStmt::print( std::ostream & os, Indenter indent ) const {
    461489        os << "Waitfor Statement" << endl;
    462490        indent += 1;
     
    514542}
    515543
    516 void NullStmt::print( std::ostream &os, Indenter indent ) const {
     544void NullStmt::print( std::ostream & os, Indenter indent ) const {
    517545        os << "Null Statement" << endl;
    518546        Statement::print( os, indent );
     
    530558}
    531559
    532 void ImplicitCtorDtorStmt::print( std::ostream &os, Indenter indent ) const {
     560void ImplicitCtorDtorStmt::print( std::ostream & os, Indenter indent ) const {
    533561        os << "Implicit Ctor Dtor Statement" << endl;
    534562        os << indent << "... with Ctor/Dtor: ";
  • src/SynTree/Statement.h

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 12 09:01:53 2019
    13 // Update Count     : 83
     12// Last Modified On : Fri Jan 10 14:13:24 2020
     13// Update Count     : 85
    1414//
    1515
     
    257257        Statement * body;
    258258
    259         ForStmt( std::list<Statement *> initialization, Expression * condition = 0, Expression * increment = 0, Statement * body = 0 );
     259        ForStmt( std::list<Statement *> initialization, Expression * condition = nullptr, Expression * increment = nullptr, Statement * body = nullptr );
    260260        ForStmt( const ForStmt & other );
    261261        virtual ~ForStmt();
     
    357357        FinallyStmt * finallyBlock;
    358358
    359         TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 );
     359        TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = nullptr );
    360360        TryStmt( const TryStmt & other );
    361361        virtual ~TryStmt();
     
    422422};
    423423
     424class 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
    424440class WaitForStmt : public Statement {
    425441  public:
  • src/SynTree/SynTree.h

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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  4 21:05:07 2019
    13 // Update Count     : 45
     12// Last Modified On : Sun Dec 15 16:52:37 2019
     13// Update Count     : 49
    1414//
    1515#include "Type.h"
     
    2424using namespace std;
    2525
     26// GENERATED START, DO NOT EDIT
     27// GENERATED BY BasicTypes-gen.cc
    2628const char * BasicType::typeNames[] = {
    2729        "_Bool",
     
    4547        "float",
    4648        "float _Complex",
    47         //"float _Imaginary",
    4849        "_Float32x",
    4950        "_Float32x _Complex",
     
    5253        "double",
    5354        "double _Complex",
    54         //"double _Imaginary",
    5555        "_Float64x",
    5656        "_Float64x _Complex",
     
    6161        "long double",
    6262        "long double _Complex",
    63         //"long double _Imaginary",
    6463        "_Float128x",
    6564        "_Float128x _Complex",
    6665};
    67 static_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 );
     66// GENERATED END
    7167
    7268Type::Type( const Qualifiers &tq, const std::list< Attribute * > & attributes ) : tq( tq ), attributes( attributes ) {}
  • src/SynTree/TypeDecl.cc

    r71d6bd8 r7030dab  
    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 : Wed Aug  9 14:35:00 2017
    13 // Update Count     : 6
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 15:26:14 2019
     13// Update Count     : 21
    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 ), init( init ), sized( kind == Ttype || sized ), kind( kind ) {
     23TypeDecl::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 ) {
    2424}
    2525
    26 TypeDecl::TypeDecl( const TypeDecl &other ) : Parent( other ), init( maybeClone( other.init ) ), sized( other.sized ), kind( other.kind ) {
     26TypeDecl::TypeDecl( const TypeDecl & other ) : Parent( other ), kind( other.kind ), sized( other.sized ), init( maybeClone( other.init ) ) {
    2727}
    2828
    2929TypeDecl::~TypeDecl() {
    30   delete init;
     30        delete init;
    3131}
    3232
    33 std::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 ];
     33const 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'
    3838}
    3939
    40 std::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." );
     40const 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." );
    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   }
     48        NamedTypeDecl::print( os, indent );
     49        if ( init ) {
     50                os << std::endl << indent << "with type initializer: ";
     51                init->print( os, indent + 1 );
     52        } // if
    5353}
    5454
    55 
    5655std::ostream & operator<<( std::ostream & os, const TypeDecl::Data & data ) {
    57   return os << data.kind << ", " << data.isComplete;
     56        return os << data.kind << ", " << data.isComplete;
    5857}
    5958
  • src/SynTree/Visitor.h

    r71d6bd8 r7030dab  
    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;
    8082        virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); }
    8183        virtual void visit( const WaitForStmt * waitforStmt ) = 0;
  • src/SynTree/module.mk

    r71d6bd8 r7030dab  
    1111## Created On       : Mon Jun  1 17:49:17 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Jun  1 17:54:09 2015
    14 ## Update Count     : 1
     13## Last Modified On : Sat Dec 14 07:26:43 2019
     14## Update Count     : 2
    1515###############################################################################
    1616
    1717SRC_SYNTREE = \
    18       SynTree/Type.cc \
    19       SynTree/VoidType.cc \
     18      SynTree/AddressExpr.cc \
     19      SynTree/AggregateDecl.cc \
     20      SynTree/ApplicationExpr.cc \
     21      SynTree/ArrayType.cc \
     22      SynTree/AttrType.cc \
     23      SynTree/Attribute.cc \
    2024      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 \
     25      SynTree/CommaExpr.cc \
     26      SynTree/CompoundStmt.cc \
    3127      SynTree/Constant.cc \
    32       SynTree/Expression.cc \
    33       SynTree/TupleExpr.cc \
    34       SynTree/CommaExpr.cc \
    35       SynTree/TypeExpr.cc \
    36       SynTree/ApplicationExpr.cc \
    37       SynTree/AddressExpr.cc \
    38       SynTree/Statement.cc \
    39       SynTree/CompoundStmt.cc \
     28      SynTree/DeclReplacer.cc \
    4029      SynTree/DeclStmt.cc \
    4130      SynTree/Declaration.cc \
    4231      SynTree/DeclarationWithType.cc \
     32      SynTree/Expression.cc \
     33      SynTree/FunctionDecl.cc \
     34      SynTree/FunctionType.cc \
     35      SynTree/Initializer.cc \
     36      SynTree/LinkageSpec.cc \
     37      SynTree/NamedTypeDecl.cc \
    4338      SynTree/ObjectDecl.cc \
    44       SynTree/FunctionDecl.cc \
    45       SynTree/AggregateDecl.cc \
    46       SynTree/NamedTypeDecl.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 \
    4746      SynTree/TypeDecl.cc \
    48       SynTree/Initializer.cc \
     47      SynTree/TypeExpr.cc \
    4948      SynTree/TypeSubstitution.cc \
    50       SynTree/Attribute.cc \
    51       SynTree/DeclReplacer.cc
     49      SynTree/TypeofType.cc \
     50      SynTree/VarArgsType.cc \
     51      SynTree/VoidType.cc \
     52      SynTree/ZeroOneType.cc
    5253
    5354SRC += $(SRC_SYNTREE)
  • src/Tuples/TupleAssignment.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 17 09:43:03 2017
    13 // Update Count     : 8
     12// Last Modified On : Fri Dec 13 23:45:33 2019
     13// Update Count     : 9
    1414//
    1515
     
    3434#include "InitTweak/GenInit.h"             // for genCtorInit
    3535#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
    36 #include "Parser/LinkageSpec.h"            // for Cforall
    3736#include "ResolvExpr/Alternative.h"        // for AltList, Alternative
    3837#include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
     
    4140#include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    4241#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

    r71d6bd8 r7030dab  
    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 : Fri Oct  4 15:38:00 2019
    13 // Update Count     : 23
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 23:45:51 2019
     13// Update Count     : 24
    1414//
    1515
     
    2727#include "Common/utility.h"       // for CodeLocation
    2828#include "InitTweak/InitTweak.h"  // for getFunction
    29 #include "Parser/LinkageSpec.h"   // for Spec, C, Intrinsic
     29#include "SynTree/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::TypeVar::Ttype ) {
     363                        if ( inst->base && inst->base->kind == ast::TypeDecl::Ttype ) {
    364364                                return inst;
    365365                        }
  • src/cfa.make

    r71d6bd8 r7030dab  
    1 
    2 
    31CFACOMPILE = $(CFACC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) $(AM_CFLAGS) $(CFLAGS)
    42LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
    53        $(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
    6         $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
    7         $(AM_CFLAGS) $(CFLAGS)
     4        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
    85
    96AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    2219        $(am__mv) $$depbase.Tpo $$depbase.Plo
    2320
    24 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    25 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    26 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    27 am__v_JAVAC_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 
    3421UPPCC = u++
    3522UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    3926am__v_UPP_0 = @echo "  UPP     " $@;
    4027am__v_UPP_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
     34AM_V_PY = $(am__v_PY_@AM_V@)
     35am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
     36am__v_PY_0 = @echo "  PYTHON  " $@;
     37am__v_PY_1 =
     38
     39AM_V_RUST = $(am__v_RUST_@AM_V@)
     40am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
     41am__v_RUST_0 = @echo "  RUST    " $@;
     42am__v_RUST_1 =
     43
     44AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
     45am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
     46am__v_NODEJS_0 = @echo "  NODEJS  " $@;
     47am__v_NODEJS_1 =
     48
     49AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     50am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     51am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     52am__v_JAVAC_1 =
  • src/main.cc

    r71d6bd8 r7030dab  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Aug 23 06:50:08 2019
    13 // Update Count     : 607
     12// Last Modified On : Sat Feb  8 08:33:50 2020
     13// Update Count     : 633
    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
     31using namespace std;
    3032
    3133#include "AST/Convert.hpp"
     
    5456#include "InitTweak/GenInit.h"              // for genInit
    5557#include "MakeLibCfa.h"                     // for makeLibCfa
    56 #include "Parser/LinkageSpec.h"             // for Spec, Cforall, Intrinsic
    5758#include "Parser/ParseNode.h"               // for DeclarationNode, buildList
    5859#include "Parser/TypedefTable.h"            // for TypedefTable
     
    6061#include "ResolvExpr/Resolver.h"            // for resolve
    6162#include "SymTab/Validate.h"                // for validate
     63#include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    6264#include "SynTree/Declaration.h"            // for Declaration
    6365#include "SynTree/Visitor.h"                // for acceptAll
     
    6567#include "Virtual/ExpandCasts.h"            // for expandCasts
    6668
    67 
    68 using 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 std::string PreludeDirector = "";
     100static 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 };
     107        enum { Frames = 50, };                                                          // maximum number of stack frames
    108108        void * array[Frames];
    109         int size = ::backtrace( array, Frames );
     109        size_t 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 ( int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
     116        for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
    117117                char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr;
    118                 for ( char *p = messages[i]; *p; ++p ) {        // find parantheses and +offset
     118
     119                for ( char * p = messages[i]; *p; p += 1 ) {    // find parantheses and +offset
    119120                        if ( *p == '(' ) {
    120121                                mangled_name = p;
     
    154155} // backtrace
    155156
    156 static 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;
     157#define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused ))
     158
     159static 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
     171static 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
    160178        backtrace( 2 );                                                                         // skip first 2 stack frames
    161         //_exit( EXIT_FAILURE );
    162179        abort();                                                                                        // cause core dump for debugging
    163180} // sigSegvBusHandler
    164181
    165 static void sigAbortHandler( __attribute__((unused)) int sig_num ) {
     182static 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
     199static void sigAbortHandler( SIGPARMS ) {
    166200        backtrace( 6 );                                                                         // skip first 6 stack frames
    167         signal( SIGABRT, SIG_DFL);                                                      // reset default signal handler
     201        Signal( SIGABRT, (void (*)(SIGPARMS))SIG_DFL, SA_SIGINFO );     // reset default signal handler
    168202        raise( SIGABRT );                                                                       // reraise SIGABRT
    169203} // sigAbortHandler
     
    174208        list< Declaration * > translationUnit;
    175209
    176         signal( SIGSEGV, sigSegvBusHandler );
    177         signal( SIGBUS, sigSegvBusHandler );
    178         signal( SIGABRT, sigAbortHandler );
    179 
    180         // std::cout << "main" << std::endl;
     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;
    181216        // for ( int i = 0; i < argc; i += 1 ) {
    182         //      std::cout << '\t' << argv[i] << std::endl;
     217        //      cout << '\t' << argv[i] << endl;
    183218        // } // for
    184219
     
    187222
    188223        if ( waiting_for_gdb ) {
    189                 std::cerr << "Waiting for gdb" << std::endl;
    190                 std::cerr << "run :" << std::endl;
    191                 std::cerr << "  gdb attach " << getpid() << std::endl;
     224                cerr << "Waiting for gdb" << endl;
     225                cerr << "run :" << endl;
     226                cerr << "  gdb attach " << getpid() << endl;
    192227                raise(SIGSTOP);
    193228        } // if
     
    395430                return EXIT_FAILURE;
    396431        } catch ( ... ) {
    397                 std::exception_ptr eptr = std::current_exception();
     432                exception_ptr eptr = current_exception();
    398433                try {
    399434                        if (eptr) {
    400                                 std::rethrow_exception(eptr);
     435                                rethrow_exception(eptr);
    401436                        } else {
    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";
     437                                cerr << "Exception Uncaught and Unknown" << endl;
     438                        } // if
     439                } catch(const exception& e) {
     440                        cerr << "Uncaught Exception \"" << e.what() << "\"\n";
    406441                } // try
    407442                return EXIT_FAILURE;
     
    414449
    415450
    416 static const char optstring[] = ":hlLmNnpP:S:tgwW:D:";
     451static const char optstring[] = ":c:ghlLmNnpP:S:twW:D:";
    417452
    418453enum { PreludeDir = 128 };
    419454static struct option long_opts[] = {
     455        { "colors", required_argument, nullptr, 'c' },
     456        { "gdb", no_argument, nullptr, 'g' },
    420457        { "help", no_argument, nullptr, 'h' },
    421458        { "libcfa", no_argument, nullptr, 'l' },
     
    429466        { "statistics", required_argument, nullptr, 'S' },
    430467        { "tree", no_argument, nullptr, 't' },
    431         { "gdb", no_argument, nullptr, 'g' },
    432468        { "", no_argument, nullptr, 0 },                                        // -w
    433469        { "", no_argument, nullptr, 0 },                                        // -W
     
    437473
    438474static const char * description[] = {
    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
     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
    445483        "generate prototypes for prelude functions",            // -p
    446         "print",                                                                                        // -P
     484        "print",                                              // -P
    447485        "<directory> prelude directory for debug/nodebug",      // no flag
    448486        "<option-list> enable profiling information:\n          counters,heap,time,all,none", // -S
    449         "building cfa standard lib",                                                                    // -t
    450         "wait for gdb to attach",                                                                       // -g
    451         "",                                                                                                     // -w
    452         "",                                                                                                     // -W
    453         "",                                                                                                     // -D
     487        "building cfa standard lib",                          // -t
     488        "",                                                   // -w
     489        "",                                                   // -W
     490        "",                                                   // -D
    454491}; // description
    455492
     
    519556        while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
    520557                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;
    521567                  case 'h':                                                                             // help message
    522568                        usage( argv );                                                          // no return
  • tests/.expect/alloc-ERROR.txt

    r71d6bd8 r7030dab  
    1 alloc.cfa:311:1 error: No reasonable alternatives for expression Applying untyped:
     1alloc.cfa:362:1 error: No reasonable alternatives for expression Applying untyped:
    22  Name: ?=?
    33...to:
    4   Name: p
     4  Name: ip
    55  Applying untyped:
    66    Name: realloc
     
    1919
    2020
    21 alloc.cfa:312:1 error: No reasonable alternatives for expression Applying untyped:
     21alloc.cfa:363:1 error: No reasonable alternatives for expression Applying untyped:
    2222  Name: ?=?
    2323...to:
    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 
    41 alloc.cfa:313:1 error: No reasonable alternatives for expression Applying untyped:
    42   Name: ?=?
    43 ...to:
    44   Name: p
     24  Name: ip
    4525  Applying untyped:
    4626    Name: memset
     
    5030
    5131
    52 alloc.cfa:314:1 error: No reasonable alternatives for expression Applying untyped:
     32alloc.cfa:364:1 error: No reasonable alternatives for expression Applying untyped:
    5333  Name: ?=?
    5434...to:
    55   Name: p
     35  Name: ip
    5636  Applying untyped:
    5737    Name: memcpy
  • tests/.expect/alloc.txt

    r71d6bd8 r7030dab  
    22CFA malloc 0xdeadbeef
    33CFA alloc 0xdeadbeef
    4 CFA array alloc, fill 0xde
    54CFA alloc, fill dededede
    65CFA alloc, fill 3
     
    24230xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0xefefefef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
    2524
    26 CFA resize array alloc
     25CFA realloc array alloc
    27260xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    28 CFA resize array alloc
     27CFA realloc array alloc
    29280xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101 0x1010101
    30 CFA resize array alloc
     29CFA realloc array alloc
    31300xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    32 CFA resize array alloc, fill
     31CFA realloc array alloc, fill
    33320xdeadbeef 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
    34 CFA resize array alloc, fill
     33CFA realloc array alloc, fill
    35340xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    36 CFA resize array alloc, fill
    37 0xdeadbeef 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
     35CFA realloc array alloc, fill
     360xdeadbeef 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
     37CFA realloc array alloc, 5
     380xdeadbeef 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
     39CFA realloc array alloc, 5
     400xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
     41CFA realloc array alloc, 5
     420xdeadbeef 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
    3843
    3944C   memalign 42 42.5
  • tests/.expect/loopctrl.txt

    r71d6bd8 r7030dab  
    66A
    77A A A A A A A A A A
     8A A A A A A A A A A A
    89B B B B B
    910C C C C C
     
    1213
    13140 1 2 3 4 5 6 7 8 9
     150 1 2 3 4 5 6 7 8 9 10
    14161 3 5 7 9
    151710 8 6 4 2
     
    2830N N N N N N N N N N
    29310 1 2 3 4 5 6 7 8 9
     320 1 2 3 4 5 6 7 8 9 10
    303310 9 8 7 6 5 4 3 2 1
    3134
  • tests/.expect/nested-types-ERR1.txt

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

    r71d6bd8 r7030dab  
    1 nested-types.cfa:73:1 error: Use of undefined global type Z
    2 nested-types.cfa:74:1 error: Qualified type requires an aggregate on the left, but has: signed int
    3 nested-types.cfa:75:1 error: Undefined type in qualified type: Qualified Type:
     1nested-types.cfa:86:1 error: Use of undefined global type Z
     2nested-types.cfa:87:1 error: Qualified type requires an aggregate on the left, but has: signed int
     3nested-types.cfa:88: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

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

    r71d6bd8 r7030dab  
    36363
    37373 9 { 1., 7. }, [1, 2, 3]
     384
    3839Destructing a Y
    3940Destructing a Y
  • tests/.expect/time.txt

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

    r71d6bd8 r7030dab  
    4646
    4747# adjust CC to current flags
    48 CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     48CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(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),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     55CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    5656
    5757PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
  • tests/Makefile.in

    r71d6bd8 r7030dab  
    214214
    215215# adjust CC to current flags
    216 CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     216CC = $(if $(DISTCC_CFA_PATH),distcc $(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(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) $(CFAFLAGS) \
    361         $(AM_CFLAGS) $(CFLAGS)
     360        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
    362361
    363362AM_V_CFA = $(am__v_CFA_@AM_V@)
     
    365364am__v_CFA_0 = @echo "  CFA     " $@;
    366365am__v_CFA_1 =
    367 AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
    368 am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
    369 am__v_JAVAC_0 = @echo "  JAVAC   " $@;
    370 am__v_JAVAC_1 =
    371 AM_V_GOC = $(am__v_GOC_@AM_V@)
    372 am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
    373 am__v_GOC_0 = @echo "  GOC     " $@;
    374 am__v_GOC_1 =
    375366UPPCC = u++
    376367UPPCOMPILE = $(UPPCC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_UPPFLAGS) $(UPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CFLAGS) $(CFLAGS)
     
    379370am__v_UPP_0 = @echo "  UPP     " $@;
    380371am__v_UPP_1 =
     372AM_V_GOC = $(am__v_GOC_@AM_V@)
     373am__v_GOC_ = $(am__v_GOC_@AM_DEFAULT_V@)
     374am__v_GOC_0 = @echo "  GOC     " $@;
     375am__v_GOC_1 =
     376AM_V_PY = $(am__v_PY_@AM_V@)
     377am__v_PY_ = $(am__v_PY_@AM_DEFAULT_V@)
     378am__v_PY_0 = @echo "  PYTHON  " $@;
     379am__v_PY_1 =
     380AM_V_RUST = $(am__v_RUST_@AM_V@)
     381am__v_RUST_ = $(am__v_RUST_@AM_DEFAULT_V@)
     382am__v_RUST_0 = @echo "  RUST    " $@;
     383am__v_RUST_1 =
     384AM_V_NODEJS = $(am__v_NODEJS_@AM_V@)
     385am__v_NODEJS_ = $(am__v_NODEJS_@AM_DEFAULT_V@)
     386am__v_NODEJS_0 = @echo "  NODEJS  " $@;
     387am__v_NODEJS_1 =
     388AM_V_JAVAC = $(am__v_JAVAC_@AM_V@)
     389am__v_JAVAC_ = $(am__v_JAVAC_@AM_DEFAULT_V@)
     390am__v_JAVAC_0 = @echo "  JAVAC   " $@;
     391am__v_JAVAC_1 =
    381392debug = yes
    382393installed = no
     
    405416
    406417# adjusted CC but without the actual distcc call
    407 CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH),$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
     418CFACCLOCAL = $(if $(DISTCC_CFA_PATH),$(DISTCC_CFA_PATH) ${ARCH_FLAGS},$(TARGET_CFA) ${DEBUG_FLAGS} ${ARCH_FLAGS})
    408419PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    409420avl_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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Oct 20 21:45:21 2019
    13 // Update Count     : 391
     12// Last Modified On : Wed Apr  1 10:58:35 2020
     13// Update Count     : 424
    1414//
    1515
     
    2828        size_t dim = 10;
    2929        char fill = '\xde';
    30         int * p, * p1;
     30        int * ip, * ip1;
    3131
    3232        // allocation, non-array types
    3333
    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
     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 );
     56
     57
     58        // allocation, array types
     59        printf( "\n" );
     60
     61        ip = (int *)calloc( dim, sizeof( *ip ) );                       // C array calloc, type unsafe
     62        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
     68        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; }
     75        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
    5081        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 );
    57 
    58 
    59         // allocation, array types
    60         printf( "\n" );
    61 
    62         p = (int *)calloc( dim, sizeof( *p ) );                         // C array calloc, type unsafe
    63         printf( "C   array calloc, fill 0\n" );
    64         for ( i; dim ) { printf( "%#x ", p[i] ); }
    65         printf( "\n" );
    66         free( p );
    67 
    68         p = calloc( dim );                                  // CFA array calloc, type safe
    69         printf( "CFA array calloc, fill 0\n" );
    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; }
    76         printf( "CFA array alloc, no fill\n" );
    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
    82         printf( "CFA array alloc, fill %#hhx\n", 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
     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
    8887        printf( "CFA array alloc, fill %#hhx\n", 0xdeadbeef );
    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
     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
    9493        printf( "CFA array alloc, fill from array\n" );
    95         for ( i; 2 * dim ) { printf( "%#x %#x, ", p[i], p1[i] ); }
    96         free( p1 );
    97         printf( "\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
     103        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; }
     110        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 );
    98174
    99175
    100176        // resize, non-array types
    101         printf( "\n" );
    102 
    103         p = (int *)realloc( p, dim * sizeof(*p) );                      // C realloc
    104         printf( "C realloc\n" );
    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; }
    111         printf( "CFA realloc\n" );
    112         for ( i; 2 * dim ) { printf( "%#x ", p[i] ); }
    113         printf( "\n" );
    114         // do not free
     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 );
    115191
    116192
    117193        // resize, array types
    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 );
     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 );
    157208
    158209
     
    169220        free( stp );
    170221
    171         stp = &(*memalign( Alignment )){ 42, 42.5 };          // CFA memalign
     222        stp = &(*memalign( Alignment )){ 42, 42.5 };            // CFA memalign
    172223        assert( (uintptr_t)stp % Alignment == 0 );
    173224        printf( "CFA memalign %d %g\n", stp->x, stp->y );
     
    301352        free( fp - 1 );
    302353
    303         p = foo( bar( baz( malloc(), 0 ), 0 ), 0 );
    304         *p = 0xdeadbeef;
    305         printf( "CFA deep malloc %#x\n", *p );
    306         free( p );
     354        ip = foo( bar( baz( malloc(), 0 ), 0 ), 0 );
     355        *ip = 0xdeadbeef;
     356        printf( "CFA deep malloc %#x\n", *ip );
     357        free( ip );
    307358
    308359#ifdef ERR1
    309360        stp = malloc();
    310361        printf( "\nSHOULD FAIL\n" );
    311         p = realloc( stp, dim * sizeof( *stp ) );
    312         p = alloc( stp, dim * sizeof( *stp ) );
    313         p = memset( stp, 10 );
    314         p = memcpy( &st1, &st );
     362        ip = realloc( stp, dim * sizeof( *stp ) );
     363        ip = memset( stp, 10 );
     364        ip = memcpy( &st1, &st );
    315365#endif
    316366} // main
  • tests/builtins/sync.cfa

    r71d6bd8 r7030dab  
    44void foo() {
    55        volatile _Bool * vpB = 0; _Bool vB = 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;
     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;
    1213        #endif
    1314        struct type * volatile * vpp = 0; struct type ** rpp = 0; struct type * vp = 0;
    1415
    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); }
     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); }
    182132        #endif
    183133        { _Bool ret; ret = __sync_bool_compare_and_swap(vpp, vp, vp); }
    184134
    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); }
     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); }
    196142        #endif
    197143        { struct type * ret; ret = __sync_val_compare_and_swap(vpp, vp, vp); }
    198144
    199145
    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); }
     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); }
    224162        #endif
    225163
     
    230168
    231169        { _Bool ret; ret = __atomic_test_and_set(vpB, vB); }
    232         { _Bool ret; ret = __atomic_test_and_set(vp1, v1); }
     170        { _Bool ret; ret = __atomic_test_and_set(vpc, vc); }
    233171        { __atomic_clear(vpB, vB); }
    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); }
     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); }
    252187        #endif
    253188        { struct type * ret; ret = __atomic_exchange_n(vpp, vp, __ATOMIC_SEQ_CST); }
    254189        { struct type * ret; __atomic_exchange(vpp, &vp, &ret, __ATOMIC_SEQ_CST); }
    255190
    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); }
     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); }
    272204        #endif
    273205        { struct type * ret; ret = __atomic_load_n(vpp, __ATOMIC_SEQ_CST); }
    274206        { struct type * ret; __atomic_load(vpp, &ret, __ATOMIC_SEQ_CST); }
    275207
    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); }
     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); }
    292221        #endif
    293222        { _Bool ret; ret = __atomic_compare_exchange_n(vpp, rpp, vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    294223        { _Bool ret; ret = __atomic_compare_exchange(vpp, rpp, &vp, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
    295224
    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); }
     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); }
    312238        #endif
    313239        { __atomic_store_n(vpp, vp, __ATOMIC_SEQ_CST); }
    314240        { __atomic_store(vpp, &vp, __ATOMIC_SEQ_CST); }
    315241
    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); }
     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); }
    474352        { __atomic_thread_fence(__ATOMIC_SEQ_CST); }
    475353        { __atomic_signal_fence(__ATOMIC_SEQ_CST); }
  • tests/concurrent/coroutineYield.cfa

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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 21 08:19:20 2019
    13 // Update Count     : 14
     12// Last Modified On : Thu Jan 16 22:36:34 2020
     13// Update Count     : 15
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 21 11:50:12 2019
    13 // Update Count     : 24
     12// Last Modified On : Thu Jan 16 23:09:43 2020
     13// Update Count     : 25
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Feb 20 08:02:37 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 21 08:25:03 2019
    13 // Update Count     : 4
     12// Last Modified On : Thu Jan 16 22:43:40 2020
     13// Update Count     : 5
    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

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

    r71d6bd8 r7030dab  
    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);
    1315        value += 1;
     16        assert(active_thread() == get_monitor(p1)->owner);
     17        assert(active_thread() == get_monitor(p2)->owner);
    1418}
    1519
  • tests/concurrent/preempt.cfa

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

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

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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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() {
    103 
    104 }
     102int main() {}
  • tests/concurrent/waitfor/parse2.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Aug 30 17:53:29 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 22 13:42:11 2019
    13 // Update Count     : 3
     12// Last Modified On : Thu Jan 16 23:13:37 2020
     13// Update Count     : 6
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    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

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

    r71d6bd8 r7030dab  
    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

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

    r71d6bd8 r7030dab  
     1struct S { int i; };
     2void ?{}( S & s, int i ) { s.i = i; }
     3int ?`mary( int );
     4int ?`mary( S );
     5[int] ?`mary( [int, int] );
     6int & ?`jane( int & );
     7int jack( int );
     8
    19int main() {
    2     struct s { int i; } x, *p = &x;
    3     int i = 3;
     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;
    415
    516    // operators
    617
    7     ! i;
     18    !i;
    819    ~i;
    920    +i;
    1021    -i;
    11     *p;
    12     ++p;
    13     --p;
    14     p++;
    15     p--;
     22    *ps;
     23    ++ps;
     24    --ps;
     25    ps++;
     26    ps--;
    1627
    17     i+i;
    18     i-i;
    19     i*i;
     28    i + j;
     29    i - j;
     30    i * j;
    2031
    21     i/i;
    22     i%i;
    23     i^i;
    24     i&i;
    25     i|i;
    26     i<i;
    27     i>i;
    28     i=i;
     32    i / j;
     33    i % j;
     34    i ^ j;
     35    i & j;
     36    i | j;
     37    i < j;
     38    i > j;
     39    i = j;
    2940
    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;
     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;
    4950
    50     i?i:i;
     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;
    5185} // main
  • tests/heap.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Nov  6 17:54:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 19 08:22:34 2019
    13 // Update Count     : 19
     12// Last Modified On : Sun Nov 24 12:34:51 2019
     13// Update Count     : 28
    1414//
    1515
     
    3838        enum { NoOfAllocs = 5000, NoOfMmaps = 10 };
    3939        char * locns[NoOfAllocs];
    40         int i;
     40        size_t amount;
     41        enum { limit = 64 * 1024 };                                                     // check alignments up to here
    4142
    4243        // check alloc/free
     
    7475                size_t s = (i + 1) * 20;
    7576                char * area = (char *)malloc( s );
    76                 if ( area == 0 ) abort( "malloc/free out of memory" );
     77                if ( area == 0p ) abort( "malloc/free out of memory" );
    7778                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
    7879                area[malloc_usable_size( area ) - 1] = '\345';  // fill ultimate byte
     
    8384                size_t s = i + 1;                                                               // +1 to make initialization simpler
    8485                locns[i] = (char *)malloc( s );
    85                 if ( locns[i] == 0 ) abort( "malloc/free out of memory" );
     86                if ( locns[i] == 0p ) abort( "malloc/free out of memory" );
    8687                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
    8788                locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
     
    99100                size_t s = i + default_mmap_start();                    // cross over point
    100101                char * area = (char *)malloc( s );
    101                 if ( area == 0 ) abort( "malloc/free out of memory" );
     102                if ( area == 0p ) abort( "malloc/free out of memory" );
    102103                area[0] = '\345'; area[s - 1] = '\345';                 // fill first/last
    103104                area[malloc_usable_size( area ) - 1] = '\345';  // fill ultimate byte
     
    108109                size_t s = i + default_mmap_start();                    // cross over point
    109110                locns[i] = (char *)malloc( s );
    110                 if ( locns[i] == 0 ) abort( "malloc/free out of memory" );
     111                if ( locns[i] == 0p ) abort( "malloc/free out of memory" );
    111112                locns[i][0] = '\345'; locns[i][s - 1] = '\345'; // fill first/last
    112113                locns[i][malloc_usable_size( locns[i] ) - 1] = '\345'; // fill ultimate byte
     
    124125                size_t s = (i + 1) * 20;
    125126                char * area = (char *)calloc( 5, s );
    126                 if ( area == 0 ) abort( "calloc/free out of memory" );
     127                if ( area == 0p ) abort( "calloc/free out of memory" );
    127128                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    128129                         area[malloc_usable_size( area ) - 1] != '\0' ||
     
    136137                size_t s = i + 1;
    137138                locns[i] = (char *)calloc( 5, s );
    138                 if ( locns[i] == 0 ) abort( "calloc/free out of memory" );
     139                if ( locns[i] == 0p ) abort( "calloc/free out of memory" );
    139140                if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
    140141                         locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
     
    155156                size_t s = i + default_mmap_start();                    // cross over point
    156157                char * area = (char *)calloc( 1, s );
    157                 if ( area == 0 ) abort( "calloc/free out of memory" );
     158                if ( area == 0p ) abort( "calloc/free out of memory" );
    158159                if ( area[0] != '\0' || area[s - 1] != '\0' ) abort( "calloc/free corrupt storage4.1" );
    159160                if ( area[malloc_usable_size( area ) - 1] != '\0' ) abort( "calloc/free corrupt storage4.2" );
     
    167168                size_t s = i + default_mmap_start();                    // cross over point
    168169                locns[i] = (char *)calloc( 1, s );
    169                 if ( locns[i] == 0 ) abort( "calloc/free out of memory" );
     170                if ( locns[i] == 0p ) abort( "calloc/free out of memory" );
    170171                if ( locns[i][0] != '\0' || locns[i][s - 1] != '\0' ||
    171172                         locns[i][malloc_usable_size( locns[i] ) - 1] != '\0' ||
     
    183184        // check memalign/free (sbrk)
    184185
    185         enum { limit = 64 * 1024 };                                                     // check alignments up to here
    186 
    187186        for ( a; libAlign() ~= limit ~ a ) {                            // generate powers of 2
    188187                //sout | alignments[a];
    189188                for ( s; 1 ~ NoOfAllocs ) {                                             // allocation of size 0 can return null
    190189                        char * area = (char *)memalign( a, s );
    191                         if ( area == 0 ) abort( "memalign/free out of memory" );
    192                         //sout | i | " " | area;
     190                        if ( area == 0p ) abort( "memalign/free out of memory" );
     191                        //sout | i | area;
    193192                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    194193                                abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, s, area );
    195194                        } // if
    196                         area[0] = '\345'; area[s - 1] = '\345'; // fill first/last byte
     195                        area[0] = '\345'; area[s - 1] = '\345';         // fill first/last byte
    197196                        area[malloc_usable_size( area ) - 1] = '\345'; // fill ultimate byte
    198197                        free( area );
     
    207206                        size_t s = i + default_mmap_start();            // cross over point
    208207                        char * area = (char *)memalign( a, s );
    209                         if ( area == 0 ) abort( "memalign/free out of memory" );
    210                         //sout | i | " " | area;
     208                        if ( area == 0p ) abort( "memalign/free out of memory" );
     209                        //sout | i | area;
    211210                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    212211                                abort( "memalign/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)s, area );
     
    223222                // initial N byte allocation
    224223                char * area = (char *)calloc( 5, i );
    225                 if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
     224                if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    226225                if ( area[0] != '\0' || area[i - 1] != '\0' ||
    227226                         area[malloc_usable_size( area ) - 1] != '\0' ||
     
    231230                for ( s; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    232231                        area = (char *)realloc( area, s );                      // attempt to reuse storage
    233                         if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
     232                        if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    234233                        if ( area[0] != '\0' || area[s - 1] != '\0' ||
    235234                                 area[malloc_usable_size( area ) - 1] != '\0' ||
     
    245244                size_t s = i + default_mmap_start();                    // cross over point
    246245                char * area = (char *)calloc( 1, s );
    247                 if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
     246                if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    248247                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    249248                         area[malloc_usable_size( area ) - 1] != '\0' ||
     
    253252                for ( r; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    254253                        area = (char *)realloc( area, r );                      // attempt to reuse storage
    255                         if ( area == 0 ) abort( "calloc/realloc/free out of memory" );
     254                        if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    256255                        if ( area[0] != '\0' || area[r - 1] != '\0' ||
    257256                                 area[malloc_usable_size( area ) - 1] != '\0' ||
     
    263262        // check memalign/realloc/free
    264263
    265         size_t amount = 2;
     264        amount = 2;
    266265        for ( a; libAlign() ~= limit ~ a ) {                            // generate powers of 2
    267266                // initial N byte allocation
    268267                char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
    269                 if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    270                 //sout | alignments[a] | " " | area;
     268                if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
     269                //sout | alignments[a] | area;
    271270                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    272271                        abort( "memalign/realloc/free bad alignment : memalign(%d,%d) = %p", (int)a, (int)amount, area );
     
    278277                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "memalign/realloc/free corrupt storage" );
    279278                        area = (char *)realloc( area, s );                      // attempt to reuse storage
    280                         if ( area == 0 ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    281                         //sout | i | " " | area;
     279                        if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
     280                        //sout | i | area;
    282281                        if ( (size_t)area % a != 0 ) {                          // check for initial alignment
    283282                                abort( "memalign/realloc/free bad alignment %p", area );
     
    294293                for ( s; 1 ~ limit ) {                                                  // allocation of size 0 can return null
    295294                        char * area = (char *)cmemalign( a, 1, s );
    296                         if ( area == 0 ) abort( "cmemalign/free out of memory" );
    297                         //sout | i | " " | area;
     295                        if ( area == 0p ) abort( "cmemalign/free out of memory" );
     296                        //sout | i | area;
    298297                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    299298                                abort( "cmemalign/free bad alignment : cmemalign(%d,%d) = %p", (int)a, s, area );
     
    313312                // initial N byte allocation
    314313                char * area = (char *)cmemalign( a, 1, amount ); // aligned N-byte allocation
    315                 if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
    316                 //sout | alignments[a] | " " | area;
     314                if ( area == 0p ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
     315                //sout | alignments[a] | area;
    317316                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    318317                        abort( "cmemalign/realloc/free bad alignment : cmemalign(%d,%d) = %p", (int)a, (int)amount, area );
     
    327326                        if ( area[0] != '\345' || area[s - 2] != '\345' ) abort( "cmemalign/realloc/free corrupt storage2" );
    328327                        area = (char *)realloc( area, s );                      // attempt to reuse storage
    329                         if ( area == 0 ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
    330                         //sout | i | " " | area;
     328                        if ( area == 0p ) abort( "cmemalign/realloc/free out of memory" ); // no storage ?
     329                        //sout | i | area;
    331330                        if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
    332331                                abort( "cmemalign/realloc/free bad alignment %p", area );
     
    339338                free( area );
    340339        } // 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
    341401        //sout | "worker" | thisTask() | "successful completion";
    342402} // Worker main
  • tests/labelledExit.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Aug 10 07:29:39 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 25 17:41:51 2019
    13 // Update Count     : 7
     12// Last Modified On : Wed Feb  5 16:49:48 2020
     13// Update Count     : 9
    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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Wed Aug  8 18:32:59 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 12 12:05:05 2019
    13 // Update Count     : 106
     12// Last Modified On : Thu Dec 12 17:55:26 2019
     13// Update Count     : 108
    1414//
    1515
     
    4343        for ( 1 ) { sout | "A"; }                                                       sout | nl;
    4444        for ( 10 ) { sout | "A"; }                                                      sout | nl;
     45        for ( = 10 ) { sout | "A"; }                                            sout | nl;
    4546        for ( 1 ~= 10 ~ 2 ) { sout | "B"; }                                     sout | nl;
    4647        for ( 10 -~= 1 ~ 2 ) { sout | "C"; }                            sout | nl;
     
    4950
    5051        for ( i; 10 ) { sout | i; }                                                     sout | nl;
     52        for ( i; = 10 ) { sout | i; }                                           sout | nl;
    5153        for ( i; 1 ~= 10 ~ 2 ) { sout | i; }                            sout | nl;
    5254        for ( i; 10 -~= 1 ~ 2 ) { sout | i; }                           sout | nl;
     
    8789        for ( N ) { sout | "N"; }                                                       sout | nl;
    8890        for ( i; N ) { sout | i; }                                                      sout | nl;
     91        for ( i; = N ) { sout | i; }                                            sout | nl;
    8992        for ( i; N -~ 0 ) { sout | i; }                                         sout | nl | nl;
    9093
  • tests/nested-types.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Jul 9 10:20:03 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov  6 17:59:40 2018
    13 // Update Count     : 2
     12// Last Modified On : Wed Feb 12 18:21:15 2020
     13// Update Count     : 3
    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;
    5265
    5366int main() {
  • tests/pybin/settings.py

    r71d6bd8 r7030dab  
    7777                        print("updated to %s" % self.target)
    7878
    79         def match(self, arch):
     79        def filter(self, tests):
     80                return [test for test in tests if not test.arch or self.target == test.arch]
    8081                return True if not arch else self.target == arch
    8182
     
    113114
    114115def init( options ):
     116        global all_arch
     117        global all_debug
     118        global all_install
    115119        global arch
    116120        global archive
     121        global continue_
    117122        global debug
    118         global distcc
    119123        global dry_run
    120124        global generating
     
    123127        global output_width
    124128        global timeout
     129        global timeout2gdb
    125130
    126         arch         = Architecture(options.arch)
     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))]
    127134        archive      = os.path.abspath(os.path.join(original_path, options.archive_errors)) if options.archive_errors else None
    128         debug        = Debug(options.debug)
     135        continue_    = options.continue_
    129136        dry_run      = options.dry_run # must be called before tools.config_hash()
    130         distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
    131137        generating   = options.regenerate_expected
    132         install      = Install(options.install)
    133138        make         = ['make']
    134139        output_width = 24
    135140        timeout      = Timeouts(options.timeout, options.global_timeout)
     141        timeout2gdb  = options.timeout_with_gdb
    136142
    137143        # if we distribute, distcc errors will fail tests, use log file for distcc
     
    146152
    147153def validate():
     154        """Validate the current configuration and update globals"""
     155
     156        global distcc
     157        distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
    148158        errf = os.path.join(BUILDDIR, ".validate.err")
    149159        make_ret, out = tools.make( ".validate", error_file = errf, output_file=subprocess.DEVNULL, error=subprocess.DEVNULL )
  • tests/pybin/tools.py

    r71d6bd8 r7030dab  
    7575                                        return proc.returncode, out.decode("utf-8") if out else None
    7676                                except subprocess.TimeoutExpired:
    77                                         proc.send_signal(signal.SIGABRT)
    78                                         proc.communicate()
    79                                         return 124, str(None)
     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)
    8085
    8186        except Exception as ex:
     
    175180
    176181def which(program):
    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
     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
    188192
    189193@contextlib.contextmanager
     
    323327        raise argparse.ArgumentTypeError(msg)
    324328
     329# Convert a function that converts a string to one that converts comma separated string.
     330def comma_separated(elements):
     331    return lambda string: [elements(part) for part in string.split(',')]
     332
    325333def fancy_print(text):
    326334        column = which('column')
     
    365373
    366374class Timed:
    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
     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
    374382
    375383def timed(src, timeout):
    376384        expire = time.time() + timeout
    377385        i = iter(src)
    378         while True:
    379                 yield i.next(max(expire - time.time(), 0))
     386        with contextlib.suppress(StopIteration):
     387                while True:
     388                        yield i.next(max(expire - time.time(), 0))
  • tests/quotedKeyword.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 21:45:53 2018
    13 // Update Count     : 23
     12// Last Modified On : Fri Feb  7 19:07:07 2020
     13// Update Count     : 25
    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

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

    r71d6bd8 r7030dab  
    1010// Created On       : Mon Mar 28 08:43:12 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar 27 07:37:17 2019
    13 // Update Count     : 80
     12// Last Modified On : Sat Feb  8 18:46:23 2020
     13// Update Count     : 86
    1414//
    1515
     
    1919#include <fstream.hfa>
    2020
    21 double convert( int i ) { return (double)i; }
     21typedef Rational(int) RatInt;
     22double convert( int i ) { return (double)i; }                   // used by narrow/widen
    2223int convert( double d ) { return (int)d; }
    2324
    2425int main() {
    2526        sout | "constructor";
    26         Rational(int) a = { 3 }, b = { 4 }, c;
    27         sout | a | b | c;
     27        RatInt a = { 3 }, b = { 4 }, c, d = 0, e = 1;
     28        sout | a | b | c | d | e;
    2829
    29         a = (Rational(int)){ 4, 8 };
    30         b = (Rational(int)){ 5, 7 };
     30        a = (RatInt){ 4, 8 };
     31        b = (RatInt){ 5, 7 };
    3132        sout | a | b;
    32         a = (Rational(int)){ -2, -3 };
    33         b = (Rational(int)){ 3, -2 };
     33        a = (RatInt){ -2, -3 };
     34        b = (RatInt){ 3, -2 };
    3435        sout | a | b;
    35         a = (Rational(int)){ -2, 3 };
    36         b = (Rational(int)){ 3, 2 };
     36        a = (RatInt){ -2, 3 };
     37        b = (RatInt){ 3, 2 };
    3738        sout | a | b;
    3839
    3940        sout | "logical";
    40         a = (Rational(int)){ -2 };
    41         b = (Rational(int)){ -3, 2 };
     41        a = (RatInt){ -2 };
     42        b = (RatInt){ -3, 2 };
    4243        sout | a | b;
    4344//      sout | a == 1; // FIX ME
     
    5859
    5960        sout | "conversion";
    60         a = (Rational(int)){ 3, 4 };
     61        a = (RatInt){ 3, 4 };
    6162        sout | widen( a );
    62         a = (Rational(int)){ 1, 7 };
     63        a = (RatInt){ 1, 7 };
    6364        sout | widen( a );
    64         a = (Rational(int)){ 355, 113 };
     65        a = (RatInt){ 355, 113 };
    6566        sout | widen( a );
    6667        sout | narrow( 0.75, 4 );
     
    7475
    7576        sout | "more tests";
    76         Rational(int) x = { 1, 2 }, y = { 2 };
     77        RatInt x = { 1, 2 }, y = { 2 };
    7778        sout | x - y;
    7879        sout | x > y;
     
    8081        sout | y | denominator( y, -2 ) | y;
    8182
    82         Rational(int) z = { 0, 5 };
     83        RatInt z = { 0, 5 };
    8384        sout | z;
    8485
    8586        sout | x | numerator( x, 0 ) | x;
    8687
    87         x = (Rational(int)){ 1, MAX } + (Rational(int)){ 1, MAX };
     88        x = (RatInt){ 1, MAX } + (RatInt){ 1, MAX };
    8889        sout | x;
    89         x = (Rational(int)){ 3, MAX } + (Rational(int)){ 2, MAX };
     90        x = (RatInt){ 3, MAX } + (RatInt){ 2, MAX };
    9091        sout | x;
    9192
  • tests/references.cfa

    r71d6bd8 r7030dab  
    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        }
    121131}
    122132
  • tests/test.py

    r71d6bd8 r7030dab  
    66
    77import argparse
     8import itertools
    89import re
    910import sys
    1011import tempfile
    1112import time
     13
     14import os
     15import psutil
     16import signal
    1217
    1318################################################################################
     
    2530                        test.path = match.group(1)
    2631                        test.arch = match.group(3)[1:] if match.group(3) else None
    27                         if settings.arch.match(test.arch):
    28                                 expected.append(test)
     32                        expected.append(test)
    2933
    3034        path_walk( match_test )
     
    4852                        x.target().startswith( tuple(excludes) )
    4953                ]
     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 ''))
    5057
    5158        return test_list
     
    7279
    7380                        if test :
    74                                 tests.append( test[0] )
     81                                tests.extend( test )
    7582                        else :
    7683                                print('ERROR: No expected file for test %s, ignoring it' % testname, file=sys.stderr)
     
    8289        # create a parser with the arguments for the tests script
    8390        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
    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='')
     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_')
    8795        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=60)
    8896        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")
    8998        parser.add_argument('--dry-run', help='Don\'t run the tests, only output the commands', action='store_true')
    9099        parser.add_argument('--list', help='List all test available', action='store_true')
     
    148157        # run everything in a temp directory to make sure core file are handled properly
    149158        with tempdir():
    150                 # if the make command succeds continue otherwise skip to diff
     159                # if the make command succeeds continue otherwise skip to diff
    151160                if success(make_ret):
    152161                        with Timed() as run_dur:
     
    221230        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    222231
     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
    223239        # create the executor for our jobs and handle the signal properly
    224         pool = multiprocessing.Pool(jobs)
     240        pool = multiprocessing.Pool(jobs, worker_init)
    225241
    226242        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)
    227248
    228249        # for each test to run
     
    262283        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
    263284
    264         return 1 if failed else 0
     285        return failed
    265286
    266287
     
    276297        settings.init( options )
    277298
    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                 print("-h --help --debug --dry-run --list --arch --all --regenerate-expected --archive-errors --install --timeout --global-timeout -j --jobs ", end='')
     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='')
    302306                print(" ".join(map(lambda t: "%s" % (t.target()), tests)))
    303307
    304308        elif options.list :
    305                 print("Listing for %s:%s"% (settings.arch.string, settings.debug.string))
     309                # fetch the liest of all valid tests
     310                tests = list_tests( options.include, options.exclude )
     311
     312                # print the available tests
    306313                fancy_print("\n".join(map(lambda t: t.toString(), tests)))
    307314
    308315        else :
    309                 # check the build configuration works
     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
    310333                settings.prep_output(tests)
    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) )
     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 )
  • tests/time.cfa

    r71d6bd8 r7030dab  
    1010// Created On       : Tue Mar 27 17:24:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Dec 20 23:09:21 2018
    13 // Update Count     : 23
     12// Last Modified On : Sun Jan  5 18:27:37 2020
     13// Update Count     : 34
    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;
    2322        d1 = 0;
    2423        sout | d1 | d2 | d3;
     
    3534        sout | t;
    3635        t = t + d1;
    37         sout | t | t.tv;
     36        sout | t | t`ns;
    3837        Time t1 = (timespec){ 104_414, 10_000_000 };
    39         sout | t1 | t1.tv;
    40         sout | t - t  | t + d5 | t.tv;
    41         char buf[16];
     38        sout | t1 | t1`ns;
     39        sout | t - t  | t + d5 | t`ns;
     40        char buf[64];
    4241        sout | "yy/mm/dd" | [t, buf]`ymd | nonl;                        // shared buf => separate calls
    4342        sout | "mm/dd/yy" | mm_dd_yy( t, buf ) | nonl;
     
    4645        sout | "dd/yy/mm" | [t, buf]`dmy;
    4746        Time t2 = { 2001, 7, 4, 0, 0, 1, 0 }, t3 = (timeval){ 994_219_201 };
    48         sout | t2 | t2.tv | nl | t3 | t3.tv;
     47        sout | t2 | t2`ns | nl | t3 | t3`ns;
    4948        sout | nl;
    5049
     
    6362        sout | "Dividing that by 2 gives" | s / 2 | "seconds";
    6463        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;
    6574} // main
    6675
  • tests/userLiterals.cfa

    r71d6bd8 r7030dab  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // user_literals.cfa --
     7// userLiterals.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 : Tue Dec  4 22:03:10 2018
    13 // Update Count     : 56
     12// Last Modified On : Wed Feb 19 07:48:45 2020
     13// Update Count     : 74
    1414//
    1515
     
    2424int ?`__thingy_( int x ) { sout | "_thingy_" | x; return x; }
    2525
    26 int ?`s( const char * s ) { sout | "secs" | s; return 0; }
    27 int ?`m( const char16_t * m ) { sout | "mins" | m; return 0;}
    28 int ?`h( const char32_t * h ) { sout | "hours" | h; return 0; }
     26int ?`s( const char * s ) { sout | "s" | s; return 0; }
     27int ?`m( const char16_t * m ) { sout | "m" | m; return 0;}
     28int ?`h( const char32_t * h ) { sout | "h" | 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 | w.stones; }
     39ofstream & ?|?( ofstream & os, Weight w ) { return os | wd(1,1, w.stones); }
     40void ?|?( ofstream & os, Weight w ) { (ofstream)(os | w); ends( os ); }
    4041
    4142Weight ?`st( double w ) { return (Weight){ w }; }               // backquote for user literals
     
    6061        sout | w;
    6162
    62 //      0`secs;
     63        0`s;
    6364        1`s;
    6465        23`s;
     
    8283
    8384        "abc"`s;
    84 //      u"abc"`m;
    85 //      U_"abc"`h;
    86 //      L"abc"`_A_;
     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_;
    8789        u8_"abc"`__thingy_;
    8890} // main
     
    9092// Local Variables: //
    9193// tab-width: 4 //
    92 // compile-command: "cfa user_literals.cfa" //
     94// compile-command: "cfa userLiterals.cfa" //
    9395// End: //
  • tools/catchsig.c

    r71d6bd8 r7030dab  
    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

    r71d6bd8 r7030dab  
    1414
    1515# Declarations
    16 color brightgreen "\<(struct|union|typedef|trait|coroutine|monitor|thread)\>"
    17 color brightgreen "\<(with)\>"
     16color brightgreen "\<(struct|union|typedef|trait|coroutine|generator)\>"
     17color brightgreen "\<(monitor|thread|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)\>"
     21color brightyellow "\<(disable|enable|waitfor|when|timeout|suspend)\>"
    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

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

    r71d6bd8 r7030dab  
    22        "name": "cforall",
    33        "version": "0.1.0",
    4         "displayName": "Cforall Language Support",
     4        "displayName": "Cāˆ€ (C-for-all) Language Support",
    55        "description": "Cforall - colorizer, grammar and snippets.",
    66        "publisher": "uwaterloo",
     
    99                "vscode": "^1.5.0"
    1010        },
    11         "icon": "images/icon.svg",
     11        "icon": "images/icon.png",
    1212        "categories": [
    13                 "Languages",
     13                "Programming Languages",
    1414                "Linters",
    1515                "Other"
    1616        ],
     17        "activationEvents": [
     18                "onLanguage:cforall"
     19        ],
     20        "main": "./client/main.js",
    1721        "contributes": {
    1822                "languages": [
     
    2125                                "aliases": [
    2226                                        "Cāˆ€",
     27                                        "CForAll",
    2328                                        "Cforall",
    24                                         "CForAll",
    2529                                        "cforall"
    2630                                ],
    2731                                "extensions": [
    28                                         ".cf"
     32                                        ".cfa",
     33                                        ".hfa",
     34                                        ".ifa"
    2935                                ],
    3036                                "configuration": "./cforall.configuration.json"
     
    3440                        {
    3541                                "language": "cforall",
    36                                 "scopeName": "source.cf",
    37                                 "path": "./syntaxes/cfa.tmLanguage"
     42                                "scopeName": "source.cfa",
     43                                "path": "./syntaxes/cfa.tmLanguage.json"
    3844                        }
    39                 ]
     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"
    4075        }
    4176}
Note: See TracChangeset for help on using the changeset viewer.