summaryrefslogtreecommitdiff
path: root/win32_threads.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2011-07-26 15:20:24 +0400
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 15:20:24 +0400
commitc521d2cf164f9d7e1fa8be9c0b21d223e265fa64 (patch)
tree82fbd7e60e6be39fbabd946717cf065a698cd038 /win32_threads.c
parent7d3768dbd2a1cd4d5c14f773f23aec43bc0651a5 (diff)
downloadbdwgc-c521d2cf164f9d7e1fa8be9c0b21d223e265fa64.tar.gz
gc4.13 tarball importgc4_13
Diffstat (limited to 'win32_threads.c')
-rwxr-xr-xwin32_threads.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/win32_threads.c b/win32_threads.c
index eb485bdc..2b01c5c6 100755
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -8,22 +8,32 @@
#define MAX_THREADS 64
struct thread_entry {
+ LONG in_use;
DWORD id;
HANDLE handle;
- void *stack; /* The cold end of the stack. */
+ void *stack; /* The cold end of the stack. */
+ /* 0 ==> entry not valid. */
+ /* !in_use ==> stack == 0 */
CONTEXT context;
+ GC_bool suspended;
};
-struct thread_entry thread_table[MAX_THREADS];
+volatile GC_bool GC_please_stop = FALSE;
+
+volatile struct thread_entry thread_table[MAX_THREADS];
void GC_stop_world()
{
DWORD thread_id = GetCurrentThreadId();
int i;
+
+ GC_please_stop = TRUE;
for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) {
+ if (thread_table[i].stack != 0
+ && thread_table[i].id != thread_id) {
if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
ABORT("SuspendThread failed");
+ thread_table[i].suspended = TRUE;
}
}
@@ -32,10 +42,13 @@ void GC_start_world()
DWORD thread_id = GetCurrentThreadId();
int i;
for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) {
+ if (thread_table[i].stack != 0 && thread_table[i].suspended
+ && thread_table[i].id != thread_id) {
if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
ABORT("ResumeThread failed");
+ thread_table[i].suspended = FALSE;
}
+ GC_please_stop = FALSE;
}
ptr_t GC_current_stackbottom()
@@ -117,20 +130,34 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
switch (reason) {
case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&GC_allocate_ml);
+ GC_init(); /* Force initialization before thread attach. */
/* fall through */
case DLL_THREAD_ATTACH:
{
int i;
- LOCK();
+ /* It appears to be unsafe to acquire a lock here, since this */
+ /* code is apparently not preeemptible on some systems. */
+ /* (This is based on complaints, not on Microsoft's official */
+ /* documentation, which says this should perform "only simple */
+ /* inititalization tasks".) */
+ /* Hence we make do with nonblocking synchronization. */
+
/* The following should be a noop according to the win32 */
/* documentation. There is empirical evidence that it */
/* isn't. - HB */
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
- for (i = 0; thread_table[i].stack != 0; i++) {
+# ifndef SMALL_CONFIG
+ if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+# endif
+
+ for (i = 0; InterlockedExchange(&thread_table[i].in_use,1) != 0; i++) {
+ /* Compare-and-swap would make this cleaner, but that's not */
+ /* supported before Windows 98 and NT 4.0. In Windows 2000, */
+ /* InterlockedExchange is supposed to be replaced by */
+ /* InterlockedExchangePointer, but that's not really what I */
+ /* want here. */
if (i == MAX_THREADS - 1)
ABORT("too many threads");
}
- thread_table[i].stack = GC_get_stack_base();
thread_table[i].id = GetCurrentThreadId();
if (!DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(),
@@ -143,7 +170,11 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
GC_printf1("Last error code: %lx\n", last_error);
ABORT("DuplicateHandle failed");
}
- UNLOCK();
+ thread_table[i].stack = GC_get_stack_base();
+ /* If this thread is being created while we are trying to stop */
+ /* the world, wait here. Hopefully this can't happen on any */
+ /* systems that don't allow us to block here. */
+ while (GC_please_stop) Sleep(20);
}
break;
case DLL_PROCESS_DETACH:
@@ -152,10 +183,14 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
int i;
DWORD thread_id = GetCurrentThreadId();
LOCK();
- for (i = 0; thread_table[i].stack == 0 || thread_table[i].id != thread_id; i++)
+ for (i = 0;
+ thread_table[i].stack == 0 || thread_table[i].id != thread_id;
+ i++) {
if (i == MAX_THREADS - 1)
ABORT("thread not found on detach");
+ }
thread_table[i].stack = 0;
+ thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
BZERO(&thread_table[i].context, sizeof(CONTEXT));
UNLOCK();