]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
merge revs
authorJulian Seward <jseward@acm.org>
Sun, 13 Oct 2002 11:52:00 +0000 (11:52 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 13 Oct 2002 11:52:00 +0000 (11:52 +0000)
   acconfig.h 1.4
   configure.in 1.70
   coregrind/vg_libpthread.c 1.95, 1.97 and 1.98
   coregrind/vg_libpthread_unimp.c 1.33
   coregrind/vg_scheduler.c 1.88
   coregrind/vg_include.h 1.88

Merge support for Red Hat 8 from HEAD.  That means principally the new
thread-specific-data stuff.

git-svn-id: svn://svn.valgrind.org/valgrind/branches/VALGRIND_1_0_BRANCH@1215

acconfig.h
configure.in
vg_include.h
vg_libpthread.c
vg_libpthread_unimp.c
vg_scheduler.c

index aa5ffc3d3f56262a59a806cdc52d0ac1796615fd..5e9821355dfe2f57174c71975bc998d8be328da2 100644 (file)
@@ -6,6 +6,7 @@
 
 #undef GLIBC_2_1
 #undef GLIBC_2_2
+#undef GLIBC_2_3
 
 #undef XFREE_3
 #undef XFREE_4
index cb42b2317826997f32b6ff3321f49c9394293f8e..903a5c60275007fe58d294abcd8463efecec8ee7 100644 (file)
@@ -131,6 +131,16 @@ AC_EGREP_CPP([GLIBC_22], [
 ],
 glibc="2.2")
 
+AC_EGREP_CPP([GLIBC_23], [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 3)
+  GLIBC_23
+ #endif
+#endif
+],
+glibc="2.3")
+
 case "${glibc}" in
      2.1)
        AC_MSG_RESULT(2.1 family)
@@ -144,9 +154,18 @@ case "${glibc}" in
        DEFAULT_SUPP="${DEFAULT_SUPP} glibc-2.2.supp"
        ;;
 
+     2.3)
+       AC_MSG_RESULT(2.3 family)
+       AC_DEFINE(GLIBC_2_3)
+       ## Use the same suppression for as for 2.2.
+       ## This is a horrible hack that should be gotten
+       ## rid of.  JRS, 20021007.
+       DEFAULT_SUPP="${DEFAULT_SUPP} glibc-2.2.supp"
+       ;;
+
      *)
        AC_MSG_RESULT(unsupported version)
-       AC_MSG_ERROR([Valgrind requires the glibc version 2.1 or 2.2])
+       AC_MSG_ERROR([Valgrind requires the glibc version 2.1, 2.2 or 2.3])
        ;;
 esac
 
index e8ad84a18572aa5158385151e4bfcb021a25e179..36b295b4aec7989884d87efc941ad7ed017f1fa6 100644 (file)
@@ -498,13 +498,14 @@ extern Bool  VG_(is_empty_arena) ( ArenaId aid );
 #define VG_USERREQ__PTHREAD_COND_BROADCAST  0x3012
 #define VG_USERREQ__PTHREAD_KEY_CREATE      0x3013
 #define VG_USERREQ__PTHREAD_KEY_DELETE      0x3014
-#define VG_USERREQ__PTHREAD_SETSPECIFIC     0x3015
-#define VG_USERREQ__PTHREAD_GETSPECIFIC     0x3016
+#define VG_USERREQ__PTHREAD_SETSPECIFIC_PTR 0x3015
+#define VG_USERREQ__PTHREAD_GETSPECIFIC_PTR 0x3016
 #define VG_USERREQ__READ_MILLISECOND_TIMER  0x3017
 #define VG_USERREQ__PTHREAD_SIGMASK         0x3018
 #define VG_USERREQ__SIGWAIT                 0x3019
 #define VG_USERREQ__PTHREAD_KILL            0x301A
 #define VG_USERREQ__PTHREAD_YIELD           0x301B
+#define VG_USERREQ__PTHREAD_KEY_VALIDATE    0x301C
 
 #define VG_USERREQ__CLEANUP_PUSH            0x3020
 #define VG_USERREQ__CLEANUP_POP             0x3021
@@ -660,8 +661,13 @@ typedef
       Int          custack_used;
       CleanupEntry custack[VG_N_CLEANUPSTACK];
 
-      /* thread-specific data */
-      void* specifics[VG_N_THREAD_KEYS];
+      /* A pointer to the thread's-specific-data.  This is handled
+         almost entirely from vg_libpthread.c.  We just provide hooks
+         to get and set this ptr.  This is either NULL, indicating the
+         thread has read/written none of its specifics so far, OR
+         points to a void*[VG_N_THREAD_KEYS], allocated and
+         deallocated in vg_libpthread.c. */
+      void** specifics_ptr;
 
       /* This thread's blocked-signals mask.  Semantics is that for a
          signal to be delivered to this thread, the signal must not be
index 5972dfa640c23d24a84cf7ca46bc7fb76ac20818..17ab75fb23389946b18f267e1cc01e5c71d2d154 100644 (file)
 
 static void wait_for_fd_to_be_readable_or_erring ( int fd );
 
+static
+int my_do_syscall1 ( int syscallno, int arg1 );
+
 static
 int my_do_syscall2 ( int syscallno, 
                      int arg1, int arg2 );
 
+static
+int my_do_syscall3 ( int syscallno, 
+                     int arg1, int arg2, int arg3 );
+
+
+#ifdef GLIBC_2_3
+   /* kludge by JRS (not from glibc) ... */
+   typedef void* __locale_t;
+
+   /* Copied from locale/locale.h in glibc-2.2.93 sources */
+   /* This value can be passed to `uselocale' and may be returned by
+      it.  Passing this value to any other function has undefined
+      behavior.  */
+#  define LC_GLOBAL_LOCALE       ((__locale_t) -1L)
+   extern __locale_t __uselocale ( __locale_t );
+#endif
+
+static
+void init_libc_tsd_keys ( void );
+
 
 /* ---------------------------------------------------------------------
    Helpers.  We have to be pretty self-sufficient.
@@ -99,20 +122,18 @@ int get_pt_trace_level ( void )
    return res;
 }
 
-
 static
 void my_exit ( int arg )
 {
-   int __res;
-   __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
-                     : "=a" (__res)
-                     : "0" (__NR_exit),
-                       "c" (arg) );
-   /* We don't bother to mention the fact that this asm trashes %ebx,
-      since it won't return.  If you ever do let it return ... fix
-      this! */
+   my_do_syscall1(__NR_exit, arg);
+   /*NOTREACHED*/
 }
 
+static
+void my_write ( int fd, const void *buf, int count )
+{
+   my_do_syscall3(__NR_write, fd, (int)buf, count );
+}
 
 /* We need this guy -- it's in valgrind.so. */
 extern void VG_(startup) ( void );
@@ -143,7 +164,7 @@ void barf ( char* str )
    strcat(buf, "\nvalgrind's libpthread.so: ");
    strcat(buf, str);
    strcat(buf, "\n\n");
-   write(2, buf, strlen(buf));
+   my_write(2, buf, strlen(buf));
    my_exit(1);
    /* We have to persuade gcc into believing this doesn't return. */
    while (1) { };
@@ -154,10 +175,10 @@ static void ignored ( char* msg )
 {
    if (get_pt_trace_level() >= 0) {
       char* ig = "valgrind's libpthread.so: IGNORED call to: ";
-      write(2, ig, strlen(ig));
-      write(2, msg, strlen(msg));
+      my_write(2, ig, strlen(ig));
+      my_write(2, msg, strlen(msg));
       ig = "\n";
-      write(2, ig, strlen(ig));
+      my_write(2, ig, strlen(ig));
    }
 }
 
@@ -165,10 +186,10 @@ static void kludged ( char* msg )
 {
    if (get_pt_trace_level() >= 0) {
       char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
-      write(2, ig, strlen(ig));
-      write(2, msg, strlen(msg));
+      my_write(2, ig, strlen(ig));
+      my_write(2, msg, strlen(msg));
       ig = "\n";
-      write(2, ig, strlen(ig));
+      my_write(2, ig, strlen(ig));
    }
 }
 
@@ -181,10 +202,10 @@ __attribute__((noreturn))
 void vgPlain_unimp ( char* what )
 {
    char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
-   write(2, ig, strlen(ig));
-   write(2, what, strlen(what));
+   my_write(2, ig, strlen(ig));
+   my_write(2, what, strlen(what));
    ig = "\n";
-   write(2, ig, strlen(ig));
+   my_write(2, ig, strlen(ig));
    barf("Please report this bug to me at: jseward@acm.org");
 }
 
@@ -211,6 +232,27 @@ void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
                              __FILE__, __LINE__,                     \
                               __PRETTY_FUNCTION__), 0)))
 
+static
+void my_free ( void* ptr )
+{
+   int res;
+   VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
+                           VG_USERREQ__FREE, ptr, 0, 0, 0);
+   my_assert(res == 0);
+}
+
+
+static
+void* my_malloc ( int nbytes )
+{
+   void* res;
+   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+                           VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
+   my_assert(res != (void*)0);
+   return res;
+}
+
+
 
 /* ---------------------------------------------------------------------
    Pass pthread_ calls to Valgrind's request mechanism.
@@ -234,6 +276,24 @@ void pthread_error ( const char* msg )
 }
 
 
+/* ---------------------------------------------------
+   Here so it can be inlined without complaint.
+   ------------------------------------------------ */
+
+__inline__
+pthread_t pthread_self(void)
+{
+   int tid;
+   ensure_valgrind("pthread_self");
+   VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
+                           VG_USERREQ__PTHREAD_GET_THREADID,
+                           0, 0, 0, 0);
+   if (tid < 1 || tid >= VG_N_THREADS)
+      barf("pthread_self: invalid ThreadId");
+   return tid;
+}
+
+
 /* ---------------------------------------------------
    THREAD ATTRIBUTES
    ------------------------------------------------ */
@@ -425,6 +485,7 @@ void thread_exit_wrapper ( void* ret_val )
    int           detached, res;
    CleanupEntry  cu;
    pthread_key_t key;
+   void**        specifics_ptr;
 
    /* Run this thread's cleanup handlers. */
    while (1) {
@@ -453,6 +514,15 @@ void thread_exit_wrapper ( void* ret_val )
       my_assert(res == -1);
    }
 
+   /* Free up my specifics space, if any. */
+   VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
+                           VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
+                           pthread_self(), 0, 0, 0);
+   my_assert(specifics_ptr != (void**)3);
+   my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
+   if (specifics_ptr != NULL)
+      my_free(specifics_ptr);
+
    /* Decide on my final disposition. */
    VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
                            VG_USERREQ__SET_OR_GET_DETACH, 
@@ -497,7 +567,6 @@ static
 __attribute__((noreturn))
 void thread_wrapper ( NewThreadInfo* info )
 {
-   int   res;
    int   attr__detachstate;
    void* (*root_fn) ( void* );
    void* arg;
@@ -508,9 +577,7 @@ void thread_wrapper ( NewThreadInfo* info )
    arg               = info->arg;
 
    /* Free up the arg block that pthread_create malloced. */
-   VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
-                           VG_USERREQ__FREE, info, 0, 0, 0);
-   my_assert(res == 0);
+   my_free(info);
 
    /* Minimally observe the attributes supplied. */
    if (attr__detachstate != PTHREAD_CREATE_DETACHED
@@ -519,6 +586,15 @@ void thread_wrapper ( NewThreadInfo* info )
    if (attr__detachstate == PTHREAD_CREATE_DETACHED)
       pthread_detach(pthread_self());
 
+#  ifdef GLIBC_2_3
+   /* Set this thread's locale to the global (default) locale.  A hack
+      in support of glibc-2.3.  This does the biz for the all new
+      threads; the root thread is done with a horrible hack in
+      init_libc_tsd_keys() below.
+   */
+   __uselocale(LC_GLOBAL_LOCALE);
+#  endif
+
    /* The root function might not return.  But if it does we simply
       move along to thread_exit_wrapper.  All other ways out for the
       thread (cancellation, or calling pthread_exit) lead there
@@ -563,11 +639,13 @@ pthread_create (pthread_t *__restrict __thredd,
 
    ensure_valgrind("pthread_create");
 
+   /* make sure the tsd keys, and hence locale info, are initialised
+      before we get into complications making new threads. */
+   init_libc_tsd_keys();
+
    /* Allocate space for the arg block.  thread_wrapper will free
       it. */
-   VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
-                           VG_USERREQ__MALLOC, 
-                           sizeof(NewThreadInfo), 0, 0, 0);
+   info = my_malloc(sizeof(NewThreadInfo));
    my_assert(info != NULL);
 
    if (__attr)
@@ -608,19 +686,6 @@ void pthread_exit(void *retval)
 }
 
 
-pthread_t pthread_self(void)
-{
-   int tid;
-   ensure_valgrind("pthread_self");
-   VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
-                           VG_USERREQ__PTHREAD_GET_THREADID,
-                           0, 0, 0, 0);
-   if (tid < 1 || tid >= VG_N_THREADS)
-      barf("pthread_self: invalid ThreadId");
-   return tid;
-}
-
-
 int pthread_detach(pthread_t th)
 {
    int res;
@@ -1201,43 +1266,140 @@ int pause ( void )
    THREAD-SPECIFICs
    ------------------------------------------------ */
 
+static
+int key_is_valid (pthread_key_t key)
+{
+   int res;
+   VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
+                           VG_USERREQ__PTHREAD_KEY_VALIDATE,
+                           key, 0, 0, 0);
+   my_assert(res != 2);
+   return res;
+}
+
+
+/* Returns NULL if thread is invalid.  Otherwise, if the thread
+   already has a specifics area, return that.  Otherwise allocate it
+   one. */
+static
+void** get_or_allocate_specifics_ptr ( pthread_t thread )
+{
+   int    res, i;
+   void** specifics_ptr;
+   ensure_valgrind("get_or_allocate_specifics_ptr");
+
+   /* Returns zero if the thread has no specific_ptr.  One if thread
+      is invalid.  Otherwise, the specific_ptr value.  This is
+      allocated with my_malloc and so is aligned and cannot be
+      confused with 1 or 3. */
+   VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
+                           VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
+                           thread, 0, 0, 0);
+   my_assert(specifics_ptr != (void**)3);
+
+   if (specifics_ptr == (void**)1) 
+      return NULL; /* invalid thread */
+
+   if (specifics_ptr != NULL)
+      return specifics_ptr; /* already has a specifics ptr. */
+
+   /* None yet ... allocate a new one.  Should never fail. */
+   specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
+   my_assert(specifics_ptr != NULL);
+
+   VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
+                           VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
+                           specifics_ptr, 0, 0, 0);
+   my_assert(res == 0);
+
+   /* POSIX sez: "Upon thread creation, the value NULL shall be
+      associated with all defined keys in the new thread."  This
+      allocation is in effect a delayed allocation of the specific
+      data for a thread, at its first-use.  Hence we initialise it
+      here. */
+   for (i = 0; i < VG_N_THREAD_KEYS; i++) {
+      specifics_ptr[i] = NULL;
+   }
+
+   return specifics_ptr;   
+}
+
+
 int __pthread_key_create(pthread_key_t *key,  
                          void  (*destr_function)  (void *))
 {
-   int res;
+   void** specifics_ptr;
+   int    res, i;
    ensure_valgrind("pthread_key_create");
-   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+
+   /* This writes *key if successful.  It should never fail. */
+   VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
                            VG_USERREQ__PTHREAD_KEY_CREATE,
                            key, destr_function, 0, 0);
+   my_assert(res == 0);
+
+   /* POSIX sez: "Upon key creation, the value NULL shall be
+      associated with the new key in all active threads." */
+   for (i = 0; i < VG_N_THREADS; i++) {
+      specifics_ptr = get_or_allocate_specifics_ptr(i);
+      /* we get NULL if i is an invalid thread. */
+      if (specifics_ptr != NULL)
+         specifics_ptr[*key] = NULL;
+   }
+
    return res;
 }
 
 int pthread_key_delete(pthread_key_t key)
 {
-   static int moans = N_MOANS;
-   if (moans-- > 0) 
-      ignored("pthread_key_delete");
+   int res;
+   ensure_valgrind("pthread_key_create");
+   if (!key_is_valid(key))
+      return EINVAL;
+   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+                           VG_USERREQ__PTHREAD_KEY_DELETE,
+                           key, 0, 0, 0);
+   my_assert(res == 0);
    return 0;
 }
 
 int __pthread_setspecific(pthread_key_t key, const void *pointer)
 {
-   int res;
+   void** specifics_ptr;
    ensure_valgrind("pthread_setspecific");
-   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
-                           VG_USERREQ__PTHREAD_SETSPECIFIC,
-                           key, pointer, 0, 0);
-   return res;
+   
+   if (!key_is_valid(key))
+      return EINVAL;
+
+   specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
+   specifics_ptr[key] = (void*)pointer;
+   return 0;
 }
 
 void * __pthread_getspecific(pthread_key_t key)
 {
-   int res;
+   void** specifics_ptr;
    ensure_valgrind("pthread_getspecific");
-   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
-                           VG_USERREQ__PTHREAD_GETSPECIFIC,
-                           key, 0 , 0, 0);
-   return (void*)res;
+
+   if (!key_is_valid(key))
+      return NULL;
+
+   specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
+   return specifics_ptr[key];
+}
+
+
+static
+void ** __pthread_getspecific_addr(pthread_key_t key)
+{
+   void** specifics_ptr;
+   ensure_valgrind("pthread_getspecific_addr");
+
+   if (!key_is_valid(key))
+      return NULL;
+
+   specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
+   return &(specifics_ptr[key]);
 }
 
 
@@ -1391,11 +1553,14 @@ struct __res_state* __res_state ( void )
 /* The allowable keys (indices) (all 3 of them). 
    From sysdeps/pthread/bits/libc-tsd.h
 */
-#define N_LIBC_TSD_EXTRA_KEYS 0
-
+/* as per glibc anoncvs HEAD of 20021001. */
 enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
                         _LIBC_TSD_KEY_DL_ERROR,
                         _LIBC_TSD_KEY_RPC_VARS,
+                        _LIBC_TSD_KEY_LOCALE,
+                        _LIBC_TSD_KEY_CTYPE_B,
+                        _LIBC_TSD_KEY_CTYPE_TOLOWER,
+                        _LIBC_TSD_KEY_CTYPE_TOUPPER,
                         _LIBC_TSD_KEY_N };
 
 /* Auto-initialising subsystem.  libc_specifics_inited is set 
@@ -1403,31 +1568,60 @@ enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
 static int             libc_specifics_inited    = 0;
 static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
 
+
 /* These are the keys we must initialise the first time. */
-static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
-                                         + N_LIBC_TSD_EXTRA_KEYS];
+static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
 
-/* Initialise the keys, if they are not already initialise. */
+
+/* Initialise the keys, if they are not already initialised. */
 static
 void init_libc_tsd_keys ( void )
 {
    int res, i;
    pthread_key_t k;
 
-   res = pthread_mutex_lock(&libc_specifics_inited_mx);
+   /* Don't fall into deadlock if we get called again whilst we still
+      hold the lock, via the __uselocale() call herein. */
+   if (libc_specifics_inited != 0)
+      return;
+
+   /* Take the lock. */
+   res = __pthread_mutex_lock(&libc_specifics_inited_mx);
    if (res != 0) barf("init_libc_tsd_keys: lock");
 
-   if (libc_specifics_inited == 0) {
-      /* printf("INIT libc specifics\n"); */
-      libc_specifics_inited = 1;
-      for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
-         res = pthread_key_create(&k, NULL);
-        if (res != 0) barf("init_libc_tsd_keys: create");
-         libc_specifics_keys[i] = k;
-      }
+   /* Now test again, to be sure there is no mistake. */
+   if (libc_specifics_inited != 0) {
+      res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
+      if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
+      return;
+   }
+
+   /* Actually do the initialisation. */
+   /* printf("INIT libc specifics\n"); */
+   for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
+      res = __pthread_key_create(&k, NULL);
+      if (res != 0) barf("init_libc_tsd_keys: create");
+      libc_specifics_keys[i] = k;
    }
 
-   res = pthread_mutex_unlock(&libc_specifics_inited_mx);
+   /* Signify init done. */
+   libc_specifics_inited = 1;
+
+#  ifdef GLIBC_2_3
+   /* Set the initialising thread's locale to the global (default)
+      locale.  A hack in support of glibc-2.3.  This does the biz for
+      the root thread.  For all other threads we run this in
+      thread_wrapper(), which does the real work of
+      pthread_create(). */
+   /* assert that we are the root thread.  I don't know if this is
+      really a valid assertion to make; if it breaks I'll reconsider
+      it. */
+   my_assert(pthread_self() == 1);
+   __uselocale(LC_GLOBAL_LOCALE);
+#  endif
+
+   /* Unlock and return. */
+   res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
    if (res != 0) barf("init_libc_tsd_keys: unlock");
 }
 
@@ -1436,18 +1630,12 @@ static int
 libc_internal_tsd_set ( enum __libc_tsd_key_t key, 
                         const void * pointer )
 {
-   int        res;
-   static int moans = N_MOANS;
+   int res;
    /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
-   if (key < _LIBC_TSD_KEY_MALLOC 
-       || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
+   if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
       barf("libc_internal_tsd_set: invalid key");
-   if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
-      fprintf(stderr, 
-         "valgrind's libpthread.so: libc_internal_tsd_set: "
-         "dubious key %d\n", key);
    init_libc_tsd_keys();
-   res = pthread_setspecific(libc_specifics_keys[key], pointer);
+   res = __pthread_setspecific(libc_specifics_keys[key], pointer);
    if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
    return 0;
 }
@@ -1455,25 +1643,17 @@ libc_internal_tsd_set ( enum __libc_tsd_key_t key,
 static void *
 libc_internal_tsd_get ( enum __libc_tsd_key_t key )
 {
-   void*      v;
-   static int moans = N_MOANS;
+   void* v;
    /* printf("GET GET GET key %d\n", key); */
-   if (key < _LIBC_TSD_KEY_MALLOC 
-       || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
+   if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
       barf("libc_internal_tsd_get: invalid key");
-   if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
-      fprintf(stderr, 
-         "valgrind's libpthread.so: libc_internal_tsd_get: "
-         "dubious key %d\n", key);
    init_libc_tsd_keys();
-   v = pthread_getspecific(libc_specifics_keys[key]);
+   v = __pthread_getspecific(libc_specifics_keys[key]);
    /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
    return v;
 }
 
 
-
-
 int (*__libc_internal_tsd_set)
     (enum __libc_tsd_key_t key, const void * pointer)
    = libc_internal_tsd_set;
@@ -1483,6 +1663,26 @@ void* (*__libc_internal_tsd_get)
    = libc_internal_tsd_get;
 
 
+#ifdef GLIBC_2_3
+/* This one was first spotted be me in the glibc-2.2.93 sources. */
+static void**
+libc_internal_tsd_address ( enum __libc_tsd_key_t key )
+{
+   void** v;
+   /* printf("ADDR ADDR ADDR key %d\n", key); */
+   if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
+      barf("libc_internal_tsd_address: invalid key");
+   init_libc_tsd_keys();
+   v = __pthread_getspecific_addr(libc_specifics_keys[key]);
+   return v;
+}
+
+void ** (*__libc_internal_tsd_address) 
+        (enum __libc_tsd_key_t key)
+   = libc_internal_tsd_address;
+#endif
+
+
 /* ---------------------------------------------------------------------
    These are here (I think) because they are deemed cancellation
    points by POSIX.  For the moment we'll simply pass the call along
index f3938ec9e69f44e6e6e13becd3dd4bcefe3ba40e..458c1a06f440f16680f97cf454f557ad70c79a8b 100644 (file)
@@ -34,6 +34,8 @@
    Give a binding for everything the real libpthread.so binds.
    ------------------------------------------------------------------ */
 
+#include "vg_include.h"  /* For GLIBC_2_3, or not, as the case may be */
+
 extern void vgPlain_unimp ( char* );
 #define unimp(str) vgPlain_unimp(str)
 
@@ -163,6 +165,13 @@ void sem_unlink ( void )  { unimp("sem_unlink"); }
 
 void __pthread_clock_gettime ( void ) { unimp("__pthread_clock_gettime"); }
 void __pthread_clock_settime ( void ) { unimp("__pthread_clock_settime"); }
+#if defined(GLIBC_2_2) || defined(GLIBC_2_3)
+/* Needed for Red Hat 8.0 */
+__asm__(".symver __pthread_clock_gettime,"
+        "__pthread_clock_gettime@GLIBC_PRIVATE");
+__asm__(".symver __pthread_clock_settime,"
+        "__pthread_clock_settime@GLIBC_PRIVATE");
+#endif
 
 #if 0
 void pthread_create@@GLIBC_2.1 ( void )  { unimp("pthread_create@@GLIBC_2.1"); }
index b4fe6247eb396ccfee0bc3846bb6099059ec4e92..8690c1b376558669ec4ef1ec3fca4cab4e18285f 100644 (file)
@@ -528,7 +528,6 @@ void increment_epoch ( void )
 static 
 void mostly_clear_thread_record ( ThreadId tid )
 {
-   Int j;
    vg_assert(tid >= 0 && tid < VG_N_THREADS);
    VG_(threads)[tid].tid                  = tid;
    VG_(threads)[tid].status               = VgTs_Empty;
@@ -546,8 +545,7 @@ void mostly_clear_thread_record ( ThreadId tid )
    VG_(threads)[tid].n_signals_returned = 0;
    VG_(ksigemptyset)(&VG_(threads)[tid].sig_mask);
    VG_(ksigemptyset)(&VG_(threads)[tid].sigs_waited_for);
-   for (j = 0; j < VG_N_THREAD_KEYS; j++)
-      VG_(threads)[tid].specifics[j] = NULL;
+   VG_(threads)[tid].specifics_ptr = NULL;
 }
 
 
@@ -2674,6 +2672,32 @@ Bool is_valid_key ( ThreadKey k )
    return True;
 }
 
+
+/* Return in %EDX a value of 1 if the key is valid, else 0. */
+static
+void do_pthread_key_validate ( ThreadId tid,
+                               pthread_key_t key )
+{
+   Char msg_buf[100];
+
+   if (VG_(clo_trace_pthread_level) >= 1) {
+      VG_(sprintf)(msg_buf, "pthread_key_validate    key %p", 
+                            key );
+      print_pthread_event(tid, msg_buf);
+   }
+
+   vg_assert(sizeof(pthread_key_t) == sizeof(ThreadKey));
+   vg_assert(VG_(is_valid_tid)(tid) 
+             && VG_(threads)[tid].status == VgTs_Runnable);
+
+   if (is_valid_key((ThreadKey)key)) {
+      SET_EDX(tid, 1);
+   } else {
+      SET_EDX(tid, 0);
+   }
+}
+
+
 static
 void do_pthread_key_create ( ThreadId tid,
                              pthread_key_t* key,
@@ -2742,66 +2766,57 @@ void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
    }
 
    vg_thread_keys[key].inuse = False;
-
-   /* Optional.  We're not required to do this, although it shouldn't
-      make any difference to programs which use the key/specifics
-      functions correctly.  */
-#  if 1
-   for (tid = 1; tid < VG_N_THREADS; tid++) {
-      if (VG_(threads)[tid].status != VgTs_Empty)
-         VG_(threads)[tid].specifics[key] = NULL;
-   }
-#  endif
+   SET_EDX(tid, 0);
 }
 
 
+/* Get the .specific_ptr for a thread.  Return 1 if the thread-slot
+   isn't in use, so that client-space can scan all thread slots.  1
+   cannot be confused with NULL or a legitimately-aligned specific_ptr
+   value. */
 static 
-void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
+void do_pthread_getspecific_ptr ( ThreadId tid )
 {
-   Char msg_buf[100];
+   void** specifics_ptr;
+   Char   msg_buf[100];
+
    if (VG_(clo_trace_pthread_level) >= 1) {
-      VG_(sprintf)(msg_buf, "pthread_getspecific      key %d", 
-                            key );
+      VG_(sprintf)(msg_buf, "pthread_getspecific_ptr" );
       print_pthread_event(tid, msg_buf);
    }
 
-   vg_assert(VG_(is_valid_tid)(tid) 
-             && VG_(threads)[tid].status == VgTs_Runnable);
+   vg_assert(VG_(is_valid_or_empty_tid)(tid));
 
-   if (!is_valid_key(key)) {
-      VG_(record_pthread_err)( tid, 
-         "pthread_getspecific: key is invalid");
-      SET_EDX(tid, (UInt)NULL);
+   if (VG_(threads)[tid].status == VgTs_Empty) {
+      SET_EDX(tid, 1);
       return;
    }
 
-   SET_EDX(tid, (UInt)VG_(threads)[tid].specifics[key]);
+   specifics_ptr = VG_(threads)[tid].specifics_ptr;
+
+#  define IS_ALIGNED4_ADDR(aaa_p) (0 == (((UInt)(aaa_p)) & 3))
+   vg_assert(specifics_ptr == NULL 
+             || IS_ALIGNED4_ADDR(specifics_ptr));
+#  undef IS_ALIGNED4_ADDR
+
+   SET_EDX(tid, (UInt)specifics_ptr);
 }
 
 
 static
-void do_pthread_setspecific ( ThreadId tid, 
-                              pthread_key_t key, 
-                              void *pointer )
+void do_pthread_setspecific_ptr ( ThreadId tid, void** ptr )
 {
    Char msg_buf[100];
    if (VG_(clo_trace_pthread_level) >= 1) {
-      VG_(sprintf)(msg_buf, "pthread_setspecific      key %d, ptr %p", 
-                            key, pointer );
+      VG_(sprintf)(msg_buf, "pthread_setspecific_ptr  ptr %p", 
+                            ptr );
       print_pthread_event(tid, msg_buf);
    }
 
    vg_assert(VG_(is_valid_tid)(tid) 
              && VG_(threads)[tid].status == VgTs_Runnable);
 
-   if (!is_valid_key(key)) {
-      VG_(record_pthread_err)( tid, 
-         "pthread_setspecific: key is invalid");
-      SET_EDX(tid, EINVAL);
-      return;
-   }
-
-   VG_(threads)[tid].specifics[key] = pointer;
+   VG_(threads)[tid].specifics_ptr = ptr;
    SET_EDX(tid, 0);
 }
 
@@ -2823,12 +2838,19 @@ void do__get_key_destr_and_spec ( ThreadId tid,
    }
    vg_assert(VG_(is_valid_tid)(tid));
    vg_assert(key >= 0 && key < VG_N_THREAD_KEYS);
+
    if (!vg_thread_keys[key].inuse) {
       SET_EDX(tid, -1);
       return;
    }
+
    cu->fn = vg_thread_keys[key].destructor;
-   cu->arg = VG_(threads)[tid].specifics[key];
+   if (VG_(threads)[tid].specifics_ptr == NULL) {
+      cu->arg = NULL;
+   } else {
+      cu->arg = VG_(threads)[tid].specifics_ptr[key];
+   }
+
    if (VG_(clo_instrument))
       VGM_(make_readable)( (Addr)cu, sizeof(CleanupEntry) );
    SET_EDX(tid, 0);
@@ -3165,8 +3187,8 @@ void do_client_request ( ThreadId tid )
          do_pthread_mutex_unlock( tid, (void *)(arg[1]) );
          break;
 
-      case VG_USERREQ__PTHREAD_GETSPECIFIC:
-        do_pthread_getspecific ( tid, (UInt)(arg[1]) );
+      case VG_USERREQ__PTHREAD_GETSPECIFIC_PTR:
+        do_pthread_getspecific_ptr ( tid );
          break;
 
       case VG_USERREQ__SET_CANCELTYPE:
@@ -3221,6 +3243,11 @@ void do_client_request ( ThreadId tid )
             (pthread_cond_t *)(arg[1]) );
          break;
 
+      case VG_USERREQ__PTHREAD_KEY_VALIDATE:
+        do_pthread_key_validate ( tid, 
+                                   (pthread_key_t)(arg[1]) );
+        break;
+
       case VG_USERREQ__PTHREAD_KEY_CREATE:
         do_pthread_key_create ( tid, 
                                  (pthread_key_t*)(arg[1]),
@@ -3232,10 +3259,9 @@ void do_client_request ( ThreadId tid )
                                  (pthread_key_t)(arg[1]) );
         break;
 
-      case VG_USERREQ__PTHREAD_SETSPECIFIC:
-        do_pthread_setspecific ( tid, 
-                                  (pthread_key_t)(arg[1]),
-                                 (void*)(arg[2]) );
+      case VG_USERREQ__PTHREAD_SETSPECIFIC_PTR:
+        do_pthread_setspecific_ptr ( tid, 
+                                     (void**)(arg[1]) );
         break;
 
       case VG_USERREQ__PTHREAD_SIGMASK: