* config.gcc: Remove --enable-altivec support.
[official-gcc.git] / boehm-gc / darwin_stop_world.c
blobbc2247fa4e72fbd3aba6314848a245ffc37cd886
1 #include "private/pthread_support.h"
3 # if defined(GC_DARWIN_THREADS)
5 #define DEBUG_THREADS 0
7 /* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
8 Page 49:
9 "The space beneath the stack pointer, where a new stack frame would normally
10 be allocated, is called the red zone. This area as shown in Figure 3-2 may
11 be used for any purpose as long as a new stack frame does not need to be
12 added to the stack."
14 Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
15 it must set up a stack frame just like routines that call other routines."
17 #define PPC_RED_ZONE_SIZE 224
19 void GC_push_all_stacks() {
20 int i;
21 kern_return_t r;
22 GC_thread p;
23 pthread_t me;
24 ptr_t lo, hi;
25 # if defined(POWERPC)
26 ppc_thread_state_t state;
27 # else
28 # error FIXME for non-ppc OS X
29 # endif
30 mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
32 me = pthread_self();
33 if (!GC_thr_initialized) GC_thr_init();
35 for(i=0;i<THREAD_TABLE_SZ;i++) {
36 for(p=GC_threads[i];p!=0;p=p->next) {
37 if(p -> flags & FINISHED) continue;
38 if(pthread_equal(p->id,me)) {
39 lo = GC_approx_sp();
40 } else {
41 /* Get the thread state (registers, etc) */
42 r = thread_get_state(
43 p->stop_info.mach_thread,
44 MACHINE_THREAD_STATE,
45 (natural_t*)&state,
46 &thread_state_count);
47 if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
49 #ifdef POWERPC
50 lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
52 GC_push_one(state.r0);
53 GC_push_one(state.r2);
54 GC_push_one(state.r3);
55 GC_push_one(state.r4);
56 GC_push_one(state.r5);
57 GC_push_one(state.r6);
58 GC_push_one(state.r7);
59 GC_push_one(state.r8);
60 GC_push_one(state.r9);
61 GC_push_one(state.r10);
62 GC_push_one(state.r11);
63 GC_push_one(state.r12);
64 GC_push_one(state.r13);
65 GC_push_one(state.r14);
66 GC_push_one(state.r15);
67 GC_push_one(state.r16);
68 GC_push_one(state.r17);
69 GC_push_one(state.r18);
70 GC_push_one(state.r19);
71 GC_push_one(state.r20);
72 GC_push_one(state.r21);
73 GC_push_one(state.r22);
74 GC_push_one(state.r23);
75 GC_push_one(state.r24);
76 GC_push_one(state.r25);
77 GC_push_one(state.r26);
78 GC_push_one(state.r27);
79 GC_push_one(state.r28);
80 GC_push_one(state.r29);
81 GC_push_one(state.r30);
82 GC_push_one(state.r31);
83 #else
84 # error FIXME for non-PPC darwin
85 #endif /* !POWERPC */
86 } /* p != me */
87 if(p->flags & MAIN_THREAD)
88 hi = GC_stackbottom;
89 else
90 hi = p->stack_end;
91 #if DEBUG_THREADS
92 GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
93 (unsigned long) p -> id,
94 (unsigned long) lo,
95 (unsigned long) hi
97 #endif
98 GC_push_all_stack(lo,hi);
99 } /* for(p=GC_threads[i]...) */
100 } /* for(i=0;i<THREAD_TABLE_SZ...) */
103 /* Caller holds allocation lock. */
104 void GC_stop_world()
106 int i;
107 GC_thread p;
108 pthread_t my_thread = pthread_self();
109 kern_return_t kern_result;
111 #if DEBUG_THREADS
112 GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
113 #endif
115 /* Make sure all free list construction has stopped before we start. */
116 /* No new construction can start, since free list construction is */
117 /* required to acquire and release the GC lock before it starts, */
118 /* and we have the lock. */
119 # ifdef PARALLEL_MARK
120 GC_acquire_mark_lock();
121 GC_ASSERT(GC_fl_builder_count == 0);
122 /* We should have previously waited for it to become zero. */
123 # endif /* PARALLEL_MARK */
125 for (i = 0; i < THREAD_TABLE_SZ; i++) {
126 for (p = GC_threads[i]; p != 0; p = p -> next) {
127 if (p -> id == my_thread) continue;
128 if (p -> flags & FINISHED) continue;
129 if (p -> thread_blocked) /* Will wait */ continue;
131 #if DEBUG_THREADS
132 GC_printf1("Suspending thread 0x%lx\n", p -> id);
133 #endif
135 /* Suspend the thread */
136 kern_result = thread_suspend(p->stop_info.mach_thread);
137 if(kern_result != KERN_SUCCESS) ABORT("thread_suspend failed");
139 /* This is only needed if we are modifying the threads
140 state. thread_abort_safely should also be used
141 if this code is ever added in again.
143 kern_result = thread_abort(p->stop_info.mach_thread);
144 if(kern_result != KERN_SUCCESS)
145 ABORT("thread_abort failed (%ul)",kern_result);
150 # ifdef MPROTECT_VDB
151 if(GC_incremental) {
152 extern void GC_mprotect_stop();
153 GC_mprotect_stop();
155 # endif
157 # ifdef PARALLEL_MARK
158 GC_release_mark_lock();
159 # endif
160 #if DEBUG_THREADS
161 GC_printf1("World stopped from 0x%lx\n", pthread_self());
162 #endif
165 /* Caller holds allocation lock, and has held it continuously since */
166 /* the world stopped. */
167 void GC_start_world()
169 pthread_t my_thread = pthread_self();
170 int i;
171 GC_thread p;
172 kern_return_t kern_result;
174 # if DEBUG_THREADS
175 GC_printf0("World starting\n");
176 # endif
178 # ifdef MPROTECT_VDB
179 if(GC_incremental) {
180 extern void GC_mprotect_resume();
181 GC_mprotect_resume();
183 # endif
185 for (i = 0; i < THREAD_TABLE_SZ; i++) {
186 for (p = GC_threads[i]; p != 0; p = p -> next) {
187 if (p -> id == my_thread) continue;
188 if (p -> flags & FINISHED) continue;
189 if (p -> thread_blocked) continue;
191 #if DEBUG_THREADS
192 GC_printf1("Resuming 0x%lx\n", p -> id);
193 #endif
195 /* Resume the thread */
196 kern_result = thread_resume(p->stop_info.mach_thread);
197 if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
200 #if DEBUG_THREADS
201 GC_printf0("World started\n");
202 #endif
205 void GC_stop_init() {
209 #endif