source: src/libcfa/concurrency/kernel.c@ 0690350

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 0690350 was c2b9f21, checked in by Thierry Delisle <tdelisle@…>, 8 years ago

Removed libhdr, moved its content to bits

  • Property mode set to 100644
File size: 17.5 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 : Fri Jul 21 22:33:18 2017
13// Update Count : 2
14//
15
16//C Includes
17#include <stddef.h>
18extern "C" {
19#include <stdio.h>
20#include <fenv.h>
21#include <sys/resource.h>
22#include <signal.h>
23#include <unistd.h>
24}
25
26//CFA Includes
27#include "kernel_private.h"
28#include "preemption.h"
29#include "startup.h"
30
31//Private includes
32#define __CFA_INVOKE_PRIVATE__
33#include "invoke.h"
34
35//Start and stop routine for the kernel, declared first to make sure they run first
36void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
37void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
38
39//-----------------------------------------------------------------------------
40// Kernel storage
41KERNEL_STORAGE(cluster, mainCluster);
42KERNEL_STORAGE(processor, mainProcessor);
43KERNEL_STORAGE(processorCtx_t, mainProcessorCtx);
44KERNEL_STORAGE(thread_desc, mainThread);
45KERNEL_STORAGE(machine_context_t, mainThreadCtx);
46
47cluster * mainCluster;
48processor * mainProcessor;
49thread_desc * mainThread;
50
51//-----------------------------------------------------------------------------
52// Global state
53
54thread_local coroutine_desc * volatile this_coroutine;
55thread_local thread_desc * volatile this_thread;
56thread_local processor * volatile this_processor;
57
58volatile thread_local bool preemption_in_progress = 0;
59volatile thread_local unsigned short disable_preempt_count = 1;
60
61//-----------------------------------------------------------------------------
62// Main thread construction
63struct current_stack_info_t {
64 machine_context_t ctx;
65 unsigned int size; // size of stack
66 void *base; // base of stack
67 void *storage; // pointer to stack
68 void *limit; // stack grows towards stack limit
69 void *context; // address of cfa_context_t
70 void *top; // address of top of storage
71};
72
73void ?{}( current_stack_info_t & this ) {
74 CtxGet( this.ctx );
75 this.base = this.ctx.FP;
76 this.storage = this.ctx.SP;
77
78 rlimit r;
79 getrlimit( RLIMIT_STACK, &r);
80 this.size = r.rlim_cur;
81
82 this.limit = (void *)(((intptr_t)this.base) - this.size);
83 this.context = &storage_mainThreadCtx;
84 this.top = this.base;
85}
86
87void ?{}( coStack_t & this, current_stack_info_t * info) {
88 this.size = info->size;
89 this.storage = info->storage;
90 this.limit = info->limit;
91 this.base = info->base;
92 this.context = info->context;
93 this.top = info->top;
94 this.userStack = true;
95}
96
97void ?{}( coroutine_desc & this, current_stack_info_t * info) {
98 (this.stack){ info };
99 this.name = "Main Thread";
100 this.errno_ = 0;
101 this.state = Start;
102 this.starter = NULL;
103}
104
105void ?{}( thread_desc & this, current_stack_info_t * info) {
106 (this.self_cor){ info };
107}
108
109//-----------------------------------------------------------------------------
110// Processor coroutine
111
112// Construct the processor context of the main processor
113void ?{}(processorCtx_t & this, processor * proc) {
114 (this.__cor){ "Processor" };
115 this.__cor.starter = NULL;
116 this.proc = proc;
117 proc->runner = &this;
118}
119
120// Construct the processor context of non-main processors
121void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
122 (this.__cor){ info };
123 this.proc = proc;
124 proc->runner = &this;
125}
126
127void ?{}(processor & this) {
128 this{ mainCluster };
129}
130
131void ?{}(processor & this, cluster * cltr) {
132 this.cltr = cltr;
133 (this.terminated){ 0 };
134 this.do_terminate = false;
135 this.preemption_alarm = NULL;
136 this.pending_preemption = false;
137
138 start( &this );
139}
140
141void ?{}(processor & this, cluster * cltr, processorCtx_t & runner) {
142 this.cltr = cltr;
143 (this.terminated){ 0 };
144 this.do_terminate = false;
145 this.preemption_alarm = NULL;
146 this.pending_preemption = false;
147 this.kernel_thread = pthread_self();
148
149 this.runner = &runner;
150 __cfaabi_dbg_print_safe("Kernel : constructing main processor context %p\n", &runner);
151 runner{ &this };
152}
153
154void ^?{}(processor & this) {
155 if( ! this.do_terminate ) {
156 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
157 this.do_terminate = true;
158 P( this.terminated );
159 pthread_join( this.kernel_thread, NULL );
160 }
161}
162
163void ?{}(cluster & this) {
164 (this.ready_queue){};
165 ( this.ready_queue_lock ){};
166
167 this.preemption = default_preemption();
168}
169
170void ^?{}(cluster & this) {
171
172}
173
174//=============================================================================================
175// Kernel Scheduling logic
176//=============================================================================================
177//Main of the processor contexts
178void main(processorCtx_t & runner) {
179 processor * this = runner.proc;
180
181 __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
182
183 {
184 // Setup preemption data
185 preemption_scope scope = { this };
186
187 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
188
189 thread_desc * readyThread = NULL;
190 for( unsigned int spin_count = 0; ! this->do_terminate; spin_count++ )
191 {
192 readyThread = nextThread( this->cltr );
193
194 if(readyThread)
195 {
196 verify( disable_preempt_count > 0 );
197
198 runThread(this, readyThread);
199
200 verify( disable_preempt_count > 0 );
201
202 //Some actions need to be taken from the kernel
203 finishRunning(this);
204
205 spin_count = 0;
206 }
207 else
208 {
209 spin(this, &spin_count);
210 }
211 }
212
213 __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this);
214 }
215
216 V( this->terminated );
217
218 __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
219}
220
221// runThread runs a thread by context switching
222// from the processor coroutine to the target thread
223void runThread(processor * this, thread_desc * dst) {
224 coroutine_desc * proc_cor = get_coroutine(*this->runner);
225 coroutine_desc * thrd_cor = get_coroutine(dst);
226
227 //Reset the terminating actions here
228 this->finish.action_code = No_Action;
229
230 //Update global state
231 this_thread = dst;
232
233 // Context Switch to the thread
234 ThreadCtxSwitch(proc_cor, thrd_cor);
235 // when ThreadCtxSwitch returns we are back in the processor coroutine
236}
237
238// Once a thread has finished running, some of
239// its final actions must be executed from the kernel
240void finishRunning(processor * this) {
241 if( this->finish.action_code == Release ) {
242 unlock( *this->finish.lock );
243 }
244 else if( this->finish.action_code == Schedule ) {
245 ScheduleThread( this->finish.thrd );
246 }
247 else if( this->finish.action_code == Release_Schedule ) {
248 unlock( *this->finish.lock );
249 ScheduleThread( this->finish.thrd );
250 }
251 else if( this->finish.action_code == Release_Multi ) {
252 for(int i = 0; i < this->finish.lock_count; i++) {
253 unlock( *this->finish.locks[i] );
254 }
255 }
256 else if( this->finish.action_code == Release_Multi_Schedule ) {
257 for(int i = 0; i < this->finish.lock_count; i++) {
258 unlock( *this->finish.locks[i] );
259 }
260 for(int i = 0; i < this->finish.thrd_count; i++) {
261 ScheduleThread( this->finish.thrds[i] );
262 }
263 }
264 else {
265 assert(this->finish.action_code == No_Action);
266 }
267}
268
269// Handles spinning logic
270// TODO : find some strategy to put cores to sleep after some time
271void spin(processor * this, unsigned int * spin_count) {
272 (*spin_count)++;
273}
274
275// Context invoker for processors
276// This is the entry point for processors (kernel threads)
277// It effectively constructs a coroutine by stealing the pthread stack
278void * CtxInvokeProcessor(void * arg) {
279 processor * proc = (processor *) arg;
280 this_processor = proc;
281 this_coroutine = NULL;
282 this_thread = NULL;
283 disable_preempt_count = 1;
284 // SKULLDUGGERY: We want to create a context for the processor coroutine
285 // which is needed for the 2-step context switch. However, there is no reason
286 // to waste the perfectly valid stack create by pthread.
287 current_stack_info_t info;
288 machine_context_t ctx;
289 info.context = &ctx;
290 processorCtx_t proc_cor_storage = { proc, &info };
291
292 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", proc_cor_storage.__cor.stack.base);
293
294 //Set global state
295 this_coroutine = &proc->runner->__cor;
296 this_thread = NULL;
297
298 //We now have a proper context from which to schedule threads
299 __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
300
301 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
302 // resume it to start it like it normally would, it will just context switch
303 // back to here. Instead directly call the main since we already are on the
304 // appropriate stack.
305 proc_cor_storage.__cor.state = Active;
306 main( proc_cor_storage );
307 proc_cor_storage.__cor.state = Halted;
308
309 // Main routine of the core returned, the core is now fully terminated
310 __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, proc->runner);
311
312 return NULL;
313}
314
315void start(processor * this) {
316 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
317
318 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
319
320 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
321}
322
323//-----------------------------------------------------------------------------
324// Scheduler routines
325void ScheduleThread( thread_desc * thrd ) {
326 // if( !thrd ) return;
327 verify( thrd );
328 verify( thrd->self_cor.state != Halted );
329
330 verify( disable_preempt_count > 0 );
331
332 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
333
334 lock( this_processor->cltr->ready_queue_lock __cfaabi_dbg_ctx2 );
335 append( this_processor->cltr->ready_queue, thrd );
336 unlock( this_processor->cltr->ready_queue_lock );
337
338 verify( disable_preempt_count > 0 );
339}
340
341thread_desc * nextThread(cluster * this) {
342 verify( disable_preempt_count > 0 );
343 lock( this->ready_queue_lock __cfaabi_dbg_ctx2 );
344 thread_desc * head = pop_head( this->ready_queue );
345 unlock( this->ready_queue_lock );
346 verify( disable_preempt_count > 0 );
347 return head;
348}
349
350void BlockInternal() {
351 disable_interrupts();
352 verify( disable_preempt_count > 0 );
353 suspend();
354 verify( disable_preempt_count > 0 );
355 enable_interrupts( __cfaabi_dbg_ctx );
356}
357
358void BlockInternal( __spinlock_t * lock ) {
359 disable_interrupts();
360 this_processor->finish.action_code = Release;
361 this_processor->finish.lock = lock;
362
363 verify( disable_preempt_count > 0 );
364 suspend();
365 verify( disable_preempt_count > 0 );
366
367 enable_interrupts( __cfaabi_dbg_ctx );
368}
369
370void BlockInternal( thread_desc * thrd ) {
371 assert(thrd);
372 disable_interrupts();
373 assert( thrd->self_cor.state != Halted );
374 this_processor->finish.action_code = Schedule;
375 this_processor->finish.thrd = thrd;
376
377 verify( disable_preempt_count > 0 );
378 suspend();
379 verify( disable_preempt_count > 0 );
380
381 enable_interrupts( __cfaabi_dbg_ctx );
382}
383
384void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) {
385 assert(thrd);
386 disable_interrupts();
387 this_processor->finish.action_code = Release_Schedule;
388 this_processor->finish.lock = lock;
389 this_processor->finish.thrd = thrd;
390
391 verify( disable_preempt_count > 0 );
392 suspend();
393 verify( disable_preempt_count > 0 );
394
395 enable_interrupts( __cfaabi_dbg_ctx );
396}
397
398void BlockInternal(__spinlock_t * locks [], unsigned short count) {
399 disable_interrupts();
400 this_processor->finish.action_code = Release_Multi;
401 this_processor->finish.locks = locks;
402 this_processor->finish.lock_count = count;
403
404 verify( disable_preempt_count > 0 );
405 suspend();
406 verify( disable_preempt_count > 0 );
407
408 enable_interrupts( __cfaabi_dbg_ctx );
409}
410
411void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
412 disable_interrupts();
413 this_processor->finish.action_code = Release_Multi_Schedule;
414 this_processor->finish.locks = locks;
415 this_processor->finish.lock_count = lock_count;
416 this_processor->finish.thrds = thrds;
417 this_processor->finish.thrd_count = thrd_count;
418
419 verify( disable_preempt_count > 0 );
420 suspend();
421 verify( disable_preempt_count > 0 );
422
423 enable_interrupts( __cfaabi_dbg_ctx );
424}
425
426void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
427 verify( disable_preempt_count > 0 );
428 this_processor->finish.action_code = thrd ? Release_Schedule : Release;
429 this_processor->finish.lock = lock;
430 this_processor->finish.thrd = thrd;
431
432 suspend();
433}
434
435//=============================================================================================
436// Kernel Setup logic
437//=============================================================================================
438//-----------------------------------------------------------------------------
439// Kernel boot procedures
440void kernel_startup(void) {
441 __cfaabi_dbg_print_safe("Kernel : Starting\n");
442
443 // Start by initializing the main thread
444 // SKULLDUGGERY: the mainThread steals the process main thread
445 // which will then be scheduled by the mainProcessor normally
446 mainThread = (thread_desc *)&storage_mainThread;
447 current_stack_info_t info;
448 (*mainThread){ &info };
449
450 __cfaabi_dbg_print_safe("Kernel : Main thread ready\n");
451
452 // Initialize the main cluster
453 mainCluster = (cluster *)&storage_mainCluster;
454 (*mainCluster){};
455
456 __cfaabi_dbg_print_safe("Kernel : main cluster ready\n");
457
458 // Initialize the main processor and the main processor ctx
459 // (the coroutine that contains the processing control flow)
460 mainProcessor = (processor *)&storage_mainProcessor;
461 (*mainProcessor){ mainCluster, *(processorCtx_t *)&storage_mainProcessorCtx };
462
463 //initialize the global state variables
464 this_processor = mainProcessor;
465 this_thread = mainThread;
466 this_coroutine = &mainThread->self_cor;
467
468 // Enable preemption
469 kernel_start_preemption();
470
471 // Add the main thread to the ready queue
472 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
473 ScheduleThread(mainThread);
474
475 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
476 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
477 // mainThread is on the ready queue when this call is made.
478 resume( *mainProcessor->runner );
479
480
481
482 // THE SYSTEM IS NOW COMPLETELY RUNNING
483 __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
484
485 enable_interrupts( __cfaabi_dbg_ctx );
486}
487
488void kernel_shutdown(void) {
489 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
490
491 disable_interrupts();
492
493 // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
494 // When its coroutine terminates, it return control to the mainThread
495 // which is currently here
496 mainProcessor->do_terminate = true;
497 suspend();
498
499 // THE SYSTEM IS NOW COMPLETELY STOPPED
500
501 // Disable preemption
502 kernel_stop_preemption();
503
504 // Destroy the main processor and its context in reverse order of construction
505 // These were manually constructed so we need manually destroy them
506 ^(*mainProcessor->runner){};
507 ^(mainProcessor){};
508
509 // Final step, destroy the main thread since it is no longer needed
510 // Since we provided a stack to this taxk it will not destroy anything
511 ^(mainThread){};
512
513 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
514}
515
516static __spinlock_t kernel_abort_lock;
517static __spinlock_t kernel_debug_lock;
518static bool kernel_abort_called = false;
519
520void * kernel_abort (void) __attribute__ ((__nothrow__)) {
521 // abort cannot be recursively entered by the same or different processors because all signal handlers return when
522 // the globalAbort flag is true.
523 lock( kernel_abort_lock __cfaabi_dbg_ctx2 );
524
525 // first task to abort ?
526 if ( !kernel_abort_called ) { // not first task to abort ?
527 kernel_abort_called = true;
528 unlock( kernel_abort_lock );
529 }
530 else {
531 unlock( kernel_abort_lock );
532
533 sigset_t mask;
534 sigemptyset( &mask );
535 sigaddset( &mask, SIGALRM ); // block SIGALRM signals
536 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals
537 sigsuspend( &mask ); // block the processor to prevent further damage during abort
538 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it
539 }
540
541 return this_thread;
542}
543
544void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
545 thread_desc * thrd = kernel_data;
546
547 int len = snprintf( abort_text, abort_text_size, "Error occurred while executing task %.256s (%p)", thrd->self_cor.name, thrd );
548 __cfaabi_dbg_bits_write( abort_text, len );
549
550 if ( thrd != this_coroutine ) {
551 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine );
552 __cfaabi_dbg_bits_write( abort_text, len );
553 }
554 else {
555 __cfaabi_dbg_bits_write( ".\n", 2 );
556 }
557}
558
559extern "C" {
560 void __cfaabi_dbg_bits_acquire() {
561 lock( kernel_debug_lock __cfaabi_dbg_ctx2 );
562 }
563
564 void __cfaabi_dbg_bits_release() {
565 unlock( kernel_debug_lock );
566 }
567}
568
569//=============================================================================================
570// Kernel Utilities
571//=============================================================================================
572//-----------------------------------------------------------------------------
573// Locks
574void ?{}( semaphore & this, int count = 1 ) {
575 (this.lock){};
576 this.count = count;
577 (this.waiting){};
578}
579void ^?{}(semaphore & this) {}
580
581void P(semaphore & this) {
582 lock( this.lock __cfaabi_dbg_ctx2 );
583 this.count -= 1;
584 if ( this.count < 0 ) {
585 // queue current task
586 append( this.waiting, (thread_desc *)this_thread );
587
588 // atomically release spin lock and block
589 BlockInternal( &this.lock );
590 }
591 else {
592 unlock( this.lock );
593 }
594}
595
596void V(semaphore & this) {
597 thread_desc * thrd = NULL;
598 lock( this.lock __cfaabi_dbg_ctx2 );
599 this.count += 1;
600 if ( this.count <= 0 ) {
601 // remove task at head of waiting list
602 thrd = pop_head( this.waiting );
603 }
604
605 unlock( this.lock );
606
607 // make new owner
608 WakeThread( thrd );
609}
610
611// Local Variables: //
612// mode: c //
613// tab-width: 4 //
614// End: //
Note: See TracBrowser for help on using the repository browser.