source: src/libcfa/concurrency/preemption.c @ 82ff5845

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 82ff5845 was 82ff5845, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

First implementation of preemption, does not appear to work with scheduling

  • Property mode set to 100644
File size: 8.1 KB
Line 
1//                              -*- Mode: CFA -*-
2//
3// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
4//
5// The contents of this file are covered under the licence agreement in the
6// file "LICENCE" distributed with Cforall.
7//
8// signal.c --
9//
10// Author           : Thierry Delisle
11// Created On       : Mon Jun 5 14:20:42 2017
12// Last Modified By : Thierry Delisle
13// Last Modified On : --
14// Update Count     : 0
15//
16
17#include "preemption.h"
18
19extern "C" {
20#include <errno.h>
21#include <signal.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25}
26
27#include "libhdr.h"
28
29#define __CFA_DEFAULT_PREEMPTION__ 10000
30
31__attribute__((weak)) unsigned int default_preemption() {
32        return __CFA_DEFAULT_PREEMPTION__;
33}
34
35#define __CFA_SIGCXT__ ucontext_t *
36#define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt
37
38static void preempt( processor   * this );
39static void timeout( thread_desc * this );
40
41void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
42void sigHandler_alarm    ( __CFA_SIGPARMS__ );
43
44static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags );
45
46//=============================================================================================
47// Kernel Preemption logic
48//=============================================================================================
49
50void kernel_start_preemption() {
51        LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n");
52        __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO );
53        __kernel_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO );
54}
55
56void kernel_stop_preemption() {
57        //Block all signals, we are no longer in a position to handle them
58        sigset_t mask;
59        sigfillset( &mask );
60        sigprocmask( SIG_BLOCK, &mask, NULL );
61        LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");
62}
63
64void tick_preemption() {
65        LIB_DEBUG_DO(
66                char text[256];
67                __attribute__((unused)) int len = snprintf( text, 256, "Ticking preemption\n" );
68                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
69        );
70
71        alarm_list_t * alarms = &systemProcessor->alarms;
72        __cfa_time_t currtime = __kernel_get_time();
73        while( alarms->head && alarms->head->alarm < currtime ) {
74                alarm_node_t * node = pop(alarms);
75                LIB_DEBUG_DO(
76                        len = snprintf( text, 256, "Ticking %p\n", node );
77                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
78                );
79                if( node->kernel_alarm ) {
80                        preempt( node->proc );
81                }
82                else {
83                        timeout( node->thrd );
84                }
85
86                if( node->period > 0 ) {
87                        node->alarm = currtime + node->period;
88                        insert( alarms, node );
89                }
90                else {
91                        node->set = false;
92                }
93        }
94
95        if( alarms->head ) {
96                __kernel_set_timer( alarms->head->alarm - currtime );
97        }
98
99        LIB_DEBUG_DO(
100                len = snprintf( text, 256, "Ticking preemption done\n" );
101                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
102        );
103}
104
105void update_preemption( processor * this, __cfa_time_t duration ) {
106        LIB_DEBUG_DO(
107                char text[256];
108                __attribute__((unused)) int len = snprintf( text, 256, "Processor : updating preemption to %lu\n", duration );
109                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
110        );
111
112        alarm_node_t * alarm = this->preemption_alarm;
113        duration *= 1000;
114
115        // Alarms need to be enabled
116        if ( duration > 0 && !alarm->set ) {
117                alarm->alarm = __kernel_get_time() + duration;
118                alarm->period = duration;
119                register_self( alarm );
120        }
121        // Zero duraction but alarm is set
122        else if ( duration == 0 && alarm->set ) {
123                unregister_self( alarm );
124                alarm->alarm = 0;
125                alarm->period = 0;
126        }
127        // If alarm is different from previous, change it
128        else if ( duration > 0 && alarm->period != duration ) {
129                unregister_self( alarm );
130                alarm->alarm = __kernel_get_time() + duration;
131                alarm->period = duration;
132                register_self( alarm );
133        }
134}
135
136void ?{}( preemption_scope * this, processor * proc ) {
137        (&this->alarm){ proc };
138        this->proc = proc;
139        this->proc->preemption_alarm = &this->alarm;
140        update_preemption( this->proc, this->proc->preemption );
141
142        // enable_interrupts();
143}
144
145void ^?{}( preemption_scope * this ) {
146        disable_interrupts();
147
148        update_preemption( this->proc, 0 );
149}
150
151//=============================================================================================
152// Kernel Signal logic
153//=============================================================================================
154
155extern "C" {
156        void disable_interrupts() {
157                __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, 1, __ATOMIC_SEQ_CST );
158                assert( prev != (unsigned short) -1 );
159        }
160
161        void enable_interrupts_noRF() {
162                unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST );
163                assert( prev != (unsigned short) 0 );
164        }
165
166        void enable_interrupts() {
167                unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST );
168                assert( prev != (unsigned short) 0 );
169                if( prev == 1 && this_processor->pending_preemption ) {
170                        this_processor->pending_preemption = false;
171                        LIB_DEBUG_DO(
172                                char text[256];
173                                __attribute__((unused)) int len = snprintf( text, 256, "Executing deferred CtxSwitch\n" );
174                                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
175                        );
176                        BlockInternal( this_processor->current_thread );
177                }
178        }
179}
180
181static inline void signal_unblock( bool alarm ) {
182        sigset_t mask;
183        sigemptyset( &mask );
184        sigaddset( &mask, SIGUSR1 );
185
186        if( alarm ) sigaddset( &mask, SIGALRM );
187
188        if ( sigprocmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
189            abortf( "internal error, sigprocmask" );
190        } // if
191}
192
193static inline bool preemption_ready() {
194        return this_processor->disable_preempt_count == 0;
195}
196
197static inline void defer_ctxSwitch() {
198        this_processor->pending_preemption = true;
199}
200
201static inline void defer_alarm() {
202        systemProcessor->pending_alarm = true;
203}
204
205void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
206
207        LIB_DEBUG_DO(
208                char text[256];
209                __attribute__((unused)) int len = snprintf( text, 256, "Ctx Switch IRH\n" );
210                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
211        );
212
213        signal_unblock( false );
214        if( preemption_ready() ) {
215                LIB_DEBUG_DO(
216                        len = snprintf( text, 256, "Ctx Switch IRH : Blocking thread\n" );
217                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
218                );
219                BlockInternal( this_processor->current_thread );
220        }
221        else {
222                LIB_DEBUG_DO(
223                        len = snprintf( text, 256, "Ctx Switch IRH : Defering\n" );
224                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
225                );
226                defer_ctxSwitch();
227        }
228}
229
230void sigHandler_alarm( __CFA_SIGPARMS__ ) {
231
232        LIB_DEBUG_DO(
233                char text[256];
234                __attribute__((unused)) int len = snprintf( text, 256, "\nAlarm IRH\n" );
235                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
236        );
237
238        signal_unblock( true );
239        if( try_lock( &systemProcessor->alarm_lock ) ) {
240                tick_preemption();
241                unlock( &systemProcessor->alarm_lock );
242        }
243        else {
244                defer_alarm();
245        }
246
247        if( preemption_ready() && this_processor->pending_preemption ) {
248                LIB_DEBUG_DO(
249                        len = snprintf( text, 256, "Alarm IRH : Blocking thread\n" );
250                        LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
251                );
252                this_processor->pending_preemption = false;
253                BlockInternal( this_processor->current_thread );
254        }
255}
256
257static void preempt( processor * this ) {
258        LIB_DEBUG_DO(
259                char text[256];
260                __attribute__((unused)) int len = snprintf( text, 256, "Processor : signalling %p\n", this );
261                LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
262        );
263
264        if( this != systemProcessor ) {
265                pthread_kill( this->kernel_thread, SIGUSR1 );
266        }
267        else {
268                defer_ctxSwitch();
269        }
270}
271
272static void timeout( thread_desc * this ) {
273        //TODO : implement waking threads
274}
275
276static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {
277        struct sigaction act;
278
279        act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
280        sigemptyset( &act.sa_mask );
281        sigaddset( &act.sa_mask, SIGALRM );             // disabled during signal handler
282        sigaddset( &act.sa_mask, SIGUSR1 );
283
284        act.sa_flags = flags;
285
286        if ( sigaction( sig, &act, NULL ) == -1 ) {
287                // THE KERNEL IS NOT STARTED SO CALL NO uC++ ROUTINES!
288                char helpText[256];
289                __attribute__((unused)) int len = snprintf( helpText, 256, " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
290                                sig, handler, flags, errno, strerror( errno ) );
291                LIB_DEBUG_WRITE( STDERR_FILENO, helpText, len );
292                _exit( EXIT_FAILURE );
293        } // if
294}
Note: See TracBrowser for help on using the repository browser.