Changeset 0e4df2e for libcfa


Ignore:
Timestamp:
May 22, 2020, 11:49:29 AM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
95cb63b
Parents:
2802824 (diff), 99fea48 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into relaxed_ready

Location:
libcfa/src
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/Makefile.am

    r2802824 r0e4df2e  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Mar 16 18:07:59 2020
    14 ## Update Count     : 242
     13## Last Modified On : Sun May 17 21:10:26 2020
     14## Update Count     : 243
    1515###############################################################################
    1616
     
    3939#----------------------------------------------------------------------------------------------------------------
    4040if BUILDLIB
    41 headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa
     41headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa clock.hfa \
     42                bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa
    4243headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
    43           containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
     44                containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/stackLockFree.hfa containers/vector.hfa
    4445
    4546libsrc = startup.cfa interpose.cfa bits/debug.cfa assert.cfa exception.c virtual.c heap.cfa ${headers:.hfa=.cfa}
  • libcfa/src/Makefile.in

    r2802824 r0e4df2e  
    241241        containers/maybe.hfa containers/pair.hfa containers/result.hfa \
    242242        containers/vector.hfa bitmanip.hfa math.hfa gmp.hfa time_t.hfa \
    243         bits/align.hfa bits/containers.hfa bits/defs.hfa \
     243        clock.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa \
    244244        bits/debug.hfa bits/locks.hfa containers/list.hfa \
    245245        concurrency/coroutine.hfa concurrency/thread.hfa \
     
    465465
    466466#----------------------------------------------------------------------------------------------------------------
    467 @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 containers/list.hfa
     467@BUILDLIB_TRUE@headers_nosrc = bitmanip.hfa math.hfa gmp.hfa time_t.hfa clock.hfa \
     468@BUILDLIB_TRUE@         bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa containers/list.hfa
     469
    468470@BUILDLIB_FALSE@headers =
    469471@BUILDLIB_TRUE@headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \
    470 @BUILDLIB_TRUE@   containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
     472@BUILDLIB_TRUE@         containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
    471473
    472474@BUILDLIB_FALSE@libsrc =
  • libcfa/src/concurrency/io.cfa

    r2802824 r0e4df2e  
    124124
    125125                // Like head/tail but not seen by the kernel
    126                 volatile uint32_t alloc;
    127126                volatile uint32_t * ready;
    128127                uint32_t ready_cnt;
     
    141140                        struct {
    142141                                struct {
    143                                         volatile unsigned long long int val;
     142                                        volatile unsigned long long int rdy;
     143                                        volatile unsigned long long int csm;
     144                                        volatile unsigned long long int avl;
    144145                                        volatile unsigned long long int cnt;
    145                                         volatile unsigned long long int block;
    146146                                } submit_avg;
    147147                                struct {
     
    150150                                        volatile unsigned long long int block;
    151151                                } look_avg;
     152                                struct {
     153                                        volatile unsigned long long int val;
     154                                        volatile unsigned long long int cnt;
     155                                        volatile unsigned long long int block;
     156                                } alloc_avg;
    152157                        } stats;
    153158                #endif
     
    279284                sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    280285                sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    281                 sq.alloc = *sq.tail;
     286
     287                {
     288                        const uint32_t num = *sq.num;
     289                        for( i; num ) {
     290                                sq.sqes[i].user_data = 0ul64;
     291                        }
     292                }
    282293
    283294                if( io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
     
    322333                // Initialize statistics
    323334                #if !defined(__CFA_NO_STATISTICS__)
    324                         this.io->submit_q.stats.submit_avg.val   = 0;
    325                         this.io->submit_q.stats.submit_avg.cnt   = 0;
    326                         this.io->submit_q.stats.submit_avg.block = 0;
     335                        this.io->submit_q.stats.submit_avg.rdy = 0;
     336                        this.io->submit_q.stats.submit_avg.csm = 0;
     337                        this.io->submit_q.stats.submit_avg.avl = 0;
     338                        this.io->submit_q.stats.submit_avg.cnt = 0;
    327339                        this.io->submit_q.stats.look_avg.val   = 0;
    328340                        this.io->submit_q.stats.look_avg.cnt   = 0;
    329341                        this.io->submit_q.stats.look_avg.block = 0;
     342                        this.io->submit_q.stats.alloc_avg.val   = 0;
     343                        this.io->submit_q.stats.alloc_avg.cnt   = 0;
     344                        this.io->submit_q.stats.alloc_avg.block = 0;
    330345                        this.io->completion_q.stats.completed_avg.val = 0;
    331346                        this.io->completion_q.stats.completed_avg.slow_cnt = 0;
     
    384399                                        this.ready_queue.head = 1p;
    385400                                        thrd.next = 0p;
     401                                        __cfaabi_dbg_debug_do( thrd.unpark_stale = true );
    386402
    387403                                        // Fixup the thread state
     
    426442                        if(this.print_stats) {
    427443                                with(this.io->submit_q.stats, this.io->completion_q.stats) {
     444                                        double avgrdy = ((double)submit_avg.rdy) / submit_avg.cnt;
     445                                        double avgcsm = ((double)submit_avg.csm) / submit_avg.cnt;
     446                                        double avgavl = ((double)submit_avg.avl) / submit_avg.cnt;
     447
    428448                                        double lavgv = 0;
    429449                                        double lavgb = 0;
     
    433453                                        }
    434454
     455                                        double aavgv = 0;
     456                                        double aavgb = 0;
     457                                        if(alloc_avg.cnt != 0) {
     458                                                aavgv = ((double)alloc_avg.val  ) / alloc_avg.cnt;
     459                                                aavgb = ((double)alloc_avg.block) / alloc_avg.cnt;
     460                                        }
     461
    435462                                        __cfaabi_bits_print_safe( STDOUT_FILENO,
    436463                                                "----- I/O uRing Stats -----\n"
    437464                                                "- total submit calls     : %'15llu\n"
    438                                                 "- avg submit             : %'18.2lf\n"
    439                                                 "- pre-submit block %%     : %'18.2lf\n"
     465                                                "- avg ready entries      : %'18.2lf\n"
     466                                                "- avg submitted entries  : %'18.2lf\n"
     467                                                "- avg available entries  : %'18.2lf\n"
    440468                                                "- total ready search     : %'15llu\n"
    441469                                                "- avg ready search len   : %'18.2lf\n"
    442470                                                "- avg ready search block : %'18.2lf\n"
     471                                                "- total alloc search     : %'15llu\n"
     472                                                "- avg alloc search len   : %'18.2lf\n"
     473                                                "- avg alloc search block : %'18.2lf\n"
    443474                                                "- total wait calls       : %'15llu   (%'llu slow, %'llu fast)\n"
    444475                                                "- avg completion/wait    : %'18.2lf\n",
    445476                                                submit_avg.cnt,
    446                                                 ((double)submit_avg.val) / submit_avg.cnt,
    447                                                 (100.0 * submit_avg.block) / submit_avg.cnt,
     477                                                avgrdy,
     478                                                avgcsm,
     479                                                avgavl,
    448480                                                look_avg.cnt,
    449481                                                lavgv,
    450482                                                lavgb,
     483                                                alloc_avg.cnt,
     484                                                aavgv,
     485                                                aavgb,
    451486                                                completed_avg.slow_cnt + completed_avg.fast_cnt,
    452487                                                completed_avg.slow_cnt,  completed_avg.fast_cnt,
     
    494529
    495530                        // If the poller thread also submits, then we need to aggregate the submissions which are ready
    496                         uint32_t * tail = ring.submit_q.tail;
     531                        uint32_t tail = *ring.submit_q.tail;
    497532                        const uint32_t mask = *ring.submit_q.mask;
    498533
     
    506541
    507542                                // If we got a real submission, append it to the list
    508                                 ring.submit_q.array[ ((*tail) + to_submit) & mask ] = idx & mask;
     543                                ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask;
    509544                                to_submit++;
    510545                        }
    511546
    512547                        // Increment the tail based on how many we are ready to submit
    513                         __atomic_fetch_add(tail, to_submit, __ATOMIC_SEQ_CST);
    514 
    515                         // update statistics
    516                         #if !defined(__CFA_NO_STATISTICS__)
    517                                 ring.submit_q.stats.submit_avg.val += to_submit;
    518                                 ring.submit_q.stats.submit_avg.cnt += 1;
    519                         #endif
    520                 }
    521 
     548                        __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST);
     549                }
     550
     551                const uint32_t smask = *ring.submit_q.mask;
     552                uint32_t shead = *ring.submit_q.head;
    522553                int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8);
    523554                if( ret < 0 ) {
     
    531562                }
    532563
     564                verify( (shead + ret) == *ring.submit_q.head );
     565
     566                // Release the consumed SQEs
     567                for( i; ret ) {
     568                        uint32_t idx = ring.submit_q.array[ (i + shead) & smask ];
     569                        ring.submit_q.sqes[ idx ].user_data = 0;
     570                }
     571
     572                uint32_t avail = 0;
     573                uint32_t sqe_num = *ring.submit_q.num;
     574                for(i; sqe_num) {
     575                        if( ring.submit_q.sqes[ i ].user_data == 0 ) avail++;
     576                }
     577
     578                // update statistics
     579                #if !defined(__CFA_NO_STATISTICS__)
     580                        ring.submit_q.stats.submit_avg.rdy += to_submit;
     581                        ring.submit_q.stats.submit_avg.csm += ret;
     582                        ring.submit_q.stats.submit_avg.avl += avail;
     583                        ring.submit_q.stats.submit_avg.cnt += 1;
     584                #endif
     585
    533586                // Drain the queue
    534587                unsigned head = *ring.completion_q.head;
    535                 unsigned tail = __atomic_load_n(ring.completion_q.tail, __ATOMIC_ACQUIRE);
     588                unsigned tail = *ring.completion_q.tail;
     589                const uint32_t mask = *ring.completion_q.mask;
     590
     591                // Memory barrier
     592                __atomic_thread_fence( __ATOMIC_SEQ_CST );
    536593
    537594                // Nothing was new return 0
     
    542599                uint32_t count = tail - head;
    543600                for(i; count) {
    544                         unsigned idx = (head + i) & (*ring.completion_q.mask);
     601                        unsigned idx = (head + i) & mask;
    545602                        struct io_uring_cqe & cqe = ring.completion_q.cqes[idx];
    546603
     
    556613
    557614                // Allow new submissions to happen
    558                 V(ring.submit, count);
     615                // V(ring.submit, count);
    559616
    560617                // Mark to the kernel that the cqe has been seen
    561618                // Ensure that the kernel only sees the new value of the head index after the CQEs have been read.
     619                __atomic_thread_fence( __ATOMIC_SEQ_CST );
    562620                __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_RELAXED );
    563621
     
    710768//
    711769
    712         static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring ) {
    713                 // Wait for a spot to be available
    714                 __attribute__((unused)) bool blocked = P(ring.submit);
    715                 #if !defined(__CFA_NO_STATISTICS__)
    716                         __atomic_fetch_add( &ring.submit_q.stats.submit_avg.block, blocked ? 1ul64 : 0ul64, __ATOMIC_RELAXED );
    717                 #endif
    718 
    719                 // Allocate the sqe
    720                 uint32_t idx = __atomic_fetch_add(&ring.submit_q.alloc, 1ul32, __ATOMIC_SEQ_CST);
    721 
    722                 // Mask the idx now to allow make everything easier to check
    723                 idx &= *ring.submit_q.mask;
    724 
    725                 // Return the sqe
    726                 return [&ring.submit_q.sqes[ idx ], idx];
     770        static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
     771                verify( data != 0 );
     772
     773                // Prepare the data we need
     774                __attribute((unused)) int len   = 0;
     775                __attribute((unused)) int block = 0;
     776                uint32_t cnt = *ring.submit_q.num;
     777                uint32_t mask = *ring.submit_q.mask;
     778                uint32_t off = __tls_rand();
     779
     780                // Loop around looking for an available spot
     781                LOOKING: for() {
     782                        // Look through the list starting at some offset
     783                        for(i; cnt) {
     784                                uint64_t expected = 0;
     785                                uint32_t idx = (i + off) & mask;
     786                                struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
     787                                volatile uint64_t * udata = &sqe->user_data;
     788
     789                                if( *udata == expected &&
     790                                        __atomic_compare_exchange_n( udata, &expected, data, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) )
     791                                {
     792                                        // update statistics
     793                                        #if !defined(__CFA_NO_STATISTICS__)
     794                                                __atomic_fetch_add( &ring.submit_q.stats.alloc_avg.val,   len,   __ATOMIC_RELAXED );
     795                                                __atomic_fetch_add( &ring.submit_q.stats.alloc_avg.block, block, __ATOMIC_RELAXED );
     796                                                __atomic_fetch_add( &ring.submit_q.stats.alloc_avg.cnt,   1,     __ATOMIC_RELAXED );
     797                                        #endif
     798
     799                                        // Success return the data
     800                                        return [sqe, idx];
     801                                }
     802                                verify(expected != data);
     803
     804                                len ++;
     805                        }
     806
     807                        block++;
     808                        yield();
     809                }
    727810        }
    728811
     
    742825                        __attribute((unused)) int len   = 0;
    743826                        __attribute((unused)) int block = 0;
    744                         uint32_t expected = -1ul32;
    745827                        uint32_t ready_mask = ring.submit_q.ready_cnt - 1;
    746828                        uint32_t off = __tls_rand();
     
    748830                                for(i; ring.submit_q.ready_cnt) {
    749831                                        uint32_t ii = (i + off) & ready_mask;
     832                                        uint32_t expected = -1ul32;
    750833                                        if( __atomic_compare_exchange_n( &ring.submit_q.ready[ii], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) {
    751834                                                break LOOKING;
    752835                                        }
     836                                        verify(expected != idx);
    753837
    754838                                        len ++;
     
    792876                        // update statistics
    793877                        #if !defined(__CFA_NO_STATISTICS__)
    794                                 ring.submit_q.stats.submit_avg.val += 1;
     878                                ring.submit_q.stats.submit_avg.csm += 1;
    795879                                ring.submit_q.stats.submit_avg.cnt += 1;
    796880                        #endif
     
    831915
    832916        #define __submit_prelude \
    833                 struct __io_data & ring = *active_cluster()->io; \
     917                io_user_data data = { 0, active_thread() }; \
     918                struct __io_data & ring = *data.thrd->curr_cluster->io; \
    834919                struct io_uring_sqe * sqe; \
    835920                uint32_t idx; \
    836                 [sqe, idx] = __submit_alloc( ring );
     921                [sqe, idx] = __submit_alloc( ring, (uint64_t)&data );
    837922
    838923        #define __submit_wait \
    839                 io_user_data data = { 0, active_thread() }; \
    840924                /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \
    841                 sqe->user_data = (uint64_t)&data; \
     925                verify( sqe->user_data == (uint64_t)&data ); \
    842926                __submit( ring, idx ); \
    843927                park( __cfaabi_dbg_ctx ); \
  • libcfa/src/concurrency/kernel.cfa

    r2802824 r0e4df2e  
    648648
    649649        // record activity
     650        __cfaabi_dbg_debug_do( char * old_caller = thrd->unpark_caller; )
    650651        __cfaabi_dbg_record_thrd( *thrd, false, caller );
    651652
  • libcfa/src/containers/list.hfa

    r2802824 r0e4df2e  
    301301                $prev_link(list_pos) = (Telem*) 0p;
    302302        }
     303
     304        static inline bool ?`is_empty(dlist(Tnode, Telem) &list) {
     305                assert( &list != 0p );
     306                $dlinks(Telem) *listLinks = & list.$links;
     307                if (listLinks->next.is_terminator) {
     308                        assert(listLinks->prev.is_terminator);
     309                        assert(listLinks->next.terminator);
     310                        assert(listLinks->prev.terminator);
     311                        return true;
     312                } else {
     313                        assert(!listLinks->prev.is_terminator);
     314                        assert(listLinks->next.elem);
     315                        assert(listLinks->prev.elem);
     316                        return false;
     317                }
     318        }
     319
     320        static inline Telem & pop_first(dlist(Tnode, Telem) &list) {
     321                assert( &list != 0p );
     322                assert( !list`is_empty );
     323                $dlinks(Telem) *listLinks = & list.$links;
     324                Telem & first = *listLinks->next.elem;
     325                Tnode & list_pos_first  = $tempcv_e2n( first );
     326                remove(list_pos_first);
     327                return first;
     328        }
     329
     330        static inline Telem & pop_last(dlist(Tnode, Telem) &list) {
     331                assert( &list != 0p );
     332                assert( !list`is_empty );
     333                $dlinks(Telem) *listLinks = & list.$links;
     334                Telem & last = *listLinks->prev.elem;
     335                Tnode & list_pos_last  = $tempcv_e2n( last );
     336                remove(list_pos_last);
     337                return last;
     338        }
     339
    303340}
    304341
  • libcfa/src/exception.c

    r2802824 r0e4df2e  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr 14 12:01:00 2020
    13 // Update Count     : 18
     12// Last Modified On : Thr May 21 12:18:00 2020
     13// Update Count     : 20
    1414//
    1515
     
    8080}
    8181
    82 void __cfaehm_throw_resume(exception_t * except) {
     82void __cfaehm_throw_resume(exception_t * except, void (*defaultHandler)(exception_t *)) {
    8383        struct exception_context_t * context = this_exception_context();
    8484
     
    9696        }
    9797
     98        // No handler found, fall back to the default operation.
    9899        __cfadbg_print_safe(exception, "Unhandled exception\n");
    99 
    100         // Fall back to termination:
    101         __cfaehm_throw_terminate(except);
    102         // TODO: Default handler for resumption.
     100        defaultHandler(except);
    103101}
    104102
     
    223221
    224222// Cancel the current stack, prefroming approprate clean-up and messaging.
    225 static __attribute__((noreturn)) void __cfaehm_cancel_stack(
    226                 exception_t * exception ) {
     223void __cfaehm_cancel_stack( exception_t * exception ) {
    227224        // TODO: Detect current stack and pick a particular stop-function.
    228225        _Unwind_Reason_Code ret;
     
    240237}
    241238
     239static void __cfaehm_cleanup_default( exception_t ** except ) {
     240        __cfaehm_delete_exception( *except );
     241        *except = NULL;
     242}
     243
    242244// The exception that is being thrown must already be stored.
    243 static __attribute__((noreturn)) void __cfaehm_begin_unwind(void) {
    244         if ( ! this_exception_context()->current_exception ) {
     245static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
     246        struct exception_context_t * context = this_exception_context();
     247        struct _Unwind_Exception * storage = &this_exception_storage;
     248        if ( NULL == context->current_exception ) {
    245249                printf("UNWIND ERROR missing exception in begin unwind\n");
    246250                abort();
     
    248252
    249253        // Call stdlibc to raise the exception
    250         _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
     254        __cfadbg_print_safe(exception, "Begin unwinding (storage &p, context %p)\n", storage, context);
     255        _Unwind_Reason_Code ret = _Unwind_RaiseException( storage );
    251256
    252257        // If we reach here it means something happened. For resumption to work we need to find a way
     
    257262        // the whole stack.
    258263
     264        // We did not simply reach the end of the stack without finding a handler. This is an error.
     265        if ( ret != _URC_END_OF_STACK ) {
     266                printf("UNWIND ERROR %d after raise exception\n", ret);
     267                abort();
     268        }
     269
    259270        // No handler found, go to the default operation.
    260         // Currently this will always be a cancellation.
    261         if ( ret == _URC_END_OF_STACK ) {
    262                 __cfadbg_print_safe(exception, "Uncaught exception %p\n", &this_exception_storage);
    263 
    264                 __cfaehm_cancel_stack(this_exception_context()->current_exception);
    265         }
    266 
    267         // We did not simply reach the end of the stack without finding a handler. This is an error.
    268         printf("UNWIND ERROR %d after raise exception\n", ret);
     271        __cfadbg_print_safe(exception, "Uncaught exception %p\n", storage);
     272
     273        __attribute__((cleanup(__cfaehm_cleanup_default)))
     274        exception_t * exception = context->current_exception;
     275        defaultHandler( exception );
     276}
     277
     278void __cfaehm_throw_terminate( exception_t * val, void (*defaultHandler)(exception_t *) ) {
     279        __cfadbg_print_safe(exception, "Throwing termination exception\n");
     280
     281        __cfaehm_allocate_exception( val );
     282        __cfaehm_begin_unwind( defaultHandler );
     283}
     284
     285static __attribute__((noreturn)) void __cfaehm_rethrow_adapter( exception_t * except ) {
     286        // TODO: Print some error message.
     287        (void)except;
    269288        abort();
    270 }
    271 
    272 void __cfaehm_throw_terminate( exception_t * val ) {
    273         __cfadbg_print_safe(exception, "Throwing termination exception\n");
    274 
    275         __cfaehm_allocate_exception( val );
    276         __cfaehm_begin_unwind();
    277289}
    278290
     
    280292        __cfadbg_print_safe(exception, "Rethrowing termination exception\n");
    281293
    282         __cfaehm_begin_unwind();
     294        __cfaehm_begin_unwind( __cfaehm_rethrow_adapter );
     295        abort();
    283296}
    284297
  • libcfa/src/exception.h

    r2802824 r0e4df2e  
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Mar 27 10:16:00 2020
    13 // Update Count     : 9
     12// Last Modified On : Tue May 19 14:17:00 2020
     13// Update Count     : 10
    1414//
    1515
     
    3838
    3939
     40void __cfaehm_cancel_stack(exception_t * except) __attribute__((noreturn));
     41
    4042// Used in throw statement translation.
    41 void __cfaehm_throw_terminate(exception_t * except) __attribute__((noreturn));
     43void __cfaehm_throw_terminate(exception_t * except, void (*)(exception_t *));
    4244void __cfaehm_rethrow_terminate() __attribute__((noreturn));
    43 void __cfaehm_throw_resume(exception_t * except);
     45void __cfaehm_throw_resume(exception_t * except, void (*)(exception_t *));
    4446
    4547// Function catches termination exceptions.
     
    7072#ifdef __cforall
    7173}
     74
     75// Not all the built-ins can be expressed in C. These can't be
     76// implemented in the .c file either so they all have to be inline.
     77
     78trait is_exception(dtype T) {
     79        /* The first field must be a pointer to a virtual table.
     80         * That virtual table must be a decendent of the base exception virtual tab$
     81         */
     82        void mark_exception(T *);
     83        // This is never used and should be a no-op.
     84};
     85
     86trait is_termination_exception(dtype T | is_exception(T)) {
     87        void defaultTerminationHandler(T &);
     88};
     89
     90trait is_resumption_exception(dtype T | is_exception(T)) {
     91        void defaultResumptionHandler(T &);
     92};
     93
     94forall(dtype T | is_termination_exception(T))
     95static inline void $throw(T & except) {
     96        __cfaehm_throw_terminate(
     97                (exception_t *)&except,
     98                (void(*)(exception_t *))defaultTerminationHandler
     99        );
     100}
     101
     102forall(dtype T | is_resumption_exception(T))
     103static inline void $throwResume(T & except) {
     104        __cfaehm_throw_resume(
     105                (exception_t *)&except,
     106                (void(*)(exception_t *))defaultResumptionHandler
     107        );
     108}
     109
     110forall(dtype T | is_exception(T))
     111static inline void cancel_stack(T & except) __attribute__((noreturn)) {
     112        __cfaehm_cancel_stack( (exception_t *)&except );
     113}
     114
     115forall(dtype T | is_exception(T))
     116static inline void defaultTerminationHandler(T & except) {
     117        return cancel_stack( except );
     118}
     119
     120forall(dtype T | is_exception(T))
     121static inline void defaultResumptionHandler(T & except) {
     122        throw except;
     123}
     124
    72125#endif
  • libcfa/src/exception.hfa

    r2802824 r0e4df2e  
    1010// Created On       : Thu Apr  7 10:25:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Apr  7 10:25:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Tue May 19 14:17:00 2020
     13// Update Count     : 2
    1414//
    1515
     
    6969#define _VTABLE_DECLARATION(exception_name, parent_name, ...) \
    7070        struct exception_name; \
     71        void mark_exception(exception_name *); \
    7172        VTABLE_TYPE(exception_name); \
    7273        extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \
     
    8586#define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__)
    8687#define _VTABLE_INSTANCE(exception_name, parent_name, ...) \
     88        void mark_exception(exception_name *) {} \
    8789        void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \
    8890                *this = *other; \
  • libcfa/src/executor.cfa

    r2802824 r0e4df2e  
    44// buffer.
    55
    6 #include <bits/containers.hfa>
     6#include <containers/list.hfa>
    77#include <thread.hfa>
    88#include <stdio.h>
    99
    10 forall( dtype T )
    11 monitor Buffer {                                        // unbounded buffer
    12     __queue_t( T ) queue;                               // unbounded list of work requests
    13     condition delay;
    14 }; // Buffer
    15 forall( dtype T | is_node(T) ) {
    16     void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) {
    17         append( queue, elem );                          // insert element into buffer
    18         signal( delay );                                // restart
    19     } // insert
    20 
    21     T * remove( Buffer( T ) & mutex buf ) with(buf) {
    22         if ( queue.head != 0 ) wait( delay );                   // no request to process ? => wait
    23 //      return pop_head( queue );
    24     } // remove
    25 } // distribution
    26 
    2710struct WRequest {                                       // client request, no return
    2811    void (* action)( void );
    29     WRequest * next;                                    // intrusive queue field
     12    DLISTED_MGD_IMPL_IN(WRequest)
    3013}; // WRequest
     14DLISTED_MGD_IMPL_OUT(WRequest)
    3115
    32 WRequest *& get_next( WRequest & this ) { return this.next; }
    33 void ?{}( WRequest & req ) with(req) { action = 0; next = 0; }
    34 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; next = 0; }
     16void ?{}( WRequest & req ) with(req) { action = 0; }
     17void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; }
    3518bool stop( WRequest & req ) { return req.action == 0; }
    3619void doit( WRequest & req ) { req.action(); }
     20
     21monitor WRBuffer {                                      // unbounded buffer
     22    dlist( WRequest, WRequest ) queue;                  // unbounded list of work requests
     23    condition delay;
     24}; // WRBuffer
     25
     26void insert( WRBuffer & mutex buf, WRequest * elem ) with(buf) {
     27    insert_last( queue, *elem );                        // insert element into buffer
     28    signal( delay );                                    // restart
     29} // insert
     30
     31WRequest * remove( WRBuffer & mutex buf ) with(buf) {
     32    if ( queue`is_empty ) wait( delay );                // no request to process ? => wait
     33    return & pop_first( queue );
     34} // remove
    3735
    3836// Each worker has its own work buffer to reduce contention between client and server. Hence, work requests arrive and
     
    4038
    4139thread Worker {
    42     Buffer( WRequest ) * requests;
     40    WRBuffer * requests;
    4341    unsigned int start, range;
    4442}; // Worker
     
    5452} // Worker::main
    5553
    56 void ?{}( Worker & worker, cluster * wc, Buffer( WRequest ) * requests, unsigned int start, unsigned int range ) {
     54void ?{}( Worker & worker, cluster * wc, WRBuffer * requests, unsigned int start, unsigned int range ) {
    5755    (*get_thread(worker)){ *wc };                       // create on given cluster
    5856    worker.[requests, start, range] = [requests, start, range];
     
    6260    cluster * cluster;                                  // if workers execute on separate cluster
    6361    processor ** processors;                            // array of virtual processors adding parallelism for workers
    64     Buffer( WRequest ) * requests;                      // list of work requests
     62    WRBuffer * requests;                                // list of work requests
    6563    Worker ** workers;                                  // array of workers executing work requests
    6664    unsigned int nprocessors, nworkers, nmailboxes;     // number of mailboxes/workers/processor tasks
     
    7977    cluster = sepClus ? new( "Executor" ) : active_cluster();
    8078    processors = (processor **)anew( nprocessors );
    81     requests = anew( nmailboxes );
     79    requests = (WRBuffer *)anew( nmailboxes );
    8280    workers = (Worker **)anew( nworkers );
    8381
     
    141139        for ( i; 3000 ) {
    142140            send( exector, workie );
    143             if ( i % 100 ) yield();
     141            if ( i % 100 == 0 ) {
     142//              fprintf( stderr, "%d\n", i );
     143                yield();
     144            }
    144145        } // for
    145146    }
  • libcfa/src/heap.cfa

    r2802824 r0e4df2e  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  6 17:29:26 2020
    13 // Update Count     : 727
     12// Last Modified On : Sun May 17 20:58:17 2020
     13// Update Count     : 762
    1414//
    1515
     
    128128#define LOCKFREE 1
    129129#define BUCKETLOCK SPINLOCK
    130 #if BUCKETLOCK == LOCKFREE
    131 #include <uStackLF.h>
     130#if BUCKETLOCK == SPINLOCK
     131#elif BUCKETLOCK == LOCKFREE
     132#include <stackLockFree.hfa>
     133#else
     134        #error undefined lock type for bucket lock
    132135#endif // LOCKFREE
    133136
     
    137140
    138141struct HeapManager {
    139 //      struct FreeHeader;                                                                      // forward declaration
    140 
    141142        struct Storage {
    142143                struct Header {                                                                 // header
     
    146147                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    147148                                                        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    148                                                         uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     149                                                        uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    149150                                                        #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    150151
    151152                                                        union {
    152 //                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
     153                                                                // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
    153154                                                                // 2nd low-order bit => zero filled
    154155                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    155156                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    156                                                                 #if BUCKLOCK == SPINLOCK
     157                                                                #if BUCKETLOCK == SPINLOCK
    157158                                                                Storage * next;                 // freed block points next freed block of same size
    158159                                                                #endif // SPINLOCK
    159160                                                        };
     161                                                        size_t size;                            // allocation size in bytes
    160162
    161163                                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    162                                                         uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     164                                                        uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    163165                                                        #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    164166                                                };
    165                                                 // future code
    166                                                 #if BUCKLOCK == LOCKFREE
    167                                                 Stack<Storage>::Link next;              // freed block points next freed block of same size (double-wide)
     167                                                #if BUCKETLOCK == LOCKFREE
     168                                                Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
    168169                                                #endif // LOCKFREE
    169170                                        };
    170171                                } real; // RealHeader
     172
    171173                                struct FakeHeader {
    172174                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    173                                         // 1st low-order bit => fake header & alignment
    174                                         uint32_t alignment;
     175                                        uint32_t alignment;                                     // 1st low-order bit => fake header & alignment
    175176                                        #endif // __ORDER_LITTLE_ENDIAN__
    176177
     
    182183                                } fake; // FakeHeader
    183184                        } kind; // Kind
    184                         size_t size;                                                            // allocation size in bytes
    185185                } header; // Header
    186186                char pad[libAlign() - sizeof( Header )];
     
    191191
    192192        struct FreeHeader {
    193                 #if BUCKLOCK == SPINLOCK
     193                #if BUCKETLOCK == SPINLOCK
    194194                __spinlock_t lock;                                                              // must be first field for alignment
    195195                Storage * freeList;
    196                 #elif BUCKLOCK == LOCKFREE
    197                 // future code
    198                 StackLF<Storage> freeList;
    199196                #else
    200                         #error undefined lock type for bucket lock
    201                 #endif // SPINLOCK
     197                StackLF(Storage) freeList;
     198                #endif // BUCKETLOCK
    202199                size_t blockSize;                                                               // size of allocations on this list
    203200        }; // FreeHeader
     
    211208        size_t heapRemaining;                                                           // amount of storage not allocated in the current chunk
    212209}; // HeapManager
     210
     211#if BUCKETLOCK == LOCKFREE
     212static inline Link(HeapManager.Storage) * getNext( HeapManager.Storage * this ) { return &this->header.kind.real.next; }
     213static inline void ?{}( HeapManager.FreeHeader & ) {}
     214static inline void ^?{}( HeapManager.FreeHeader & ) {}
     215#endif // LOCKFREE
    213216
    214217static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
     
    251254static bool heapBoot = 0;                                                               // detect recursion during boot
    252255#endif // __CFA_DEBUG__
     256
     257// The constructor for heapManager is called explicitly in memory_startup.
    253258static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    254259
     
    354359
    355360
    356 // static inline void noMemory() {
    357 //      abort( "Heap memory exhausted at %zu bytes.\n"
    358 //                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
    359 //                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
    360 // } // noMemory
    361 
    362 
    363361// thunk problem
    364362size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
     
    406404
    407405
     406// static inline void noMemory() {
     407//      abort( "Heap memory exhausted at %zu bytes.\n"
     408//                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
     409//                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
     410// } // noMemory
     411
     412
    408413static inline void checkAlign( size_t alignment ) {
    409414        if ( alignment < libAlign() || ! libPow2( alignment ) ) {
     
    433438
    434439
    435 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
     440static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem,
     441                                                        size_t & size, size_t & alignment ) with( heapManager ) {
    436442        header = headerAddr( addr );
    437443
     
    465471
    466472
    467 static inline void * extend( size_t size ) with ( heapManager ) {
     473static inline void * extend( size_t size ) with( heapManager ) {
    468474        lock( extlock __cfaabi_dbg_ctx2 );
    469475        ptrdiff_t rem = heapRemaining - size;
     
    496502
    497503
    498 static inline void * doMalloc( size_t size ) with ( heapManager ) {
     504static inline void * doMalloc( size_t size ) with( heapManager ) {
    499505        HeapManager.Storage * block;                                            // pointer to new block of storage
    500506
     
    529535                // Spin until the lock is acquired for this particular size of block.
    530536
    531                 #if defined( SPINLOCK )
     537                #if BUCKETLOCK == SPINLOCK
    532538                lock( freeElem->lock __cfaabi_dbg_ctx2 );
    533539                block = freeElem->freeList;                                             // remove node from stack
    534540                #else
    535                 block = freeElem->freeList.pop();
    536                 #endif // SPINLOCK
     541                block = pop( freeElem->freeList );
     542                #endif // BUCKETLOCK
    537543                if ( unlikely( block == 0p ) ) {                                // no free block ?
    538                         #if defined( SPINLOCK )
     544                        #if BUCKETLOCK == SPINLOCK
    539545                        unlock( freeElem->lock );
    540                         #endif // SPINLOCK
     546                        #endif // BUCKETLOCK
    541547
    542548                        // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more
     
    544550
    545551                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    546   if ( unlikely( block == 0p ) ) return 0p;
    547                 #if defined( SPINLOCK )
     552        if ( unlikely( block == 0p ) ) return 0p;
     553                #if BUCKETLOCK == SPINLOCK
    548554                } else {
    549555                        freeElem->freeList = block->header.kind.real.next;
    550556                        unlock( freeElem->lock );
    551                 #endif // SPINLOCK
     557                #endif // BUCKETLOCK
    552558                } // if
    553559
     
    572578        } // if
    573579
    574         block->header.size = size;                                                      // store allocation size
     580        block->header.kind.real.size = size;                            // store allocation size
    575581        void * addr = &(block->data);                                           // adjust off header to user bytes
    576582
     
    591597
    592598
    593 static inline void doFree( void * addr ) with ( heapManager ) {
     599static inline void doFree( void * addr ) with( heapManager ) {
    594600        #ifdef __CFA_DEBUG__
    595601        if ( unlikely( heapManager.heapBegin == 0p ) ) {
     
    623629                free_storage += size;
    624630                #endif // __STATISTICS__
    625                 #if defined( SPINLOCK )
     631                #if BUCKETLOCK == SPINLOCK
    626632                lock( freeElem->lock __cfaabi_dbg_ctx2 );               // acquire spin lock
    627633                header->kind.real.next = freeElem->freeList;    // push on stack
     
    629635                unlock( freeElem->lock );                                               // release spin lock
    630636                #else
    631                 freeElem->freeList.push( *(HeapManager.Storage *)header );
    632                 #endif // SPINLOCK
     637                push( freeElem->freeList, *(HeapManager.Storage *)header );
     638                #endif // BUCKETLOCK
    633639        } // if
    634640
     
    645651
    646652
    647 size_t prtFree( HeapManager & manager ) with ( manager ) {
     653size_t prtFree( HeapManager & manager ) with( manager ) {
    648654        size_t total = 0;
    649655        #ifdef __STATISTICS__
     
    657663                #endif // __STATISTICS__
    658664
    659                 #if defined( SPINLOCK )
     665                #if BUCKETLOCK == SPINLOCK
    660666                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    661667                #else
    662                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
    663                 #endif // SPINLOCK
     668                for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
     669                        typeof(p) temp = getNext( p )->top;                     // FIX ME: direct assignent fails, initialization works
     670                        p = temp;
     671                #endif // BUCKETLOCK
    664672                        total += size;
    665673                        #ifdef __STATISTICS__
     
    681689
    682690
    683 static void ?{}( HeapManager & manager ) with ( manager ) {
     691static void ?{}( HeapManager & manager ) with( manager ) {
    684692        pageSize = sysconf( _SC_PAGESIZE );
    685693
     
    10951103                        header = realHeader( header );                          // backup from fake to real header
    10961104                } // if
    1097                 return header->size;
     1105                return header->kind.real.size;
    10981106        } // malloc_size
    10991107
     
    11051113                        header = realHeader( header );                          // backup from fake to real header
    11061114                } // if
    1107                 size_t ret = header->size;
    1108                 header->size = size;
     1115                size_t ret = header->kind.real.size;
     1116                header->kind.real.size = size;
    11091117                return ret;
    11101118        } // $malloc_size_set
  • libcfa/src/stdlib.hfa

    r2802824 r0e4df2e  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 16 22:44:05 2020
    13 // Update Count     : 432
     12// Last Modified On : Wed May 13 17:23:51 2020
     13// Update Count     : 435
    1414//
    1515
     
    2323// Reduce includes by explicitly defining these routines.
    2424extern "C" {
     25        void * aalloc( size_t dim, size_t elemSize );           // CFA heap
     26        void * resize( void * oaddr, size_t size );                     // CFA heap
    2527        void * memalign( size_t align, size_t size );           // malloc.h
     28        void * amemalign( size_t align, size_t dim, size_t elemSize ); // CFA heap
     29        void * cmemalign( size_t align, size_t noOfElems, size_t elemSize ); // CFA heap
     30        size_t malloc_size( void * addr );                                      // CFA heap
    2631        size_t malloc_usable_size( void * ptr );                        // malloc.h
    27         size_t malloc_size( void * addr );                                      // CFA heap
    28         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap
    2932        void * memset( void * dest, int fill, size_t size ); // string.h
    3033        void * memcpy( void * dest, const void * src, size_t size ); // string.h
    31         void * resize( void * oaddr, size_t size );                     // CFA heap
    3234} // extern "C"
    3335
     
    5254        } // malloc
    5355
     56        T * aalloc( size_t dim ) {
     57                if ( _Alignof(T) <= libAlign() ) return (T *)(void *)aalloc( dim, (size_t)sizeof(T) ); // CFA aalloc
     58                else return (T *)amemalign( _Alignof(T), dim, sizeof(T) );
     59        } // aalloc
     60
    5461        T * calloc( size_t dim ) {
    5562                if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc
     
    5764        } // calloc
    5865
     66        T * resize( T * ptr, size_t size ) {                            // CFA realloc, eliminate return-type cast
     67                return (T *)(void *)resize( (void *)ptr, size ); // C realloc
     68        } // resize
     69
    5970        T * realloc( T * ptr, size_t size ) {                           // CFA realloc, eliminate return-type cast
    6071                return (T *)(void *)realloc( (void *)ptr, size ); // C realloc
     
    6576        } // memalign
    6677
     78        T * amemalign( size_t align, size_t dim ) {
     79                return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign
     80        } // amemalign
     81
    6782        T * cmemalign( size_t align, size_t dim  ) {
    6883                return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign
     
    86101
    87102        T * alloc( size_t dim ) {
    88                 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( dim * (size_t)sizeof(T) );
    89                 else return (T *)memalign( _Alignof(T), dim * sizeof(T) );
     103                return aalloc( dim );
    90104        } // alloc
    91105
     
    106120                        return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc
    107121                } else {
    108                         struct __Unknown {};
    109                         return alloc( (__Unknown *)ptr, dim );          // reuse, cheat making T/S different types
     122                        return resize( ptr, dim * sizeof(T) );          // resize
    110123                } // if
    111124        } // alloc
     
    148161        } // alloc_align
    149162
    150         T * alloc_align( T ptr[], size_t align ) {                      // aligned realloc array
     163        T * alloc_align( T * ptr, size_t align ) {                      // aligned realloc array
    151164                return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc
    152165        } // alloc_align
Note: See TracChangeset for help on using the changeset viewer.