Ignore:
Timestamp:
Feb 15, 2018, 10:52:35 AM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
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:
d27e340
Parents:
ff2d1139
Message:

Updated alarm to use bits/cfatime and fixed preemption for coroutines

Location:
src/libcfa/concurrency
Files:
8 edited

Legend:

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

    rff2d1139 rb69ea6b  
    1818#include <stdio.h>
    1919#include <string.h>
    20 #include <time.h>
    2120#include <unistd.h>
    2221#include <sys/time.h>
     
    2726#include "preemption.h"
    2827
    29 //=============================================================================================
    30 // time type
    31 //=============================================================================================
    3228
    33 #define one_second         1_000_000_000ul
    34 #define one_milisecond         1_000_000ul
    35 #define one_microsecond            1_000ul
    36 #define one_nanosecond                 1ul
    37 
    38 __cfa_time_t zero_time = { 0 };
    39 
    40 void ?{}( __cfa_time_t & this ) { this.val = 0; }
    41 void ?{}( __cfa_time_t & this, zero_t zero ) { this.val = 0; }
    42 
    43 void ?{}( itimerval & this, __cfa_time_t * alarm ) with( this ) {
    44         it_value.tv_sec = alarm->val / one_second;                      // seconds
    45         it_value.tv_usec = max( (alarm->val % one_second) / one_microsecond, 1000 ); // microseconds
     29static inline void ?{}( itimerval & this, __cfa_time_t * alarm ) with( this ) {
     30        it_value.tv_sec = alarm->val / (1`cfa_s).val;                   // seconds
     31        it_value.tv_usec = max( (alarm->val % (1`cfa_s).val) / (1`cfa_us).val, 1000 ); // microseconds
    4632        it_interval.tv_sec = 0;
    4733        it_interval.tv_usec = 0;
    4834}
    4935
    50 
    51 void ?{}( __cfa_time_t & this, timespec * curr ) {
     36static inline void ?{}( __cfa_time_t & this, timespec * curr ) {
    5237        uint64_t secs  = curr->tv_sec;
    5338        uint64_t nsecs = curr->tv_nsec;
    54         this.val = (secs * one_second) + nsecs;
     39        this.val = from_s(secs).val + nsecs;
    5540}
    56 
    57 __cfa_time_t ?=?( __cfa_time_t & this, zero_t rhs ) {
    58         this.val = 0;
    59         return this;
    60 }
    61 
    62 __cfa_time_t from_s ( uint64_t val ) { __cfa_time_t ret; ret.val = val * 1_000_000_000ul; return ret; }
    63 __cfa_time_t from_ms( uint64_t val ) { __cfa_time_t ret; ret.val = val *     1_000_000ul; return ret; }
    64 __cfa_time_t from_us( uint64_t val ) { __cfa_time_t ret; ret.val = val *         1_000ul; return ret; }
    65 __cfa_time_t from_ns( uint64_t val ) { __cfa_time_t ret; ret.val = val *             1ul; return ret; }
    6641
    6742//=============================================================================================
     
    8459//=============================================================================================
    8560
    86 void ?{}( alarm_node_t & this, thread_desc * thrd, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time ) with( this ) {
     61void ?{}( alarm_node_t & this, thread_desc * thrd, __cfa_time_t alarm = 0`cfa_s, __cfa_time_t period = 0`cfa_s ) with( this ) {
    8762        this.thrd = thrd;
    8863        this.alarm = alarm;
     
    9368}
    9469
    95 void ?{}( alarm_node_t & this, processor   * proc, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time ) with( this ) {
     70void ?{}( alarm_node_t & this, processor   * proc, __cfa_time_t alarm = 0`cfa_s, __cfa_time_t period = 0`cfa_s ) with( this ) {
    9671        this.proc = proc;
    9772        this.alarm = alarm;
  • src/libcfa/concurrency/alarm.h

    rff2d1139 rb69ea6b  
    2121#include <assert.h>
    2222
     23#include "bits/cfatime.h"
     24
    2325struct thread_desc;
    2426struct processor;
    25 
    26 struct timespec;
    27 struct itimerval;
    28 
    29 //=============================================================================================
    30 // time type
    31 //=============================================================================================
    32 
    33 struct __cfa_time_t {
    34         uint64_t val;
    35 };
    36 
    37 // ctors
    38 void ?{}( __cfa_time_t & this );
    39 void ?{}( __cfa_time_t & this, zero_t zero );
    40 void ?{}( __cfa_time_t & this, timespec * curr );
    41 void ?{}( itimerval & this, __cfa_time_t * alarm );
    42 
    43 __cfa_time_t ?=?( __cfa_time_t & this, zero_t rhs );
    44 
    45 // logical ops
    46 static inline bool ?==?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val == rhs.val; }
    47 static inline bool ?!=?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val != rhs.val; }
    48 static inline bool ?>? ( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val >  rhs.val; }
    49 static inline bool ?<? ( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val <  rhs.val; }
    50 static inline bool ?>=?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val >= rhs.val; }
    51 static inline bool ?<=?( __cfa_time_t lhs, __cfa_time_t rhs ) { return lhs.val <= rhs.val; }
    52 
    53 static inline bool ?==?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val == rhs; }
    54 static inline bool ?!=?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val != rhs; }
    55 static inline bool ?>? ( __cfa_time_t lhs, zero_t rhs ) { return lhs.val >  rhs; }
    56 static inline bool ?<? ( __cfa_time_t lhs, zero_t rhs ) { return lhs.val <  rhs; }
    57 static inline bool ?>=?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val >= rhs; }
    58 static inline bool ?<=?( __cfa_time_t lhs, zero_t rhs ) { return lhs.val <= rhs; }
    59 
    60 // addition/substract
    61 static inline __cfa_time_t ?+?( __cfa_time_t lhs, __cfa_time_t rhs ) {
    62         __cfa_time_t ret;
    63         ret.val = lhs.val + rhs.val;
    64         return ret;
    65 }
    66 
    67 static inline __cfa_time_t ?-?( __cfa_time_t lhs, __cfa_time_t rhs ) {
    68         __cfa_time_t ret;
    69         ret.val = lhs.val - rhs.val;
    70         return ret;
    71 }
    72 
    73 __cfa_time_t from_s ( uint64_t );
    74 __cfa_time_t from_ms( uint64_t );
    75 __cfa_time_t from_us( uint64_t );
    76 __cfa_time_t from_ns( uint64_t );
    77 
    78 extern __cfa_time_t zero_time;
    7927
    8028//=============================================================================================
     
    10553typedef alarm_node_t ** __alarm_it_t;
    10654
    107 void ?{}( alarm_node_t & this, thread_desc * thrd, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time );
    108 void ?{}( alarm_node_t & this, processor   * proc, __cfa_time_t alarm = zero_time, __cfa_time_t period = zero_time );
     55void ?{}( alarm_node_t & this, thread_desc * thrd, __cfa_time_t alarm = 0`cfa_s, __cfa_time_t period = 0`cfa_s );
     56void ?{}( alarm_node_t & this, processor   * proc, __cfa_time_t alarm = 0`cfa_s, __cfa_time_t period = 0`cfa_s );
    10957void ^?{}( alarm_node_t & this );
    11058
  • src/libcfa/concurrency/coroutine.c

    rff2d1139 rb69ea6b  
    9999// Wrapper for co
    100100void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
     101        verify( preemption.enabled || this_processor->do_terminate );
    101102        disable_interrupts();
    102103
     
    116117
    117118        enable_interrupts( __cfaabi_dbg_ctx );
     119        verify( preemption.enabled || this_processor->do_terminate );
    118120} //ctxSwitchDirect
    119121
  • src/libcfa/concurrency/invoke.c

    rff2d1139 rb69ea6b  
    2828extern void __suspend_internal(void);
    2929extern void __leave_coroutine(void);
     30extern void __finish_creation(void);
    3031extern void __leave_thread_monitor( struct thread_desc * this );
    3132extern void disable_interrupts();
     
    4445
    4546        cor->state = Active;
     47
     48        enable_interrupts( __cfaabi_dbg_ctx );
    4649
    4750        main( this );
     
    6265        // First suspend, once the thread arrives here,
    6366        // the function pointer to main can be invalidated without risk
    64         __suspend_internal();
     67        __finish_creation();
    6568
    6669        // Fetch the thread handle from the user defined thread structure
  • src/libcfa/concurrency/kernel.c

    rff2d1139 rb69ea6b  
    5656thread_local processor *      volatile this_processor;
    5757
    58 volatile thread_local bool preemption_in_progress = 0;
    59 volatile thread_local bool preemption_enabled = false;
    60 volatile thread_local unsigned short disable_preempt_count = 1;
     58// volatile thread_local bool preemption_in_progress = 0;
     59// volatile thread_local bool preemption_enabled = false;
     60// volatile thread_local unsigned short disable_preempt_count = 1;
     61
     62volatile thread_local __cfa_kernel_preemption_data_t preemption = { false, false, 1 };
    6163
    6264//-----------------------------------------------------------------------------
     
    207209                        if(readyThread)
    208210                        {
    209                                 verify( !preemption_enabled );
     211                                verify( !preemption.enabled );
    210212
    211213                                runThread(this, readyThread);
    212214
    213                                 verify( !preemption_enabled );
     215                                verify( !preemption.enabled );
    214216
    215217                                //Some actions need to be taken from the kernel
     
    260262void finishRunning(processor * this) with( this->finish ) {
    261263        if( action_code == Release ) {
    262                 verify( !preemption_enabled );
     264                verify( !preemption.enabled );
    263265                unlock( *lock );
    264266        }
     
    267269        }
    268270        else if( action_code == Release_Schedule ) {
    269                 verify( !preemption_enabled );
     271                verify( !preemption.enabled );
    270272                unlock( *lock );
    271273                ScheduleThread( thrd );
    272274        }
    273275        else if( action_code == Release_Multi ) {
    274                 verify( !preemption_enabled );
     276                verify( !preemption.enabled );
    275277                for(int i = 0; i < lock_count; i++) {
    276278                        unlock( *locks[i] );
     
    304306        this_coroutine = NULL;
    305307        this_thread = NULL;
    306         preemption_enabled = false;
    307         disable_preempt_count = 1;
     308        preemption.enabled = false;
     309        preemption.disable_count = 1;
    308310        // SKULLDUGGERY: We want to create a context for the processor coroutine
    309311        // which is needed for the 2-step context switch. However, there is no reason
     
    345347}
    346348
     349void kernel_first_resume(processor * this) {
     350        coroutine_desc * src = this_coroutine;
     351        coroutine_desc * dst = get_coroutine(*this->runner);
     352
     353        verify( !preemption.enabled );
     354
     355        create_stack(&dst->stack, dst->stack.size);
     356        CtxStart(this->runner, CtxInvokeCoroutine);
     357
     358        verify( !preemption.enabled );
     359
     360        dst->last = src;
     361        dst->starter = dst->starter ? dst->starter : src;
     362
     363        // set state of current coroutine to inactive
     364        src->state = src->state == Halted ? Halted : Inactive;
     365
     366        // set new coroutine that task is executing
     367        this_coroutine = dst;
     368
     369        // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.
     370        // Therefore, when first creating a coroutine, interrupts are enable before calling the main.
     371        // This is consistent with thread creation. However, when creating the main processor coroutine,
     372        // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will
     373        // stay disabled.
     374        disable_interrupts();
     375
     376        // context switch to specified coroutine
     377        assert( src->stack.context );
     378        CtxSwitch( src->stack.context, dst->stack.context );
     379        // when CtxSwitch returns we are back in the src coroutine
     380
     381        // set state of new coroutine to active
     382        src->state = Active;
     383
     384        verify( !preemption.enabled );
     385}
     386
    347387//-----------------------------------------------------------------------------
    348388// Scheduler routines
     
    352392        verify( thrd->self_cor.state != Halted );
    353393
    354         verify( !preemption_enabled );
     394        verify( !preemption.enabled );
    355395
    356396        verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
     
    362402        }
    363403
    364         verify( !preemption_enabled );
     404        verify( !preemption.enabled );
    365405}
    366406
    367407thread_desc * nextThread(cluster * this) with( *this ) {
    368         verify( !preemption_enabled );
     408        verify( !preemption.enabled );
    369409        lock( ready_queue_lock __cfaabi_dbg_ctx2 );
    370410        thread_desc * head = pop_head( ready_queue );
    371411        unlock( ready_queue_lock );
    372         verify( !preemption_enabled );
     412        verify( !preemption.enabled );
    373413        return head;
    374414}
     
    376416void BlockInternal() {
    377417        disable_interrupts();
    378         verify( !preemption_enabled );
     418        verify( !preemption.enabled );
    379419        returnToKernel();
    380         verify( !preemption_enabled );
     420        verify( !preemption.enabled );
    381421        enable_interrupts( __cfaabi_dbg_ctx );
    382422}
     
    387427        this_processor->finish.lock        = lock;
    388428
    389         verify( !preemption_enabled );
     429        verify( !preemption.enabled );
    390430        returnToKernel();
    391         verify( !preemption_enabled );
     431        verify( !preemption.enabled );
    392432
    393433        enable_interrupts( __cfaabi_dbg_ctx );
     
    399439        this_processor->finish.thrd        = thrd;
    400440
    401         verify( !preemption_enabled );
     441        verify( !preemption.enabled );
    402442        returnToKernel();
    403         verify( !preemption_enabled );
     443        verify( !preemption.enabled );
    404444
    405445        enable_interrupts( __cfaabi_dbg_ctx );
     
    413453        this_processor->finish.thrd        = thrd;
    414454
    415         verify( !preemption_enabled );
     455        verify( !preemption.enabled );
    416456        returnToKernel();
    417         verify( !preemption_enabled );
     457        verify( !preemption.enabled );
    418458
    419459        enable_interrupts( __cfaabi_dbg_ctx );
     
    426466        this_processor->finish.lock_count  = count;
    427467
    428         verify( !preemption_enabled );
     468        verify( !preemption.enabled );
    429469        returnToKernel();
    430         verify( !preemption_enabled );
     470        verify( !preemption.enabled );
    431471
    432472        enable_interrupts( __cfaabi_dbg_ctx );
     
    441481        this_processor->finish.thrd_count  = thrd_count;
    442482
    443         verify( !preemption_enabled );
     483        verify( !preemption.enabled );
    444484        returnToKernel();
    445         verify( !preemption_enabled );
     485        verify( !preemption.enabled );
    446486
    447487        enable_interrupts( __cfaabi_dbg_ctx );
     
    449489
    450490void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
    451         verify( !preemption_enabled );
     491        verify( !preemption.enabled );
    452492        this_processor->finish.action_code = thrd ? Release_Schedule : Release;
    453493        this_processor->finish.lock        = lock;
     
    463503// Kernel boot procedures
    464504void kernel_startup(void) {
     505        verify( !preemption.enabled );
    465506        __cfaabi_dbg_print_safe("Kernel : Starting\n");
    466507
     
    500541        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    501542        // mainThread is on the ready queue when this call is made.
    502         resume( *mainProcessor->runner );
     543        kernel_first_resume( this_processor );
    503544
    504545
     
    507548        __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
    508549
     550        verify( !preemption.enabled );
    509551        enable_interrupts( __cfaabi_dbg_ctx );
     552        verify( preemption.enabled );
    510553}
    511554
     
    513556        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
    514557
     558        verify( preemption.enabled );
    515559        disable_interrupts();
     560        verify( !preemption.enabled );
    516561
    517562        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
  • src/libcfa/concurrency/kernel_private.h

    rff2d1139 rb69ea6b  
    7474extern thread_local processor *      volatile this_processor;
    7575
    76 extern volatile thread_local bool preemption_in_progress;
    77 extern volatile thread_local bool preemption_enabled;
    78 extern volatile thread_local unsigned short disable_preempt_count;
     76// extern volatile thread_local bool preemption_in_progress;
     77// extern volatile thread_local bool preemption_enabled;
     78// extern volatile thread_local unsigned short disable_preempt_count;
     79
     80struct __cfa_kernel_preemption_data_t {
     81        bool enabled;
     82        bool in_progress;
     83        unsigned short disable_count;
     84};
     85
     86extern volatile thread_local __cfa_kernel_preemption_data_t preemption;
    7987
    8088//-----------------------------------------------------------------------------
  • src/libcfa/concurrency/preemption.c

    rff2d1139 rb69ea6b  
    149149        // Disable interrupts by incrementing the counter
    150150        void disable_interrupts() {
    151                 preemption_enabled = false;
    152                 __attribute__((unused)) unsigned short new_val = disable_preempt_count + 1;
    153                 disable_preempt_count = new_val;
     151                preemption.enabled = false;
     152                __attribute__((unused)) unsigned short new_val = preemption.disable_count + 1;
     153                preemption.disable_count = new_val;
    154154                verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
    155155        }
     
    161161                thread_desc * thrd = this_thread;         // Cache the thread now since interrupts can start happening after the atomic add
    162162
    163                 unsigned short prev = disable_preempt_count;
    164                 disable_preempt_count -= 1;
     163                unsigned short prev = preemption.disable_count;
     164                preemption.disable_count -= 1;
    165165                verify( prev != 0u );                     // If this triggers someone is enabled already enabled interruptsverify( prev != 0u );
    166166
    167167                // Check if we need to prempt the thread because an interrupt was missed
    168168                if( prev == 1 ) {
    169                         preemption_enabled = true;
     169                        preemption.enabled = true;
    170170                        if( proc->pending_preemption ) {
    171171                                proc->pending_preemption = false;
     
    181181        // Don't execute any pending CtxSwitch even if counter reaches 0
    182182        void enable_interrupts_noPoll() {
    183                 unsigned short prev = disable_preempt_count;
    184                 disable_preempt_count -= 1;
     183                unsigned short prev = preemption.disable_count;
     184                preemption.disable_count -= 1;
    185185                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    186186                if( prev == 1 ) {
    187                         preemption_enabled = true;
     187                        preemption.enabled = true;
    188188                }
    189189        }
     
    235235// If false : preemption is unsafe and marked as pending
    236236static inline bool preemption_ready() {
    237         bool ready = preemption_enabled && !preemption_in_progress; // Check if preemption is safe
     237        bool ready = preemption.enabled && !preemption.in_progress; // Check if preemption is safe
    238238        this_processor->pending_preemption = !ready;                        // Adjust the pending flag accordingly
    239239        return ready;
     
    250250
    251251        // Start with preemption disabled until ready
    252         preemption_enabled = false;
    253         disable_preempt_count = 1;
     252        preemption.enabled = false;
     253        preemption.disable_count = 1;
    254254
    255255        // Initialize the event kernel
     
    290290// Used by thread to control when they want to receive preemption signals
    291291void ?{}( preemption_scope & this, processor * proc ) {
    292         (this.alarm){ proc, zero_time, zero_time };
     292        (this.alarm){ proc, 0`cfa_s, 0`cfa_s };
    293293        this.proc = proc;
    294294        this.proc->preemption_alarm = &this.alarm;
     
    300300        disable_interrupts();
    301301
    302         update_preemption( this.proc, zero_time );
     302        update_preemption( this.proc, 0`cfa_s );
    303303}
    304304
     
    330330        __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p).\n", this_processor, this_thread);
    331331
    332         preemption_in_progress = true;                      // Sync flag : prevent recursive calls to the signal handler
     332        preemption.in_progress = true;                      // Sync flag : prevent recursive calls to the signal handler
    333333        signal_unblock( SIGUSR1 );                          // We are about to CtxSwitch out of the signal handler, let other handlers in
    334         preemption_in_progress = false;                     // Clear the in progress flag
     334        preemption.in_progress = false;                     // Clear the in progress flag
    335335
    336336        // Preemption can occur here
  • src/libcfa/concurrency/thread.c

    rff2d1139 rb69ea6b  
    9090}
    9191
     92extern "C" {
     93        void __finish_creation(void) {
     94                coroutine_desc* thrd_c = this_coroutine;
     95                ThreadCtxSwitch( thrd_c, thrd_c->last );
     96        }
     97}
     98
    9299void yield( void ) {
     100        verify( preemption.enabled );
    93101        BlockInternal( this_thread );
     102        verify( preemption.enabled );
    94103}
    95104
Note: See TracChangeset for help on using the changeset viewer.