+
+int
+futex_wake(int *lock_word, int n)
+{
+ return umtx_wake((void *)lock_word, n);
+}
+#endif
+#endif /* __FreeBSD__ */
+
+#ifdef LISP_FEATURE_DARWIN
+/* defined in ppc-darwin-os.c instead */
+#elif defined(LISP_FEATURE_FREEBSD)
+#ifndef KERN_PROC_PATHNAME
+#define KERN_PROC_PATHNAME 12
+#endif
+
+char *
+os_get_runtime_executable_path(int external)
+{
+ char path[PATH_MAX + 1];
+
+ if (getosreldate() >= 600024) {
+ /* KERN_PROC_PATHNAME is available */
+ size_t len = PATH_MAX + 1;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ if (sysctl(mib, 4, &path, &len, NULL, 0) != 0)
+ return NULL;
+ } else {
+ int size;
+ size = readlink("/proc/curproc/file", path, sizeof(path) - 1);
+ if (size < 0)
+ return NULL;
+ path[size] = '\0';
+ }
+ if (strcmp(path, "unknown") == 0)
+ return NULL;
+ return copied_string(path);
+}
+#elif defined(LISP_FEATURE_NETBSD) || defined(LISP_FEATURE_OPENBSD)
+char *
+os_get_runtime_executable_path(int external)
+{
+ struct stat sb;
+ if (!external && stat("/proc/curproc/file", &sb) == 0)
+ return copied_string("/proc/curproc/file");
+ return NULL;
+}
+#else /* Not DARWIN or FREEBSD or NETBSD or OPENBSD */
+char *
+os_get_runtime_executable_path(int external)
+{
+ return NULL;
+}
+#endif
+
+#ifdef __OpenBSD__
+
+int openbsd_use_fxsave = 0;
+
+void
+openbsd_init()
+{
+#ifdef LISP_FEATURE_X86
+ int mib[2];
+ size_t size;
+#endif
+ /*
+ * Show a warning if it looks like the memory available after
+ * allocating the spaces won't be at least this much.
+ */
+#ifdef LISP_FEATURE_X86_64
+ const int wantfree = 64 * 1024 * 1024;
+#else
+ const int wantfree = 32 * 1024 * 1024;
+#endif
+ struct rlimit rl;
+
+#ifdef LISP_FEATURE_X86
+ /* Save the machdep.osfxsr sysctl for use by os_restore_fp_control() */
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_OSFXSR;
+ size = sizeof (openbsd_use_fxsave);
+ sysctl(mib, 2, &openbsd_use_fxsave, &size, NULL, 0);
+#endif
+
+ /* OpenBSD, like NetBSD, counts mmap()ed space against the
+ * process's data size limit. If the soft limit is lower than the
+ * hard limit then try to yank it up, this lets users in the
+ * "staff" or "daemon" login classes run sbcl with larger dynamic
+ * space sizes.
+ */
+ getrlimit (RLIMIT_DATA, &rl);
+ if (rl.rlim_cur < rl.rlim_max) {
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit (RLIMIT_DATA, &rl) < 0) {
+ fprintf (stderr,
+ "RUNTIME WARNING: unable to raise process data size limit:\n\
+ %s.\n\
+The system may fail to start.\n",
+ strerror(errno));
+ }
+ }
+
+ /*
+ * Display a (hopefully) helpful warning if it looks like we won't
+ * be able to allocate enough memory.
+ */
+ getrlimit (RLIMIT_DATA, &rl);
+ if (dynamic_space_size + READ_ONLY_SPACE_SIZE + STATIC_SPACE_SIZE +
+ LINKAGE_TABLE_SPACE_SIZE + wantfree > rl.rlim_cur)
+ fprintf (stderr,
+ "RUNTIME WARNING: data size resource limit may be too low,\n"
+ " try decreasing the dynamic space size with --dynamic-space-size\n"
+ " or raising the datasize or datasize-max limits in /etc/login.conf\n");
+}
+
+/* OpenBSD's dlsym() relies on the gcc bulitin
+ * __builtin_return_address(0) returning an address in the
+ * executable's text segment, but when called from lisp it will return
+ * an address in the dynamic space. Work around this by calling this
+ * wrapper function instead. Note that tail-call optimization will
+ * defeat this, disable it by saving the dlsym() return value in a
+ * volatile variable.
+*/
+void *
+os_dlsym(void *handle, const char *symbol)
+{
+ void * volatile ret = dlsym(handle, symbol);
+ return ret;
+}
+