- Timestamp:
- May 22, 2020, 11:49:29 AM (4 years ago)
- 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. - Location:
- libcfa/src
- Files:
-
- 1 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
r2802824 r0e4df2e 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Mar 16 18:07:59202014 ## Update Count : 24 213 ## Last Modified On : Sun May 17 21:10:26 2020 14 ## Update Count : 243 15 15 ############################################################################### 16 16 … … 39 39 #---------------------------------------------------------------------------------------------------------------- 40 40 if 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 41 headers_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 42 43 headers = 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.hfa44 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/stackLockFree.hfa containers/vector.hfa 44 45 45 46 libsrc = startup.cfa interpose.cfa bits/debug.cfa assert.cfa exception.c virtual.c heap.cfa ${headers:.hfa=.cfa} -
libcfa/src/Makefile.in
r2802824 r0e4df2e 241 241 containers/maybe.hfa containers/pair.hfa containers/result.hfa \ 242 242 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 \ 244 244 bits/debug.hfa bits/locks.hfa containers/list.hfa \ 245 245 concurrency/coroutine.hfa concurrency/thread.hfa \ … … 465 465 466 466 #---------------------------------------------------------------------------------------------------------------- 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 468 470 @BUILDLIB_FALSE@headers = 469 471 @BUILDLIB_TRUE@headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \ 470 @BUILDLIB_TRUE@ 472 @BUILDLIB_TRUE@ containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa 471 473 472 474 @BUILDLIB_FALSE@libsrc = -
libcfa/src/concurrency/io.cfa
r2802824 r0e4df2e 124 124 125 125 // Like head/tail but not seen by the kernel 126 volatile uint32_t alloc;127 126 volatile uint32_t * ready; 128 127 uint32_t ready_cnt; … … 141 140 struct { 142 141 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; 144 145 volatile unsigned long long int cnt; 145 volatile unsigned long long int block;146 146 } submit_avg; 147 147 struct { … … 150 150 volatile unsigned long long int block; 151 151 } 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; 152 157 } stats; 153 158 #endif … … 279 284 sq.dropped = ( uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 280 285 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 } 282 293 283 294 if( io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) { … … 322 333 // Initialize statistics 323 334 #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; 327 339 this.io->submit_q.stats.look_avg.val = 0; 328 340 this.io->submit_q.stats.look_avg.cnt = 0; 329 341 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; 330 345 this.io->completion_q.stats.completed_avg.val = 0; 331 346 this.io->completion_q.stats.completed_avg.slow_cnt = 0; … … 384 399 this.ready_queue.head = 1p; 385 400 thrd.next = 0p; 401 __cfaabi_dbg_debug_do( thrd.unpark_stale = true ); 386 402 387 403 // Fixup the thread state … … 426 442 if(this.print_stats) { 427 443 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 428 448 double lavgv = 0; 429 449 double lavgb = 0; … … 433 453 } 434 454 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 435 462 __cfaabi_bits_print_safe( STDOUT_FILENO, 436 463 "----- I/O uRing Stats -----\n" 437 464 "- 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" 440 468 "- total ready search : %'15llu\n" 441 469 "- avg ready search len : %'18.2lf\n" 442 470 "- 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" 443 474 "- total wait calls : %'15llu (%'llu slow, %'llu fast)\n" 444 475 "- avg completion/wait : %'18.2lf\n", 445 476 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, 448 480 look_avg.cnt, 449 481 lavgv, 450 482 lavgb, 483 alloc_avg.cnt, 484 aavgv, 485 aavgb, 451 486 completed_avg.slow_cnt + completed_avg.fast_cnt, 452 487 completed_avg.slow_cnt, completed_avg.fast_cnt, … … 494 529 495 530 // 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; 497 532 const uint32_t mask = *ring.submit_q.mask; 498 533 … … 506 541 507 542 // 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; 509 544 to_submit++; 510 545 } 511 546 512 547 // 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; 522 553 int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8); 523 554 if( ret < 0 ) { … … 531 562 } 532 563 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 533 586 // Drain the queue 534 587 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 ); 536 593 537 594 // Nothing was new return 0 … … 542 599 uint32_t count = tail - head; 543 600 for(i; count) { 544 unsigned idx = (head + i) & (*ring.completion_q.mask);601 unsigned idx = (head + i) & mask; 545 602 struct io_uring_cqe & cqe = ring.completion_q.cqes[idx]; 546 603 … … 556 613 557 614 // Allow new submissions to happen 558 V(ring.submit, count);615 // V(ring.submit, count); 559 616 560 617 // Mark to the kernel that the cqe has been seen 561 618 // 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 ); 562 620 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_RELAXED ); 563 621 … … 710 768 // 711 769 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 } 727 810 } 728 811 … … 742 825 __attribute((unused)) int len = 0; 743 826 __attribute((unused)) int block = 0; 744 uint32_t expected = -1ul32;745 827 uint32_t ready_mask = ring.submit_q.ready_cnt - 1; 746 828 uint32_t off = __tls_rand(); … … 748 830 for(i; ring.submit_q.ready_cnt) { 749 831 uint32_t ii = (i + off) & ready_mask; 832 uint32_t expected = -1ul32; 750 833 if( __atomic_compare_exchange_n( &ring.submit_q.ready[ii], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) { 751 834 break LOOKING; 752 835 } 836 verify(expected != idx); 753 837 754 838 len ++; … … 792 876 // update statistics 793 877 #if !defined(__CFA_NO_STATISTICS__) 794 ring.submit_q.stats.submit_avg. val+= 1;878 ring.submit_q.stats.submit_avg.csm += 1; 795 879 ring.submit_q.stats.submit_avg.cnt += 1; 796 880 #endif … … 831 915 832 916 #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; \ 834 919 struct io_uring_sqe * sqe; \ 835 920 uint32_t idx; \ 836 [sqe, idx] = __submit_alloc( ring );921 [sqe, idx] = __submit_alloc( ring, (uint64_t)&data ); 837 922 838 923 #define __submit_wait \ 839 io_user_data data = { 0, active_thread() }; \840 924 /*__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 ); \ 842 926 __submit( ring, idx ); \ 843 927 park( __cfaabi_dbg_ctx ); \ -
libcfa/src/concurrency/kernel.cfa
r2802824 r0e4df2e 648 648 649 649 // record activity 650 __cfaabi_dbg_debug_do( char * old_caller = thrd->unpark_caller; ) 650 651 __cfaabi_dbg_record_thrd( *thrd, false, caller ); 651 652 -
libcfa/src/containers/list.hfa
r2802824 r0e4df2e 301 301 $prev_link(list_pos) = (Telem*) 0p; 302 302 } 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 303 340 } 304 341 -
libcfa/src/exception.c
r2802824 r0e4df2e 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Apr 14 12:01:00 202013 // Update Count : 1812 // Last Modified On : Thr May 21 12:18:00 2020 13 // Update Count : 20 14 14 // 15 15 … … 80 80 } 81 81 82 void __cfaehm_throw_resume(exception_t * except ) {82 void __cfaehm_throw_resume(exception_t * except, void (*defaultHandler)(exception_t *)) { 83 83 struct exception_context_t * context = this_exception_context(); 84 84 … … 96 96 } 97 97 98 // No handler found, fall back to the default operation. 98 99 __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); 103 101 } 104 102 … … 223 221 224 222 // Cancel the current stack, prefroming approprate clean-up and messaging. 225 static __attribute__((noreturn)) void __cfaehm_cancel_stack( 226 exception_t * exception ) { 223 void __cfaehm_cancel_stack( exception_t * exception ) { 227 224 // TODO: Detect current stack and pick a particular stop-function. 228 225 _Unwind_Reason_Code ret; … … 240 237 } 241 238 239 static void __cfaehm_cleanup_default( exception_t ** except ) { 240 __cfaehm_delete_exception( *except ); 241 *except = NULL; 242 } 243 242 244 // 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 ) { 245 static 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 ) { 245 249 printf("UNWIND ERROR missing exception in begin unwind\n"); 246 250 abort(); … … 248 252 249 253 // 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 ); 251 256 252 257 // If we reach here it means something happened. For resumption to work we need to find a way … … 257 262 // the whole stack. 258 263 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 259 270 // 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 278 void __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 285 static __attribute__((noreturn)) void __cfaehm_rethrow_adapter( exception_t * except ) { 286 // TODO: Print some error message. 287 (void)except; 269 288 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();277 289 } 278 290 … … 280 292 __cfadbg_print_safe(exception, "Rethrowing termination exception\n"); 281 293 282 __cfaehm_begin_unwind(); 294 __cfaehm_begin_unwind( __cfaehm_rethrow_adapter ); 295 abort(); 283 296 } 284 297 -
libcfa/src/exception.h
r2802824 r0e4df2e 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Mar 27 10:16:00 202013 // Update Count : 912 // Last Modified On : Tue May 19 14:17:00 2020 13 // Update Count : 10 14 14 // 15 15 … … 38 38 39 39 40 void __cfaehm_cancel_stack(exception_t * except) __attribute__((noreturn)); 41 40 42 // Used in throw statement translation. 41 void __cfaehm_throw_terminate(exception_t * except ) __attribute__((noreturn));43 void __cfaehm_throw_terminate(exception_t * except, void (*)(exception_t *)); 42 44 void __cfaehm_rethrow_terminate() __attribute__((noreturn)); 43 void __cfaehm_throw_resume(exception_t * except );45 void __cfaehm_throw_resume(exception_t * except, void (*)(exception_t *)); 44 46 45 47 // Function catches termination exceptions. … … 70 72 #ifdef __cforall 71 73 } 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 78 trait 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 86 trait is_termination_exception(dtype T | is_exception(T)) { 87 void defaultTerminationHandler(T &); 88 }; 89 90 trait is_resumption_exception(dtype T | is_exception(T)) { 91 void defaultResumptionHandler(T &); 92 }; 93 94 forall(dtype T | is_termination_exception(T)) 95 static inline void $throw(T & except) { 96 __cfaehm_throw_terminate( 97 (exception_t *)&except, 98 (void(*)(exception_t *))defaultTerminationHandler 99 ); 100 } 101 102 forall(dtype T | is_resumption_exception(T)) 103 static inline void $throwResume(T & except) { 104 __cfaehm_throw_resume( 105 (exception_t *)&except, 106 (void(*)(exception_t *))defaultResumptionHandler 107 ); 108 } 109 110 forall(dtype T | is_exception(T)) 111 static inline void cancel_stack(T & except) __attribute__((noreturn)) { 112 __cfaehm_cancel_stack( (exception_t *)&except ); 113 } 114 115 forall(dtype T | is_exception(T)) 116 static inline void defaultTerminationHandler(T & except) { 117 return cancel_stack( except ); 118 } 119 120 forall(dtype T | is_exception(T)) 121 static inline void defaultResumptionHandler(T & except) { 122 throw except; 123 } 124 72 125 #endif -
libcfa/src/exception.hfa
r2802824 r0e4df2e 10 10 // Created On : Thu Apr 7 10:25:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Apr 7 10:25:00 202013 // Update Count : 012 // Last Modified On : Tue May 19 14:17:00 2020 13 // Update Count : 2 14 14 // 15 15 … … 69 69 #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ 70 70 struct exception_name; \ 71 void mark_exception(exception_name *); \ 71 72 VTABLE_TYPE(exception_name); \ 72 73 extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ … … 85 86 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) 86 87 #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ 88 void mark_exception(exception_name *) {} \ 87 89 void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ 88 90 *this = *other; \ -
libcfa/src/executor.cfa
r2802824 r0e4df2e 4 4 // buffer. 5 5 6 #include < bits/containers.hfa>6 #include <containers/list.hfa> 7 7 #include <thread.hfa> 8 8 #include <stdio.h> 9 9 10 forall( dtype T )11 monitor Buffer { // unbounded buffer12 __queue_t( T ) queue; // unbounded list of work requests13 condition delay;14 }; // Buffer15 forall( dtype T | is_node(T) ) {16 void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) {17 append( queue, elem ); // insert element into buffer18 signal( delay ); // restart19 } // insert20 21 T * remove( Buffer( T ) & mutex buf ) with(buf) {22 if ( queue.head != 0 ) wait( delay ); // no request to process ? => wait23 // return pop_head( queue );24 } // remove25 } // distribution26 27 10 struct WRequest { // client request, no return 28 11 void (* action)( void ); 29 WRequest * next; // intrusive queue field12 DLISTED_MGD_IMPL_IN(WRequest) 30 13 }; // WRequest 14 DLISTED_MGD_IMPL_OUT(WRequest) 31 15 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; } 16 void ?{}( WRequest & req ) with(req) { action = 0; } 17 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; } 35 18 bool stop( WRequest & req ) { return req.action == 0; } 36 19 void doit( WRequest & req ) { req.action(); } 20 21 monitor WRBuffer { // unbounded buffer 22 dlist( WRequest, WRequest ) queue; // unbounded list of work requests 23 condition delay; 24 }; // WRBuffer 25 26 void insert( WRBuffer & mutex buf, WRequest * elem ) with(buf) { 27 insert_last( queue, *elem ); // insert element into buffer 28 signal( delay ); // restart 29 } // insert 30 31 WRequest * 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 37 35 38 36 // Each worker has its own work buffer to reduce contention between client and server. Hence, work requests arrive and … … 40 38 41 39 thread Worker { 42 Buffer( WRequest )* requests;40 WRBuffer * requests; 43 41 unsigned int start, range; 44 42 }; // Worker … … 54 52 } // Worker::main 55 53 56 void ?{}( Worker & worker, cluster * wc, Buffer( WRequest )* requests, unsigned int start, unsigned int range ) {54 void ?{}( Worker & worker, cluster * wc, WRBuffer * requests, unsigned int start, unsigned int range ) { 57 55 (*get_thread(worker)){ *wc }; // create on given cluster 58 56 worker.[requests, start, range] = [requests, start, range]; … … 62 60 cluster * cluster; // if workers execute on separate cluster 63 61 processor ** processors; // array of virtual processors adding parallelism for workers 64 Buffer( WRequest ) * requests;// list of work requests62 WRBuffer * requests; // list of work requests 65 63 Worker ** workers; // array of workers executing work requests 66 64 unsigned int nprocessors, nworkers, nmailboxes; // number of mailboxes/workers/processor tasks … … 79 77 cluster = sepClus ? new( "Executor" ) : active_cluster(); 80 78 processors = (processor **)anew( nprocessors ); 81 requests = anew( nmailboxes );79 requests = (WRBuffer *)anew( nmailboxes ); 82 80 workers = (Worker **)anew( nworkers ); 83 81 … … 141 139 for ( i; 3000 ) { 142 140 send( exector, workie ); 143 if ( i % 100 ) yield(); 141 if ( i % 100 == 0 ) { 142 // fprintf( stderr, "%d\n", i ); 143 yield(); 144 } 144 145 } // for 145 146 } -
libcfa/src/heap.cfa
r2802824 r0e4df2e 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 6 17:29:26202013 // Update Count : 7 2712 // Last Modified On : Sun May 17 20:58:17 2020 13 // Update Count : 762 14 14 // 15 15 … … 128 128 #define LOCKFREE 1 129 129 #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 132 135 #endif // LOCKFREE 133 136 … … 137 140 138 141 struct HeapManager { 139 // struct FreeHeader; // forward declaration140 141 142 struct Storage { 142 143 struct Header { // header … … 146 147 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 147 148 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 148 uint 32_t padding; // unused, force home/blocksize to overlay alignment in fake header149 uint64_t padding; // unused, force home/blocksize to overlay alignment in fake header 149 150 #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 150 151 151 152 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) 153 154 // 2nd low-order bit => zero filled 154 155 void * home; // allocated block points back to home locations (must overlay alignment) 155 156 size_t blockSize; // size for munmap (must overlay alignment) 156 #if BUCK LOCK == SPINLOCK157 #if BUCKETLOCK == SPINLOCK 157 158 Storage * next; // freed block points next freed block of same size 158 159 #endif // SPINLOCK 159 160 }; 161 size_t size; // allocation size in bytes 160 162 161 163 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 162 uint 32_t padding; // unused, force home/blocksize to overlay alignment in fake header164 uint64_t padding; // unused, force home/blocksize to overlay alignment in fake header 163 165 #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 164 166 }; 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) 168 169 #endif // LOCKFREE 169 170 }; 170 171 } real; // RealHeader 172 171 173 struct FakeHeader { 172 174 #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 175 176 #endif // __ORDER_LITTLE_ENDIAN__ 176 177 … … 182 183 } fake; // FakeHeader 183 184 } kind; // Kind 184 size_t size; // allocation size in bytes185 185 } header; // Header 186 186 char pad[libAlign() - sizeof( Header )]; … … 191 191 192 192 struct FreeHeader { 193 #if BUCK LOCK == SPINLOCK193 #if BUCKETLOCK == SPINLOCK 194 194 __spinlock_t lock; // must be first field for alignment 195 195 Storage * freeList; 196 #elif BUCKLOCK == LOCKFREE197 // future code198 StackLF<Storage> freeList;199 196 #else 200 #error undefined lock type for bucket lock201 #endif // SPINLOCK197 StackLF(Storage) freeList; 198 #endif // BUCKETLOCK 202 199 size_t blockSize; // size of allocations on this list 203 200 }; // FreeHeader … … 211 208 size_t heapRemaining; // amount of storage not allocated in the current chunk 212 209 }; // HeapManager 210 211 #if BUCKETLOCK == LOCKFREE 212 static inline Link(HeapManager.Storage) * getNext( HeapManager.Storage * this ) { return &this->header.kind.real.next; } 213 static inline void ?{}( HeapManager.FreeHeader & ) {} 214 static inline void ^?{}( HeapManager.FreeHeader & ) {} 215 #endif // LOCKFREE 213 216 214 217 static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; } … … 251 254 static bool heapBoot = 0; // detect recursion during boot 252 255 #endif // __CFA_DEBUG__ 256 257 // The constructor for heapManager is called explicitly in memory_startup. 253 258 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 254 259 … … 354 359 355 360 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 // } // noMemory361 362 363 361 // thunk problem 364 362 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { … … 406 404 407 405 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 408 413 static inline void checkAlign( size_t alignment ) { 409 414 if ( alignment < libAlign() || ! libPow2( alignment ) ) { … … 433 438 434 439 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 ) { 440 static 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 ) { 436 442 header = headerAddr( addr ); 437 443 … … 465 471 466 472 467 static inline void * extend( size_t size ) with 473 static inline void * extend( size_t size ) with( heapManager ) { 468 474 lock( extlock __cfaabi_dbg_ctx2 ); 469 475 ptrdiff_t rem = heapRemaining - size; … … 496 502 497 503 498 static inline void * doMalloc( size_t size ) with 504 static inline void * doMalloc( size_t size ) with( heapManager ) { 499 505 HeapManager.Storage * block; // pointer to new block of storage 500 506 … … 529 535 // Spin until the lock is acquired for this particular size of block. 530 536 531 #if defined( SPINLOCK )537 #if BUCKETLOCK == SPINLOCK 532 538 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 533 539 block = freeElem->freeList; // remove node from stack 534 540 #else 535 block = freeElem->freeList.pop();536 #endif // SPINLOCK541 block = pop( freeElem->freeList ); 542 #endif // BUCKETLOCK 537 543 if ( unlikely( block == 0p ) ) { // no free block ? 538 #if defined( SPINLOCK )544 #if BUCKETLOCK == SPINLOCK 539 545 unlock( freeElem->lock ); 540 #endif // SPINLOCK546 #endif // BUCKETLOCK 541 547 542 548 // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more … … 544 550 545 551 block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call 546 547 #if defined( SPINLOCK )552 if ( unlikely( block == 0p ) ) return 0p; 553 #if BUCKETLOCK == SPINLOCK 548 554 } else { 549 555 freeElem->freeList = block->header.kind.real.next; 550 556 unlock( freeElem->lock ); 551 #endif // SPINLOCK557 #endif // BUCKETLOCK 552 558 } // if 553 559 … … 572 578 } // if 573 579 574 block->header. size = size;// store allocation size580 block->header.kind.real.size = size; // store allocation size 575 581 void * addr = &(block->data); // adjust off header to user bytes 576 582 … … 591 597 592 598 593 static inline void doFree( void * addr ) with 599 static inline void doFree( void * addr ) with( heapManager ) { 594 600 #ifdef __CFA_DEBUG__ 595 601 if ( unlikely( heapManager.heapBegin == 0p ) ) { … … 623 629 free_storage += size; 624 630 #endif // __STATISTICS__ 625 #if defined( SPINLOCK )631 #if BUCKETLOCK == SPINLOCK 626 632 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 627 633 header->kind.real.next = freeElem->freeList; // push on stack … … 629 635 unlock( freeElem->lock ); // release spin lock 630 636 #else 631 freeElem->freeList.push(*(HeapManager.Storage *)header );632 #endif // SPINLOCK637 push( freeElem->freeList, *(HeapManager.Storage *)header ); 638 #endif // BUCKETLOCK 633 639 } // if 634 640 … … 645 651 646 652 647 size_t prtFree( HeapManager & manager ) with 653 size_t prtFree( HeapManager & manager ) with( manager ) { 648 654 size_t total = 0; 649 655 #ifdef __STATISTICS__ … … 657 663 #endif // __STATISTICS__ 658 664 659 #if defined( SPINLOCK )665 #if BUCKETLOCK == SPINLOCK 660 666 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 661 667 #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 664 672 total += size; 665 673 #ifdef __STATISTICS__ … … 681 689 682 690 683 static void ?{}( HeapManager & manager ) with 691 static void ?{}( HeapManager & manager ) with( manager ) { 684 692 pageSize = sysconf( _SC_PAGESIZE ); 685 693 … … 1095 1103 header = realHeader( header ); // backup from fake to real header 1096 1104 } // if 1097 return header-> size;1105 return header->kind.real.size; 1098 1106 } // malloc_size 1099 1107 … … 1105 1113 header = realHeader( header ); // backup from fake to real header 1106 1114 } // 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; 1109 1117 return ret; 1110 1118 } // $malloc_size_set -
libcfa/src/stdlib.hfa
r2802824 r0e4df2e 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 16 22:44:05202013 // Update Count : 43 212 // Last Modified On : Wed May 13 17:23:51 2020 13 // Update Count : 435 14 14 // 15 15 … … 23 23 // Reduce includes by explicitly defining these routines. 24 24 extern "C" { 25 void * aalloc( size_t dim, size_t elemSize ); // CFA heap 26 void * resize( void * oaddr, size_t size ); // CFA heap 25 27 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 26 31 size_t malloc_usable_size( void * ptr ); // malloc.h 27 size_t malloc_size( void * addr ); // CFA heap28 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap29 32 void * memset( void * dest, int fill, size_t size ); // string.h 30 33 void * memcpy( void * dest, const void * src, size_t size ); // string.h 31 void * resize( void * oaddr, size_t size ); // CFA heap32 34 } // extern "C" 33 35 … … 52 54 } // malloc 53 55 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 54 61 T * calloc( size_t dim ) { 55 62 if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc … … 57 64 } // calloc 58 65 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 59 70 T * realloc( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast 60 71 return (T *)(void *)realloc( (void *)ptr, size ); // C realloc … … 65 76 } // memalign 66 77 78 T * amemalign( size_t align, size_t dim ) { 79 return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign 80 } // amemalign 81 67 82 T * cmemalign( size_t align, size_t dim ) { 68 83 return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign … … 86 101 87 102 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 ); 90 104 } // alloc 91 105 … … 106 120 return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 107 121 } 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 110 123 } // if 111 124 } // alloc … … 148 161 } // alloc_align 149 162 150 T * alloc_align( T ptr[], size_t align ) { // aligned realloc array163 T * alloc_align( T * ptr, size_t align ) { // aligned realloc array 151 164 return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc 152 165 } // alloc_align
Note: See TracChangeset
for help on using the changeset viewer.