Changes in / [b751c8e:8c680e9]
- Location:
- src
- Files:
-
- 1 deleted
- 18 edited
-
benchmark/CorCtxSwitch.c (modified) (1 diff)
-
benchmark/csv-data.c (modified) (1 diff)
-
benchmark/interrupt_linux.c (deleted)
-
libcfa/concurrency/alarm.c (modified) (7 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) (3 diffs)
-
libcfa/concurrency/kernel (modified) (4 diffs)
-
libcfa/concurrency/kernel.c (modified) (35 diffs)
-
libcfa/concurrency/kernel_private.h (modified) (3 diffs)
-
libcfa/concurrency/monitor (modified) (1 diff)
-
libcfa/concurrency/monitor.c (modified) (23 diffs)
-
libcfa/concurrency/preemption.c (modified) (10 diffs)
-
libcfa/concurrency/thread (modified) (1 diff)
-
libcfa/concurrency/thread.c (modified) (4 diffs)
-
libcfa/libhdr/libalign.h (modified) (3 diffs)
-
libcfa/libhdr/libdebug.h (modified) (2 diffs)
-
tests/sched-int-block.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/benchmark/CorCtxSwitch.c
rb751c8e r8c680e9 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
rb751c8e r8c680e9 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
rb751c8e r8c680e9 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 } 25 26 #include "libhdr.h"27 21 28 22 #include "alarm.h" … … 37 31 timespec curr; 38 32 clock_gettime( CLOCK_REALTIME, &curr ); 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; 33 return ((__cfa_time_t)curr.tv_sec * TIMEGRAN) + curr.tv_nsec; 42 34 } 43 35 44 36 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 );46 37 itimerval val; 47 38 val.it_value.tv_sec = alarm / TIMEGRAN; // seconds … … 80 71 } 81 72 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 91 73 static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { 92 verify( !n->next );74 assert( !n->next ); 93 75 if( p == this->tail ) { 94 76 this->tail = &n->next; … … 98 80 } 99 81 *p = n; 100 101 verify( validate( this ) );102 82 } 103 83 … … 109 89 110 90 insert_at( this, n, it ); 111 112 verify( validate( this ) );113 91 } 114 92 … … 122 100 head->next = NULL; 123 101 } 124 verify( validate( this ) );125 102 return head; 126 103 } … … 128 105 static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) { 129 106 verify( it ); 130 verify( (*it) == n );107 verify( (*it)->next == n ); 131 108 132 (*it) = n->next;109 (*it)->next = n->next; 133 110 if( !n-> next ) { 134 111 this->tail = it; 135 112 } 136 113 n->next = NULL; 137 138 verify( validate( this ) );139 114 } 140 115 141 116 static inline void remove( alarm_list_t * this, alarm_node_t * n ) { 142 117 alarm_node_t ** it = &this->head; 143 while( (*it) && (*it) != n ) {118 while( (*it) && (*it)->next != n ) { 144 119 it = &(*it)->next; 145 120 } 146 121 147 verify( validate( this ) );148 149 122 if( *it ) { remove_at( this, n, it ); } 150 151 verify( validate( this ) );152 123 } 153 124 154 125 void register_self( alarm_node_t * this ) { 155 126 disable_interrupts(); 156 verify( !systemProcessor->pending_alarm );157 lock( &systemProcessor->alarm_lock DEBUG_CTX2);127 assert( !systemProcessor->pending_alarm ); 128 lock( &systemProcessor->alarm_lock ); 158 129 { 159 verify( validate( &systemProcessor->alarms ) );160 bool first = !systemProcessor->alarms.head;161 162 130 insert( &systemProcessor->alarms, this ); 163 131 if( systemProcessor->pending_alarm ) { 164 132 tick_preemption(); 165 133 } 166 if( first ) {167 __kernel_set_timer( systemProcessor->alarms.head->alarm - __kernel_get_time() );168 }169 134 } 170 135 unlock( &systemProcessor->alarm_lock ); 171 136 this->set = true; 172 enable_interrupts( DEBUG_CTX);137 enable_interrupts(); 173 138 } 174 139 175 140 void unregister_self( alarm_node_t * this ) { 176 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Kernel : unregister %p start\n", this );177 141 disable_interrupts(); 178 lock( &systemProcessor->alarm_lock DEBUG_CTX2 ); 179 { 180 verify( validate( &systemProcessor->alarms ) ); 181 remove( &systemProcessor->alarms, this ); 182 } 142 lock( &systemProcessor->alarm_lock ); 143 remove( &systemProcessor->alarms, this ); 183 144 unlock( &systemProcessor->alarm_lock ); 184 enable_interrupts( DEBUG_CTX);145 disable_interrupts(); 185 146 this->set = false; 186 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Kernel : unregister %p end\n", this );187 147 } -
src/libcfa/concurrency/coroutine
rb751c8e r8c680e9 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
rb751c8e r8c680e9 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
rb751c8e r8c680e9 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( DEBUG_CTX_PARAM ); 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( DEBUG_CTX ); 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
rb751c8e r8c680e9 31 31 struct spinlock { 32 32 volatile int lock; 33 #ifdef __CFA_DEBUG__34 const char * prev_name;35 void* prev_thrd;36 #endif37 33 }; 38 34 … … 87 83 struct __thread_queue_t entry_queue; // queue of threads that are blocked waiting for the monitor 88 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 89 86 unsigned int recursion; // monitor routines can be called recursively, we need to keep track of that 90 87 }; … … 102 99 #ifndef _INVOKE_PRIVATE_H_ 103 100 #define _INVOKE_PRIVATE_H_ 104 101 105 102 struct machine_context_t { 106 103 void *SP; -
src/libcfa/concurrency/kernel
rb751c8e r8c680e9 28 28 //----------------------------------------------------------------------------- 29 29 // Locks 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 * ); 30 bool try_lock( spinlock * ); 31 void lock( spinlock * ); 32 void unlock( spinlock * ); 34 33 35 34 struct signal_once { … … 69 68 unsigned short thrd_count; 70 69 }; 71 static inline void ?{}(FinishAction * this) { 70 static inline void ?{}(FinishAction * this) { 72 71 this->action_code = No_Action; 73 72 this->thrd = NULL; … … 79 78 struct processorCtx_t * runner; 80 79 cluster * cltr; 80 coroutine_desc * current_coroutine; 81 thread_desc * current_thread; 81 82 pthread_t kernel_thread; 82 83 83 84 signal_once terminated; 84 85 volatile bool is_terminated; … … 89 90 unsigned int preemption; 90 91 92 unsigned short disable_preempt_count; 93 91 94 bool pending_preemption; 92 93 char * last_enable;94 95 }; 95 96 -
src/libcfa/concurrency/kernel.c
rb751c8e r8c680e9 15 15 // 16 16 17 #include "libhdr.h" 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" 18 25 19 26 //C Includes … … 28 35 29 36 //CFA Includes 30 #include " kernel_private.h"37 #include "libhdr.h" 31 38 #include "preemption.h" 32 #include "startup.h"33 39 34 40 //Private includes 35 41 #define __CFA_INVOKE_PRIVATE__ 36 42 #include "invoke.h" 37 38 //Start and stop routine for the kernel, declared first to make sure they run first39 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));40 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));41 43 42 44 //----------------------------------------------------------------------------- … … 57 59 // Global state 58 60 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; 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 } 63 70 64 71 //----------------------------------------------------------------------------- 65 72 // Main thread construction 66 73 struct current_stack_info_t { 67 machine_context_t ctx; 74 machine_context_t ctx; 68 75 unsigned int size; // size of stack 69 76 void *base; // base of stack … … 99 106 100 107 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 101 (&this->stack){ info }; 108 (&this->stack){ info }; 102 109 this->name = "Main Thread"; 103 110 this->errno_ = 0; … … 129 136 void ?{}(processor * this, cluster * cltr) { 130 137 this->cltr = cltr; 138 this->current_coroutine = NULL; 139 this->current_thread = NULL; 131 140 (&this->terminated){}; 132 141 this->is_terminated = false; 133 142 this->preemption_alarm = NULL; 134 143 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled 135 145 this->pending_preemption = false; 136 146 … … 140 150 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 141 151 this->cltr = cltr; 152 this->current_coroutine = NULL; 153 this->current_thread = NULL; 142 154 (&this->terminated){}; 143 155 this->is_terminated = false; 144 this->preemption_alarm = NULL; 145 this->preemption = default_preemption(); 156 this->disable_preempt_count = 0; 146 157 this->pending_preemption = false; 147 this->kernel_thread = pthread_self();148 158 149 159 this->runner = runner; 150 LIB_DEBUG_PRINT_SAFE("Kernel : constructing systemprocessor context %p\n", runner);160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner); 151 161 runner{ this }; 152 162 } 153 154 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )155 163 156 164 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 160 168 161 169 (&this->proc){ cltr, runner }; 162 163 verify( validate( &this->alarms ) );164 170 } 165 171 … … 178 184 179 185 void ^?{}(cluster * this) { 180 186 181 187 } 182 188 … … 197 203 198 204 thread_desc * readyThread = NULL; 199 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 200 206 { 201 207 readyThread = nextThread( this->cltr ); … … 203 209 if(readyThread) 204 210 { 205 verify( disable_preempt_count > 0 );206 207 211 runThread(this, readyThread); 208 209 verify( disable_preempt_count > 0 );210 212 211 213 //Some actions need to be taken from the kernel … … 227 229 } 228 230 229 // runThread runs a thread by context switching 230 // 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 231 233 void runThread(processor * this, thread_desc * dst) { 232 234 coroutine_desc * proc_cor = get_coroutine(this->runner); 233 235 coroutine_desc * thrd_cor = get_coroutine(dst); 234 236 235 237 //Reset the terminating actions here 236 238 this->finish.action_code = No_Action; 237 239 238 240 //Update global state 239 this _thread = dst;241 this->current_thread = dst; 240 242 241 243 // Context Switch to the thread … … 244 246 } 245 247 246 // Once a thread has finished running, some of 248 // Once a thread has finished running, some of 247 249 // its final actions must be executed from the kernel 248 250 void finishRunning(processor * this) { … … 254 256 } 255 257 else if( this->finish.action_code == Release_Schedule ) { 256 unlock( this->finish.lock ); 258 unlock( this->finish.lock ); 257 259 ScheduleThread( this->finish.thrd ); 258 260 } … … 287 289 processor * proc = (processor *) arg; 288 290 this_processor = proc; 289 this_coroutine = NULL;290 this_thread = NULL;291 disable_preempt_count = 1;292 291 // SKULLDUGGERY: We want to create a context for the processor coroutine 293 292 // which is needed for the 2-step context switch. However, there is no reason 294 // to waste the perfectly valid stack create by pthread. 293 // to waste the perfectly valid stack create by pthread. 295 294 current_stack_info_t info; 296 295 machine_context_t ctx; … … 301 300 302 301 //Set global state 303 this_coroutine = &proc->runner->__cor;304 this_thread = NULL;302 proc->current_coroutine = &proc->runner->__cor; 303 proc->current_thread = NULL; 305 304 306 305 //We now have a proper context from which to schedule threads 307 306 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 308 307 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 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 312 311 // appropriate stack. 313 312 proc_cor_storage.__cor.state = Active; … … 316 315 317 316 // Main routine of the core returned, the core is now fully terminated 318 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); 319 318 320 319 return NULL; … … 323 322 void start(processor * this) { 324 323 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 325 326 // SIGALRM must only be caught by the system processor 327 sigset_t old_mask; 328 bool is_system_proc = this_processor == &systemProcessor->proc; 329 if ( is_system_proc ) { 330 // Child kernel-thread inherits the signal mask from the parent kernel-thread. So one special case for the 331 // system processor creating the user processor => toggle the blocking SIGALRM on system processor, create user 332 // processor, and toggle back (below) previous signal mask of the system processor. 333 334 sigset_t new_mask; 335 sigemptyset( &new_mask ); 336 sigemptyset( &old_mask ); 337 sigaddset( &new_mask, SIGALRM ); 338 339 if ( sigprocmask( SIG_BLOCK, &new_mask, &old_mask ) == -1 ) { 340 abortf( "internal error, sigprocmask" ); 341 } 342 343 assert( ! sigismember( &old_mask, SIGALRM ) ); 344 } 345 324 346 325 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 347 326 348 // Toggle back previous signal mask of system processor. 349 if ( is_system_proc ) { 350 if ( sigprocmask( SIG_SETMASK, &old_mask, NULL ) == -1 ) { 351 abortf( "internal error, sigprocmask" ); 352 } // if 353 } // if 354 355 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 356 328 } 357 329 … … 359 331 // Scheduler routines 360 332 void ScheduleThread( thread_desc * thrd ) { 361 // if( !thrd ) return; 362 assert( thrd ); 363 assert( thrd->cor.state != Halted ); 364 365 verify( disable_preempt_count > 0 ); 333 if( !thrd ) return; 366 334 367 335 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 368 369 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2);336 337 lock( &systemProcessor->proc.cltr->lock ); 370 338 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 371 339 unlock( &systemProcessor->proc.cltr->lock ); 372 373 verify( disable_preempt_count > 0 );374 340 } 375 341 376 342 thread_desc * nextThread(cluster * this) { 377 verify( disable_preempt_count > 0 ); 378 lock( &this->lock DEBUG_CTX2 ); 343 lock( &this->lock ); 379 344 thread_desc * head = pop_head( &this->ready_queue ); 380 345 unlock( &this->lock ); 381 verify( disable_preempt_count > 0 );382 346 return head; 383 347 } 384 348 385 void BlockInternal() { 386 disable_interrupts(); 387 verify( disable_preempt_count > 0 ); 349 void ScheduleInternal() { 388 350 suspend(); 389 verify( disable_preempt_count > 0 ); 390 enable_interrupts( DEBUG_CTX ); 391 } 392 393 void BlockInternal( spinlock * lock ) { 394 disable_interrupts(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 395 354 this_processor->finish.action_code = Release; 396 355 this_processor->finish.lock = lock; 397 398 verify( disable_preempt_count > 0 );399 356 suspend(); 400 verify( disable_preempt_count > 0 ); 401 402 enable_interrupts( DEBUG_CTX ); 403 } 404 405 void BlockInternal( thread_desc * thrd ) { 406 disable_interrupts(); 407 assert( thrd->cor.state != Halted ); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 408 360 this_processor->finish.action_code = Schedule; 409 361 this_processor->finish.thrd = thrd; 410 411 verify( disable_preempt_count > 0 );412 362 suspend(); 413 verify( disable_preempt_count > 0 ); 414 415 enable_interrupts( DEBUG_CTX ); 416 } 417 418 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 419 disable_interrupts(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 420 366 this_processor->finish.action_code = Release_Schedule; 421 367 this_processor->finish.lock = lock; 422 368 this_processor->finish.thrd = thrd; 423 424 verify( disable_preempt_count > 0 );425 369 suspend(); 426 verify( disable_preempt_count > 0 ); 427 428 enable_interrupts( DEBUG_CTX ); 429 } 430 431 void BlockInternal(spinlock ** locks, unsigned short count) { 432 disable_interrupts(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 433 373 this_processor->finish.action_code = Release_Multi; 434 374 this_processor->finish.locks = locks; 435 375 this_processor->finish.lock_count = count; 436 437 verify( disable_preempt_count > 0 );438 376 suspend(); 439 verify( disable_preempt_count > 0 ); 440 441 enable_interrupts( DEBUG_CTX ); 442 } 443 444 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 445 disable_interrupts(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 446 380 this_processor->finish.action_code = Release_Multi_Schedule; 447 381 this_processor->finish.locks = locks; … … 449 383 this_processor->finish.thrds = thrds; 450 384 this_processor->finish.thrd_count = thrd_count; 451 452 verify( disable_preempt_count > 0 );453 385 suspend(); 454 verify( disable_preempt_count > 0 );455 456 enable_interrupts( DEBUG_CTX );457 386 } 458 387 … … 463 392 // Kernel boot procedures 464 393 void kernel_startup(void) { 465 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 466 395 467 396 // Start by initializing the main thread 468 // SKULLDUGGERY: the mainThread steals the process main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 469 398 // which will then be scheduled by the systemProcessor normally 470 399 mainThread = (thread_desc *)&mainThread_storage; … … 474 403 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 475 404 405 // Enable preemption 406 kernel_start_preemption(); 407 476 408 // Initialize the system cluster 477 409 systemCluster = (cluster *)&systemCluster_storage; … … 485 417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 486 418 487 // Add the main thread to the ready queue 419 // Add the main thread to the ready queue 488 420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 489 421 ScheduleThread(mainThread); … … 491 423 //initialize the global state variables 492 424 this_processor = &systemProcessor->proc; 493 this_thread = mainThread; 494 this_coroutine = &mainThread->cor; 495 disable_preempt_count = 1; 496 497 // Enable preemption 498 kernel_start_preemption(); 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 499 427 500 428 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 501 429 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 502 // mainThread is on the ready queue when this call is made. 430 // mainThread is on the ready queue when this call is made. 503 431 resume( systemProcessor->proc.runner ); 504 432 … … 507 435 // THE SYSTEM IS NOW COMPLETELY RUNNING 508 436 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 509 510 enable_interrupts( DEBUG_CTX );511 437 } 512 438 513 439 void kernel_shutdown(void) { 514 440 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 515 516 disable_interrupts();517 441 518 442 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 524 448 // THE SYSTEM IS NOW COMPLETELY STOPPED 525 449 526 // Disable preemption527 kernel_stop_preemption();528 529 450 // Destroy the system processor and its context in reverse order of construction 530 451 // These were manually constructed so we need manually destroy them … … 536 457 ^(mainThread){}; 537 458 538 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 539 460 } 540 461 … … 546 467 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 547 468 // the globalAbort flag is true. 548 lock( &kernel_abort_lock DEBUG_CTX2);469 lock( &kernel_abort_lock ); 549 470 550 471 // first task to abort ? … … 552 473 kernel_abort_called = true; 553 474 unlock( &kernel_abort_lock ); 554 } 475 } 555 476 else { 556 477 unlock( &kernel_abort_lock ); 557 478 558 479 sigset_t mask; 559 480 sigemptyset( &mask ); … … 561 482 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 562 483 sigsuspend( &mask ); // block the processor to prevent further damage during abort 563 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 564 } 565 566 return this_thread ;484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread(); 567 488 } 568 489 … … 573 494 __lib_debug_write( STDERR_FILENO, abort_text, len ); 574 495 575 if ( thrd != this_coroutine ) {576 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() ); 577 498 __lib_debug_write( STDERR_FILENO, abort_text, len ); 578 } 499 } 579 500 else { 580 501 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 584 505 extern "C" { 585 506 void __lib_debug_acquire() { 586 lock( &kernel_debug_lock DEBUG_CTX2);507 lock(&kernel_debug_lock); 587 508 } 588 509 589 510 void __lib_debug_release() { 590 unlock( &kernel_debug_lock);511 unlock(&kernel_debug_lock); 591 512 } 592 513 } … … 604 525 } 605 526 606 bool try_lock( spinlock * this DEBUG_CTX_PARAM2) {527 bool try_lock( spinlock * this ) { 607 528 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 608 529 } 609 530 610 void lock( spinlock * this DEBUG_CTX_PARAM2) {531 void lock( spinlock * this ) { 611 532 for ( unsigned int i = 1;; i += 1 ) { 612 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 613 } 614 LIB_DEBUG_DO( 615 this->prev_name = caller; 616 this->prev_thrd = this_thread; 617 ) 618 } 619 620 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 621 for ( unsigned int i = 1;; i += 1 ) { 622 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 623 yield(); 624 } 625 LIB_DEBUG_DO( 626 this->prev_name = caller; 627 this->prev_thrd = this_thread; 628 ) 629 } 630 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 } 535 } 631 536 632 537 void unlock( spinlock * this ) { … … 642 547 643 548 void wait( signal_once * this ) { 644 lock( &this->lock DEBUG_CTX2);549 lock( &this->lock ); 645 550 if( !this->cond ) { 646 append( &this->blocked, (thread_desc*)this_thread ); 647 BlockInternal( &this->lock ); 648 } 649 else { 650 unlock( &this->lock ); 651 } 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 652 556 } 653 557 654 558 void signal( signal_once * this ) { 655 lock( &this->lock DEBUG_CTX2);559 lock( &this->lock ); 656 560 { 657 561 this->cond = true; 658 562 659 disable_interrupts();660 563 thread_desc * it; 661 564 while( it = pop_head( &this->blocked) ) { 662 565 ScheduleThread( it ); 663 566 } 664 enable_interrupts( DEBUG_CTX );665 567 } 666 568 unlock( &this->lock ); … … 688 590 } 689 591 head->next = NULL; 690 } 592 } 691 593 return head; 692 594 } … … 707 609 this->top = top->next; 708 610 top->next = NULL; 709 } 611 } 710 612 return top; 711 613 } -
src/libcfa/concurrency/kernel_private.h
rb751c8e r8c680e9 18 18 #define KERNEL_PRIVATE_H 19 19 20 #include "libhdr.h"21 22 20 #include "kernel" 23 21 #include "thread" … … 25 23 #include "alarm.h" 26 24 25 #include "libhdr.h" 27 26 28 27 //----------------------------------------------------------------------------- 29 28 // Scheduler 30 31 extern "C" {32 void disable_interrupts();33 void enable_interrupts_noRF();34 void enable_interrupts( DEBUG_CTX_PARAM );35 }36 37 29 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 }45 30 thread_desc * nextThread(cluster * this); 46 31 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);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); 53 38 54 39 //----------------------------------------------------------------------------- … … 75 60 extern cluster * systemCluster; 76 61 extern system_proc_t * systemProcessor; 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; 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 } 81 82 82 83 //----------------------------------------------------------------------------- -
src/libcfa/concurrency/monitor
rb751c8e r8c680e9 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
rb751c8e r8c680e9 19 19 #include <stdlib> 20 20 21 #include "kernel_private.h" 21 22 #include "libhdr.h" 22 #include "kernel_private.h"23 23 24 24 //----------------------------------------------------------------------------- … … 44 44 45 45 extern "C" { 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);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 ourselves68 return; 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 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 _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 );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_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 ); 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 … … 188 159 // Internal scheduling 189 160 void wait( condition * this, uintptr_t user_info = 0 ) { 190 //LIB_DEBUG_PRINT_SAFE("Waiting\n");161 LIB_DEBUG_PRINT_SAFE("Waiting\n"); 191 162 192 163 brand_condition( this ); … … 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 BlockInternal202 203 //LIB_DEBUG_PRINT_SAFE("count %i\n", count);204 205 __condition_node_t waiter = { (thread_desc*)this_thread, count, user_info };172 spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal 173 174 LIB_DEBUG_PRINT_SAFE("count %i\n", count); 175 176 __condition_node_t waiter = { this_thread(), count, user_info }; 206 177 207 178 __condition_criterion_t criteria[count]; 208 179 for(int i = 0; i < count; i++) { 209 180 (&criteria[i]){ this->monitors[i], &waiter }; 210 //LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] );181 LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] ); 211 182 } 212 183 … … 230 201 } 231 202 232 //LIB_DEBUG_PRINT_SAFE("Will unblock: ");203 LIB_DEBUG_PRINT_SAFE("Will unblock: "); 233 204 for(int i = 0; i < thread_count; i++) { 234 //LIB_DEBUG_PRINT_SAFE("%p ", threads[i]);235 } 236 //LIB_DEBUG_PRINT_SAFE("\n");205 LIB_DEBUG_PRINT_SAFE("%p ", threads[i]); 206 } 207 LIB_DEBUG_PRINT_SAFE("\n"); 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 … … 251 222 bool signal( condition * this ) { 252 223 if( is_empty( this ) ) { 253 //LIB_DEBUG_PRINT_SAFE("Nothing to signal\n");224 LIB_DEBUG_PRINT_SAFE("Nothing to signal\n"); 254 225 return false; 255 226 } … … 260 231 261 232 unsigned short count = this->monitor_count; 262 233 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 ); … … 277 248 //Lock all the monitors 278 249 lock_all( this->monitors, NULL, count ); 279 //LIB_DEBUG_PRINT_SAFE("Signalling");250 LIB_DEBUG_PRINT_SAFE("Signalling"); 280 251 281 252 //Pop the head of the waiting queue … … 285 256 for(int i = 0; i < count; i++) { 286 257 __condition_criterion_t * crit = &node->criteria[i]; 287 //LIB_DEBUG_PRINT_SAFE(" %p", crit->target);258 LIB_DEBUG_PRINT_SAFE(" %p", crit->target); 288 259 assert( !crit->ready ); 289 260 push( &crit->target->signal_stack, crit ); 290 261 } 291 262 292 //LIB_DEBUG_PRINT_SAFE("\n");263 LIB_DEBUG_PRINT_SAFE("\n"); 293 264 294 265 //Release … … 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]; 320 291 for(int i = 0; i < count; i++) { 321 292 (&criteria[i]){ this->monitors[i], &waiter }; 322 //LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] );293 LIB_DEBUG_PRINT_SAFE( "Criterion %p\n", &criteria[i] ); 323 294 push( &criteria[i].target->signal_stack, &criteria[i] ); 324 295 } … … 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 … … 354 325 355 326 uintptr_t front( condition * this ) { 356 verifyf( !is_empty(this), 327 verifyf( !is_empty(this), 357 328 "Attempt to access user data on an empty condition.\n" 358 329 "Possible cause is not checking if the condition is empty before reading stored data." … … 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 _yield( locks[i] DEBUG_CTX2);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 _yield( l DEBUG_CTX2);402 lock( l ); 432 403 if(locks) locks[i] = l; 433 404 } … … 472 443 for( int i = 0; i < count; i++ ) { 473 444 474 //LIB_DEBUG_PRINT_SAFE( "Checking %p for %p\n", &criteria[i], target );445 LIB_DEBUG_PRINT_SAFE( "Checking %p for %p\n", &criteria[i], target ); 475 446 if( &criteria[i] == target ) { 476 447 criteria[i].ready = true; 477 //LIB_DEBUG_PRINT_SAFE( "True\n" );448 LIB_DEBUG_PRINT_SAFE( "True\n" ); 478 449 } 479 450 … … 481 452 } 482 453 483 //LIB_DEBUG_PRINT_SAFE( "Runing %i\n", ready2run );454 LIB_DEBUG_PRINT_SAFE( "Runing %i\n", ready2run ); 484 455 return ready2run ? node->waiting_thread : NULL; 485 456 } 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 //LIB_DEBUG_PRINT_SAFE("Branding\n");461 LIB_DEBUG_PRINT_SAFE("Branding\n"); 491 462 assertf( thrd->current_monitors != NULL, "No current monitor to brand condition", thrd->current_monitors ); 492 463 this->monitor_count = thrd->current_monitor_count; -
src/libcfa/concurrency/preemption.c
rb751c8e r8c680e9 15 15 // 16 16 17 #include "libhdr.h"18 17 #include "preemption.h" 19 18 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 36 #define __CFA_DEFAULT_PREEMPTION__ 10000 23 #define __CFA_DEFAULT_PREEMPTION__ 10 37 24 38 25 __attribute__((weak)) unsigned int default_preemption() { … … 40 27 } 41 28 42 #define __CFA_SIGCXT__ ucontext_t *43 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt44 45 29 static void preempt( processor * this ); 46 30 static void timeout( thread_desc * this ); 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 31 55 32 //============================================================================================= … … 58 35 59 36 void kernel_start_preemption() { 60 LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n"); 61 __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); 62 __kernel_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO ); 63 __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); 64 __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); 65 // __kernel_sigaction( SIGABRT, sigHandler_abort , SA_SIGINFO ); 37 66 38 } 67 39 68 void kernel_stop_preemption() {69 //Block all signals, we are no longer in a position to handle them70 sigset_t mask;71 sigfillset( &mask );72 sigprocmask( SIG_BLOCK, &mask, NULL );73 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");74 75 // assert( !systemProcessor->alarms.head );76 // assert( systemProcessor->alarms.tail == &systemProcessor->alarms.head );77 }78 79 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )80 81 40 void tick_preemption() { 82 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );83 84 41 alarm_list_t * alarms = &systemProcessor->alarms; 85 42 __cfa_time_t currtime = __kernel_get_time(); 86 43 while( alarms->head && alarms->head->alarm < currtime ) { 87 44 alarm_node_t * node = pop(alarms); 88 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node );89 90 45 if( node->kernel_alarm ) { 91 46 preempt( node->proc ); … … 95 50 } 96 51 97 verify( validate( alarms ) );98 99 52 if( node->period > 0 ) { 100 node->alarm = currtime +node->period;53 node->alarm += node->period; 101 54 insert( alarms, node ); 102 55 } … … 109 62 __kernel_set_timer( alarms->head->alarm - currtime ); 110 63 } 111 112 verify( validate( alarms ) );113 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" );114 64 } 115 65 116 66 void update_preemption( processor * this, __cfa_time_t duration ) { 117 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration ); 118 67 // assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 ); 119 68 alarm_node_t * alarm = this->preemption_alarm; 120 duration *= 1000;121 69 122 70 // Alarms need to be enabled … … 149 97 150 98 void ^?{}( preemption_scope * this ) { 151 disable_interrupts();152 153 99 update_preemption( this->proc, 0 ); 154 100 } … … 158 104 //============================================================================================= 159 105 160 LIB_DEBUG_DO( static thread_local void * last_interrupt = 0; )161 162 extern "C" {163 void disable_interrupts() {164 __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST );165 verify( new_val < (unsigned short)65_000 );166 verify( new_val != (unsigned short) 0 );167 }168 169 void enable_interrupts_noRF() {170 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );171 verify( prev != (unsigned short) 0 );172 }173 174 void enable_interrupts( DEBUG_CTX_PARAM ) {175 processor * proc = this_processor;176 thread_desc * thrd = this_thread;177 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );178 verify( prev != (unsigned short) 0 );179 if( prev == 1 && proc->pending_preemption ) {180 proc->pending_preemption = false;181 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Executing deferred CtxSwitch on %p\n", this_processor );182 BlockInternal( thrd );183 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Executing deferred back\n" );184 }185 186 LIB_DEBUG_DO( proc->last_enable = caller; )187 }188 }189 190 static inline void signal_unblock( int sig ) {191 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p unblocking sig %i\n", this_processor, sig );192 193 // LIB_DEBUG_DO(194 // sigset_t waiting;195 // sigemptyset(&waiting);196 // sigpending(&waiting);197 // verify( !sigismember(&waiting, sig) );198 // )199 200 sigset_t mask;201 sigemptyset( &mask );202 sigaddset( &mask, sig );203 204 if ( sigprocmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {205 abortf( "internal error, sigprocmask" );206 } // if207 }208 209 106 static inline bool preemption_ready() { 210 return disable_preempt_count == 0;107 return this_processor->disable_preempt_count == 0; 211 108 } 212 109 … … 219 116 } 220 117 221 extern "C" { 222 __attribute__((noinline)) void __debug_break() { 223 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(); 224 124 } 225 125 } 226 126 227 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 228 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "CtxSw IRH %10p running %10p @ %10p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) ); 229 LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[REG_RIP]); ) 230 231 if( preemption_ready() ) { 232 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Blocking thread %p on %p\n", this_thread, this_processor ); 233 signal_unblock( SIGUSR1 ); 234 BlockInternal( (thread_desc*)this_thread ); 235 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Back\n\n"); 236 } 237 else { 238 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Defering\n" ); 239 defer_ctxSwitch(); 240 signal_unblock( SIGUSR1 ); 241 } 242 } 243 244 void sigHandler_alarm( __CFA_SIGPARMS__ ) { 245 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "\nAlarm IRH %10p running %10p @ %10p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) ); 246 LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[REG_RIP]); ) 247 248 if( try_lock( &systemProcessor->alarm_lock DEBUG_CTX2 ) ) { 127 void sigHandler_alarm( __attribute__((unused)) int sig ) { 128 if( try_lock( &systemProcessor->alarm_lock ) ) { 249 129 tick_preemption(); 250 130 unlock( &systemProcessor->alarm_lock ); … … 253 133 defer_alarm(); 254 134 } 255 256 signal_unblock( SIGALRM );257 258 if( preemption_ready() && this_processor->pending_preemption ) {259 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm IRH : Blocking thread %p on %p\n", this_thread, this_processor );260 this_processor->pending_preemption = false;261 BlockInternal( (thread_desc*)this_thread );262 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm Switch IRH : Back\n\n");263 }264 135 } 265 136 266 137 static void preempt( processor * this ) { 267 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : signalling %p\n", this ); 268 269 if( this != systemProcessor ) { 270 pthread_kill( this->kernel_thread, SIGUSR1 ); 271 } 272 else { 273 defer_ctxSwitch(); 274 } 138 pthread_kill( this->kernel_thread, SIGUSR1 ); 275 139 } 276 140 … … 278 142 //TODO : implement waking threads 279 143 } 280 281 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {282 struct sigaction act;283 284 act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;285 act.sa_flags = flags;286 287 // disabled during signal handler288 sigemptyset( &act.sa_mask );289 sigaddset( &act.sa_mask, sig );290 291 if ( sigaction( sig, &act, NULL ) == -1 ) {292 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,293 " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",294 sig, handler, flags, errno, strerror( errno )295 );296 _exit( EXIT_FAILURE );297 }298 }299 300 typedef void (*sa_handler_t)(int);301 302 static void __kernel_sigdefault( int sig ) {303 struct sigaction act;304 305 // act.sa_handler = SIG_DFL;306 act.sa_flags = 0;307 sigemptyset( &act.sa_mask );308 309 if ( sigaction( sig, &act, NULL ) == -1 ) {310 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,311 " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",312 sig, errno, strerror( errno )313 );314 _exit( EXIT_FAILURE );315 }316 }317 318 //=============================================================================================319 // Terminating Signals logic320 //=============================================================================================321 322 LIB_DEBUG_DO(323 static void __kernel_backtrace( int start ) {324 // skip first N stack frames325 326 enum { Frames = 50 };327 void * array[Frames];328 int size = backtrace( array, Frames );329 char ** messages = backtrace_symbols( array, size );330 331 // find executable name332 *index( messages[0], '(' ) = '\0';333 #ifdef __USE_STREAM__334 serr | "Stack back trace for:" | messages[0] | endl;335 #else336 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);337 #endif338 339 // skip last 2 stack frames after main340 for ( int i = start; i < size && messages != NULL; i += 1 ) {341 char * name = NULL;342 char * offset_begin = NULL;343 char * offset_end = NULL;344 345 for ( char *p = messages[i]; *p; ++p ) {346 // find parantheses and +offset347 if ( *p == '(' ) {348 name = p;349 }350 else if ( *p == '+' ) {351 offset_begin = p;352 }353 else if ( *p == ')' ) {354 offset_end = p;355 break;356 }357 }358 359 // if line contains symbol print it360 int frameNo = i - start;361 if ( name && offset_begin && offset_end && name < offset_begin ) {362 // delimit strings363 *name++ = '\0';364 *offset_begin++ = '\0';365 *offset_end++ = '\0';366 367 #ifdef __USE_STREAM__368 serr | "(" | frameNo | ")" | messages[i] | ":"369 | name | "+" | offset_begin | offset_end | endl;370 #else371 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);372 #endif373 }374 // otherwise, print the whole line375 else {376 #ifdef __USE_STREAM__377 serr | "(" | frameNo | ")" | messages[i] | endl;378 #else379 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );380 #endif381 }382 }383 384 free( messages );385 }386 )387 388 void sigHandler_segv( __CFA_SIGPARMS__ ) {389 LIB_DEBUG_DO(390 #ifdef __USE_STREAM__391 serr | "*CFA runtime error* program cfa-cpp terminated with"392 | (sig == SIGSEGV ? "segment fault." : "bus error.")393 | endl;394 #else395 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );396 #endif397 398 // skip first 2 stack frames399 __kernel_backtrace( 1 );400 )401 exit( EXIT_FAILURE );402 }403 404 // void sigHandler_abort( __CFA_SIGPARMS__ ) {405 // // skip first 6 stack frames406 // LIB_DEBUG_DO( __kernel_backtrace( 6 ); )407 408 // // reset default signal handler409 // __kernel_sigdefault( SIGABRT );410 411 // raise( SIGABRT );412 // } -
src/libcfa/concurrency/thread
rb751c8e r8c680e9 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
rb751c8e r8c680e9 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( DEBUG_CTX );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/libalign.h
rb751c8e r8c680e9 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>36 35 37 // Minimum size used to align memory boundaries for memory allocations. 36 // Minimum size used to align memory boundaries for memory allocations. 38 37 #define libAlign() (sizeof(double)) 39 38 -
src/libcfa/libhdr/libdebug.h
rb751c8e r8c680e9 18 18 19 19 #ifdef __CFA_DEBUG__ 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 20 #define LIB_DEBUG_DO(x) x 21 #define LIB_NO_DEBUG_DO(x) ((void)0) 26 22 #else 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 23 #define LIB_DEBUG_DO(x) ((void)0) 24 #define LIB_NO_DEBUG_DO(x) x 33 25 #endif 34 26 … … 59 51 60 52 #ifdef __CFA_DEBUG_PRINT__ 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 ); 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__) 69 59 #else 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) 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) 78 66 #endif 79 67 -
src/tests/sched-int-block.c
rb751c8e r8c680e9 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.