[Gc] do_blocking for Win32

Ivan Maidanski ivmai at mail.ru
Thu Nov 13 08:37:24 PST 2008


Hi!

I've added GC_do_blocking() proto to gc.h. I've changed its fn type to GC_fn_type for convenience (I think this is acceptable since GC_do_blocking() has an 'undocumented' status up to now).

I've also added its implementation for Win32.

Bye.

-------------- next part --------------
diff -ru bdwgc/include/gc.h updated/bdwgc/include/gc.h
--- bdwgc/include/gc.h	2008-11-12 20:15:54.000000000 +0300
+++ updated/bdwgc/include/gc.h	2008-11-13 12:23:54.000000000 +0300
@@ -920,6 +920,10 @@
 /* by saving it in a global data structure.				*/
 GC_API int GC_CALL GC_unregister_my_thread(void);
 
+/* Wrapper for functions that are likely to block for an appreciable	*/
+/* length of time.							*/
+GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data);
+
 /* Attempt to fill in the GC_stack_base structure with the stack base	*/
 /* for this thread.  This appears to be required to implement anything	*/
 /* like the JNI AttachCurrentThread in an environment in which new	*/
diff -ru bdwgc/pthread_support.c updated/bdwgc/pthread_support.c
--- bdwgc/pthread_support.c	2008-11-12 16:36:34.000000000 +0300
+++ updated/bdwgc/pthread_support.c	2008-11-13 14:47:15.000000000 +0300
@@ -875,11 +875,11 @@
 /* length of time.							*/
 
 struct blocking_data {
-    void (GC_CALLBACK *fn)(void *);
-    void *arg;
+    GC_fn_type fn;
+    void * client_data; /* and result */
 };
 
-static void GC_do_blocking_inner(ptr_t data, void * context) {
+STATIC void GC_do_blocking_inner(ptr_t data, void * context) {
     struct blocking_data * d = (struct blocking_data *) data;
     GC_thread me;
     LOCK();
@@ -896,18 +896,19 @@
     me -> thread_blocked = TRUE;
     /* Save context here if we want to support precise stack marking */
     UNLOCK();
-    (d -> fn)(d -> arg);
+    d -> client_data = (d -> fn)(d -> client_data);
     LOCK();   /* This will block if the world is stopped.	*/
     me -> thread_blocked = FALSE;
     UNLOCK();
 }
 
-void GC_CALL GC_do_blocking(void (GC_CALLBACK *fn)(void *), void *arg) {
+GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data) {
     struct blocking_data my_data;
 
     my_data.fn = fn;
-    my_data.arg = arg;
+    my_data.client_data = client_data;
     GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
+    return my_data.client_data; /* result */
 }
     
 struct start_info {
diff -ru bdwgc/win32_threads.c updated/bdwgc/win32_threads.c
--- bdwgc/win32_threads.c	2008-11-13 00:36:09.000000000 +0300
+++ updated/bdwgc/win32_threads.c	2008-11-13 16:47:34.000000000 +0300
@@ -203,6 +203,13 @@
     ptr_t backing_store_ptr;
 # endif
 
+  ptr_t thread_blocked_sp;	/* Protected by GC lock.		*/
+				/* NULL value means thread unblocked.	*/
+				/* If set to non-NULL, thread will	*/
+				/* acquire GC lock before doing any	*/
+				/* pointer manipulations.  Thus it does	*/
+				/* not need to stop this thread.	*/
+
   GC_bool suspended;
 
 # ifdef GC_PTHREADS
@@ -310,8 +317,9 @@
     result -> next = GC_threads[hv];
     GC_threads[hv] = result;
 #   ifdef GC_PTHREADS
-      GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);
+      GC_ASSERT(result -> flags == 0);
 #   endif
+    GC_ASSERT(result -> thread_blocked_sp == NULL);
     return(result);
 }
 
@@ -625,7 +633,43 @@
     return GC_SUCCESS;
 }
 
+/* Wrapper for functions that are likely to block for an appreciable	*/
+/* length of time.							*/
+
+struct blocking_data {
+    GC_fn_type fn;
+    void * client_data; /* and result */
+};
 
+/* GC_do_blocking[_inner]() are nealy the same as in pthread_support.c	*/
+STATIC void GC_do_blocking_inner(ptr_t data, void * context) {
+    struct blocking_data * d = (struct blocking_data *) data;
+    DWORD t = GetCurrentThreadId();
+    GC_thread me;
+    LOCK();
+    me = GC_lookup_thread_inner(t);
+    GC_ASSERT(me -> thread_blocked_sp == NULL);
+#   ifdef IA64
+	me -> backing_store_ptr = GC_save_regs_in_stack();
+#   endif
+    me -> thread_blocked_sp = (ptr_t) &d; /* save approx. sp */
+    /* Save context here if we want to support precise stack marking */
+    UNLOCK();
+    d -> client_data = (d -> fn)(d -> client_data);
+    LOCK();   /* This will block if the world is stopped.	*/
+    me -> thread_blocked_sp = NULL;
+    UNLOCK();
+}
+
+GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data) {
+    struct blocking_data my_data;
+
+    my_data.fn = fn;
+    my_data.client_data = client_data;
+    GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
+    return my_data.client_data; /* result */
+}
+    
 #ifdef GC_PTHREADS
 
 /* A quick-and-dirty cache of the mapping between pthread_t	*/
@@ -635,7 +679,7 @@
 #define HASH(pthread_id) ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
 	/* It appears pthread_t is really a pointer type ... */
 #define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
-	GC_pthread_map_cache[HASH(pthread_id)] = (win32_id);
+	(GC_pthread_map_cache[HASH(pthread_id)] = (win32_id))
 #define GET_PTHREAD_MAP_CACHE(pthread_id) \
 	GC_pthread_map_cache[HASH(pthread_id)]
 
@@ -714,7 +758,7 @@
 }
 
 /* Suspend the given thread, if it's still active.	*/
-void GC_suspend(GC_thread t)
+STATIC void GC_suspend(GC_thread t)
 {
 # ifdef MSWINCE
     /* SuspendThread will fail if thread is running kernel code */
@@ -781,7 +825,7 @@
     my_max = (int)GC_get_max_thread_index();
     for (i = 0; i <= my_max; i++) {
       GC_vthread t = dll_thread_table + i;
-      if (t -> stack_base != 0
+      if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
 	  && t -> id != thread_id) {
 	  GC_suspend((GC_thread)t);
       }
@@ -792,7 +836,7 @@
 
       for (i = 0; i < THREAD_TABLE_SZ; i++) {
         for (t = GC_threads[i]; t != 0; t = t -> next) {
-	  if (t -> stack_base != 0
+	  if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
 	  && !KNOWN_FINISHED(t)
 	  && t -> id != thread_id) {
 	    GC_suspend(t);
@@ -901,8 +945,11 @@
 
     if (thread -> stack_base) {
       if (thread -> id == me) {
+	GC_ASSERT(thread -> thread_blocked_sp == NULL);
 	sp = (ptr_t) &dummy;
-      } else {
+      } else if ((sp = thread -> thread_blocked_sp) == NULL) {
+		/* Use saved sp value for blocked threads.	*/
+	/* For unblocked threads call GetThreadContext().	*/
         CONTEXT context;
         context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
         if (!GetThreadContext(thread -> handle, &context))


More information about the Gc mailing list