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