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