]> gitweb.factorcode.org Git - factor.git/blob - vm/os-unix.cpp
vm: don't SIGQUIT on unix or Ctrl-Break on windows
[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(SIGINT,&fep_sigaction,NULL);
341
342         init_sigaction_with_handler(&sample_sigaction, sample_signal_handler);
343         sigaction_safe(SIGALRM,&sample_sigaction,NULL);
344
345         /* We don't use SA_IGN here because then the ignore action is inherited
346         by subprocesses, which we don't want. There is a unit test in
347         io.launcher.unix for this. */
348         init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
349         sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
350         /* We send SIGUSR2 to the stdin_loop thread to interrupt it on FEP */
351         sigaction_safe(SIGUSR2,&ignore_sigaction,NULL);
352 }
353
354 /* On Unix, shared fds such as stdin cannot be set to non-blocking mode
355 (http://homepages.tesco.net/J.deBoynePollard/FGA/dont-set-shared-file-descriptors-to-non-blocking-mode.html)
356 so we kludge around this by spawning a thread, which waits on a control pipe
357 for a signal, upon receiving this signal it reads one block of data from stdin
358 and writes it to a data pipe. Upon completion, it writes a 4-byte integer to
359 the size pipe, indicating how much data was written to the data pipe.
360
361 The read end of the size pipe can be set to non-blocking. */
362 extern "C" {
363         int stdin_read;
364         int stdin_write;
365
366         int control_read;
367         int control_write;
368
369         int size_read;
370         int size_write;
371
372         THREADHANDLE stdin_thread;
373         pthread_mutex_t stdin_mutex;
374 }
375
376 void safe_close(int fd)
377 {
378         if(close(fd) < 0)
379                 fatal_error("error closing fd",errno);
380 }
381
382 bool check_write(int fd, void *data, ssize_t size)
383 {
384         if(write(fd,data,size) == size)
385                 return true;
386         else
387         {
388                 if(errno == EINTR)
389                         return check_write(fd,data,size);
390                 else
391                         return false;
392         }
393 }
394
395 void safe_write(int fd, void *data, ssize_t size)
396 {
397         if(!check_write(fd,data,size))
398                 fatal_error("error writing fd",errno);
399 }
400
401 void safe_write_nonblock(int fd, void *data, ssize_t size)
402 {
403         if(!check_write(fd,data,size) && errno != EAGAIN)
404                 fatal_error("error writing fd",errno);
405 }
406
407 bool safe_read(int fd, void *data, ssize_t size)
408 {
409         ssize_t bytes = read(fd,data,size);
410         if(bytes < 0)
411         {
412                 if(errno == EINTR)
413                         return safe_read(fd,data,size);
414                 else
415                 {
416                         fatal_error("error reading fd",errno);
417                         return false;
418                 }
419         }
420         else
421                 return (bytes == size);
422 }
423
424 void *stdin_loop(void *arg)
425 {
426         unsigned char buf[4096];
427         bool loop_running = true;
428
429         sigset_t mask;
430         sigfillset(&mask);
431         sigdelset(&mask, SIGUSR2);
432         sigdelset(&mask, SIGTTIN);
433         sigdelset(&mask, SIGTERM);
434         sigdelset(&mask, SIGQUIT);
435         pthread_sigmask(SIG_SETMASK, &mask, NULL);
436
437         while(loop_running)
438         {
439                 if(!safe_read(control_read,buf,1))
440                         break;
441
442                 if(buf[0] != 'X')
443                         fatal_error("stdin_loop: bad data on control fd",buf[0]);
444
445                 for(;;)
446                 {
447                         // If we fep, the parent thread will grab stdin_mutex and send us
448                         // SIGUSR2 to interrupt the read() call.
449                         pthread_mutex_lock(&stdin_mutex);
450                         pthread_mutex_unlock(&stdin_mutex);
451                         ssize_t bytes = read(0,buf,sizeof(buf));
452                         if(bytes < 0)
453                         {
454                                 if(errno == EINTR)
455                                         continue;
456                                 else
457                                 {
458                                         loop_running = false;
459                                         break;
460                                 }
461                         }
462                         else if(bytes >= 0)
463                         {
464                                 safe_write(size_write,&bytes,sizeof(bytes));
465
466                                 if(!check_write(stdin_write,buf,bytes))
467                                         loop_running = false;
468                                 break;
469                         }
470                 }
471         }
472
473         safe_close(stdin_write);
474         safe_close(control_read);
475
476         return NULL;
477 }
478
479 void factor_vm::open_console()
480 {
481         safe_pipe(&control_read,&control_write);
482         safe_pipe(&size_read,&size_write);
483         safe_pipe(&stdin_read,&stdin_write);
484         stdin_thread = start_thread(stdin_loop,NULL);
485         pthread_mutex_init(&stdin_mutex, NULL);
486 }
487
488 void factor_vm::lock_console()
489 {
490         // Lock the stdin_mutex and send the stdin_loop thread a signal to interrupt
491         // any read() it has in progress. When the stdin loop iterates again, it will
492         // try to lock the same mutex and wait until unlock_console() is called.
493         pthread_mutex_lock(&stdin_mutex);
494         pthread_kill(stdin_thread, SIGUSR2);
495 }
496
497 void factor_vm::unlock_console()
498 {
499         pthread_mutex_unlock(&stdin_mutex);
500 }
501
502 }