Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/preemption.cfa

    rbfcf6b9 r09d4b22  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Nov  6 07:42:13 2020
    13 // Update Count     : 54
     12// Last Modified On : Thu Dec  5 16:34:05 2019
     13// Update Count     : 43
    1414//
    1515
     
    1919#include <assert.h>
    2020
     21extern "C" {
    2122#include <errno.h>
    2223#include <stdio.h>
     
    2425#include <unistd.h>
    2526#include <limits.h>                                                                             // PTHREAD_STACK_MIN
     27}
    2628
    2729#include "bits/signal.hfa"
    28 #include "kernel_private.hfa"
    2930
    3031#if !defined(__CFA_DEFAULT_PREEMPTION__)
     
    3839// FwdDeclarations : timeout handlers
    3940static void preempt( processor   * this );
    40 static void timeout( $thread * this );
     41static void timeout( thread_desc * this );
    4142
    4243// FwdDeclarations : Signal handlers
    4344static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
    44 static void sigHandler_alarm    ( __CFA_SIGPARMS__ );
    4545static void sigHandler_segv     ( __CFA_SIGPARMS__ );
    4646static void sigHandler_ill      ( __CFA_SIGPARMS__ );
     
    5656#elif defined( __x86_64 )
    5757#define CFA_REG_IP gregs[REG_RIP]
    58 #elif defined( __arm__ )
     58#elif defined( __ARM_ARCH )
    5959#define CFA_REG_IP arm_pc
    60 #elif defined( __aarch64__ )
    61 #define CFA_REG_IP pc
    6260#else
    63 #error unsupported hardware architecture
     61#error unknown hardware architecture
    6462#endif
    6563
     
    8583// Get next expired node
    8684static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) {
    87         if( ! & (*alarms)`first ) return 0p;                                            // If no alarms return null
    88         if( (*alarms)`first.alarm >= currtime ) return 0p;      // If alarms head not expired return null
     85        if( !alarms->head ) return 0p;                                          // If no alarms return null
     86        if( alarms->head->alarm >= currtime ) return 0p;        // If alarms head not expired return null
    8987        return pop(alarms);                                                                     // Otherwise just pop head
    9088}
    9189
    9290// Tick one frame of the Discrete Event Simulation for alarms
    93 static void tick_preemption(void) {
     91static void tick_preemption() {
    9492        alarm_node_t * node = 0p;                                                       // Used in the while loop but cannot be declared in the while condition
    9593        alarm_list_t * alarms = &event_kernel->alarms;          // Local copy for ease of reading
     
    9997        while( node = get_expired( alarms, currtime ) ) {
    10098                // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" );
     99
     100                // Check if this is a kernel
     101                if( node->kernel_alarm ) {
     102                        preempt( node->proc );
     103                }
     104                else {
     105                        timeout( node->thrd );
     106                }
     107
     108                // Check if this is a periodic alarm
    101109                Duration period = node->period;
    102                 if( period == 0) {
    103                         node->set = false;                  // Node is one-shot, just mark it as not pending
    104                 }
    105 
    106                 // Check if this is a kernel
    107                 if( node->type == Kernel ) {
    108                         preempt( node->proc );
    109                 }
    110                 else if( node->type == User ) {
    111                         timeout( node->thrd );
    112                 }
    113                 else {
    114                         node->callback(*node);
    115                 }
    116 
    117                 // Check if this is a periodic alarm
    118110                if( period > 0 ) {
    119111                        // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv );
     
    121113                        insert( alarms, node );             // Reinsert the node for the next time it triggers
    122114                }
     115                else {
     116                        node->set = false;                  // Node is one-shot, just mark it as not pending
     117                }
    123118        }
    124119
    125120        // If there are still alarms pending, reset the timer
    126         if( & (*alarms)`first ) {
    127                 __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
    128                 Duration delta = (*alarms)`first.alarm - currtime;
    129                 Duration capped = max(delta, 50`us);
     121        if( alarms->head ) {
     122                __cfaabi_dbg_print_buffer_decl( " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
     123                Duration delta = alarms->head->alarm - currtime;
     124                Duration caped = max(delta, 50`us);
    130125                // itimerval tim  = { caped };
    131126                // __cfaabi_dbg_print_buffer_local( "    Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec);
    132127
    133                 __kernel_set_timer( capped );
     128                __kernel_set_timer( caped );
    134129        }
    135130}
     
    163158// Kernel Signal Tools
    164159//=============================================================================================
    165 // In a user-level threading system, there are handful of thread-local variables where this problem occurs on the ARM.
    166 //
    167 // For each kernel thread running user-level threads, there is a flag variable to indicate if interrupts are
    168 // enabled/disabled for that kernel thread. Therefore, this variable is made thread local.
    169 //
    170 // For example, this code fragment sets the state of the "interrupt" variable in thread-local memory.
    171 //
    172 // _Thread_local volatile int interrupts;
    173 // int main() {
    174 //     interrupts = 0; // disable interrupts }
    175 //
    176 // which generates the following code on the ARM
    177 //
    178 // (gdb) disassemble main
    179 // Dump of assembler code for function main:
    180 //    0x0000000000000610 <+0>:  mrs     x1, tpidr_el0
    181 //    0x0000000000000614 <+4>:  mov     w0, #0x0                        // #0
    182 //    0x0000000000000618 <+8>:  add     x1, x1, #0x0, lsl #12
    183 //    0x000000000000061c <+12>: add     x1, x1, #0x10
    184 //    0x0000000000000620 <+16>: str     wzr, [x1]
    185 //    0x0000000000000624 <+20>: ret
    186 //
    187 // The mrs moves a pointer from coprocessor register tpidr_el0 into register x1.  Register w0 is set to 0. The two adds
    188 // increase the TLS pointer with the displacement (offset) 0x10, which is the location in the TSL of variable
    189 // "interrupts".  Finally, 0 is stored into "interrupts" through the pointer in register x1 that points into the
    190 // TSL. Now once x1 has the pointer to the location of the TSL for kernel thread N, it can be be preempted at a
    191 // user-level and the user thread is put on the user-level ready-queue. When the preempted thread gets to the front of
    192 // the user-level ready-queue it is run on kernel thread M. It now stores 0 into "interrupts" back on kernel thread N,
    193 // turning off interrupt on the wrong kernel thread.
    194 //
    195 // On the x86, the following code is generated for the same code fragment.
    196 //
    197 // (gdb) disassemble main
    198 // Dump of assembler code for function main:
    199 //    0x0000000000400420 <+0>:  movl   $0x0,%fs:0xfffffffffffffffc
    200 //    0x000000000040042c <+12>: xor    %eax,%eax
    201 //    0x000000000040042e <+14>: retq
    202 //
    203 // and there is base-displacement addressing used to atomically reset variable "interrupts" off of the TSL pointer in
    204 // register "fs".
    205 //
    206 // Hence, the ARM has base-displacement address for the general purpose registers, BUT not to the coprocessor
    207 // registers. As a result, generating the address for the write into variable "interrupts" is no longer atomic.
    208 //
    209 // Note this problem does NOT occur when just using multiple kernel threads because the preemption ALWAYS restarts the
    210 // thread on the same kernel thread.
    211 //
    212 // The obvious question is why does ARM use a coprocessor register to store the TSL pointer given that coprocessor
    213 // registers are second-class registers with respect to the instruction set. One possible answer is that they did not
    214 // want to dedicate one of the general registers to hold the TLS pointer and there was a free coprocessor register
    215 // available.
    216 
    217 //-----------------------------------------------------------------------------
    218 // Some assembly required
    219 #define __cfaasm_label(label, when) when: asm volatile goto(".global __cfaasm_" #label "_" #when "\n" "__cfaasm_" #label "_" #when ":":::"memory":when)
    220 
    221 //----------
    222 // special case for preemption since used often
    223 bool __preemption_enabled() {
    224         // create a assembler label before
    225         // marked as clobber all to avoid movement
    226         __cfaasm_label(check, before);
    227 
    228         // access tls as normal
    229         bool enabled = __cfaabi_tls.preemption_state.enabled;
    230 
    231         // create a assembler label after
    232         // marked as clobber all to avoid movement
    233         __cfaasm_label(check, after);
    234         return enabled;
    235 }
    236 
    237 struct asm_region {
    238         void * before;
    239         void * after;
    240 };
    241 
    242 static inline bool __cfaasm_in( void * ip, struct asm_region & region ) {
    243         return ip >= region.before && ip <= region.after;
    244 }
    245 
    246 
    247 //----------
    248 // Get data from the TLS block
    249 // struct asm_region __cfaasm_get;
    250 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
    251 uintptr_t __cfatls_get( unsigned long int offset ) {
    252         // create a assembler label before
    253         // marked as clobber all to avoid movement
    254         __cfaasm_label(get, before);
    255 
    256         // access tls as normal (except for pointer arithmetic)
    257         uintptr_t val = *(uintptr_t*)((uintptr_t)&__cfaabi_tls + offset);
    258 
    259         // create a assembler label after
    260         // marked as clobber all to avoid movement
    261         __cfaasm_label(get, after);
    262         return val;
    263 }
     160
     161__cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
    264162
    265163extern "C" {
    266164        // Disable interrupts by incrementing the counter
    267165        void disable_interrupts() {
    268                 // create a assembler label before
    269                 // marked as clobber all to avoid movement
    270                 __cfaasm_label(dsable, before);
    271 
    272                 with( __cfaabi_tls.preemption_state ) {
     166                with( kernelTLS.preemption_state ) {
    273167                        #if GCC_VERSION > 50000
    274168                        static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     
    287181                        verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
    288182                }
    289 
    290                 // create a assembler label after
    291                 // marked as clobber all to avoid movement
    292                 __cfaasm_label(dsable, after);
    293 
    294183        }
    295184
    296185        // Enable interrupts by decrementing the counter
    297         // If counter reaches 0, execute any pending __cfactx_switch
     186        // If counter reaches 0, execute any pending CtxSwitch
    298187        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    299                 // Cache the processor now since interrupts can start happening after the atomic store
    300                 processor   * proc = __cfaabi_tls.this_processor;
    301                 /* paranoid */ verify( proc );
    302 
    303                 with( __cfaabi_tls.preemption_state ){
     188                processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store
     189                thread_desc * thrd = kernelTLS.this_thread;       // Cache the thread now since interrupts can start happening after the atomic store
     190
     191                with( kernelTLS.preemption_state ){
    304192                        unsigned short prev = disable_count;
    305193                        disable_count -= 1;
    306 
    307                         // If this triggers someone is enabled already enabled interruptsverify( prev != 0u );
    308                         /* paranoid */ verify( prev != 0u );
     194                        verify( prev != 0u );                     // If this triggers someone is enabled already enabled interruptsverify( prev != 0u );
    309195
    310196                        // Check if we need to prempt the thread because an interrupt was missed
    311197                        if( prev == 1 ) {
    312198                                #if GCC_VERSION > 50000
    313                                         static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     199                                static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
    314200                                #endif
    315201
     
    323209                                if( proc->pending_preemption ) {
    324210                                        proc->pending_preemption = false;
    325                                         force_yield( __POLL_PREEMPTION );
     211                                        BlockInternal( thrd );
    326212                                }
    327213                        }
     
    333219
    334220        // Disable interrupts by incrementint the counter
    335         // Don't execute any pending __cfactx_switch even if counter reaches 0
     221        // Don't execute any pending CtxSwitch even if counter reaches 0
    336222        void enable_interrupts_noPoll() {
    337                 unsigned short prev = __cfaabi_tls.preemption_state.disable_count;
    338                 __cfaabi_tls.preemption_state.disable_count -= 1;
    339                 // If this triggers someone is enabled already enabled interrupts
    340                 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev );
     223                unsigned short prev = kernelTLS.preemption_state.disable_count;
     224                kernelTLS.preemption_state.disable_count -= 1;
     225                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    341226                if( prev == 1 ) {
    342227                        #if GCC_VERSION > 50000
    343                                 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");
     228                        static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free");
    344229                        #endif
    345230                        // Set enabled flag to true
    346231                        // should be atomic to avoid preemption in the middle of the operation.
    347232                        // use memory order RELAXED since there is no inter-thread on this variable requirements
    348                         __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);
     233                        __atomic_store_n(&kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED);
    349234
    350235                        // Signal the compiler that a fence is needed but only for signal handlers
     
    353238        }
    354239}
    355 
    356 #undef __cfaasm_label
    357240
    358241// sigprocmask wrapper : unblock a single signal
     
    374257
    375258        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    376                 abort( "internal error, pthread_sigmask" );
     259            abort( "internal error, pthread_sigmask" );
    377260        }
    378261}
     
    385268
    386269// reserved for future use
    387 static void timeout( $thread * this ) {
    388         unpark( this );
    389 }
    390 
    391 //-----------------------------------------------------------------------------
    392 // Some assembly required
    393 #if defined( __i386 )
    394         #ifdef __PIC__
    395                 #define RELOC_PRELUDE( label ) \
    396                         "calll   .Lcfaasm_prelude_" #label "$pb\n\t" \
    397                         ".Lcfaasm_prelude_" #label "$pb:\n\t" \
    398                         "popl    %%eax\n\t" \
    399                         ".Lcfaasm_prelude_" #label "_end:\n\t" \
    400                         "addl    $_GLOBAL_OFFSET_TABLE_+(.Lcfaasm_prelude_" #label "_end-.Lcfaasm_prelude_" #label "$pb), %%eax\n\t"
    401                 #define RELOC_PREFIX ""
    402                 #define RELOC_SUFFIX "@GOT(%%eax)"
    403         #else
    404                 #define RELOC_PREFIX "$"
    405                 #define RELOC_SUFFIX ""
    406         #endif
    407         #define __cfaasm_label( label ) struct asm_region label = \
    408                 ({ \
    409                         struct asm_region region; \
    410                         asm( \
    411                                 RELOC_PRELUDE( label ) \
    412                                 "movl " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \
    413                                 "movl " RELOC_PREFIX "__cfaasm_" #label "_after"  RELOC_SUFFIX ", %[va]\n\t" \
    414                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    415                         ); \
    416                         region; \
    417                 });
    418 #elif defined( __x86_64 )
    419         #ifdef __PIC__
    420                 #define RELOC_PREFIX ""
    421                 #define RELOC_SUFFIX "@GOTPCREL(%%rip)"
    422         #else
    423                 #define RELOC_PREFIX "$"
    424                 #define RELOC_SUFFIX ""
    425         #endif
    426         #define __cfaasm_label( label ) struct asm_region label = \
    427                 ({ \
    428                         struct asm_region region; \
    429                         asm( \
    430                                 "movq " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \
    431                                 "movq " RELOC_PREFIX "__cfaasm_" #label "_after"  RELOC_SUFFIX ", %[va]\n\t" \
    432                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    433                         ); \
    434                         region; \
    435                 });
    436 #elif defined( __aarch64__ )
    437         #ifdef __PIC__
    438                 // Note that this works only for gcc
    439                 #define __cfaasm_label( label ) struct asm_region label = \
    440                 ({ \
    441                         struct asm_region region; \
    442                         asm( \
    443                                 "adrp %[vb], _GLOBAL_OFFSET_TABLE_"                              "\n\t" \
    444                                 "ldr  %[vb], [%[vb], #:gotpage_lo15:__cfaasm_" #label "_before]" "\n\t" \
    445                                 "adrp %[va], _GLOBAL_OFFSET_TABLE_"                              "\n\t" \
    446                                 "ldr  %[va], [%[va], #:gotpage_lo15:__cfaasm_" #label "_after]"  "\n\t" \
    447                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    448                         ); \
    449                         region; \
    450                 });
    451         #else
    452                 #error this is not the right thing to do
    453                 /*
    454                 #define __cfaasm_label( label ) struct asm_region label = \
    455                 ({ \
    456                         struct asm_region region; \
    457                         asm( \
    458                                 "adrp %[vb], __cfaasm_" #label "_before"              "\n\t" \
    459                                 "add  %[vb], %[vb], :lo12:__cfaasm_" #label "_before" "\n\t" \
    460                                 "adrp %[va], :got:__cfaasm_" #label "_after"          "\n\t" \
    461                                 "add  %[va], %[va], :lo12:__cfaasm_" #label "_after"  "\n\t" \
    462                                  : [vb]"=r"(region.before), [va]"=r"(region.after) \
    463                         ); \
    464                         region; \
    465                 });
    466                 */
    467         #endif
    468 #else
    469         #error unknown hardware architecture
    470 #endif
     270static void timeout( thread_desc * this ) {
     271        //TODO : implement waking threads
     272}
    471273
    472274// KERNEL ONLY
    473 // Check if a __cfactx_switch signal handler shoud defer
     275// Check if a CtxSwitch signal handler shoud defer
    474276// If true  : preemption is safe
    475277// If false : preemption is unsafe and marked as pending
    476 static inline bool preemption_ready( void * ip ) {
    477         // Get all the region for which it is not safe to preempt
    478         __cfaasm_label( get    );
    479         __cfaasm_label( check  );
    480         __cfaasm_label( dsable );
    481 
     278static inline bool preemption_ready() {
    482279        // Check if preemption is safe
    483         bool ready = true;
    484         if( __cfaasm_in( ip, get    ) ) { ready = false; goto EXIT; };
    485         if( __cfaasm_in( ip, check  ) ) { ready = false; goto EXIT; };
    486         if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; };
    487         if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; };
    488         if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; };
    489 
    490 EXIT:
     280        bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress;
     281
    491282        // Adjust the pending flag accordingly
    492         __cfaabi_tls.this_processor->pending_preemption = !ready;
     283        kernelTLS.this_processor->pending_preemption = !ready;
    493284        return ready;
    494285}
     
    500291// Startup routine to activate preemption
    501292// Called from kernel_startup
    502 void __kernel_alarm_startup() {
     293void kernel_start_preemption() {
    503294        __cfaabi_dbg_print_safe( "Kernel : Starting preemption\n" );
    504295
    505296        // Start with preemption disabled until ready
    506         __cfaabi_tls.preemption_state.enabled = false;
    507         __cfaabi_tls.preemption_state.disable_count = 1;
     297        kernelTLS.preemption_state.enabled = false;
     298        kernelTLS.preemption_state.disable_count = 1;
    508299
    509300        // Initialize the event kernel
     
    512303
    513304        // Setup proper signal handlers
    514         __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
    515         __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO | SA_RESTART ); // debug handler
     305        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // CtxSwitch handler
    516306
    517307        signal_block( SIGALRM );
    518308
    519         alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p );
     309        alarm_stack = create_pthread( &alarm_thread, alarm_loop, 0p );
    520310}
    521311
    522312// Shutdown routine to deactivate preemption
    523313// Called from kernel_shutdown
    524 void __kernel_alarm_shutdown() {
     314void kernel_stop_preemption() {
    525315        __cfaabi_dbg_print_safe( "Kernel : Preemption stopping\n" );
    526316
     
    536326        // Wait for the preemption thread to finish
    537327
    538         __destroy_pthread( alarm_thread, alarm_stack, 0p );
     328        pthread_join( alarm_thread, 0p );
     329        free( alarm_stack );
    539330
    540331        // Preemption is now fully stopped
     
    562353// Kernel Signal Handlers
    563354//=============================================================================================
    564 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
    565355
    566356// Context switch signal handler
    567357// Receives SIGUSR1 signal and causes the current thread to yield
    568358static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    569         void * ip = (void *)(cxt->uc_mcontext.CFA_REG_IP);
    570         __cfaabi_dbg_debug_do( last_interrupt = ip; )
     359        __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); )
    571360
    572361        // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it,
    573362        // the interrupt that is supposed to force the kernel thread to preempt might arrive
    574         // before the kernel thread has even started running. When that happens, an interrupt
    575         // with a null 'this_processor' will be caught, just ignore it.
    576         if(! __cfaabi_tls.this_processor ) return;
     363        // before the kernel thread has even started running. When that happens an iterrupt
     364        // we a null 'this_processor' will be caught, just ignore it.
     365        if(! kernelTLS.this_processor ) return;
    577366
    578367        choose(sfp->si_value.sival_int) {
    579368                case PREEMPT_NORMAL   : ;// Normal case, nothing to do here
    580                 case PREEMPT_TERMINATE: verify( __atomic_load_n( &__cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
     369                case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
    581370                default:
    582371                        abort( "internal error, signal value is %d", sfp->si_value.sival_int );
     
    584373
    585374        // Check if it is safe to preempt here
    586         if( !preemption_ready( ip ) ) { return; }
    587 
    588         __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", __cfaabi_tls.this_processor, __cfaabi_tls.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
     375        if( !preemption_ready() ) { return; }
     376
     377        __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", kernelTLS.this_processor, kernelTLS.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );
    589378
    590379        // Sync flag : prevent recursive calls to the signal handler
    591         __cfaabi_tls.preemption_state.in_progress = true;
     380        kernelTLS.preemption_state.in_progress = true;
    592381
    593382        // Clear sighandler mask before context switching.
     
    599388        }
    600389
     390        // TODO: this should go in finish action
    601391        // Clear the in progress flag
    602         __cfaabi_tls.preemption_state.in_progress = false;
     392        kernelTLS.preemption_state.in_progress = false;
    603393
    604394        // Preemption can occur here
    605395
    606         force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch
    607 }
    608 
    609 static void sigHandler_alarm( __CFA_SIGPARMS__ ) {
    610         abort("SIGALRM should never reach the signal handler");
    611 }
    612 
    613 #if !defined(__CFA_NO_STATISTICS__)
    614         int __print_alarm_stats = 0;
    615 #endif
     396        BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch
     397}
    616398
    617399// Main of the alarm thread
    618400// Waits on SIGALRM and send SIGUSR1 to whom ever needs it
    619401static void * alarm_loop( __attribute__((unused)) void * args ) {
    620         __processor_id_t id;
    621         id.full_proc = false;
    622         id.id = doregister(&id);
    623         __cfaabi_tls.this_proc_id = &id;
    624 
    625         #if !defined(__CFA_NO_STATISTICS__)
    626                 struct __stats_t local_stats;
    627                 __cfaabi_tls.this_stats = &local_stats;
    628                 __init_stats( &local_stats );
    629         #endif
    630 
    631402        // Block sigalrms to control when they arrive
    632403        sigset_t mask;
     
    686457EXIT:
    687458        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    688         unregister(&id);
    689 
    690         #if !defined(__CFA_NO_STATISTICS__)
    691                 if( 0 != __print_alarm_stats ) {
    692                         __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p );
    693                 }
    694         #endif
    695459        return 0p;
    696460}
     
    701465
    702466void __cfaabi_check_preemption() {
    703         bool ready = __preemption_enabled();
     467        bool ready = kernelTLS.preemption_state.enabled;
    704468        if(!ready) { abort("Preemption should be ready"); }
    705469
    706470        sigset_t oldset;
    707471        int ret;
    708         ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset);  // workaround trac#208: cast should be unnecessary
     472        ret = pthread_sigmask(0, 0p, &oldset);
    709473        if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }
    710474
     
    724488#ifdef __CFA_WITH_VERIFY__
    725489bool __cfaabi_dbg_in_kernel() {
    726         return !__preemption_enabled();
     490        return !kernelTLS.preemption_state.enabled;
    727491}
    728492#endif
Note: See TracChangeset for help on using the changeset viewer.