Changes in src/libcfa/concurrency/kernel.c [eafb094:77e6fcb]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (21 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
reafb094 r77e6fcb 9 9 // 10 10 // Author : Thierry Delisle 11 // Created On : Tue Jan 17 12:27:26 201 711 // Created On : Tue Jan 17 12:27:26 2016 12 12 // Last Modified By : Thierry Delisle 13 13 // Last Modified On : -- … … 20 20 21 21 //Header 22 #include "kernel _private.h"22 #include "kernel" 23 23 24 24 //C Includes 25 25 #include <stddef.h> 26 26 extern "C" { 27 #include <fenv.h>28 27 #include <sys/resource.h> 29 28 } … … 31 30 //CFA Includes 32 31 #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 40 47 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)] 41 48 … … 85 92 86 93 rlimit r; 87 getrlimit( RLIMIT_STACK, &r);94 int ret = getrlimit( RLIMIT_STACK, &r); 88 95 this->size = r.rlim_cur; 89 96 … … 107 114 this->name = "Main Thread"; 108 115 this->errno_ = 0; 109 this->state = Start; 116 this->state = Inactive; 117 this->notHalted = true; 110 118 } 111 119 … … 119 127 (&this->c){}; 120 128 this->proc = proc; 121 proc-> runner= this;129 proc->ctx = this; 122 130 } 123 131 … … 125 133 (&this->c){ info }; 126 134 this->proc = proc; 127 proc->runner = this; 128 } 135 proc->ctx = this; 136 } 137 138 void start(processor * this); 129 139 130 140 void ?{}(processor * this) { … … 136 146 this->current_coroutine = NULL; 137 147 this->current_thread = NULL; 138 (&this-> terminated){};139 this-> is_terminated = false;148 (&this->lock){}; 149 this->terminated = false; 140 150 141 151 start( this ); 142 152 } 143 153 144 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) {154 void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) { 145 155 this->cltr = cltr; 146 156 this->current_coroutine = NULL; 147 157 this->current_thread = NULL; 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 };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 }; 154 164 } 155 165 156 166 void ^?{}(processor * this) { 157 if( ! this-> is_terminated ) {167 if( ! this->terminated ) { 158 168 LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this); 159 this-> is_terminated = true;160 wait( &this->terminated);169 this->terminated = true; 170 lock( &this->lock ); 161 171 } 162 172 } … … 164 174 void ?{}(cluster * this) { 165 175 ( &this->ready_queue ){}; 166 ( &this->lock ){};176 pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE ); 167 177 } 168 178 169 179 void ^?{}(cluster * this) { 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; 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; 179 192 LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this); 180 193 181 194 thread * readyThread = NULL; 182 for( unsigned int spin_count = 0; ! this-> is_terminated; spin_count++ )183 {195 for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) { 196 184 197 readyThread = nextThread( this->cltr ); 185 198 186 if(readyThread) 187 { 188 runThread(this, readyThread); 189 190 //Some actions need to be taken from the kernel 191 finishRunning(this); 192 199 if(readyThread) { 200 scheduleInternal(this, readyThread); 193 201 spin_count = 0; 194 } 195 else 196 { 202 } else { 197 203 spin(this, &spin_count); 198 204 } … … 200 206 201 207 LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this); 202 signal( &this->terminated);208 unlock( &this->lock ); 203 209 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this); 204 210 } 205 211 206 // runThread runs a thread by context switching 212 //Declarations for scheduleInternal 213 extern void ThreadCtxSwitch(coroutine * src, coroutine * dst); 214 215 // scheduleInternal runs a thread by context switching 207 216 // from the processor coroutine to the target thread 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 } 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 239 242 } 240 243 … … 259 262 processorCtx_t proc_cor_storage = { proc, &info }; 260 263 261 LIB_DEBUG_PRINTF("Coroutine : created stack %p\n", proc_cor_storage.c.stack.base);262 263 264 //Set global state 264 proc->current_coroutine = &proc-> runner->c;265 proc->current_coroutine = &proc->ctx->c; 265 266 proc->current_thread = NULL; 266 267 267 268 //We now have a proper context from which to schedule threads 268 LIB_DEBUG_PRINTF("Kernel : core %p created (%p , %p)\n", proc, proc->runner, &ctx);269 LIB_DEBUG_PRINTF("Kernel : core %p created (%p)\n", proc, proc->ctx); 269 270 270 271 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't … … 274 275 proc_cor_storage.c.state = Active; 275 276 main( &proc_cor_storage ); 276 proc_cor_storage.c.state = Halted; 277 proc_cor_storage.c.state = Halt; 278 proc_cor_storage.c.notHalted = false; 277 279 278 280 // Main routine of the core returned, the core is now fully terminated 279 LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc-> runner);281 LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->ctx); 280 282 281 283 return NULL; … … 285 287 LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this); 286 288 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 );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 ); 293 295 294 296 LIB_DEBUG_PRINTF("Kernel : core %p started\n", this); … … 297 299 //----------------------------------------------------------------------------- 298 300 // Scheduler routines 299 void ScheduleThread( thread * thrd ) {301 void thread_schedule( thread * thrd ) { 300 302 assertf( thrd->next == NULL, "Expected null got %p", thrd->next ); 301 303 302 lock( &systemProcessor->cltr->lock );304 pthread_spinlock_guard guard = { &systemProcessor->cltr->lock }; 303 305 append( &systemProcessor->cltr->ready_queue, thrd ); 304 unlock( &systemProcessor->cltr->lock );305 306 } 306 307 307 308 thread * nextThread(cluster * this) { 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(); 309 pthread_spinlock_guard guard = { &this->lock }; 310 return pop_head( &this->ready_queue ); 335 311 } 336 312 … … 338 314 // Kernel boot procedures 339 315 void kernel_startup(void) { 340 LIB_DEBUG_PRINTF("Kernel : Starting\n"); 341 342 // Start by initializing the main thread 316 343 317 // SKULLDUGGERY: the mainThread steals the process main thread 344 318 // which will then be scheduled by the systemProcessor normally 319 LIB_DEBUG_PRINTF("Kernel : Starting\n"); 320 321 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 thread 345 331 mainThread = (thread *)&mainThread_storage; 346 current_stack_info_t info;347 332 mainThread{ &info }; 348 333 … … 358 343 // Add the main thread to the ready queue 359 344 // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread 360 ScheduleThread(mainThread);345 thread_schedule(mainThread); 361 346 362 347 //initialize the global state variables … … 368 353 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 369 354 // mainThread is on the ready queue when this call is made. 370 resume(systemProcessor-> runner);355 resume(systemProcessor->ctx); 371 356 372 357 373 358 374 359 // THE SYSTEM IS NOW COMPLETELY RUNNING 360 361 362 375 363 LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n"); 376 364 } … … 382 370 // When its coroutine terminates, it return control to the mainThread 383 371 // which is currently here 384 systemProcessor-> is_terminated = true;372 systemProcessor->terminated = true; 385 373 suspend(); 386 374 … … 389 377 // Destroy the system processor and its context in reverse order of construction 390 378 // These were manually constructed so we need manually destroy them 391 ^(systemProcessor-> runner){};379 ^(systemProcessor->ctx){}; 392 380 ^(systemProcessor){}; 393 381 … … 401 389 //----------------------------------------------------------------------------- 402 390 // Locks 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; 391 void ?{}( simple_lock * this ) { 392 ( &this->blocked ){}; 393 } 394 395 void ^?{}( simple_lock * this ) { 396 397 } 398 399 void lock( simple_lock * this ) { 400 { 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() ); 413 403 } 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 ); 404 suspend(); 405 } 406 407 void unlock( simple_lock * this ) { 408 thread * it; 409 while( it = pop_head( &this->blocked) ) { 410 thread_schedule( it ); 433 411 } 434 unlock( &this->lock );435 }436 437 void signal( signal_once * this ) {438 lock( &this->lock );439 {440 this->condition = true;441 442 thread * it;443 while( it = pop_head( &this->blocked) ) {444 ScheduleThread( it );445 }446 }447 unlock( &this->lock );448 412 } 449 413
Note:
See TracChangeset
for help on using the changeset viewer.