]> gitweb.factorcode.org Git - factor.git/blob - vm/os-unix.cpp
vm: hand SIGALRM to signal pipe if not sampling
[factor.git] / vm / os-unix.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 THREADHANDLE start_thread(void *(*start_routine)(void *),void *args)
7 {
8         pthread_attr_t attr;
9         pthread_t thread;
10         if (pthread_attr_init (&attr) != 0)
11                 fatal_error("pthread_attr_init() failed",0);
12         if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE) != 0)
13                 fatal_error("pthread_attr_setdetachstate() failed",0);
14         if (pthread_create (&thread, &attr, start_routine, args) != 0)
15                 fatal_error("pthread_create() failed",0);
16         pthread_attr_destroy(&attr);
17         return thread;
18 }
19
20 static void *null_dll;
21
22 void sleep_nanos(u64 nsec)
23 {
24         timespec ts;
25         timespec ts_rem;
26         int ret;
27         ts.tv_sec = nsec / 1000000000;
28         ts.tv_nsec = nsec % 1000000000;
29         ret = nanosleep(&ts,&ts_rem);
30         while(ret == -1 && errno == EINTR)
31         {
32                 memcpy(&ts, &ts_rem, sizeof(ts));
33                 ret = nanosleep(&ts, &ts_rem);
34         }
35
36         if(ret == -1)
37                 fatal_error("nanosleep failed", 0);
38 }
39
40 void factor_vm::init_ffi()
41 {
42         null_dll = dlopen(NULL,RTLD_LAZY);
43 }
44
45 void factor_vm::ffi_dlopen(dll *dll)
46 {
47         dll->handle = dlopen(alien_offset(dll->path), RTLD_LAZY);
48 }
49
50 void *factor_vm::ffi_dlsym_raw(dll *dll, symbol_char *symbol)
51 {
52         return dlsym(dll ? dll->handle : null_dll, symbol);
53 }
54
55 void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
56 {
57         return FUNCTION_CODE_POINTER(ffi_dlsym_raw(dll, symbol));
58 }
59
60 #ifdef FACTOR_PPC
61 void *factor_vm::ffi_dlsym_toc(dll *dll, symbol_char *symbol)
62 {
63         return FUNCTION_TOC_POINTER(ffi_dlsym_raw(dll, symbol));
64 }
65 #endif
66
67 void factor_vm::ffi_dlclose(dll *dll)
68 {
69         if(dlclose(dll->handle))
70                 general_error(ERROR_FFI,false_object,false_object);
71         dll->handle = NULL;
72 }
73
74 void factor_vm::primitive_existsp()
75 {
76         struct stat sb;
77         char *path = (char *)(untag_check<byte_array>(ctx->pop()) + 1);
78         ctx->push(tag_boolean(stat(path,&sb) >= 0));
79 }
80
81 void factor_vm::move_file(const vm_char *path1, const vm_char *path2)
82 {
83         int ret = 0;
84         do
85         {
86                 ret = rename((path1),(path2));
87         }
88         while(ret < 0 && errno == EINTR);
89
90         if(ret < 0)
91                 general_error(ERROR_IO,tag_fixnum(errno),false_object);
92 }
93
94 segment::segment(cell size_, bool executable_p)
95 {
96         size = size_;
97
98         int pagesize = getpagesize();
99
100         int prot;
101         if(executable_p)
102                 prot = (PROT_READ | PROT_WRITE | PROT_EXEC);
103         else
104                 prot = (PROT_READ | PROT_WRITE);
105
106         char *array = (char *)mmap(NULL,pagesize + size + pagesize,prot,MAP_ANON | MAP_PRIVATE,-1,0);
107         if(array == (char*)-1) out_of_memory();
108
109         if(mprotect(array,pagesize,PROT_NONE) == -1)
110                 fatal_error("Cannot protect low guard page",(cell)array);
111
112         if(mprotect(array + pagesize + size,pagesize,PROT_NONE) == -1)
113                 fatal_error("Cannot protect high guard page",(cell)array);
114
115         start = (cell)(array + pagesize);
116         end = start + size;
117 }
118
119 segment::~segment()
120 {
121         int pagesize = getpagesize();
122         int retval = munmap((void*)(start - pagesize),pagesize + size + pagesize);
123         if(retval)
124                 fatal_error("Segment deallocation failed",0);
125 }
126
127 void code_heap::guard_safepoint()
128 {
129         if(mprotect(safepoint_page,getpagesize(),PROT_NONE) == -1)
130                 fatal_error("Cannot protect safepoint guard page",(cell)safepoint_page);
131 }
132
133 void code_heap::unguard_safepoint()
134 {
135         if(mprotect(safepoint_page,getpagesize(),PROT_WRITE) == -1)
136                 fatal_error("Cannot unprotect safepoint guard page",(cell)safepoint_page);
137 }
138
139 void factor_vm::dispatch_signal(void *uap, void (handler)())
140 {
141         dispatch_signal_handler(
142                 (cell*)&UAP_STACK_POINTER(uap),
143                 (cell*)&UAP_PROGRAM_COUNTER(uap),
144                 (cell)FUNCTION_CODE_POINTER(handler)
145         );
146         UAP_SET_TOC_POINTER(uap, (cell)FUNCTION_TOC_POINTER(handler));
147 }
148
149 void factor_vm::start_sampling_profiler_timer()
150 {
151         struct itimerval timer;
152         memset((void*)&timer, 0, sizeof(struct itimerval));
153         timer.it_value.tv_usec = 1000000/samples_per_second;
154         timer.it_interval.tv_usec = 1000000/samples_per_second;
155         setitimer(ITIMER_REAL, &timer, NULL);
156 }
157
158 void factor_vm::end_sampling_profiler_timer()
159 {
160         struct itimerval timer;
161         memset((void*)&timer, 0, sizeof(struct itimerval));
162         setitimer(ITIMER_REAL, &timer, NULL);
163 }
164
165 void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
166 {
167         factor_vm *vm = current_vm();
168         vm->signal_fault_addr = (cell)siginfo->si_addr;
169         vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
170 }
171
172 void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
173 {
174         factor_vm *vm = current_vm_p();
175         if (vm)
176         {
177                 vm->signal_number = signal;
178                 vm->dispatch_signal(uap,factor::synchronous_signal_handler_impl);
179         } else
180                 fatal_error("Foreign thread received signal", signal);
181 }
182
183 void safe_write_nonblock(int fd, void *data, ssize_t size);
184
185 static void enqueue_signal(factor_vm *vm, int signal)
186 {
187         if (vm->signal_pipe_output != 0)
188                 safe_write_nonblock(vm->signal_pipe_output, &signal, sizeof(int));
189 }
190
191 void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
192 {
193         factor_vm *vm = current_vm_p();
194         if (vm)
195                 enqueue_signal(vm, signal);
196         else
197                 fatal_error("Foreign thread received signal", signal);
198 }
199
200 void fep_signal_handler(int signal, siginfo_t *siginfo, void *uap)
201 {
202         factor_vm *vm = current_vm_p();
203         if (vm)
204         {
205                 vm->safepoint.enqueue_fep(vm);
206                 enqueue_signal(vm, signal);
207         }
208         else
209                 fatal_error("Foreign thread received signal", signal);
210 }
211
212 void sample_signal_handler(int signal, siginfo_t *siginfo, void *uap)
213 {
214         factor_vm *vm = current_vm_p();
215         bool foreign_thread = false;
216         if (vm == NULL)
217         {
218                 foreign_thread = true;
219                 vm = thread_vms.begin()->second;
220         }
221         if (atomic::load(&vm->sampling_profiler_p))
222                 vm->safepoint.enqueue_samples(vm, 1, (cell)UAP_PROGRAM_COUNTER(uap), foreign_thread);
223         else if (!foreign_thread)
224                 enqueue_signal(vm, signal);
225 }
226
227 void ignore_signal_handler(int signal, siginfo_t *siginfo, void *uap)
228 {
229 }
230
231 void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
232 {
233         factor_vm *vm = current_vm();
234         vm->signal_number = signal;
235         vm->signal_fpu_status = fpu_status(uap_fpu_status(uap));
236         uap_clear_fpu_status(uap);
237
238         vm->dispatch_signal(uap,
239                 (siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
240                 ? factor::synchronous_signal_handler_impl
241                 : factor::fp_signal_handler_impl);
242 }
243
244 static void sigaction_safe(int signum, const struct sigaction *act, struct sigaction *oldact)
245 {
246         int ret;
247         do
248         {
249                 ret = sigaction(signum, act, oldact);
250         }
251         while(ret == -1 && errno == EINTR);
252
253         if(ret == -1)
254                 fatal_error("sigaction failed", 0);
255 }
256
257 static void init_sigaction_with_handler(struct sigaction *act,
258         void (*handler)(int, siginfo_t*, void*))
259 {
260         memset(act, 0, sizeof(struct sigaction));
261         sigemptyset(&act->sa_mask);
262         act->sa_sigaction = handler;
263         act->sa_flags = SA_SIGINFO | SA_ONSTACK;
264 }
265
266 static void safe_pipe(int *in, int *out)
267 {
268         int filedes[2];
269
270         if(pipe(filedes) < 0)
271                 fatal_error("Error opening pipe",errno);
272
273         *in = filedes[0];
274         *out = filedes[1];
275
276         if(fcntl(*in,F_SETFD,FD_CLOEXEC) < 0)
277                 fatal_error("Error with fcntl",errno);
278
279         if(fcntl(*out,F_SETFD,FD_CLOEXEC) < 0)
280                 fatal_error("Error with fcntl",errno);
281 }
282
283 static void init_signal_pipe(factor_vm *vm)
284 {
285         safe_pipe(&vm->signal_pipe_input, &vm->signal_pipe_output);
286
287         if(fcntl(vm->signal_pipe_output,F_SETFL,O_NONBLOCK) < 0)
288                 fatal_error("Error with fcntl",errno);
289
290         vm->special_objects[OBJ_SIGNAL_PIPE] = tag_fixnum(vm->signal_pipe_input);
291 }
292
293 void factor_vm::unix_init_signals()
294 {
295         init_signal_pipe(this);
296
297         signal_callstack_seg = new segment(callstack_size,false);
298
299         stack_t signal_callstack;
300         signal_callstack.ss_sp = (char *)signal_callstack_seg->start;
301         signal_callstack.ss_size = signal_callstack_seg->size;
302         signal_callstack.ss_flags = 0;
303
304         if(sigaltstack(&signal_callstack,(stack_t *)NULL) < 0)
305                 fatal_error("sigaltstack() failed",0);
306
307         struct sigaction memory_sigaction;
308         struct sigaction synchronous_sigaction;
309         struct sigaction enqueue_sigaction;
310         struct sigaction fep_sigaction;
311         struct sigaction sample_sigaction;
312         struct sigaction fpe_sigaction;
313         struct sigaction ignore_sigaction;
314
315         init_sigaction_with_handler(&memory_sigaction, memory_signal_handler);
316         sigaction_safe(SIGBUS,&memory_sigaction,NULL);
317         sigaction_safe(SIGSEGV,&memory_sigaction,NULL);
318         sigaction_safe(SIGTRAP,&memory_sigaction,NULL);
319
320         init_sigaction_with_handler(&fpe_sigaction, fpe_signal_handler);
321         sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
322
323         init_sigaction_with_handler(&synchronous_sigaction, synchronous_signal_handler);
324         sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
325         sigaction_safe(SIGABRT,&synchronous_sigaction,NULL);
326
327         init_sigaction_with_handler(&enqueue_sigaction, enqueue_signal_handler);
328         sigaction_safe(SIGWINCH,&enqueue_sigaction,NULL);
329         sigaction_safe(SIGUSR1,&enqueue_sigaction,NULL);
330         sigaction_safe(SIGCONT,&enqueue_sigaction,NULL);
331         sigaction_safe(SIGURG,&enqueue_sigaction,NULL);
332         sigaction_safe(SIGIO,&enqueue_sigaction,NULL);
333         sigaction_safe(SIGPROF,&enqueue_sigaction,NULL);
334         sigaction_safe(SIGVTALRM,&enqueue_sigaction,NULL);
335 #ifdef SIGINFO
336         sigaction_safe(SIGINFO,&enqueue_sigaction,NULL);
337 #endif
338
339         init_sigaction_with_handler(&fep_sigaction, fep_signal_handler);
340         sigaction_safe(SIGQUIT,&fep_sigaction,NULL);
341         sigaction_safe(SIGINT,&fep_sigaction,NULL);
342
343         init_sigaction_with_handler(&sample_sigaction, sample_signal_handler);
344         sigaction_safe(SIGALRM,&sample_sigaction,NULL);
345
346         /* We don't use SA_IGN here because then the ignore action is inherited
347         by subprocesses, which we don't want. There is a unit test in
348         io.launcher.unix for this. */
349         init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
350         sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
351         /* We send SIGUSR2 to the stdin_loop thread to interrupt it on FEP */
352         sigaction_safe(SIGUSR2,&ignore_sigaction,NULL);
353 }
354
355 /* On Unix, shared fds such as stdin cannot be set to non-blocking mode
356 (http://homepages.tesco.net/J.deBoynePollard/FGA/dont-set-shared-file-descriptors-to-non-blocking-mode.html)
357 so we kludge around this by spawning a thread, which waits on a control pipe
358 for a signal, upon receiving this signal it reads one block of data from stdin
359 and writes it to a data pipe. Upon completion, it writes a 4-byte integer to
360 the size pipe, indicating how much data was written to the data pipe.
361
362 The read end of the size pipe can be set to non-blocking. */
363 extern "C" {
364         int stdin_read;
365         int stdin_write;
366
367         int control_read;
368         int control_write;
369
370         int size_read;
371         int size_write;
372
373         THREADHANDLE stdin_thread;
374         pthread_mutex_t stdin_mutex;
375 }
376
377 void safe_close(int fd)
378 {
379         if(close(fd) < 0)
380                 fatal_error("error closing fd",errno);
381 }
382
383 bool check_write(int fd, void *data, ssize_t size)
384 {
385         if(write(fd,data,size) == size)
386                 return true;
387         else
388         {
389                 if(errno == EINTR)
390                         return check_write(fd,data,size);
391                 else
392                         return false;
393         }
394 }
395
396 void safe_write(int fd, void *data, ssize_t size)
397 {
398         if(!check_write(fd,data,size))
399                 fatal_error("error writing fd",errno);
400 }
401
402 void safe_write_nonblock(int fd, void *data, ssize_t size)
403 {
404         if(!check_write(fd,data,size) && errno != EAGAIN)
405                 fatal_error("error writing fd",errno);
406 }
407
408 bool safe_read(int fd, void *data, ssize_t size)
409 {
410         ssize_t bytes = read(fd,data,size);
411         if(bytes < 0)
412         {
413                 if(errno == EINTR)
414                         return safe_read(fd,data,size);
415                 else
416                 {
417                         fatal_error("error reading fd",errno);
418                         return false;
419                 }
420         }
421         else
422                 return (bytes == size);
423 }
424
425 void *stdin_loop(void *arg)
426 {
427         unsigned char buf[4096];
428         bool loop_running = true;
429
430         sigset_t mask;
431         sigfillset(&mask);
432         sigdelset(&mask, SIGUSR2);
433         sigdelset(&mask, SIGTTIN);
434         pthread_sigmask(SIG_SETMASK, &mask, NULL);
435
436         while(loop_running)
437         {
438                 if(!safe_read(control_read,buf,1))
439                         break;
440
441                 if(buf[0] != 'X')
442                         fatal_error("stdin_loop: bad data on control fd",buf[0]);
443
444                 for(;;)
445                 {
446                         // If we fep, the parent thread will grab stdin_mutex and send us
447                         // SIGUSR2 to interrupt the read() call.
448                         pthread_mutex_lock(&stdin_mutex);
449                         pthread_mutex_unlock(&stdin_mutex);
450                         ssize_t bytes = read(0,buf,sizeof(buf));
451                         if(bytes < 0)
452                         {
453                                 if(errno == EINTR)
454                                         continue;
455                                 else
456                                 {
457                                         loop_running = false;
458                                         break;
459                                 }
460                         }
461                         else if(bytes >= 0)
462                         {
463                                 safe_write(size_write,&bytes,sizeof(bytes));
464
465                                 if(!check_write(stdin_write,buf,bytes))
466                                         loop_running = false;
467                                 break;
468                         }
469                 }
470         }
471
472         safe_close(stdin_write);
473         safe_close(control_read);
474
475         return NULL;
476 }
477
478 void factor_vm::open_console()
479 {
480         safe_pipe(&control_read,&control_write);
481         safe_pipe(&size_read,&size_write);
482         safe_pipe(&stdin_read,&stdin_write);
483         stdin_thread = start_thread(stdin_loop,NULL);
484         pthread_mutex_init(&stdin_mutex, NULL);
485 }
486
487 void factor_vm::lock_console()
488 {
489         // Lock the stdin_mutex and send the stdin_loop thread a signal to interrupt
490         // any read() it has in progress. When the stdin loop iterates again, it will
491         // try to lock the same mutex and wait until unlock_console() is called.
492         pthread_mutex_lock(&stdin_mutex);
493         pthread_kill(stdin_thread, SIGUSR2);
494 }
495
496 void factor_vm::unlock_console()
497 {
498         pthread_mutex_unlock(&stdin_mutex);
499 }
500
501 }