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.
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 );
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) { };
{
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));
}
}
{
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));
}
}
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");
}
__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.
}
+/* ---------------------------------------------------
+ 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
------------------------------------------------ */
int detached, res;
CleanupEntry cu;
pthread_key_t key;
+ void** specifics_ptr;
/* Run this thread's cleanup handlers. */
while (1) {
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,
__attribute__((noreturn))
void thread_wrapper ( NewThreadInfo* info )
{
- int res;
int attr__detachstate;
void* (*root_fn) ( void* );
void* arg;
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
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
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)
}
-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;
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]);
}
/* 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
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");
}
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;
}
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;
= 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
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;
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;
}
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,
}
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);
}
}
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);
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:
(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]),
(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: