2 * This is the Darwin incarnation of OS-dependent routines. See also
7 * This software is part of the SBCL system. See the README file for
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.
23 #include <mach-o/dyld.h>
28 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
29 #include <mach/mach.h>
33 os_get_runtime_executable_path(int external)
35 char path[PATH_MAX + 1];
36 uint32_t size = sizeof(path);
38 if (_NSGetExecutablePath(path, &size) == -1)
41 return copied_string(path);
44 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
46 /* exc_server handles mach exception messages from the kernel and
47 * calls catch exception raise. We use the system-provided
48 * mach_msg_server, which, I assume, calls exc_server in a loop.
51 extern boolean_t exc_server();
54 mach_exception_handler(void *port)
56 mach_msg_server(exc_server, 2048, (mach_port_t) port, 0);
57 /* mach_msg_server should never return, but it should dispatch mach
58 * exceptions to our catch_exception_raise function
60 lose("mach_msg_server returned");
63 /* Sets up the thread that will listen for mach exceptions. note that
64 the exception handlers will be run on this thread. This is
65 different from the BSD-style signal handling situation in which the
66 signal handlers run in the relevant thread directly. */
68 mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL;
69 mach_port_t current_mach_task = MACH_PORT_NULL;
72 setup_mach_exception_handling_thread()
75 pthread_t mach_exception_handling_thread = NULL;
78 current_mach_task = mach_task_self();
80 /* allocate a mach_port for this process */
81 ret = mach_port_allocate(current_mach_task,
82 MACH_PORT_RIGHT_PORT_SET,
83 &mach_exception_handler_port_set);
85 /* create the thread that will receive the mach exceptions */
87 FSHOW((stderr, "Creating mach_exception_handler thread!\n"));
89 pthread_attr_init(&attr);
90 pthread_create(&mach_exception_handling_thread,
92 mach_exception_handler,
93 (void*) mach_exception_handler_port_set);
94 pthread_attr_destroy(&attr);
96 return mach_exception_handling_thread;
99 /* tell the kernel that we want EXC_BAD_ACCESS exceptions sent to the
100 exception port (which is being listened to do by the mach
101 exception handling thread). */
103 mach_thread_init(mach_port_t thread_exception_port)
106 mach_port_t current_mach_thread;
108 /* allocate a named port for the thread */
109 FSHOW((stderr, "Allocating mach port %x\n", thread_exception_port));
110 ret = mach_port_allocate_name(current_mach_task,
111 MACH_PORT_RIGHT_RECEIVE,
112 thread_exception_port);
114 lose("mach_port_allocate_name failed with return_code %d\n", ret);
117 /* establish the right for the thread_exception_port to send messages */
118 ret = mach_port_insert_right(current_mach_task,
119 thread_exception_port,
120 thread_exception_port,
121 MACH_MSG_TYPE_MAKE_SEND);
123 lose("mach_port_insert_right failed with return_code %d\n", ret);
126 current_mach_thread = mach_thread_self();
127 ret = thread_set_exception_ports(current_mach_thread,
128 EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION,
129 thread_exception_port,
133 lose("thread_set_exception_ports failed with return_code %d\n", ret);
136 ret = mach_port_deallocate (current_mach_task, current_mach_thread);
138 lose("mach_port_deallocate failed with return_code %d\n", ret);
141 ret = mach_port_move_member(current_mach_task,
142 thread_exception_port,
143 mach_exception_handler_port_set);
145 lose("mach_port_move_member failed with return_code %d\n", ret);
152 setup_mach_exceptions() {
153 setup_mach_exception_handling_thread();
154 mach_thread_init(THREAD_STRUCT_TO_EXCEPTION_PORT(all_threads));
161 setup_mach_exceptions();
169 void darwin_init(void)
171 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
172 setup_mach_exception_handling_thread();
177 #ifdef LISP_FEATURE_SB_THREAD
180 os_sem_init(os_sem_t *sem, unsigned int value)
182 if (KERN_SUCCESS!=semaphore_create(current_mach_task, sem, SYNC_POLICY_FIFO, (int)value))
183 lose("os_sem_init(%p): %s", sem, strerror(errno));
187 os_sem_wait(os_sem_t *sem, char *what)
191 FSHOW((stderr, "%s: os_sem_wait(%p)\n", what, sem));
192 ret = semaphore_wait(*sem);
193 FSHOW((stderr, "%s: os_sem_wait(%p) => %s\n", what, sem,
194 KERN_SUCCESS==ret ? "ok" : strerror(errno)));
198 /* It is unclear just when we can get this, but a sufficiently
199 * long wait seems to do that, at least sometimes.
201 * However, a wait that long is definitely abnormal for the
202 * GC, so we complain before retrying.
204 case KERN_OPERATION_TIMED_OUT:
205 fprintf(stderr, "%s: os_sem_wait(%p): %s", what, sem, strerror(errno));
206 /* This is analogous to POSIX EINTR. */
210 lose("%s: os_sem_wait(%p): %lu, %s", what, sem, ret, strerror(errno));
215 os_sem_post(os_sem_t *sem, char *what)
217 if (KERN_SUCCESS!=semaphore_signal(*sem))
218 lose("%s: os_sem_post(%p): %s", what, sem, strerror(errno));
219 FSHOW((stderr, "%s: os_sem_post(%p) ok\n", what, sem));
223 os_sem_destroy(os_sem_t *sem)
225 if (-1==semaphore_destroy(current_mach_task, *sem))
226 lose("os_sem_destroy(%p): %s", sem, strerror(errno));