OSDN Git Service

* approved by rth
[pf3gnuchains/gcc-fork.git] / boehm-gc / darwin_stop_world.c
1 #include "private/pthread_support.h"
2
3 # if defined(GC_DARWIN_THREADS)
4
5 #define DEBUG_THREADS 0
6
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."
13    
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."
16 */
17 #define PPC_RED_ZONE_SIZE 224
18
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;
31     
32     me = pthread_self();
33     if (!GC_thr_initialized) GC_thr_init();
34     
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");
48     
49                 #ifdef POWERPC
50                     lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
51                     
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
96                 );
97             #endif
98             GC_push_all_stack(lo,hi);
99         } /* for(p=GC_threads[i]...) */
100     } /* for(i=0;i<THREAD_TABLE_SZ...) */
101 }
102
103 /* Caller holds allocation lock.        */
104 void GC_stop_world()
105 {
106     int i;
107     GC_thread p;
108     pthread_t my_thread = pthread_self();
109     kern_return_t kern_result;
110     
111     #if DEBUG_THREADS
112     GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
113     #endif
114        
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 */
124
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;
130             
131             #if DEBUG_THREADS
132             GC_printf1("Suspending thread 0x%lx\n", p -> id);
133             #endif
134             
135             /* Suspend the thread */
136             kern_result = thread_suspend(p->stop_info.mach_thread);
137             if(kern_result != KERN_SUCCESS) ABORT("thread_suspend failed");
138             
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.
142                
143                kern_result = thread_abort(p->stop_info.mach_thread);
144                if(kern_result != KERN_SUCCESS)
145                    ABORT("thread_abort failed (%ul)",kern_result);
146             */
147         }
148     }
149     
150 #   ifdef MPROTECT_VDB
151     if(GC_incremental) {
152         extern void GC_mprotect_stop();
153         GC_mprotect_stop();
154     }
155 #   endif
156     
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
163 }
164
165 /* Caller holds allocation lock, and has held it continuously since     */
166 /* the world stopped.                                                   */
167 void GC_start_world()
168 {
169     pthread_t my_thread = pthread_self();
170     int i;
171     GC_thread p;
172     kern_return_t kern_result;
173
174 #   if DEBUG_THREADS
175       GC_printf0("World starting\n");
176 #   endif
177
178 #   ifdef MPROTECT_VDB
179     if(GC_incremental) {
180         extern void GC_mprotect_resume();
181         GC_mprotect_resume();
182     }
183 #   endif
184
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;
190     
191             #if DEBUG_THREADS
192             GC_printf1("Resuming 0x%lx\n", p -> id);
193             #endif
194             
195             /* Resume the thread */
196             kern_result = thread_resume(p->stop_info.mach_thread);
197             if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
198         }
199     }
200     #if DEBUG_THREADS
201       GC_printf0("World started\n");
202     #endif
203 }
204
205 void GC_stop_init() {
206
207 }
208
209 #endif