source: src/libcfa/concurrency/kernel.c @ 63f78f0

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 63f78f0 was bd98b58, checked in by Thierry Delisle <tdelisle@…>, 7 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.