]> gitweb.factorcode.org Git - factor.git/blob - vm/os-unix.cpp
vm: charge samples collected in prolog to parent
[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->verify_memory_protection_error((cell)siginfo->si_addr);
169         vm->signal_fault_addr = (cell)siginfo->si_addr;
170         vm->signal_fault_pc = (cell)UAP_PROGRAM_COUNTER(uap);
171         vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
172 }
173
174 void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
175 {
176         if (factor_vm::fatal_erroring_p)
177                 return;
178
179         factor_vm *vm = current_vm_p();
180         if (vm)
181         {
182                 vm->signal_number = signal;
183                 vm->dispatch_signal(uap,factor::synchronous_signal_handler_impl);
184         }
185         else
186                 fatal_error("Foreign thread received signal", signal);
187 }
188
189 void safe_write_nonblock(int fd, void *data, ssize_t size);
190
191 static void enqueue_signal(factor_vm *vm, int signal)
192 {
193         if (vm->signal_pipe_output != 0)
194                 safe_write_nonblock(vm->signal_pipe_output, &signal, sizeof(int));
195 }
196
197 void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
198 {
199         if (factor_vm::fatal_erroring_p)
200                 return;
201
202         factor_vm *vm = current_vm_p();
203         if (vm)
204                 enqueue_signal(vm, signal);
205         else
206                 fatal_error("Foreign thread received signal", signal);
207 }
208
209 void fep_signal_handler(int signal, siginfo_t *siginfo, void *uap)
210 {
211         if (factor_vm::fatal_erroring_p)
212                 return;
213
214         factor_vm *vm = current_vm_p();
215         if (vm)
216         {
217                 vm->safepoint.enqueue_fep(vm);
218                 enqueue_signal(vm, signal);
219         }
220         else
221                 fatal_error("Foreign thread received signal", signal);
222 }
223
224 void sample_signal_handler(int signal, siginfo_t *siginfo, void *uap)
225 {
226         factor_vm *vm = current_vm_p();
227         bool foreign_thread = false;
228         if (vm == NULL)
229         {
230                 foreign_thread = true;
231                 vm = thread_vms.begin()->second;
232         }
233         if (atomic::load(&vm->sampling_profiler_p))
234                 vm->safepoint.enqueue_samples(vm, 1, (cell)UAP_PROGRAM_COUNTER(uap), foreign_thread);
235         else if (!foreign_thread)
236                 enqueue_signal(vm, signal);
237 }
238
239 void ignore_signal_handler(int signal, siginfo_t *siginfo, void *uap)
240 {
241 }
242
243 void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
244 {
245         factor_vm *vm = current_vm();
246         vm->signal_number = signal;
247         vm->signal_fpu_status = fpu_status(uap_fpu_status(uap));
248         uap_clear_fpu_status(uap);
249
250         vm->dispatch_signal(uap,
251                 (siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
252                 ? factor::synchronous_signal_handler_impl
253                 : factor::fp_signal_handler_impl);
254 }
255
256 static void sigaction_safe(int signum, const struct sigaction *act, struct sigaction *oldact)
257 {
258         int ret;
259         do
260         {
261                 ret = sigaction(signum, act, oldact);
262         }
263         while(ret == -1 && errno == EINTR);
264
265         if(ret == -1)
266                 fatal_error("sigaction failed", errno);
267 }
268
269 static void init_sigaction_with_handler(struct sigaction *act,
270         void (*handler)(int, siginfo_t*, void*))
271 {
272         memset(act, 0, sizeof(struct sigaction));
273         sigemptyset(&act->sa_mask);
274         act->sa_sigaction = handler;
275         act->sa_flags = SA_SIGINFO | SA_ONSTACK;
276 }
277
278 static void safe_pipe(int *in, int *out)
279 {
280         int filedes[2];
281
282         if(pipe(filedes) < 0)
283                 fatal_error("Error opening pipe",errno);
284
285         *in = filedes[0];
286         *out = filedes[1];
287
288         if(fcntl(*in,F_SETFD,FD_CLOEXEC) < 0)
289                 fatal_error("Error with fcntl",errno);
290
291         if(fcntl(*out,F_SETFD,FD_CLOEXEC) < 0)
292                 fatal_error("Error with fcntl",errno);
293 }
294
295 static void init_signal_pipe(factor_vm *vm)
296 {
297         safe_pipe(&vm->signal_pipe_input, &vm->signal_pipe_output);
298
299         if(fcntl(vm->signal_pipe_output,F_SETFL,O_NONBLOCK) < 0)
300                 fatal_error("Error with fcntl",errno);
301
302         vm->special_objects[OBJ_SIGNAL_PIPE] = tag_fixnum(vm->signal_pipe_input);
303 }
304
305 void factor_vm::unix_init_signals()
306 {
307         init_signal_pipe(this);
308
309         signal_callstack_seg = new segment(callstack_size,false);
310
311         stack_t signal_callstack;
312         signal_callstack.ss_sp = (char *)signal_callstack_seg->start;
313         signal_callstack.ss_size = signal_callstack_seg->size;
314         signal_callstack.ss_flags = 0;
315
316         if(sigaltstack(&signal_callstack,(stack_t *)NULL) < 0)
317                 fatal_error("sigaltstack() failed",0);
318
319         struct sigaction memory_sigaction;
320         struct sigaction synchronous_sigaction;
321         struct sigaction enqueue_sigaction;
322         struct sigaction sample_sigaction;
323         struct sigaction fpe_sigaction;
324         struct sigaction ignore_sigaction;
325
326         init_sigaction_with_handler(&memory_sigaction, memory_signal_handler);
327         sigaction_safe(SIGBUS,&memory_sigaction,NULL);
328         sigaction_safe(SIGSEGV,&memory_sigaction,NULL);
329         sigaction_safe(SIGTRAP,&memory_sigaction,NULL);
330
331         init_sigaction_with_handler(&fpe_sigaction, fpe_signal_handler);
332         sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
333
334         init_sigaction_with_handler(&synchronous_sigaction, synchronous_signal_handler);
335         sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
336         sigaction_safe(SIGABRT,&synchronous_sigaction,NULL);
337
338         init_sigaction_with_handler(&enqueue_sigaction, enqueue_signal_handler);
339         sigaction_safe(SIGWINCH,&enqueue_sigaction,NULL);
340         sigaction_safe(SIGUSR1,&enqueue_sigaction,NULL);
341         sigaction_safe(SIGCONT,&enqueue_sigaction,NULL);
342         sigaction_safe(SIGURG,&enqueue_sigaction,NULL);
343         sigaction_safe(SIGIO,&enqueue_sigaction,NULL);
344         sigaction_safe(SIGPROF,&enqueue_sigaction,NULL);
345         sigaction_safe(SIGVTALRM,&enqueue_sigaction,NULL);
346 #ifdef SIGINFO
347         sigaction_safe(SIGINFO,&enqueue_sigaction,NULL);
348 #endif
349
350         handle_ctrl_c();
351
352         init_sigaction_with_handler(&sample_sigaction, sample_signal_handler);
353         sigaction_safe(SIGALRM,&sample_sigaction,NULL);
354
355         /* We don't use SA_IGN here because then the ignore action is inherited
356         by subprocesses, which we don't want. There is a unit test in
357         io.launcher.unix for this. */
358         init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
359         sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
360         /* We send SIGUSR2 to the stdin_loop thread to interrupt it on FEP */
361         sigaction_safe(SIGUSR2,&ignore_sigaction,NULL);
362 }
363
364 /* On Unix, shared fds such as stdin cannot be set to non-blocking mode
365 (http://homepages.tesco.net/J.deBoynePollard/FGA/dont-set-shared-file-descriptors-to-non-blocking-mode.html)
366 so we kludge around this by spawning a thread, which waits on a control pipe
367 for a signal, upon receiving this signal it reads one block of data from stdin
368 and writes it to a data pipe. Upon completion, it writes a 4-byte integer to
369 the size pipe, indicating how much data was written to the data pipe.
370
371 The read end of the size pipe can be set to non-blocking. */
372 extern "C" {
373         int stdin_read;
374         int stdin_write;
375
376         int control_read;
377         int control_write;
378
379         int size_read;
380         int size_write;
381
382         bool stdin_thread_initialized_p = false;
383         THREADHANDLE stdin_thread;
384         pthread_mutex_t stdin_mutex;
385 }
386
387 void safe_close(int fd)
388 {
389         if(close(fd) < 0)
390                 fatal_error("error closing fd",errno);
391 }
392
393 bool check_write(int fd, void *data, ssize_t size)
394 {
395         if(write(fd,data,size) == size)
396                 return true;
397         else
398         {
399                 if(errno == EINTR)
400                         return check_write(fd,data,size);
401                 else
402                         return false;
403         }
404 }
405
406 void safe_write(int fd, void *data, ssize_t size)
407 {
408         if(!check_write(fd,data,size))
409                 fatal_error("error writing fd",errno);
410 }
411
412 void safe_write_nonblock(int fd, void *data, ssize_t size)
413 {
414         if(!check_write(fd,data,size) && errno != EAGAIN)
415                 fatal_error("error writing fd",errno);
416 }
417
418 bool safe_read(int fd, void *data, ssize_t size)
419 {
420         ssize_t bytes = read(fd,data,size);
421         if(bytes < 0)
422         {
423                 if(errno == EINTR)
424                         return safe_read(fd,data,size);
425                 else
426                 {
427                         fatal_error("error reading fd",errno);
428                         return false;
429                 }
430         }
431         else
432                 return (bytes == size);
433 }
434
435 void *stdin_loop(void *arg)
436 {
437         unsigned char buf[4096];
438         bool loop_running = true;
439
440         sigset_t mask;
441         sigfillset(&mask);
442         sigdelset(&mask, SIGUSR2);
443         sigdelset(&mask, SIGTTIN);
444         sigdelset(&mask, SIGTERM);
445         sigdelset(&mask, SIGQUIT);
446         pthread_sigmask(SIG_SETMASK, &mask, NULL);
447
448         int unused;
449         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &unused);
450         pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &unused);
451
452         while(loop_running)
453         {
454                 if(!safe_read(control_read,buf,1))
455                         break;
456
457                 if(buf[0] != 'X')
458                         fatal_error("stdin_loop: bad data on control fd",buf[0]);
459
460                 for(;;)
461                 {
462                         /* If we fep, the parent thread will grab stdin_mutex and send us
463                         SIGUSR2 to interrupt the read() call. */
464                         pthread_mutex_lock(&stdin_mutex);
465                         pthread_mutex_unlock(&stdin_mutex);
466                         ssize_t bytes = read(0,buf,sizeof(buf));
467                         if(bytes < 0)
468                         {
469                                 if(errno == EINTR)
470                                         continue;
471                                 else
472                                 {
473                                         loop_running = false;
474                                         break;
475                                 }
476                         }
477                         else if(bytes >= 0)
478                         {
479                                 safe_write(size_write,&bytes,sizeof(bytes));
480
481                                 if(!check_write(stdin_write,buf,bytes))
482                                         loop_running = false;
483                                 break;
484                         }
485                 }
486         }
487
488         safe_close(stdin_write);
489         safe_close(control_read);
490
491         return NULL;
492 }
493
494 void factor_vm::open_console()
495 {
496         assert(!stdin_thread_initialized_p);
497         safe_pipe(&control_read,&control_write);
498         safe_pipe(&size_read,&size_write);
499         safe_pipe(&stdin_read,&stdin_write);
500         stdin_thread = start_thread(stdin_loop,NULL);
501         stdin_thread_initialized_p = true;
502         pthread_mutex_init(&stdin_mutex, NULL);
503 }
504
505 /* This method is used to kill the stdin_loop before exiting from factor.
506 A Nvidia driver bug on Linux is the reason this has to be done, see:
507 http://www.nvnews.net/vbulletin/showthread.php?t=164619 */
508 void factor_vm::close_console()
509 {
510         if (stdin_thread_initialized_p)
511                 pthread_cancel(stdin_thread);
512 }
513
514 void factor_vm::lock_console()
515 {
516         assert(stdin_thread_initialized_p);
517         /* Lock the stdin_mutex and send the stdin_loop thread a signal to interrupt
518         any read() it has in progress. When the stdin loop iterates again, it will
519         try to lock the same mutex and wait until unlock_console() is called. */
520         pthread_mutex_lock(&stdin_mutex);
521         pthread_kill(stdin_thread, SIGUSR2);
522 }
523
524 void factor_vm::unlock_console()
525 {
526         assert(stdin_thread_initialized_p);
527         pthread_mutex_unlock(&stdin_mutex);
528 }
529
530 void factor_vm::ignore_ctrl_c()
531 {
532         sig_t ret;
533         do
534         {
535                 ret = signal(SIGINT, SIG_DFL);
536         }
537         while(ret == SIG_ERR && errno == EINTR);
538 }
539
540 void factor_vm::handle_ctrl_c()
541 {
542         struct sigaction fep_sigaction;
543         init_sigaction_with_handler(&fep_sigaction, fep_signal_handler);
544         sigaction_safe(SIGINT,&fep_sigaction,NULL);
545 }
546
547 void factor_vm::abort()
548 {
549         sig_t ret;
550         do
551         {
552                 ret = signal(SIGABRT, SIG_DFL);
553         }
554         while(ret == SIG_ERR && errno == EINTR);
555         
556         close_console();
557         ::abort();
558 }
559
560 }