~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/gc/darwin_stop_world.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "private/pthread_support.h"
 
2
 
 
3
# if defined(GC_DARWIN_THREADS)
 
4
 
 
5
/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
 
6
   Page 49:
 
7
   "The space beneath the stack pointer, where a new stack frame would normally
 
8
   be allocated, is called the red zone. This area as shown in Figure 3-2 may
 
9
   be used for any purpose as long as a new stack frame does not need to be
 
10
   added to the stack."
 
11
   
 
12
   Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
 
13
   it must set up a stack frame just like routines that call other routines."
 
14
*/
 
15
#ifdef POWERPC
 
16
# if CPP_WORDSZ == 32
 
17
#   define PPC_RED_ZONE_SIZE 224
 
18
# elif CPP_WORDSZ == 64
 
19
#   define PPC_RED_ZONE_SIZE 320
 
20
# endif
 
21
#endif
 
22
 
 
23
typedef struct StackFrame {
 
24
  unsigned long savedSP;
 
25
  unsigned long savedCR;
 
26
  unsigned long savedLR;
 
27
  unsigned long reserved[2];
 
28
  unsigned long savedRTOC;
 
29
} StackFrame;
 
30
 
 
31
unsigned long FindTopOfStack(unsigned int stack_start) {
 
32
  StackFrame    *frame;
 
33
  
 
34
  if (stack_start == 0) {
 
35
# ifdef POWERPC
 
36
#   if CPP_WORDSZ == 32
 
37
      __asm__ volatile("lwz     %0,0(r1)" : "=r" (frame));
 
38
#   else
 
39
      __asm__ volatile("ldz     %0,0(r1)" : "=r" (frame));
 
40
#   endif
 
41
# endif
 
42
  } else {
 
43
    frame = (StackFrame *)stack_start;
 
44
  }
 
45
 
 
46
# ifdef DEBUG_THREADS
 
47
    /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
 
48
# endif
 
49
  do {
 
50
    if (frame->savedSP == 0) break;
 
51
                /* if there are no more stack frames, stop */
 
52
 
 
53
    frame = (StackFrame*)frame->savedSP;
 
54
 
 
55
    /* we do these next two checks after going to the next frame
 
56
       because the LR for the first stack frame in the loop
 
57
       is not set up on purpose, so we shouldn't check it. */
 
58
    if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */
 
59
    if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */
 
60
  } while (1); 
 
61
 
 
62
# ifdef DEBUG_THREADS
 
63
    /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
 
64
# endif
 
65
 
 
66
  return (unsigned long)frame;
 
67
}       
 
68
 
 
69
#ifdef DARWIN_DONT_PARSE_STACK
 
70
void GC_push_all_stacks() {
 
71
  int i;
 
72
  kern_return_t r;
 
73
  GC_thread p;
 
74
  pthread_t me;
 
75
  ptr_t lo, hi;
 
76
  ppc_thread_state_t state;
 
77
  mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
 
78
  
 
79
  me = pthread_self();
 
80
  if (!GC_thr_initialized) GC_thr_init();
 
81
  
 
82
  for(i=0;i<THREAD_TABLE_SZ;i++) {
 
83
    for(p=GC_threads[i];p!=0;p=p->next) {
 
84
      if(p -> flags & FINISHED) continue;
 
85
      if(pthread_equal(p->id,me)) {
 
86
        lo = GC_approx_sp();
 
87
      } else {
 
88
        /* Get the thread state (registers, etc) */
 
89
        r = thread_get_state(
 
90
                             p->stop_info.mach_thread,
 
91
                             MACHINE_THREAD_STATE,
 
92
                             (natural_t*)&state,
 
93
                             &thread_state_count);
 
94
        if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
 
95
        
 
96
        lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
 
97
        
 
98
        GC_push_one(state.r0); 
 
99
        GC_push_one(state.r2); 
 
100
        GC_push_one(state.r3); 
 
101
        GC_push_one(state.r4); 
 
102
        GC_push_one(state.r5); 
 
103
        GC_push_one(state.r6); 
 
104
        GC_push_one(state.r7); 
 
105
        GC_push_one(state.r8); 
 
106
        GC_push_one(state.r9); 
 
107
        GC_push_one(state.r10); 
 
108
        GC_push_one(state.r11); 
 
109
        GC_push_one(state.r12); 
 
110
        GC_push_one(state.r13); 
 
111
        GC_push_one(state.r14); 
 
112
        GC_push_one(state.r15); 
 
113
        GC_push_one(state.r16); 
 
114
        GC_push_one(state.r17); 
 
115
        GC_push_one(state.r18); 
 
116
        GC_push_one(state.r19); 
 
117
        GC_push_one(state.r20); 
 
118
        GC_push_one(state.r21); 
 
119
        GC_push_one(state.r22); 
 
120
        GC_push_one(state.r23); 
 
121
        GC_push_one(state.r24); 
 
122
        GC_push_one(state.r25); 
 
123
        GC_push_one(state.r26); 
 
124
        GC_push_one(state.r27); 
 
125
        GC_push_one(state.r28); 
 
126
        GC_push_one(state.r29); 
 
127
        GC_push_one(state.r30); 
 
128
        GC_push_one(state.r31);
 
129
      } /* p != me */
 
130
      if(p->flags & MAIN_THREAD)
 
131
        hi = GC_stackbottom;
 
132
      else
 
133
        hi = p->stack_end;
 
134
#if DEBUG_THREADS
 
135
      GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
 
136
                 (unsigned long) p -> id,
 
137
                 (unsigned long) lo,
 
138
                 (unsigned long) hi
 
139
                 );
 
140
#endif
 
141
      GC_push_all_stack(lo,hi);
 
142
    } /* for(p=GC_threads[i]...) */
 
143
  } /* for(i=0;i<THREAD_TABLE_SZ...) */
 
144
}
 
145
 
 
146
#else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
 
147
 
 
148
void GC_push_all_stacks() {
 
149
    int i;
 
150
    kern_return_t r;
 
151
    mach_port_t me;
 
152
    ptr_t lo, hi;
 
153
    thread_act_array_t act_list = 0;
 
154
    mach_msg_type_number_t listcount = 0;
 
155
 
 
156
    me = mach_thread_self();
 
157
    if (!GC_thr_initialized) GC_thr_init();
 
158
    
 
159
    r = task_threads(current_task(), &act_list, &listcount);
 
160
    if(r != KERN_SUCCESS) ABORT("task_threads failed");
 
161
    for(i = 0; i < listcount; i++) {
 
162
      thread_act_t thread = act_list[i];
 
163
      if (thread == me) {
 
164
        lo = GC_approx_sp();
 
165
        hi = (ptr_t)FindTopOfStack(0);
 
166
      } else {
 
167
#     if defined(POWERPC)
 
168
#      if CPP_WORDSZ == 32
 
169
        ppc_thread_state_t info;
 
170
#      else
 
171
        ppc_thread_state64_t info;
 
172
#      endif
 
173
        mach_msg_type_number_t outCount = THREAD_STATE_MAX;
 
174
        r = thread_get_state(thread, MACHINE_THREAD_STATE,
 
175
                             (natural_t *)&info, &outCount);
 
176
        if(r != KERN_SUCCESS) ABORT("task_get_state failed");
 
177
 
 
178
        lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
 
179
        hi = (ptr_t)FindTopOfStack(info.r1);
 
180
 
 
181
        GC_push_one(info.r0); 
 
182
        GC_push_one(info.r2); 
 
183
        GC_push_one(info.r3); 
 
184
        GC_push_one(info.r4); 
 
185
        GC_push_one(info.r5); 
 
186
        GC_push_one(info.r6); 
 
187
        GC_push_one(info.r7); 
 
188
        GC_push_one(info.r8); 
 
189
        GC_push_one(info.r9); 
 
190
        GC_push_one(info.r10); 
 
191
        GC_push_one(info.r11); 
 
192
        GC_push_one(info.r12); 
 
193
        GC_push_one(info.r13); 
 
194
        GC_push_one(info.r14); 
 
195
        GC_push_one(info.r15); 
 
196
        GC_push_one(info.r16); 
 
197
        GC_push_one(info.r17); 
 
198
        GC_push_one(info.r18); 
 
199
        GC_push_one(info.r19); 
 
200
        GC_push_one(info.r20); 
 
201
        GC_push_one(info.r21); 
 
202
        GC_push_one(info.r22); 
 
203
        GC_push_one(info.r23); 
 
204
        GC_push_one(info.r24); 
 
205
        GC_push_one(info.r25); 
 
206
        GC_push_one(info.r26); 
 
207
        GC_push_one(info.r27); 
 
208
        GC_push_one(info.r28); 
 
209
        GC_push_one(info.r29); 
 
210
        GC_push_one(info.r30); 
 
211
        GC_push_one(info.r31);
 
212
#      else
 
213
        /* FIXME: Remove after testing: */
 
214
        WARN("This is completely untested and likely will not work\n", 0);
 
215
        i386_thread_state_t info;
 
216
        mach_msg_type_number_t outCount = THREAD_STATE_MAX;
 
217
        r = thread_get_state(thread, MACHINE_THREAD_STATE,
 
218
                             (natural_t *)&info, &outCount);
 
219
        if(r != KERN_SUCCESS) ABORT("task_get_state failed");
 
220
 
 
221
        lo = (void*)info.esp;
 
222
        hi = (ptr_t)FindTopOfStack(info.esp);
 
223
 
 
224
        GC_push_one(info.eax); 
 
225
        GC_push_one(info.ebx); 
 
226
        GC_push_one(info.ecx); 
 
227
        GC_push_one(info.edx); 
 
228
        GC_push_one(info.edi); 
 
229
        GC_push_one(info.esi); 
 
230
        /* GC_push_one(info.ebp);  */
 
231
        /* GC_push_one(info.esp);  */
 
232
        GC_push_one(info.ss); 
 
233
        GC_push_one(info.eip); 
 
234
        GC_push_one(info.cs); 
 
235
        GC_push_one(info.ds); 
 
236
        GC_push_one(info.es); 
 
237
        GC_push_one(info.fs); 
 
238
        GC_push_one(info.gs); 
 
239
#      endif /* !POWERPC */
 
240
      }
 
241
#     if DEBUG_THREADS
 
242
       GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
 
243
                  (unsigned long) thread,
 
244
                  (unsigned long) lo,
 
245
                  (unsigned long) hi
 
246
                 );
 
247
#     endif
 
248
      GC_push_all_stack(lo, hi); 
 
249
    } /* for(p=GC_threads[i]...) */
 
250
}
 
251
#endif /* !DARWIN_DONT_PARSE_STACK */
 
252
 
 
253
static mach_port_t GC_mach_handler_thread;
 
254
static int GC_use_mach_handler_thread = 0;
 
255
 
 
256
static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
 
257
static int GC_mach_threads_count;
 
258
 
 
259
void GC_stop_init() {
 
260
  int i;
 
261
 
 
262
  for (i = 0; i < THREAD_TABLE_SZ; i++) {
 
263
    GC_mach_threads[i].thread = 0;
 
264
    GC_mach_threads[i].already_suspended = 0;
 
265
  }
 
266
  GC_mach_threads_count = 0;
 
267
}
 
268
 
 
269
/* returns true if there's a thread in act_list that wasn't in old_list */
 
270
int GC_suspend_thread_list(thread_act_array_t act_list, int count, 
 
271
                           thread_act_array_t old_list, int old_count) {
 
272
  mach_port_t my_thread = mach_thread_self();
 
273
  int i, j;
 
274
 
 
275
  int changed = 0;
 
276
 
 
277
  for(i = 0; i < count; i++) {
 
278
    thread_act_t thread = act_list[i];
 
279
#   if DEBUG_THREADS 
 
280
      GC_printf1("Attempting to suspend thread %p\n", thread);
 
281
#   endif
 
282
    /* find the current thread in the old list */
 
283
    int found = 0;
 
284
    for(j = 0; j < old_count; j++) {
 
285
      thread_act_t old_thread = old_list[j];
 
286
      if (old_thread == thread) {
 
287
        found = 1;
 
288
        break;
 
289
      }
 
290
    }
 
291
    if (!found) {
 
292
      /* add it to the GC_mach_threads list */
 
293
      GC_mach_threads[GC_mach_threads_count].thread = thread;
 
294
      /* default is not suspended */
 
295
      GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
 
296
      changed = 1;
 
297
    }      
 
298
 
 
299
    if (thread != my_thread &&
 
300
        (!GC_use_mach_handler_thread
 
301
         || (GC_use_mach_handler_thread
 
302
             && GC_mach_handler_thread != thread))) {
 
303
      struct thread_basic_info info;
 
304
      mach_msg_type_number_t outCount = THREAD_INFO_MAX;
 
305
      kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
 
306
                                (thread_info_t)&info, &outCount);
 
307
      if(kern_result != KERN_SUCCESS) {
 
308
        /* the thread may have quit since the thread_threads () call 
 
309
         * we mark already_suspended so it's not dealt with anymore later
 
310
         */
 
311
        if (!found) {
 
312
          GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
 
313
          GC_mach_threads_count++;
 
314
        }
 
315
        continue;
 
316
      }
 
317
#     if DEBUG_THREADS
 
318
        GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
 
319
#     endif
 
320
      if (!found) {
 
321
        GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
 
322
      }
 
323
      if (info.suspend_count) continue;
 
324
      
 
325
#     if DEBUG_THREADS
 
326
        GC_printf1("Suspending 0x%lx\n", thread);
 
327
#     endif
 
328
      /* Suspend the thread */
 
329
      kern_result = thread_suspend(thread);
 
330
      if(kern_result != KERN_SUCCESS) {
 
331
        /* the thread may have quit since the thread_threads () call 
 
332
         * we mark already_suspended so it's not dealt with anymore later
 
333
         */
 
334
        if (!found) {
 
335
          GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
 
336
          GC_mach_threads_count++;
 
337
        }
 
338
        continue;
 
339
      }
 
340
    } 
 
341
    if (!found) GC_mach_threads_count++;
 
342
  }
 
343
  return changed;
 
344
}
 
345
 
 
346
 
 
347
/* Caller holds allocation lock.        */
 
348
void GC_stop_world()
 
349
{
 
350
  int i, changes;
 
351
    GC_thread p;
 
352
    mach_port_t my_thread = mach_thread_self();
 
353
    kern_return_t kern_result;
 
354
    thread_act_array_t act_list, prev_list;
 
355
    mach_msg_type_number_t listcount, prevcount;
 
356
    
 
357
#   if DEBUG_THREADS
 
358
      GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
 
359
#   endif
 
360
 
 
361
    /* clear out the mach threads list table */
 
362
    GC_stop_init(); 
 
363
       
 
364
    /* Make sure all free list construction has stopped before we start. */
 
365
    /* No new construction can start, since free list construction is   */
 
366
    /* required to acquire and release the GC lock before it starts,    */
 
367
    /* and we have the lock.                                            */
 
368
#   ifdef PARALLEL_MARK
 
369
      GC_acquire_mark_lock();
 
370
      GC_ASSERT(GC_fl_builder_count == 0);
 
371
      /* We should have previously waited for it to become zero. */
 
372
#   endif /* PARALLEL_MARK */
 
373
 
 
374
      /* Loop stopping threads until you have gone over the whole list
 
375
         twice without a new one appearing. thread_create() won't
 
376
         return (and thus the thread stop) until the new thread
 
377
         exists, so there is no window whereby you could stop a
 
378
         thread, recognise it is stopped, but then have a new thread
 
379
         it created before stopping show up later.
 
380
      */
 
381
      
 
382
      changes = 1;
 
383
      prev_list = NULL;
 
384
      prevcount = 0;
 
385
      do {
 
386
        int result;
 
387
        kern_result = task_threads(current_task(), &act_list, &listcount);
 
388
        result = GC_suspend_thread_list(act_list, listcount,
 
389
                                        prev_list, prevcount);
 
390
        changes = result;
 
391
        prev_list = act_list;
 
392
        prevcount = listcount;
 
393
      } while (changes);
 
394
      
 
395
 
 
396
#   ifdef MPROTECT_VDB
 
397
      if(GC_incremental) {
 
398
        extern void GC_mprotect_stop();
 
399
        GC_mprotect_stop();
 
400
      }
 
401
#   endif
 
402
    
 
403
#   ifdef PARALLEL_MARK
 
404
      GC_release_mark_lock();
 
405
#   endif
 
406
    #if DEBUG_THREADS
 
407
      GC_printf1("World stopped from 0x%lx\n", my_thread);
 
408
    #endif
 
409
}
 
410
 
 
411
/* Caller holds allocation lock, and has held it continuously since     */
 
412
/* the world stopped.                                                   */
 
413
void GC_start_world()
 
414
{
 
415
  mach_port_t my_thread = mach_thread_self();
 
416
  int i, j;
 
417
  GC_thread p;
 
418
  kern_return_t kern_result;
 
419
  thread_act_array_t act_list;
 
420
  mach_msg_type_number_t listcount;
 
421
  struct thread_basic_info info;
 
422
  mach_msg_type_number_t outCount = THREAD_INFO_MAX;
 
423
  
 
424
#   if DEBUG_THREADS
 
425
      GC_printf0("World starting\n");
 
426
#   endif
 
427
 
 
428
#   ifdef MPROTECT_VDB
 
429
      if(GC_incremental) {
 
430
        extern void GC_mprotect_resume();
 
431
        GC_mprotect_resume();
 
432
      }
 
433
#   endif
 
434
 
 
435
    kern_result = task_threads(current_task(), &act_list, &listcount);
 
436
    for(i = 0; i < listcount; i++) {
 
437
      thread_act_t thread = act_list[i];
 
438
      if (thread != my_thread &&
 
439
          (!GC_use_mach_handler_thread ||
 
440
           (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
 
441
        for(j = 0; j < GC_mach_threads_count; j++) {
 
442
          if (thread == GC_mach_threads[j].thread) {
 
443
            if (GC_mach_threads[j].already_suspended) {
 
444
#             if DEBUG_THREADS
 
445
                GC_printf1("Not resuming already suspended thread %p\n", thread);
 
446
#             endif
 
447
              continue;
 
448
            }
 
449
            kern_result = thread_info(thread, THREAD_BASIC_INFO,
 
450
                                      (thread_info_t)&info, &outCount);
 
451
            if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
 
452
#           if DEBUG_THREADS
 
453
              GC_printf2("Thread state for 0x%lx = %d\n", thread,
 
454
                         info.run_state);
 
455
              GC_printf1("Resuming 0x%lx\n", thread);
 
456
#           endif
 
457
            /* Resume the thread */
 
458
            kern_result = thread_resume(thread);
 
459
            if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
 
460
          } 
 
461
        }
 
462
      }
 
463
    }
 
464
#   if DEBUG_THREADS
 
465
     GC_printf0("World started\n");
 
466
#   endif
 
467
}
 
468
 
 
469
void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
 
470
  GC_mach_handler_thread = thread;
 
471
  GC_use_mach_handler_thread = 1;
 
472
}
 
473
 
 
474
#endif