<commit_before>#include "master.hpp"

namespace factor
{

THREADHANDLE start_thread(void *(*start_routine)(void *),void *args)
{
	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_JOINABLE) != 0)
		fatal_error("pthread_attr_setdetachstate() failed",0);
	if (pthread_create (&thread, &attr, start_routine, args) != 0)
		fatal_error("pthread_create() failed",0);
	pthread_attr_destroy(&attr);
	return thread;
}

pthread_key_t current_vm_tls_key = 0;

void init_platform_globals()
{
	if(pthread_key_create(&current_vm_tls_key, NULL) != 0)
		fatal_error("pthread_key_create() failed",0);
}

void register_vm_with_thread(factor_vm *vm)
{
	pthread_setspecific(current_vm_tls_key,vm);
}

factor_vm *current_vm()
{
	factor_vm *vm = (factor_vm*)pthread_getspecific(current_vm_tls_key);
	assert(vm != NULL);
	return vm;
}

static void *null_dll;

u64 system_micros()
{
	struct timeval t;
	gettimeofday(&t,NULL);
	return (u64)t.tv_sec * 1000000 + t.tv_usec;
}

void sleep_nanos(u64 nsec)
{
	timespec ts;
	timespec ts_rem;
	int ret;
	ts.tv_sec = nsec / 1000000000;
	ts.tv_nsec = nsec % 1000000000;
	ret = nanosleep(&ts,&ts_rem);
	while(ret == -1 && errno == EINTR)
	{
		memcpy(&ts, &ts_rem, sizeof(ts));
		ret = nanosleep(&ts, &ts_rem);
	}

	if(ret == -1)
		fatal_error("nanosleep failed", 0);
}

void factor_vm::init_ffi()
{
	/* NULL_DLL is "libfactor.dylib" for OS X and NULL for generic Unix */
	null_dll = dlopen(NULL_DLL,RTLD_LAZY);
}

void factor_vm::ffi_dlopen(dll *dll)
{
	dll->handle = dlopen(alien_offset(dll->path), RTLD_LAZY);
}

void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
{
	void *handle = (dll == NULL ? null_dll : dll->handle);
	return dlsym(handle,symbol);
}

void factor_vm::ffi_dlclose(dll *dll)
{
	if(dlclose(dll->handle))
		general_error(ERROR_FFI,false_object,false_object);
	dll->handle = NULL;
}

void factor_vm::primitive_existsp()
{
	struct stat sb;
	char *path = (char *)(untag_check<byte_array>(ctx->pop()) + 1);
	ctx->push(tag_boolean(stat(path,&sb) >= 0));
}

void factor_vm::move_file(const vm_char *path1, const vm_char *path2)
{
	int ret = 0;
	do {
		ret = rename((path1),(path2));
	} while(ret < 0 && errno == EINTR);
	if(ret < 0)
		general_error(ERROR_IO,tag_fixnum(errno),false_object);
}

segment::segment(cell size_, bool executable_p)
{
	size = size_;

	int pagesize = getpagesize();

	int prot;
	if(executable_p)
		prot = (PROT_READ | PROT_WRITE | PROT_EXEC);
	else
		prot = (PROT_READ | PROT_WRITE);

	char *array = (char *)mmap(NULL,pagesize + size + pagesize,prot,MAP_ANON | MAP_PRIVATE,-1,0);
	if(array == (char*)-1) out_of_memory();

	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);

	start = (cell)(array + pagesize);
	end = start + size;
}

segment::~segment()
{
	int pagesize = getpagesize();
	int retval = munmap((void*)(start - pagesize),pagesize + size + pagesize);
	if(retval)
		fatal_error("Segment deallocation failed",0);
}

void factor_vm::dispatch_signal(void *uap, void (handler)())
{
	UAP_STACK_POINTER(uap) = (UAP_STACK_POINTER_TYPE)fix_callstack_top((stack_frame *)UAP_STACK_POINTER(uap));
	UAP_PROGRAM_COUNTER(uap) = (cell)handler;

	signal_callstack_top = (stack_frame *)UAP_STACK_POINTER(uap);
}

void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
	factor_vm *vm = current_vm();
	vm->signal_fault_addr = (cell)siginfo->si_addr;
	vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
}

void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
	factor_vm *vm = current_vm();
	vm->signal_number = signal;
	vm->dispatch_signal(uap,factor::misc_signal_handler_impl);
}

void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
	factor_vm *vm = current_vm();
	vm->signal_number = signal;
	vm->signal_fpu_status = fpu_status(uap_fpu_status(uap));
	uap_clear_fpu_status(uap);

	vm->dispatch_signal(uap,
		(siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
		? factor::misc_signal_handler_impl
		: factor::fp_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);

	if(ret == -1)
		fatal_error("sigaction failed", 0);
}

void factor_vm::unix_init_signals()
{
	signal_callstack_seg = new segment(callstack_size,false);

	stack_t signal_callstack;
	signal_callstack.ss_sp = (void *)signal_callstack_seg->start;
	signal_callstack.ss_size = signal_callstack_seg->size;
	signal_callstack.ss_flags = 0;

	if(sigaltstack(&signal_callstack,(stack_t *)NULL) < 0)
		fatal_error("sigaltstack() failed",0);

	struct sigaction memory_sigaction;
	struct sigaction misc_sigaction;
	struct sigaction fpe_sigaction;<commit_msg>vm: fix compilation on FreeBSD<commit_after>#include "master.hpp"

namespace factor
{

THREADHANDLE start_thread(void *(*start_routine)(void *),void *args)
{
	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_JOINABLE) != 0)
		fatal_error("pthread_attr_setdetachstate() failed",0);
	if (pthread_create (&thread, &attr, start_routine, args) != 0)
		fatal_error("pthread_create() failed",0);
	pthread_attr_destroy(&attr);
	return thread;
}

pthread_key_t current_vm_tls_key = 0;

void init_platform_globals()
{
	if(pthread_key_create(&current_vm_tls_key, NULL) != 0)
		fatal_error("pthread_key_create() failed",0);
}

void register_vm_with_thread(factor_vm *vm)
{
	pthread_setspecific(current_vm_tls_key,vm);
}

factor_vm *current_vm()
{
	factor_vm *vm = (factor_vm*)pthread_getspecific(current_vm_tls_key);
	assert(vm != NULL);
	return vm;
}

static void *null_dll;

u64 system_micros()
{
	struct timeval t;
	gettimeofday(&t,NULL);
	return (u64)t.tv_sec * 1000000 + t.tv_usec;
}

void sleep_nanos(u64 nsec)
{
	timespec ts;
	timespec ts_rem;
	int ret;
	ts.tv_sec = nsec / 1000000000;
	ts.tv_nsec = nsec % 1000000000;
	ret = nanosleep(&ts,&ts_rem);
	while(ret == -1 && errno == EINTR)
	{
		memcpy(&ts, &ts_rem, sizeof(ts));
		ret = nanosleep(&ts, &ts_rem);
	}

	if(ret == -1)
		fatal_error("nanosleep failed", 0);
}

void factor_vm::init_ffi()
{
	/* NULL_DLL is "libfactor.dylib" for OS X and NULL for generic Unix */
	null_dll = dlopen(NULL_DLL,RTLD_LAZY);
}

void factor_vm::ffi_dlopen(dll *dll)
{
	dll->handle = dlopen(alien_offset(dll->path), RTLD_LAZY);
}

void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
{
	void *handle = (dll == NULL ? null_dll : dll->handle);
	return dlsym(handle,symbol);
}

void factor_vm::ffi_dlclose(dll *dll)
{
	if(dlclose(dll->handle))
		general_error(ERROR_FFI,false_object,false_object);
	dll->handle = NULL;
}

void factor_vm::primitive_existsp()
{
	struct stat sb;
	char *path = (char *)(untag_check<byte_array>(ctx->pop()) + 1);
	ctx->push(tag_boolean(stat(path,&sb) >= 0));
}

void factor_vm::move_file(const vm_char *path1, const vm_char *path2)
{
	int ret = 0;
	do
	{
		ret = rename((path1),(path2));
	}
	while(ret < 0 && errno == EINTR);

	if(ret < 0)
		general_error(ERROR_IO,tag_fixnum(errno),false_object);
}

segment::segment(cell size_, bool executable_p)
{
	size = size_;

	int pagesize = getpagesize();

	int prot;
	if(executable_p)
		prot = (PROT_READ | PROT_WRITE | PROT_EXEC);
	else
		prot = (PROT_READ | PROT_WRITE);

	char *array = (char *)mmap(NULL,pagesize + size + pagesize,prot,MAP_ANON | MAP_PRIVATE,-1,0);
	if(array == (char*)-1) out_of_memory();

	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);

	start = (cell)(array + pagesize);
	end = start + size;
}

segment::~segment()
{
	int pagesize = getpagesize();
	int retval = munmap((void*)(start - pagesize),pagesize + size + pagesize);
	if(retval)
		fatal_error("Segment deallocation failed",0);
}

void factor_vm::dispatch_signal(void *uap, void (handler)())
{
	UAP_STACK_POINTER(uap) = (UAP_STACK_POINTER_TYPE)fix_callstack_top((stack_frame *)UAP_STACK_POINTER(uap));
	UAP_PROGRAM_COUNTER(uap) = (cell)handler;

	signal_callstack_top = (stack_frame *)UAP_STACK_POINTER(uap);
}

void memory_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
	factor_vm *vm = current_vm();
	vm->signal_fault_addr = (cell)siginfo->si_addr;
	vm->dispatch_signal(uap,factor::memory_signal_handler_impl);
}

void misc_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
	factor_vm *vm = current_vm();
	vm->signal_number = signal;
	vm->dispatch_signal(uap,factor::misc_signal_handler_impl);
}

void fpe_signal_handler(int signal, siginfo_t *siginfo, void *uap)
{
	factor_vm *vm = current_vm();
	vm->signal_number = signal;
	vm->signal_fpu_status = fpu_status(uap_fpu_status(uap));
	uap_clear_fpu_status(uap);

	vm->dispatch_signal(uap,
		(siginfo->si_code == FPE_INTDIV || siginfo->si_code == FPE_INTOVF)
		? factor::misc_signal_handler_impl
		: factor::fp_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);

	if(ret == -1)
		fatal_error("sigaction failed", 0);
}

void factor_vm::unix_init_signals()
{
	signal_callstack_seg = new segment(callstack_size,false);

	stack_t signal_callstack;
	signal_callstack.ss_sp = (char *)signal_callstack_seg->start;
	signal_callstack.ss_size = signal_callstack_seg->size;
	signal_callstack.ss_flags = 0;

	if(sigaltstack(&signal_callstack,(stack_t *)NULL) < 0)
		fatal_error("sigaltstack() failed",0);

	struct sigaction memory_sigaction;
	struct sigaction misc_sigaction;
	struct sigaction fpe_sigaction;
{'fraction_non_alphanumeric': 0.1454310173203265, 'fraction_numerical': 0.01313955803304798, 'mean_word_length': 6.2073170731707314, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2043645', 'n_tokens_mistral': 4217, 'n_tokens_neox': 3961, 'n_words': 725}