source: src/libcfa/concurrency/kernel.c@ 9c47a47

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 9c47a47 was c2b9f21, checked in by Thierry Delisle <tdelisle@…>, 8 years ago

Removed libhdr, moved its content to bits

  • Property mode set to 100644
File size: 17.5 KB
RevLine 
[8118303]1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// kernel.c --
8//
9// Author : Thierry Delisle
[75f3522]10// Created On : Tue Jan 17 12:27:26 2017
[6b0b624]11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Jul 21 22:33:18 2017
13// Update Count : 2
[8118303]14//
15
16//C Includes
[c84e80a]17#include <stddef.h>
[eb2e723]18extern "C" {
[9d944b2]19#include <stdio.h>
[8fcbb4c]20#include <fenv.h>
[eb2e723]21#include <sys/resource.h>
[9d944b2]22#include <signal.h>
23#include <unistd.h>
[eb2e723]24}
[8118303]25
26//CFA Includes
[2ac095d]27#include "kernel_private.h"
[c81ebf9]28#include "preemption.h"
[2ac095d]29#include "startup.h"
[8118303]30
31//Private includes
32#define __CFA_INVOKE_PRIVATE__
33#include "invoke.h"
34
[2ac095d]35//Start and stop routine for the kernel, declared first to make sure they run first
36void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
37void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
38
[8def349]39//-----------------------------------------------------------------------------
40// Kernel storage
[969b3fe]41KERNEL_STORAGE(cluster, mainCluster);
42KERNEL_STORAGE(processor, mainProcessor);
43KERNEL_STORAGE(processorCtx_t, mainProcessorCtx);
44KERNEL_STORAGE(thread_desc, mainThread);
[f2b12406]45KERNEL_STORAGE(machine_context_t, mainThreadCtx);
[8def349]46
[969b3fe]47cluster * mainCluster;
48processor * mainProcessor;
[348006f]49thread_desc * mainThread;
[eb2e723]50
[bd98b58]51//-----------------------------------------------------------------------------
52// Global state
53
[9cc0472]54thread_local coroutine_desc * volatile this_coroutine;
55thread_local thread_desc * volatile this_thread;
56thread_local processor * volatile this_processor;
[969b3fe]57
[d6ff3ff]58volatile thread_local bool preemption_in_progress = 0;
[1c273d0]59volatile thread_local unsigned short disable_preempt_count = 1;
[c84e80a]60
61//-----------------------------------------------------------------------------
[8def349]62// Main thread construction
63struct current_stack_info_t {
[1c273d0]64 machine_context_t ctx;
[8def349]65 unsigned int size; // size of stack
66 void *base; // base of stack
67 void *storage; // pointer to stack
68 void *limit; // stack grows towards stack limit
69 void *context; // address of cfa_context_t
70 void *top; // address of top of storage
[c84e80a]71};
72
[242a902]73void ?{}( current_stack_info_t & this ) {
74 CtxGet( this.ctx );
75 this.base = this.ctx.FP;
76 this.storage = this.ctx.SP;
[8def349]77
78 rlimit r;
[132fad4]79 getrlimit( RLIMIT_STACK, &r);
[242a902]80 this.size = r.rlim_cur;
[8def349]81
[242a902]82 this.limit = (void *)(((intptr_t)this.base) - this.size);
[9236060]83 this.context = &storage_mainThreadCtx;
[242a902]84 this.top = this.base;
[8def349]85}
86
[242a902]87void ?{}( coStack_t & this, current_stack_info_t * info) {
88 this.size = info->size;
89 this.storage = info->storage;
90 this.limit = info->limit;
91 this.base = info->base;
92 this.context = info->context;
93 this.top = info->top;
94 this.userStack = true;
[8def349]95}
96
[242a902]97void ?{}( coroutine_desc & this, current_stack_info_t * info) {
98 (this.stack){ info };
99 this.name = "Main Thread";
100 this.errno_ = 0;
101 this.state = Start;
[39fea2f]102 this.starter = NULL;
[8def349]103}
104
[242a902]105void ?{}( thread_desc & this, current_stack_info_t * info) {
[b18830e]106 (this.self_cor){ info };
[8def349]107}
[c84e80a]108
[8def349]109//-----------------------------------------------------------------------------
110// Processor coroutine
[39fea2f]111
112// Construct the processor context of the main processor
[242a902]113void ?{}(processorCtx_t & this, processor * proc) {
114 (this.__cor){ "Processor" };
[b462670]115 this.__cor.starter = NULL;
[242a902]116 this.proc = proc;
117 proc->runner = &this;
[8def349]118}
119
[39fea2f]120// Construct the processor context of non-main processors
[242a902]121void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
122 (this.__cor){ info };
123 this.proc = proc;
124 proc->runner = &this;
[8def349]125}
126
[242a902]127void ?{}(processor & this) {
[969b3fe]128 this{ mainCluster };
[8def349]129}
130
[242a902]131void ?{}(processor & this, cluster * cltr) {
132 this.cltr = cltr;
133 (this.terminated){ 0 };
[9236060]134 this.do_terminate = false;
[242a902]135 this.preemption_alarm = NULL;
136 this.pending_preemption = false;
[8def349]137
[242a902]138 start( &this );
[c84e80a]139}
140
[83a071f9]141void ?{}(processor & this, cluster * cltr, processorCtx_t & runner) {
[242a902]142 this.cltr = cltr;
143 (this.terminated){ 0 };
[9236060]144 this.do_terminate = false;
[242a902]145 this.preemption_alarm = NULL;
146 this.pending_preemption = false;
147 this.kernel_thread = pthread_self();
[8def349]148
[83a071f9]149 this.runner = &runner;
[36982fc]150 __cfaabi_dbg_print_safe("Kernel : constructing main processor context %p\n", &runner);
[83a071f9]151 runner{ &this };
[8def349]152}
153
[242a902]154void ^?{}(processor & this) {
[9236060]155 if( ! this.do_terminate ) {
[36982fc]156 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
[9236060]157 this.do_terminate = true;
[4cedd9f]158 P( this.terminated );
[242a902]159 pthread_join( this.kernel_thread, NULL );
[8def349]160 }
161}
162
[242a902]163void ?{}(cluster & this) {
[0cf5b79]164 (this.ready_queue){};
[9236060]165 ( this.ready_queue_lock ){};
[e60e0dc]166
[9236060]167 this.preemption = default_preemption();
[8def349]168}
169
[242a902]170void ^?{}(cluster & this) {
[1c273d0]171
[c84e80a]172}
173
[75f3522]174//=============================================================================================
175// Kernel Scheduling logic
176//=============================================================================================
[8fcbb4c]177//Main of the processor contexts
[83a071f9]178void main(processorCtx_t & runner) {
179 processor * this = runner.proc;
[c81ebf9]180
[36982fc]181 __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
[8118303]182
[75f3522]183 {
[c81ebf9]184 // Setup preemption data
185 preemption_scope scope = { this };
186
[36982fc]187 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
[8118303]188
[c81ebf9]189 thread_desc * readyThread = NULL;
[e60e0dc]190 for( unsigned int spin_count = 0; ! this->do_terminate; spin_count++ )
[75f3522]191 {
[c81ebf9]192 readyThread = nextThread( this->cltr );
[75f3522]193
[c81ebf9]194 if(readyThread)
195 {
[0b33412]196 verify( disable_preempt_count > 0 );
[4e6fb8e]197
[c81ebf9]198 runThread(this, readyThread);
[75f3522]199
[0b33412]200 verify( disable_preempt_count > 0 );
[4e6fb8e]201
[c81ebf9]202 //Some actions need to be taken from the kernel
203 finishRunning(this);
204
205 spin_count = 0;
206 }
207 else
208 {
209 spin(this, &spin_count);
210 }
211 }
212
[36982fc]213 __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this);
[c84e80a]214 }
[8118303]215
[4cedd9f]216 V( this->terminated );
[bdeba0b]217
[36982fc]218 __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
[c84e80a]219}
220
[1c273d0]221// runThread runs a thread by context switching
222// from the processor coroutine to the target thread
[348006f]223void runThread(processor * this, thread_desc * dst) {
[83a071f9]224 coroutine_desc * proc_cor = get_coroutine(*this->runner);
[c3acb841]225 coroutine_desc * thrd_cor = get_coroutine(dst);
[1c273d0]226
[75f3522]227 //Reset the terminating actions here
[db6f06a]228 this->finish.action_code = No_Action;
[8fcbb4c]229
[75f3522]230 //Update global state
[1c273d0]231 this_thread = dst;
[75f3522]232
233 // Context Switch to the thread
234 ThreadCtxSwitch(proc_cor, thrd_cor);
235 // when ThreadCtxSwitch returns we are back in the processor coroutine
236}
237
[1c273d0]238// Once a thread has finished running, some of
[75f3522]239// its final actions must be executed from the kernel
[db6f06a]240void finishRunning(processor * this) {
241 if( this->finish.action_code == Release ) {
[ea7d2b0]242 unlock( *this->finish.lock );
[db6f06a]243 }
244 else if( this->finish.action_code == Schedule ) {
245 ScheduleThread( this->finish.thrd );
246 }
247 else if( this->finish.action_code == Release_Schedule ) {
[ea7d2b0]248 unlock( *this->finish.lock );
[db6f06a]249 ScheduleThread( this->finish.thrd );
250 }
[0c78741]251 else if( this->finish.action_code == Release_Multi ) {
252 for(int i = 0; i < this->finish.lock_count; i++) {
[ea7d2b0]253 unlock( *this->finish.locks[i] );
[0c78741]254 }
255 }
256 else if( this->finish.action_code == Release_Multi_Schedule ) {
257 for(int i = 0; i < this->finish.lock_count; i++) {
[ea7d2b0]258 unlock( *this->finish.locks[i] );
[0c78741]259 }
260 for(int i = 0; i < this->finish.thrd_count; i++) {
261 ScheduleThread( this->finish.thrds[i] );
262 }
263 }
[db6f06a]264 else {
265 assert(this->finish.action_code == No_Action);
[8fcbb4c]266 }
[c84e80a]267}
268
[0c92c9f]269// Handles spinning logic
270// TODO : find some strategy to put cores to sleep after some time
[c84e80a]271void spin(processor * this, unsigned int * spin_count) {
272 (*spin_count)++;
273}
274
[0c92c9f]275// Context invoker for processors
276// This is the entry point for processors (kernel threads)
277// It effectively constructs a coroutine by stealing the pthread stack
[8def349]278void * CtxInvokeProcessor(void * arg) {
279 processor * proc = (processor *) arg;
280 this_processor = proc;
[1c273d0]281 this_coroutine = NULL;
282 this_thread = NULL;
[4e6fb8e]283 disable_preempt_count = 1;
[8def349]284 // SKULLDUGGERY: We want to create a context for the processor coroutine
285 // which is needed for the 2-step context switch. However, there is no reason
[1c273d0]286 // to waste the perfectly valid stack create by pthread.
[8def349]287 current_stack_info_t info;
288 machine_context_t ctx;
289 info.context = &ctx;
290 processorCtx_t proc_cor_storage = { proc, &info };
291
[36982fc]292 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", proc_cor_storage.__cor.stack.base);
[8fcbb4c]293
[0c92c9f]294 //Set global state
[1c273d0]295 this_coroutine = &proc->runner->__cor;
296 this_thread = NULL;
[8def349]297
298 //We now have a proper context from which to schedule threads
[36982fc]299 __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
[8def349]300
[1c273d0]301 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
302 // resume it to start it like it normally would, it will just context switch
303 // back to here. Instead directly call the main since we already are on the
[8def349]304 // appropriate stack.
[17af7d1]305 proc_cor_storage.__cor.state = Active;
[83a071f9]306 main( proc_cor_storage );
[4aa2fb2]307 proc_cor_storage.__cor.state = Halted;
[8def349]308
[0c92c9f]309 // Main routine of the core returned, the core is now fully terminated
[36982fc]310 __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, proc->runner);
[8def349]311
312 return NULL;
[c84e80a]313}
314
[8def349]315void start(processor * this) {
[36982fc]316 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
[82ff5845]317
[8fcbb4c]318 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
[eb2e723]319
[36982fc]320 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
[eb2e723]321}
322
[8def349]323//-----------------------------------------------------------------------------
324// Scheduler routines
[348006f]325void ScheduleThread( thread_desc * thrd ) {
[1c273d0]326 // if( !thrd ) return;
[135b431]327 verify( thrd );
[b18830e]328 verify( thrd->self_cor.state != Halted );
[1c273d0]329
330 verify( disable_preempt_count > 0 );
[690f13c]331
[4aa2fb2]332 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
[1c273d0]333
[36982fc]334 lock( this_processor->cltr->ready_queue_lock __cfaabi_dbg_ctx2 );
[8fc45b7]335 append( this_processor->cltr->ready_queue, thrd );
[ea7d2b0]336 unlock( this_processor->cltr->ready_queue_lock );
[1c273d0]337
338 verify( disable_preempt_count > 0 );
[db6f06a]339}
340
[348006f]341thread_desc * nextThread(cluster * this) {
[1c273d0]342 verify( disable_preempt_count > 0 );
[36982fc]343 lock( this->ready_queue_lock __cfaabi_dbg_ctx2 );
[8fc45b7]344 thread_desc * head = pop_head( this->ready_queue );
[ea7d2b0]345 unlock( this->ready_queue_lock );
[1c273d0]346 verify( disable_preempt_count > 0 );
[db6f06a]347 return head;
[eb2e723]348}
349
[82ff5845]350void BlockInternal() {
351 disable_interrupts();
[0b33412]352 verify( disable_preempt_count > 0 );
[75f3522]353 suspend();
[0b33412]354 verify( disable_preempt_count > 0 );
[36982fc]355 enable_interrupts( __cfaabi_dbg_ctx );
[75f3522]356}
357
[ea7d2b0]358void BlockInternal( __spinlock_t * lock ) {
[82ff5845]359 disable_interrupts();
[89a3df5]360 this_processor->finish.action_code = Release;
361 this_processor->finish.lock = lock;
[0b33412]362
363 verify( disable_preempt_count > 0 );
[db6f06a]364 suspend();
[0b33412]365 verify( disable_preempt_count > 0 );
366
[36982fc]367 enable_interrupts( __cfaabi_dbg_ctx );
[db6f06a]368}
369
[82ff5845]370void BlockInternal( thread_desc * thrd ) {
[97e3296]371 assert(thrd);
[82ff5845]372 disable_interrupts();
[b18830e]373 assert( thrd->self_cor.state != Halted );
[89a3df5]374 this_processor->finish.action_code = Schedule;
375 this_processor->finish.thrd = thrd;
[0b33412]376
377 verify( disable_preempt_count > 0 );
[db6f06a]378 suspend();
[0b33412]379 verify( disable_preempt_count > 0 );
380
[36982fc]381 enable_interrupts( __cfaabi_dbg_ctx );
[db6f06a]382}
383
[ea7d2b0]384void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) {
[97e3296]385 assert(thrd);
[82ff5845]386 disable_interrupts();
[89a3df5]387 this_processor->finish.action_code = Release_Schedule;
388 this_processor->finish.lock = lock;
389 this_processor->finish.thrd = thrd;
[0b33412]390
391 verify( disable_preempt_count > 0 );
[db6f06a]392 suspend();
[0b33412]393 verify( disable_preempt_count > 0 );
394
[36982fc]395 enable_interrupts( __cfaabi_dbg_ctx );
[eb2e723]396}
397
[ea7d2b0]398void BlockInternal(__spinlock_t * locks [], unsigned short count) {
[82ff5845]399 disable_interrupts();
[0c78741]400 this_processor->finish.action_code = Release_Multi;
401 this_processor->finish.locks = locks;
402 this_processor->finish.lock_count = count;
[0b33412]403
404 verify( disable_preempt_count > 0 );
[0c78741]405 suspend();
[0b33412]406 verify( disable_preempt_count > 0 );
407
[36982fc]408 enable_interrupts( __cfaabi_dbg_ctx );
[0c78741]409}
410
[ea7d2b0]411void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
[82ff5845]412 disable_interrupts();
[0c78741]413 this_processor->finish.action_code = Release_Multi_Schedule;
414 this_processor->finish.locks = locks;
415 this_processor->finish.lock_count = lock_count;
416 this_processor->finish.thrds = thrds;
417 this_processor->finish.thrd_count = thrd_count;
[0b33412]418
419 verify( disable_preempt_count > 0 );
[0c78741]420 suspend();
[0b33412]421 verify( disable_preempt_count > 0 );
422
[36982fc]423 enable_interrupts( __cfaabi_dbg_ctx );
[0c78741]424}
425
[ea7d2b0]426void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
[f2b12406]427 verify( disable_preempt_count > 0 );
428 this_processor->finish.action_code = thrd ? Release_Schedule : Release;
429 this_processor->finish.lock = lock;
430 this_processor->finish.thrd = thrd;
431
432 suspend();
433}
434
[fa21ac9]435//=============================================================================================
436// Kernel Setup logic
437//=============================================================================================
[eb2e723]438//-----------------------------------------------------------------------------
439// Kernel boot procedures
440void kernel_startup(void) {
[36982fc]441 __cfaabi_dbg_print_safe("Kernel : Starting\n");
[eb2e723]442
443 // Start by initializing the main thread
[1c273d0]444 // SKULLDUGGERY: the mainThread steals the process main thread
[969b3fe]445 // which will then be scheduled by the mainProcessor normally
446 mainThread = (thread_desc *)&storage_mainThread;
[8fcbb4c]447 current_stack_info_t info;
[83a071f9]448 (*mainThread){ &info };
[eb2e723]449
[36982fc]450 __cfaabi_dbg_print_safe("Kernel : Main thread ready\n");
[fa21ac9]451
[969b3fe]452 // Initialize the main cluster
453 mainCluster = (cluster *)&storage_mainCluster;
[9236060]454 (*mainCluster){};
[bd98b58]455
[36982fc]456 __cfaabi_dbg_print_safe("Kernel : main cluster ready\n");
[fa21ac9]457
[969b3fe]458 // Initialize the main processor and the main processor ctx
[eb2e723]459 // (the coroutine that contains the processing control flow)
[969b3fe]460 mainProcessor = (processor *)&storage_mainProcessor;
[9236060]461 (*mainProcessor){ mainCluster, *(processorCtx_t *)&storage_mainProcessorCtx };
[eb2e723]462
[dcb42b8]463 //initialize the global state variables
[969b3fe]464 this_processor = mainProcessor;
[1c273d0]465 this_thread = mainThread;
[b18830e]466 this_coroutine = &mainThread->self_cor;
[eb2e723]467
[82ff5845]468 // Enable preemption
469 kernel_start_preemption();
470
[969b3fe]471 // Add the main thread to the ready queue
472 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
473 ScheduleThread(mainThread);
474
475 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
[dcb42b8]476 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
[1c273d0]477 // mainThread is on the ready queue when this call is made.
[9236060]478 resume( *mainProcessor->runner );
[eb2e723]479
[dcb42b8]480
481
482 // THE SYSTEM IS NOW COMPLETELY RUNNING
[36982fc]483 __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
[82ff5845]484
[36982fc]485 enable_interrupts( __cfaabi_dbg_ctx );
[eb2e723]486}
487
[dcb42b8]488void kernel_shutdown(void) {
[36982fc]489 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
[eb2e723]490
[4e6fb8e]491 disable_interrupts();
492
[969b3fe]493 // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
[dcb42b8]494 // When its coroutine terminates, it return control to the mainThread
495 // which is currently here
[969b3fe]496 mainProcessor->do_terminate = true;
[eb2e723]497 suspend();
498
[dcb42b8]499 // THE SYSTEM IS NOW COMPLETELY STOPPED
[eb2e723]500
[82ff5845]501 // Disable preemption
502 kernel_stop_preemption();
503
[969b3fe]504 // Destroy the main processor and its context in reverse order of construction
[dcb42b8]505 // These were manually constructed so we need manually destroy them
[9236060]506 ^(*mainProcessor->runner){};
[969b3fe]507 ^(mainProcessor){};
[eb2e723]508
[dcb42b8]509 // Final step, destroy the main thread since it is no longer needed
510 // Since we provided a stack to this taxk it will not destroy anything
[eb2e723]511 ^(mainThread){};
512
[36982fc]513 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
[9d944b2]514}
515
[ea7d2b0]516static __spinlock_t kernel_abort_lock;
517static __spinlock_t kernel_debug_lock;
[9d944b2]518static bool kernel_abort_called = false;
519
520void * kernel_abort (void) __attribute__ ((__nothrow__)) {
521 // abort cannot be recursively entered by the same or different processors because all signal handlers return when
522 // the globalAbort flag is true.
[36982fc]523 lock( kernel_abort_lock __cfaabi_dbg_ctx2 );
[9d944b2]524
525 // first task to abort ?
526 if ( !kernel_abort_called ) { // not first task to abort ?
527 kernel_abort_called = true;
[ea7d2b0]528 unlock( kernel_abort_lock );
[1c273d0]529 }
[9d944b2]530 else {
[ea7d2b0]531 unlock( kernel_abort_lock );
[1c273d0]532
[9d944b2]533 sigset_t mask;
534 sigemptyset( &mask );
535 sigaddset( &mask, SIGALRM ); // block SIGALRM signals
536 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals
537 sigsuspend( &mask ); // block the processor to prevent further damage during abort
[1c273d0]538 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it
[9d944b2]539 }
540
[1c273d0]541 return this_thread;
[9d944b2]542}
543
544void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
545 thread_desc * thrd = kernel_data;
546
[b18830e]547 int len = snprintf( abort_text, abort_text_size, "Error occurred while executing task %.256s (%p)", thrd->self_cor.name, thrd );
[36982fc]548 __cfaabi_dbg_bits_write( abort_text, len );
[9d944b2]549
[1c273d0]550 if ( thrd != this_coroutine ) {
551 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine );
[36982fc]552 __cfaabi_dbg_bits_write( abort_text, len );
[1c273d0]553 }
[9d944b2]554 else {
[36982fc]555 __cfaabi_dbg_bits_write( ".\n", 2 );
[9d944b2]556 }
557}
558
559extern "C" {
[36982fc]560 void __cfaabi_dbg_bits_acquire() {
561 lock( kernel_debug_lock __cfaabi_dbg_ctx2 );
[9d944b2]562 }
563
[36982fc]564 void __cfaabi_dbg_bits_release() {
[ea7d2b0]565 unlock( kernel_debug_lock );
[9d944b2]566 }
[8118303]567}
568
[fa21ac9]569//=============================================================================================
570// Kernel Utilities
571//=============================================================================================
[bd98b58]572//-----------------------------------------------------------------------------
573// Locks
[242a902]574void ?{}( semaphore & this, int count = 1 ) {
575 (this.lock){};
576 this.count = count;
577 (this.waiting){};
[db6f06a]578}
[242a902]579void ^?{}(semaphore & this) {}
[db6f06a]580
[4cedd9f]581void P(semaphore & this) {
[36982fc]582 lock( this.lock __cfaabi_dbg_ctx2 );
[4cedd9f]583 this.count -= 1;
584 if ( this.count < 0 ) {
[bdeba0b]585 // queue current task
[8fc45b7]586 append( this.waiting, (thread_desc *)this_thread );
[bdeba0b]587
588 // atomically release spin lock and block
[4cedd9f]589 BlockInternal( &this.lock );
[8def349]590 }
[4e6fb8e]591 else {
[ea7d2b0]592 unlock( this.lock );
[4e6fb8e]593 }
[bd98b58]594}
595
[4cedd9f]596void V(semaphore & this) {
[bdeba0b]597 thread_desc * thrd = NULL;
[36982fc]598 lock( this.lock __cfaabi_dbg_ctx2 );
[4cedd9f]599 this.count += 1;
600 if ( this.count <= 0 ) {
[bdeba0b]601 // remove task at head of waiting list
[8fc45b7]602 thrd = pop_head( this.waiting );
[bd98b58]603 }
[bdeba0b]604
[ea7d2b0]605 unlock( this.lock );
[bdeba0b]606
607 // make new owner
608 WakeThread( thrd );
[bd98b58]609}
610
[8118303]611// Local Variables: //
612// mode: c //
613// tab-width: 4 //
614// End: //
Note: See TracBrowser for help on using the repository browser.