Changes in / [d43cd01:653f2c7]
- Location:
- src
- Files:
-
- 1 deleted
- 17 edited
-
benchmark/CorCtxSwitch.c (modified) (1 diff)
-
benchmark/csv-data.c (modified) (1 diff)
-
benchmark/interrupt_linux.c (deleted)
-
libcfa/concurrency/alarm.c (modified) (8 diffs)
-
libcfa/concurrency/coroutine (modified) (4 diffs)
-
libcfa/concurrency/coroutine.c (modified) (2 diffs)
-
libcfa/concurrency/invoke.c (modified) (5 diffs)
-
libcfa/concurrency/invoke.h (modified) (2 diffs)
-
libcfa/concurrency/kernel (modified) (3 diffs)
-
libcfa/concurrency/kernel.c (modified) (33 diffs)
-
libcfa/concurrency/kernel_private.h (modified) (2 diffs)
-
libcfa/concurrency/monitor (modified) (1 diff)
-
libcfa/concurrency/monitor.c (modified) (16 diffs)
-
libcfa/concurrency/preemption.c (modified) (10 diffs)
-
libcfa/concurrency/thread (modified) (1 diff)
-
libcfa/concurrency/thread.c (modified) (4 diffs)
-
libcfa/libhdr/libdebug.h (modified) (2 diffs)
-
tests/sched-int-block.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/benchmark/CorCtxSwitch.c
rd43cd01 r653f2c7 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 // } 33 37 resumer( &s, NoOfTimes ); 34 38 EndTime = Time(); -
src/benchmark/csv-data.c
rd43cd01 r653f2c7 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 // } 40 44 resumer( &s, NoOfTimes ); 41 45 EndTime = Time(); -
src/libcfa/concurrency/alarm.c
rd43cd01 r653f2c7 16 16 17 17 extern "C" { 18 #include <errno.h>19 #include <stdio.h>20 #include <string.h>21 18 #include <time.h> 22 #include <unistd.h>23 19 #include <sys/time.h> 24 20 } … … 26 22 #include "alarm.h" 27 23 #include "kernel_private.h" 28 #include "libhdr.h"29 24 #include "preemption.h" 30 25 … … 36 31 timespec curr; 37 32 clock_gettime( CLOCK_REALTIME, &curr ); 38 __cfa_time_t curr_time = ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; 39 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : current time is %lu\n", curr_time ); 40 return curr_time; 33 return ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; 41 34 } 42 35 43 36 void __kernel_set_timer( __cfa_time_t alarm ) { 44 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : set timer to %lu\n", (__cfa_time_t)alarm );45 37 itimerval val; 46 38 val.it_value.tv_sec = alarm / TIMEGRAN; // seconds … … 79 71 } 80 72 81 LIB_DEBUG_DO( bool validate( alarm_list_t * this ) {82 alarm_node_t ** it = &this->head;83 while( (*it) ) {84 it = &(*it)->next;85 }86 87 return it == this->tail;88 })89 90 73 static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { 91 verify( !n->next );74 assert( !n->next ); 92 75 if( p == this->tail ) { 93 76 this->tail = &n->next; … … 97 80 } 98 81 *p = n; 99 100 verify( validate( this ) );101 82 } 102 83 … … 108 89 109 90 insert_at( this, n, it ); 110 111 verify( validate( this ) );112 91 } 113 92 … … 121 100 head->next = NULL; 122 101 } 123 verify( validate( this ) );124 102 return head; 125 103 } … … 127 105 static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) { 128 106 verify( it ); 129 verify( (*it) == n );107 verify( (*it)->next == n ); 130 108 131 (*it) = n->next;109 (*it)->next = n->next; 132 110 if( !n-> next ) { 133 111 this->tail = it; 134 112 } 135 113 n->next = NULL; 136 137 verify( validate( this ) );138 114 } 139 115 140 116 static inline void remove( alarm_list_t * this, alarm_node_t * n ) { 141 117 alarm_node_t ** it = &this->head; 142 while( (*it) && (*it) != n ) {118 while( (*it) && (*it)->next != n ) { 143 119 it = &(*it)->next; 144 120 } 145 121 146 verify( validate( this ) );147 148 122 if( *it ) { remove_at( this, n, it ); } 149 150 verify( validate( this ) );151 123 } 152 124 153 125 void register_self( alarm_node_t * this ) { 154 126 disable_interrupts(); 155 verify( !systemProcessor->pending_alarm );156 lock( &systemProcessor->alarm_lock , __PRETTY_FUNCTION__);127 assert( !systemProcessor->pending_alarm ); 128 lock( &systemProcessor->alarm_lock ); 157 129 { 158 verify( validate( &systemProcessor->alarms ) );159 bool first = !systemProcessor->alarms.head;160 161 130 insert( &systemProcessor->alarms, this ); 162 131 if( systemProcessor->pending_alarm ) { 163 132 tick_preemption(); 164 133 } 165 if( first ) {166 __kernel_set_timer( systemProcessor->alarms.head->alarm - __kernel_get_time() );167 }168 134 } 169 135 unlock( &systemProcessor->alarm_lock ); 170 136 this->set = true; 171 enable_interrupts( __PRETTY_FUNCTION__);137 enable_interrupts(); 172 138 } 173 139 174 140 void unregister_self( alarm_node_t * this ) { 175 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : unregister %p start\n", this );176 141 disable_interrupts(); 177 lock( &systemProcessor->alarm_lock, __PRETTY_FUNCTION__ ); 178 { 179 verify( validate( &systemProcessor->alarms ) ); 180 remove( &systemProcessor->alarms, this ); 181 } 142 lock( &systemProcessor->alarm_lock ); 143 remove( &systemProcessor->alarms, this ); 182 144 unlock( &systemProcessor->alarm_lock ); 183 145 disable_interrupts(); 184 146 this->set = false; 185 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Kernel : unregister %p end\n", this );186 147 } -
src/libcfa/concurrency/coroutine
rd43cd01 r653f2c7 63 63 64 64 // Get current coroutine 65 extern volatile thread_local coroutine_desc * this_coroutine;65 coroutine_desc * this_coroutine(void); 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
rd43cd01 r653f2c7 32 32 #include "invoke.h" 33 33 34 extern volatilethread_local processor * this_processor;34 extern thread_local processor * this_processor; 35 35 36 36 //----------------------------------------------------------------------------- … … 106 106 107 107 // set state of current coroutine to inactive 108 src->state = src->state == Halted ? Halted :Inactive;108 src->state = Inactive; 109 109 110 110 // set new coroutine that task is executing 111 this_ coroutine = dst;111 this_processor->current_coroutine = dst; 112 112 113 113 // context switch to specified coroutine 114 assert( src->stack.context );115 114 CtxSwitch( src->stack.context, dst->stack.context ); 116 115 // when CtxSwitch returns we are back in the src coroutine -
src/libcfa/concurrency/invoke.c
rd43cd01 r653f2c7 29 29 30 30 extern void __suspend_internal(void); 31 extern void __leave_thread_monitor( struct thread_desc * this ); 32 extern void disable_interrupts(); 33 extern void enable_interrupts( const char * ); 31 extern void __leave_monitor_desc( struct monitor_desc * this ); 34 32 35 33 void CtxInvokeCoroutine( 36 void (*main)(void *), 37 struct coroutine_desc *(*get_coroutine)(void *), 34 void (*main)(void *), 35 struct coroutine_desc *(*get_coroutine)(void *), 38 36 void *this 39 37 ) { … … 58 56 59 57 void CtxInvokeThread( 60 void (*dtor)(void *), 61 void (*main)(void *), 62 struct thread_desc *(*get_thread)(void *), 58 void (*dtor)(void *), 59 void (*main)(void *), 60 struct thread_desc *(*get_thread)(void *), 63 61 void *this 64 62 ) { 65 // First suspend, once the thread arrives here,66 // the function pointer to main can be invalidated without risk67 63 __suspend_internal(); 68 64 69 // Fetch the thread handle from the user defined thread structure70 65 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; 71 69 72 // Officially start the thread by enabling preemption 73 enable_interrupts( __PRETTY_FUNCTION__ ); 74 75 // Call the main of the thread 70 // LIB_DEBUG_PRINTF("Invoke Thread : invoking main %p (args %p)\n", main, this); 76 71 main( this ); 77 72 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 ); 73 __leave_monitor_desc( mon ); 84 74 85 75 //Final suspend, should never return … … 90 80 91 81 void CtxStart( 92 void (*main)(void *), 93 struct coroutine_desc *(*get_coroutine)(void *), 94 void *this, 82 void (*main)(void *), 83 struct coroutine_desc *(*get_coroutine)(void *), 84 void *this, 95 85 void (*invoke)(void *) 96 86 ) { … … 118 108 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke; 119 109 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520 120 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 110 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 121 111 122 112 #elif defined( __x86_64__ ) … … 138 128 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke; 139 129 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520 140 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 130 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 141 131 #else 142 132 #error Only __i386__ and __x86_64__ is supported for threads in cfa -
src/libcfa/concurrency/invoke.h
rd43cd01 r653f2c7 31 31 struct spinlock { 32 32 volatile int lock; 33 #ifdef __CFA_DEBUG__34 const char * prev;35 #endif36 33 }; 37 34 … … 86 83 struct __thread_queue_t entry_queue; // queue of threads that are blocked waiting for the monitor 87 84 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 monitor 88 86 unsigned int recursion; // monitor routines can be called recursively, we need to keep track of that 89 87 }; -
src/libcfa/concurrency/kernel
rd43cd01 r653f2c7 28 28 //----------------------------------------------------------------------------- 29 29 // Locks 30 bool try_lock( spinlock * 31 #ifdef __CFA_DEBUG__ 32 , const char * caller 33 #endif 34 ); 35 36 void lock( spinlock * 37 #ifdef __CFA_DEBUG__ 38 , const char * caller 39 #endif 40 ); 41 30 bool try_lock( spinlock * ); 31 void lock( spinlock * ); 42 32 void unlock( spinlock * ); 43 33 … … 88 78 struct processorCtx_t * runner; 89 79 cluster * cltr; 80 coroutine_desc * current_coroutine; 81 thread_desc * current_thread; 90 82 pthread_t kernel_thread; 91 83 … … 98 90 unsigned int preemption; 99 91 92 unsigned short disable_preempt_count; 93 100 94 bool pending_preemption; 101 102 char * last_enable;103 95 }; 104 96 -
src/libcfa/concurrency/kernel.c
rd43cd01 r653f2c7 59 59 // Global state 60 60 61 volatile thread_local processor * this_processor; 62 volatile thread_local coroutine_desc * this_coroutine; 63 volatile thread_local thread_desc * this_thread; 64 volatile thread_local unsigned short disable_preempt_count = 1; 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 } 65 70 66 71 //----------------------------------------------------------------------------- 67 72 // Main thread construction 68 73 struct current_stack_info_t { 69 machine_context_t ctx; 74 machine_context_t ctx; 70 75 unsigned int size; // size of stack 71 76 void *base; // base of stack … … 101 106 102 107 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 103 (&this->stack){ info }; 108 (&this->stack){ info }; 104 109 this->name = "Main Thread"; 105 110 this->errno_ = 0; … … 131 136 void ?{}(processor * this, cluster * cltr) { 132 137 this->cltr = cltr; 138 this->current_coroutine = NULL; 139 this->current_thread = NULL; 133 140 (&this->terminated){}; 134 141 this->is_terminated = false; 135 142 this->preemption_alarm = NULL; 136 143 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled 137 145 this->pending_preemption = false; 138 146 … … 142 150 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 143 151 this->cltr = cltr; 152 this->current_coroutine = NULL; 153 this->current_thread = NULL; 144 154 (&this->terminated){}; 145 155 this->is_terminated = false; 146 this->preemption_alarm = NULL; 147 this->preemption = default_preemption(); 156 this->disable_preempt_count = 0; 148 157 this->pending_preemption = false; 149 this->kernel_thread = pthread_self();150 158 151 159 this->runner = runner; 152 LIB_DEBUG_PRINT_SAFE("Kernel : constructing systemprocessor context %p\n", runner);160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner); 153 161 runner{ this }; 154 162 } 155 156 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )157 163 158 164 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 162 168 163 169 (&this->proc){ cltr, runner }; 164 165 verify( validate( &this->alarms ) );166 170 } 167 171 … … 180 184 181 185 void ^?{}(cluster * this) { 182 186 183 187 } 184 188 … … 199 203 200 204 thread_desc * readyThread = NULL; 201 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 202 206 { 203 207 readyThread = nextThread( this->cltr ); … … 205 209 if(readyThread) 206 210 { 207 verify( disable_preempt_count > 0 );208 209 211 runThread(this, readyThread); 210 211 verify( disable_preempt_count > 0 );212 212 213 213 //Some actions need to be taken from the kernel … … 229 229 } 230 230 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 233 233 void runThread(processor * this, thread_desc * dst) { 234 234 coroutine_desc * proc_cor = get_coroutine(this->runner); 235 235 coroutine_desc * thrd_cor = get_coroutine(dst); 236 236 237 237 //Reset the terminating actions here 238 238 this->finish.action_code = No_Action; 239 239 240 240 //Update global state 241 this _thread = dst;241 this->current_thread = dst; 242 242 243 243 // Context Switch to the thread … … 246 246 } 247 247 248 // Once a thread has finished running, some of 248 // Once a thread has finished running, some of 249 249 // its final actions must be executed from the kernel 250 250 void finishRunning(processor * this) { … … 256 256 } 257 257 else if( this->finish.action_code == Release_Schedule ) { 258 unlock( this->finish.lock ); 258 unlock( this->finish.lock ); 259 259 ScheduleThread( this->finish.thrd ); 260 260 } … … 289 289 processor * proc = (processor *) arg; 290 290 this_processor = proc; 291 this_coroutine = NULL;292 this_thread = NULL;293 disable_preempt_count = 1;294 291 // SKULLDUGGERY: We want to create a context for the processor coroutine 295 292 // which is needed for the 2-step context switch. However, there is no reason 296 // to waste the perfectly valid stack create by pthread. 293 // to waste the perfectly valid stack create by pthread. 297 294 current_stack_info_t info; 298 295 machine_context_t ctx; … … 303 300 304 301 //Set global state 305 this_coroutine = &proc->runner->__cor;306 this_thread = NULL;302 proc->current_coroutine = &proc->runner->__cor; 303 proc->current_thread = NULL; 307 304 308 305 //We now have a proper context from which to schedule threads 309 306 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 310 307 311 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 312 // resume it to start it like it normally would, it will just context switch 313 // back to here. Instead directly call the main since we already are on the 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 314 311 // appropriate stack. 315 312 proc_cor_storage.__cor.state = Active; … … 318 315 319 316 // Main routine of the core returned, the core is now fully terminated 320 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 317 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 321 318 322 319 return NULL; … … 325 322 void start(processor * this) { 326 323 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 327 328 // SIGALRM must only be caught by the system processor 329 sigset_t old_mask; 330 bool is_system_proc = this_processor == &systemProcessor->proc; 331 if ( is_system_proc ) { 332 // Child kernel-thread inherits the signal mask from the parent kernel-thread. So one special case for the 333 // system processor creating the user processor => toggle the blocking SIGALRM on system processor, create user 334 // processor, and toggle back (below) previous signal mask of the system processor. 335 336 sigset_t new_mask; 337 sigemptyset( &new_mask ); 338 sigemptyset( &old_mask ); 339 sigaddset( &new_mask, SIGALRM ); 340 341 if ( sigprocmask( SIG_BLOCK, &new_mask, &old_mask ) == -1 ) { 342 abortf( "internal error, sigprocmask" ); 343 } 344 345 assert( ! sigismember( &old_mask, SIGALRM ) ); 346 } 347 324 348 325 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 349 326 350 // Toggle back previous signal mask of system processor. 351 if ( is_system_proc ) { 352 if ( sigprocmask( SIG_SETMASK, &old_mask, NULL ) == -1 ) { 353 abortf( "internal error, sigprocmask" ); 354 } // if 355 } // if 356 357 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 358 328 } 359 329 … … 361 331 // Scheduler routines 362 332 void ScheduleThread( thread_desc * thrd ) { 363 // if( !thrd ) return; 364 assert( thrd ); 365 assert( thrd->cor.state != Halted ); 366 367 verify( disable_preempt_count > 0 ); 333 if( !thrd ) return; 368 334 369 335 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 370 371 lock( &systemProcessor->proc.cltr->lock , __PRETTY_FUNCTION__);336 337 lock( &systemProcessor->proc.cltr->lock ); 372 338 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 373 339 unlock( &systemProcessor->proc.cltr->lock ); 374 375 verify( disable_preempt_count > 0 );376 340 } 377 341 378 342 thread_desc * nextThread(cluster * this) { 379 verify( disable_preempt_count > 0 ); 380 lock( &this->lock, __PRETTY_FUNCTION__ ); 343 lock( &this->lock ); 381 344 thread_desc * head = pop_head( &this->ready_queue ); 382 345 unlock( &this->lock ); 383 verify( disable_preempt_count > 0 );384 346 return head; 385 347 } 386 348 387 void BlockInternal() { 388 disable_interrupts(); 389 verify( disable_preempt_count > 0 ); 349 void ScheduleInternal() { 390 350 suspend(); 391 verify( disable_preempt_count > 0 ); 392 enable_interrupts( __PRETTY_FUNCTION__ ); 393 } 394 395 void BlockInternal( spinlock * lock ) { 396 disable_interrupts(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 397 354 this_processor->finish.action_code = Release; 398 355 this_processor->finish.lock = lock; 399 400 verify( disable_preempt_count > 0 );401 356 suspend(); 402 verify( disable_preempt_count > 0 ); 403 404 enable_interrupts( __PRETTY_FUNCTION__ ); 405 } 406 407 void BlockInternal( thread_desc * thrd ) { 408 disable_interrupts(); 409 assert( thrd->cor.state != Halted ); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 410 360 this_processor->finish.action_code = Schedule; 411 361 this_processor->finish.thrd = thrd; 412 413 verify( disable_preempt_count > 0 );414 362 suspend(); 415 verify( disable_preempt_count > 0 ); 416 417 enable_interrupts( __PRETTY_FUNCTION__ ); 418 } 419 420 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 421 disable_interrupts(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 422 366 this_processor->finish.action_code = Release_Schedule; 423 367 this_processor->finish.lock = lock; 424 368 this_processor->finish.thrd = thrd; 425 426 verify( disable_preempt_count > 0 );427 369 suspend(); 428 verify( disable_preempt_count > 0 ); 429 430 enable_interrupts( __PRETTY_FUNCTION__ ); 431 } 432 433 void BlockInternal(spinlock ** locks, unsigned short count) { 434 disable_interrupts(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 435 373 this_processor->finish.action_code = Release_Multi; 436 374 this_processor->finish.locks = locks; 437 375 this_processor->finish.lock_count = count; 438 439 verify( disable_preempt_count > 0 );440 376 suspend(); 441 verify( disable_preempt_count > 0 ); 442 443 enable_interrupts( __PRETTY_FUNCTION__ ); 444 } 445 446 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 447 disable_interrupts(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 448 380 this_processor->finish.action_code = Release_Multi_Schedule; 449 381 this_processor->finish.locks = locks; … … 451 383 this_processor->finish.thrds = thrds; 452 384 this_processor->finish.thrd_count = thrd_count; 453 454 verify( disable_preempt_count > 0 );455 385 suspend(); 456 verify( disable_preempt_count > 0 );457 458 enable_interrupts( __PRETTY_FUNCTION__ );459 386 } 460 387 … … 465 392 // Kernel boot procedures 466 393 void kernel_startup(void) { 467 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 468 395 469 396 // Start by initializing the main thread 470 // SKULLDUGGERY: the mainThread steals the process main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 471 398 // which will then be scheduled by the systemProcessor normally 472 399 mainThread = (thread_desc *)&mainThread_storage; … … 476 403 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 477 404 405 // Enable preemption 406 kernel_start_preemption(); 407 478 408 // Initialize the system cluster 479 409 systemCluster = (cluster *)&systemCluster_storage; … … 487 417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 488 418 489 // Add the main thread to the ready queue 419 // Add the main thread to the ready queue 490 420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 491 421 ScheduleThread(mainThread); … … 493 423 //initialize the global state variables 494 424 this_processor = &systemProcessor->proc; 495 this_thread = mainThread; 496 this_coroutine = &mainThread->cor; 497 disable_preempt_count = 1; 498 499 // Enable preemption 500 kernel_start_preemption(); 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 501 427 502 428 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 503 429 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 504 // mainThread is on the ready queue when this call is made. 430 // mainThread is on the ready queue when this call is made. 505 431 resume( systemProcessor->proc.runner ); 506 432 … … 509 435 // THE SYSTEM IS NOW COMPLETELY RUNNING 510 436 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 511 512 enable_interrupts( __PRETTY_FUNCTION__ );513 437 } 514 438 515 439 void kernel_shutdown(void) { 516 440 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 517 518 disable_interrupts();519 441 520 442 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 526 448 // THE SYSTEM IS NOW COMPLETELY STOPPED 527 449 528 // Disable preemption529 kernel_stop_preemption();530 531 450 // Destroy the system processor and its context in reverse order of construction 532 451 // These were manually constructed so we need manually destroy them … … 538 457 ^(mainThread){}; 539 458 540 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 541 460 } 542 461 … … 548 467 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 549 468 // the globalAbort flag is true. 550 lock( &kernel_abort_lock , __PRETTY_FUNCTION__);469 lock( &kernel_abort_lock ); 551 470 552 471 // first task to abort ? … … 554 473 kernel_abort_called = true; 555 474 unlock( &kernel_abort_lock ); 556 } 475 } 557 476 else { 558 477 unlock( &kernel_abort_lock ); 559 478 560 479 sigset_t mask; 561 480 sigemptyset( &mask ); … … 563 482 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 564 483 sigsuspend( &mask ); // block the processor to prevent further damage during abort 565 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 566 } 567 568 return this_thread ;484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread(); 569 488 } 570 489 … … 575 494 __lib_debug_write( STDERR_FILENO, abort_text, len ); 576 495 577 if ( thrd != this_coroutine ) {578 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ->name, this_coroutine);496 if ( thrd != this_coroutine() ) { 497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine()->name, this_coroutine() ); 579 498 __lib_debug_write( STDERR_FILENO, abort_text, len ); 580 } 499 } 581 500 else { 582 501 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 586 505 extern "C" { 587 506 void __lib_debug_acquire() { 588 lock(&kernel_debug_lock , __PRETTY_FUNCTION__);507 lock(&kernel_debug_lock); 589 508 } 590 509 … … 606 525 } 607 526 608 bool try_lock( spinlock * this, const char * caller ) { 609 bool ret = this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 610 this->prev = caller; 611 return ret; 612 } 613 614 void lock( spinlock * this, const char * caller ) { 527 bool try_lock( spinlock * this ) { 528 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 529 } 530 531 void lock( spinlock * this ) { 615 532 for ( unsigned int i = 1;; i += 1 ) { 616 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 617 534 } 618 this->prev = caller;619 535 } 620 536 … … 631 547 632 548 void wait( signal_once * this ) { 633 lock( &this->lock , __PRETTY_FUNCTION__);549 lock( &this->lock ); 634 550 if( !this->cond ) { 635 append( &this->blocked, (thread_desc*)this_thread ); 636 BlockInternal( &this->lock ); 637 } 638 else { 639 unlock( &this->lock ); 640 } 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 641 556 } 642 557 643 558 void signal( signal_once * this ) { 644 lock( &this->lock , __PRETTY_FUNCTION__);559 lock( &this->lock ); 645 560 { 646 561 this->cond = true; 647 562 648 disable_interrupts();649 563 thread_desc * it; 650 564 while( it = pop_head( &this->blocked) ) { 651 565 ScheduleThread( it ); 652 566 } 653 enable_interrupts( __PRETTY_FUNCTION__ );654 567 } 655 568 unlock( &this->lock ); … … 677 590 } 678 591 head->next = NULL; 679 } 592 } 680 593 return head; 681 594 } … … 696 609 this->top = top->next; 697 610 top->next = NULL; 698 } 611 } 699 612 return top; 700 613 } -
src/libcfa/concurrency/kernel_private.h
rd43cd01 r653f2c7 27 27 //----------------------------------------------------------------------------- 28 28 // Scheduler 29 30 extern "C" {31 void disable_interrupts();32 void enable_interrupts_noRF();33 void enable_interrupts( const char * );34 }35 36 29 void ScheduleThread( thread_desc * ); 37 static inline void WakeThread( thread_desc * thrd ) {38 if( !thrd ) return;39 40 disable_interrupts();41 ScheduleThread( thrd );42 enable_interrupts( __PRETTY_FUNCTION__ );43 }44 30 thread_desc * nextThread(cluster * this); 45 31 46 void BlockInternal(void);47 void BlockInternal(spinlock * lock);48 void BlockInternal(thread_desc * thrd);49 void BlockInternal(spinlock * lock, thread_desc * thrd);50 void BlockInternal(spinlock ** locks, unsigned short count);51 void BlockInternal(spinlock ** locks, unsigned short count, thread_desc ** thrds, unsigned short thrd_count);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); 52 38 53 39 //----------------------------------------------------------------------------- … … 74 60 extern cluster * systemCluster; 75 61 extern system_proc_t * systemProcessor; 76 extern volatile thread_local processor * this_processor; 77 extern volatile thread_local coroutine_desc * this_coroutine; 78 extern volatile thread_local thread_desc * this_thread; 79 extern volatile thread_local unsigned short disable_preempt_count; 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 } 80 82 81 83 //----------------------------------------------------------------------------- -
src/libcfa/concurrency/monitor
rd43cd01 r653f2c7 26 26 static inline void ?{}(monitor_desc * this) { 27 27 this->owner = NULL; 28 this->stack_owner = NULL; 28 29 this->recursion = 0; 29 30 } -
src/libcfa/concurrency/monitor.c
rd43cd01 r653f2c7 44 44 45 45 extern "C" { 46 void __enter_monitor_desc( monitor_desc * this) {47 lock( &this->lock , __PRETTY_FUNCTION__);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( &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); 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 BlockInternal( &this->lock );66 67 // BlockInternal will unlock spinlock, no need to unlock ourselves64 LIB_DEBUG_PRINT_SAFE("%p Blocking on entry\n", thrd); 65 ScheduleInternal( &this->lock ); 66 67 //ScheduleInternal will unlock spinlock, no need to unlock ourselves 68 68 return; 69 69 } … … 75 75 // leave pseudo code : 76 76 // TODO 77 void __leave_monitor_desc( monitor_desc * this) {78 lock( &this->lock , __PRETTY_FUNCTION__);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 );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 ); 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 WakeThread( new_owner ); 102 } 103 104 void __leave_thread_monitor( thread_desc * thrd ) { 105 monitor_desc * this = &thrd->mon; 106 lock( &this->lock, __PRETTY_FUNCTION__ ); 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 ); 101 ScheduleThread( new_owner ); 131 102 } 132 103 } … … 150 121 enter( this->m, this->count ); 151 122 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;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; 157 128 } 158 129 … … 160 131 leave( this->m, this->count ); 161 132 162 this_thread ->current_monitors = this->prev_mntrs;163 this_thread ->current_monitor_count = this->prev_count;133 this_thread()->current_monitors = this->prev_mntrs; 134 this_thread()->current_monitor_count = this->prev_count; 164 135 } 165 136 … … 199 170 unsigned short count = this->monitor_count; 200 171 unsigned int recursions[ count ]; //Save the current recursion levels to restore them later 201 spinlock * locks [ count ]; //We need to pass-in an array of locks to BlockInternal172 spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal 202 173 203 174 LIB_DEBUG_PRINT_SAFE("count %i\n", count); 204 175 205 __condition_node_t waiter = { (thread_desc*)this_thread, count, user_info };176 __condition_node_t waiter = { this_thread(), count, user_info }; 206 177 207 178 __condition_criterion_t criteria[count]; … … 237 208 238 209 // Everything is ready to go to sleep 239 BlockInternal( locks, count, threads, thread_count );210 ScheduleInternal( locks, count, threads, thread_count ); 240 211 241 212 … … 263 234 //Some more checking in debug 264 235 LIB_DEBUG_DO( 265 thread_desc * this_thrd = this_thread ;236 thread_desc * this_thrd = this_thread(); 266 237 if ( this->monitor_count != this_thrd->current_monitor_count ) { 267 238 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 ); … … 310 281 unsigned short count = this->monitor_count; 311 282 unsigned int recursions[ count ]; //Save the current recursion levels to restore them later 312 spinlock * locks [ count ]; //We need to pass-in an array of locks to BlockInternal283 spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal 313 284 314 285 lock_all( this->monitors, locks, count ); 315 286 316 287 //create creteria 317 __condition_node_t waiter = { (thread_desc*)this_thread, count, 0 };288 __condition_node_t waiter = { this_thread(), count, 0 }; 318 289 319 290 __condition_criterion_t criteria[count]; … … 338 309 339 310 //Everything is ready to go to sleep 340 BlockInternal( locks, count, &signallee, 1 );311 ScheduleInternal( locks, count, &signallee, 1 ); 341 312 342 313 … … 364 335 // Internal scheduling 365 336 void __accept_internal( unsigned short count, __acceptable_t * acceptables, void (*func)(void) ) { 366 // thread_desc * this = this_thread ;337 // thread_desc * this = this_thread(); 367 338 368 339 // unsigned short count = this->current_monitor_count; 369 340 // unsigned int recursions[ count ]; //Save the current recursion levels to restore them later 370 // spinlock * locks [ count ]; //We need to pass-in an array of locks to BlockInternal341 // spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal 371 342 372 343 // lock_all( this->current_monitors, locks, count ); … … 377 348 378 349 // // // Everything is ready to go to sleep 379 // // BlockInternal( locks, count, threads, thread_count );350 // // ScheduleInternal( locks, count, threads, thread_count ); 380 351 381 352 … … 422 393 static inline void lock_all( spinlock ** locks, unsigned short count ) { 423 394 for( int i = 0; i < count; i++ ) { 424 lock( locks[i] , __PRETTY_FUNCTION__);395 lock( locks[i] ); 425 396 } 426 397 } … … 429 400 for( int i = 0; i < count; i++ ) { 430 401 spinlock * l = &source[i]->lock; 431 lock( l , __PRETTY_FUNCTION__);402 lock( l ); 432 403 if(locks) locks[i] = l; 433 404 } … … 486 457 487 458 static inline void brand_condition( condition * this ) { 488 thread_desc * thrd = this_thread ;459 thread_desc * thrd = this_thread(); 489 460 if( !this->monitors ) { 490 461 LIB_DEBUG_PRINT_SAFE("Branding\n"); -
src/libcfa/concurrency/preemption.c
rd43cd01 r653f2c7 17 17 #include "preemption.h" 18 18 19 20 19 extern "C" { 21 #include <errno.h>22 #include <execinfo.h>23 #define __USE_GNU24 20 #include <signal.h> 25 #undef __USE_GNU26 #include <stdio.h>27 #include <string.h>28 #include <unistd.h>29 21 } 30 22 31 32 #ifdef __USE_STREAM__ 33 #include "fstream" 34 #endif 35 #include "libhdr.h" 36 37 #define __CFA_DEFAULT_PREEMPTION__ 10000 23 #define __CFA_DEFAULT_PREEMPTION__ 10 38 24 39 25 __attribute__((weak)) unsigned int default_preemption() { … … 41 27 } 42 28 43 #define __CFA_SIGCXT__ ucontext_t *44 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt45 46 29 static void preempt( processor * this ); 47 30 static void timeout( thread_desc * this ); 48 49 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );50 void sigHandler_alarm ( __CFA_SIGPARMS__ );51 void sigHandler_segv ( __CFA_SIGPARMS__ );52 void sigHandler_abort ( __CFA_SIGPARMS__ );53 54 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags );55 31 56 32 //============================================================================================= … … 59 35 60 36 void kernel_start_preemption() { 61 LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n"); 62 __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); 63 __kernel_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO ); 64 __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); 65 __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); 66 // __kernel_sigaction( SIGABRT, sigHandler_abort , SA_SIGINFO ); 37 67 38 } 68 39 69 void kernel_stop_preemption() {70 //Block all signals, we are no longer in a position to handle them71 sigset_t mask;72 sigfillset( &mask );73 sigprocmask( SIG_BLOCK, &mask, NULL );74 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");75 76 // assert( !systemProcessor->alarms.head );77 // assert( systemProcessor->alarms.tail == &systemProcessor->alarms.head );78 }79 80 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )81 82 40 void tick_preemption() { 83 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );84 85 41 alarm_list_t * alarms = &systemProcessor->alarms; 86 42 __cfa_time_t currtime = __kernel_get_time(); 87 43 while( alarms->head && alarms->head->alarm < currtime ) { 88 44 alarm_node_t * node = pop(alarms); 89 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node );90 91 45 if( node->kernel_alarm ) { 92 46 preempt( node->proc ); … … 96 50 } 97 51 98 verify( validate( alarms ) );99 100 52 if( node->period > 0 ) { 101 node->alarm = currtime +node->period;53 node->alarm += node->period; 102 54 insert( alarms, node ); 103 55 } … … 110 62 __kernel_set_timer( alarms->head->alarm - currtime ); 111 63 } 112 113 verify( validate( alarms ) );114 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" );115 64 } 116 65 117 66 void update_preemption( processor * this, __cfa_time_t duration ) { 118 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration ); 119 67 // assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 ); 120 68 alarm_node_t * alarm = this->preemption_alarm; 121 duration *= 1000;122 69 123 70 // Alarms need to be enabled … … 150 97 151 98 void ^?{}( preemption_scope * this ) { 152 disable_interrupts();153 154 99 update_preemption( this->proc, 0 ); 155 100 } … … 159 104 //============================================================================================= 160 105 161 extern "C" {162 void disable_interrupts() {163 __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST );164 verify( new_val < (unsigned short)65_000 );165 verify( new_val != (unsigned short) 0 );166 }167 168 void enable_interrupts_noRF() {169 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );170 verify( prev != (unsigned short) 0 );171 }172 173 void enable_interrupts( const char * func ) {174 processor * proc = this_processor;175 thread_desc * thrd = this_thread;176 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );177 verify( prev != (unsigned short) 0 );178 if( prev == 1 && proc->pending_preemption ) {179 proc->pending_preemption = false;180 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Executing deferred CtxSwitch on %p\n", this_processor );181 BlockInternal( thrd );182 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Executing deferred back\n" );183 }184 185 proc->last_enable = func;186 }187 }188 189 static inline void signal_unblock( int sig ) {190 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p unblocking sig %i\n", this_processor, sig );191 192 sigset_t mask;193 sigemptyset( &mask );194 sigaddset( &mask, sig );195 196 if ( sigprocmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {197 abortf( "internal error, sigprocmask" );198 } // if199 }200 201 106 static inline bool preemption_ready() { 202 return disable_preempt_count == 0;107 return this_processor->disable_preempt_count == 0; 203 108 } 204 109 … … 211 116 } 212 117 213 extern "C" { 214 __attribute__((noinline)) void __debug_break() { 215 pthread_kill( pthread_self(), SIGTRAP ); 118 void sigHandler_ctxSwitch( __attribute__((unused)) int sig ) { 119 if( preemption_ready() ) { 120 ScheduleInternal( this_processor->current_thread ); 121 } 122 else { 123 defer_ctxSwitch(); 216 124 } 217 125 } 218 126 219 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 220 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ctx Switch IRH %p running %p @ %p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) ); 221 222 if( preemption_ready() ) { 223 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Blocking thread %p on %p\n", this_thread, this_processor ); 224 signal_unblock( SIGUSR1 ); 225 BlockInternal( (thread_desc*)this_thread ); 226 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Back\n\n"); 227 } 228 else { 229 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Defering\n" ); 230 defer_ctxSwitch(); 231 signal_unblock( SIGUSR1 ); 232 } 233 } 234 235 void sigHandler_alarm( __CFA_SIGPARMS__ ) { 236 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "\nAlarm IRH %p running %p @ %p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) ); 237 238 // if( ((intptr_t)cxt->uc_mcontext.gregs[REG_RIP]) > 0xFFFFFF ) __debug_break(); 239 240 if( try_lock( &systemProcessor->alarm_lock, __PRETTY_FUNCTION__ ) ) { 127 void sigHandler_alarm( __attribute__((unused)) int sig ) { 128 if( try_lock( &systemProcessor->alarm_lock ) ) { 241 129 tick_preemption(); 242 130 unlock( &systemProcessor->alarm_lock ); … … 245 133 defer_alarm(); 246 134 } 247 248 signal_unblock( SIGALRM );249 250 if( preemption_ready() && this_processor->pending_preemption ) {251 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm IRH : Blocking thread %p on %p\n", this_thread, this_processor );252 this_processor->pending_preemption = false;253 BlockInternal( (thread_desc*)this_thread );254 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm Switch IRH : Back\n\n");255 }256 135 } 257 136 258 137 static void preempt( processor * this ) { 259 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : signalling %p\n", this ); 260 261 if( this != systemProcessor ) { 262 pthread_kill( this->kernel_thread, SIGUSR1 ); 263 } 264 else { 265 defer_ctxSwitch(); 266 } 138 pthread_kill( this->kernel_thread, SIGUSR1 ); 267 139 } 268 140 … … 270 142 //TODO : implement waking threads 271 143 } 272 273 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {274 struct sigaction act;275 276 act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;277 act.sa_flags = flags;278 279 // disabled during signal handler280 sigemptyset( &act.sa_mask );281 sigaddset( &act.sa_mask, sig );282 283 if ( sigaction( sig, &act, NULL ) == -1 ) {284 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,285 " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",286 sig, handler, flags, errno, strerror( errno )287 );288 _exit( EXIT_FAILURE );289 }290 }291 292 typedef void (*sa_handler_t)(int);293 294 static void __kernel_sigdefault( int sig ) {295 struct sigaction act;296 297 // act.sa_handler = SIG_DFL;298 act.sa_flags = 0;299 sigemptyset( &act.sa_mask );300 301 if ( sigaction( sig, &act, NULL ) == -1 ) {302 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,303 " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",304 sig, errno, strerror( errno )305 );306 _exit( EXIT_FAILURE );307 }308 }309 310 //=============================================================================================311 // Terminating Signals logic312 //=============================================================================================313 314 LIB_DEBUG_DO(315 static void __kernel_backtrace( int start ) {316 // skip first N stack frames317 318 enum { Frames = 50 };319 void * array[Frames];320 int size = backtrace( array, Frames );321 char ** messages = backtrace_symbols( array, size );322 323 // find executable name324 *index( messages[0], '(' ) = '\0';325 #ifdef __USE_STREAM__326 serr | "Stack back trace for:" | messages[0] | endl;327 #else328 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);329 #endif330 331 // skip last 2 stack frames after main332 for ( int i = start; i < size && messages != NULL; i += 1 ) {333 char * name = NULL;334 char * offset_begin = NULL;335 char * offset_end = NULL;336 337 for ( char *p = messages[i]; *p; ++p ) {338 // find parantheses and +offset339 if ( *p == '(' ) {340 name = p;341 }342 else if ( *p == '+' ) {343 offset_begin = p;344 }345 else if ( *p == ')' ) {346 offset_end = p;347 break;348 }349 }350 351 // if line contains symbol print it352 int frameNo = i - start;353 if ( name && offset_begin && offset_end && name < offset_begin ) {354 // delimit strings355 *name++ = '\0';356 *offset_begin++ = '\0';357 *offset_end++ = '\0';358 359 #ifdef __USE_STREAM__360 serr | "(" | frameNo | ")" | messages[i] | ":"361 | name | "+" | offset_begin | offset_end | endl;362 #else363 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);364 #endif365 }366 // otherwise, print the whole line367 else {368 #ifdef __USE_STREAM__369 serr | "(" | frameNo | ")" | messages[i] | endl;370 #else371 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );372 #endif373 }374 }375 376 free( messages );377 }378 )379 380 void sigHandler_segv( __CFA_SIGPARMS__ ) {381 LIB_DEBUG_DO(382 #ifdef __USE_STREAM__383 serr | "*CFA runtime error* program cfa-cpp terminated with"384 | (sig == SIGSEGV ? "segment fault." : "bus error.")385 | endl;386 #else387 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );388 #endif389 390 // skip first 2 stack frames391 __kernel_backtrace( 1 );392 )393 exit( EXIT_FAILURE );394 }395 396 // void sigHandler_abort( __CFA_SIGPARMS__ ) {397 // // skip first 6 stack frames398 // LIB_DEBUG_DO( __kernel_backtrace( 6 ); )399 400 // // reset default signal handler401 // __kernel_sigdefault( SIGABRT );402 403 // raise( SIGABRT );404 // } -
src/libcfa/concurrency/thread
rd43cd01 r653f2c7 54 54 } 55 55 56 extern volatile thread_local thread_desc * this_thread;56 thread_desc * this_thread(void); 57 57 58 58 forall( dtype T | is_thread(T) ) -
src/libcfa/concurrency/thread.c
rd43cd01 r653f2c7 28 28 } 29 29 30 extern volatilethread_local processor * this_processor;30 extern 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; 73 thrd_c->last = this_coroutine(); 74 this_processor->current_coroutine = thrd_c; 74 75 75 //LIB_DEBUG_PRINT_SAFE("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h);76 LIB_DEBUG_PRINT_SAFE("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h); 76 77 77 disable_interrupts();78 78 create_stack(&thrd_c->stack, thrd_c->stack.size); 79 this_coroutine = thrd_c;80 79 CtxStart(this, CtxInvokeThread); 81 assert( thrd_c->last->stack.context );82 80 CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context ); 83 81 84 82 ScheduleThread(thrd_h); 85 enable_interrupts( __PRETTY_FUNCTION__ );86 83 } 87 84 88 85 void yield( void ) { 89 BlockInternal( (thread_desc *)this_thread );86 ScheduleInternal( this_processor->current_thread ); 90 87 } 91 88 … … 98 95 void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 99 96 // set state of current coroutine to inactive 100 src->state = src->state == Halted ? Halted :Inactive;97 src->state = Inactive; 101 98 dst->state = Active; 102 99 … … 106 103 // set new coroutine that the processor is executing 107 104 // and context switch to it 108 this_coroutine = dst; 109 assert( src->stack.context ); 105 this_processor->current_coroutine = dst; 110 106 CtxSwitch( src->stack.context, dst->stack.context ); 111 this_ coroutine = src;107 this_processor->current_coroutine = src; 112 108 113 109 // set state of new coroutine to active 114 dst->state = dst->state == Halted ? Halted :Inactive;110 dst->state = Inactive; 115 111 src->state = Active; 116 112 } -
src/libcfa/libhdr/libdebug.h
rd43cd01 r653f2c7 18 18 19 19 #ifdef __CFA_DEBUG__ 20 #define LIB_DEBUG_DO( ...) __VA_ARGS__21 #define LIB_NO_DEBUG_DO( ...)20 #define LIB_DEBUG_DO(x) x 21 #define LIB_NO_DEBUG_DO(x) ((void)0) 22 22 #else 23 #define LIB_DEBUG_DO( ...)24 #define LIB_NO_DEBUG_DO( ...) __VA_ARGS__23 #define LIB_DEBUG_DO(x) ((void)0) 24 #define LIB_NO_DEBUG_DO(x) x 25 25 #endif 26 26 … … 51 51 52 52 #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__) 59 #define LIB_DEBUG_PRINT_BUFFER_DECL(fd, ...) char text[256]; int len = snprintf( text, 256, __VA_ARGS__ ); __lib_debug_write( fd, text, len ); 60 #define LIB_DEBUG_PRINT_BUFFER_LOCAL(fd, ...) len = snprintf( text, 256, __VA_ARGS__ ); __lib_debug_write( fd, text, len ); 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 59 #else 62 #define LIB_DEBUG_WRITE(...) ((void)0) 63 #define LIB_DEBUG_ACQUIRE() ((void)0) 64 #define LIB_DEBUG_RELEASE() ((void)0) 65 #define LIB_DEBUG_PRINT_SAFE(...) ((void)0) 66 #define LIB_DEBUG_PRINT_NOLOCK(...) ((void)0) 67 #define LIB_DEBUG_PRINT_BUFFER(...) ((void)0) 68 #define LIB_DEBUG_PRINT_BUFFER_DECL(...) ((void)0) 69 #define LIB_DEBUG_PRINT_BUFFER_LOCAL(...) ((void)0) 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 66 #endif 71 67 -
src/tests/sched-int-block.c
rd43cd01 r653f2c7 29 29 //------------------------------------------------------------------------------ 30 30 void wait_op( global_data_t * mutex a, global_data_t * mutex b, unsigned i ) { 31 wait( &cond, (uintptr_t)this_thread );31 wait( &cond, (uintptr_t)this_thread() ); 32 32 33 33 yield( ((unsigned)rand48()) % 10 ); … … 38 38 } 39 39 40 a->last_thread = b->last_thread = this_thread ;40 a->last_thread = b->last_thread = this_thread(); 41 41 42 42 yield( ((unsigned)rand48()) % 10 ); … … 54 54 yield( ((unsigned)rand48()) % 10 ); 55 55 56 a->last_thread = b->last_thread = a->last_signaller = b->last_signaller = this_thread ;56 a->last_thread = b->last_thread = a->last_signaller = b->last_signaller = this_thread(); 57 57 58 58 if( !is_empty( &cond ) ) { … … 84 84 //------------------------------------------------------------------------------ 85 85 void barge_op( global_data_t * mutex a ) { 86 a->last_thread = this_thread ;86 a->last_thread = this_thread(); 87 87 } 88 88
Note:
See TracChangeset
for help on using the changeset viewer.