source: libcfa/src/concurrency/kernel.cfa@ d4f1521

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum stuck-waitfor-destruct
Last change on this file since d4f1521 was 30763fd, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

Merge branch 'master' into relaxed_ready

  • Property mode set to 100644
File size: 26.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// kernel.c --
8//
9// Author : Thierry Delisle
10// Created On : Tue Jan 17 12:27:26 2017
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Thu Nov 21 16:46:59 2019
13// Update Count : 27
14//
15
16#define __cforall_thread__
17
18//C Includes
19#include <stddef.h>
20#include <errno.h>
21#include <string.h>
22extern "C" {
23#include <stdio.h>
24#include <fenv.h>
25#include <sys/resource.h>
26#include <signal.h>
27#include <unistd.h>
28}
29
30//CFA Includes
31#include "time.hfa"
32#include "kernel_private.hfa"
33#include "preemption.hfa"
34#include "startup.hfa"
35
36//Private includes
37#define __CFA_INVOKE_PRIVATE__
38#include "invoke.h"
39
40//-----------------------------------------------------------------------------
41// Some assembly required
42#if defined( __i386 )
43 #define CtxGet( ctx ) \
44 __asm__ volatile ( \
45 "movl %%esp,%0\n"\
46 "movl %%ebp,%1\n"\
47 : "=rm" (ctx.SP),\
48 "=rm" (ctx.FP) \
49 )
50
51 // mxcr : SSE Status and Control bits (control bits are preserved across function calls)
52 // fcw : X87 FPU control word (preserved across function calls)
53 #define __x87_store \
54 uint32_t __mxcr; \
55 uint16_t __fcw; \
56 __asm__ volatile ( \
57 "stmxcsr %0\n" \
58 "fnstcw %1\n" \
59 : "=m" (__mxcr),\
60 "=m" (__fcw) \
61 )
62
63 #define __x87_load \
64 __asm__ volatile ( \
65 "fldcw %1\n" \
66 "ldmxcsr %0\n" \
67 ::"m" (__mxcr),\
68 "m" (__fcw) \
69 )
70
71#elif defined( __x86_64 )
72 #define CtxGet( ctx ) \
73 __asm__ volatile ( \
74 "movq %%rsp,%0\n"\
75 "movq %%rbp,%1\n"\
76 : "=rm" (ctx.SP),\
77 "=rm" (ctx.FP) \
78 )
79
80 #define __x87_store \
81 uint32_t __mxcr; \
82 uint16_t __fcw; \
83 __asm__ volatile ( \
84 "stmxcsr %0\n" \
85 "fnstcw %1\n" \
86 : "=m" (__mxcr),\
87 "=m" (__fcw) \
88 )
89
90 #define __x87_load \
91 __asm__ volatile ( \
92 "fldcw %1\n" \
93 "ldmxcsr %0\n" \
94 :: "m" (__mxcr),\
95 "m" (__fcw) \
96 )
97
98
99#elif defined( __ARM_ARCH )
100#define CtxGet( ctx ) __asm__ ( \
101 "mov %0,%%sp\n" \
102 "mov %1,%%r11\n" \
103 : "=rm" (ctx.SP), "=rm" (ctx.FP) )
104#else
105 #error unknown hardware architecture
106#endif
107
108//-----------------------------------------------------------------------------
109//Start and stop routine for the kernel, declared first to make sure they run first
110static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
111static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
112
113//-----------------------------------------------------------------------------
114// Kernel storage
115KERNEL_STORAGE(cluster, mainCluster);
116KERNEL_STORAGE(processor, mainProcessor);
117KERNEL_STORAGE(thread_desc, mainThread);
118KERNEL_STORAGE(__stack_t, mainThreadCtx);
119
120cluster * mainCluster;
121processor * mainProcessor;
122thread_desc * mainThread;
123
124extern "C" {
125struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
126}
127
128size_t __page_size = 0;
129
130//-----------------------------------------------------------------------------
131// Global state
132thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = {
133 NULL,
134 NULL,
135 { 1, false, false },
136 6u //this should be seeded better but due to a bug calling rdtsc doesn't work
137};
138
139//-----------------------------------------------------------------------------
140// Struct to steal stack
141struct current_stack_info_t {
142 __stack_t * storage; // pointer to stack object
143 void *base; // base of stack
144 void *limit; // stack grows towards stack limit
145 void *context; // address of cfa_context_t
146};
147
148void ?{}( current_stack_info_t & this ) {
149 __stack_context_t ctx;
150 CtxGet( ctx );
151 this.base = ctx.FP;
152
153 rlimit r;
154 getrlimit( RLIMIT_STACK, &r);
155 size_t size = r.rlim_cur;
156
157 this.limit = (void *)(((intptr_t)this.base) - size);
158 this.context = &storage_mainThreadCtx;
159}
160
161//-----------------------------------------------------------------------------
162// Main thread construction
163
164void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
165 stack.storage = info->storage;
166 with(*stack.storage) {
167 limit = info->limit;
168 base = info->base;
169 }
170 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage;
171 *istorage |= 0x1;
172 name = "Main Thread";
173 state = Start;
174 starter = NULL;
175 last = NULL;
176 cancellation = NULL;
177}
178
179void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
180 state = Start;
181 self_cor{ info };
182 curr_cor = &self_cor;
183 curr_cluster = mainCluster;
184 self_mon.owner = &this;
185 self_mon.recursion = 1;
186 self_mon_p = &self_mon;
187 next = NULL;
188
189 node.next = NULL;
190 node.prev = NULL;
191 doregister(curr_cluster, this);
192
193 monitors{ &self_mon_p, 1, (fptr_t)0 };
194}
195
196//-----------------------------------------------------------------------------
197// Processor coroutine
198void ?{}(processorCtx_t & this) {
199
200}
201
202// Construct the processor context of non-main processors
203static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
204 (this.__cor){ info };
205 this.proc = proc;
206}
207
208static void start(processor * this);
209void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
210 this.name = name;
211 this.cltr = &cltr;
212 id = -1u;
213 terminated{ 0 };
214 do_terminate = false;
215 preemption_alarm = NULL;
216 pending_preemption = false;
217 runner.proc = &this;
218
219 idleLock{};
220
221 start( &this );
222}
223
224void ^?{}(processor & this) with( this ){
225 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
226 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
227
228 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
229 wake( &this );
230
231 P( terminated );
232 verify( kernelTLS.this_processor != &this);
233 }
234
235 pthread_join( kernel_thread, NULL );
236}
237
238void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {
239 this.name = name;
240 this.preemption_rate = preemption_rate;
241 ready_queue{};
242 ready_lock{};
243
244 idles{ __get };
245 threads{ __get };
246
247 doregister(this);
248}
249
250void ^?{}(cluster & this) {
251 unregister(this);
252}
253
254//=============================================================================================
255// Kernel Scheduling logic
256//=============================================================================================
257static void runThread(processor * this, thread_desc * dst);
258static void finishRunning(processor * this);
259static void halt(processor * this);
260
261//Main of the processor contexts
262void main(processorCtx_t & runner) {
263 // Because of a bug, we couldn't initialized the seed on construction
264 // Do it here
265 kernelTLS.rand_seed ^= rdtscl();
266
267 processor * this = runner.proc;
268 verify(this);
269
270 __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
271
272 // register the processor unless it's the main thread which is handled in the boot sequence
273 if(this != mainProcessor)
274 this->id = doregister(this->cltr, this);
275
276 {
277 // Setup preemption data
278 preemption_scope scope = { this };
279
280 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
281
282 thread_desc * readyThread = NULL;
283 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ )
284 {
285 readyThread = nextThread( this->cltr );
286
287 if(readyThread)
288 {
289 verify( ! kernelTLS.preemption_state.enabled );
290
291 runThread(this, readyThread);
292
293 verify( ! kernelTLS.preemption_state.enabled );
294
295 //Some actions need to be taken from the kernel
296 finishRunning(this);
297
298 spin_count = 0;
299 }
300 else
301 {
302 // spin(this, &spin_count);
303 halt(this);
304 }
305 }
306
307 __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this);
308 }
309
310 V( this->terminated );
311
312 // unregister the processor unless it's the main thread which is handled in the boot sequence
313 if(this != mainProcessor)
314 unregister(this->cltr, this);
315
316 __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
317}
318
319static int * __volatile_errno() __attribute__((noinline));
320static int * __volatile_errno() { asm(""); return &errno; }
321
322// KERNEL ONLY
323// runThread runs a thread by context switching
324// from the processor coroutine to the target thread
325static void runThread(processor * this, thread_desc * thrd_dst) {
326 coroutine_desc * proc_cor = get_coroutine(this->runner);
327
328 // Reset the terminating actions here
329 this->finish.action_code = No_Action;
330
331 // Update global state
332 kernelTLS.this_thread = thrd_dst;
333
334 // set state of processor coroutine to inactive and the thread to active
335 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
336 thrd_dst->state = Active;
337
338 // set context switch to the thread that the processor is executing
339 verify( thrd_dst->context.SP );
340 CtxSwitch( &proc_cor->context, &thrd_dst->context );
341 // when CtxSwitch returns we are back in the processor coroutine
342
343 // set state of processor coroutine to active and the thread to inactive
344 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive;
345 proc_cor->state = Active;
346}
347
348// KERNEL_ONLY
349static void returnToKernel() {
350 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
351 thread_desc * thrd_src = kernelTLS.this_thread;
352
353 // set state of current coroutine to inactive
354 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive;
355 proc_cor->state = Active;
356 int local_errno = *__volatile_errno();
357 #if defined( __i386 ) || defined( __x86_64 )
358 __x87_store;
359 #endif
360
361 // set new coroutine that the processor is executing
362 // and context switch to it
363 verify( proc_cor->context.SP );
364 CtxSwitch( &thrd_src->context, &proc_cor->context );
365
366 // set state of new coroutine to active
367 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
368 thrd_src->state = Active;
369
370 #if defined( __i386 ) || defined( __x86_64 )
371 __x87_load;
372 #endif
373 *__volatile_errno() = local_errno;
374}
375
376// KERNEL_ONLY
377// Once a thread has finished running, some of
378// its final actions must be executed from the kernel
379static void finishRunning(processor * this) with( this->finish ) {
380 verify( ! kernelTLS.preemption_state.enabled );
381 choose( action_code ) {
382 case No_Action:
383 break;
384 case Release:
385 unlock( *lock );
386 case Schedule:
387 ScheduleThread( thrd );
388 case Release_Schedule:
389 unlock( *lock );
390 ScheduleThread( thrd );
391 case Release_Multi:
392 for(int i = 0; i < lock_count; i++) {
393 unlock( *locks[i] );
394 }
395 case Release_Multi_Schedule:
396 for(int i = 0; i < lock_count; i++) {
397 unlock( *locks[i] );
398 }
399 for(int i = 0; i < thrd_count; i++) {
400 ScheduleThread( thrds[i] );
401 }
402 case Callback:
403 callback();
404 default:
405 abort("KERNEL ERROR: Unexpected action to run after thread");
406 }
407}
408
409// KERNEL_ONLY
410// Context invoker for processors
411// This is the entry point for processors (kernel threads)
412// It effectively constructs a coroutine by stealing the pthread stack
413static void * CtxInvokeProcessor(void * arg) {
414 processor * proc = (processor *) arg;
415 kernelTLS.this_processor = proc;
416 kernelTLS.this_thread = NULL;
417 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
418 // SKULLDUGGERY: We want to create a context for the processor coroutine
419 // which is needed for the 2-step context switch. However, there is no reason
420 // to waste the perfectly valid stack create by pthread.
421 current_stack_info_t info;
422 __stack_t ctx;
423 info.storage = &ctx;
424 (proc->runner){ proc, &info };
425
426 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
427
428 //Set global state
429 kernelTLS.this_thread = NULL;
430
431 //We now have a proper context from which to schedule threads
432 __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);
433
434 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
435 // resume it to start it like it normally would, it will just context switch
436 // back to here. Instead directly call the main since we already are on the
437 // appropriate stack.
438 get_coroutine(proc->runner)->state = Active;
439 main( proc->runner );
440 get_coroutine(proc->runner)->state = Halted;
441
442 // Main routine of the core returned, the core is now fully terminated
443 __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);
444
445 return NULL;
446}
447
448static void start(processor * this) {
449 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
450
451 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
452
453 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
454}
455
456// KERNEL_ONLY
457void kernel_first_resume( processor * this ) {
458 thread_desc * src = mainThread;
459 coroutine_desc * dst = get_coroutine(this->runner);
460
461 verify( ! kernelTLS.preemption_state.enabled );
462
463 __stack_prepare( &dst->stack, 65000 );
464 CtxStart(&this->runner, CtxInvokeCoroutine);
465
466 verify( ! kernelTLS.preemption_state.enabled );
467
468 dst->last = &src->self_cor;
469 dst->starter = dst->starter ? dst->starter : &src->self_cor;
470
471 // set state of current coroutine to inactive
472 src->state = src->state == Halted ? Halted : Inactive;
473
474 // context switch to specified coroutine
475 verify( dst->context.SP );
476 CtxSwitch( &src->context, &dst->context );
477 // when CtxSwitch returns we are back in the src coroutine
478
479 // set state of new coroutine to active
480 src->state = Active;
481
482 verify( ! kernelTLS.preemption_state.enabled );
483}
484
485// KERNEL_ONLY
486void kernel_last_resume( processor * this ) {
487 coroutine_desc * src = &mainThread->self_cor;
488 coroutine_desc * dst = get_coroutine(this->runner);
489
490 verify( ! kernelTLS.preemption_state.enabled );
491 verify( dst->starter == src );
492 verify( dst->context.SP );
493
494 // context switch to the processor
495 CtxSwitch( &src->context, &dst->context );
496}
497
498//-----------------------------------------------------------------------------
499// Scheduler routines
500
501// KERNEL ONLY
502void ScheduleThread( thread_desc * thrd ) {
503 verify( thrd );
504 verify( thrd->state != Halted );
505
506 verify( ! kernelTLS.preemption_state.enabled );
507
508 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
509
510 with( *thrd->curr_cluster ) {
511 ready_schedule_lock(*thrd->curr_cluster, kernelTLS.this_processor);
512 __atomic_acquire(&ready_queue.lock);
513 thrd->ts = rdtscl();
514 bool was_empty = push( ready_queue, thrd );
515 __atomic_unlock(&ready_queue.lock);
516 ready_schedule_unlock(*thrd->curr_cluster, kernelTLS.this_processor);
517
518 if(was_empty) {
519 lock (proc_list_lock __cfaabi_dbg_ctx2);
520 if(idles) {
521 wake_fast(idles.head);
522 }
523 unlock (proc_list_lock);
524 }
525 else if( struct processor * idle = idles.head ) {
526 wake_fast(idle);
527 }
528
529 }
530
531 verify( ! kernelTLS.preemption_state.enabled );
532}
533
534// KERNEL ONLY
535thread_desc * nextThread(cluster * this) with( *this ) {
536 verify( ! kernelTLS.preemption_state.enabled );
537
538 ready_schedule_lock(*this, kernelTLS.this_processor);
539 __atomic_acquire(&ready_queue.lock);
540 thread_desc * head;
541 __attribute__((unused)) bool _;
542 [head, _] = pop( ready_queue );
543 __atomic_unlock(&ready_queue.lock);
544 ready_schedule_unlock(*this, kernelTLS.this_processor);
545
546 verify( ! kernelTLS.preemption_state.enabled );
547 return head;
548}
549
550void BlockInternal() {
551 disable_interrupts();
552 verify( ! kernelTLS.preemption_state.enabled );
553 returnToKernel();
554 verify( ! kernelTLS.preemption_state.enabled );
555 enable_interrupts( __cfaabi_dbg_ctx );
556}
557
558void BlockInternal( __spinlock_t * lock ) {
559 disable_interrupts();
560 with( *kernelTLS.this_processor ) {
561 finish.action_code = Release;
562 finish.lock = lock;
563 }
564
565 verify( ! kernelTLS.preemption_state.enabled );
566 returnToKernel();
567 verify( ! kernelTLS.preemption_state.enabled );
568
569 enable_interrupts( __cfaabi_dbg_ctx );
570}
571
572void BlockInternal( thread_desc * thrd ) {
573 disable_interrupts();
574 with( * kernelTLS.this_processor ) {
575 finish.action_code = Schedule;
576 finish.thrd = thrd;
577 }
578
579 verify( ! kernelTLS.preemption_state.enabled );
580 returnToKernel();
581 verify( ! kernelTLS.preemption_state.enabled );
582
583 enable_interrupts( __cfaabi_dbg_ctx );
584}
585
586void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) {
587 assert(thrd);
588 disable_interrupts();
589 with( * kernelTLS.this_processor ) {
590 finish.action_code = Release_Schedule;
591 finish.lock = lock;
592 finish.thrd = thrd;
593 }
594
595 verify( ! kernelTLS.preemption_state.enabled );
596 returnToKernel();
597 verify( ! kernelTLS.preemption_state.enabled );
598
599 enable_interrupts( __cfaabi_dbg_ctx );
600}
601
602void BlockInternal(__spinlock_t * locks [], unsigned short count) {
603 disable_interrupts();
604 with( * kernelTLS.this_processor ) {
605 finish.action_code = Release_Multi;
606 finish.locks = locks;
607 finish.lock_count = count;
608 }
609
610 verify( ! kernelTLS.preemption_state.enabled );
611 returnToKernel();
612 verify( ! kernelTLS.preemption_state.enabled );
613
614 enable_interrupts( __cfaabi_dbg_ctx );
615}
616
617void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
618 disable_interrupts();
619 with( *kernelTLS.this_processor ) {
620 finish.action_code = Release_Multi_Schedule;
621 finish.locks = locks;
622 finish.lock_count = lock_count;
623 finish.thrds = thrds;
624 finish.thrd_count = thrd_count;
625 }
626
627 verify( ! kernelTLS.preemption_state.enabled );
628 returnToKernel();
629 verify( ! kernelTLS.preemption_state.enabled );
630
631 enable_interrupts( __cfaabi_dbg_ctx );
632}
633
634void BlockInternal(__finish_callback_fptr_t callback) {
635 disable_interrupts();
636 with( *kernelTLS.this_processor ) {
637 finish.action_code = Callback;
638 finish.callback = callback;
639 }
640
641 verify( ! kernelTLS.preemption_state.enabled );
642 returnToKernel();
643 verify( ! kernelTLS.preemption_state.enabled );
644
645 enable_interrupts( __cfaabi_dbg_ctx );
646}
647
648// KERNEL ONLY
649void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
650 verify( ! kernelTLS.preemption_state.enabled );
651 with( * kernelTLS.this_processor ) {
652 finish.action_code = thrd ? Release_Schedule : Release;
653 finish.lock = lock;
654 finish.thrd = thrd;
655 }
656
657 returnToKernel();
658}
659
660//=============================================================================================
661// Kernel Setup logic
662//=============================================================================================
663//-----------------------------------------------------------------------------
664// Kernel boot procedures
665static void kernel_startup(void) {
666 verify( ! kernelTLS.preemption_state.enabled );
667 __cfaabi_dbg_print_safe("Kernel : Starting\n");
668
669 __page_size = sysconf( _SC_PAGESIZE );
670
671 __cfa_dbg_global_clusters.list{ __get };
672 __cfa_dbg_global_clusters.lock{};
673
674 // Initialize the main cluster
675 mainCluster = (cluster *)&storage_mainCluster;
676 (*mainCluster){"Main Cluster"};
677
678 __cfaabi_dbg_print_safe("Kernel : Main cluster ready\n");
679
680 // Start by initializing the main thread
681 // SKULLDUGGERY: the mainThread steals the process main thread
682 // which will then be scheduled by the mainProcessor normally
683 mainThread = (thread_desc *)&storage_mainThread;
684 current_stack_info_t info;
685 info.storage = (__stack_t*)&storage_mainThreadCtx;
686 (*mainThread){ &info };
687
688 __cfaabi_dbg_print_safe("Kernel : Main thread ready\n");
689
690
691
692 // Construct the processor context of the main processor
693 void ?{}(processorCtx_t & this, processor * proc) {
694 (this.__cor){ "Processor" };
695 this.__cor.starter = NULL;
696 this.proc = proc;
697 }
698
699 void ?{}(processor & this) with( this ) {
700 name = "Main Processor";
701 cltr = mainCluster;
702 terminated{ 0 };
703 do_terminate = false;
704 preemption_alarm = NULL;
705 pending_preemption = false;
706 kernel_thread = pthread_self();
707 id = -1u;
708
709 runner{ &this };
710 __cfaabi_dbg_print_safe("Kernel : constructed main processor context %p\n", &runner);
711 }
712
713 // Initialize the main processor and the main processor ctx
714 // (the coroutine that contains the processing control flow)
715 mainProcessor = (processor *)&storage_mainProcessor;
716 (*mainProcessor){};
717
718 mainProcessor->id = doregister(mainCluster, mainProcessor);
719
720 //initialize the global state variables
721 kernelTLS.this_processor = mainProcessor;
722 kernelTLS.this_thread = mainThread;
723
724 // Enable preemption
725 kernel_start_preemption();
726
727 // Add the main thread to the ready queue
728 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
729 ScheduleThread(mainThread);
730
731 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
732 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
733 // mainThread is on the ready queue when this call is made.
734 kernel_first_resume( kernelTLS.this_processor );
735
736
737
738 // THE SYSTEM IS NOW COMPLETELY RUNNING
739 __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
740
741 verify( ! kernelTLS.preemption_state.enabled );
742 enable_interrupts( __cfaabi_dbg_ctx );
743 verify( TL_GET( preemption_state.enabled ) );
744}
745
746static void kernel_shutdown(void) {
747 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
748
749 verify( TL_GET( preemption_state.enabled ) );
750 disable_interrupts();
751 verify( ! kernelTLS.preemption_state.enabled );
752
753 // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
754 // When its coroutine terminates, it return control to the mainThread
755 // which is currently here
756 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
757 kernel_last_resume( kernelTLS.this_processor );
758 mainThread->self_cor.state = Halted;
759
760 // THE SYSTEM IS NOW COMPLETELY STOPPED
761
762 // Disable preemption
763 kernel_stop_preemption();
764
765 unregister(mainCluster, mainProcessor);
766
767 // Destroy the main processor and its context in reverse order of construction
768 // These were manually constructed so we need manually destroy them
769 ^(mainProcessor->runner){};
770 ^(*mainProcessor){};
771
772 // Final step, destroy the main thread since it is no longer needed
773 // Since we provided a stack to this task it will not destroy anything
774 ^(*mainThread){};
775
776 ^(*mainCluster){};
777
778 ^(__cfa_dbg_global_clusters.list){};
779 ^(__cfa_dbg_global_clusters.lock){};
780
781 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
782}
783
784//=============================================================================================
785// Kernel Quiescing
786//=============================================================================================
787static void halt(processor * this) with( *this ) {
788 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
789
790 with( *cltr ) {
791 lock (proc_list_lock __cfaabi_dbg_ctx2);
792 push_front(idles, *this);
793 unlock (proc_list_lock);
794 }
795
796 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
797
798 wait( idleLock );
799
800 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
801
802 with( *cltr ) {
803 lock (proc_list_lock __cfaabi_dbg_ctx2);
804 remove (idles, *this);
805 unlock (proc_list_lock);
806 }
807}
808
809//=============================================================================================
810// Unexpected Terminating logic
811//=============================================================================================
812static __spinlock_t kernel_abort_lock;
813static bool kernel_abort_called = false;
814
815void * kernel_abort(void) __attribute__ ((__nothrow__)) {
816 // abort cannot be recursively entered by the same or different processors because all signal handlers return when
817 // the globalAbort flag is true.
818 lock( kernel_abort_lock __cfaabi_dbg_ctx2 );
819
820 // first task to abort ?
821 if ( kernel_abort_called ) { // not first task to abort ?
822 unlock( kernel_abort_lock );
823
824 sigset_t mask;
825 sigemptyset( &mask );
826 sigaddset( &mask, SIGALRM ); // block SIGALRM signals
827 sigsuspend( &mask ); // block the processor to prevent further damage during abort
828 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it
829 }
830 else {
831 kernel_abort_called = true;
832 unlock( kernel_abort_lock );
833 }
834
835 return kernelTLS.this_thread;
836}
837
838void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
839 thread_desc * thrd = kernel_data;
840
841 if(thrd) {
842 int len = snprintf( abort_text, abort_text_size, "Error occurred while executing thread %.256s (%p)", thrd->self_cor.name, thrd );
843 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
844
845 if ( &thrd->self_cor != thrd->curr_cor ) {
846 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
847 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
848 }
849 else {
850 __cfaabi_bits_write( STDERR_FILENO, ".\n", 2 );
851 }
852 }
853 else {
854 int len = snprintf( abort_text, abort_text_size, "Error occurred outside of any thread.\n" );
855 __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
856 }
857}
858
859int kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) {
860 return get_coroutine(kernelTLS.this_thread) == get_coroutine(mainThread) ? 4 : 2;
861}
862
863static __spinlock_t kernel_debug_lock;
864
865extern "C" {
866 void __cfaabi_bits_acquire() {
867 lock( kernel_debug_lock __cfaabi_dbg_ctx2 );
868 }
869
870 void __cfaabi_bits_release() {
871 unlock( kernel_debug_lock );
872 }
873}
874
875//=============================================================================================
876// Kernel Utilities
877//=============================================================================================
878//-----------------------------------------------------------------------------
879// Locks
880void ?{}( semaphore & this, int count = 1 ) {
881 (this.lock){};
882 this.count = count;
883 (this.waiting){};
884}
885void ^?{}(semaphore & this) {}
886
887void P(semaphore & this) with( this ){
888 lock( lock __cfaabi_dbg_ctx2 );
889 count -= 1;
890 if ( count < 0 ) {
891 // queue current task
892 append( waiting, kernelTLS.this_thread );
893
894 // atomically release spin lock and block
895 BlockInternal( &lock );
896 }
897 else {
898 unlock( lock );
899 }
900}
901
902void V(semaphore & this) with( this ) {
903 thread_desc * thrd = NULL;
904 lock( lock __cfaabi_dbg_ctx2 );
905 count += 1;
906 if ( count <= 0 ) {
907 // remove task at head of waiting list
908 thrd = pop_head( waiting );
909 }
910
911 unlock( lock );
912
913 // make new owner
914 WakeThread( thrd );
915}
916
917//-----------------------------------------------------------------------------
918// Global Queues
919void doregister( cluster & cltr ) {
920 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
921 push_front( __cfa_dbg_global_clusters.list, cltr );
922 unlock ( __cfa_dbg_global_clusters.lock );
923}
924
925void unregister( cluster & cltr ) {
926 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
927 remove( __cfa_dbg_global_clusters.list, cltr );
928 unlock( __cfa_dbg_global_clusters.lock );
929}
930
931void doregister( cluster * cltr, thread_desc & thrd ) {
932 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2);
933 cltr->nthreads += 1;
934 push_front(cltr->threads, thrd);
935 unlock (cltr->thread_list_lock);
936}
937
938void unregister( cluster * cltr, thread_desc & thrd ) {
939 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2);
940 remove(cltr->threads, thrd );
941 cltr->nthreads -= 1;
942 unlock(cltr->thread_list_lock);
943}
944
945//-----------------------------------------------------------------------------
946// Debug
947__cfaabi_dbg_debug_do(
948 extern "C" {
949 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
950 this.prev_name = prev_name;
951 this.prev_thrd = kernelTLS.this_thread;
952 }
953 }
954)
955
956//-----------------------------------------------------------------------------
957// Debug
958bool threading_enabled(void) {
959 return true;
960}
961// Local Variables: //
962// mode: c //
963// tab-width: 4 //
964// End: //
Note: See TracBrowser for help on using the repository browser.