Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / libgc / openbsd_stop_world.c
1 #include "private/pthread_support.h"
2
3 /* derived from pthread_stop_world.c */
4
5 # if defined(GC_OPENBSD_THREADS)
6
7 #define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
8
9 /* We hold allocation lock.  Should do exactly the right thing if the   */
10 /* world is stopped.  Should not fail if it isn't.                      */
11 void GC_push_all_stacks()
12 {
13     GC_bool found_me = FALSE;
14     size_t nthreads = 0;
15     int i;
16     GC_thread p;
17     ptr_t lo, hi;
18     pthread_t me = pthread_self();
19     
20     if (!GC_thr_initialized) GC_thr_init();
21 #   if DEBUG_THREADS
22         GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) me);
23 #   endif
24     for (i = 0; i < THREAD_TABLE_SZ; i++) {
25       for (p = GC_threads[i]; p != 0; p = p -> next) {
26         if (p -> flags & FINISHED) continue;
27         ++nthreads;
28         if (THREAD_EQUAL(p -> id, me)) {
29 #           ifdef SPARC
30                 lo = (ptr_t)GC_save_regs_in_stack();
31 #           else
32                 lo = GC_approx_sp();
33 #           endif
34             found_me = TRUE;
35         } else {
36             lo = p -> stop_info.stack_ptr;
37         }
38         if ((p -> flags & MAIN_THREAD) == 0) {
39             hi = p -> stack_end;
40         } else {
41             /* The original stack. */
42             hi = GC_stackbottom;
43         }
44 #       if DEBUG_THREADS
45             GC_printf("Stack for thread 0x%x = [%p,%p)\n",
46                       (unsigned)(p -> id), lo, hi);
47 #       endif
48         if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
49 #       ifdef STACK_GROWS_UP
50           /* We got them backwards! */
51           GC_push_all_stack(hi, lo);
52 #       else
53           GC_push_all_stack(lo, hi);
54 #       endif
55       }
56     }
57     if (!found_me && !GC_in_thread_creation)
58       ABORT("Collecting from unknown thread.");
59 }
60
61 /* We hold the allocation lock.  Suspend all threads that might */
62 /* still be running. */ 
63 void GC_suspend_all()
64 {
65     int i;
66     GC_thread p;
67     int result;
68     pthread_t my_thread = pthread_self();
69     
70     for (i = 0; i < THREAD_TABLE_SZ; i++) {
71       for (p = GC_threads[i]; p != 0; p = p -> next) {
72         if (!THREAD_EQUAL(p -> id, my_thread)) {
73             if (p -> flags & FINISHED) continue;
74             if (p -> thread_blocked) /* Will wait */ continue;
75 #           if DEBUG_THREADS
76               GC_printf("Suspending thread 0x%x\n",
77                         (unsigned)(p -> id));
78 #           endif
79         
80             if (pthread_suspend_np(p -> id) != 0)
81               ABORT("pthread_suspend_np failed");
82
83            /*
84             * This will only work for userland pthreads. It will
85             * fail badly on rthreads. Perhaps we should consider
86             * a pthread_sp_np() function that returns the stack
87             * pointer for a suspended thread and implement in
88             * both pthreads and rthreads.
89             */
90            p -> stop_info.stack_ptr = *(ptr_t*)((char *)p -> id + UTHREAD_SP_OFFSET);
91         }
92       }
93     }
94 }
95
96 void GC_stop_world()
97 {
98     int i;
99
100     GC_ASSERT(I_HOLD_LOCK());
101 #   if DEBUG_THREADS
102       GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
103 #   endif
104        
105     /* Make sure all free list construction has stopped before we start. */
106     /* No new construction can start, since free list construction is   */
107     /* required to acquire and release the GC lock before it starts,    */
108     /* and we have the lock.                                            */
109 #   ifdef PARALLEL_MARK
110       GC_acquire_mark_lock();
111       GC_ASSERT(GC_fl_builder_count == 0);
112       /* We should have previously waited for it to become zero. */
113 #   endif /* PARALLEL_MARK */
114
115     GC_suspend_all();
116
117 #   ifdef PARALLEL_MARK
118       GC_release_mark_lock();
119 #   endif
120     #if DEBUG_THREADS
121       GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
122     #endif
123 }
124
125 /* Caller holds allocation lock, and has held it continuously since     */
126 /* the world stopped.                                                   */
127 void GC_start_world()
128 {
129     pthread_t my_thread = pthread_self();
130     register int i;
131     register GC_thread p;
132     register int result;
133
134 #   if DEBUG_THREADS
135       GC_printf("World starting\n");
136 #   endif
137
138     for (i = 0; i < THREAD_TABLE_SZ; i++) {
139       for (p = GC_threads[i]; p != 0; p = p -> next) {
140         if (!THREAD_EQUAL(p -> id, my_thread)) {
141             if (p -> flags & FINISHED) continue;
142             if (p -> thread_blocked) continue;
143             #if DEBUG_THREADS
144               GC_printf("Resuming thread 0x%x\n",
145                         (unsigned)(p -> id));
146             #endif
147         
148             if (pthread_resume_np(p -> id) != 0)
149               ABORT("pthread_kill failed");
150         }
151       }
152     }
153 #    if DEBUG_THREADS
154       GC_printf("World started\n");
155 #    endif
156 }
157
158 void GC_stop_init() {
159 }
160
161 #endif