Remove more disassembler bogosity
[sbcl.git] / src / runtime / darwin-os.c
blob8fdfab9c9b00f0c215dcb13f76b1c9ab3ad51d25
1 /*
2 * This is the Darwin incarnation of OS-dependent routines. See also
3 * "bsd-os.c".
4 */
6 /*
7 * This software is part of the SBCL system. See the README file for
8 * more information.
10 * This software is derived from the CMU CL system, which was
11 * written at Carnegie Mellon University and released into the
12 * public domain. The software is in the public domain and is
13 * provided with absolutely no warranty. See the COPYING and CREDITS
14 * files for more information.
17 #include "thread.h"
18 #include "sbcl.h"
19 #include "globals.h"
20 #include "runtime.h"
21 #include <signal.h>
22 #include <limits.h>
23 #include <mach-o/dyld.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <dlfcn.h>
27 #include <pthread.h>
29 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
30 #include <mach/mach.h>
31 #include <libkern/OSAtomic.h>
32 #include <stdlib.h>
33 #endif
35 #if defined(LISP_FEATURE_SB_WTIMER)
36 # include <sys/types.h>
37 # include <sys/event.h>
38 # include <sys/time.h>
39 #endif
41 char *
42 os_get_runtime_executable_path(int external)
44 char path[PATH_MAX + 1];
45 uint32_t size = sizeof(path);
47 if (_NSGetExecutablePath(path, &size) == -1)
48 return NULL;
50 return copied_string(path);
53 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
55 /* exc_server handles mach exception messages from the kernel and
56 * calls catch exception raise. We use the system-provided
57 * mach_msg_server, which, I assume, calls exc_server in a loop.
60 extern boolean_t exc_server();
62 void *
63 mach_exception_handler(void *port)
65 mach_msg_server(exc_server, 2048, (mach_port_t) port, 0);
66 /* mach_msg_server should never return, but it should dispatch mach
67 * exceptions to our catch_exception_raise function
69 lose("mach_msg_server returned");
72 /* Sets up the thread that will listen for mach exceptions. note that
73 the exception handlers will be run on this thread. This is
74 different from the BSD-style signal handling situation in which the
75 signal handlers run in the relevant thread directly. */
77 mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL;
79 pthread_t
80 setup_mach_exception_handling_thread()
82 kern_return_t ret;
83 pthread_t mach_exception_handling_thread = NULL;
84 pthread_attr_t attr;
86 /* allocate a mach_port for this process */
87 ret = mach_port_allocate(mach_task_self(),
88 MACH_PORT_RIGHT_PORT_SET,
89 &mach_exception_handler_port_set);
91 /* create the thread that will receive the mach exceptions */
93 FSHOW((stderr, "Creating mach_exception_handler thread!\n"));
95 pthread_attr_init(&attr);
96 pthread_create(&mach_exception_handling_thread,
97 &attr,
98 mach_exception_handler,
99 (void*)(long)mach_exception_handler_port_set);
100 pthread_attr_destroy(&attr);
102 return mach_exception_handling_thread;
105 /* tell the kernel that we want EXC_BAD_ACCESS exceptions sent to the
106 exception port (which is being listened to do by the mach
107 exception handling thread). */
108 kern_return_t
109 mach_lisp_thread_init(struct thread * thread)
111 kern_return_t ret;
112 mach_port_t current_mach_thread, thread_exception_port;
114 if (mach_port_allocate(mach_task_self(),
115 MACH_PORT_RIGHT_RECEIVE,
116 &thread_exception_port) != KERN_SUCCESS) {
117 lose("Cannot allocate thread_exception_port");
120 if (mach_port_set_context(mach_task_self(), thread_exception_port,
121 (mach_port_context_t)thread)
122 != KERN_SUCCESS) {
123 lose("Cannot set thread_exception_port context");
125 thread->mach_port_name = thread_exception_port;
127 /* establish the right for the thread_exception_port to send messages */
128 ret = mach_port_insert_right(mach_task_self(),
129 thread_exception_port,
130 thread_exception_port,
131 MACH_MSG_TYPE_MAKE_SEND);
132 if (ret) {
133 lose("mach_port_insert_right failed with return_code %d\n", ret);
136 current_mach_thread = mach_thread_self();
137 ret = thread_set_exception_ports(current_mach_thread,
138 EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION,
139 thread_exception_port,
140 EXCEPTION_DEFAULT,
141 THREAD_STATE_NONE);
142 if (ret) {
143 lose("thread_set_exception_ports failed with return_code %d\n", ret);
146 ret = mach_port_deallocate (mach_task_self(), current_mach_thread);
147 if (ret) {
148 lose("mach_port_deallocate failed with return_code %d\n", ret);
151 ret = mach_port_move_member(mach_task_self(),
152 thread_exception_port,
153 mach_exception_handler_port_set);
154 if (ret) {
155 lose("mach_port_move_member failed with return_code %d\n", ret);
158 return ret;
161 void
162 mach_lisp_thread_destroy(struct thread *thread) {
163 mach_port_t port = thread->mach_port_name;
164 FSHOW((stderr, "Deallocating mach port %x\n", port));
165 if (mach_port_move_member(mach_task_self(), port, MACH_PORT_NULL)
166 != KERN_SUCCESS) {
167 lose("Error destroying an exception port");
169 if (mach_port_deallocate(mach_task_self(), port) != KERN_SUCCESS) {
170 lose("Error destroying an exception port");
173 if (mach_port_destroy(mach_task_self(), port) != KERN_SUCCESS) {
174 lose("Error destroying an exception port");
178 void
179 setup_mach_exceptions() {
180 setup_mach_exception_handling_thread();
181 mach_lisp_thread_init(all_threads);
184 pid_t
185 mach_fork() {
186 pid_t pid = fork();
187 if (pid == 0) {
188 setup_mach_exceptions();
189 return pid;
190 } else {
191 return pid;
194 #endif
196 void darwin_init(void)
198 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
199 setup_mach_exception_handling_thread();
200 #endif
204 #ifdef LISP_FEATURE_SB_THREAD
206 inline void
207 os_sem_init(os_sem_t *sem, unsigned int value)
209 if (KERN_SUCCESS!=semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, (int)value))
210 lose("os_sem_init(%p): %s", sem, strerror(errno));
213 inline void
214 os_sem_wait(os_sem_t *sem, char *what)
216 kern_return_t ret;
217 restart:
218 FSHOW((stderr, "%s: os_sem_wait(%p)\n", what, sem));
219 ret = semaphore_wait(*sem);
220 FSHOW((stderr, "%s: os_sem_wait(%p) => %s\n", what, sem,
221 KERN_SUCCESS==ret ? "ok" : strerror(errno)));
222 switch (ret) {
223 case KERN_SUCCESS:
224 return;
225 /* It is unclear just when we can get this, but a sufficiently
226 * long wait seems to do that, at least sometimes.
228 * However, a wait that long is definitely abnormal for the
229 * GC, so we complain before retrying.
231 case KERN_OPERATION_TIMED_OUT:
232 fprintf(stderr, "%s: os_sem_wait(%p): %s", what, sem, strerror(errno));
233 /* This is analogous to POSIX EINTR. */
234 case KERN_ABORTED:
235 goto restart;
236 default:
237 lose("%s: os_sem_wait(%p): %lu, %s", what, sem, ret, strerror(errno));
241 void
242 os_sem_post(os_sem_t *sem, char *what)
244 if (KERN_SUCCESS!=semaphore_signal(*sem))
245 lose("%s: os_sem_post(%p): %s", what, sem, strerror(errno));
246 FSHOW((stderr, "%s: os_sem_post(%p) ok\n", what, sem));
249 void
250 os_sem_destroy(os_sem_t *sem)
252 if (-1==semaphore_destroy(mach_task_self(), *sem))
253 lose("os_sem_destroy(%p): %s", sem, strerror(errno));
256 #endif
258 #if defined(LISP_FEATURE_SB_WTIMER)
260 # error Completely untested. Go ahead! Remove this line, try your luck!
263 * Waitable timer implementation for the safepoint-based (SIGALRM-free)
264 * timer facility using kqueue.
266 * Unlike FreeBSD with its ms (!) timer resolution, Darwin supports ns
267 * timer resolution -- or at least it pretends to do so on the API
268 * level (?). To use it, we need the *64 versions of the functions and
269 * structures.
271 * Unfortunately, I don't run Darwin, and can't test this code, so it's
272 * just a hopeful translation from FreeBSD.
276 os_create_wtimer()
278 int kq = kqueue();
279 if (kq == -1)
280 lose("os_create_wtimer: kqueue");
281 return kq;
285 os_wait_for_wtimer(int kq)
287 struct kevent64_s ev;
288 int n;
289 if ( (n = kevent64(kq, 0, 0, &ev, 1, 0, 0)) == -1) {
290 if (errno != EINTR)
291 lose("os_wtimer_listen failed");
292 n = 0;
294 return n != 1;
297 void
298 os_close_wtimer(int kq)
300 if (close(kq) == -1)
301 lose("os_close_wtimer failed");
304 void
305 os_set_wtimer(int kq, int sec, int nsec)
307 int64_t nsec = ((int64_t) sec) * 1000000000 + (int64_t) nsec;
309 struct kevent64_s ev;
310 EV_SET64(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT, NOTE_NSECONDS,
311 nsec, 0, 0, 0);
312 if (kevent64(kq, &ev, 1, 0, 0, 0, 0) == -1)
313 perror("os_set_wtimer: kevent");
316 void
317 os_cancel_wtimer(int kq)
319 struct kevent64_s ev;
320 EV_SET64(&ev, 1, EVFILT_TIMER, EV_DISABLE, 0, 0, 0, 0, 0);
321 if (kevent64(kq, &ev, 1, 0, 0, 0, 0) == -1 && errno != ENOENT)
322 perror("os_cancel_wtimer: kevent");
324 #endif