Changeset 1eb239e4 for libcfa/src/concurrency/kernel.cfa
- Timestamp:
- Aug 10, 2020, 2:43:02 PM (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:
- 8465b4d
- Parents:
- 6c144d8
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
r6c144d8 r1eb239e4 86 86 // Kernel Scheduling logic 87 87 static $thread * __next_thread(cluster * this); 88 static bool __has_next_thread(cluster * this);88 static $thread * __next_thread_slow(cluster * this); 89 89 static void __run_thread(processor * this, $thread * dst); 90 static bool __wake_one(struct __processor_id_t * id, cluster * cltr); 91 static void __halt(processor * this); 92 bool __wake_proc(processor *); 90 static void __wake_one(struct __processor_id_t * id, cluster * cltr); 91 92 static void push (__cluster_idles & idles, processor & proc); 93 static void remove(__cluster_idles & idles, processor & proc); 94 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles ); 95 93 96 94 97 //============================================================================================= … … 118 121 119 122 $thread * readyThread = 0p; 120 for( unsigned int spin_count = 0;; spin_count++ ) { 123 MAIN_LOOP: 124 for() { 121 125 // Try to get the next thread 122 126 readyThread = __next_thread( this->cltr ); 123 127 124 // Check if we actually found a thread 125 if( readyThread ) { 126 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 127 /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted); 128 /* paranoid */ verifyf( readyThread->link.next == 0p, "Expected null got %p", readyThread->link.next ); 129 __builtin_prefetch( readyThread->context.SP ); 130 131 // We found a thread run it 132 __run_thread(this, readyThread); 133 134 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 128 if( !readyThread ) { 129 readyThread = __next_thread_slow( this->cltr ); 135 130 } 136 131 137 if(__atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST)) break; 138 132 HALT: 139 133 if( !readyThread ) { 140 // Block until a thread is ready 141 __halt(this); 134 // Don't block if we are done 135 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 136 137 #if !defined(__CFA_NO_STATISTICS__) 138 __tls_stats()->ready.sleep.halts++; 139 #endif 140 141 // Push self to idle stack 142 push(this->cltr->idles, * this); 143 144 // Confirm the ready-queue is empty 145 readyThread = __next_thread_slow( this->cltr ); 146 if( readyThread ) { 147 // A thread was found, cancel the halt 148 remove(this->cltr->idles, * this); 149 150 #if !defined(__CFA_NO_STATISTICS__) 151 __tls_stats()->ready.sleep.cancels++; 152 #endif 153 154 // continue the mai loop 155 break HALT; 156 } 157 158 #if !defined(__CFA_NO_STATISTICS__) 159 if(this->print_halts) { 160 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); 161 } 162 #endif 163 164 wait( this->idle ); 165 166 #if !defined(__CFA_NO_STATISTICS__) 167 if(this->print_halts) { 168 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); 169 } 170 #endif 171 172 // We were woken up, remove self from idle 173 remove(this->cltr->idles, * this); 174 175 // DON'T just proceed, start looking again 176 continue MAIN_LOOP; 142 177 } 178 179 /* paranoid */ verify( readyThread ); 180 181 // We found a thread run it 182 __run_thread(this, readyThread); 183 184 // Are we done? 185 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 143 186 } 144 187 … … 165 208 // from the processor coroutine to the target thread 166 209 static void __run_thread(processor * this, $thread * thrd_dst) { 210 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 211 /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted); 212 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 213 __builtin_prefetch( thrd_dst->context.SP ); 214 167 215 $coroutine * proc_cor = get_coroutine(this->runner); 168 216 … … 244 292 proc_cor->state = Active; 245 293 kernelTLS.this_thread = 0p; 294 295 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 246 296 } 247 297 … … 300 350 ready_schedule_lock ( id ); 301 351 push( thrd->curr_cluster, thrd ); 302 303 #if !defined(__CFA_NO_STATISTICS__) 304 bool woke = 305 #endif 306 __wake_one(id, thrd->curr_cluster); 307 308 #if !defined(__CFA_NO_STATISTICS__) 309 if(woke) __tls_stats()->ready.sleep.wakes++; 310 #endif 352 __wake_one(id, thrd->curr_cluster); 311 353 ready_schedule_unlock( id ); 312 354 … … 315 357 316 358 // KERNEL ONLY 317 static $thread * __next_thread(cluster * this) with( *this ) {359 static inline $thread * __next_thread(cluster * this) with( *this ) { 318 360 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 319 361 320 362 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 321 $thread * head = pop( this );363 $thread * thrd = pop( this ); 322 364 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 323 365 324 366 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 325 return head;367 return thrd; 326 368 } 327 369 328 370 // KERNEL ONLY 329 static bool __has_next_thread(cluster * this) with( *this ) {371 static inline $thread * __next_thread_slow(cluster * this) with( *this ) { 330 372 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 331 373 332 374 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 333 bool not_empty = query( this );375 $thread * thrd = pop_slow( this ); 334 376 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 335 377 336 378 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 337 return not_empty;379 return thrd; 338 380 } 339 381 … … 425 467 //============================================================================================= 426 468 // Wake a thread from the front if there are any 427 static bool __wake_one(struct __processor_id_t * id, cluster * this) { 469 static void __wake_one(struct __processor_id_t * id, cluster * this) { 470 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 428 471 /* paranoid */ verify( ready_schedule_islocked( id ) ); 429 472 430 473 // Check if there is a sleeping processor 431 processor * p = pop(this->idles); 474 processor * p; 475 unsigned idle; 476 unsigned total; 477 [idle, total, p] = query(this->idles); 432 478 433 479 // If no one is sleeping, we are done 434 if( 0p == p ) return false;480 if( idle == 0 ) return; 435 481 436 482 // We found a processor, wake it up 437 483 post( p->idle ); 438 484 439 return true; 485 #if !defined(__CFA_NO_STATISTICS__) 486 __tls_stats()->ready.sleep.wakes++; 487 #endif 488 489 /* paranoid */ verify( ready_schedule_islocked( id ) ); 490 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 491 492 return; 440 493 } 441 494 442 495 // Unconditionnaly wake a thread 443 bool__wake_proc(processor * this) {496 void __wake_proc(processor * this) { 444 497 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 445 498 … … 448 501 bool ret = post( this->idle ); 449 502 enable_interrupts( __cfaabi_dbg_ctx ); 450 451 return ret; 452 } 453 454 static void __halt(processor * this) with( *this ) { 455 if( do_terminate ) return; 456 457 #if !defined(__CFA_NO_STATISTICS__) 458 __tls_stats()->ready.sleep.halts++; 459 #endif 460 // Push self to queue 461 push(cltr->idles, *this); 462 463 // Makre sure we don't miss a thread 464 if( __has_next_thread(cltr) ) { 465 // A thread was posted, make sure a processor is woken up 466 struct __processor_id_t *id = (struct __processor_id_t *) this; 467 ready_schedule_lock ( id ); 468 __wake_one( id, cltr ); 469 ready_schedule_unlock( id ); 470 #if !defined(__CFA_NO_STATISTICS__) 471 __tls_stats()->ready.sleep.cancels++; 472 #endif 473 } 474 475 #if !defined(__CFA_NO_STATISTICS__) 476 if(this->print_halts) { 477 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); 478 } 479 #endif 480 481 wait( idle ); 482 483 #if !defined(__CFA_NO_STATISTICS__) 484 if(this->print_halts) { 485 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); 486 } 487 #endif 503 } 504 505 static void push (__cluster_idles & this, processor & proc) { 506 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 507 lock( this ); 508 this.idle++; 509 /* paranoid */ verify( this.idle <= this.total ); 510 511 insert_first(this.list, proc); 512 unlock( this ); 513 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 514 } 515 516 static void remove(__cluster_idles & this, processor & proc) { 517 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 518 lock( this ); 519 this.idle--; 520 /* paranoid */ verify( this.idle >= 0 ); 521 522 remove(proc); 523 unlock( this ); 524 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 525 } 526 527 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) { 528 for() { 529 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST); 530 if( 1 == (l % 2) ) { Pause(); continue; } 531 unsigned idle = this.idle; 532 unsigned total = this.total; 533 processor * proc = &this.list`first; 534 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; } 535 return [idle, total, proc]; 536 } 488 537 } 489 538
Note: See TracChangeset
for help on using the changeset viewer.