[Gc] win32_pthreads

Boehm, Hans hans.boehm at hp.com
Tue May 22 15:48:15 PDT 2007


Thanks.  Though it's not that small a change, I'm inclined to check it
in immediately, especially since it fixes a bug or two in the current
code.

Could you resend the patch as an attachment?  Some mail software managed
to add line breaks ...

Hans

> -----Original Message-----
> From: gc-bounces at napali.hpl.hp.com 
> [mailto:gc-bounces at napali.hpl.hp.com] On Behalf Of Romano Paolo Tenca
> Sent: Tuesday, May 22, 2007 10:57 AM
> To: Gc at napali.hpl.hp.com
> Subject: [Gc] win32_pthreads
> 
> This is my patch to support win32 pthreads under mingw.
> 
> Don't worry: it seems big, but the real changes are small 
> (most is debug suppport).
> 
> I define a new macro GC_WIN32_PTHREADS to be used at makefile level.
> 
> In gc_config_macros.h it defines the already known macros:
> 
>  GC_WIN32_THREADS
>  GC_PTHREADS
> 
> I try to support both the static as the dynamic version of 
> the pthread library. The default is dynamic.
> Use -DPTW32_STATIC_LIB to use the static version of the 
> library (i assume a suffix 's for the static library name 
> i.e. "libpthreadGC2s" 
> instead of "libpthreadGC2"  in threadlib.exe).
> 
> I share code between Cygwin and Mingw, so i changed many 
> points of the source to use
>   #ifdef GC_PTHTREADS
> instead of
>   #ifdef  CYGWIN32
> 
> I added support for DEBUG_WIN32_PTHREADS.
> 
> I found only one point to change with THREAD_EQUAL().
> 
> You must use -DNO_INCREMENTAL to compile gctest else it hangs 
> (i do not know if it is normal or a bug of my porting).
> 
> I tested only the static version of GC.
> 
> It compiles and gctest works, both with static and dynamic 
> pthread library, but if i define DEBUG_WIN32_PTHREADS, gctest 
> hangs in a deadlock condition (i suppose) in different points 
> of the code. I have tried to debug that but with no success. 
> Could be that there are other points to patch but i do not 
> know enough of the internal detail of GC to resolve the problem.
> 
> If someone can help me to find the problem(s) i will be happy
> 
> -- 
> 
> Romano Paolo Tenca
> 
> 
> -------------------------
> Index: gc_dlopen.c
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/gc_dlopen.c,v
> retrieving revision 1.1.1.1
> diff -u -r1.1.1.1 gc_dlopen.c
> --- gc_dlopen.c    10 Oct 2005 22:33:34 -0000    1.1.1.1
> +++ gc_dlopen.c    19 May 2007 17:03:55 -0000
> @@ -25,7 +25,7 @@
>  
>  #include "private/gc_priv.h"
>  
> -# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \
> +# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) &&
> !defined(GC_WIN32_PTHREADS)\
>        || defined(GC_SOLARIS_THREADS)
>  
>  # if defined(dlopen) && !defined(GC_USE_LD_WRAP)
> Index: thread_local_alloc.c
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/thread_local_alloc.c,v
> retrieving revision 1.8
> diff -u -r1.8 thread_local_alloc.c
> --- thread_local_alloc.c    11 May 2007 21:55:38 -0000    1.8
> +++ thread_local_alloc.c    19 May 2007 19:29:04 -0000
> @@ -124,7 +124,8 @@
>  #   endif
>  }
>  
> -#if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && 
> !defined(CYGWIN32)
> +#if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && 
> !defined(CYGWIN32) \
> +    && !defined(GC_WIN32_PTHREADS)
>  # include <pthread.h>
>    extern char * GC_lookup_thread(pthread_t id);  #endif
> Index: threadlibs.c
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/threadlibs.c,v
> retrieving revision 1.4
> diff -u -r1.4 threadlibs.c
> --- threadlibs.c    17 Nov 2006 05:28:22 -0000    1.4
> +++ threadlibs.c    21 May 2007 19:57:43 -0000
> @@ -42,6 +42,14 @@
>  #   if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
>          printf("-lpthread\n");
>  #   endif
> +#   if defined(GC_WIN32_PTHREADS)
> +#      ifdef PTW32_STATIC_LIB
> +     /* assume suffix s for static version of the win32 
> pthread library */
> +         printf("-lpthreadGC2s -lws2_32\n");
> +#      else
> +         printf("-lpthreadGC2\n");
> +#      endif
> +#   endif
>  #   if defined(GC_OSF1_THREADS)
>      printf("-pthread -lrt"); /* DOB: must be -pthread, not 
> -lpthread */
>  #   endif
> Index: win32_threads.c
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/win32_threads.c,v
> retrieving revision 1.8
> diff -u -r1.8 win32_threads.c
> --- win32_threads.c    15 May 2007 18:57:48 -0000    1.8
> +++ win32_threads.c    22 May 2007 14:23:27 -0000
> @@ -2,7 +2,7 @@
>  
>  #if defined(GC_WIN32_THREADS)
>  
> -#if defined( _MINGW_VER )
> +#if defined( _MINGW_VER ) || defined(__MINGW32__)
>  # include <stdint.h>
>      /* We mention uintptr_t.                    */
>      /* Perhaps this should be included in pure msft 
> environments    */
> @@ -29,7 +29,7 @@
>    unsigned long GC_lock_holder = NO_THREAD;  #endif
>  
> -#ifdef CYGWIN32
> +#ifdef GC_PTHREADS
>  # include <errno.h>
>  
>  /* GC_DLL should not normally be defined, especially since 
> we often do 
> turn on    */
> @@ -48,6 +48,7 @@
>  # undef dlopen
>  
>  # define DEBUG_CYGWIN_THREADS 0
> +# define DEBUG_WIN32_PTHREADS 0
>  
>    void * GC_pthread_start(void * arg);
>    void GC_thread_exit_proc(void *arg);
> @@ -165,7 +166,7 @@
>              /* !in_use ==> stack_base == 0    */
>    GC_bool suspended;
>  
> -# ifdef CYGWIN32
> +# ifdef GC_PTHREADS
>      void *status; /* hold exit value until join in case it's 
> a pointer */
>      pthread_t pthread_id;
>      short flags;        /* Protected by GC lock.    */
> @@ -255,7 +256,8 @@
>          GC_ASSERT(!GC_win32_dll_threads);
>          result = (struct GC_Thread_Rep *)
>               GC_INTERNAL_MALLOC(sizeof(struct 
> GC_Thread_Rep), NORMAL);
> -#       ifdef CYGWIN32
> +#       ifdef GC_PTHREADS
> +      /* result can be NULL - segfault */
>        GC_ASSERT(result -> flags == 0);
>  #       endif
>      }
> @@ -263,7 +265,7 @@
>      /* result -> id = id; Done by caller.    */
>      result -> next = GC_threads[hv];
>      GC_threads[hv] = result;
> -#   ifdef CYGWIN32
> +#   ifdef GC_PTHREADS
>        GC_ASSERT(result -> flags == 0 /* && result -> 
> thread_blocked == 0 */);
>  #   endif
>      return(result);
> @@ -345,9 +347,11 @@
>      GC_ASSERT(I_HOLD_LOCK());
>      me = GC_new_thread(thread_id);
>    }
> -# ifdef CYGWIN32
> -    me -> pthread_id = pthread_self();
> +# ifdef GC_PTHREADS
> +  /* me can be NULL -> segfault */
> +  me -> pthread_id = pthread_self();
>  # endif
> +
>    if (!DuplicateHandle(GetCurrentProcess(),
>                       GetCurrentThread(),
>                  GetCurrentProcess(),
> @@ -471,6 +475,9 @@
>  #   ifdef CYGWIN32
>        gc_id -> pthread_id = 0;
>  #   endif /* CYGWIN32 */
> +#   ifdef GC_WIN32_PTHREADS
> +      gc_id -> pthread_id.p = NULL;
> +#   endif /* GC_WIN32_PTHREADS */
>      AO_store_release(&(gc_id->in_use), FALSE);
>    } else {
>      /* Cast away volatile qualifier, since we have lock. */ 
> @@ -567,7 +574,7 @@  }
>  
>  
> -#ifdef CYGWIN32
> +#ifdef GC_PTHREADS
>  
>  /* A quick-and-dirty cache of the mapping between pthread_t    */
>  /* and win32 thread id.                        */
> @@ -595,7 +602,7 @@
>      for (i = 0;
>           i <= my_max &&
>           (!AO_load_acquire(&(dll_thread_table[i].in_use))
> -      || dll_thread_table[i].pthread_id != id);
> +      || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
>         /* Must still be in_use, since nobody else can store 
> our thread_id. */
>         i++);
>      if (i > my_max) return 0;
> @@ -625,7 +632,7 @@
>    }
>  }
>  
> -#endif /* CYGWIN32 */
> +#endif /* GC_PTHREADS */
>  
>  void GC_push_thread_structures(void)
>  {
> @@ -634,7 +641,7 @@
>      /* Unlike the other threads implementations, the thread table 
> here    */
>      /* contains no pointers to the collectable heap.  Thus 
> we have    */
>      /* no private structures we need to preserve.            */
> -#   ifdef CYGWIN32
> +#   ifdef GC_PTHREADS
>      { int i; /* pthreads may keep a pointer in the thread 
> exit value */
>        LONG my_max = GC_get_max_thread_index();
>  
> @@ -671,7 +678,7 @@
>      if (GetExitCodeThread(t -> handle, &exitCode) &&
>          exitCode != STILL_ACTIVE) {
>        t -> stack_base = 0; /* prevent stack from being pushed */
> -#     ifndef CYGWIN32
> +#     ifndef GC_PTHREADS
>          /* this breaks pthread_join on Cygwin, which is 
> guaranteed to  */
>          /* only see user pthreads                         */
>          AO_store(&(t -> in_use), FALSE); @@ -686,7 +693,7 @@  }
>  
>  /* Defined in misc.c */
> -#ifndef CYGWIN32
> +#ifndef GC_PTHREADS
>    extern CRITICAL_SECTION GC_write_cs;
>  #endif
>  
> @@ -699,7 +706,7 @@
>    GC_ASSERT(I_HOLD_LOCK());
>  
>    GC_please_stop = TRUE;
> -# ifndef CYGWIN32
> +# ifndef GC_PTHREADS
>      EnterCriticalSection(&GC_write_cs);
>  # endif
>    if (GC_win32_dll_threads) {
> @@ -728,7 +735,7 @@
>      }
>        }
>    }
> -# ifndef CYGWIN32
> +# ifndef GC_PTHREADS
>      LeaveCriticalSection(&GC_write_cs);
>  # endif   
>  }
> @@ -850,6 +857,10 @@
>        GC_printf("Pushing thread from %p to %p for %d from %d\n",
>              sp, thread -> stack_base, thread -> id, me);
>  #       endif
> +#       if DEBUG_WIN32_PTHREADS
> +      GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n",
> +            sp, thread -> stack_base, thread -> id, me);
> +#       endif
>          GC_push_all_stack(sp, thread->stack_base);
>        } else {
>          WARN("Thread stack pointer 0x%lx out of range, 
> pushing everything\n", @@ -938,7 +949,7 @@
>      if (*lo < start) *lo = start;
>  }
>  
> -#if !defined(CYGWIN32)
> +#ifndef GC_PTHREADS
>  
>  /* We have no DllMain to take care of new threads.  Thus we    */
>  /* must properly intercept thread creation.            */
> @@ -1067,7 +1078,7 @@
>    _endthreadex(retval);
>  }
>  
> -#endif /* !CYGWIN32 */
> +#endif /* !GC_PTHREADS */
>  
>  #ifdef MSWINCE
>  
> @@ -1137,7 +1148,7 @@
>      GC_register_my_thread(&sb);
>  }
>  
> -#ifdef CYGWIN32
> +#ifdef GC_PTHREADS
>  
>  struct start_info {
>      void *(*start_routine)(void *);
> @@ -1154,6 +1165,10 @@
>        GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
>          (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
>  #   endif
> +#   if DEBUG_WIN32_PTHREADS
> +      GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
> +        (pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
> +#   endif
>  
>      if (!parallel_initialized) GC_init_parallel();
>      /* Thread being joined might not have registered itself 
> yet. */ @@ -1175,6 +1190,10 @@
>        GC_printf("thread 0x%x(0x%x) completed join with 
> thread 0x%x.\n",
>           (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
>  #   endif
> +#   if DEBUG_WIN32_PTHREADS
> +      GC_printf("thread 0x%x(0x%x) completed join with 
> thread 0x%x.\n",
> +        (pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
> +#   endif
>  
>      return result;
>  }
> @@ -1213,6 +1232,10 @@
>        GC_printf("About to create a thread from 0x%x(0x%x)\n",
>          (int)pthread_self(), GetCurrentThreadId);
>  #   endif
> +#   if DEBUG_WIN32_PTHREADS
> +      GC_printf("About to create a thread from 0x%x(0x%x)\n",
> +        (pthread_self()).p, GetCurrentThreadId());
> +#   endif
>      GC_need_to_lock = TRUE;
>      result = pthread_create(new_thread, attr, GC_pthread_start, si);
>  
> @@ -1239,6 +1262,10 @@
>        GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id,
>                                  thread_id);
>  #   endif
> +#   if DEBUG_WIN32_PTHREADS
> +      GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p,
> +                                thread_id);
> +#   endif
>  
>      GC_ASSERT(!GC_win32_dll_threads);
>      /* If a GC occurs before the thread is registered, that 
> GC will    */
> @@ -1268,6 +1295,10 @@
>        GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
>          (int)pthread_self(),GetCurrentThreadId());
>  #   endif
> +#   if DEBUG_WIN32_PTHREADS
> +      GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
> +        (int)(pthread_self()).p, GetCurrentThreadId());
> +#   endif
>  
>      return(result);
>  }
> @@ -1287,6 +1318,10 @@
>        GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
>          (int)pthread_self(),GetCurrentThreadId());
>  #   endif
> +#   if DEBUG_WIN32_PTHREADS
> +      GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
> +        (int)(pthread_self()).p,GetCurrentThreadId());
> +#   endif
>  
>      LOCK();
>  #   if defined(THREAD_LOCAL_ALLOC)
> @@ -1301,11 +1336,14 @@
>      UNLOCK();
>  }
>  
> +#ifndef GC_WIN32_PTHREADS
> +/* win32 pthread does not support sigmask */
>  /* nothing required here... */
>  int GC_pthread_sigmask(int how, const sigset_t *set, 
> sigset_t *oset) {
>    if (!parallel_initialized) GC_init_parallel();
>    return pthread_sigmask(how, set, oset);  }
> +#endif
>  
>  int GC_pthread_detach(pthread_t thread)  { @@ -1329,7 +1367,7 @@
>      return result;
>  }
>  
> -#else /* !CYGWIN32 */
> +#else /* !GC_PTHREADS */
>  
>  /*
>   * We avoid acquiring locks here, since this doesn't seem to 
> be preemptable.
> @@ -1394,7 +1432,7 @@
>    return TRUE;
>  }
>  #endif /* GC_DLL */
> -#endif /* !CYGWIN32 */
> +#endif /* !GC_PTHREADS */
>  
>  # endif /* !MSWINCE */
>  
> Index: include/gc.h
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/include/gc.h,v
> retrieving revision 1.14
> diff -u -r1.14 gc.h
> --- include/gc.h    11 May 2007 21:55:38 -0000    1.14
> +++ include/gc.h    19 May 2007 22:12:48 -0000
> @@ -986,7 +986,8 @@
>    (int (*callback)(const char *, void *, size_t));
>  
>  
> -#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) &&
> !defined(__CYGWIN__)
> +#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) &&
> !defined(__CYGWIN__) \
> +    && !defined(GC_PTHREADS)
>  # include <windows.h>
>  
>    /*
> Index: include/gc_config_macros.h
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/include/gc_config_macros.h,v
> retrieving revision 1.7
> diff -u -r1.7 gc_config_macros.h
> --- include/gc_config_macros.h    11 May 2007 00:30:36 -0000    1.7
> +++ include/gc_config_macros.h    19 May 2007 17:03:55 -0000
> @@ -69,6 +69,11 @@
>  #   define GC_PTHREADS
>  # endif
>  
> +#if defined(GC_WIN32_PTHREADS)
> +#   define GC_WIN32_THREADS
> +#   define GC_PTHREADS
> +#endif
> +
>  #if defined(GC_THREADS) && !defined(GC_PTHREADS)  # if 
> defined(__linux__)
>  #   define GC_LINUX_THREADS
> Index: include/private/gc_locks.h
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/include/private/gc_locks.h,v
> retrieving revision 1.7
> diff -u -r1.7 gc_locks.h
> --- include/private/gc_locks.h    15 May 2007 18:57:48 -0000    1.7
> +++ include/private/gc_locks.h    21 May 2007 15:58:52 -0000
> @@ -81,16 +81,23 @@
>       /* the mapping to integers does not need to result in 
> different    */
>       /* integers for each thread, though that should be true 
> as much    */
>       /* as possible.                            */
> -#    if 1 /* Refine to exclude platforms on which pthread_t 
> is struct */
> -#    define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
> -#    define THREAD_EQUAL(id1, id2) ((id1) == (id2))
> -#       define NUMERIC_THREAD_ID_UNIQUE
> +     /* Refine to exclude platforms on which pthread_t is struct */
> +#    if !defined(GC_WIN32_PTHREADS)
> +#      define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
> +#      define THREAD_EQUAL(id1, id2) ((id1) == (id2))
> +#      define NUMERIC_THREAD_ID_UNIQUE
>  #    else
> -    /* Generic definitions that always work, but will result in    */
> -    /* poor performance and weak assertion checking.        */
> -#    define NUMERIC_THREAD_ID(id) 1l
> -#    define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
> -#       undef NUMERIC_THREAD_ID_UNIQUE
> +#      if defined(GC_WIN32_PTHREADS)
> +#     define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
> +#     define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
> +#        undef NUMERIC_THREAD_ID_UNIQUE
> +#      else
> +     /* Generic definitions that always work, but will 
> result in    */
> +     /* poor performance and weak assertion checking.        */
> +#        define NUMERIC_THREAD_ID(id) 1l
> +#     define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
> +#        undef NUMERIC_THREAD_ID_UNIQUE
> +#      endif
>  #    endif
>  #    define NO_THREAD (-1l)  /* != NUMERIC_THREAD_ID(pthread_self()) 
> for any thread */
>  
> Index: tests/test.c
> ===================================================================
> RCS file: /cvsroot/bdwgc/bdwgc/tests/test.c,v
> retrieving revision 1.5
> diff -u -r1.5 test.c
> --- tests/test.c    20 Sep 2006 01:08:14 -0000    1.5
> +++ tests/test.c    21 May 2007 19:52:18 -0000
> @@ -446,7 +446,7 @@
>   */
>  #ifdef THREADS
>  
> -# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
> +# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
>      DWORD  __stdcall tiny_reverse_test(void * arg)  # else
>      void * tiny_reverse_test(void * arg) @@ -1384,7 +1384,7 
> @@  }  # endif
>  
> -#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
> +#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
>  
>  DWORD __stdcall thr_run_one_test(void *arg)  { @@ -1580,7 +1580,6 @@
>      pthread_t th2;
>      pthread_attr_t attr;
>      int code;
> -
>  #   ifdef GC_IRIX_THREADS
>      /* Force a larger stack to be preallocated      */
>      /* Since the initial cant always grow later.    */
> @@ -1593,6 +1592,10 @@
>            (void)GC_printf("pthread_default_stacksize_np failed.\n");
>      }
>  #   endif    /* GC_HPUX_THREADS */
> +#   ifdef PTW32_STATIC_LIB
> +    pthread_win32_process_attach_np ();
> +    pthread_win32_thread_attach_np ();
> +#   endif
>      GC_INIT();
>  
>      pthread_attr_init(&attr);
> @@ -1643,6 +1646,10 @@
>      (void)fflush(stdout);
>      pthread_attr_destroy(&attr);
>      GC_printf("Completed %d collections\n", GC_gc_no);
> +#   ifdef PTW32_STATIC_LIB
> +    pthread_win32_thread_detach_np ();
> +    pthread_win32_process_detach_np ();
> +#   endif
>      return(0);
>  }
>  #endif /* GC_PTHREADS */
> -------------------------
> 
> _______________________________________________
> Gc mailing list
> Gc at linux.hpl.hp.com
> http://www.hpl.hp.com/hosted/linux/mail-archives/gc/
> 



More information about the Gc mailing list