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

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 a362f97 was e15df4c, checked in by Thierry Delisle <tdelisle@…>, 9 years ago

Renamed thread to scoped and thread_h to thread

  • Property mode set to 100644
File size: 12.0 KB
RevLine 
[8118303]1// -*- Mode: CFA -*-
2//
3// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
4//
5// The contents of this file are covered under the licence agreement in the
6// file "LICENCE" distributed with Cforall.
7//
8// kernel.c --
9//
10// Author : Thierry Delisle
11// Created On : Tue Jan 17 12:27:26 2016
12// Last Modified By : Thierry Delisle
13// Last Modified On : --
14// Update Count : 0
15//
16
17//Header
18#include "kernel"
19
20//C Includes
[c84e80a]21#include <stddef.h>
[eb2e723]22extern "C" {
23#include <sys/resource.h>
24}
[8118303]25
26//CFA Includes
27#include "libhdr.h"
28#include "threads"
29
30//Private includes
31#define __CFA_INVOKE_PRIVATE__
32#include "invoke.h"
33
[8def349]34//-----------------------------------------------------------------------------
35// Kernel storage
36struct processorCtx_t {
37 processor * proc;
38 coroutine c;
39};
40
41DECL_COROUTINE(processorCtx_t)
42
43#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
44
45KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
46KERNEL_STORAGE(cluster, systemCluster);
47KERNEL_STORAGE(processor, systemProcessor);
[e15df4c]48KERNEL_STORAGE(thread, mainThread);
[8def349]49KERNEL_STORAGE(machine_context_t, mainThread_context);
50
[bd98b58]51cluster * systemCluster;
[eb2e723]52processor * systemProcessor;
[e15df4c]53thread * mainThread;
[eb2e723]54
55void kernel_startup(void) __attribute__((constructor(101)));
56void kernel_shutdown(void) __attribute__((destructor(101)));
[8118303]57
[bd98b58]58//-----------------------------------------------------------------------------
59// Global state
60
[8def349]61thread_local processor * this_processor;
62
63processor * get_this_processor() {
64 return this_processor;
65}
[c84e80a]66
[bd98b58]67coroutine * this_coroutine(void) {
68 return this_processor->current_coroutine;
69}
70
[e15df4c]71thread * this_thread(void) {
[bd98b58]72 return this_processor->current_thread;
[c84e80a]73}
74
75//-----------------------------------------------------------------------------
[8def349]76// Main thread construction
77struct current_stack_info_t {
78 machine_context_t ctx;
79 unsigned int size; // size of stack
80 void *base; // base of stack
81 void *storage; // pointer to stack
82 void *limit; // stack grows towards stack limit
83 void *context; // address of cfa_context_t
84 void *top; // address of top of storage
[c84e80a]85};
86
[8def349]87void ?{}( current_stack_info_t * this ) {
88 CtxGet( &this->ctx );
89 this->base = this->ctx.FP;
90 this->storage = this->ctx.SP;
91
92 rlimit r;
93 int ret = getrlimit( RLIMIT_STACK, &r);
94 this->size = r.rlim_cur;
95
96 this->limit = (void *)(((intptr_t)this->base) - this->size);
97 this->context = &mainThread_context_storage;
98 this->top = this->base;
99}
100
101void ?{}( coStack_t * this, current_stack_info_t * info) {
102 this->size = info->size;
103 this->storage = info->storage;
104 this->limit = info->limit;
105 this->base = info->base;
106 this->context = info->context;
107 this->top = info->top;
108 this->userStack = true;
109}
110
111void ?{}( coroutine * this, current_stack_info_t * info) {
112 (&this->stack){ info };
113 this->name = "Main Thread";
114 this->errno_ = 0;
115 this->state = Inactive;
116 this->notHalted = true;
117}
118
[e15df4c]119void ?{}( thread * this, current_stack_info_t * info) {
[8def349]120 (&this->c){ info };
121}
[c84e80a]122
[8def349]123//-----------------------------------------------------------------------------
124// Processor coroutine
[eb2e723]125void ?{}(processorCtx_t * this, processor * proc) {
126 (&this->c){};
[c84e80a]127 this->proc = proc;
[8def349]128 proc->ctx = this;
129}
130
131void ?{}(processorCtx_t * this, processor * proc, current_stack_info_t * info) {
132 (&this->c){ info };
133 this->proc = proc;
134 proc->ctx = this;
135}
136
137void start(processor * this);
138
139void ?{}(processor * this) {
140 this{ systemCluster };
141}
142
143void ?{}(processor * this, cluster * cltr) {
144 this->cltr = cltr;
145 this->current_coroutine = NULL;
146 this->current_thread = NULL;
147 (&this->lock){};
148 this->terminated = false;
149
150 start( this );
[c84e80a]151}
152
[8def349]153void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) {
154 this->cltr = cltr;
155 this->current_coroutine = NULL;
156 this->current_thread = NULL;
157 (&this->lock){};
158 this->terminated = false;
159
160 this->ctx = ctx;
161 LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", ctx);
162 ctx{ this };
163}
164
165void ^?{}(processor * this) {
166 if( ! this->terminated ) {
167 LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this);
168 this->terminated = true;
169 lock( &this->lock );
170 }
171}
172
173void ?{}(cluster * this) {
174 ( &this->ready_queue ){};
175 pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );
176}
177
178void ^?{}(cluster * this) {
179 pthread_spin_destroy( &this->lock );
[c84e80a]180}
181
182//-----------------------------------------------------------------------------
183// Processor running routines
[eb2e723]184void main(processorCtx_t * ctx);
[e15df4c]185thread * nextThread(cluster * this);
186void runThread(processor * this, thread * dst);
[c84e80a]187void spin(processor * this, unsigned int * spin_count);
[8118303]188
[eb2e723]189void main(processorCtx_t * ctx) {
190 processor * this = ctx->proc;
191 LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
[8118303]192
[e15df4c]193 thread * readyThread = NULL;
[c84e80a]194 for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
195
[bd98b58]196 readyThread = nextThread( this->cltr );
[8118303]197
[c84e80a]198 if(readyThread) {
199 runThread(this, readyThread);
200 spin_count = 0;
201 } else {
202 spin(this, &spin_count);
203 }
204 }
[8118303]205
[8def349]206 LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
207 unlock( &this->lock );
[c84e80a]208 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
209}
210
[e15df4c]211void runThread(processor * this, thread * dst) {
[eb2e723]212 coroutine * proc_ctx = get_coroutine(this->ctx);
[c84e80a]213 coroutine * thrd_ctx = get_coroutine(dst);
214 thrd_ctx->last = proc_ctx;
215
216 // context switch to specified coroutine
217 // Which is now the current_coroutine
[8f49a54]218 // LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
[bd98b58]219 this->current_thread = dst;
220 this->current_coroutine = thrd_ctx;
[c84e80a]221 CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
[bd98b58]222 this->current_coroutine = proc_ctx;
[8f49a54]223 // LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
[c84e80a]224
225 // when CtxSwitch returns we are back in the processor coroutine
226}
227
228void spin(processor * this, unsigned int * spin_count) {
229 (*spin_count)++;
230}
231
[8def349]232void * CtxInvokeProcessor(void * arg) {
233 processor * proc = (processor *) arg;
234 this_processor = proc;
235 // SKULLDUGGERY: We want to create a context for the processor coroutine
236 // which is needed for the 2-step context switch. However, there is no reason
237 // to waste the perfectly valid stack create by pthread.
238 current_stack_info_t info;
239 machine_context_t ctx;
240 info.context = &ctx;
241 processorCtx_t proc_cor_storage = { proc, &info };
242
243 proc->current_coroutine = &proc->ctx->c;
244 proc->current_thread = NULL;
245
246 LIB_DEBUG_PRINTF("Kernel : core %p created (%p)\n", proc, proc->ctx);
247
248 // LIB_DEBUG_PRINTF("Kernel : core base : %p \n", info.base );
249 // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
250 // LIB_DEBUG_PRINTF("Kernel : core size : %x \n", info.size );
251 // LIB_DEBUG_PRINTF("Kernel : core limit : %p \n", info.limit );
252 // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
253 // LIB_DEBUG_PRINTF("Kernel : core top : %p \n", info.top );
254
255 //We now have a proper context from which to schedule threads
256
257 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
258 // resume it to start it like it normally would, it will just context switch
259 // back to here. Instead directly call the main since we already are on the
260 // appropriate stack.
261 proc_cor_storage.c.state = Active;
262 main( &proc_cor_storage );
263 proc_cor_storage.c.state = Halt;
264 proc_cor_storage.c.notHalted = false;
265
266 LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->ctx);
267
268 return NULL;
[c84e80a]269}
270
[8def349]271void start(processor * this) {
272 LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this);
273
274 pthread_attr_t attributes;
275 pthread_attr_init( &attributes );
[eb2e723]276
[8def349]277 pthread_create( &this->kernel_thread, &attributes, CtxInvokeProcessor, (void*)this );
[eb2e723]278
[8def349]279 pthread_attr_destroy( &attributes );
[eb2e723]280
[8def349]281 LIB_DEBUG_PRINTF("Kernel : core %p started\n", this);
[eb2e723]282}
283
[8def349]284//-----------------------------------------------------------------------------
285// Scheduler routines
[e15df4c]286void thread_schedule( thread * thrd ) {
[8def349]287 assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
288
289 pthread_spinlock_guard guard = { &systemProcessor->cltr->lock };
290 append( &systemProcessor->cltr->ready_queue, thrd );
[eb2e723]291}
292
[e15df4c]293thread * nextThread(cluster * this) {
[8def349]294 pthread_spinlock_guard guard = { &this->lock };
295 return pop_head( &this->ready_queue );
[eb2e723]296}
297
298//-----------------------------------------------------------------------------
299// Kernel boot procedures
300void kernel_startup(void) {
301
302 // SKULLDUGGERY: the mainThread steals the process main thread
303 // which will then be scheduled by the systemProcessor normally
304 LIB_DEBUG_PRINTF("Kernel : Starting\n");
305
[8def349]306 current_stack_info_t info;
307
308 // LIB_DEBUG_PRINTF("Kernel : core base : %p \n", info.base );
309 // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
310 // LIB_DEBUG_PRINTF("Kernel : core size : %x \n", info.size );
311 // LIB_DEBUG_PRINTF("Kernel : core limit : %p \n", info.limit );
312 // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
313 // LIB_DEBUG_PRINTF("Kernel : core top : %p \n", info.top );
[eb2e723]314
315 // Start by initializing the main thread
[e15df4c]316 mainThread = (thread *)&mainThread_storage;
[8def349]317 mainThread{ &info };
[eb2e723]318
[bd98b58]319 // Initialize the system cluster
320 systemCluster = (cluster *)&systemCluster_storage;
321 systemCluster{};
322
[8def349]323 // Initialize the system processor and the system processor ctx
[eb2e723]324 // (the coroutine that contains the processing control flow)
[8def349]325 systemProcessor = (processor *)&systemProcessor_storage;
326 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
[eb2e723]327
[dcb42b8]328 // Add the main thread to the ready queue
329 // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread
[bd98b58]330 thread_schedule(mainThread);
[eb2e723]331
[dcb42b8]332 //initialize the global state variables
[bd98b58]333 this_processor = systemProcessor;
334 this_processor->current_thread = mainThread;
335 this_processor->current_coroutine = &mainThread->c;
[eb2e723]336
[dcb42b8]337 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX
338 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
339 // mainThread is on the ready queue when this call is made.
[eb2e723]340 resume(systemProcessor->ctx);
341
[dcb42b8]342
343
344 // THE SYSTEM IS NOW COMPLETELY RUNNING
345
346
347
[eb2e723]348 LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
349}
350
[dcb42b8]351void kernel_shutdown(void) {
352 LIB_DEBUG_PRINTF("\n--------------------------------------------------\nKernel : Shutting down\n");
[eb2e723]353
[dcb42b8]354 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates.
355 // When its coroutine terminates, it return control to the mainThread
356 // which is currently here
[8f49a54]357 systemProcessor->terminated = true;
[eb2e723]358 suspend();
359
[dcb42b8]360 // THE SYSTEM IS NOW COMPLETELY STOPPED
[eb2e723]361
[dcb42b8]362 // Destroy the system processor and its context in reverse order of construction
363 // These were manually constructed so we need manually destroy them
[eb2e723]364 ^(systemProcessor->ctx){};
365 ^(systemProcessor){};
366
[dcb42b8]367 // Final step, destroy the main thread since it is no longer needed
368 // Since we provided a stack to this taxk it will not destroy anything
[eb2e723]369 ^(mainThread){};
370
371 LIB_DEBUG_PRINTF("Kernel : Shutdown complete\n");
[8118303]372}
373
[bd98b58]374//-----------------------------------------------------------------------------
375// Locks
376void ?{}( simple_lock * this ) {
377 ( &this->blocked ){};
378}
379
380void ^?{}( simple_lock * this ) {
381
382}
383
384void lock( simple_lock * this ) {
[8def349]385 {
386 pthread_spinlock_guard guard = { &systemCluster->lock }; //HUGE TEMP HACK which only works if we have a single cluster and is stupid
387 append( &this->blocked, this_thread() );
388 }
[bd98b58]389 suspend();
390}
391
392void unlock( simple_lock * this ) {
[e15df4c]393 thread * it;
[bd98b58]394 while( it = pop_head( &this->blocked) ) {
395 thread_schedule( it );
396 }
397}
398
399//-----------------------------------------------------------------------------
400// Queues
401void ?{}( simple_thread_list * this ) {
402 this->head = NULL;
403 this->tail = &this->head;
404}
405
[e15df4c]406void append( simple_thread_list * this, thread * t ) {
[bd98b58]407 assert( t->next == NULL );
408 *this->tail = t;
409 this->tail = &t->next;
410}
411
[e15df4c]412thread * pop_head( simple_thread_list * this ) {
413 thread * head = this->head;
[bd98b58]414 if( head ) {
415 this->head = head->next;
416 if( !head->next ) {
417 this->tail = &this->head;
418 }
419 head->next = NULL;
420 }
421
422 return head;
423}
[8118303]424// Local Variables: //
425// mode: c //
426// tab-width: 4 //
427// End: //
Note: See TracBrowser for help on using the repository browser.