Changes in / [307a732:67fa9f9]
- Location:
- src
- Files:
-
- 5 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
src/benchmark/CorCtxSwitch.c
r307a732 r67fa9f9 31 31 32 32 StartTime = Time(); 33 // for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {34 // resume( this_coroutine() );35 // // resume( &s );36 // }37 33 resumer( &s, NoOfTimes ); 38 34 EndTime = Time(); -
src/benchmark/csv-data.c
r307a732 r67fa9f9 38 38 39 39 StartTime = Time(); 40 // for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {41 // resume( this_coroutine() );42 // // resume( &s );43 // }44 40 resumer( &s, NoOfTimes ); 45 41 EndTime = Time(); -
src/libcfa/concurrency/alarm.c
r307a732 r67fa9f9 16 16 17 17 extern "C" { 18 #include <errno.h> 19 #include <stdio.h> 20 #include <string.h> 18 21 #include <time.h> 22 #include <unistd.h> 19 23 #include <sys/time.h> 20 24 } 25 26 #include "libhdr.h" 21 27 22 28 #include "alarm.h" … … 31 37 timespec curr; 32 38 clock_gettime( CLOCK_REALTIME, &curr ); 33 return ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; 39 __cfa_time_t curr_time = ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; 40 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : current time is %lu\n", curr_time ); 41 return curr_time; 34 42 } 35 43 36 44 void __kernel_set_timer( __cfa_time_t alarm ) { 45 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : set timer to %lu\n", (__cfa_time_t)alarm ); 37 46 itimerval val; 38 47 val.it_value.tv_sec = alarm / TIMEGRAN; // seconds … … 71 80 } 72 81 82 LIB_DEBUG_DO( bool validate( alarm_list_t * this ) { 83 alarm_node_t ** it = &this->head; 84 while( (*it) ) { 85 it = &(*it)->next; 86 } 87 88 return it == this->tail; 89 }) 90 73 91 static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { 74 assert( !n->next );92 verify( !n->next ); 75 93 if( p == this->tail ) { 76 94 this->tail = &n->next; … … 80 98 } 81 99 *p = n; 100 101 verify( validate( this ) ); 82 102 } 83 103 … … 89 109 90 110 insert_at( this, n, it ); 111 112 verify( validate( this ) ); 91 113 } 92 114 … … 100 122 head->next = NULL; 101 123 } 124 verify( validate( this ) ); 102 125 return head; 103 126 } … … 105 128 static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) { 106 129 verify( it ); 107 verify( (*it) ->next== n );130 verify( (*it) == n ); 108 131 109 (*it) ->next= n->next;132 (*it) = n->next; 110 133 if( !n-> next ) { 111 134 this->tail = it; 112 135 } 113 136 n->next = NULL; 137 138 verify( validate( this ) ); 114 139 } 115 140 116 141 static inline void remove( alarm_list_t * this, alarm_node_t * n ) { 117 142 alarm_node_t ** it = &this->head; 118 while( (*it) && (*it) ->next!= n ) {143 while( (*it) && (*it) != n ) { 119 144 it = &(*it)->next; 120 145 } 121 146 147 verify( validate( this ) ); 148 122 149 if( *it ) { remove_at( this, n, it ); } 150 151 verify( validate( this ) ); 123 152 } 124 153 125 154 void register_self( alarm_node_t * this ) { 126 155 disable_interrupts(); 127 assert( !systemProcessor->pending_alarm );128 lock( &systemProcessor->alarm_lock );156 verify( !systemProcessor->pending_alarm ); 157 lock( &systemProcessor->alarm_lock DEBUG_CTX2 ); 129 158 { 159 verify( validate( &systemProcessor->alarms ) ); 160 bool first = !systemProcessor->alarms.head; 161 130 162 insert( &systemProcessor->alarms, this ); 131 163 if( systemProcessor->pending_alarm ) { 132 164 tick_preemption(); 133 165 } 166 if( first ) { 167 __kernel_set_timer( systemProcessor->alarms.head->alarm - __kernel_get_time() ); 168 } 134 169 } 135 170 unlock( &systemProcessor->alarm_lock ); 136 171 this->set = true; 137 enable_interrupts( );172 enable_interrupts( DEBUG_CTX ); 138 173 } 139 174 140 175 void unregister_self( alarm_node_t * this ) { 176 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : unregister %p start\n", this ); 141 177 disable_interrupts(); 142 lock( &systemProcessor->alarm_lock ); 143 remove( &systemProcessor->alarms, this ); 178 lock( &systemProcessor->alarm_lock DEBUG_CTX2 ); 179 { 180 verify( validate( &systemProcessor->alarms ) ); 181 remove( &systemProcessor->alarms, this ); 182 } 144 183 unlock( &systemProcessor->alarm_lock ); 145 disable_interrupts();184 enable_interrupts( DEBUG_CTX ); 146 185 this->set = false; 186 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Kernel : unregister %p end\n", this ); 147 187 } -
src/libcfa/concurrency/coroutine
r307a732 r67fa9f9 63 63 64 64 // Get current coroutine 65 coroutine_desc * this_coroutine(void);65 extern volatile thread_local coroutine_desc * this_coroutine; 66 66 67 67 // Private wrappers for context switch and stack creation … … 71 71 // Suspend implementation inlined for performance 72 72 static inline void suspend() { 73 coroutine_desc * src = this_coroutine (); // optimization73 coroutine_desc * src = this_coroutine; // optimization 74 74 75 75 assertf( src->last != 0, … … 88 88 forall(dtype T | is_coroutine(T)) 89 89 static inline void resume(T * cor) { 90 coroutine_desc * src = this_coroutine (); // optimization90 coroutine_desc * src = this_coroutine; // optimization 91 91 coroutine_desc * dst = get_coroutine(cor); 92 92 … … 112 112 113 113 static inline void resume(coroutine_desc * dst) { 114 coroutine_desc * src = this_coroutine (); // optimization114 coroutine_desc * src = this_coroutine; // optimization 115 115 116 116 // not resuming self ? -
src/libcfa/concurrency/coroutine.c
r307a732 r67fa9f9 32 32 #include "invoke.h" 33 33 34 extern thread_local processor * this_processor;34 extern volatile thread_local processor * this_processor; 35 35 36 36 //----------------------------------------------------------------------------- … … 44 44 // Coroutine ctors and dtors 45 45 void ?{}(coStack_t* this) { 46 this->size = 10240; // size of stack46 this->size = 65000; // size of stack 47 47 this->storage = NULL; // pointer to stack 48 48 this->limit = NULL; // stack grows towards stack limit … … 50 50 this->context = NULL; // address of cfa_context_t 51 51 this->top = NULL; // address of top of storage 52 this->userStack = false; 52 this->userStack = false; 53 53 } 54 54 … … 106 106 107 107 // set state of current coroutine to inactive 108 src->state = Inactive;108 src->state = src->state == Halted ? Halted : Inactive; 109 109 110 110 // set new coroutine that task is executing 111 this_ processor->current_coroutine = dst;111 this_coroutine = dst; 112 112 113 113 // context switch to specified coroutine 114 assert( src->stack.context ); 114 115 CtxSwitch( src->stack.context, dst->stack.context ); 115 // when CtxSwitch returns we are back in the src coroutine 116 // when CtxSwitch returns we are back in the src coroutine 116 117 117 118 // set state of new coroutine to active … … 131 132 this->size = libCeiling( storageSize, 16 ); 132 133 // use malloc/memalign because "new" raises an exception for out-of-memory 133 134 134 135 // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment 135 136 LIB_DEBUG_DO( this->storage = memalign( pageSize, cxtSize + this->size + pageSize ) ); -
src/libcfa/concurrency/invoke.c
r307a732 r67fa9f9 29 29 30 30 extern void __suspend_internal(void); 31 extern void __leave_monitor_desc( struct monitor_desc * this ); 31 extern void __leave_thread_monitor( struct thread_desc * this ); 32 extern void disable_interrupts(); 33 extern void enable_interrupts( DEBUG_CTX_PARAM ); 32 34 33 35 void CtxInvokeCoroutine( 34 void (*main)(void *), 35 struct coroutine_desc *(*get_coroutine)(void *), 36 void (*main)(void *), 37 struct coroutine_desc *(*get_coroutine)(void *), 36 38 void *this 37 39 ) { … … 56 58 57 59 void CtxInvokeThread( 58 void (*dtor)(void *), 59 void (*main)(void *), 60 struct thread_desc *(*get_thread)(void *), 60 void (*dtor)(void *), 61 void (*main)(void *), 62 struct thread_desc *(*get_thread)(void *), 61 63 void *this 62 64 ) { 65 // First suspend, once the thread arrives here, 66 // the function pointer to main can be invalidated without risk 63 67 __suspend_internal(); 64 68 69 // Fetch the thread handle from the user defined thread structure 65 70 struct thread_desc* thrd = get_thread( this ); 66 struct coroutine_desc* cor = &thrd->cor;67 struct monitor_desc* mon = &thrd->mon;68 cor->state = Active;69 71 70 // LIB_DEBUG_PRINTF("Invoke Thread : invoking main %p (args %p)\n", main, this); 72 // Officially start the thread by enabling preemption 73 enable_interrupts( DEBUG_CTX ); 74 75 // Call the main of the thread 71 76 main( this ); 72 77 73 __leave_monitor_desc( mon ); 78 // To exit a thread we must : 79 // 1 - Mark it as halted 80 // 2 - Leave its monitor 81 // 3 - Disable the interupts 82 // The order of these 3 operations is very important 83 __leave_thread_monitor( thrd ); 74 84 75 85 //Final suspend, should never return … … 80 90 81 91 void CtxStart( 82 void (*main)(void *), 83 struct coroutine_desc *(*get_coroutine)(void *), 84 void *this, 92 void (*main)(void *), 93 struct coroutine_desc *(*get_coroutine)(void *), 94 void *this, 85 95 void (*invoke)(void *) 86 96 ) { … … 108 118 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke; 109 119 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520 110 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 120 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 111 121 112 122 #elif defined( __x86_64__ ) … … 128 138 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke; 129 139 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520 130 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 140 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 131 141 #else 132 142 #error Only __i386__ and __x86_64__ is supported for threads in cfa -
src/libcfa/concurrency/invoke.h
r307a732 r67fa9f9 31 31 struct spinlock { 32 32 volatile int lock; 33 #ifdef __CFA_DEBUG__ 34 const char * prev_name; 35 void* prev_thrd; 36 #endif 33 37 }; 34 38 … … 83 87 struct __thread_queue_t entry_queue; // queue of threads that are blocked waiting for the monitor 84 88 struct __condition_stack_t signal_stack; // stack of conditions to run next once we exit the monitor 85 struct monitor_desc * stack_owner; // if bulk acquiring was used we need to synchronize signals with an other monitor86 89 unsigned int recursion; // monitor routines can be called recursively, we need to keep track of that 87 90 }; … … 99 102 #ifndef _INVOKE_PRIVATE_H_ 100 103 #define _INVOKE_PRIVATE_H_ 101 104 102 105 struct machine_context_t { 103 106 void *SP; -
src/libcfa/concurrency/kernel
r307a732 r67fa9f9 28 28 //----------------------------------------------------------------------------- 29 29 // Locks 30 bool try_lock( spinlock * ); 31 void lock( spinlock * ); 32 void unlock( spinlock * ); 30 bool try_lock ( spinlock * DEBUG_CTX_PARAM2 ); 31 void lock ( spinlock * DEBUG_CTX_PARAM2 ); 32 void lock_yield( spinlock * DEBUG_CTX_PARAM2 ); 33 void unlock ( spinlock * ); 33 34 34 35 struct signal_once { … … 68 69 unsigned short thrd_count; 69 70 }; 70 static inline void ?{}(FinishAction * this) { 71 static inline void ?{}(FinishAction * this) { 71 72 this->action_code = No_Action; 72 73 this->thrd = NULL; … … 78 79 struct processorCtx_t * runner; 79 80 cluster * cltr; 80 coroutine_desc * current_coroutine;81 thread_desc * current_thread;82 81 pthread_t kernel_thread; 83 82 84 83 signal_once terminated; 85 84 volatile bool is_terminated; … … 90 89 unsigned int preemption; 91 90 92 unsigned short disable_preempt_count;91 bool pending_preemption; 93 92 94 bool pending_preemption;93 char * last_enable; 95 94 }; 96 95 -
src/libcfa/concurrency/kernel.c
r307a732 r67fa9f9 15 15 // 16 16 17 #include "startup.h" 18 19 //Start and stop routine for the kernel, declared first to make sure they run first 20 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 21 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 22 23 //Header 24 #include "kernel_private.h" 17 #include "libhdr.h" 25 18 26 19 //C Includes … … 35 28 36 29 //CFA Includes 37 #include " libhdr.h"30 #include "kernel_private.h" 38 31 #include "preemption.h" 32 #include "startup.h" 39 33 40 34 //Private includes 41 35 #define __CFA_INVOKE_PRIVATE__ 42 36 #include "invoke.h" 37 38 //Start and stop routine for the kernel, declared first to make sure they run first 39 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 40 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 43 41 44 42 //----------------------------------------------------------------------------- … … 59 57 // Global state 60 58 61 thread_local processor * this_processor; 62 63 coroutine_desc * this_coroutine(void) { 64 return this_processor->current_coroutine; 65 } 66 67 thread_desc * this_thread(void) { 68 return this_processor->current_thread; 69 } 59 volatile thread_local processor * this_processor; 60 volatile thread_local coroutine_desc * this_coroutine; 61 volatile thread_local thread_desc * this_thread; 62 volatile thread_local unsigned short disable_preempt_count = 1; 70 63 71 64 //----------------------------------------------------------------------------- 72 65 // Main thread construction 73 66 struct current_stack_info_t { 74 machine_context_t ctx; 67 machine_context_t ctx; 75 68 unsigned int size; // size of stack 76 69 void *base; // base of stack … … 106 99 107 100 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 108 (&this->stack){ info }; 101 (&this->stack){ info }; 109 102 this->name = "Main Thread"; 110 103 this->errno_ = 0; … … 136 129 void ?{}(processor * this, cluster * cltr) { 137 130 this->cltr = cltr; 138 this->current_coroutine = NULL;139 this->current_thread = NULL;140 131 (&this->terminated){}; 141 132 this->is_terminated = false; 142 133 this->preemption_alarm = NULL; 143 134 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled145 135 this->pending_preemption = false; 146 136 … … 150 140 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 151 141 this->cltr = cltr; 152 this->current_coroutine = NULL;153 this->current_thread = NULL;154 142 (&this->terminated){}; 155 143 this->is_terminated = false; 156 this->disable_preempt_count = 0; 144 this->preemption_alarm = NULL; 145 this->preemption = default_preemption(); 157 146 this->pending_preemption = false; 147 this->kernel_thread = pthread_self(); 158 148 159 149 this->runner = runner; 160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);150 LIB_DEBUG_PRINT_SAFE("Kernel : constructing system processor context %p\n", runner); 161 151 runner{ this }; 162 152 } 153 154 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); ) 163 155 164 156 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 168 160 169 161 (&this->proc){ cltr, runner }; 162 163 verify( validate( &this->alarms ) ); 170 164 } 171 165 … … 184 178 185 179 void ^?{}(cluster * this) { 186 180 187 181 } 188 182 … … 203 197 204 198 thread_desc * readyThread = NULL; 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 199 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 206 200 { 207 201 readyThread = nextThread( this->cltr ); … … 209 203 if(readyThread) 210 204 { 205 verify( disable_preempt_count > 0 ); 206 211 207 runThread(this, readyThread); 208 209 verify( disable_preempt_count > 0 ); 212 210 213 211 //Some actions need to be taken from the kernel … … 229 227 } 230 228 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 229 // runThread runs a thread by context switching 230 // from the processor coroutine to the target thread 233 231 void runThread(processor * this, thread_desc * dst) { 234 232 coroutine_desc * proc_cor = get_coroutine(this->runner); 235 233 coroutine_desc * thrd_cor = get_coroutine(dst); 236 234 237 235 //Reset the terminating actions here 238 236 this->finish.action_code = No_Action; 239 237 240 238 //Update global state 241 this ->current_thread = dst;239 this_thread = dst; 242 240 243 241 // Context Switch to the thread … … 246 244 } 247 245 248 // Once a thread has finished running, some of 246 // Once a thread has finished running, some of 249 247 // its final actions must be executed from the kernel 250 248 void finishRunning(processor * this) { … … 256 254 } 257 255 else if( this->finish.action_code == Release_Schedule ) { 258 unlock( this->finish.lock ); 256 unlock( this->finish.lock ); 259 257 ScheduleThread( this->finish.thrd ); 260 258 } … … 289 287 processor * proc = (processor *) arg; 290 288 this_processor = proc; 289 this_coroutine = NULL; 290 this_thread = NULL; 291 disable_preempt_count = 1; 291 292 // SKULLDUGGERY: We want to create a context for the processor coroutine 292 293 // which is needed for the 2-step context switch. However, there is no reason 293 // to waste the perfectly valid stack create by pthread. 294 // to waste the perfectly valid stack create by pthread. 294 295 current_stack_info_t info; 295 296 machine_context_t ctx; … … 300 301 301 302 //Set global state 302 proc->current_coroutine = &proc->runner->__cor;303 proc->current_thread = NULL;303 this_coroutine = &proc->runner->__cor; 304 this_thread = NULL; 304 305 305 306 //We now have a proper context from which to schedule threads 306 307 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 307 308 308 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 309 // resume it to start it like it normally would, it will just context switch 310 // back to here. Instead directly call the main since we already are on the 309 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 310 // resume it to start it like it normally would, it will just context switch 311 // back to here. Instead directly call the main since we already are on the 311 312 // appropriate stack. 312 313 proc_cor_storage.__cor.state = Active; … … 315 316 316 317 // Main routine of the core returned, the core is now fully terminated 317 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 318 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 318 319 319 320 return NULL; … … 322 323 void start(processor * this) { 323 324 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 324 325 325 326 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 326 327 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 329 } 329 330 … … 331 332 // Scheduler routines 332 333 void ScheduleThread( thread_desc * thrd ) { 333 if( !thrd ) return; 334 // if( !thrd ) return; 335 assert( thrd ); 336 assert( thrd->cor.state != Halted ); 337 338 verify( disable_preempt_count > 0 ); 334 339 335 340 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 336 337 lock( &systemProcessor->proc.cltr->lock );341 342 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2 ); 338 343 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 339 344 unlock( &systemProcessor->proc.cltr->lock ); 345 346 verify( disable_preempt_count > 0 ); 340 347 } 341 348 342 349 thread_desc * nextThread(cluster * this) { 343 lock( &this->lock ); 350 verify( disable_preempt_count > 0 ); 351 lock( &this->lock DEBUG_CTX2 ); 344 352 thread_desc * head = pop_head( &this->ready_queue ); 345 353 unlock( &this->lock ); 354 verify( disable_preempt_count > 0 ); 346 355 return head; 347 356 } 348 357 349 void ScheduleInternal() { 358 void BlockInternal() { 359 disable_interrupts(); 360 verify( disable_preempt_count > 0 ); 350 361 suspend(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 362 verify( disable_preempt_count > 0 ); 363 enable_interrupts( DEBUG_CTX ); 364 } 365 366 void BlockInternal( spinlock * lock ) { 367 disable_interrupts(); 354 368 this_processor->finish.action_code = Release; 355 369 this_processor->finish.lock = lock; 370 371 verify( disable_preempt_count > 0 ); 356 372 suspend(); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 373 verify( disable_preempt_count > 0 ); 374 375 enable_interrupts( DEBUG_CTX ); 376 } 377 378 void BlockInternal( thread_desc * thrd ) { 379 disable_interrupts(); 380 assert( thrd->cor.state != Halted ); 360 381 this_processor->finish.action_code = Schedule; 361 382 this_processor->finish.thrd = thrd; 383 384 verify( disable_preempt_count > 0 ); 362 385 suspend(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 386 verify( disable_preempt_count > 0 ); 387 388 enable_interrupts( DEBUG_CTX ); 389 } 390 391 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 392 disable_interrupts(); 366 393 this_processor->finish.action_code = Release_Schedule; 367 394 this_processor->finish.lock = lock; 368 395 this_processor->finish.thrd = thrd; 396 397 verify( disable_preempt_count > 0 ); 369 398 suspend(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 399 verify( disable_preempt_count > 0 ); 400 401 enable_interrupts( DEBUG_CTX ); 402 } 403 404 void BlockInternal(spinlock ** locks, unsigned short count) { 405 disable_interrupts(); 373 406 this_processor->finish.action_code = Release_Multi; 374 407 this_processor->finish.locks = locks; 375 408 this_processor->finish.lock_count = count; 409 410 verify( disable_preempt_count > 0 ); 376 411 suspend(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 412 verify( disable_preempt_count > 0 ); 413 414 enable_interrupts( DEBUG_CTX ); 415 } 416 417 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 418 disable_interrupts(); 380 419 this_processor->finish.action_code = Release_Multi_Schedule; 381 420 this_processor->finish.locks = locks; … … 383 422 this_processor->finish.thrds = thrds; 384 423 this_processor->finish.thrd_count = thrd_count; 424 425 verify( disable_preempt_count > 0 ); 385 426 suspend(); 427 verify( disable_preempt_count > 0 ); 428 429 enable_interrupts( DEBUG_CTX ); 386 430 } 387 431 … … 392 436 // Kernel boot procedures 393 437 void kernel_startup(void) { 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 438 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 395 439 396 440 // Start by initializing the main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 441 // SKULLDUGGERY: the mainThread steals the process main thread 398 442 // which will then be scheduled by the systemProcessor normally 399 443 mainThread = (thread_desc *)&mainThread_storage; … … 403 447 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 404 448 405 // Enable preemption406 kernel_start_preemption();407 408 449 // Initialize the system cluster 409 450 systemCluster = (cluster *)&systemCluster_storage; … … 417 458 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 418 459 419 // Add the main thread to the ready queue 460 // Add the main thread to the ready queue 420 461 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 421 462 ScheduleThread(mainThread); … … 423 464 //initialize the global state variables 424 465 this_processor = &systemProcessor->proc; 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 466 this_thread = mainThread; 467 this_coroutine = &mainThread->cor; 468 disable_preempt_count = 1; 469 470 // Enable preemption 471 kernel_start_preemption(); 427 472 428 473 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 429 474 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 430 // mainThread is on the ready queue when this call is made. 475 // mainThread is on the ready queue when this call is made. 431 476 resume( systemProcessor->proc.runner ); 432 477 … … 435 480 // THE SYSTEM IS NOW COMPLETELY RUNNING 436 481 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 482 483 enable_interrupts( DEBUG_CTX ); 437 484 } 438 485 439 486 void kernel_shutdown(void) { 440 487 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 488 489 disable_interrupts(); 441 490 442 491 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 448 497 // THE SYSTEM IS NOW COMPLETELY STOPPED 449 498 499 // Disable preemption 500 kernel_stop_preemption(); 501 450 502 // Destroy the system processor and its context in reverse order of construction 451 503 // These were manually constructed so we need manually destroy them … … 457 509 ^(mainThread){}; 458 510 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 511 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 460 512 } 461 513 … … 467 519 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 468 520 // the globalAbort flag is true. 469 lock( &kernel_abort_lock );521 lock( &kernel_abort_lock DEBUG_CTX2 ); 470 522 471 523 // first task to abort ? … … 473 525 kernel_abort_called = true; 474 526 unlock( &kernel_abort_lock ); 475 } 527 } 476 528 else { 477 529 unlock( &kernel_abort_lock ); 478 530 479 531 sigset_t mask; 480 532 sigemptyset( &mask ); … … 482 534 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 483 535 sigsuspend( &mask ); // block the processor to prevent further damage during abort 484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread ();536 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 537 } 538 539 return this_thread; 488 540 } 489 541 … … 494 546 __lib_debug_write( STDERR_FILENO, abort_text, len ); 495 547 496 if ( thrd != this_coroutine ()) {497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ()->name, this_coroutine());548 if ( thrd != this_coroutine ) { 549 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine ); 498 550 __lib_debug_write( STDERR_FILENO, abort_text, len ); 499 } 551 } 500 552 else { 501 553 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 505 557 extern "C" { 506 558 void __lib_debug_acquire() { 507 lock( &kernel_debug_lock);559 lock( &kernel_debug_lock DEBUG_CTX2 ); 508 560 } 509 561 510 562 void __lib_debug_release() { 511 unlock( &kernel_debug_lock);563 unlock( &kernel_debug_lock ); 512 564 } 513 565 } … … 525 577 } 526 578 527 bool try_lock( spinlock * this ) {579 bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) { 528 580 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 529 581 } 530 582 531 void lock( spinlock * this ) {583 void lock( spinlock * this DEBUG_CTX_PARAM2 ) { 532 584 for ( unsigned int i = 1;; i += 1 ) { 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 } 535 } 585 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 586 } 587 LIB_DEBUG_DO( 588 this->prev_name = caller; 589 this->prev_thrd = this_thread; 590 ) 591 } 592 593 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 594 for ( unsigned int i = 1;; i += 1 ) { 595 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 596 yield(); 597 } 598 LIB_DEBUG_DO( 599 this->prev_name = caller; 600 this->prev_thrd = this_thread; 601 ) 602 } 603 536 604 537 605 void unlock( spinlock * this ) { … … 547 615 548 616 void wait( signal_once * this ) { 549 lock( &this->lock );617 lock( &this->lock DEBUG_CTX2 ); 550 618 if( !this->cond ) { 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 619 append( &this->blocked, (thread_desc*)this_thread ); 620 BlockInternal( &this->lock ); 621 } 622 else { 623 unlock( &this->lock ); 624 } 556 625 } 557 626 558 627 void signal( signal_once * this ) { 559 lock( &this->lock );628 lock( &this->lock DEBUG_CTX2 ); 560 629 { 561 630 this->cond = true; 562 631 632 disable_interrupts(); 563 633 thread_desc * it; 564 634 while( it = pop_head( &this->blocked) ) { 565 635 ScheduleThread( it ); 566 636 } 637 enable_interrupts( DEBUG_CTX ); 567 638 } 568 639 unlock( &this->lock ); … … 590 661 } 591 662 head->next = NULL; 592 } 663 } 593 664 return head; 594 665 } … … 609 680 this->top = top->next; 610 681 top->next = NULL; 611 } 682 } 612 683 return top; 613 684 } -
src/libcfa/concurrency/kernel_private.h
r307a732 r67fa9f9 18 18 #define KERNEL_PRIVATE_H 19 19 20 #include "libhdr.h" 21 20 22 #include "kernel" 21 23 #include "thread" … … 23 25 #include "alarm.h" 24 26 25 #include "libhdr.h"26 27 27 28 //----------------------------------------------------------------------------- 28 29 // Scheduler 30 31 extern "C" { 32 void disable_interrupts(); 33 void enable_interrupts_noRF(); 34 void enable_interrupts( DEBUG_CTX_PARAM ); 35 } 36 29 37 void ScheduleThread( thread_desc * ); 38 static inline void WakeThread( thread_desc * thrd ) { 39 if( !thrd ) return; 40 41 disable_interrupts(); 42 ScheduleThread( thrd ); 43 enable_interrupts( DEBUG_CTX ); 44 } 30 45 thread_desc * nextThread(cluster * this); 31 46 32 void ScheduleInternal(void);33 void ScheduleInternal(spinlock * lock);34 void ScheduleInternal(thread_desc * thrd);35 void ScheduleInternal(spinlock * lock, thread_desc * thrd);36 void ScheduleInternal(spinlock ** locks, unsigned short count);37 void ScheduleInternal(spinlock ** locks, unsigned short count, thread_desc ** thrds, unsigned short thrd_count);47 void BlockInternal(void); 48 void BlockInternal(spinlock * lock); 49 void BlockInternal(thread_desc * thrd); 50 void BlockInternal(spinlock * lock, thread_desc * thrd); 51 void BlockInternal(spinlock ** locks, unsigned short count); 52 void BlockInternal(spinlock ** locks, unsigned short count, thread_desc ** thrds, unsigned short thrd_count); 38 53 39 54 //----------------------------------------------------------------------------- … … 60 75 extern cluster * systemCluster; 61 76 extern system_proc_t * systemProcessor; 62 extern thread_local processor * this_processor; 63 64 static inline void disable_interrupts() { 65 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, 1, __ATOMIC_SEQ_CST ); 66 assert( prev != (unsigned short) -1 ); 67 } 68 69 static inline void enable_interrupts_noRF() { 70 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 71 verify( prev != (unsigned short) 0 ); 72 } 73 74 static inline void enable_interrupts() { 75 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 76 verify( prev != (unsigned short) 0 ); 77 if( prev == 1 && this_processor->pending_preemption ) { 78 ScheduleInternal( this_processor->current_thread ); 79 this_processor->pending_preemption = false; 80 } 81 } 77 extern volatile thread_local processor * this_processor; 78 extern volatile thread_local coroutine_desc * this_coroutine; 79 extern volatile thread_local thread_desc * this_thread; 80 extern volatile thread_local unsigned short disable_preempt_count; 82 81 83 82 //----------------------------------------------------------------------------- -
src/libcfa/concurrency/monitor
r307a732 r67fa9f9 26 26 static inline void ?{}(monitor_desc * this) { 27 27 this->owner = NULL; 28 this->stack_owner = NULL;29 28 this->recursion = 0; 30 29 } -
src/libcfa/concurrency/monitor.c
r307a732 r67fa9f9 19 19 #include <stdlib> 20 20 21 #include "libhdr.h" 21 22 #include "kernel_private.h" 22 #include "libhdr.h"23 23 24 24 //----------------------------------------------------------------------------- … … 44 44 45 45 extern "C" { 46 void __enter_monitor_desc( monitor_desc * this) {47 lock ( &this->lock);48 thread_desc * thrd = this_thread ();49 50 LIB_DEBUG_PRINT_SAFE("%p Entering %p (o: %p, r: %i)\n", thrd, this, this->owner, this->recursion);46 void __enter_monitor_desc( monitor_desc * this ) { 47 lock_yield( &this->lock DEBUG_CTX2 ); 48 thread_desc * thrd = this_thread; 49 50 // LIB_DEBUG_PRINT_SAFE("%p Entering %p (o: %p, r: %i)\n", thrd, this, this->owner, this->recursion); 51 51 52 52 if( !this->owner ) { … … 62 62 //Some one else has the monitor, wait in line for it 63 63 append( &this->entry_queue, thrd ); 64 LIB_DEBUG_PRINT_SAFE("%p Blocking on entry\n", thrd);65 ScheduleInternal( &this->lock );66 67 // ScheduleInternal will unlock spinlock, no need to unlock ourselves68 return; 64 // LIB_DEBUG_PRINT_SAFE("%p Blocking on entry\n", thrd); 65 BlockInternal( &this->lock ); 66 67 //BlockInternal will unlock spinlock, no need to unlock ourselves 68 return; 69 69 } 70 70 … … 75 75 // leave pseudo code : 76 76 // TODO 77 void __leave_monitor_desc( monitor_desc * this) {78 lock ( &this->lock);79 80 LIB_DEBUG_PRINT_SAFE("%p Leaving %p (o: %p, r: %i)\n", thrd, this, this->owner, this->recursion);81 verifyf( this_thread () == this->owner, "Expected owner to be %p, got %p (r: %i)", this_thread(), this->owner, this->recursion );77 void __leave_monitor_desc( monitor_desc * this ) { 78 lock_yield( &this->lock DEBUG_CTX2 ); 79 80 // LIB_DEBUG_PRINT_SAFE("%p Leaving %p (o: %p, r: %i). ", this_thread, this, this->owner, this->recursion); 81 verifyf( this_thread == this->owner, "Expected owner to be %p, got %p (r: %i)", this_thread, this->owner, this->recursion ); 82 82 83 83 //Leaving a recursion level, decrement the counter … … 96 96 unlock( &this->lock ); 97 97 98 LIB_DEBUG_PRINT_SAFE("Next owner is %p\n", new_owner);98 // LIB_DEBUG_PRINT_SAFE("Next owner is %p\n", new_owner); 99 99 100 100 //We need to wake-up the thread 101 ScheduleThread( new_owner ); 101 WakeThread( new_owner ); 102 } 103 104 void __leave_thread_monitor( thread_desc * thrd ) { 105 monitor_desc * this = &thrd->mon; 106 lock_yield( &this->lock DEBUG_CTX2 ); 107 108 disable_interrupts(); 109 110 thrd->cor.state = Halted; 111 112 verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i)", thrd, this->owner, this->recursion ); 113 114 //Leaving a recursion level, decrement the counter 115 this->recursion -= 1; 116 117 //If we haven't left the last level of recursion 118 //it means we don't need to do anything 119 if( this->recursion != 0) { 120 unlock( &this->lock ); 121 return; 122 } 123 124 thread_desc * new_owner = next_thread( this ); 125 126 //We can now let other threads in safely 127 unlock( &this->lock ); 128 129 //We need to wake-up the thread 130 if( new_owner) ScheduleThread( new_owner ); 102 131 } 103 132 } … … 121 150 enter( this->m, this->count ); 122 151 123 this->prev_mntrs = this_thread ()->current_monitors;124 this->prev_count = this_thread ()->current_monitor_count;125 126 this_thread ()->current_monitors = m;127 this_thread ()->current_monitor_count = count;152 this->prev_mntrs = this_thread->current_monitors; 153 this->prev_count = this_thread->current_monitor_count; 154 155 this_thread->current_monitors = m; 156 this_thread->current_monitor_count = count; 128 157 } 129 158 … … 131 160 leave( this->m, this->count ); 132 161 133 this_thread ()->current_monitors = this->prev_mntrs;134 this_thread ()->current_monitor_count = this->prev_count;162 this_thread->current_monitors = this->prev_mntrs; 163 this_thread->current_monitor_count = this->prev_count; 135 164 } 136 165 … … 159 188 // Internal scheduling 160 189 void wait( condition * this, uintptr_t user_info = 0 ) { 161 LIB_DEBUG_PRINT_SAFE("Waiting\n");190 // LIB_DEBUG_PRINT_SAFE("Waiting\n"); 162 191 163 192 brand_condition( this ); … … 170 199 unsigned short count = this->monitor_count; 171 200 unsigned int recursions[ count ]; //Save the current recursion levels to restore them later 172 spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal173 174 LIB_DEBUG_PRINT_SAFE("count %i\n", count);175 176 __condition_node_t waiter = { this_thread(), count, user_info };201 spinlock * locks [ count ]; //We need to pass-in an array of locks to BlockInternal 202 203 // LIB_DEBUG_PRINT_SAFE("count %i\n", count); 204 205 __condition_node_t waiter = { (thread_desc*)this_thread, count, user_info }; 177 206 178 207 __condition_criterion_t criteria[count]; 179 208 for(int i = 0; i < count; i++) { 180 209 (&criteria[i]){ this->monitors[i], &waiter }; 181 LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] );210 // LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] ); 182 211 } 183 212 … … 201 230 } 202 231 203 LIB_DEBUG_PRINT_SAFE("Will unblock: ");232 // LIB_DEBUG_PRINT_SAFE("Will unblock: "); 204 233 for(int i = 0; i < thread_count; i++) { 205 LIB_DEBUG_PRINT_SAFE("%p ", threads[i]);206 } 207 LIB_DEBUG_PRINT_SAFE("\n");234 // LIB_DEBUG_PRINT_SAFE("%p ", threads[i]); 235 } 236 // LIB_DEBUG_PRINT_SAFE("\n"); 208 237 209 238 // Everything is ready to go to sleep 210 ScheduleInternal( locks, count, threads, thread_count );239 BlockInternal( locks, count, threads, thread_count ); 211 240 212 241 … … 222 251 bool signal( condition * this ) { 223 252 if( is_empty( this ) ) { 224 LIB_DEBUG_PRINT_SAFE("Nothing to signal\n");253 // LIB_DEBUG_PRINT_SAFE("Nothing to signal\n"); 225 254 return false; 226 255 } … … 231 260 232 261 unsigned short count = this->monitor_count; 233 262 234 263 //Some more checking in debug 235 264 LIB_DEBUG_DO( 236 thread_desc * this_thrd = this_thread ();265 thread_desc * this_thrd = this_thread; 237 266 if ( this->monitor_count != this_thrd->current_monitor_count ) { 238 267 abortf( "Signal on condition %p made with different number of monitor(s), expected %i got %i", this, this->monitor_count, this_thrd->current_monitor_count ); … … 248 277 //Lock all the monitors 249 278 lock_all( this->monitors, NULL, count ); 250 LIB_DEBUG_PRINT_SAFE("Signalling");279 // LIB_DEBUG_PRINT_SAFE("Signalling"); 251 280 252 281 //Pop the head of the waiting queue … … 256 285 for(int i = 0; i < count; i++) { 257 286 __condition_criterion_t * crit = &node->criteria[i]; 258 LIB_DEBUG_PRINT_SAFE(" %p", crit->target);287 // LIB_DEBUG_PRINT_SAFE(" %p", crit->target); 259 288 assert( !crit->ready ); 260 289 push( &crit->target->signal_stack, crit ); 261 290 } 262 291 263 LIB_DEBUG_PRINT_SAFE("\n");292 // LIB_DEBUG_PRINT_SAFE("\n"); 264 293 265 294 //Release … … 281 310 unsigned short count = this->monitor_count; 282 311 unsigned int recursions[ count ]; //Save the current recursion levels to restore them later 283 spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal312 spinlock * locks [ count ]; //We need to pass-in an array of locks to BlockInternal 284 313 285 314 lock_all( this->monitors, locks, count ); 286 315 287 316 //create creteria 288 __condition_node_t waiter = { this_thread(), count, 0 };317 __condition_node_t waiter = { (thread_desc*)this_thread, count, 0 }; 289 318 290 319 __condition_criterion_t criteria[count]; 291 320 for(int i = 0; i < count; i++) { 292 321 (&criteria[i]){ this->monitors[i], &waiter }; 293 LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] );322 // LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] ); 294 323 push( &criteria[i].target->signal_stack, &criteria[i] ); 295 324 } … … 309 338 310 339 //Everything is ready to go to sleep 311 ScheduleInternal( locks, count, &signallee, 1 );340 BlockInternal( locks, count, &signallee, 1 ); 312 341 313 342 … … 325 354 326 355 uintptr_t front( condition * this ) { 327 verifyf( !is_empty(this), 356 verifyf( !is_empty(this), 328 357 "Attempt to access user data on an empty condition.\n" 329 358 "Possible cause is not checking if the condition is empty before reading stored data." … … 335 364 // Internal scheduling 336 365 void __accept_internal( unsigned short count, __acceptable_t * acceptables, void (*func)(void) ) { 337 // thread_desc * this = this_thread ();366 // thread_desc * this = this_thread; 338 367 339 368 // unsigned short count = this->current_monitor_count; 340 369 // unsigned int recursions[ count ]; //Save the current recursion levels to restore them later 341 // spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal370 // spinlock * locks [ count ]; //We need to pass-in an array of locks to BlockInternal 342 371 343 372 // lock_all( this->current_monitors, locks, count ); … … 348 377 349 378 // // // Everything is ready to go to sleep 350 // // ScheduleInternal( locks, count, threads, thread_count );379 // // BlockInternal( locks, count, threads, thread_count ); 351 380 352 381 … … 393 422 static inline void lock_all( spinlock ** locks, unsigned short count ) { 394 423 for( int i = 0; i < count; i++ ) { 395 lock ( locks[i]);424 lock_yield( locks[i] DEBUG_CTX2 ); 396 425 } 397 426 } … … 400 429 for( int i = 0; i < count; i++ ) { 401 430 spinlock * l = &source[i]->lock; 402 lock ( l);431 lock_yield( l DEBUG_CTX2 ); 403 432 if(locks) locks[i] = l; 404 433 } … … 443 472 for( int i = 0; i < count; i++ ) { 444 473 445 LIB_DEBUG_PRINT_SAFE( "Checking %p for %p\n", &criteria[i], target );474 // LIB_DEBUG_PRINT_SAFE( "Checking %p for %p\n", &criteria[i], target ); 446 475 if( &criteria[i] == target ) { 447 476 criteria[i].ready = true; 448 LIB_DEBUG_PRINT_SAFE( "True\n" );477 // LIB_DEBUG_PRINT_SAFE( "True\n" ); 449 478 } 450 479 … … 452 481 } 453 482 454 LIB_DEBUG_PRINT_SAFE( "Runing %i\n", ready2run );483 // LIB_DEBUG_PRINT_SAFE( "Runing %i\n", ready2run ); 455 484 return ready2run ? node->waiting_thread : NULL; 456 485 } 457 486 458 487 static inline void brand_condition( condition * this ) { 459 thread_desc * thrd = this_thread ();488 thread_desc * thrd = this_thread; 460 489 if( !this->monitors ) { 461 LIB_DEBUG_PRINT_SAFE("Branding\n");490 // LIB_DEBUG_PRINT_SAFE("Branding\n"); 462 491 assertf( thrd->current_monitors != NULL, "No current monitor to brand condition", thrd->current_monitors ); 463 492 this->monitor_count = thrd->current_monitor_count; -
src/libcfa/concurrency/preemption.c
r307a732 r67fa9f9 15 15 // 16 16 17 #include "libhdr.h" 17 18 #include "preemption.h" 18 19 19 20 extern "C" { 21 #include <errno.h> 22 #include <execinfo.h> 23 #define __USE_GNU 20 24 #include <signal.h> 21 } 22 23 #define __CFA_DEFAULT_PREEMPTION__ 10 25 #undef __USE_GNU 26 #include <stdio.h> 27 #include <string.h> 28 #include <unistd.h> 29 } 30 31 32 #ifdef __USE_STREAM__ 33 #include "fstream" 34 #endif 35 36 #define __CFA_DEFAULT_PREEMPTION__ 10000 24 37 25 38 __attribute__((weak)) unsigned int default_preemption() { … … 27 40 } 28 41 42 #define __CFA_SIGCXT__ ucontext_t * 43 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt 44 29 45 static void preempt( processor * this ); 30 46 static void timeout( thread_desc * this ); 31 47 48 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 49 void sigHandler_alarm ( __CFA_SIGPARMS__ ); 50 void sigHandler_segv ( __CFA_SIGPARMS__ ); 51 void sigHandler_abort ( __CFA_SIGPARMS__ ); 52 53 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ); 54 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); ) 55 56 #ifdef __x86_64__ 57 #define CFA_REG_IP REG_RIP 58 #else 59 #define CFA_REG_IP REG_EIP 60 #endif 61 62 32 63 //============================================================================================= 33 64 // Kernel Preemption logic 34 65 //============================================================================================= 35 66 36 void kernel_start_preemption() {37 38 }39 40 67 void tick_preemption() { 68 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" ); 69 41 70 alarm_list_t * alarms = &systemProcessor->alarms; 42 71 __cfa_time_t currtime = __kernel_get_time(); 43 72 while( alarms->head && alarms->head->alarm < currtime ) { 44 73 alarm_node_t * node = pop(alarms); 74 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node ); 75 45 76 if( node->kernel_alarm ) { 46 77 preempt( node->proc ); … … 50 81 } 51 82 83 verify( validate( alarms ) ); 84 52 85 if( node->period > 0 ) { 53 node->alarm +=node->period;86 node->alarm = currtime + node->period; 54 87 insert( alarms, node ); 55 88 } … … 62 95 __kernel_set_timer( alarms->head->alarm - currtime ); 63 96 } 97 98 verify( validate( alarms ) ); 99 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" ); 64 100 } 65 101 66 102 void update_preemption( processor * this, __cfa_time_t duration ) { 67 // assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 ); 103 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration ); 104 68 105 alarm_node_t * alarm = this->preemption_alarm; 106 duration *= 1000; 69 107 70 108 // Alarms need to be enabled … … 89 127 } 90 128 129 //============================================================================================= 130 // Kernel Signal Tools 131 //============================================================================================= 132 133 LIB_DEBUG_DO( static thread_local void * last_interrupt = 0; ) 134 135 extern "C" { 136 void disable_interrupts() { 137 __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST ); 138 verify( new_val < (unsigned short)65_000 ); 139 verify( new_val != (unsigned short) 0 ); 140 } 141 142 void enable_interrupts_noRF() { 143 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 144 verify( prev != (unsigned short) 0 ); 145 } 146 147 void enable_interrupts( DEBUG_CTX_PARAM ) { 148 processor * proc = this_processor; 149 thread_desc * thrd = this_thread; 150 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 151 verify( prev != (unsigned short) 0 ); 152 if( prev == 1 && proc->pending_preemption ) { 153 proc->pending_preemption = false; 154 BlockInternal( thrd ); 155 } 156 157 LIB_DEBUG_DO( proc->last_enable = caller; ) 158 } 159 } 160 161 static inline void signal_unblock( int sig ) { 162 sigset_t mask; 163 sigemptyset( &mask ); 164 sigaddset( &mask, sig ); 165 166 if ( pthread_sigmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) { 167 abortf( "internal error, pthread_sigmask" ); 168 } 169 } 170 171 static inline void signal_block( int sig ) { 172 sigset_t mask; 173 sigemptyset( &mask ); 174 sigaddset( &mask, sig ); 175 176 if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) { 177 abortf( "internal error, pthread_sigmask" ); 178 } 179 } 180 181 static inline bool preemption_ready() { 182 return disable_preempt_count == 0; 183 } 184 185 static inline void defer_ctxSwitch() { 186 this_processor->pending_preemption = true; 187 } 188 189 static inline void defer_alarm() { 190 systemProcessor->pending_alarm = true; 191 } 192 193 static void preempt( processor * this ) { 194 pthread_kill( this->kernel_thread, SIGUSR1 ); 195 } 196 197 static void timeout( thread_desc * this ) { 198 //TODO : implement waking threads 199 } 200 201 //============================================================================================= 202 // Kernel Signal Startup/Shutdown logic 203 //============================================================================================= 204 205 static pthread_t alarm_thread; 206 void * alarm_loop( __attribute__((unused)) void * args ); 207 208 void kernel_start_preemption() { 209 LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n"); 210 __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); 211 __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); 212 __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); 213 214 signal_block( SIGALRM ); 215 216 pthread_create( &alarm_thread, NULL, alarm_loop, NULL ); 217 } 218 219 void kernel_stop_preemption() { 220 sigset_t mask; 221 sigfillset( &mask ); 222 sigprocmask( SIG_BLOCK, &mask, NULL ); 223 224 pthread_kill( alarm_thread, SIGINT ); 225 pthread_join( alarm_thread, NULL ); 226 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n"); 227 } 228 91 229 void ?{}( preemption_scope * this, processor * proc ) { 92 230 (&this->alarm){ proc }; … … 97 235 98 236 void ^?{}( preemption_scope * this ) { 237 disable_interrupts(); 238 99 239 update_preemption( this->proc, 0 ); 100 240 } 101 241 102 242 //============================================================================================= 103 // Kernel Signal logic 104 //============================================================================================= 105 106 static inline bool preemption_ready() { 107 return this_processor->disable_preempt_count == 0; 108 } 109 110 static inline void defer_ctxSwitch() { 111 this_processor->pending_preemption = true; 112 } 113 114 static inline void defer_alarm() { 115 systemProcessor->pending_alarm = true; 116 } 117 118 void sigHandler_ctxSwitch( __attribute__((unused)) int sig ) { 243 // Kernel Signal Handlers 244 //============================================================================================= 245 246 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 247 LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[CFA_REG_IP]); ) 119 248 if( preemption_ready() ) { 120 ScheduleInternal( this_processor->current_thread ); 249 signal_unblock( SIGUSR1 ); 250 BlockInternal( (thread_desc*)this_thread ); 121 251 } 122 252 else { … … 125 255 } 126 256 127 void sigHandler_alarm( __attribute__((unused)) int sig ) { 128 if( try_lock( &systemProcessor->alarm_lock ) ) { 129 tick_preemption(); 130 unlock( &systemProcessor->alarm_lock ); 131 } 132 else { 133 defer_alarm(); 134 } 135 } 136 137 static void preempt( processor * this ) { 138 pthread_kill( this->kernel_thread, SIGUSR1 ); 139 } 140 141 static void timeout( thread_desc * this ) { 142 //TODO : implement waking threads 143 } 257 // void sigHandler_alarm( __CFA_SIGPARMS__ ) { 258 // LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[CFA_REG_IP]); ) 259 // verify( this_processor == systemProcessor ); 260 261 // if( try_lock( &systemProcessor->alarm_lock DEBUG_CTX2 ) ) { 262 // tick_preemption(); 263 // systemProcessor->pending_alarm = false; 264 // unlock( &systemProcessor->alarm_lock ); 265 // } 266 // else { 267 // defer_alarm(); 268 // } 269 270 // signal_unblock( SIGALRM ); 271 272 // if( preemption_ready() && this_processor->pending_preemption ) { 273 274 // this_processor->pending_preemption = false; 275 // BlockInternal( (thread_desc*)this_thread ); 276 // } 277 // } 278 279 void * alarm_loop( __attribute__((unused)) void * args ) { 280 sigset_t mask; 281 sigemptyset( &mask ); 282 sigaddset( &mask, SIGALRM ); 283 sigaddset( &mask, SIGUSR2 ); 284 sigaddset( &mask, SIGINT ); 285 286 if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) { 287 abortf( "internal error, pthread_sigmask" ); 288 } 289 290 while( true ) { 291 int sig; 292 if( sigwait( &mask, &sig ) != 0 ) { 293 abortf( "internal error, sigwait" ); 294 } 295 296 switch( sig) { 297 case SIGALRM: 298 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread tick\n"); 299 lock( &systemProcessor->alarm_lock DEBUG_CTX2 ); 300 tick_preemption(); 301 unlock( &systemProcessor->alarm_lock ); 302 break; 303 case SIGUSR2: 304 //TODO other actions 305 break; 306 case SIGINT: 307 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread stopping\n"); 308 return NULL; 309 default: 310 abortf( "internal error, sigwait returned sig %d", sig ); 311 break; 312 } 313 } 314 } 315 316 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) { 317 struct sigaction act; 318 319 act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler; 320 act.sa_flags = flags; 321 322 if ( sigaction( sig, &act, NULL ) == -1 ) { 323 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, 324 " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n", 325 sig, handler, flags, errno, strerror( errno ) 326 ); 327 _exit( EXIT_FAILURE ); 328 } 329 } 330 331 typedef void (*sa_handler_t)(int); 332 333 static void __kernel_sigdefault( int sig ) { 334 struct sigaction act; 335 336 // act.sa_handler = SIG_DFL; 337 act.sa_flags = 0; 338 sigemptyset( &act.sa_mask ); 339 340 if ( sigaction( sig, &act, NULL ) == -1 ) { 341 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, 342 " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n", 343 sig, errno, strerror( errno ) 344 ); 345 _exit( EXIT_FAILURE ); 346 } 347 } 348 349 //============================================================================================= 350 // Terminating Signals logic 351 //============================================================================================= 352 353 LIB_DEBUG_DO( 354 static void __kernel_backtrace( int start ) { 355 // skip first N stack frames 356 357 enum { Frames = 50 }; 358 void * array[Frames]; 359 int size = backtrace( array, Frames ); 360 char ** messages = backtrace_symbols( array, size ); 361 362 // find executable name 363 *index( messages[0], '(' ) = '\0'; 364 #ifdef __USE_STREAM__ 365 serr | "Stack back trace for:" | messages[0] | endl; 366 #else 367 fprintf( stderr, "Stack back trace for: %s\n", messages[0]); 368 #endif 369 370 // skip last 2 stack frames after main 371 for ( int i = start; i < size && messages != NULL; i += 1 ) { 372 char * name = NULL; 373 char * offset_begin = NULL; 374 char * offset_end = NULL; 375 376 for ( char *p = messages[i]; *p; ++p ) { 377 // find parantheses and +offset 378 if ( *p == '(' ) { 379 name = p; 380 } 381 else if ( *p == '+' ) { 382 offset_begin = p; 383 } 384 else if ( *p == ')' ) { 385 offset_end = p; 386 break; 387 } 388 } 389 390 // if line contains symbol print it 391 int frameNo = i - start; 392 if ( name && offset_begin && offset_end && name < offset_begin ) { 393 // delimit strings 394 *name++ = '\0'; 395 *offset_begin++ = '\0'; 396 *offset_end++ = '\0'; 397 398 #ifdef __USE_STREAM__ 399 serr | "(" | frameNo | ")" | messages[i] | ":" 400 | name | "+" | offset_begin | offset_end | endl; 401 #else 402 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end); 403 #endif 404 } 405 // otherwise, print the whole line 406 else { 407 #ifdef __USE_STREAM__ 408 serr | "(" | frameNo | ")" | messages[i] | endl; 409 #else 410 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] ); 411 #endif 412 } 413 } 414 415 free( messages ); 416 } 417 ) 418 419 void sigHandler_segv( __CFA_SIGPARMS__ ) { 420 LIB_DEBUG_DO( 421 #ifdef __USE_STREAM__ 422 serr | "*CFA runtime error* program cfa-cpp terminated with" 423 | (sig == SIGSEGV ? "segment fault." : "bus error.") 424 | endl; 425 #else 426 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." ); 427 #endif 428 429 // skip first 2 stack frames 430 __kernel_backtrace( 1 ); 431 ) 432 exit( EXIT_FAILURE ); 433 } 434 435 // void sigHandler_abort( __CFA_SIGPARMS__ ) { 436 // // skip first 6 stack frames 437 // LIB_DEBUG_DO( __kernel_backtrace( 6 ); ) 438 439 // // reset default signal handler 440 // __kernel_sigdefault( SIGABRT ); 441 442 // raise( SIGABRT ); 443 // } -
src/libcfa/concurrency/thread
r307a732 r67fa9f9 54 54 } 55 55 56 thread_desc * this_thread(void);56 extern volatile thread_local thread_desc * this_thread; 57 57 58 58 forall( dtype T | is_thread(T) ) -
src/libcfa/concurrency/thread.c
r307a732 r67fa9f9 28 28 } 29 29 30 extern thread_local processor * this_processor;30 extern volatile thread_local processor * this_processor; 31 31 32 32 //----------------------------------------------------------------------------- … … 71 71 coroutine_desc* thrd_c = get_coroutine(this); 72 72 thread_desc* thrd_h = get_thread (this); 73 thrd_c->last = this_coroutine(); 74 this_processor->current_coroutine = thrd_c; 73 thrd_c->last = this_coroutine; 75 74 76 LIB_DEBUG_PRINT_SAFE("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h);75 // LIB_DEBUG_PRINT_SAFE("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h); 77 76 77 disable_interrupts(); 78 78 create_stack(&thrd_c->stack, thrd_c->stack.size); 79 this_coroutine = thrd_c; 79 80 CtxStart(this, CtxInvokeThread); 81 assert( thrd_c->last->stack.context ); 80 82 CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context ); 81 83 82 84 ScheduleThread(thrd_h); 85 enable_interrupts( DEBUG_CTX ); 83 86 } 84 87 85 88 void yield( void ) { 86 ScheduleInternal( this_processor->current_thread );89 BlockInternal( (thread_desc *)this_thread ); 87 90 } 88 91 … … 95 98 void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 96 99 // set state of current coroutine to inactive 97 src->state = Inactive;100 src->state = src->state == Halted ? Halted : Inactive; 98 101 dst->state = Active; 99 102 … … 103 106 // set new coroutine that the processor is executing 104 107 // and context switch to it 105 this_processor->current_coroutine = dst; 108 this_coroutine = dst; 109 assert( src->stack.context ); 106 110 CtxSwitch( src->stack.context, dst->stack.context ); 107 this_ processor->current_coroutine = src;111 this_coroutine = src; 108 112 109 113 // set state of new coroutine to active 110 dst->state = Inactive;114 dst->state = dst->state == Halted ? Halted : Inactive; 111 115 src->state = Active; 112 116 } -
src/libcfa/libhdr/libalign.h
r307a732 r67fa9f9 1 // -*- Mode: C++ -*- 1 // -*- Mode: C++ -*- 2 2 // 3 3 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo … … 18 18 // Free Software Foundation; either version 2.1 of the License, or (at your 19 19 // option) any later version. 20 // 20 // 21 21 // This library is distributed in the hope that it will be useful, but WITHOUT 22 22 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 23 23 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 24 24 // for more details. 25 // 25 // 26 26 // You should have received a copy of the GNU Lesser General Public License 27 27 // along with this library. 28 // 28 // 29 29 30 30 … … 33 33 34 34 #include "assert" 35 #include <stdbool.h> 35 36 36 // Minimum size used to align memory boundaries for memory allocations. 37 // Minimum size used to align memory boundaries for memory allocations. 37 38 #define libAlign() (sizeof(double)) 38 39 -
src/libcfa/libhdr/libdebug.h
r307a732 r67fa9f9 18 18 19 19 #ifdef __CFA_DEBUG__ 20 #define LIB_DEBUG_DO(x) x 21 #define LIB_NO_DEBUG_DO(x) ((void)0) 20 #define LIB_DEBUG_DO(...) __VA_ARGS__ 21 #define LIB_NO_DEBUG_DO(...) 22 #define DEBUG_CTX __PRETTY_FUNCTION__ 23 #define DEBUG_CTX2 , __PRETTY_FUNCTION__ 24 #define DEBUG_CTX_PARAM const char * caller 25 #define DEBUG_CTX_PARAM2 , const char * caller 22 26 #else 23 #define LIB_DEBUG_DO(x) ((void)0) 24 #define LIB_NO_DEBUG_DO(x) x 27 #define LIB_DEBUG_DO(...) 28 #define LIB_NO_DEBUG_DO(...) __VA_ARGS__ 29 #define DEBUG_CTX 30 #define DEBUG_CTX2 31 #define DEBUG_CTX_PARAM 32 #define DEBUG_CTX_PARAM2 25 33 #endif 26 34 … … 51 59 52 60 #ifdef __CFA_DEBUG_PRINT__ 53 #define LIB_DEBUG_WRITE( fd, buffer, len ) __lib_debug_write( fd, buffer, len ) 54 #define LIB_DEBUG_ACQUIRE() __lib_debug_acquire() 55 #define LIB_DEBUG_RELEASE() __lib_debug_release() 56 #define LIB_DEBUG_PRINT_SAFE(...) __lib_debug_print_safe (__VA_ARGS__) 57 #define LIB_DEBUG_PRINT_NOLOCK(...) __lib_debug_print_nolock (__VA_ARGS__) 58 #define LIB_DEBUG_PRINT_BUFFER(...) __lib_debug_print_buffer (__VA_ARGS__) 61 #define LIB_DEBUG_WRITE( fd, buffer, len ) __lib_debug_write( fd, buffer, len ) 62 #define LIB_DEBUG_ACQUIRE() __lib_debug_acquire() 63 #define LIB_DEBUG_RELEASE() __lib_debug_release() 64 #define LIB_DEBUG_PRINT_SAFE(...) __lib_debug_print_safe (__VA_ARGS__) 65 #define LIB_DEBUG_PRINT_NOLOCK(...) __lib_debug_print_nolock (__VA_ARGS__) 66 #define LIB_DEBUG_PRINT_BUFFER(...) __lib_debug_print_buffer (__VA_ARGS__) 67 #define LIB_DEBUG_PRINT_BUFFER_DECL(fd, ...) char text[256]; int len = snprintf( text, 256, __VA_ARGS__ ); __lib_debug_write( fd, text, len ); 68 #define LIB_DEBUG_PRINT_BUFFER_LOCAL(fd, ...) len = snprintf( text, 256, __VA_ARGS__ ); __lib_debug_write( fd, text, len ); 59 69 #else 60 #define LIB_DEBUG_WRITE(...) ((void)0) 61 #define LIB_DEBUG_ACQUIRE() ((void)0) 62 #define LIB_DEBUG_RELEASE() ((void)0) 63 #define LIB_DEBUG_PRINT_SAFE(...) ((void)0) 64 #define LIB_DEBUG_PRINT_NOLOCK(...) ((void)0) 65 #define LIB_DEBUG_PRINT_BUFFER(...) ((void)0) 70 #define LIB_DEBUG_WRITE(...) ((void)0) 71 #define LIB_DEBUG_ACQUIRE() ((void)0) 72 #define LIB_DEBUG_RELEASE() ((void)0) 73 #define LIB_DEBUG_PRINT_SAFE(...) ((void)0) 74 #define LIB_DEBUG_PRINT_NOLOCK(...) ((void)0) 75 #define LIB_DEBUG_PRINT_BUFFER(...) ((void)0) 76 #define LIB_DEBUG_PRINT_BUFFER_DECL(...) ((void)0) 77 #define LIB_DEBUG_PRINT_BUFFER_LOCAL(...) ((void)0) 66 78 #endif 67 79 -
src/tests/sched-int-block.c
r307a732 r67fa9f9 31 31 //------------------------------------------------------------------------------ 32 32 void wait_op( global_data_t * mutex a, global_data_t * mutex b, unsigned i ) { 33 wait( &cond, (uintptr_t)this_thread ());33 wait( &cond, (uintptr_t)this_thread ); 34 34 35 35 yield( ((unsigned)rand48()) % 10 ); … … 40 40 } 41 41 42 a->last_thread = b->last_thread = this_thread ();42 a->last_thread = b->last_thread = this_thread; 43 43 44 44 yield( ((unsigned)rand48()) % 10 ); … … 56 56 yield( ((unsigned)rand48()) % 10 ); 57 57 58 a->last_thread = b->last_thread = a->last_signaller = b->last_signaller = this_thread ();58 a->last_thread = b->last_thread = a->last_signaller = b->last_signaller = this_thread; 59 59 60 60 if( !is_empty( &cond ) ) { … … 86 86 //------------------------------------------------------------------------------ 87 87 void barge_op( global_data_t * mutex a ) { 88 a->last_thread = this_thread ();88 a->last_thread = this_thread; 89 89 } 90 90
Note: See TracChangeset
for help on using the changeset viewer.