Ignore:
File:
1 edited

Legend:

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

    rc5ac6d5 r0b33412  
    1717#include "preemption.h"
    1818
     19
    1920extern "C" {
     21#include <errno.h>
     22#define __USE_GNU
    2023#include <signal.h>
    21 }
    22 
    23 #define __CFA_DEFAULT_PREEMPTION__ 10
     24#undef __USE_GNU
     25#include <stdio.h>
     26#include <string.h>
     27#include <unistd.h>
     28}
     29
     30#include "libhdr.h"
     31
     32#define __CFA_DEFAULT_PREEMPTION__ 10000
    2433
    2534__attribute__((weak)) unsigned int default_preemption() {
     
    2736}
    2837
     38#define __CFA_SIGCXT__ ucontext_t *
     39#define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt
     40
    2941static void preempt( processor   * this );
    3042static void timeout( thread_desc * this );
     43
     44void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
     45void sigHandler_alarm    ( __CFA_SIGPARMS__ );
     46
     47static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags );
    3148
    3249//=============================================================================================
     
    3552
    3653void kernel_start_preemption() {
    37 
    38 }
     54        LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n");
     55        __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO );
     56        __kernel_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO );
     57}
     58
     59void kernel_stop_preemption() {
     60        //Block all signals, we are no longer in a position to handle them
     61        sigset_t mask;
     62        sigfillset( &mask );
     63        sigprocmask( SIG_BLOCK, &mask, NULL );
     64        LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");
     65
     66        assert( !systemProcessor->alarms.head );
     67        assert( systemProcessor->alarms.tail == &systemProcessor->alarms.head );
     68}
     69
     70LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )
    3971
    4072void tick_preemption() {
     73        LIB_DEBUG_DO(
     74                char text[256];
     75                __attribute__((unused)) int len = snprintf( text, 256, "Ticking preemption\n" );
     76                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     77        );
     78
    4179        alarm_list_t * alarms = &systemProcessor->alarms;
    4280        __cfa_time_t currtime = __kernel_get_time();
    4381        while( alarms->head && alarms->head->alarm < currtime ) {
    4482                alarm_node_t * node = pop(alarms);
     83                LIB_DEBUG_DO(
     84                        len = snprintf( text, 256, "Ticking %p\n", node );
     85                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     86                );
    4587                if( node->kernel_alarm ) {
    4688                        preempt( node->proc );
     
    5092                }
    5193
     94                LIB_DEBUG_DO( assert( validate( alarms ) ) );
     95
    5296                if( node->period > 0 ) {
    53                         node->alarm += node->period;
     97                        node->alarm = currtime + node->period;
    5498                        insert( alarms, node );
    5599                }
     
    62106                __kernel_set_timer( alarms->head->alarm - currtime );
    63107        }
     108
     109        verify( validate( alarms ) );
     110        LIB_DEBUG_DO(
     111                len = snprintf( text, 256, "Ticking preemption done\n" );
     112                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     113        );
    64114}
    65115
    66116void update_preemption( processor * this, __cfa_time_t duration ) {
    67         //     assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 );
     117        LIB_DEBUG_DO(
     118                char text[256];
     119                __attribute__((unused)) int len = snprintf( text, 256, "Processor : %p updating preemption to %lu\n", this, duration );
     120                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     121        );
     122
    68123        alarm_node_t * alarm = this->preemption_alarm;
     124        duration *= 1000;
    69125
    70126        // Alarms need to be enabled
     
    97153
    98154void ^?{}( preemption_scope * this ) {
     155        disable_interrupts();
     156
    99157        update_preemption( this->proc, 0 );
    100158}
     
    104162//=============================================================================================
    105163
     164extern "C" {
     165        void disable_interrupts() {
     166                __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST );
     167                verify( new_val < (unsigned short)65_000 );
     168                verify( new_val != (unsigned short) 0 );
     169        }
     170
     171        void enable_interrupts_noRF() {
     172                unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
     173                verify( prev != (unsigned short) 0 );
     174        }
     175
     176        void enable_interrupts( const char * func ) {
     177                unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
     178                verify( prev != (unsigned short) 0 );
     179                if( prev == 1 && this_processor->pending_preemption ) {
     180                        this_processor->pending_preemption = false;
     181                        LIB_DEBUG_DO(
     182                                char text[256];
     183                                __attribute__((unused)) int len = snprintf( text, 256, "Executing deferred CtxSwitch on %p\n", this_processor );
     184                                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     185                        );
     186                        BlockInternal( this_processor->current_thread );
     187                }
     188
     189                this_processor->last_enable = func;
     190        }
     191}
     192
     193static inline void signal_unblock( bool alarm ) {
     194        sigset_t mask;
     195        sigemptyset( &mask );
     196        sigaddset( &mask, SIGUSR1 );
     197
     198        if( alarm ) sigaddset( &mask, SIGALRM );
     199
     200        if ( sigprocmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
     201            abortf( "internal error, sigprocmask" );
     202        } // if
     203}
     204
    106205static inline bool preemption_ready() {
    107         return this_processor->disable_preempt_count == 0;
     206        return disable_preempt_count == 0;
    108207}
    109208
     
    116215}
    117216
    118 void sigHandler_ctxSwitch( __attribute__((unused)) int sig ) {
     217void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
     218
     219        LIB_DEBUG_DO(
     220                char text[256];
     221                __attribute__((unused)) int len = snprintf( text, 256, "Ctx Switch IRH %p\n", (void *)(cxt->uc_mcontext.gregs[REG_RIP]));
     222                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     223        );
     224
     225        signal_unblock( false );
    119226        if( preemption_ready() ) {
    120                 ScheduleInternal( this_processor->current_thread );
     227                LIB_DEBUG_DO(
     228                        len = snprintf( text, 256, "Ctx Switch IRH : Blocking thread %p on %p\n", this_processor->current_thread, this_processor );
     229                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     230                );
     231                BlockInternal( this_processor->current_thread );
    121232        }
    122233        else {
     234                LIB_DEBUG_DO(
     235                        len = snprintf( text, 256, "Ctx Switch IRH : Defering\n" );
     236                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     237                );
    123238                defer_ctxSwitch();
    124239        }
    125240}
    126241
    127 void sigHandler_alarm( __attribute__((unused)) int sig ) {
     242void sigHandler_alarm( __CFA_SIGPARMS__ ) {
     243
     244        LIB_DEBUG_DO(
     245                char text[256];
     246                __attribute__((unused)) int len = snprintf( text, 256, "\nAlarm IRH %p\n", (void *)(cxt->uc_mcontext.gregs[REG_RIP]) );
     247                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     248        );
     249
     250        signal_unblock( true );
    128251        if( try_lock( &systemProcessor->alarm_lock ) ) {
    129252                tick_preemption();
     
    133256                defer_alarm();
    134257        }
     258
     259        if( preemption_ready() && this_processor->pending_preemption ) {
     260                LIB_DEBUG_DO(
     261                        len = snprintf( text, 256, "Alarm IRH : Blocking thread\n" );
     262                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     263                );
     264                this_processor->pending_preemption = false;
     265                BlockInternal( this_processor->current_thread );
     266        }
    135267}
    136268
    137269static void preempt( processor * this ) {
    138         pthread_kill( this->kernel_thread, SIGUSR1 );
     270        LIB_DEBUG_DO(
     271                char text[256];
     272                __attribute__((unused)) int len = snprintf( text, 256, "Processor : signalling %p\n", this );
     273                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
     274        );
     275
     276        if( this != systemProcessor ) {
     277                pthread_kill( this->kernel_thread, SIGUSR1 );
     278        }
     279        else {
     280                defer_ctxSwitch();
     281        }
    139282}
    140283
     
    142285        //TODO : implement waking threads
    143286}
     287
     288static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {
     289        struct sigaction act;
     290
     291        act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
     292        sigemptyset( &act.sa_mask );
     293        sigaddset( &act.sa_mask, SIGALRM );             // disabled during signal handler
     294        sigaddset( &act.sa_mask, SIGUSR1 );
     295
     296        act.sa_flags = flags;
     297
     298        if ( sigaction( sig, &act, NULL ) == -1 ) {
     299                // THE KERNEL IS NOT STARTED SO CALL NO uC++ ROUTINES!
     300                char helpText[256];
     301                __attribute__((unused)) int len = snprintf( helpText, 256, " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
     302                                sig, handler, flags, errno, strerror( errno ) );
     303                LIB_DEBUG_WRITE( STDERR_FILENO, helpText, len );
     304                _exit( EXIT_FAILURE );
     305        } // if
     306}
Note: See TracChangeset for help on using the changeset viewer.