Changes in src/libcfa/concurrency/kernel.c [77e6fcb:eafb094]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (21 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
r77e6fcb reafb094 9 9 // 10 10 // Author : Thierry Delisle 11 // Created On : Tue Jan 17 12:27:26 201 611 // Created On : Tue Jan 17 12:27:26 2017 12 12 // Last Modified By : Thierry Delisle 13 13 // Last Modified On : -- … … 20 20 21 21 //Header 22 #include "kernel "22 #include "kernel_private.h" 23 23 24 24 //C Includes 25 25 #include <stddef.h> 26 26 extern "C" { 27 #include <fenv.h> 27 28 #include <sys/resource.h> 28 29 } … … 30 31 //CFA Includes 31 32 #include "libhdr.h" 32 #include "threads"33 33 34 34 //Private includes … … 38 38 //----------------------------------------------------------------------------- 39 39 // Kernel storage 40 struct processorCtx_t {41 processor * proc;42 coroutine c;43 };44 45 DECL_COROUTINE(processorCtx_t);46 47 40 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)] 48 41 … … 92 85 93 86 rlimit r; 94 int ret =getrlimit( RLIMIT_STACK, &r);87 getrlimit( RLIMIT_STACK, &r); 95 88 this->size = r.rlim_cur; 96 89 … … 114 107 this->name = "Main Thread"; 115 108 this->errno_ = 0; 116 this->state = Inactive; 117 this->notHalted = true; 109 this->state = Start; 118 110 } 119 111 … … 127 119 (&this->c){}; 128 120 this->proc = proc; 129 proc-> ctx= this;121 proc->runner = this; 130 122 } 131 123 … … 133 125 (&this->c){ info }; 134 126 this->proc = proc; 135 proc->ctx = this; 136 } 137 138 void start(processor * this); 127 proc->runner = this; 128 } 139 129 140 130 void ?{}(processor * this) { … … 146 136 this->current_coroutine = NULL; 147 137 this->current_thread = NULL; 148 (&this-> lock){};149 this-> terminated = false;138 (&this->terminated){}; 139 this->is_terminated = false; 150 140 151 141 start( this ); 152 142 } 153 143 154 void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) {144 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 155 145 this->cltr = cltr; 156 146 this->current_coroutine = NULL; 157 147 this->current_thread = NULL; 158 (&this-> lock){};159 this-> terminated = false;160 161 this-> ctx = ctx;162 LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", ctx);163 ctx{ this };148 (&this->terminated){}; 149 this->is_terminated = false; 150 151 this->runner = runner; 152 LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", runner); 153 runner{ this }; 164 154 } 165 155 166 156 void ^?{}(processor * this) { 167 if( ! this-> terminated ) {157 if( ! this->is_terminated ) { 168 158 LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this); 169 this-> terminated = true;170 lock( &this->lock);159 this->is_terminated = true; 160 wait( &this->terminated ); 171 161 } 172 162 } … … 174 164 void ?{}(cluster * this) { 175 165 ( &this->ready_queue ){}; 176 pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );166 ( &this->lock ){}; 177 167 } 178 168 179 169 void ^?{}(cluster * this) { 180 pthread_spin_destroy( &this->lock ); 181 } 182 183 //----------------------------------------------------------------------------- 184 // Processor running routines 185 void main(processorCtx_t * ctx); 186 thread * nextThread(cluster * this); 187 void scheduleInternal(processor * this, thread * dst); 188 void spin(processor * this, unsigned int * spin_count); 189 190 void main(processorCtx_t * ctx) { 191 processor * this = ctx->proc; 170 171 } 172 173 //============================================================================================= 174 // Kernel Scheduling logic 175 //============================================================================================= 176 //Main of the processor contexts 177 void main(processorCtx_t * runner) { 178 processor * this = runner->proc; 192 179 LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this); 193 180 194 181 thread * readyThread = NULL; 195 for( unsigned int spin_count = 0; ! this-> terminated; spin_count++ ) {196 182 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 183 { 197 184 readyThread = nextThread( this->cltr ); 198 185 199 if(readyThread) { 200 scheduleInternal(this, readyThread); 186 if(readyThread) 187 { 188 runThread(this, readyThread); 189 190 //Some actions need to be taken from the kernel 191 finishRunning(this); 192 201 193 spin_count = 0; 202 } else { 194 } 195 else 196 { 203 197 spin(this, &spin_count); 204 198 } … … 206 200 207 201 LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this); 208 unlock( &this->lock);202 signal( &this->terminated ); 209 203 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this); 210 204 } 211 205 212 //Declarations for scheduleInternal 213 extern void ThreadCtxSwitch(coroutine * src, coroutine * dst); 214 215 // scheduleInternal runs a thread by context switching 206 // runThread runs a thread by context switching 216 207 // from the processor coroutine to the target thread 217 void scheduleInternal(processor * this, thread * dst) { 218 // coroutine * proc_ctx = get_coroutine(this->ctx); 219 // coroutine * thrd_ctx = get_coroutine(dst); 220 221 // //Update global state 222 // this->current_thread = dst; 223 224 // // Context Switch to the thread 225 // ThreadCtxSwitch(proc_ctx, thrd_ctx); 226 // // when ThreadCtxSwitch returns we are back in the processor coroutine 227 228 coroutine * proc_ctx = get_coroutine(this->ctx); 229 coroutine * thrd_ctx = get_coroutine(dst); 230 thrd_ctx->last = proc_ctx; 231 232 // context switch to specified coroutine 233 // Which is now the current_coroutine 234 LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, this->current_coroutine); 235 this->current_thread = dst; 236 this->current_coroutine = thrd_ctx; 237 CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context ); 238 this->current_coroutine = proc_ctx; 239 LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, this->current_coroutine); 240 241 // when CtxSwitch returns we are back in the processor coroutine 208 void runThread(processor * this, thread * dst) { 209 coroutine * proc_cor = get_coroutine(this->runner); 210 coroutine * thrd_cor = get_coroutine(dst); 211 212 //Reset the terminating actions here 213 this->finish.action_code = No_Action; 214 215 //Update global state 216 this->current_thread = dst; 217 218 // Context Switch to the thread 219 ThreadCtxSwitch(proc_cor, thrd_cor); 220 // when ThreadCtxSwitch returns we are back in the processor coroutine 221 } 222 223 // Once a thread has finished running, some of 224 // its final actions must be executed from the kernel 225 void finishRunning(processor * this) { 226 if( this->finish.action_code == Release ) { 227 unlock( this->finish.lock ); 228 } 229 else if( this->finish.action_code == Schedule ) { 230 ScheduleThread( this->finish.thrd ); 231 } 232 else if( this->finish.action_code == Release_Schedule ) { 233 unlock( this->finish.lock ); 234 ScheduleThread( this->finish.thrd ); 235 } 236 else { 237 assert(this->finish.action_code == No_Action); 238 } 242 239 } 243 240 … … 262 259 processorCtx_t proc_cor_storage = { proc, &info }; 263 260 261 LIB_DEBUG_PRINTF("Coroutine : created stack %p\n", proc_cor_storage.c.stack.base); 262 264 263 //Set global state 265 proc->current_coroutine = &proc-> ctx->c;264 proc->current_coroutine = &proc->runner->c; 266 265 proc->current_thread = NULL; 267 266 268 267 //We now have a proper context from which to schedule threads 269 LIB_DEBUG_PRINTF("Kernel : core %p created (%p )\n", proc, proc->ctx);268 LIB_DEBUG_PRINTF("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 270 269 271 270 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't … … 275 274 proc_cor_storage.c.state = Active; 276 275 main( &proc_cor_storage ); 277 proc_cor_storage.c.state = Halt; 278 proc_cor_storage.c.notHalted = false; 276 proc_cor_storage.c.state = Halted; 279 277 280 278 // Main routine of the core returned, the core is now fully terminated 281 LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc-> ctx);279 LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->runner); 282 280 283 281 return NULL; … … 287 285 LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this); 288 286 289 pthread_attr_t attributes;290 pthread_attr_init( &attributes );291 292 pthread_create( &this->kernel_thread, &attributes, CtxInvokeProcessor, (void*)this );293 294 pthread_attr_destroy( &attributes );287 // pthread_attr_t attributes; 288 // pthread_attr_init( &attributes ); 289 290 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 291 292 // pthread_attr_destroy( &attributes ); 295 293 296 294 LIB_DEBUG_PRINTF("Kernel : core %p started\n", this); … … 299 297 //----------------------------------------------------------------------------- 300 298 // Scheduler routines 301 void thread_schedule( thread * thrd ) {299 void ScheduleThread( thread * thrd ) { 302 300 assertf( thrd->next == NULL, "Expected null got %p", thrd->next ); 303 301 304 pthread_spinlock_guard guard = { &systemProcessor->cltr->lock };302 lock( &systemProcessor->cltr->lock ); 305 303 append( &systemProcessor->cltr->ready_queue, thrd ); 304 unlock( &systemProcessor->cltr->lock ); 306 305 } 307 306 308 307 thread * nextThread(cluster * this) { 309 pthread_spinlock_guard guard = { &this->lock }; 310 return pop_head( &this->ready_queue ); 308 lock( &this->lock ); 309 thread * head = pop_head( &this->ready_queue ); 310 unlock( &this->lock ); 311 return head; 312 } 313 314 void ScheduleInternal() { 315 suspend(); 316 } 317 318 void ScheduleInternal( spinlock * lock ) { 319 get_this_processor()->finish.action_code = Release; 320 get_this_processor()->finish.lock = lock; 321 suspend(); 322 } 323 324 void ScheduleInternal( thread * thrd ) { 325 get_this_processor()->finish.action_code = Schedule; 326 get_this_processor()->finish.thrd = thrd; 327 suspend(); 328 } 329 330 void ScheduleInternal( spinlock * lock, thread * thrd ) { 331 get_this_processor()->finish.action_code = Release_Schedule; 332 get_this_processor()->finish.lock = lock; 333 get_this_processor()->finish.thrd = thrd; 334 suspend(); 311 335 } 312 336 … … 314 338 // Kernel boot procedures 315 339 void kernel_startup(void) { 316 340 LIB_DEBUG_PRINTF("Kernel : Starting\n"); 341 342 // Start by initializing the main thread 317 343 // SKULLDUGGERY: the mainThread steals the process main thread 318 344 // which will then be scheduled by the systemProcessor normally 319 LIB_DEBUG_PRINTF("Kernel : Starting\n"); 320 345 mainThread = (thread *)&mainThread_storage; 321 346 current_stack_info_t info; 322 323 // LIB_DEBUG_PRINTF("Kernel : core base : %p \n", info.base );324 // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );325 // LIB_DEBUG_PRINTF("Kernel : core size : %x \n", info.size );326 // LIB_DEBUG_PRINTF("Kernel : core limit : %p \n", info.limit );327 // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );328 // LIB_DEBUG_PRINTF("Kernel : core top : %p \n", info.top );329 330 // Start by initializing the main thread331 mainThread = (thread *)&mainThread_storage;332 347 mainThread{ &info }; 333 348 … … 343 358 // Add the main thread to the ready queue 344 359 // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread 345 thread_schedule(mainThread);360 ScheduleThread(mainThread); 346 361 347 362 //initialize the global state variables … … 353 368 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 354 369 // mainThread is on the ready queue when this call is made. 355 resume(systemProcessor-> ctx);370 resume(systemProcessor->runner); 356 371 357 372 358 373 359 374 // THE SYSTEM IS NOW COMPLETELY RUNNING 360 361 362 363 375 LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n"); 364 376 } … … 370 382 // When its coroutine terminates, it return control to the mainThread 371 383 // which is currently here 372 systemProcessor-> terminated = true;384 systemProcessor->is_terminated = true; 373 385 suspend(); 374 386 … … 377 389 // Destroy the system processor and its context in reverse order of construction 378 390 // These were manually constructed so we need manually destroy them 379 ^(systemProcessor-> ctx){};391 ^(systemProcessor->runner){}; 380 392 ^(systemProcessor){}; 381 393 … … 389 401 //----------------------------------------------------------------------------- 390 402 // Locks 391 void ?{}( simple_lock * this ) { 392 ( &this->blocked ){}; 393 } 394 395 void ^?{}( simple_lock * this ) { 396 397 } 398 399 void lock( simple_lock * this ) { 403 void ?{}( spinlock * this ) { 404 this->lock = 0; 405 } 406 void ^?{}( spinlock * this ) { 407 408 } 409 410 void lock( spinlock * this ) { 411 for ( unsigned int i = 1;; i += 1 ) { 412 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 413 } 414 } 415 416 void unlock( spinlock * this ) { 417 __sync_lock_release_4( &this->lock ); 418 } 419 420 void ?{}( signal_once * this ) { 421 this->condition = false; 422 } 423 void ^?{}( signal_once * this ) { 424 425 } 426 427 void wait( signal_once * this ) { 428 lock( &this->lock ); 429 if( !this->condition ) { 430 append( &this->blocked, this_thread() ); 431 ScheduleInternal( &this->lock ); 432 lock( &this->lock ); 433 } 434 unlock( &this->lock ); 435 } 436 437 void signal( signal_once * this ) { 438 lock( &this->lock ); 400 439 { 401 pthread_spinlock_guard guard = { &systemCluster->lock }; //HUGE TEMP HACK which only works if we have a single cluster and is stupid 402 append( &this->blocked, this_thread() ); 403 } 404 suspend(); 405 } 406 407 void unlock( simple_lock * this ) { 408 thread * it; 409 while( it = pop_head( &this->blocked) ) { 410 thread_schedule( it ); 411 } 440 this->condition = true; 441 442 thread * it; 443 while( it = pop_head( &this->blocked) ) { 444 ScheduleThread( it ); 445 } 446 } 447 unlock( &this->lock ); 412 448 } 413 449
Note:
See TracChangeset
for help on using the changeset viewer.