source: src/libcfa/concurrency/preemption.c@ 9d85038

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 9d85038 was 82ff5845, checked in by Thierry Delisle <tdelisle@…>, 8 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.