source: src/libcfa/concurrency/kernel.c@ 0bfaf80

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

Kernel now uses intrusive lists and blocking locks for ready queue management.
Update the plan for concurrency.

  • Property mode set to 100644
File size: 8.7 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
34cluster * systemCluster;
35processor * systemProcessor;
36thread_h * mainThread;
37
38void kernel_startup(void) __attribute__((constructor(101)));
39void kernel_shutdown(void) __attribute__((destructor(101)));
40
41void ?{}(processor * this, cluster * cltr) {
42 this->ctx = NULL;
43 this->cltr = cltr;
44 this->terminated = false;
45}
46
47void ^?{}(processor * this) {}
48
49void ?{}(cluster * this) {
50 ( &this->ready_queue ){};
51}
52
53void ^?{}(cluster * this) {}
54
55//-----------------------------------------------------------------------------
56// Global state
57
58/*thread_local*/ processor * this_processor;
59
60coroutine * this_coroutine(void) {
61 return this_processor->current_coroutine;
62}
63
64thread_h * this_thread(void) {
65 return this_processor->current_thread;
66}
67
68//-----------------------------------------------------------------------------
69// Processor coroutine
70struct processorCtx_t {
71 processor * proc;
72 coroutine c;
73};
74
75DECL_COROUTINE(processorCtx_t)
76
77void ?{}(processorCtx_t * this, processor * proc) {
78 (&this->c){};
79 this->proc = proc;
80}
81
82void CtxInvokeProcessor(processor * proc) {
83 processorCtx_t proc_cor_storage = {proc};
84 resume( &proc_cor_storage );
85}
86
87//-----------------------------------------------------------------------------
88// Processor running routines
89void main(processorCtx_t * ctx);
90thread_h * nextThread(cluster * this);
91void runThread(processor * this, thread_h * dst);
92void spin(processor * this, unsigned int * spin_count);
93
94void main(processorCtx_t * ctx) {
95 processor * this = ctx->proc;
96 LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
97
98 thread_h * readyThread = NULL;
99 for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
100
101 readyThread = nextThread( this->cltr );
102
103 if(readyThread) {
104 runThread(this, readyThread);
105 spin_count = 0;
106 } else {
107 spin(this, &spin_count);
108 }
109 }
110
111 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
112}
113
114void runThread(processor * this, thread_h * dst) {
115 coroutine * proc_ctx = get_coroutine(this->ctx);
116 coroutine * thrd_ctx = get_coroutine(dst);
117 thrd_ctx->last = proc_ctx;
118
119 // context switch to specified coroutine
120 // Which is now the current_coroutine
121 // LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
122 this->current_thread = dst;
123 this->current_coroutine = thrd_ctx;
124 CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
125 this->current_coroutine = proc_ctx;
126 // LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
127
128 // when CtxSwitch returns we are back in the processor coroutine
129}
130
131void spin(processor * this, unsigned int * spin_count) {
132 (*spin_count)++;
133}
134
135//-----------------------------------------------------------------------------
136// Scheduler routines
137void thread_schedule( thread_h * thrd ) {
138 assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
139 append( &systemProcessor->cltr->ready_queue, thrd );
140}
141
142thread_h * nextThread(cluster * this) {
143 return pop_head( &this->ready_queue );
144}
145
146//-----------------------------------------------------------------------------
147// Kernel storage
148#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
149
150KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
151KERNEL_STORAGE(cluster, systemCluster);
152KERNEL_STORAGE(processor, systemProcessor);
153KERNEL_STORAGE(thread_h, mainThread);
154KERNEL_STORAGE(machine_context_t, mainThread_context);
155
156//-----------------------------------------------------------------------------
157// Main thread construction
158struct mainThread_info_t {
159 machine_context_t ctx;
160 unsigned int size; // size of stack
161 void *base; // base of stack
162 void *storage; // pointer to stack
163 void *limit; // stack grows towards stack limit
164 void *context; // address of cfa_context_t
165 void *top; // address of top of storage
166};
167
168void ?{}( mainThread_info_t * this ) {
169 CtxGet( &this->ctx );
170 this->base = this->ctx.FP;
171 this->storage = this->ctx.SP;
172
173 rlimit r;
174 int ret = getrlimit( RLIMIT_STACK, &r);
175 this->size = r.rlim_cur;
176
177 this->limit = (void *)(((intptr_t)this->base) - this->size);
178 this->context = &mainThread_context_storage;
179 this->top = this->base;
180}
181
182void ?{}( coStack_t * this, mainThread_info_t * info) {
183 this->size = info->size;
184 this->storage = info->storage;
185 this->limit = info->limit;
186 this->base = info->base;
187 this->context = info->context;
188 this->top = info->top;
189 this->userStack = true;
190}
191
192void ?{}( coroutine * this, mainThread_info_t * info) {
193 (&this->stack){ info };
194 this->name = "Main Thread";
195 this->errno_ = 0;
196 this->state = Inactive;
197 this->notHalted = true;
198}
199
200void ?{}( thread_h * this, mainThread_info_t * info) {
201 (&this->c){ info };
202}
203
204//-----------------------------------------------------------------------------
205// Kernel boot procedures
206void kernel_startup(void) {
207
208 // SKULLDUGGERY: the mainThread steals the process main thread
209 // which will then be scheduled by the systemProcessor normally
210 LIB_DEBUG_PRINTF("Kernel : Starting\n");
211
212 mainThread_info_t ctx;
213
214 // Start by initializing the main thread
215 mainThread = (thread_h *)&mainThread_storage;
216 mainThread{ &ctx };
217
218 // Initialize the system cluster
219 systemCluster = (cluster *)&systemCluster_storage;
220 systemCluster{};
221
222 // Initialize the system processor
223 systemProcessor = (processor *)&systemProcessor_storage;
224 systemProcessor{ systemCluster };
225
226 // Initialize the system processor ctx
227 // (the coroutine that contains the processing control flow)
228 systemProcessor->ctx = (processorCtx_t *)&systemProcessorCtx_storage;
229 systemProcessor->ctx{ systemProcessor };
230
231 // Add the main thread to the ready queue
232 // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread
233 thread_schedule(mainThread);
234
235 //initialize the global state variables
236 this_processor = systemProcessor;
237 this_processor->current_thread = mainThread;
238 this_processor->current_coroutine = &mainThread->c;
239
240 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX
241 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
242 // mainThread is on the ready queue when this call is made.
243 resume(systemProcessor->ctx);
244
245
246
247 // THE SYSTEM IS NOW COMPLETELY RUNNING
248
249
250
251 LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
252}
253
254void kernel_shutdown(void) {
255 LIB_DEBUG_PRINTF("\n--------------------------------------------------\nKernel : Shutting down\n");
256
257 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates.
258 // When its coroutine terminates, it return control to the mainThread
259 // which is currently here
260 systemProcessor->terminated = true;
261 suspend();
262
263 // THE SYSTEM IS NOW COMPLETELY STOPPED
264
265 // Destroy the system processor and its context in reverse order of construction
266 // These were manually constructed so we need manually destroy them
267 ^(systemProcessor->ctx){};
268 ^(systemProcessor){};
269
270 // Final step, destroy the main thread since it is no longer needed
271 // Since we provided a stack to this taxk it will not destroy anything
272 ^(mainThread){};
273
274 LIB_DEBUG_PRINTF("Kernel : Shutdown complete\n");
275}
276
277//-----------------------------------------------------------------------------
278// Locks
279void ?{}( simple_lock * this ) {
280 ( &this->blocked ){};
281}
282
283void ^?{}( simple_lock * this ) {
284
285}
286
287void lock( simple_lock * this ) {
288 append( &this->blocked, this_thread() );
289 suspend();
290}
291
292void unlock( simple_lock * this ) {
293 thread_h * it;
294 while( it = pop_head( &this->blocked) ) {
295 thread_schedule( it );
296 }
297}
298
299//-----------------------------------------------------------------------------
300// Queues
301void ?{}( simple_thread_list * this ) {
302 this->head = NULL;
303 this->tail = &this->head;
304}
305
306void append( simple_thread_list * this, thread_h * t ) {
307 assert( t->next == NULL );
308 *this->tail = t;
309 this->tail = &t->next;
310}
311
312thread_h * pop_head( simple_thread_list * this ) {
313 thread_h * head = this->head;
314 if( head ) {
315 this->head = head->next;
316 if( !head->next ) {
317 this->tail = &this->head;
318 }
319 head->next = NULL;
320 }
321
322 return head;
323}
324// Local Variables: //
325// mode: c //
326// tab-width: 4 //
327// End: //
Note: See TracBrowser for help on using the repository browser.