]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/os-unix.cpp
io.streams.256color: faster by caching styles
[factor.git] / vm / os-unix.cpp
index 8754ed23eacd18fe6c8d7cdda411c1f478ed4a1b..adf235880032d1edae34a3eb0fb910a7e8a16852 100644 (file)
@@ -74,11 +74,6 @@ bool move_file(const vm_char* path1, const vm_char* path2) {
   return ret == 0;
 }
 
-void check_ENOMEM(const char* msg) {
-  if(errno == ENOMEM)
-    out_of_memory(msg);
-}
-
 segment::segment(cell size_, bool executable_p) {
   size = size_;
 
@@ -90,11 +85,17 @@ segment::segment(cell size_, bool executable_p) {
   else
     prot = PROT_READ | PROT_WRITE;
 
-  char* array = (char*)mmap(NULL, 2 * pagesize + size, prot,
+  cell alloc_size = 2 * pagesize + size;
+#if defined(__APPLE__) && defined(FACTOR_ARM64)  // FIXME: could be in header file
+  char* array = (char*)mmap(NULL, alloc_size, prot,
+                            MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
+#else
+  char* array = (char*)mmap(NULL, alloc_size, prot,
                             MAP_ANON | MAP_PRIVATE, -1, 0);
+#endif
 
   if (array == (char*)-1)
-    out_of_memory("mmap");
+    fatal_error("Out of memory in mmap", alloc_size);
 
   start = (cell)(array + pagesize);
   end = start + size;
@@ -102,35 +103,13 @@ segment::segment(cell size_, bool executable_p) {
   set_border_locked(true);
 }
 
-void segment::set_border_locked(bool locked) {
-  int pagesize = getpagesize();
-  cell lo = start - pagesize;
-  if (!set_memory_locked(lo, pagesize, locked)) {
-    check_ENOMEM("mprotect low");
-    fatal_error("Cannot (un)protect low guard page", lo);
-  }
-
-  cell hi = end;
-  if (!set_memory_locked(hi, pagesize, locked)) {
-    check_ENOMEM("mprotect high");
-    fatal_error("Cannot (un)protect high guard page", hi);
-  }
-}
-
 segment::~segment() {
   int pagesize = getpagesize();
-  int retval = munmap((void*)(start - pagesize), pagesize + size + pagesize);
+  int retval = munmap((void*)(start - pagesize), 2 * pagesize + size);
   if (retval)
     fatal_error("Segment deallocation failed", 0);
 }
 
-void factor_vm::dispatch_signal(void* uap, void(handler)()) {
-  dispatch_signal_handler((cell*)&UAP_STACK_POINTER(uap),
-                          (cell*)&UAP_PROGRAM_COUNTER(uap),
-                          (cell)FUNCTION_CODE_POINTER(handler));
-  UAP_SET_TOC_POINTER(uap, (cell)FUNCTION_TOC_POINTER(handler));
-}
-
 void factor_vm::start_sampling_profiler_timer() {
   struct itimerval timer;
   memset((void*)&timer, 0, sizeof(struct itimerval));
@@ -145,27 +124,31 @@ void factor_vm::end_sampling_profiler_timer() {
   setitimer(ITIMER_REAL, &timer, NULL);
 }
 
-void memory_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+void factor_vm::dispatch_signal(void* uap, void(handler)()) {
+  dispatch_signal_handler((cell*)&UAP_STACK_POINTER(uap),
+                          (cell*)&UAP_PROGRAM_COUNTER(uap),
+                          (cell)FUNCTION_CODE_POINTER(handler));
+}
 
+void memory_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+  (void) signal;
   cell fault_addr = (cell)siginfo->si_addr;
   cell fault_pc = (cell)UAP_PROGRAM_COUNTER(uap);
   factor_vm* vm = current_vm();
-  vm->verify_memory_protection_error(fault_addr);
-  vm->signal_fault_addr = fault_addr;
-  vm->signal_fault_pc = fault_pc;
+  vm->set_memory_protection_error(fault_addr, fault_pc);
   vm->dispatch_signal(uap, factor::memory_signal_handler_impl);
 }
 
 void synchronous_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+  (void) siginfo;
   if (factor_vm::fatal_erroring_p)
     return;
 
   factor_vm* vm = current_vm_p();
-  if (vm) {
-    vm->signal_number = signal;
-    vm->dispatch_signal(uap, factor::synchronous_signal_handler_impl);
-  } else
+  if (!vm)
     fatal_error("Foreign thread received signal", signal);
+  vm->signal_number = signal;
+  vm->dispatch_signal(uap, factor::synchronous_signal_handler_impl);
 }
 
 void safe_write_nonblock(int fd, void* data, ssize_t size);
@@ -176,6 +159,8 @@ static void enqueue_signal(factor_vm* vm, int signal) {
 }
 
 void enqueue_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+  (void) siginfo;
+  (void) uap;
   if (factor_vm::fatal_erroring_p)
     return;
 
@@ -185,18 +170,21 @@ void enqueue_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
 }
 
 void fep_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+  (void) siginfo;
+  (void) uap;
   if (factor_vm::fatal_erroring_p)
     return;
 
   factor_vm* vm = current_vm_p();
   if (vm) {
-    vm->safepoint.enqueue_fep(vm);
+    vm->enqueue_fep();
     enqueue_signal(vm, signal);
   } else
     fatal_error("Foreign thread received signal", signal);
 }
 
 void sample_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+  (void) siginfo;
   factor_vm* vm = current_vm_p();
   bool foreign_thread = false;
   if (vm == NULL) {
@@ -204,13 +192,16 @@ void sample_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
     vm = thread_vms.begin()->second;
   }
   if (atomic::load(&vm->sampling_profiler_p))
-    vm->safepoint.enqueue_samples(vm, 1, (cell)UAP_PROGRAM_COUNTER(uap),
-                                  foreign_thread);
+    vm->enqueue_samples(1, (cell)UAP_PROGRAM_COUNTER(uap), foreign_thread);
   else if (!foreign_thread)
     enqueue_signal(vm, signal);
 }
 
-void ignore_signal_handler(int signal, siginfo_t* siginfo, void* uap) {}
+void ignore_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
+  (void) signal;
+  (void) siginfo;
+  (void) uap;
+}
 
 void fpe_signal_handler(int signal, siginfo_t* siginfo, void* uap) {
   factor_vm* vm = current_vm();
@@ -327,27 +318,27 @@ void factor_vm::unix_init_signals() {
     sigaction_safe(SIGALRM, &sample_sigaction, NULL);
   }
 
-  /* We don't use SA_IGN here because then the ignore action is inherited
-     by subprocesses, which we don't want. There is a unit test in
-     io.launcher.unix for this. */
+  // We don't use SA_IGN here because then the ignore action is inherited
+  // by subprocesses, which we don't want. There is a unit test in
+  // io.launcher.unix for this.
   {
     struct sigaction ignore_sigaction;
     init_sigaction_with_handler(&ignore_sigaction, ignore_signal_handler);
     sigaction_safe(SIGPIPE, &ignore_sigaction, NULL);
-    /* We send SIGUSR2 to the stdin_loop thread to interrupt it on FEP */
+    // We send SIGUSR2 to the stdin_loop thread to interrupt it on FEP
     sigaction_safe(SIGUSR2, &ignore_sigaction, NULL);
   }
 }
 
-/* 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.
+// 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. */
+// The read end of the size pipe can be set to non-blocking.
 extern "C" {
 int stdin_read;
 int stdin_write;
@@ -400,6 +391,7 @@ bool safe_read(int fd, void* data, ssize_t size) {
 }
 
 void* stdin_loop(void* arg) {
+  (void) arg;
   unsigned char buf[4096];
   bool loop_running = true;
 
@@ -423,8 +415,8 @@ void* stdin_loop(void* arg) {
       fatal_error("stdin_loop: bad data on control fd", buf[0]);
 
     for (;;) {
-      /* If we fep, the parent thread will grab stdin_mutex and send us
-         SIGUSR2 to interrupt the read() call. */
+      // If we fep, the parent thread will grab stdin_mutex and send us
+      // SIGUSR2 to interrupt the read() call.
       pthread_mutex_lock(&stdin_mutex);
       pthread_mutex_unlock(&stdin_mutex);
       ssize_t bytes = read(0, buf, sizeof(buf));
@@ -461,9 +453,9 @@ void open_console() {
   pthread_mutex_init(&stdin_mutex, NULL);
 }
 
-/* This method is used to kill the stdin_loop before exiting from factor.
-   A Nvidia driver bug on Linux is the reason this has to be done, see:
-     http://www.nvnews.net/vbulletin/showthread.php?t=164619 */
+// This method is used to kill the stdin_loop before exiting from factor.
+// An Nvidia driver bug on Linux is the reason this has to be done, see:
+//   http://www.nvnews.net/vbulletin/showthread.php?t=164619
 void close_console() {
   if (stdin_thread_initialized_p) {
     pthread_cancel(stdin_thread);
@@ -473,9 +465,9 @@ void close_console() {
 
 void lock_console() {
   FACTOR_ASSERT(stdin_thread_initialized_p);
-  /* Lock the stdin_mutex and send the stdin_loop thread a signal to interrupt
-     any read() it has in progress. When the stdin loop iterates again, it will
-     try to lock the same mutex and wait until unlock_console() is called. */
+  // Lock the stdin_mutex and send the stdin_loop thread a signal to interrupt
+  // any read() it has in progress. When the stdin loop iterates again, it will
+  // try to lock the same mutex and wait until unlock_console() is called.
   pthread_mutex_lock(&stdin_mutex);
   pthread_kill(stdin_thread, SIGUSR2);
 }
@@ -498,6 +490,14 @@ void handle_ctrl_c() {
   sigaction_safe(SIGINT, &fep_sigaction, NULL);
 }
 
+void factor_vm::primitive_disable_ctrl_break() {
+  stop_on_ctrl_break = false;
+}
+
+void factor_vm::primitive_enable_ctrl_break() {
+  stop_on_ctrl_break = true;
+}
+
 void abort() {
   sig_t ret;
   do {