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
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
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() {
26 ppc_thread_state_t state
;
28 # error FIXME for non-ppc OS X
30 mach_msg_type_number_t thread_state_count
= MACHINE_THREAD_STATE_COUNT
;
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
)) {
41 /* Get the thread state (registers, etc) */
43 p
->stop_info
.mach_thread
,
47 if(r
!= KERN_SUCCESS
) ABORT("thread_get_state failed");
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
);
84 # error FIXME for non-PPC darwin
87 if(p
->flags
& MAIN_THREAD
)
92 GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
93 (unsigned long) p
-> id
,
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. */
108 pthread_t my_thread
= pthread_self();
109 kern_return_t kern_result
;
112 GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
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;
132 GC_printf1("Suspending thread 0x%lx\n", p
-> id
);
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);
152 extern void GC_mprotect_stop();
157 # ifdef PARALLEL_MARK
158 GC_release_mark_lock();
161 GC_printf1("World stopped from 0x%lx\n", pthread_self());
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();
172 kern_return_t kern_result
;
175 GC_printf0("World starting\n");
180 extern void GC_mprotect_resume();
181 GC_mprotect_resume();
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;
192 GC_printf1("Resuming 0x%lx\n", p
-> id
);
195 /* Resume the thread */
196 kern_result
= thread_resume(p
->stop_info
.mach_thread
);
197 if(kern_result
!= KERN_SUCCESS
) ABORT("thread_resume failed");
201 GC_printf0("World started\n");
205 void GC_stop_init() {