- File:
-
- 1 edited
-
libcfa/src/concurrency/kernel.cfa (modified) (25 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
r8c50aed re3fea42 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Jan 30 22:55:50202013 // Update Count : 5 612 // Last Modified On : Tue Feb 4 13:03:15 2020 13 // Update Count : 58 14 14 // 15 15 … … 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 212 void ?{}(processor & this, const char * name, cluster & cltr) with( this ) { 210 static void start(processor * this); 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 … … 244 238 } 245 239 246 void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {240 void ?{}(cluster & this, const char name[], Duration preemption_rate) with( this ) { 247 241 this.name = name; 248 242 this.preemption_rate = preemption_rate; … … 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 … … 459 441 } 460 442 461 static void Abort( int ret, const char * func) {443 static void Abort( int ret, const char func[] ) { 462 444 if ( ret ) { // pthread routines return errno values 463 445 abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) ); … … 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 … … 487 469 ); 488 470 489 Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" ); 471 Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" ); 490 472 491 473 Abort( pthread_create( pthread, &attr, start, arg ), "pthread_create" ); … … 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); … … 500 490 verify( ! kernelTLS.preemption_state.enabled ); 501 491 502 kernelTLS.this_thread->curr_cor = dst;503 492 __stack_prepare( &dst->stack, 65000 ); 504 CtxStart( main, dst,this->runner, CtxInvokeCoroutine);493 CtxStart(&this->runner, CtxInvokeCoroutine); 505 494 506 495 verify( ! kernelTLS.preemption_state.enabled ); … … 517 506 // when CtxSwitch returns we are back in the src coroutine 518 507 519 mainThread->curr_cor = &mainThread->self_cor;520 521 508 // set state of new coroutine to active 522 509 src->state = Active; … … 526 513 527 514 // KERNEL_ONLY 528 static void __kernel_last_resume( processor * this ) {515 void kernel_last_resume( processor * this ) { 529 516 coroutine_desc * src = &mainThread->self_cor; 530 517 coroutine_desc * dst = get_coroutine(this->runner); … … 540 527 //----------------------------------------------------------------------------- 541 528 // Scheduler routines 529 542 530 // 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); 531 void ScheduleThread( thread_desc * thrd ) { 532 verify( thrd ); 533 verify( thrd->state != Halted ); 534 535 verify( ! kernelTLS.preemption_state.enabled ); 536 537 verifyf( thrd->next == 0p, "Expected null got %p", thrd->next ); 538 539 with( *thrd->curr_cluster ) { 540 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 541 bool was_empty = !(ready_queue != 0); 542 append( ready_queue, thrd ); 543 unlock( ready_queue_lock ); 544 545 if(was_empty) { 546 lock (proc_list_lock __cfaabi_dbg_ctx2); 547 if(idles) { 548 wake_fast(idles.head); 549 } 550 unlock (proc_list_lock); 562 551 } 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 );552 else if( struct processor * idle = idles.head ) { 553 wake_fast(idle); 554 } 555 556 } 557 558 verify( ! kernelTLS.preemption_state.enabled ); 570 559 } 571 560 572 561 // KERNEL ONLY 573 static thread_desc * __next_thread(cluster * this) with( *this ) { 574 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 575 562 thread_desc * nextThread(cluster * this) with( *this ) { 563 verify( ! kernelTLS.preemption_state.enabled ); 576 564 lock( ready_queue_lock __cfaabi_dbg_ctx2 ); 577 565 thread_desc * head = pop_head( ready_queue ); 578 566 unlock( ready_queue_lock ); 579 580 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 567 verify( ! kernelTLS.preemption_state.enabled ); 581 568 return head; 582 569 } 583 570 584 void unpark( thread_desc * thrd ) { 585 if( !thrd ) return; 586 571 void BlockInternal() { 587 572 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 } 573 verify( ! kernelTLS.preemption_state.enabled ); 574 returnToKernel(); 575 verify( ! kernelTLS.preemption_state.enabled ); 611 576 enable_interrupts( __cfaabi_dbg_ctx ); 612 577 } 613 578 614 void park( void ) { 615 /* paranoid */ verify( kernelTLS.preemption_state.enabled ); 579 void BlockInternal( __spinlock_t * lock ) { 616 580 disable_interrupts(); 617 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 618 /* paranoid */ verify( kernelTLS.this_thread->preempted == __NO_PREEMPTION ); 619 581 with( *kernelTLS.this_processor ) { 582 finish.action_code = Release; 583 finish.lock = lock; 584 } 585 586 verify( ! kernelTLS.preemption_state.enabled ); 620 587 returnToKernel(); 621 622 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 588 verify( ! kernelTLS.preemption_state.enabled ); 589 623 590 enable_interrupts( __cfaabi_dbg_ctx ); 624 /* paranoid */ verify( kernelTLS.preemption_state.enabled ); 625 591 } 592 593 void BlockInternal( thread_desc * thrd ) { 594 disable_interrupts(); 595 with( * kernelTLS.this_processor ) { 596 finish.action_code = Schedule; 597 finish.thrd = thrd; 598 } 599 600 verify( ! kernelTLS.preemption_state.enabled ); 601 returnToKernel(); 602 verify( ! kernelTLS.preemption_state.enabled ); 603 604 enable_interrupts( __cfaabi_dbg_ctx ); 605 } 606 607 void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) { 608 assert(thrd); 609 disable_interrupts(); 610 with( * kernelTLS.this_processor ) { 611 finish.action_code = Release_Schedule; 612 finish.lock = lock; 613 finish.thrd = thrd; 614 } 615 616 verify( ! kernelTLS.preemption_state.enabled ); 617 returnToKernel(); 618 verify( ! kernelTLS.preemption_state.enabled ); 619 620 enable_interrupts( __cfaabi_dbg_ctx ); 621 } 622 623 void BlockInternal(__spinlock_t * locks [], unsigned short count) { 624 disable_interrupts(); 625 with( * kernelTLS.this_processor ) { 626 finish.action_code = Release_Multi; 627 finish.locks = locks; 628 finish.lock_count = count; 629 } 630 631 verify( ! kernelTLS.preemption_state.enabled ); 632 returnToKernel(); 633 verify( ! kernelTLS.preemption_state.enabled ); 634 635 enable_interrupts( __cfaabi_dbg_ctx ); 636 } 637 638 void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) { 639 disable_interrupts(); 640 with( *kernelTLS.this_processor ) { 641 finish.action_code = Release_Multi_Schedule; 642 finish.locks = locks; 643 finish.lock_count = lock_count; 644 finish.thrds = thrds; 645 finish.thrd_count = thrd_count; 646 } 647 648 verify( ! kernelTLS.preemption_state.enabled ); 649 returnToKernel(); 650 verify( ! kernelTLS.preemption_state.enabled ); 651 652 enable_interrupts( __cfaabi_dbg_ctx ); 653 } 654 655 void BlockInternal(__finish_callback_fptr_t callback) { 656 disable_interrupts(); 657 with( *kernelTLS.this_processor ) { 658 finish.action_code = Callback; 659 finish.callback = callback; 660 } 661 662 verify( ! kernelTLS.preemption_state.enabled ); 663 returnToKernel(); 664 verify( ! kernelTLS.preemption_state.enabled ); 665 666 enable_interrupts( __cfaabi_dbg_ctx ); 626 667 } 627 668 628 669 // KERNEL ONLY 629 void __leave_thread() { 630 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 670 void LeaveThread(__spinlock_t * lock, thread_desc * thrd) { 671 verify( ! kernelTLS.preemption_state.enabled ); 672 with( * kernelTLS.this_processor ) { 673 finish.action_code = thrd ? Release_Schedule : Release; 674 finish.lock = lock; 675 finish.thrd = thrd; 676 } 677 631 678 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 679 } 661 680 … … 665 684 //----------------------------------------------------------------------------- 666 685 // Kernel boot procedures 667 static void __kernel_startup(void) {686 static void kernel_startup(void) { 668 687 verify( ! kernelTLS.preemption_state.enabled ); 669 688 __cfaabi_dbg_print_safe("Kernel : Starting\n"); … … 726 745 // Add the main thread to the ready queue 727 746 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 728 __schedule_thread(mainThread);747 ScheduleThread(mainThread); 729 748 730 749 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX 731 750 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 732 751 // mainThread is on the ready queue when this call is made. 733 __kernel_first_resume( kernelTLS.this_processor );752 kernel_first_resume( kernelTLS.this_processor ); 734 753 735 754 … … 743 762 } 744 763 745 static void __kernel_shutdown(void) {764 static void kernel_shutdown(void) { 746 765 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n"); 747 766 … … 754 773 // which is currently here 755 774 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 756 __kernel_last_resume( kernelTLS.this_processor );775 kernel_last_resume( kernelTLS.this_processor ); 757 776 mainThread->self_cor.state = Halted; 758 777 … … 780 799 // Kernel Quiescing 781 800 //============================================================================================= 782 static void __halt(processor * this) with( *this ) {801 static void halt(processor * this) with( *this ) { 783 802 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 784 803 … … 891 910 892 911 // atomically release spin lock and block 893 unlock( lock ); 894 park(); 912 BlockInternal( &lock ); 895 913 } 896 914 else { … … 911 929 912 930 // make new owner 913 unpark( thrd );931 WakeThread( thrd ); 914 932 } 915 933 … … 960 978 __cfaabi_dbg_debug_do( 961 979 extern "C" { 962 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {980 void __cfaabi_dbg_record(__spinlock_t & this, const char prev_name[]) { 963 981 this.prev_name = prev_name; 964 982 this.prev_thrd = kernelTLS.this_thread; … … 969 987 //----------------------------------------------------------------------------- 970 988 // Debug 971 bool threading_enabled(void) __attribute__((const)){989 bool threading_enabled(void) { 972 990 return true; 973 991 }
Note:
See TracChangeset
for help on using the changeset viewer.