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
Line 
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
21#include <stddef.h>
22extern "C" {
23#include <sys/resource.h>
24}
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
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);
48KERNEL_STORAGE(thread, mainThread);
49KERNEL_STORAGE(machine_context_t, mainThread_context);
50
51cluster * systemCluster;
52processor * systemProcessor;
53thread * mainThread;
54
55void kernel_startup(void) __attribute__((constructor(101)));
56void kernel_shutdown(void) __attribute__((destructor(101)));
57
58//-----------------------------------------------------------------------------
59// Global state
60
61thread_local processor * this_processor;
62
63processor * get_this_processor() {
64 return this_processor;
65}
66
67coroutine * this_coroutine(void) {
68 return this_processor->current_coroutine;
69}
70
71thread * this_thread(void) {
72 return this_processor->current_thread;
73}
74
75//-----------------------------------------------------------------------------
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
85};
86
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
119void ?{}( thread * this, current_stack_info_t * info) {
120 (&this->c){ info };
121}
122
123//-----------------------------------------------------------------------------
124// Processor coroutine
125void ?{}(processorCtx_t * this, processor * proc) {
126 (&this->c){};
127 this->proc = proc;
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 );
151}
152
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 );
180}
181
182//-----------------------------------------------------------------------------
183// Processor running routines
184void main(processorCtx_t * ctx);
185thread * nextThread(cluster * this);
186void runThread(processor * this, thread * dst);
187void spin(processor * this, unsigned int * spin_count);
188
189void main(processorCtx_t * ctx) {
190 processor * this = ctx->proc;
191 LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
192
193 thread * readyThread = NULL;
194 for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
195
196 readyThread = nextThread( this->cltr );
197
198 if(readyThread) {
199 runThread(this, readyThread);
200 spin_count = 0;
201 } else {
202 spin(this, &spin_count);
203 }
204 }
205
206 LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
207 unlock( &this->lock );
208 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
209}
210
211void runThread(processor * this, thread * dst) {
212 coroutine * proc_ctx = get_coroutine(this->ctx);
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
218 // LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
219 this->current_thread = dst;
220 this->current_coroutine = thrd_ctx;
221 CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
222 this->current_coroutine = proc_ctx;
223 // LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
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
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;
269}
270
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 );
276
277 pthread_create( &this->kernel_thread, &attributes, CtxInvokeProcessor, (void*)this );
278
279 pthread_attr_destroy( &attributes );
280
281 LIB_DEBUG_PRINTF("Kernel : core %p started\n", this);
282}
283
284//-----------------------------------------------------------------------------
285// Scheduler routines
286void thread_schedule( thread * thrd ) {
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 );
291}
292
293thread * nextThread(cluster * this) {
294 pthread_spinlock_guard guard = { &this->lock };
295 return pop_head( &this->ready_queue );
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
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 );
314
315 // Start by initializing the main thread
316 mainThread = (thread *)&mainThread_storage;
317 mainThread{ &info };
318
319 // Initialize the system cluster
320 systemCluster = (cluster *)&systemCluster_storage;
321 systemCluster{};
322
323 // Initialize the system processor and the system processor ctx
324 // (the coroutine that contains the processing control flow)
325 systemProcessor = (processor *)&systemProcessor_storage;
326 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
327
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
330 thread_schedule(mainThread);
331
332 //initialize the global state variables
333 this_processor = systemProcessor;
334 this_processor->current_thread = mainThread;
335 this_processor->current_coroutine = &mainThread->c;
336
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.
340 resume(systemProcessor->ctx);
341
342
343
344 // THE SYSTEM IS NOW COMPLETELY RUNNING
345
346
347
348 LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
349}
350
351void kernel_shutdown(void) {
352 LIB_DEBUG_PRINTF("\n--------------------------------------------------\nKernel : Shutting down\n");
353
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
357 systemProcessor->terminated = true;
358 suspend();
359
360 // THE SYSTEM IS NOW COMPLETELY STOPPED
361
362 // Destroy the system processor and its context in reverse order of construction
363 // These were manually constructed so we need manually destroy them
364 ^(systemProcessor->ctx){};
365 ^(systemProcessor){};
366
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
369 ^(mainThread){};
370
371 LIB_DEBUG_PRINTF("Kernel : Shutdown complete\n");
372}
373
374//-----------------------------------------------------------------------------
375// Locks
376void ?{}( simple_lock * this ) {
377 ( &this->blocked ){};
378}
379
380void ^?{}( simple_lock * this ) {
381
382}
383
384void lock( simple_lock * this ) {
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 }
389 suspend();
390}
391
392void unlock( simple_lock * this ) {
393 thread * it;
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
406void append( simple_thread_list * this, thread * t ) {
407 assert( t->next == NULL );
408 *this->tail = t;
409 this->tail = &t->next;
410}
411
412thread * pop_head( simple_thread_list * this ) {
413 thread * head = this->head;
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}
424// Local Variables: //
425// mode: c //
426// tab-width: 4 //
427// End: //
Note: See TracBrowser for help on using the repository browser.