]> gitweb.factorcode.org Git - factor.git/blob - vm/os-unix.cpp
30924c6bfe47ce40ca0ba40ff678dc9766afe6ff
[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::enqueue_safepoint_signal(cell signal)
150 {
151         /* to be implemented, see #297
152         code->guard_safepoint();
153         */
154 }
155
156 void factor_vm::start_sampling_profiler_timer()
157 {
158         struct itimerval timer;
159         memset((void*)&timer, 0, sizeof(struct itimerval));
160         timer.it_value.tv_usec = 1000000/samples_per_second;
161         timer.it_interval.tv_usec = 1000000/samples_per_second;
162         setitimer(ITIMER_REAL, &timer, NULL);
163 }
164
165 void factor_vm::end_sampling_profiler_timer()
166 {
167         struct itimerval timer;
168         memset((void*)&timer, 0, sizeof(struct itimerval));
169         setitimer(ITIMER_REAL, &timer, NULL);
170 }
171
172 void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
173 {
174         factor_vm *vm = current_vm();
175         vm->signal_fault_addr = (cell)siginfo->si_addr;
176         vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
177 }
178
179 void synchronous_signal_handler(int signal, siginfo_t *siginfo, void *uap)
180 {
181         factor_vm *vm = current_vm_p();
182         if (vm)
183         {
184                 vm->signal_number = signal;
185                 vm->dispatch_signal(uap,factor::synchronous_signal_handler_impl);
186         } else
187                 fatal_error("Foreign thread received signal", signal);
188 }
189
190 void enqueue_signal_handler(int signal, siginfo_t *siginfo, void *uap)
191 {
192         factor_vm *vm = current_vm_p();
193         if (vm)
194                 vm->enqueue_safepoint_signal(signal);
195         else
196                 fatal_error("Foreign thread received signal", signal);
197 }
198
199 void fep_signal_handler(int signal, siginfo_t *siginfo, void *uap)
200 {
201         factor_vm *vm = current_vm_p();
202         if (vm)
203                 vm->enqueue_safepoint_fep();
204         else
205                 fatal_error("Foreign thread received signal", signal);
206 }
207
208 void sample_signal_handler(int signal, siginfo_t *siginfo, void *uap)
209 {
210         factor_vm *vm = current_vm_p();
211         if (vm)
212                 vm->enqueue_safepoint_sample(1, (cell)UAP_PROGRAM_COUNTER(uap), false);
213         else if (thread_vms.size() == 1) {
214                 factor_vm *the_only_vm = thread_vms.begin()->second;
215                 the_only_vm->enqueue_safepoint_sample(1, (cell)UAP_PROGRAM_COUNTER(uap), true);
216         }
217 }
218
219 void ignore_signal_handler(int signal, siginfo_t *siginfo, void *uap)
220 {
221 }
222
223 void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
224 {
225         factor_vm *vm = current_vm();
226         vm->signal_number = signal;
227         vm->signal_fpu_status = fpu_status(uap_fpu_status(uap));
228         uap_clear_fpu_status(uap);
229
230         vm->dispatch_signal(uap,
231                 (siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
232                 ? factor::synchronous_signal_handler_impl
233                 : factor::fp_signal_handler_impl);
234 }
235
236 static void sigaction_safe(int signum, const struct sigaction *act, struct sigaction *oldact)
237 {
238         int ret;
239         do
240         {
241                 ret = sigaction(signum, act, oldact);
242         }
243         while(ret == -1 && errno == EINTR);
244
245         if(ret == -1)
246                 fatal_error("sigaction failed", 0);
247 }
248
249 static void init_sigaction_with_handler(struct sigaction *act,
250         void (*handler)(int, siginfo_t*, void*))
251 {
252         memset(act, 0, sizeof(struct sigaction));
253         sigemptyset(&act->sa_mask);
254         act->sa_sigaction = handler;
255         act->sa_flags = SA_SIGINFO | SA_ONSTACK;
256 }
257
258 void factor_vm::unix_init_signals()
259 {
260         signal_callstack_seg = new segment(callstack_size,false);
261
262         stack_t signal_callstack;
263         signal_callstack.ss_sp = (char *)signal_callstack_seg->start;
264         signal_callstack.ss_size = signal_callstack_seg->size;
265         signal_callstack.ss_flags = 0;
266
267         if(sigaltstack(&signal_callstack,(stack_t *)NULL) < 0)
268                 fatal_error("sigaltstack() failed",0);
269
270         struct sigaction memory_sigaction;
271         struct sigaction synchronous_sigaction;
272         struct sigaction enqueue_sigaction;
273         struct sigaction fep_sigaction;
274         struct sigaction sample_sigaction;
275         struct sigaction fpe_sigaction;
276         struct sigaction ignore_sigaction;
277
278         init_sigaction_with_handler(&memory_sigaction, memory_signal_handler);
279         sigaction_safe(SIGBUS,&memory_sigaction,NULL);
280         sigaction_safe(SIGSEGV,&memory_sigaction,NULL);
281         sigaction_safe(SIGTRAP,&memory_sigaction,NULL);
282
283         init_sigaction_with_handler(&fpe_sigaction, fpe_signal_handler);
284         sigaction_safe(SIGFPE,&fpe_sigaction,NULL);
285
286         init_sigaction_with_handler(&synchronous_sigaction, synchronous_signal_handler);
287         sigaction_safe(SIGILL,&synchronous_sigaction,NULL);
288         sigaction_safe(SIGABRT,&synchronous_sigaction,NULL);
289
290         init_sigaction_with_handler(&enqueue_sigaction, enqueue_signal_handler);
291         sigaction_safe(SIGUSR1,&enqueue_sigaction,NULL);
292         sigaction_safe(SIGUSR2,&enqueue_sigaction,NULL);
293         sigaction_safe(SIGWINCH,&enqueue_sigaction,NULL);
294 #ifdef SIGINFO
295         sigaction_safe(SIGINFO,&enqueue_sigaction,NULL);
296 #endif
297
298         init_sigaction_with_handler(&fep_sigaction, fep_signal_handler);
299         sigaction_safe(SIGQUIT,&fep_sigaction,NULL);
300         sigaction_safe(SIGINT,&fep_sigaction,NULL);
301
302         init_sigaction_with_handler(&sample_sigaction, sample_signal_handler);
303         sigaction_safe(SIGALRM,&sample_sigaction,NULL);
304
305         /* We don't use SA_IGN here because then the ignore action is inherited
306         by subprocesses, which we don't want. There is a unit test in
307         io.launcher.unix for this. */
308         init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
309         sigaction_safe(SIGPIPE,&ignore_sigaction,NULL);
310 }
311
312 /* On Unix, shared fds such as stdin cannot be set to non-blocking mode
313 (http://homepages.tesco.net/J.deBoynePollard/FGA/dont-set-shared-file-descriptors-to-non-blocking-mode.html)
314 so we kludge around this by spawning a thread, which waits on a control pipe
315 for a signal, upon receiving this signal it reads one block of data from stdin
316 and writes it to a data pipe. Upon completion, it writes a 4-byte integer to
317 the size pipe, indicating how much data was written to the data pipe.
318
319 The read end of the size pipe can be set to non-blocking. */
320 extern "C" {
321         int stdin_read;
322         int stdin_write;
323
324         int control_read;
325         int control_write;
326
327         int size_read;
328         int size_write;
329 }
330
331 void safe_close(int fd)
332 {
333         if(close(fd) < 0)
334                 fatal_error("error closing fd",errno);
335 }
336
337 bool check_write(int fd, void *data, ssize_t size)
338 {
339         if(write(fd,data,size) == size)
340                 return true;
341         else
342         {
343                 if(errno == EINTR)
344                         return check_write(fd,data,size);
345                 else
346                         return false;
347         }
348 }
349
350 void safe_write(int fd, void *data, ssize_t size)
351 {
352         if(!check_write(fd,data,size))
353                 fatal_error("error writing fd",errno);
354 }
355
356 bool safe_read(int fd, void *data, ssize_t size)
357 {
358         ssize_t bytes = read(fd,data,size);
359         if(bytes < 0)
360         {
361                 if(errno == EINTR)
362                         return safe_read(fd,data,size);
363                 else
364                 {
365                         fatal_error("error reading fd",errno);
366                         return false;
367                 }
368         }
369         else
370                 return (bytes == size);
371 }
372
373 void *stdin_loop(void *arg)
374 {
375         unsigned char buf[4096];
376         bool loop_running = true;
377
378         sigset_t mask;
379         sigfillset(&mask);
380         pthread_sigmask(SIG_BLOCK, &mask, NULL);
381
382         while(loop_running)
383         {
384                 if(!safe_read(control_read,buf,1))
385                         break;
386
387                 if(buf[0] != 'X')
388                         fatal_error("stdin_loop: bad data on control fd",buf[0]);
389
390                 for(;;)
391                 {
392                         ssize_t bytes = read(0,buf,sizeof(buf));
393                         if(bytes < 0)
394                         {
395                                 if(errno == EINTR)
396                                         continue;
397                                 else
398                                 {
399                                         loop_running = false;
400                                         break;
401                                 }
402                         }
403                         else if(bytes >= 0)
404                         {
405                                 safe_write(size_write,&bytes,sizeof(bytes));
406
407                                 if(!check_write(stdin_write,buf,bytes))
408                                         loop_running = false;
409                                 break;
410                         }
411                 }
412         }
413
414         safe_close(stdin_write);
415         safe_close(control_read);
416
417         return NULL;
418 }
419
420 void safe_pipe(int *in, int *out)
421 {
422         int filedes[2];
423
424         if(pipe(filedes) < 0)
425                 fatal_error("Error opening pipe",errno);
426
427         *in = filedes[0];
428         *out = filedes[1];
429
430         if(fcntl(*in,F_SETFD,FD_CLOEXEC) < 0)
431                 fatal_error("Error with fcntl",errno);
432
433         if(fcntl(*out,F_SETFD,FD_CLOEXEC) < 0)
434                 fatal_error("Error with fcntl",errno);
435 }
436
437 void open_console()
438 {
439         safe_pipe(&control_read,&control_write);
440         safe_pipe(&size_read,&size_write);
441         safe_pipe(&stdin_read,&stdin_write);
442         start_thread(stdin_loop,NULL);
443 }
444
445 }