source: src/libcfa/concurrency/preemption.c@ 405c592

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 405c592 was 0b33412, checked in by Thierry Delisle <tdelisle@…>, 8 years ago

Updated tests to use verify instead of assert

  • Property mode set to 100644
File size: 8.5 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
19
20extern "C" {
21#include <errno.h>
22#define __USE_GNU
23#include <signal.h>
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
33
34__attribute__((weak)) unsigned int default_preemption() {
35 return __CFA_DEFAULT_PREEMPTION__;
36}
37
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
41static void preempt( processor * this );
42static 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 );
48
49//=============================================================================================
50// Kernel Preemption logic
51//=============================================================================================
52
53void kernel_start_preemption() {
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 ); )
71
72void 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
79 alarm_list_t * alarms = &systemProcessor->alarms;
80 __cfa_time_t currtime = __kernel_get_time();
81 while( alarms->head && alarms->head->alarm < currtime ) {
82 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 );
87 if( node->kernel_alarm ) {
88 preempt( node->proc );
89 }
90 else {
91 timeout( node->thrd );
92 }
93
94 LIB_DEBUG_DO( assert( validate( alarms ) ) );
95
96 if( node->period > 0 ) {
97 node->alarm = currtime + node->period;
98 insert( alarms, node );
99 }
100 else {
101 node->set = false;
102 }
103 }
104
105 if( alarms->head ) {
106 __kernel_set_timer( alarms->head->alarm - currtime );
107 }
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 );
114}
115
116void update_preemption( processor * this, __cfa_time_t duration ) {
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
123 alarm_node_t * alarm = this->preemption_alarm;
124 duration *= 1000;
125
126 // Alarms need to be enabled
127 if ( duration > 0 && !alarm->set ) {
128 alarm->alarm = __kernel_get_time() + duration;
129 alarm->period = duration;
130 register_self( alarm );
131 }
132 // Zero duraction but alarm is set
133 else if ( duration == 0 && alarm->set ) {
134 unregister_self( alarm );
135 alarm->alarm = 0;
136 alarm->period = 0;
137 }
138 // If alarm is different from previous, change it
139 else if ( duration > 0 && alarm->period != duration ) {
140 unregister_self( alarm );
141 alarm->alarm = __kernel_get_time() + duration;
142 alarm->period = duration;
143 register_self( alarm );
144 }
145}
146
147void ?{}( preemption_scope * this, processor * proc ) {
148 (&this->alarm){ proc };
149 this->proc = proc;
150 this->proc->preemption_alarm = &this->alarm;
151 update_preemption( this->proc, this->proc->preemption );
152}
153
154void ^?{}( preemption_scope * this ) {
155 disable_interrupts();
156
157 update_preemption( this->proc, 0 );
158}
159
160//=============================================================================================
161// Kernel Signal logic
162//=============================================================================================
163
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
205static inline bool preemption_ready() {
206 return disable_preempt_count == 0;
207}
208
209static inline void defer_ctxSwitch() {
210 this_processor->pending_preemption = true;
211}
212
213static inline void defer_alarm() {
214 systemProcessor->pending_alarm = true;
215}
216
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 );
226 if( preemption_ready() ) {
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 );
232 }
233 else {
234 LIB_DEBUG_DO(
235 len = snprintf( text, 256, "Ctx Switch IRH : Defering\n" );
236 LIB_DEBUG_WRITE( STDERR_FILENO, text, len );
237 );
238 defer_ctxSwitch();
239 }
240}
241
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 );
251 if( try_lock( &systemProcessor->alarm_lock ) ) {
252 tick_preemption();
253 unlock( &systemProcessor->alarm_lock );
254 }
255 else {
256 defer_alarm();
257 }
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 }
267}
268
269static void preempt( processor * this ) {
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 }
282}
283
284static void timeout( thread_desc * this ) {
285 //TODO : implement waking threads
286}
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 TracBrowser for help on using the repository browser.