| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | #include "master.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | void start_thread(void *(*start_routine)(void *)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pthread_attr_t attr; | 
					
						
							|  |  |  | 	pthread_t thread; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pthread_attr_init (&attr) != 0) | 
					
						
							|  |  |  | 		fatal_error("pthread_attr_init() failed",0); | 
					
						
							|  |  |  | 	if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) != 0) | 
					
						
							|  |  |  | 		fatal_error("pthread_attr_setdetachstate() failed",0); | 
					
						
							|  |  |  | 	if (pthread_create (&thread, &attr, start_routine, NULL) != 0) | 
					
						
							|  |  |  | 		fatal_error("pthread_create() failed",0); | 
					
						
							|  |  |  | 	pthread_attr_destroy (&attr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | static void *null_dll; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 02:50:05 -05:00
										 |  |  | s64 current_micros(void) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct timeval t; | 
					
						
							|  |  |  | 	gettimeofday(&t,NULL); | 
					
						
							| 
									
										
										
										
											2008-11-19 02:50:05 -05:00
										 |  |  | 	return (s64)t.tv_sec * 1000000 + t.tv_usec; | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-19 02:50:05 -05:00
										 |  |  | void sleep_micros(CELL usec) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-11-19 02:50:05 -05:00
										 |  |  | 	usleep(usec); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void init_ffi(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* NULL_DLL is "libfactor.dylib" for OS X and NULL for generic unix */ | 
					
						
							|  |  |  | 	null_dll = dlopen(NULL_DLL,RTLD_LAZY); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-16 01:54:54 -05:00
										 |  |  | void ffi_dlopen(F_DLL *dll) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-10 20:58:53 -05:00
										 |  |  | 	dll->dll = dlopen(alien_offset(dll->path), RTLD_LAZY); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *ffi_dlsym(F_DLL *dll, F_SYMBOL *symbol) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *handle = (dll == NULL ? null_dll : dll->dll); | 
					
						
							|  |  |  | 	return dlsym(handle,symbol); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ffi_dlclose(F_DLL *dll) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(dlclose(dll->dll)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		general_error(ERROR_FFI,tag_object( | 
					
						
							|  |  |  | 			from_char_string(dlerror())),F,NULL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dll->dll = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-13 04:20:34 -05:00
										 |  |  | void primitive_existsp(void) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct stat sb; | 
					
						
							| 
									
										
										
										
											2008-03-20 01:39:32 -04:00
										 |  |  | 	box_boolean(stat(unbox_char_string(),&sb) >= 0); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | F_SEGMENT *alloc_segment(CELL size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int pagesize = getpagesize(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	char *array = mmap(NULL,pagesize + size + pagesize, | 
					
						
							|  |  |  | 		PROT_READ | PROT_WRITE | PROT_EXEC, | 
					
						
							|  |  |  | 		MAP_ANON | MAP_PRIVATE,-1,0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(array == (char*)-1) | 
					
						
							| 
									
										
										
										
											2008-07-25 23:05:36 -04:00
										 |  |  | 		out_of_memory(); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(mprotect(array,pagesize,PROT_NONE) == -1) | 
					
						
							|  |  |  | 		fatal_error("Cannot protect low guard page",(CELL)array); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(mprotect(array + pagesize + size,pagesize,PROT_NONE) == -1) | 
					
						
							|  |  |  | 		fatal_error("Cannot protect high guard page",(CELL)array); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	F_SEGMENT *retval = safe_malloc(sizeof(F_SEGMENT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	retval->start = (CELL)(array + pagesize); | 
					
						
							|  |  |  | 	retval->size = size; | 
					
						
							|  |  |  | 	retval->end = retval->start + size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return retval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dealloc_segment(F_SEGMENT *block) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int pagesize = getpagesize(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int retval = munmap((void*)(block->start - pagesize), | 
					
						
							|  |  |  | 		pagesize + block->size + pagesize); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if(retval) | 
					
						
							|  |  |  | 		fatal_error("dealloc_segment failed",0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(block); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  | INLINE F_STACK_FRAME *uap_stack_pointer(void *uap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* There is a race condition here, but in practice a signal
 | 
					
						
							|  |  |  | 	delivered during stack frame setup/teardown or while transitioning | 
					
						
							|  |  |  | 	from Factor to C is a sign of things seriously gone wrong, not just | 
					
						
							|  |  |  | 	a divide by zero or stack underflow in the listener */ | 
					
						
							|  |  |  | 	if(in_code_heap_p(UAP_PROGRAM_COUNTER(uap))) | 
					
						
							| 
									
										
										
										
											2008-01-16 01:16:53 -05:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		F_STACK_FRAME *ptr = ucontext_stack_pointer(uap); | 
					
						
							|  |  |  | 		if(!ptr) | 
					
						
							|  |  |  | 			critical_error("Invalid uap",(CELL)uap); | 
					
						
							|  |  |  | 		return ptr; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	signal_fault_addr = (CELL)siginfo->si_addr; | 
					
						
							|  |  |  | 	signal_callstack_top = uap_stack_pointer(uap); | 
					
						
							|  |  |  | 	UAP_PROGRAM_COUNTER(uap) = (CELL)memory_signal_handler_impl; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	signal_number = signal; | 
					
						
							|  |  |  | 	signal_callstack_top = uap_stack_pointer(uap); | 
					
						
							|  |  |  | 	UAP_PROGRAM_COUNTER(uap) = (CELL)misc_signal_handler_impl; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sigaction_safe(int signum, const struct sigaction *act, struct sigaction *oldact) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	do | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ret = sigaction(signum, act, oldact); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	while(ret == -1 && errno == EINTR); | 
					
						
							| 
									
										
										
										
											2007-12-04 16:47:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(ret == -1) | 
					
						
							|  |  |  | 		fatal_error("sigaction failed", 0); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void unix_init_signals(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sigaction memory_sigaction; | 
					
						
							|  |  |  | 	struct sigaction misc_sigaction; | 
					
						
							|  |  |  | 	struct sigaction ignore_sigaction; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&memory_sigaction,0,sizeof(struct sigaction)); | 
					
						
							|  |  |  | 	sigemptyset(&memory_sigaction.sa_mask); | 
					
						
							|  |  |  | 	memory_sigaction.sa_sigaction = memory_signal_handler; | 
					
						
							|  |  |  | 	memory_sigaction.sa_flags = SA_SIGINFO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sigaction_safe(SIGBUS,&memory_sigaction,NULL); | 
					
						
							|  |  |  | 	sigaction_safe(SIGSEGV,&memory_sigaction,NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&misc_sigaction,0,sizeof(struct sigaction)); | 
					
						
							|  |  |  | 	sigemptyset(&misc_sigaction.sa_mask); | 
					
						
							|  |  |  | 	misc_sigaction.sa_sigaction = misc_signal_handler; | 
					
						
							|  |  |  | 	misc_sigaction.sa_flags = SA_SIGINFO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sigaction_safe(SIGABRT,&misc_sigaction,NULL); | 
					
						
							|  |  |  | 	sigaction_safe(SIGFPE,&misc_sigaction,NULL); | 
					
						
							|  |  |  | 	sigaction_safe(SIGQUIT,&misc_sigaction,NULL); | 
					
						
							|  |  |  | 	sigaction_safe(SIGILL,&misc_sigaction,NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&ignore_sigaction,0,sizeof(struct sigaction)); | 
					
						
							|  |  |  | 	sigemptyset(&ignore_sigaction.sa_mask); | 
					
						
							|  |  |  | 	ignore_sigaction.sa_handler = SIG_IGN; | 
					
						
							|  |  |  | 	sigaction_safe(SIGPIPE,&ignore_sigaction,NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | /* On Unix, shared fds such as stdin cannot be set to non-blocking mode
 | 
					
						
							|  |  |  | (http://homepages.tesco.net/J.deBoynePollard/FGA/dont-set-shared-file-descriptors-to-non-blocking-mode.html)
 | 
					
						
							|  |  |  | so we kludge around this by spawning a thread, which waits on a control pipe | 
					
						
							|  |  |  | for a signal, upon receiving this signal it reads one block of data from stdin | 
					
						
							|  |  |  | and writes it to a data pipe. Upon completion, it writes a 4-byte integer to | 
					
						
							|  |  |  | the size pipe, indicating how much data was written to the data pipe. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The read end of the size pipe can be set to non-blocking. */ | 
					
						
							|  |  |  | __attribute__((visibility("default"))) int stdin_read; | 
					
						
							|  |  |  | __attribute__((visibility("default"))) int stdin_write; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __attribute__((visibility("default"))) int control_read; | 
					
						
							|  |  |  | __attribute__((visibility("default"))) int control_write; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __attribute__((visibility("default"))) int size_read; | 
					
						
							|  |  |  | __attribute__((visibility("default"))) int size_write; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void safe_close(int fd) | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | 	if(close(fd) < 0) | 
					
						
							|  |  |  | 		fatal_error("error closing fd",errno); | 
					
						
							| 
									
										
										
										
											2007-09-20 18:09:08 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-11-21 15:27:25 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | bool check_write(int fd, void *data, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(write(fd,data,size) == size) | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(errno == EINTR) | 
					
						
							|  |  |  | 			return check_write(fd,data,size); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void safe_write(int fd, void *data, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(!check_write(fd,data,size)) | 
					
						
							|  |  |  | 		fatal_error("error writing fd",errno); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | bool safe_read(int fd, void *data, size_t size) | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-06 19:28:41 -04:00
										 |  |  | 	ssize_t bytes = read(fd,data,size); | 
					
						
							|  |  |  | 	if(bytes < 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(errno == EINTR) | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 			return safe_read(fd,data,size); | 
					
						
							| 
									
										
										
										
											2008-07-06 19:28:41 -04:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2008-07-06 19:28:41 -04:00
										 |  |  | 			fatal_error("error reading fd",errno); | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-06 19:28:41 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		return (bytes == size); | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *stdin_loop(void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char buf[4096]; | 
					
						
							|  |  |  | 	bool loop_running = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(loop_running) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 		if(!safe_read(control_read,buf,1)) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | 		if(buf[0] != 'X') | 
					
						
							|  |  |  | 			fatal_error("stdin_loop: bad data on control fd",buf[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for(;;) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2008-07-06 05:12:46 -04:00
										 |  |  | 			ssize_t bytes = read(0,buf,sizeof(buf)); | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | 			if(bytes < 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if(errno == EINTR) | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					loop_running = false; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if(bytes >= 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				safe_write(size_write,&bytes,sizeof(bytes)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 				if(!check_write(stdin_write,buf,bytes)) | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | 					loop_running = false; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	safe_close(stdin_write); | 
					
						
							| 
									
										
										
										
											2008-12-20 19:02:08 -05:00
										 |  |  | 	safe_close(control_read); | 
					
						
							| 
									
										
										
										
											2008-07-03 18:44:44 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void open_console(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int filedes[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(pipe(filedes) < 0) | 
					
						
							|  |  |  | 		fatal_error("Error opening control pipe",errno); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	control_read = filedes[0]; | 
					
						
							|  |  |  | 	control_write = filedes[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(pipe(filedes) < 0) | 
					
						
							|  |  |  | 		fatal_error("Error opening size pipe",errno); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size_read = filedes[0]; | 
					
						
							|  |  |  | 	size_write = filedes[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(pipe(filedes) < 0) | 
					
						
							|  |  |  | 		fatal_error("Error opening stdin pipe",errno); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stdin_read = filedes[0]; | 
					
						
							|  |  |  | 	stdin_write = filedes[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	start_thread(stdin_loop); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DLLEXPORT void wait_for_stdin(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(write(control_write,"X",1) != 1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(errno == EINTR) | 
					
						
							|  |  |  | 			wait_for_stdin(); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			fatal_error("Error writing control fd",errno); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |