Changes in src/libcfa/concurrency/kernel.c [c84e80a:e15df4c]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
rc84e80a re15df4c 20 20 //C Includes 21 21 #include <stddef.h> 22 extern "C" { 23 #include <sys/resource.h> 24 } 22 25 23 26 //CFA Includes … … 29 32 #include "invoke.h" 30 33 31 processor systemProcessorStorage = {}; 32 processor * systemProcessor = &systemProcessorStorage; 33 34 void ?{}(processor * this) { 35 this->cor = NULL; 36 this->thread_index = 0; 37 this->thread_count = 10; 38 this->terminated = false; 39 40 for(int i = 0; i < 10; i++) { 41 this->threads[i] = NULL; 42 } 43 44 LIB_DEBUG_PRINTF("Processor : ctor for core %p (core spots %d)\n", this, this->thread_count); 45 } 46 47 void ^?{}(processor * this) { 48 49 } 50 51 //----------------------------------------------------------------------------- 52 // Processor coroutine 53 struct proc_coroutine { 34 //----------------------------------------------------------------------------- 35 // Kernel storage 36 struct processorCtx_t { 54 37 processor * proc; 55 38 coroutine c; 56 39 }; 57 40 58 void ?{}(coroutine * this, processor * proc) { 59 this{}; 60 } 61 62 DECL_COROUTINE(proc_coroutine) 63 64 void ?{}(proc_coroutine * this, processor * proc) { 65 (&this->c){proc}; 41 DECL_COROUTINE(processorCtx_t) 42 43 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)] 44 45 KERNEL_STORAGE(processorCtx_t, systemProcessorCtx); 46 KERNEL_STORAGE(cluster, systemCluster); 47 KERNEL_STORAGE(processor, systemProcessor); 48 KERNEL_STORAGE(thread, mainThread); 49 KERNEL_STORAGE(machine_context_t, mainThread_context); 50 51 cluster * systemCluster; 52 processor * systemProcessor; 53 thread * mainThread; 54 55 void kernel_startup(void) __attribute__((constructor(101))); 56 void kernel_shutdown(void) __attribute__((destructor(101))); 57 58 //----------------------------------------------------------------------------- 59 // Global state 60 61 thread_local processor * this_processor; 62 63 processor * get_this_processor() { 64 return this_processor; 65 } 66 67 coroutine * this_coroutine(void) { 68 return this_processor->current_coroutine; 69 } 70 71 thread * this_thread(void) { 72 return this_processor->current_thread; 73 } 74 75 //----------------------------------------------------------------------------- 76 // Main thread construction 77 struct 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 87 void ?{}( 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 101 void ?{}( 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 111 void ?{}( 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 119 void ?{}( thread * this, current_stack_info_t * info) { 120 (&this->c){ info }; 121 } 122 123 //----------------------------------------------------------------------------- 124 // Processor coroutine 125 void ?{}(processorCtx_t * this, processor * proc) { 126 (&this->c){}; 66 127 this->proc = proc; 67 proc->cor = this; 68 } 69 70 void ^?{}(proc_coroutine * this) { 71 ^(&this->c){}; 72 } 73 74 void CtxInvokeProcessor(processor * proc) { 75 proc_coroutine proc_cor_storage = {proc}; 76 resume( &proc_cor_storage ); 128 proc->ctx = this; 129 } 130 131 void ?{}(processorCtx_t * this, processor * proc, current_stack_info_t * info) { 132 (&this->c){ info }; 133 this->proc = proc; 134 proc->ctx = this; 135 } 136 137 void start(processor * this); 138 139 void ?{}(processor * this) { 140 this{ systemCluster }; 141 } 142 143 void ?{}(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 153 void ?{}(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 165 void ^?{}(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 173 void ?{}(cluster * this) { 174 ( &this->ready_queue ){}; 175 pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE ); 176 } 177 178 void ^?{}(cluster * this) { 179 pthread_spin_destroy( &this->lock ); 77 180 } 78 181 79 182 //----------------------------------------------------------------------------- 80 183 // Processor running routines 81 void main(proc _coroutine * cor);82 thread _h * nextThread(processor * this);83 void runThread(processor * this, thread _h* dst);184 void main(processorCtx_t * ctx); 185 thread * nextThread(cluster * this); 186 void runThread(processor * this, thread * dst); 84 187 void spin(processor * this, unsigned int * spin_count); 85 188 86 void main(proc _coroutine * cor) {87 processor * this ;88 this = cor->proc;89 90 thread _h* readyThread = NULL;189 void main(processorCtx_t * ctx) { 190 processor * this = ctx->proc; 191 LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this); 192 193 thread * readyThread = NULL; 91 194 for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) { 92 195 93 readyThread = nextThread( this);196 readyThread = nextThread( this->cltr ); 94 197 95 198 if(readyThread) { … … 101 204 } 102 205 206 LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this); 207 unlock( &this->lock ); 103 208 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this); 104 209 } 105 210 106 thread_h * nextThread(processor * this) { 107 for(int i = 0; i < this->thread_count; i++) { 108 this->thread_index = (this->thread_index + 1) % this->thread_count; 109 110 thread_h * thrd = this->threads[this->thread_index]; 111 if(thrd) return thrd; 112 } 113 114 return NULL; 115 } 116 117 void runThread(processor * this, thread_h * dst) { 118 coroutine * proc_ctx = get_coroutine(this->cor); 211 void runThread(processor * this, thread * dst) { 212 coroutine * proc_ctx = get_coroutine(this->ctx); 119 213 coroutine * thrd_ctx = get_coroutine(dst); 120 214 thrd_ctx->last = proc_ctx; … … 122 216 // context switch to specified coroutine 123 217 // Which is now the current_coroutine 124 LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine); 125 current_coroutine = thrd_ctx; 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; 126 221 CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context ); 127 current_coroutine = proc_ctx;128 LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);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); 129 224 130 225 // when CtxSwitch returns we are back in the processor coroutine … … 135 230 } 136 231 137 //----------------------------------------------------------------------------- 138 // Kernel runner (Temporary) 139 140 void scheduler_add( struct thread_h * thrd ) { 141 LIB_DEBUG_PRINTF("Kernel : scheduling %p on core %p (%d spots)\n", thrd, systemProcessor, systemProcessor->thread_count); 142 for(int i = 0; i < systemProcessor->thread_count; i++) { 143 if(systemProcessor->threads[i] == NULL) { 144 systemProcessor->threads[i] = thrd; 145 return; 232 void * 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 271 void 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 286 void 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 293 thread * nextThread(cluster * this) { 294 pthread_spinlock_guard guard = { &this->lock }; 295 return pop_head( &this->ready_queue ); 296 } 297 298 //----------------------------------------------------------------------------- 299 // Kernel boot procedures 300 void 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 351 void 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 376 void ?{}( simple_lock * this ) { 377 ( &this->blocked ){}; 378 } 379 380 void ^?{}( simple_lock * this ) { 381 382 } 383 384 void 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 392 void unlock( simple_lock * this ) { 393 thread * it; 394 while( it = pop_head( &this->blocked) ) { 395 thread_schedule( it ); 396 } 397 } 398 399 //----------------------------------------------------------------------------- 400 // Queues 401 void ?{}( simple_thread_list * this ) { 402 this->head = NULL; 403 this->tail = &this->head; 404 } 405 406 void append( simple_thread_list * this, thread * t ) { 407 assert( t->next == NULL ); 408 *this->tail = t; 409 this->tail = &t->next; 410 } 411 412 thread * 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; 146 418 } 147 } 148 assert(false); 149 } 150 151 void scheduler_remove( struct thread_h * thrd ) { 152 LIB_DEBUG_PRINTF("Kernel : unscheduling %p from core %p\n", thrd, systemProcessor); 153 for(int i = 0; i < systemProcessor->thread_count; i++) { 154 if(systemProcessor->threads[i] == thrd) { 155 systemProcessor->threads[i] = NULL; 156 break; 157 } 158 } 159 for(int i = 0; i < systemProcessor->thread_count; i++) { 160 if(systemProcessor->threads[i] != NULL) { 161 return; 162 } 163 } 164 LIB_DEBUG_PRINTF("Kernel : terminating core %p\n\n\n", systemProcessor); 165 systemProcessor->terminated = true; 166 } 167 168 void kernel_run( void ) { 169 CtxInvokeProcessor(systemProcessor); 170 } 171 419 head->next = NULL; 420 } 421 422 return head; 423 } 172 424 // Local Variables: // 173 425 // mode: c //
Note:
See TracChangeset
for help on using the changeset viewer.