Changes in / [a505021:c744563a]
- Files:
-
- 4 deleted
- 16 edited
-
libcfa/src/bits/containers.hfa (modified) (2 diffs)
-
libcfa/src/bits/locks.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (4 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (18 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/monitor.cfa (modified) (19 diffs)
-
libcfa/src/concurrency/monitor.hfa (modified) (1 diff)
-
libcfa/src/concurrency/mutex.cfa (modified) (8 diffs)
-
libcfa/src/concurrency/preemption.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (2 diffs)
-
tests/concurrent/examples/.expect/datingService.txt (modified) (1 diff)
-
tests/concurrent/examples/datingService.cfa (modified) (3 diffs)
-
tests/concurrent/multi-monitor.cfa (modified) (1 diff)
-
tests/concurrent/park/.expect/contention.txt (deleted)
-
tests/concurrent/park/.expect/force_preempt.txt (deleted)
-
tests/concurrent/park/contention.cfa (deleted)
-
tests/concurrent/park/force_preempt.cfa (deleted)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/bits/containers.hfa
ra505021 rc744563a 146 146 static inline forall( dtype T | is_node(T) ) { 147 147 void ?{}( __queue(T) & this ) with( this ) { 148 head{ 1p };148 head{ 0p }; 149 149 tail{ &head }; 150 verify(*tail == 1p);151 150 } 152 151 153 152 void append( __queue(T) & this, T * val ) with( this ) { 154 153 verify(tail != 0p); 155 verify(*tail == 1p);156 154 *tail = val; 157 155 tail = &get_next( *val ); 158 *tail = 1p;159 156 } 160 157 161 158 T * pop_head( __queue(T) & this ) { 162 verify(*this.tail == 1p);163 159 T * head = this.head; 164 if( head != 1p) {160 if( head ) { 165 161 this.head = get_next( *head ); 166 if( get_next( *head ) == 1p) {162 if( !get_next( *head ) ) { 167 163 this.tail = &this.head; 168 164 } 169 165 get_next( *head ) = 0p; 170 verify(*this.tail == 1p); 171 return head; 172 } 173 verify(*this.tail == 1p); 174 return 0p; 166 } 167 return head; 175 168 } 176 169 … … 187 180 get_next( *val ) = 0p; 188 181 189 verify( (head == 1p) == (&head == tail) );190 verify( *tail == 1p );182 verify( (head == 0p) == (&head == tail) ); 183 verify( *tail == 0p ); 191 184 return val; 192 185 } -
libcfa/src/bits/locks.hfa
ra505021 rc744563a 60 60 } 61 61 62 extern void yield( unsigned int ); 63 62 64 static inline void ?{}( __spinlock_t & this ) { 63 65 this.lock = 0; … … 66 68 // Lock the spinlock, return false if already acquired 67 69 static inline bool try_lock ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) { 68 disable_interrupts();69 70 bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0); 70 71 if( result ) { 72 disable_interrupts(); 71 73 __cfaabi_dbg_record( this, caller ); 72 } else {73 enable_interrupts_noPoll();74 74 } 75 75 return result; … … 83 83 #endif 84 84 85 disable_interrupts();86 85 for ( unsigned int i = 1;; i += 1 ) { 87 86 if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break; … … 99 98 #endif 100 99 } 100 disable_interrupts(); 101 101 __cfaabi_dbg_record( this, caller ); 102 102 } 103 103 104 104 static inline void unlock( __spinlock_t & this ) { 105 enable_interrupts_noPoll(); 105 106 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 106 enable_interrupts_noPoll();107 107 } 108 108 -
libcfa/src/concurrency/coroutine.hfa
ra505021 rc744563a 54 54 void prime(T & cor); 55 55 56 static inline struct coroutine_desc * active_coroutine() __attribute__((const)){ return TL_GET( this_thread )->curr_cor; }56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; } 57 57 58 58 //----------------------------------------------------------------------------- … … 73 73 // Private wrappers for context switch and stack creation 74 74 // Wrapper for co 75 static inline void CoroutineCtxSwitch( coroutine_desc * src, coroutine_desc * dst ) __attribute__((nonnull (1, 2))) {75 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 76 76 // set state of current coroutine to inactive 77 77 src->state = src->state == Halted ? Halted : Inactive; … … 152 152 } 153 153 154 static inline void resume( coroutine_desc * dst ) __attribute__((nonnull (1))) {154 static inline void resume(coroutine_desc * dst) { 155 155 // optimization : read TLS once and reuse it 156 156 // Safety note: this is preemption safe since if -
libcfa/src/concurrency/invoke.h
ra505021 rc744563a 92 92 }; 93 93 94 enum coroutine_state { Halted, Start, Primed, Inactive, Active, Rerun }; 95 enum __Preemption_Reason { __NO_PREEMPTION, __ALARM_PREEMPTION, __POLL_PREEMPTION, __MANUAL_PREEMPTION }; 94 enum coroutine_state { Halted, Start, Inactive, Active, Primed }; 96 95 97 96 struct coroutine_desc { … … 165 164 166 165 // current execution status for coroutine 167 volatile int state; 168 enum __Preemption_Reason preempted; 166 enum coroutine_state state; 169 167 170 168 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it … … 200 198 #ifdef __cforall 201 199 extern "Cforall" { 202 static inline thread_desc *& get_next( thread_desc & this ) __attribute__((const)){200 static inline thread_desc *& get_next( thread_desc & this ) { 203 201 return this.next; 204 202 } 205 203 206 static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) /*__attribute__((const))*/{204 static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) { 207 205 return this.node.[next, prev]; 208 206 } … … 220 218 } 221 219 222 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) __attribute__((const)){220 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) { 223 221 if( (lhs.data != 0) != (rhs.data != 0) ) return false; 224 222 if( lhs.size != rhs.size ) return false; -
libcfa/src/concurrency/kernel.cfa
ra505021 rc744563a 110 110 //----------------------------------------------------------------------------- 111 111 //Start and stop routine for the kernel, declared first to make sure they run first 112 static void __kernel_startup (void)__attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));113 static void __kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));112 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 113 static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 114 114 115 115 //----------------------------------------------------------------------------- … … 208 208 } 209 209 210 static void * CtxInvokeProcessor(void * arg); 211 210 static void start(processor * this); 212 211 void ?{}(processor & this, const char name[], cluster & cltr) with( this ) { 213 212 this.name = name; 214 213 this.cltr = &cltr; 215 214 terminated{ 0 }; 216 destroyer = 0p;217 215 do_terminate = false; 218 216 preemption_alarm = 0p; … … 222 220 idleLock{}; 223 221 224 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", &this); 225 226 this.stack = __create_pthread( &this.kernel_thread, CtxInvokeProcessor, (void *)&this ); 227 228 __cfaabi_dbg_print_safe("Kernel : core %p started\n", &this); 222 start( &this ); 229 223 } 230 224 … … 264 258 // Kernel Scheduling logic 265 259 //============================================================================================= 266 static thread_desc * __next_thread(cluster * this);267 static void __run_thread(processor * this, thread_desc * dst);268 static void __halt(processor * this);260 static void runThread(processor * this, thread_desc * dst); 261 static void finishRunning(processor * this); 262 static void halt(processor * this); 269 263 270 264 //Main of the processor contexts … … 289 283 thread_desc * readyThread = 0p; 290 284 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ ) { 291 readyThread = __next_thread( this->cltr );285 readyThread = nextThread( this->cltr ); 292 286 293 287 if(readyThread) { 294 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 295 /* paranoid */ verifyf( readyThread->state == Inactive || readyThread->state == Start || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted); 296 /* paranoid */ verifyf( readyThread->next == 0p, "Expected null got %p", readyThread->next ); 297 298 __run_thread(this, readyThread); 299 300 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 288 verify( ! kernelTLS.preemption_state.enabled ); 289 290 runThread(this, readyThread); 291 292 verify( ! kernelTLS.preemption_state.enabled ); 293 294 //Some actions need to be taken from the kernel 295 finishRunning(this); 301 296 302 297 spin_count = 0; 303 298 } else { 304 299 // spin(this, &spin_count); 305 __halt(this);300 halt(this); 306 301 } 307 302 } … … 323 318 // runThread runs a thread by context switching 324 319 // from the processor coroutine to the target thread 325 static void __run_thread(processor * this, thread_desc * thrd_dst) {320 static void runThread(processor * this, thread_desc * thrd_dst) { 326 321 coroutine_desc * proc_cor = get_coroutine(this->runner); 322 323 // Reset the terminating actions here 324 this->finish.action_code = No_Action; 327 325 328 326 // Update global state 329 327 kernelTLS.this_thread = thrd_dst; 330 328 331 // set state of processor coroutine to inactive 332 verify(proc_cor->state == Active); 333 proc_cor->state = Inactive; 334 335 // Actually run the thread 336 RUNNING: while(true) { 337 if(unlikely(thrd_dst->preempted)) { 338 thrd_dst->preempted = __NO_PREEMPTION; 339 verify(thrd_dst->state == Active || thrd_dst->state == Rerun); 340 } else { 341 verify(thrd_dst->state == Start || thrd_dst->state == Primed || thrd_dst->state == Inactive); 342 thrd_dst->state = Active; 343 } 344 345 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 346 347 // set context switch to the thread that the processor is executing 348 verify( thrd_dst->context.SP ); 349 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 350 // when CtxSwitch returns we are back in the processor coroutine 351 352 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 353 354 355 // We just finished running a thread, there are a few things that could have happened. 356 // 1 - Regular case : the thread has blocked and now one has scheduled it yet. 357 // 2 - Racy case : the thread has blocked but someone has already tried to schedule it. 358 // 3 - Polite Racy case : the thread has blocked, someone has already tried to schedule it, but the thread is nice and wants to go through the ready-queue any way 359 // 4 - Preempted 360 // In case 1, we may have won a race so we can't write to the state again. 361 // In case 2, we lost the race so we now own the thread. 362 // In case 3, we lost the race but can just reschedule the thread. 363 364 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 365 // The thread was preempted, reschedule it and reset the flag 366 __schedule_thread( thrd_dst ); 367 break RUNNING; 368 } 369 370 // set state of processor coroutine to active and the thread to inactive 371 static_assert(sizeof(thrd_dst->state) == sizeof(int)); 372 enum coroutine_state old_state = __atomic_exchange_n(&thrd_dst->state, Inactive, __ATOMIC_SEQ_CST); 373 switch(old_state) { 374 case Halted: 375 // The thread has halted, it should never be scheduled/run again, leave it back to Halted and move on 376 thrd_dst->state = Halted; 377 378 // We may need to wake someone up here since 379 unpark( this->destroyer ); 380 this->destroyer = 0p; 381 break RUNNING; 382 case Active: 383 // This is case 1, the regular case, nothing more is needed 384 break RUNNING; 385 case Rerun: 386 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 387 // In this case, just run it again. 388 continue RUNNING; 389 default: 390 // This makes no sense, something is wrong abort 391 abort("Finished running a thread that was Inactive/Start/Primed %d\n", old_state); 392 } 393 } 394 395 // Just before returning to the processor, set the processor coroutine to active 329 // set state of processor coroutine to inactive and the thread to active 330 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 331 thrd_dst->state = Active; 332 333 // set context switch to the thread that the processor is executing 334 verify( thrd_dst->context.SP ); 335 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 336 // when CtxSwitch returns we are back in the processor coroutine 337 338 // set state of processor coroutine to active and the thread to inactive 339 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive; 396 340 proc_cor->state = Active; 397 341 } 398 342 399 343 // KERNEL_ONLY 400 void returnToKernel() { 401 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 344 static void returnToKernel() { 402 345 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 403 346 thread_desc * thrd_src = kernelTLS.this_thread; 404 347 405 // Run the thread on this processor 406 { 407 int local_errno = *__volatile_errno(); 408 #if defined( __i386 ) || defined( __x86_64 ) 409 __x87_store; 410 #endif 411 verify( proc_cor->context.SP ); 412 CtxSwitch( &thrd_src->context, &proc_cor->context ); 413 #if defined( __i386 ) || defined( __x86_64 ) 414 __x87_load; 415 #endif 416 *__volatile_errno() = local_errno; 417 } 418 419 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 348 // set state of current coroutine to inactive 349 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive; 350 proc_cor->state = Active; 351 int local_errno = *__volatile_errno(); 352 #if defined( __i386 ) || defined( __x86_64 ) 353 __x87_store; 354 #endif 355 356 // set new coroutine that the processor is executing 357 // and context switch to it 358 verify( proc_cor->context.SP ); 359 CtxSwitch( &thrd_src->context, &proc_cor->context ); 360 361 // set state of new coroutine to active 362 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 363 thrd_src->state = Active; 364 365 #if defined( __i386 ) || defined( __x86_64 ) 366 __x87_load; 367 #endif 368 *__volatile_errno() = local_errno; 369 } 370 371 // KERNEL_ONLY 372 // Once a thread has finished running, some of 373 // its final actions must be executed from the kernel 374 static void finishRunning(processor * this) with( this->finish ) { 375 verify( ! kernelTLS.preemption_state.enabled ); 376 choose( action_code ) { 377 case No_Action: 378 break; 379 case Release: 380 unlock( *lock ); 381 case Schedule: 382 ScheduleThread( thrd ); 383 case Release_Schedule: 384 unlock( *lock ); 385 ScheduleThread( thrd ); 386 case Release_Multi: 387 for(int i = 0; i < lock_count; i++) { 388 unlock( *locks[i] ); 389 } 390 case Release_Multi_Schedule: 391 for(int i = 0; i < lock_count; i++) { 392 unlock( *locks[i] ); 393 } 394 for(int i = 0; i < thrd_count; i++) { 395 ScheduleThread( thrds[i] ); 396 } 397 case Callback: 398 callback(); 399 default: 400 abort("KERNEL ERROR: Unexpected action to run after thread"); 401 } 420 402 } 421 403 … … 465 447 } // Abort 466 448 467 void * __create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) {449 void * create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) { 468 450 pthread_attr_t attr; 469 451 … … 493 475 } 494 476 477 static void start(processor * this) { 478 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this); 479 480 this->stack = create_pthread( &this->kernel_thread, CtxInvokeProcessor, (void *)this ); 481 482 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this); 483 } 484 495 485 // KERNEL_ONLY 496 static void __kernel_first_resume( processor * this ) {486 void kernel_first_resume( processor * this ) { 497 487 thread_desc * src = mainThread; 498 488 coroutine_desc * dst = get_coroutine(this->runner); … … 526 516 527 517 // KERNEL_ONLY 528 static void __kernel_last_resume( processor * this ) {518 void kernel_last_resume( processor * this ) { 529 519 coroutine_desc * src = &mainThread->self_cor; 530 520 coroutine_desc * dst = get_coroutine(this->runner); … … 540 530 //----------------------------------------------------------------------------- 541 531 // Scheduler routines 532 542 533 // KERNEL ONLY 543 void __schedule_thread( thread_desc * thrd ) with( *thrd->curr_cluster ) { 544 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 545 /* paranoid */ #if defined( __CFA_WITH_VERIFY__ ) 546 /* paranoid */ if( thrd->state == Inactive || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION, 547 "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted ); 548 /* paranoid */ if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active || thrd->state == Rerun, 549 "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted ); 550 /* paranoid */ #endif 551 /* paranoid */ verifyf( thrd->next == 0p, "Expected null got %p", thrd->next ); 552 553 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 554 bool was_empty = !(ready_queue != 0); 555 append( ready_queue, thrd ); 556 unlock( ready_queue_lock ); 557 558 if(was_empty) { 559 lock (proc_list_lock __cfaabi_dbg_ctx2); 560 if(idles) { 561 wake_fast(idles.head); 534 void ScheduleThread( thread_desc * thrd ) { 535 verify( thrd ); 536 verify( thrd->state != Halted ); 537 538 verify( ! kernelTLS.preemption_state.enabled ); 539 540 verifyf( thrd->next == 0p, "Expected null got %p", thrd->next ); 541 542 with( *thrd->curr_cluster ) { 543 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 544 bool was_empty = !(ready_queue != 0); 545 append( ready_queue, thrd ); 546 unlock( ready_queue_lock ); 547 548 if(was_empty) { 549 lock (proc_list_lock __cfaabi_dbg_ctx2); 550 if(idles) { 551 wake_fast(idles.head); 552 } 553 unlock (proc_list_lock); 562 554 } 563 unlock (proc_list_lock);564 }565 else if( struct processor * idle = idles.head ) {566 wake_fast(idle); 567 } 568 569 /* paranoid */verify( ! kernelTLS.preemption_state.enabled );555 else if( struct processor * idle = idles.head ) { 556 wake_fast(idle); 557 } 558 559 } 560 561 verify( ! kernelTLS.preemption_state.enabled ); 570 562 } 571 563 572 564 // KERNEL ONLY 573 static thread_desc * __next_thread(cluster * this) with( *this ) { 574 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 575 565 thread_desc * nextThread(cluster * this) with( *this ) { 566 verify( ! kernelTLS.preemption_state.enabled ); 576 567 lock( ready_queue_lock __cfaabi_dbg_ctx2 ); 577 568 thread_desc * head = pop_head( ready_queue ); 578 569 unlock( ready_queue_lock ); 579 580 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 570 verify( ! kernelTLS.preemption_state.enabled ); 581 571 return head; 582 572 } 583 573 584 void unpark( thread_desc * thrd ) { 585 if( !thrd ) return; 586 574 void BlockInternal() { 587 575 disable_interrupts(); 588 static_assert(sizeof(thrd->state) == sizeof(int)); 589 enum coroutine_state old_state = __atomic_exchange_n(&thrd->state, Rerun, __ATOMIC_SEQ_CST); 590 switch(old_state) { 591 case Active: 592 // Wake won the race, the thread will reschedule/rerun itself 593 break; 594 case Inactive: 595 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 596 597 // Wake lost the race, 598 thrd->state = Inactive; 599 __schedule_thread( thrd ); 600 break; 601 case Rerun: 602 abort("More than one thread attempted to schedule thread %p\n", thrd); 603 break; 604 case Halted: 605 case Start: 606 case Primed: 607 default: 608 // This makes no sense, something is wrong abort 609 abort(); 610 } 576 verify( ! kernelTLS.preemption_state.enabled ); 577 returnToKernel(); 578 verify( ! kernelTLS.preemption_state.enabled ); 611 579 enable_interrupts( __cfaabi_dbg_ctx ); 612 580 } 613 581 614 void park( void ) { 615 /* paranoid */ verify( kernelTLS.preemption_state.enabled ); 582 void BlockInternal( __spinlock_t * lock ) { 616 583 disable_interrupts(); 617 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 618 /* paranoid */ verify( kernelTLS.this_thread->preempted == __NO_PREEMPTION ); 619 584 with( *kernelTLS.this_processor ) { 585 finish.action_code = Release; 586 finish.lock = lock; 587 } 588 589 verify( ! kernelTLS.preemption_state.enabled ); 620 590 returnToKernel(); 621 622 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 591 verify( ! kernelTLS.preemption_state.enabled ); 592 623 593 enable_interrupts( __cfaabi_dbg_ctx ); 624 /* paranoid */ verify( kernelTLS.preemption_state.enabled ); 625 594 } 595 596 void BlockInternal( thread_desc * thrd ) { 597 disable_interrupts(); 598 with( * kernelTLS.this_processor ) { 599 finish.action_code = Schedule; 600 finish.thrd = thrd; 601 } 602 603 verify( ! kernelTLS.preemption_state.enabled ); 604 returnToKernel(); 605 verify( ! kernelTLS.preemption_state.enabled ); 606 607 enable_interrupts( __cfaabi_dbg_ctx ); 608 } 609 610 void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) { 611 assert(thrd); 612 disable_interrupts(); 613 with( * kernelTLS.this_processor ) { 614 finish.action_code = Release_Schedule; 615 finish.lock = lock; 616 finish.thrd = thrd; 617 } 618 619 verify( ! kernelTLS.preemption_state.enabled ); 620 returnToKernel(); 621 verify( ! kernelTLS.preemption_state.enabled ); 622 623 enable_interrupts( __cfaabi_dbg_ctx ); 624 } 625 626 void BlockInternal(__spinlock_t * locks [], unsigned short count) { 627 disable_interrupts(); 628 with( * kernelTLS.this_processor ) { 629 finish.action_code = Release_Multi; 630 finish.locks = locks; 631 finish.lock_count = count; 632 } 633 634 verify( ! kernelTLS.preemption_state.enabled ); 635 returnToKernel(); 636 verify( ! kernelTLS.preemption_state.enabled ); 637 638 enable_interrupts( __cfaabi_dbg_ctx ); 639 } 640 641 void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) { 642 disable_interrupts(); 643 with( *kernelTLS.this_processor ) { 644 finish.action_code = Release_Multi_Schedule; 645 finish.locks = locks; 646 finish.lock_count = lock_count; 647 finish.thrds = thrds; 648 finish.thrd_count = thrd_count; 649 } 650 651 verify( ! kernelTLS.preemption_state.enabled ); 652 returnToKernel(); 653 verify( ! kernelTLS.preemption_state.enabled ); 654 655 enable_interrupts( __cfaabi_dbg_ctx ); 656 } 657 658 void BlockInternal(__finish_callback_fptr_t callback) { 659 disable_interrupts(); 660 with( *kernelTLS.this_processor ) { 661 finish.action_code = Callback; 662 finish.callback = callback; 663 } 664 665 verify( ! kernelTLS.preemption_state.enabled ); 666 returnToKernel(); 667 verify( ! kernelTLS.preemption_state.enabled ); 668 669 enable_interrupts( __cfaabi_dbg_ctx ); 626 670 } 627 671 628 672 // KERNEL ONLY 629 void __leave_thread() { 630 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 673 void LeaveThread(__spinlock_t * lock, thread_desc * thrd) { 674 verify( ! kernelTLS.preemption_state.enabled ); 675 with( * kernelTLS.this_processor ) { 676 finish.action_code = thrd ? Release_Schedule : Release; 677 finish.lock = lock; 678 finish.thrd = thrd; 679 } 680 631 681 returnToKernel(); 632 abort();633 }634 635 // KERNEL ONLY636 bool force_yield( __Preemption_Reason reason ) {637 /* paranoid */ verify( kernelTLS.preemption_state.enabled );638 disable_interrupts();639 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );640 641 thread_desc * thrd = kernelTLS.this_thread;642 /* paranoid */ verify(thrd->state == Active || thrd->state == Rerun);643 644 // SKULLDUGGERY: It is possible that we are preempting this thread just before645 // it was going to park itself. If that is the case and it is already using the646 // intrusive fields then we can't use them to preempt the thread647 // If that is the case, abandon the preemption.648 bool preempted = false;649 if(thrd->next == 0p) {650 preempted = true;651 thrd->preempted = reason;652 returnToKernel();653 }654 655 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );656 enable_interrupts_noPoll();657 /* paranoid */ verify( kernelTLS.preemption_state.enabled );658 659 return preempted;660 682 } 661 683 … … 665 687 //----------------------------------------------------------------------------- 666 688 // Kernel boot procedures 667 static void __kernel_startup(void) {689 static void kernel_startup(void) { 668 690 verify( ! kernelTLS.preemption_state.enabled ); 669 691 __cfaabi_dbg_print_safe("Kernel : Starting\n"); … … 726 748 // Add the main thread to the ready queue 727 749 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 728 __schedule_thread(mainThread);750 ScheduleThread(mainThread); 729 751 730 752 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX 731 753 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 732 754 // mainThread is on the ready queue when this call is made. 733 __kernel_first_resume( kernelTLS.this_processor );755 kernel_first_resume( kernelTLS.this_processor ); 734 756 735 757 … … 743 765 } 744 766 745 static void __kernel_shutdown(void) {767 static void kernel_shutdown(void) { 746 768 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n"); 747 769 … … 754 776 // which is currently here 755 777 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 756 __kernel_last_resume( kernelTLS.this_processor );778 kernel_last_resume( kernelTLS.this_processor ); 757 779 mainThread->self_cor.state = Halted; 758 780 … … 780 802 // Kernel Quiescing 781 803 //============================================================================================= 782 static void __halt(processor * this) with( *this ) {804 static void halt(processor * this) with( *this ) { 783 805 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 784 806 … … 891 913 892 914 // atomically release spin lock and block 893 unlock( lock ); 894 park(); 915 BlockInternal( &lock ); 895 916 } 896 917 else { … … 911 932 912 933 // make new owner 913 unpark( thrd );934 WakeThread( thrd ); 914 935 } 915 936 … … 969 990 //----------------------------------------------------------------------------- 970 991 // Debug 971 bool threading_enabled(void) __attribute__((const)){992 bool threading_enabled(void) { 972 993 return true; 973 994 } -
libcfa/src/concurrency/kernel.hfa
ra505021 rc744563a 45 45 extern struct cluster * mainCluster; 46 46 47 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback }; 48 49 typedef void (*__finish_callback_fptr_t)(void); 50 51 //TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI) 52 struct FinishAction { 53 FinishOpCode action_code; 54 /* 55 // Union of possible actions 56 union { 57 // Option 1 : locks and threads 58 struct { 59 // 1 thread or N thread 60 union { 61 thread_desc * thrd; 62 struct { 63 thread_desc ** thrds; 64 unsigned short thrd_count; 65 }; 66 }; 67 // 1 lock or N lock 68 union { 69 __spinlock_t * lock; 70 struct { 71 __spinlock_t ** locks; 72 unsigned short lock_count; 73 }; 74 }; 75 }; 76 // Option 2 : action pointer 77 __finish_callback_fptr_t callback; 78 }; 79 /*/ 80 thread_desc * thrd; 81 thread_desc ** thrds; 82 unsigned short thrd_count; 83 __spinlock_t * lock; 84 __spinlock_t ** locks; 85 unsigned short lock_count; 86 __finish_callback_fptr_t callback; 87 //*/ 88 }; 89 static inline void ?{}(FinishAction & this) { 90 this.action_code = No_Action; 91 this.thrd = 0p; 92 this.lock = 0p; 93 } 94 static inline void ^?{}(FinishAction &) {} 95 47 96 // Processor 48 97 coroutine processorCtx_t { … … 67 116 // RunThread data 68 117 // Action to do after a thread is ran 69 thread_desc * destroyer;118 struct FinishAction finish; 70 119 71 120 // Preemption data … … 108 157 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster }; } 109 158 110 static inline [processor *&, processor *& ] __get( processor & this ) /*__attribute__((const))*/ { return this.node.[next, prev]; } 159 static inline [processor *&, processor *& ] __get( processor & this ) { 160 return this.node.[next, prev]; 161 } 111 162 112 163 //----------------------------------------------------------------------------- … … 151 202 static inline void ?{} (cluster & this, const char name[]) { this{name, default_preemption()}; } 152 203 153 static inline [cluster *&, cluster *& ] __get( cluster & this ) /*__attribute__((const))*/ { return this.node.[next, prev]; } 154 155 static inline struct processor * active_processor() __attribute__((const)) { return TL_GET( this_processor ); } // UNSAFE 156 static inline struct cluster * active_cluster () __attribute__((const)) { return TL_GET( this_processor )->cltr; } 204 static inline [cluster *&, cluster *& ] __get( cluster & this ) { 205 return this.node.[next, prev]; 206 } 207 208 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 209 static inline struct cluster * active_cluster () { return TL_GET( this_processor )->cltr; } 157 210 158 211 // Local Variables: // -
libcfa/src/concurrency/kernel_private.hfa
ra505021 rc744563a 31 31 } 32 32 33 void __schedule_thread( thread_desc * ) __attribute__((nonnull (1))); 33 void ScheduleThread( thread_desc * ); 34 static inline void WakeThread( thread_desc * thrd ) { 35 if( !thrd ) return; 36 37 verify(thrd->state == Inactive); 38 39 disable_interrupts(); 40 ScheduleThread( thrd ); 41 enable_interrupts( __cfaabi_dbg_ctx ); 42 } 43 thread_desc * nextThread(cluster * this); 34 44 35 45 //Block current thread and release/wake-up the following resources 36 void __leave_thread() __attribute__((noreturn)); 46 void BlockInternal(void); 47 void BlockInternal(__spinlock_t * lock); 48 void BlockInternal(thread_desc * thrd); 49 void BlockInternal(__spinlock_t * lock, thread_desc * thrd); 50 void BlockInternal(__spinlock_t * locks [], unsigned short count); 51 void BlockInternal(__spinlock_t * locks [], unsigned short count, thread_desc * thrds [], unsigned short thrd_count); 52 void BlockInternal(__finish_callback_fptr_t callback); 53 void LeaveThread(__spinlock_t * lock, thread_desc * thrd); 37 54 38 55 //----------------------------------------------------------------------------- … … 40 57 void main(processorCtx_t *); 41 58 42 void * __create_pthread( pthread_t *, void * (*)(void *), void * );59 void * create_pthread( pthread_t *, void * (*)(void *), void * ); 43 60 44 61 static inline void wake_fast(processor * this) { … … 85 102 #define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)] 86 103 87 static inline uint32_t __tls_rand() {104 static inline uint32_t tls_rand() { 88 105 kernelTLS.rand_seed ^= kernelTLS.rand_seed << 6; 89 106 kernelTLS.rand_seed ^= kernelTLS.rand_seed >> 21; -
libcfa/src/concurrency/monitor.cfa
ra505021 rc744563a 117 117 118 118 // Some one else has the monitor, wait in line for it 119 /* paranoid */ verify( thrd->next == 0p );120 119 append( this->entry_queue, thrd ); 121 /* paranoid */ verify( thrd->next == 1p ); 122 123 unlock( this->lock ); 124 park(); 120 121 BlockInternal( &this->lock ); 125 122 126 123 __cfaabi_dbg_print_safe( "Kernel : %10p Entered mon %p\n", thrd, this); 127 124 128 / * paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );125 // BlockInternal will unlock spinlock, no need to unlock ourselves 129 126 return; 130 127 } 131 128 132 129 __cfaabi_dbg_print_safe( "Kernel : %10p Entered mon %p\n", thrd, this); 133 134 /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );135 /* paranoid */ verify( this->lock.lock );136 130 137 131 // Release the lock and leave … … 155 149 set_owner( this, thrd ); 156 150 157 verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );158 159 151 unlock( this->lock ); 160 152 return; … … 174 166 // Wake the thread that is waiting for this 175 167 __condition_criterion_t * urgent = pop( this->signal_stack ); 176 /* paranoid */verify( urgent );168 verify( urgent ); 177 169 178 170 // Reset mask … … 183 175 184 176 // Some one else has the monitor, wait for him to finish and then run 185 unlock( this->lock ); 186 187 // Release the next thread 188 /* paranoid */ verifyf( urgent->owner->waiting_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this ); 189 unpark( urgent->owner->waiting_thread ); 190 191 // Park current thread waiting 192 park(); 177 BlockInternal( &this->lock, urgent->owner->waiting_thread ); 193 178 194 179 // Some one was waiting for us, enter 195 /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this);180 set_owner( this, thrd ); 196 181 } 197 182 else { … … 202 187 203 188 // Some one else has the monitor, wait in line for it 204 /* paranoid */ verify( thrd->next == 0p );205 189 append( this->entry_queue, thrd ); 206 /* paranoid */ verify( thrd->next == 1p ); 207 unlock( this->lock ); 208 209 // Park current thread waiting 210 park(); 211 212 /* paranoid */ verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this ); 190 BlockInternal( &this->lock ); 191 192 // BlockInternal will unlock spinlock, no need to unlock ourselves 213 193 return; 214 194 } … … 225 205 __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", kernelTLS.this_thread, this, this->owner); 226 206 227 /* paranoid */verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );207 verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this ); 228 208 229 209 // Leaving a recursion level, decrement the counter … … 241 221 thread_desc * new_owner = next_thread( this ); 242 222 243 // Check the new owner is consistent with who we wake-up244 // new_owner might be null even if someone owns the monitor when the owner is still waiting for another monitor245 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this );246 247 223 // We can now let other threads in safely 248 224 unlock( this->lock ); 249 225 250 226 //We need to wake-up the thread 251 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 252 unpark( new_owner ); 227 WakeThread( new_owner ); 253 228 } 254 229 … … 277 252 disable_interrupts(); 278 253 279 thrd->s tate = Halted;280 281 /* paranoid */verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this );254 thrd->self_cor.state = Halted; 255 256 verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 282 257 283 258 // Leaving a recursion level, decrement the counter … … 291 266 thread_desc * new_owner = next_thread( this ); 292 267 293 // Release the monitor lock 294 unlock( this->lock ); 295 296 // Unpark the next owner if needed 297 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 298 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 299 /* paranoid */ verify( ! kernelTLS.this_processor->destroyer ); 300 /* paranoid */ verify( thrd->state == Halted ); 301 302 kernelTLS.this_processor->destroyer = new_owner; 303 304 // Leave the thread 305 __leave_thread(); 268 // Leave the thread, this will unlock the spinlock 269 // Use leave thread instead of BlockInternal which is 270 // specialized for this case and supports null new_owner 271 LeaveThread( &this->lock, new_owner ); 306 272 307 273 // Control flow should never reach here! … … 434 400 // Append the current wait operation to the ones already queued on the condition 435 401 // We don't need locks for that since conditions must always be waited on inside monitor mutual exclusion 436 /* paranoid */ verify( waiter.next == 0p );437 402 append( this.blocked, &waiter ); 438 /* paranoid */ verify( waiter.next == 1p );439 403 440 404 // Lock all monitors (aggregates the locks as well) … … 455 419 } 456 420 457 // Unlock the locks, we don't need them anymore458 for(int i = 0; i < count; i++) {459 unlock( *locks[i] );460 }461 462 // Wake the threads463 for(int i = 0; i < thread_count; i++) {464 unpark( threads[i] );465 }466 467 421 // Everything is ready to go to sleep 468 park();422 BlockInternal( locks, count, threads, thread_count ); 469 423 470 424 // We are back, restore the owners and recursions … … 536 490 //Find the thread to run 537 491 thread_desc * signallee = pop_head( this.blocked )->waiting_thread; 538 /* paranoid */ verify( signallee->next == 0p );539 492 set_owner( monitors, count, signallee ); 540 493 541 494 __cfaabi_dbg_print_buffer_decl( "Kernel : signal_block condition %p (s: %p)\n", &this, signallee ); 542 495 543 // unlock all the monitors544 unlock_all( locks, count );545 546 // unpark the thread we signalled547 unpark( signallee );548 549 496 //Everything is ready to go to sleep 550 park();497 BlockInternal( locks, count, &signallee, 1 ); 551 498 552 499 … … 645 592 set_owner( monitors, count, next ); 646 593 647 // unlock all the monitors 648 unlock_all( locks, count ); 649 650 // unpark the thread we signalled 651 unpark( next ); 652 653 //Everything is ready to go to sleep 654 park(); 594 // Everything is ready to go to sleep 595 BlockInternal( locks, count, &next, 1 ); 655 596 656 597 // We are back, restore the owners and recursions … … 690 631 } 691 632 692 // unlock all the monitors693 unlock_all( locks, count );694 695 633 //Everything is ready to go to sleep 696 park();634 BlockInternal( locks, count ); 697 635 698 636 … … 712 650 713 651 static inline void set_owner( monitor_desc * this, thread_desc * owner ) { 714 / * paranoid */ verify( this->lock.lock);652 // __cfaabi_dbg_print_safe( "Kernal : Setting owner of %p to %p ( was %p)\n", this, owner, this->owner ); 715 653 716 654 //Pass the monitor appropriately … … 722 660 723 661 static inline void set_owner( monitor_desc * monitors [], __lock_size_t count, thread_desc * owner ) { 724 /* paranoid */ verify ( monitors[0]->lock.lock ); 725 /* paranoid */ verifyf( monitors[0]->owner == kernelTLS.this_thread, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, monitors[0]->owner, monitors[0]->recursion, monitors[0] ); 726 monitors[0]->owner = owner; 727 monitors[0]->recursion = 1; 662 monitors[0]->owner = owner; 663 monitors[0]->recursion = 1; 728 664 for( __lock_size_t i = 1; i < count; i++ ) { 729 /* paranoid */ verify ( monitors[i]->lock.lock ); 730 /* paranoid */ verifyf( monitors[i]->owner == kernelTLS.this_thread, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, monitors[i]->owner, monitors[i]->recursion, monitors[i] ); 731 monitors[i]->owner = owner; 732 monitors[i]->recursion = 0; 665 monitors[i]->owner = owner; 666 monitors[i]->recursion = 0; 733 667 } 734 668 } … … 754 688 //regardless of if we are ready to baton pass, 755 689 //we need to set the monitor as in use 756 /* paranoid */ verifyf( !this->owner || kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );757 690 set_owner( this, urgent->owner->waiting_thread ); 758 691 … … 763 696 // Get the next thread in the entry_queue 764 697 thread_desc * new_owner = pop_head( this->entry_queue ); 765 /* paranoid */ verifyf( !this->owner || kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );766 /* paranoid */ verify( !new_owner || new_owner->next == 0p );767 698 set_owner( this, new_owner ); 768 699 … … 910 841 // For each thread in the entry-queue 911 842 for( thread_desc ** thrd_it = &entry_queue.head; 912 *thrd_it != 1p;843 *thrd_it; 913 844 thrd_it = &(*thrd_it)->next 914 845 ) { -
libcfa/src/concurrency/monitor.hfa
ra505021 rc744563a 133 133 bool signal ( condition & this ); 134 134 bool signal_block( condition & this ); 135 static inline bool is_empty ( condition & this ) { return this.blocked.head == 1p; }135 static inline bool is_empty ( condition & this ) { return !this.blocked.head; } 136 136 uintptr_t front ( condition & this ); 137 137 -
libcfa/src/concurrency/mutex.cfa
ra505021 rc744563a 40 40 if( is_locked ) { 41 41 append( blocked_threads, kernelTLS.this_thread ); 42 unlock( lock ); 43 park(); 42 BlockInternal( &lock ); 44 43 } 45 44 else { … … 63 62 lock( this.lock __cfaabi_dbg_ctx2 ); 64 63 this.is_locked = (this.blocked_threads != 0); 65 unpark(64 WakeThread( 66 65 pop_head( this.blocked_threads ) 67 66 ); … … 95 94 else { 96 95 append( blocked_threads, kernelTLS.this_thread ); 97 unlock( lock ); 98 park(); 96 BlockInternal( &lock ); 99 97 } 100 98 } … … 123 121 owner = thrd; 124 122 recursion_count = (thrd ? 1 : 0); 125 unpark( thrd );123 WakeThread( thrd ); 126 124 } 127 125 unlock( lock ); … … 140 138 void notify_one(condition_variable & this) with(this) { 141 139 lock( lock __cfaabi_dbg_ctx2 ); 142 unpark(140 WakeThread( 143 141 pop_head( this.blocked_threads ) 144 142 ); … … 149 147 lock( lock __cfaabi_dbg_ctx2 ); 150 148 while(this.blocked_threads) { 151 unpark(149 WakeThread( 152 150 pop_head( this.blocked_threads ) 153 151 ); … … 159 157 lock( this.lock __cfaabi_dbg_ctx2 ); 160 158 append( this.blocked_threads, kernelTLS.this_thread ); 161 unlock( this.lock ); 162 park(); 159 BlockInternal( &this.lock ); 163 160 } 164 161 … … 167 164 lock( this.lock __cfaabi_dbg_ctx2 ); 168 165 append( this.blocked_threads, kernelTLS.this_thread ); 169 unlock(l); 170 unlock(this.lock); 171 park(); 166 void __unlock(void) { 167 unlock(l); 168 unlock(this.lock); 169 } 170 BlockInternal( __unlock ); 172 171 lock(l); 173 172 } -
libcfa/src/concurrency/preemption.cfa
ra505021 rc744563a 187 187 void enable_interrupts( __cfaabi_dbg_ctx_param ) { 188 188 processor * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store 189 thread_desc * thrd = kernelTLS.this_thread; // Cache the thread now since interrupts can start happening after the atomic store 189 190 190 191 with( kernelTLS.preemption_state ){ … … 208 209 if( proc->pending_preemption ) { 209 210 proc->pending_preemption = false; 210 force_yield( __POLL_PREEMPTION);211 BlockInternal( thrd ); 211 212 } 212 213 } … … 306 307 signal_block( SIGALRM ); 307 308 308 alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p );309 alarm_stack = create_pthread( &alarm_thread, alarm_loop, 0p ); 309 310 } 310 311 … … 393 394 // Preemption can occur here 394 395 395 force_yield( __ALARM_PREEMPTION); // Do the actual CtxSwitch396 BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch 396 397 } 397 398 -
libcfa/src/concurrency/thread.cfa
ra505021 rc744563a 23 23 #include "invoke.h" 24 24 25 extern "C" { 26 #include <fenv.h> 27 #include <stddef.h> 28 } 29 30 //extern volatile thread_local processor * this_processor; 31 25 32 //----------------------------------------------------------------------------- 26 33 // Thread ctors and dtors … … 29 36 self_cor{ name, storage, storageSize }; 30 37 state = Start; 31 preempted = __NO_PREEMPTION;32 38 curr_cor = &self_cor; 33 39 self_mon.owner = &this; … … 49 55 } 50 56 51 //-----------------------------------------------------------------------------52 // Starting and stopping threads53 forall( dtype T | is_thread(T) )54 void __thrd_start( T & this, void (*main_p)(T &) ) {55 thread_desc * this_thrd = get_thread(this);56 57 disable_interrupts();58 CtxStart(main_p, get_coroutine(this), this, CtxInvokeThread);59 60 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];61 verify( this_thrd->context.SP );62 63 __schedule_thread(this_thrd);64 enable_interrupts( __cfaabi_dbg_ctx );65 }66 67 //-----------------------------------------------------------------------------68 // Support for threads that don't ues the thread keyword69 57 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } ) 70 58 void ?{}( scoped(T)& this ) with( this ) { … … 84 72 } 85 73 74 //----------------------------------------------------------------------------- 75 // Starting and stopping threads 76 forall( dtype T | is_thread(T) ) 77 void __thrd_start( T & this, void (*main_p)(T &) ) { 78 thread_desc * this_thrd = get_thread(this); 79 80 disable_interrupts(); 81 CtxStart(main_p, get_coroutine(this), this, CtxInvokeThread); 82 83 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 84 verify( this_thrd->context.SP ); 85 86 ScheduleThread(this_thrd); 87 enable_interrupts( __cfaabi_dbg_ctx ); 88 } 89 90 void yield( void ) { 91 // Safety note : This could cause some false positives due to preemption 92 verify( TL_GET( preemption_state.enabled ) ); 93 BlockInternal( TL_GET( this_thread ) ); 94 // Safety note : This could cause some false positives due to preemption 95 verify( TL_GET( preemption_state.enabled ) ); 96 } 97 98 void yield( unsigned times ) { 99 for( unsigned i = 0; i < times; i++ ) { 100 yield(); 101 } 102 } 103 86 104 // Local Variables: // 87 105 // mode: c // -
libcfa/src/concurrency/thread.hfa
ra505021 rc744563a 31 31 }; 32 32 33 // define that satisfies the trait without using the thread keyword 34 #define DECL_THREAD(X) thread_desc* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this) 35 36 // Inline getters for threads/coroutines/monitors 37 forall( dtype T | is_thread(T) ) 38 static inline coroutine_desc* get_coroutine(T & this) __attribute__((const)) { return &get_thread(this)->self_cor; } 33 #define DECL_THREAD(X) thread_desc* get_thread(X& this) { return &this.__thrd; } void main(X& this) 39 34 40 35 forall( dtype T | is_thread(T) ) 41 static inline monitor_desc * get_monitor (T & this) __attribute__((const)) { return &get_thread(this)->self_mon; } 36 static inline coroutine_desc* get_coroutine(T & this) { 37 return &get_thread(this)->self_cor; 38 } 42 39 43 static inline coroutine_desc* get_coroutine(thread_desc * this) __attribute__((const)) { return &this->self_cor; } 44 static inline monitor_desc * get_monitor (thread_desc * this) __attribute__((const)) { return &this->self_mon; } 40 forall( dtype T | is_thread(T) ) 41 static inline monitor_desc* get_monitor(T & this) { 42 return &get_thread(this)->self_mon; 43 } 45 44 46 //----------------------------------------------------------------------------- 47 // forward declarations needed for threads 45 static inline coroutine_desc* get_coroutine(thread_desc * this) { 46 return &this->self_cor; 47 } 48 49 static inline monitor_desc* get_monitor(thread_desc * this) { 50 return &this->self_mon; 51 } 52 48 53 extern struct cluster * mainCluster; 49 54 … … 83 88 void ^?{}( scoped(T)& this ); 84 89 85 //----------------------------------------------------------------------------- 86 // Thread getters 90 void yield(); 91 void yield( unsigned times ); 92 87 93 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); } 88 89 //-----------------------------------------------------------------------------90 // Scheduler API91 92 //----------93 // Park thread: block until corresponding call to unpark, won't block if unpark is already called94 void park( void );95 96 //----------97 // Unpark a thread, if the thread is already blocked, schedule it98 // if the thread is not yet block, signal that it should rerun immediately99 void unpark( thread_desc * this );100 101 forall( dtype T | is_thread(T) )102 static inline void unpark( T & this ) { if(!&this) return; unpark( get_thread( this ) );}103 104 //----------105 // Yield: force thread to block and be rescheduled106 bool force_yield( enum __Preemption_Reason );107 108 static inline void yield() {109 force_yield(__MANUAL_PREEMPTION);110 }111 112 // Yield: yield N times113 static inline void yield( unsigned times ) {114 for( times ) {115 yield();116 }117 }118 94 119 95 // Local Variables: // -
tests/concurrent/examples/.expect/datingService.txt
ra505021 rc744563a 1 Girl:17 is dating Boy at 2 with ccode 17 2 Boy:2 is dating Girl 17 with ccode 17 3 Boy:14 is dating Girl 5 with ccode 5 4 Girl:5 is dating Boy at 14 with ccode 5 5 Boy:9 is dating Girl 10 with ccode 10 6 Girl:10 is dating Boy at 9 with ccode 10 7 Boy:1 is dating Girl 18 with ccode 18 8 Girl:18 is dating Boy at 1 with ccode 18 9 Boy:16 is dating Girl 3 with ccode 3 10 Girl:3 is dating Boy at 16 with ccode 3 11 Boy:5 is dating Girl 14 with ccode 14 12 Girl:14 is dating Boy at 5 with ccode 14 13 Boy:15 is dating Girl 4 with ccode 4 14 Girl:4 is dating Boy at 15 with ccode 4 15 Girl:0 is dating Boy at 19 with ccode 0 16 Boy:19 is dating Girl 0 with ccode 0 17 Girl:9 is dating Boy at 10 with ccode 9 18 Boy:10 is dating Girl 9 with ccode 9 19 Girl:11 is dating Boy at 8 with ccode 11 20 Boy:8 is dating Girl 11 with ccode 11 21 Boy:12 is dating Girl 7 with ccode 7 22 Girl:7 is dating Boy at 12 with ccode 7 23 Boy:11 is dating Girl 8 with ccode 8 24 Girl:8 is dating Boy at 11 with ccode 8 25 Girl:16 is dating Boy at 3 with ccode 16 26 Boy:3 is dating Girl 16 with ccode 16 27 Girl:15 is dating Boy at 4 with ccode 15 28 Boy:4 is dating Girl 15 with ccode 15 29 Girl:19 is dating Boy at 0 with ccode 19 30 Boy:0 is dating Girl 19 with ccode 19 31 Girl:2 is dating Boy at 17 with ccode 2 32 Boy:17 is dating Girl 2 with ccode 2 33 Boy:13 is dating Girl 6 with ccode 6 34 Girl:6 is dating Boy at 13 with ccode 6 35 Boy:7 is dating Girl 12 with ccode 12 36 Girl:12 is dating Boy at 7 with ccode 12 37 Girl:13 is dating Boy at 6 with ccode 13 38 Boy:6 is dating Girl 13 with ccode 13 39 Girl:1 is dating Boy at 18 with ccode 1 40 Boy:18 is dating Girl 1 with ccode 1 -
tests/concurrent/examples/datingService.cfa
ra505021 rc744563a 1 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 3 // 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. … … 35 35 signal_block( Boys[ccode] ); // restart boy to set phone number 36 36 } // if 37 //sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;37 sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode; 38 38 return BoyPhoneNo; 39 39 } // DatingService girl … … 47 47 signal_block( Girls[ccode] ); // restart girl to set phone number 48 48 } // if 49 //sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;49 sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode; 50 50 return GirlPhoneNo; 51 51 } // DatingService boy -
tests/concurrent/multi-monitor.cfa
ra505021 rc744563a 11 11 12 12 void increment( monitor_t & mutex p1, monitor_t & mutex p2, int & value ) { 13 assert(active_thread() == get_monitor(p1)->owner);14 assert(active_thread() == get_monitor(p2)->owner);15 13 value += 1; 16 assert(active_thread() == get_monitor(p1)->owner);17 assert(active_thread() == get_monitor(p2)->owner);18 14 } 19 15
Note:
See TracChangeset
for help on using the changeset viewer.