Ignore:
Timestamp:
Jul 19, 2017, 11:49:33 AM (8 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
9cc0472
Parents:
fea3faa (diff), a57cb58 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/kernel.c

    rfea3faa rb826e6b  
    1515//
    1616
    17 #include "startup.h"
    18 
    19 //Start and stop routine for the kernel, declared first to make sure they run first
    20 void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
    21 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
    22 
    23 //Header
    24 #include "kernel_private.h"
     17#include "libhdr.h"
    2518
    2619//C Includes
     
    3528
    3629//CFA Includes
    37 #include "libhdr.h"
     30#include "kernel_private.h"
    3831#include "preemption.h"
     32#include "startup.h"
    3933
    4034//Private includes
     
    4236#include "invoke.h"
    4337
     38//Start and stop routine for the kernel, declared first to make sure they run first
     39void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     40void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
     41
    4442//-----------------------------------------------------------------------------
    4543// Kernel storage
    46 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
    47 
    48 KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
    49 KERNEL_STORAGE(cluster, systemCluster);
    50 KERNEL_STORAGE(system_proc_t, systemProcessor);
    51 KERNEL_STORAGE(thread_desc, mainThread);
    52 KERNEL_STORAGE(machine_context_t, mainThread_context);
    53 
    54 cluster * systemCluster;
    55 system_proc_t * systemProcessor;
     44KERNEL_STORAGE(cluster,           mainCluster);
     45KERNEL_STORAGE(processor,         mainProcessor);
     46KERNEL_STORAGE(processorCtx_t,    mainProcessorCtx);
     47KERNEL_STORAGE(thread_desc,       mainThread);
     48KERNEL_STORAGE(machine_context_t, mainThreadCtx);
     49
     50cluster *     mainCluster;
     51processor *   mainProcessor;
    5652thread_desc * mainThread;
    5753
     
    5955// Global state
    6056
    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 }
     57volatile thread_local coroutine_desc * this_coroutine;
     58volatile thread_local thread_desc * this_thread;
     59volatile thread_local processor * this_processor;
     60
     61volatile thread_local bool preemption_in_progress = 0;
     62volatile thread_local unsigned short disable_preempt_count = 1;
    7063
    7164//-----------------------------------------------------------------------------
    7265// Main thread construction
    7366struct current_stack_info_t {
    74         machine_context_t ctx; 
     67        machine_context_t ctx;
    7568        unsigned int size;              // size of stack
    7669        void *base;                             // base of stack
     
    8275
    8376void ?{}( current_stack_info_t * this ) {
    84         CtxGet( &this->ctx );
     77        CtxGet( this->ctx );
    8578        this->base = this->ctx.FP;
    8679        this->storage = this->ctx.SP;
     
    9184
    9285        this->limit = (void *)(((intptr_t)this->base) - this->size);
    93         this->context = &mainThread_context_storage;
     86        this->context = &storage_mainThreadCtx;
    9487        this->top = this->base;
    9588}
     
    10699
    107100void ?{}( coroutine_desc * this, current_stack_info_t * info) {
    108         (&this->stack){ info }; 
     101        (&this->stack){ info };
    109102        this->name = "Main Thread";
    110103        this->errno_ = 0;
     
    131124
    132125void ?{}(processor * this) {
    133         this{ systemCluster };
     126        this{ mainCluster };
    134127}
    135128
    136129void ?{}(processor * this, cluster * cltr) {
    137130        this->cltr = cltr;
    138         this->current_coroutine = NULL;
    139         this->current_thread = NULL;
    140         (&this->terminated){};
    141         this->is_terminated = false;
     131        (&this->terminated){ 0 };
     132        this->do_terminate = false;
    142133        this->preemption_alarm = NULL;
    143         this->preemption = default_preemption();
    144         this->disable_preempt_count = 1;                //Start with interrupts disabled
    145134        this->pending_preemption = false;
    146135
     
    150139void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) {
    151140        this->cltr = cltr;
    152         this->current_coroutine = NULL;
    153         this->current_thread = NULL;
    154         (&this->terminated){};
    155         this->is_terminated = false;
    156         this->disable_preempt_count = 0;
     141        (&this->terminated){ 0 };
     142        this->do_terminate = false;
     143        this->preemption_alarm = NULL;
    157144        this->pending_preemption = false;
     145        this->kernel_thread = pthread_self();
    158146
    159147        this->runner = runner;
    160         LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);
     148        LIB_DEBUG_PRINT_SAFE("Kernel : constructing main processor context %p\n", runner);
    161149        runner{ this };
    162150}
    163151
    164 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) {
    165         (&this->alarms){};
    166         (&this->alarm_lock){};
    167         this->pending_alarm = false;
    168 
    169         (&this->proc){ cltr, runner };
    170 }
    171 
    172152void ^?{}(processor * this) {
    173         if( ! this->is_terminated ) {
     153        if( ! this->do_terminate ) {
    174154                LIB_DEBUG_PRINT_SAFE("Kernel : core %p signaling termination\n", this);
    175                 this->is_terminated = true;
    176                 wait( &this->terminated );
     155                this->do_terminate = true;
     156                P( &this->terminated );
     157                pthread_join( this->kernel_thread, NULL );
    177158        }
    178159}
     
    180161void ?{}(cluster * this) {
    181162        ( &this->ready_queue ){};
    182         ( &this->lock ){};
     163        ( &this->ready_queue_lock ){};
     164
     165        this->preemption = default_preemption();
    183166}
    184167
    185168void ^?{}(cluster * this) {
    186        
     169
    187170}
    188171
     
    203186
    204187                thread_desc * readyThread = NULL;
    205                 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ )
     188                for( unsigned int spin_count = 0; ! this->do_terminate; spin_count++ )
    206189                {
    207190                        readyThread = nextThread( this->cltr );
     
    209192                        if(readyThread)
    210193                        {
     194                                verify( disable_preempt_count > 0 );
     195
    211196                                runThread(this, readyThread);
     197
     198                                verify( disable_preempt_count > 0 );
    212199
    213200                                //Some actions need to be taken from the kernel
     
    225212        }
    226213
    227         signal( &this->terminated );
     214        V( &this->terminated );
     215
    228216        LIB_DEBUG_PRINT_SAFE("Kernel : core %p terminated\n", this);
    229217}
    230218
    231 // runThread runs a thread by context switching 
    232 // from the processor coroutine to the target thread 
     219// runThread runs a thread by context switching
     220// from the processor coroutine to the target thread
    233221void runThread(processor * this, thread_desc * dst) {
    234222        coroutine_desc * proc_cor = get_coroutine(this->runner);
    235223        coroutine_desc * thrd_cor = get_coroutine(dst);
    236        
     224
    237225        //Reset the terminating actions here
    238226        this->finish.action_code = No_Action;
    239227
    240228        //Update global state
    241         this->current_thread = dst;
     229        this_thread = dst;
    242230
    243231        // Context Switch to the thread
     
    246234}
    247235
    248 // Once a thread has finished running, some of 
     236// Once a thread has finished running, some of
    249237// its final actions must be executed from the kernel
    250238void finishRunning(processor * this) {
     
    256244        }
    257245        else if( this->finish.action_code == Release_Schedule ) {
    258                 unlock( this->finish.lock );           
     246                unlock( this->finish.lock );
    259247                ScheduleThread( this->finish.thrd );
    260248        }
     
    289277        processor * proc = (processor *) arg;
    290278        this_processor = proc;
     279        this_coroutine = NULL;
     280        this_thread = NULL;
     281        disable_preempt_count = 1;
    291282        // SKULLDUGGERY: We want to create a context for the processor coroutine
    292283        // which is needed for the 2-step context switch. However, there is no reason
    293         // to waste the perfectly valid stack create by pthread. 
     284        // to waste the perfectly valid stack create by pthread.
    294285        current_stack_info_t info;
    295286        machine_context_t ctx;
     
    300291
    301292        //Set global state
    302         proc->current_coroutine = &proc->runner->__cor;
    303         proc->current_thread = NULL;
     293        this_coroutine = &proc->runner->__cor;
     294        this_thread = NULL;
    304295
    305296        //We now have a proper context from which to schedule threads
    306297        LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
    307298
    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 
     299        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     300        // resume it to start it like it normally would, it will just context switch
     301        // back to here. Instead directly call the main since we already are on the
    311302        // appropriate stack.
    312303        proc_cor_storage.__cor.state = Active;
     
    315306
    316307        // Main routine of the core returned, the core is now fully terminated
    317         LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 
     308        LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner);
    318309
    319310        return NULL;
     
    322313void start(processor * this) {
    323314        LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this);
    324        
     315
    325316        pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
    326317
    327         LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this);       
     318        LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this);
    328319}
    329320
     
    331322// Scheduler routines
    332323void ScheduleThread( thread_desc * thrd ) {
    333         if( !thrd ) return;
     324        // if( !thrd ) return;
     325        assert( thrd );
     326        assert( thrd->cor.state != Halted );
     327
     328        verify( disable_preempt_count > 0 );
    334329
    335330        verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
    336        
    337         lock( &systemProcessor->proc.cltr->lock );
    338         append( &systemProcessor->proc.cltr->ready_queue, thrd );
    339         unlock( &systemProcessor->proc.cltr->lock );
     331
     332        lock(   &this_processor->cltr->ready_queue_lock DEBUG_CTX2 );
     333        append( &this_processor->cltr->ready_queue, thrd );
     334        unlock( &this_processor->cltr->ready_queue_lock );
     335
     336        verify( disable_preempt_count > 0 );
    340337}
    341338
    342339thread_desc * nextThread(cluster * this) {
    343         lock( &this->lock );
     340        verify( disable_preempt_count > 0 );
     341        lock( &this->ready_queue_lock DEBUG_CTX2 );
    344342        thread_desc * head = pop_head( &this->ready_queue );
    345         unlock( &this->lock );
     343        unlock( &this->ready_queue_lock );
     344        verify( disable_preempt_count > 0 );
    346345        return head;
    347346}
    348347
    349 void ScheduleInternal() {
    350         suspend();
    351 }
    352 
    353 void ScheduleInternal( spinlock * lock ) {
     348void BlockInternal() {
     349        disable_interrupts();
     350        verify( disable_preempt_count > 0 );
     351        suspend();
     352        verify( disable_preempt_count > 0 );
     353        enable_interrupts( DEBUG_CTX );
     354}
     355
     356void BlockInternal( spinlock * lock ) {
     357        disable_interrupts();
    354358        this_processor->finish.action_code = Release;
    355359        this_processor->finish.lock = lock;
    356         suspend();
    357 }
    358 
    359 void ScheduleInternal( thread_desc * thrd ) {
     360
     361        verify( disable_preempt_count > 0 );
     362        suspend();
     363        verify( disable_preempt_count > 0 );
     364
     365        enable_interrupts( DEBUG_CTX );
     366}
     367
     368void BlockInternal( thread_desc * thrd ) {
     369        disable_interrupts();
     370        assert( thrd->cor.state != Halted );
    360371        this_processor->finish.action_code = Schedule;
    361372        this_processor->finish.thrd = thrd;
    362         suspend();
    363 }
    364 
    365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) {
     373
     374        verify( disable_preempt_count > 0 );
     375        suspend();
     376        verify( disable_preempt_count > 0 );
     377
     378        enable_interrupts( DEBUG_CTX );
     379}
     380
     381void BlockInternal( spinlock * lock, thread_desc * thrd ) {
     382        disable_interrupts();
    366383        this_processor->finish.action_code = Release_Schedule;
    367384        this_processor->finish.lock = lock;
    368385        this_processor->finish.thrd = thrd;
    369         suspend();
    370 }
    371 
    372 void ScheduleInternal(spinlock ** locks, unsigned short count) {
     386
     387        verify( disable_preempt_count > 0 );
     388        suspend();
     389        verify( disable_preempt_count > 0 );
     390
     391        enable_interrupts( DEBUG_CTX );
     392}
     393
     394void BlockInternal(spinlock ** locks, unsigned short count) {
     395        disable_interrupts();
    373396        this_processor->finish.action_code = Release_Multi;
    374397        this_processor->finish.locks = locks;
    375398        this_processor->finish.lock_count = count;
    376         suspend();
    377 }
    378 
    379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) {
     399
     400        verify( disable_preempt_count > 0 );
     401        suspend();
     402        verify( disable_preempt_count > 0 );
     403
     404        enable_interrupts( DEBUG_CTX );
     405}
     406
     407void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) {
     408        disable_interrupts();
    380409        this_processor->finish.action_code = Release_Multi_Schedule;
    381410        this_processor->finish.locks = locks;
     
    383412        this_processor->finish.thrds = thrds;
    384413        this_processor->finish.thrd_count = thrd_count;
     414
     415        verify( disable_preempt_count > 0 );
     416        suspend();
     417        verify( disable_preempt_count > 0 );
     418
     419        enable_interrupts( DEBUG_CTX );
     420}
     421
     422void LeaveThread(spinlock * lock, thread_desc * thrd) {
     423        verify( disable_preempt_count > 0 );
     424        this_processor->finish.action_code = thrd ? Release_Schedule : Release;
     425        this_processor->finish.lock = lock;
     426        this_processor->finish.thrd = thrd;
     427
    385428        suspend();
    386429}
     
    392435// Kernel boot procedures
    393436void kernel_startup(void) {
    394         LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n");   
     437        LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n");
    395438
    396439        // Start by initializing the main thread
    397         // SKULLDUGGERY: the mainThread steals the process main thread 
    398         // which will then be scheduled by the systemProcessor normally
    399         mainThread = (thread_desc *)&mainThread_storage;
     440        // SKULLDUGGERY: the mainThread steals the process main thread
     441        // which will then be scheduled by the mainProcessor normally
     442        mainThread = (thread_desc *)&storage_mainThread;
    400443        current_stack_info_t info;
    401444        mainThread{ &info };
     
    403446        LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n");
    404447
     448        // Initialize the main cluster
     449        mainCluster = (cluster *)&storage_mainCluster;
     450        mainCluster{};
     451
     452        LIB_DEBUG_PRINT_SAFE("Kernel : main cluster ready\n");
     453
     454        // Initialize the main processor and the main processor ctx
     455        // (the coroutine that contains the processing control flow)
     456        mainProcessor = (processor *)&storage_mainProcessor;
     457        mainProcessor{ mainCluster, (processorCtx_t *)&storage_mainProcessorCtx };
     458
     459        //initialize the global state variables
     460        this_processor = mainProcessor;
     461        this_thread = mainThread;
     462        this_coroutine = &mainThread->cor;
     463
    405464        // Enable preemption
    406465        kernel_start_preemption();
    407466
    408         // Initialize the system cluster
    409         systemCluster = (cluster *)&systemCluster_storage;
    410         systemCluster{};
    411 
    412         LIB_DEBUG_PRINT_SAFE("Kernel : System cluster ready\n");
    413 
    414         // Initialize the system processor and the system processor ctx
    415         // (the coroutine that contains the processing control flow)
    416         systemProcessor = (system_proc_t *)&systemProcessor_storage;
    417         systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
    418 
    419         // Add the main thread to the ready queue
    420         // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread
     467        // Add the main thread to the ready queue
     468        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    421469        ScheduleThread(mainThread);
    422470
    423         //initialize the global state variables
    424         this_processor = &systemProcessor->proc;
    425         this_processor->current_thread = mainThread;
    426         this_processor->current_coroutine = &mainThread->cor;
    427 
    428         // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX
     471        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
    429472        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    430         // mainThread is on the ready queue when this call is made. 
    431         resume( systemProcessor->proc.runner );
     473        // mainThread is on the ready queue when this call is made.
     474        resume( mainProcessor->runner );
    432475
    433476
     
    435478        // THE SYSTEM IS NOW COMPLETELY RUNNING
    436479        LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n");
     480
     481        enable_interrupts( DEBUG_CTX );
    437482}
    438483
     
    440485        LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n");
    441486
    442         // SKULLDUGGERY: Notify the systemProcessor it needs to terminates.
     487        disable_interrupts();
     488
     489        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
    443490        // When its coroutine terminates, it return control to the mainThread
    444491        // which is currently here
    445         systemProcessor->proc.is_terminated = true;
     492        mainProcessor->do_terminate = true;
    446493        suspend();
    447494
    448495        // THE SYSTEM IS NOW COMPLETELY STOPPED
    449496
    450         // Destroy the system processor and its context in reverse order of construction
     497        // Disable preemption
     498        kernel_stop_preemption();
     499
     500        // Destroy the main processor and its context in reverse order of construction
    451501        // These were manually constructed so we need manually destroy them
    452         ^(systemProcessor->proc.runner){};
    453         ^(systemProcessor){};
     502        ^(mainProcessor->runner){};
     503        ^(mainProcessor){};
    454504
    455505        // Final step, destroy the main thread since it is no longer needed
     
    457507        ^(mainThread){};
    458508
    459         LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n");   
     509        LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n");
    460510}
    461511
     
    467517        // abort cannot be recursively entered by the same or different processors because all signal handlers return when
    468518        // the globalAbort flag is true.
    469         lock( &kernel_abort_lock );
     519        lock( &kernel_abort_lock DEBUG_CTX2 );
    470520
    471521        // first task to abort ?
     
    473523                kernel_abort_called = true;
    474524                unlock( &kernel_abort_lock );
    475         } 
     525        }
    476526        else {
    477527                unlock( &kernel_abort_lock );
    478                
     528
    479529                sigset_t mask;
    480530                sigemptyset( &mask );
     
    482532                sigaddset( &mask, SIGUSR1 );                    // block SIGUSR1 signals
    483533                sigsuspend( &mask );                            // block the processor to prevent further damage during abort
    484                 _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it             
    485         }
    486 
    487         return this_thread();
     534                _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it
     535        }
     536
     537        return this_thread;
    488538}
    489539
     
    494544        __lib_debug_write( STDERR_FILENO, abort_text, len );
    495545
    496         if ( thrd != this_coroutine() ) {
    497                 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine()->name, this_coroutine() );
     546        if ( thrd != this_coroutine ) {
     547                len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine );
    498548                __lib_debug_write( STDERR_FILENO, abort_text, len );
    499         } 
     549        }
    500550        else {
    501551                __lib_debug_write( STDERR_FILENO, ".\n", 2 );
     
    505555extern "C" {
    506556        void __lib_debug_acquire() {
    507                 lock(&kernel_debug_lock);
     557                lock( &kernel_debug_lock DEBUG_CTX2 );
    508558        }
    509559
    510560        void __lib_debug_release() {
    511                 unlock(&kernel_debug_lock);
     561                unlock( &kernel_debug_lock );
    512562        }
    513563}
     
    525575}
    526576
    527 bool try_lock( spinlock * this ) {
     577bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) {
    528578        return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0;
    529579}
    530580
    531 void lock( spinlock * this ) {
     581void lock( spinlock * this DEBUG_CTX_PARAM2 ) {
    532582        for ( unsigned int i = 1;; i += 1 ) {
    533                 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break;
    534         }
    535 }
     583                if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; }
     584        }
     585        LIB_DEBUG_DO(
     586                this->prev_name = caller;
     587                this->prev_thrd = this_thread;
     588        )
     589}
     590
     591void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) {
     592        for ( unsigned int i = 1;; i += 1 ) {
     593                if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; }
     594                yield();
     595        }
     596        LIB_DEBUG_DO(
     597                this->prev_name = caller;
     598                this->prev_thrd = this_thread;
     599        )
     600}
     601
    536602
    537603void unlock( spinlock * this ) {
     
    539605}
    540606
    541 void ?{}( signal_once * this ) {
    542         this->cond = false;
    543 }
    544 void ^?{}( signal_once * this ) {
    545 
    546 }
    547 
    548 void wait( signal_once * this ) {
    549         lock( &this->lock );
    550         if( !this->cond ) {
    551                 append( &this->blocked, this_thread() );
    552                 ScheduleInternal( &this->lock );
    553                 lock( &this->lock );
    554         }
     607void  ?{}( semaphore * this, int count = 1 ) {
     608        (&this->lock){};
     609        this->count = count;
     610        (&this->waiting){};
     611}
     612void ^?{}(semaphore * this) {}
     613
     614void P(semaphore * this) {
     615        lock( &this->lock DEBUG_CTX2 );
     616        this->count -= 1;
     617        if ( this->count < 0 ) {
     618                // queue current task
     619                append( &this->waiting, (thread_desc *)this_thread );
     620
     621                // atomically release spin lock and block
     622                BlockInternal( &this->lock );
     623        }
     624        else {
     625            unlock( &this->lock );
     626        }
     627}
     628
     629void V(semaphore * this) {
     630        thread_desc * thrd = NULL;
     631        lock( &this->lock DEBUG_CTX2 );
     632        this->count += 1;
     633        if ( this->count <= 0 ) {
     634                // remove task at head of waiting list
     635                thrd = pop_head( &this->waiting );
     636        }
     637
    555638        unlock( &this->lock );
    556 }
    557 
    558 void signal( signal_once * this ) {
    559         lock( &this->lock );
    560         {
    561                 this->cond = true;
    562 
    563                 thread_desc * it;
    564                 while( it = pop_head( &this->blocked) ) {
    565                         ScheduleThread( it );
    566                 }
    567         }
    568         unlock( &this->lock );
     639
     640        // make new owner
     641        WakeThread( thrd );
    569642}
    570643
     
    590663                }
    591664                head->next = NULL;
    592         }       
     665        }
    593666        return head;
    594667}
     
    609682                this->top = top->next;
    610683                top->next = NULL;
    611         }       
     684        }
    612685        return top;
    613686}
Note: See TracChangeset for help on using the changeset viewer.