A new kind of error: PThread errors. Used to report detected misuse in
authorsewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Tue, 4 Jun 2002 22:54:20 +0000 (22:54 +0000)
committersewardj <sewardj@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Tue, 4 Jun 2002 22:54:20 +0000 (22:54 +0000)
the pthread_* API.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@379 a5019735-40e9-0310-863c-91ae7b9d1cf9

23 files changed:
Makefile.am
addrcheck/Makefile.am
cachegrind/Makefile.am
cachegrind/docs/manual.html
corecheck/Makefile.am
coregrind/Makefile.am
coregrind/arch/x86-linux/vg_libpthread.c
coregrind/docs/manual.html
coregrind/vg_errcontext.c
coregrind/vg_include.h
coregrind/vg_libpthread.c
coregrind/vg_scheduler.c
docs/manual.html
glibc-2.2.supp
helgrind/Makefile.am
lackey/Makefile.am
memcheck/Makefile.am
memcheck/docs/manual.html
none/Makefile.am
vg_errcontext.c
vg_include.h
vg_libpthread.c
vg_scheduler.c

index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 3320b2da7d8c078acaa1b303078fa650bcde38f7..2a3f20fa89595601e965d46c4eab9781c4468d86 100644 (file)
@@ -26,7 +26,7 @@
 <a name="title">&nbsp;</a>
 <h1 align=center>Valgrind, snapshot 20020522</h1>
 <center>This manual was majorly updated on 20020501</center>
-<center>This manual was minorly updated on 20020522</center>
+<center>This manual was minorly updated on 20020603</center>
 <p>
 
 <center>
@@ -1021,7 +1021,9 @@ You can ask to add suppressions from another file, by specifying
       memory access of 1, 2, 4 or 8 bytes respectively.  Or 
       <code>Param</code>,
       meaning an invalid system call parameter error.  Or
-      <code>Free</code>, meaning an invalid or mismatching free.</li><br>
+      <code>Free</code>, meaning an invalid or mismatching free.
+      Or <code>PThread</code>, meaning any kind of complaint to do
+      with the PThreads API.</li><br>
       <p>
 
   <li>The "immediate location" specification.  For Value and Addr
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index c2b0f68e619ec9fdf8888422e0dcfdb74cada214..8a74a5c382de9da03a040184c8ee49181dca3910 100644 (file)
@@ -216,6 +216,20 @@ void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
 #include <sys/time.h> /* gettimeofday */
 
 
+/* ---------------------------------------------------
+   Ummm ..
+   ------------------------------------------------ */
+
+static
+void pthread_error ( const char* msg )
+{
+   int res;
+   VALGRIND_MAGIC_SEQUENCE(res, 0,
+                           VG_USERREQ__PTHREAD_ERROR, 
+                           msg, 0, 0, 0);
+}
+
+
 /* ---------------------------------------------------
    THREAD ATTRIBUTES
    ------------------------------------------------ */
@@ -230,8 +244,11 @@ int pthread_attr_init(pthread_attr_t *attr)
 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
 {
    if (detachstate != PTHREAD_CREATE_JOINABLE 
-       && detachstate != PTHREAD_CREATE_DETACHED)
+       && detachstate != PTHREAD_CREATE_DETACHED) {
+      pthread_error("pthread_attr_setdetachstate: "
+                    "detachstate is invalid");
       return EINVAL;
+   }
    attr->__detachstate = detachstate;
    return 0;
 }
@@ -301,6 +318,8 @@ int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
    ensure_valgrind("pthread_attr_setscope");
    if (scope == PTHREAD_SCOPE_SYSTEM)
       return 0;
+   pthread_error("pthread_attr_setscope: "
+                 "invalid or unsupported scope");
    if (scope == PTHREAD_SCOPE_PROCESS)
       return ENOTSUP;
    return EINVAL;
@@ -581,10 +600,18 @@ int pthread_detach(pthread_t th)
    VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
                            VG_USERREQ__SET_OR_GET_DETACH,
                            2 /* get */, th, 0, 0);
-   if (res == -1) /* not found */ 
+   if (res == -1) {
+      /* not found */ 
+      pthread_error("pthread_detach: "
+                    "invalid target thread");
       return ESRCH;
-   if (res == 1) /* already detached */
+   }
+   if (res == 1) { 
+      /* already detached */
+      pthread_error("pthread_detach: "
+                    "target thread is already detached");
       return EINVAL;
+   }
    if (res == 0) {
       VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
                               VG_USERREQ__SET_OR_GET_DETACH,
@@ -709,6 +736,8 @@ int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
          attr->__mutexkind = type;
          return 0;
       default:
+         pthread_error("pthread_mutexattr_settype: "
+                       "invalid type");
          return EINVAL;
    }
 }
@@ -790,12 +819,15 @@ int __pthread_mutex_destroy(pthread_mutex_t *mutex)
 {
    /* Valgrind doesn't hold any resources on behalf of the mutex, so no
       need to involve it. */
-    if (mutex->__m_count > 0)
+   if (mutex->__m_count > 0) {
+       pthread_error("pthread_mutex_destroy: "
+                     "mutex is still in use");
        return EBUSY;
-    mutex->__m_count = 0;
-    mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
-    mutex->__m_kind  = PTHREAD_MUTEX_ERRORCHECK_NP;
-    return 0;
+   }
+   mutex->__m_count = 0;
+   mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
+   mutex->__m_kind  = PTHREAD_MUTEX_ERRORCHECK_NP;
+   return 0;
 }
 
 
@@ -937,8 +969,11 @@ int pthread_setcancelstate(int state, int *oldstate)
    int res;
    ensure_valgrind("pthread_setcancelstate");
    if (state != PTHREAD_CANCEL_ENABLE
-       && state != PTHREAD_CANCEL_DISABLE) 
+       && state != PTHREAD_CANCEL_DISABLE) {
+      pthread_error("pthread_setcancelstate: "
+                    "invalid state");
       return EINVAL;
+   }
    my_assert(-1 != PTHREAD_CANCEL_ENABLE);
    my_assert(-1 != PTHREAD_CANCEL_DISABLE);
    VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
@@ -955,8 +990,11 @@ int pthread_setcanceltype(int type, int *oldtype)
    int res;
    ensure_valgrind("pthread_setcanceltype");
    if (type != PTHREAD_CANCEL_DEFERRED
-       && type != PTHREAD_CANCEL_ASYNCHRONOUS) 
+       && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
+      pthread_error("pthread_setcanceltype: "
+                    "invalid type");
       return EINVAL;
+   }
    my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
    my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
    VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
@@ -1038,7 +1076,8 @@ int pthread_sigmask(int how, const sigset_t *newmask,
       case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
       case SIG_BLOCK:   how = VKI_SIG_BLOCK; break;
       case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
-      default:          return EINVAL;
+      default: pthread_error("pthread_sigmask: invalid how");
+               return EINVAL;
    }
 
    /* Crude check */
@@ -1084,9 +1123,9 @@ int pthread_kill(pthread_t thread, int signo)
 int raise (int sig)
 {
   int retcode = pthread_kill(pthread_self(), sig);
-  if (retcode == 0)
+  if (retcode == 0) {
     return 0;
-  else {
+  else {
     errno = retcode;
     return -1;
   }
@@ -1153,7 +1192,6 @@ int __pthread_once ( pthread_once_t *once_control,
    res = __pthread_mutex_lock(&once_masterlock);
 
    if (res != 0) {
-     printf("res = %d\n",res);
       barf("pthread_once: Looks like your program's "
            "init routine calls back to pthread_once() ?!");
    }
@@ -2040,6 +2078,7 @@ int sem_init(sem_t *sem, int pshared, unsigned int value)
    vg_sem_t* vg_sem;
    ensure_valgrind("sem_init");
    if (pshared != 0) {
+      pthread_error("sem_init: unsupported pshared value");
       errno = ENOSYS;
       return -1;
    }
index 3320b2da7d8c078acaa1b303078fa650bcde38f7..2a3f20fa89595601e965d46c4eab9781c4468d86 100644 (file)
@@ -26,7 +26,7 @@
 <a name="title">&nbsp;</a>
 <h1 align=center>Valgrind, snapshot 20020522</h1>
 <center>This manual was majorly updated on 20020501</center>
-<center>This manual was minorly updated on 20020522</center>
+<center>This manual was minorly updated on 20020603</center>
 <p>
 
 <center>
@@ -1021,7 +1021,9 @@ You can ask to add suppressions from another file, by specifying
       memory access of 1, 2, 4 or 8 bytes respectively.  Or 
       <code>Param</code>,
       meaning an invalid system call parameter error.  Or
-      <code>Free</code>, meaning an invalid or mismatching free.</li><br>
+      <code>Free</code>, meaning an invalid or mismatching free.
+      Or <code>PThread</code>, meaning any kind of complaint to do
+      with the PThreads API.</li><br>
       <p>
 
   <li>The "immediate location" specification.  For Value and Addr
index 61753391c00971b07510998e3f5b3431e63aac5d..d5e0abb43dfd12bebbf5a043e8f4190ec7523105 100644 (file)
@@ -53,7 +53,9 @@ typedef
       /* Invalid read/write attempt at given size */
       Addr1, Addr2, Addr4, Addr8,
       /* Invalid or mismatching free */
-      FreeS
+      FreeS,
+      /* Pthreading error */
+      PThread
    } 
    SuppressionKind;
 
@@ -108,7 +110,9 @@ typedef
 typedef 
    enum { ValueErr, AddrErr, 
           ParamErr, UserErr, /* behaves like an anonymous ParamErr */
-          FreeErr, FreeMismatchErr }
+          FreeErr, FreeMismatchErr,
+          PThreadErr /* pthread API error */
+   }
    ErrKind;
 
 /* What kind of memory access is involved in the error? */
@@ -138,7 +142,7 @@ typedef
       Addr addr;
       /* Addr, Free, Param, User */
       AddrInfo addrinfo;
-      /* Param */
+      /* Param; hijacked for PThread as a description */
       Char* syscall_param;
       /* Param, User */
       Bool isWriteableLack;
@@ -255,6 +259,12 @@ static Bool eq_ErrContext ( Bool cheap_addr_cmp,
       return False;
 
    switch (e1->ekind) {
+      case PThreadErr:
+         if (e1->syscall_param == e2->syscall_param) 
+            return True;
+         if (0 == VG_(strcmp)(e1->syscall_param, e2->syscall_param))
+            return True;
+         return False;
       case UserErr:
       case ParamErr:
          if (e1->isWriteableLack != e2->isWriteableLack) return False;
@@ -412,6 +422,10 @@ static void pp_ErrContext ( ErrContext* ec, Bool printCount )
          VG_(pp_ExeContext)(ec->where);
          pp_AddrInfo(ec->addr, &ec->addrinfo);
          break;
+      case PThreadErr:
+         VG_(message)(Vg_UserMsg, "%s", ec->syscall_param );
+         VG_(pp_ExeContext)(ec->where);
+         break;
       default: 
          VG_(panic)("pp_ErrContext");
    }
@@ -747,6 +761,25 @@ void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
    VG_(maybe_add_context) ( &ec );
 }
 
+void VG_(record_pthread_err) ( ThreadId tid, Char* msg )
+{
+   ErrContext ec;
+   if (vg_ignore_errors) return;
+   if (!VG_(clo_instrument)) return;
+   clear_ErrContext( &ec );
+   ec.count   = 1;
+   ec.next    = NULL;
+   ec.where   = VG_(get_ExeContext)( False, VG_(threads)[tid].m_eip, 
+                                            VG_(threads)[tid].m_ebp );
+   ec.ekind   = PThreadErr;
+   ec.tid     = tid;
+   ec.syscall_param = msg;
+   ec.m_eip   = VG_(threads)[tid].m_eip;
+   ec.m_esp   = VG_(threads)[tid].m_esp;
+   ec.m_ebp   = VG_(threads)[tid].m_ebp;
+   VG_(maybe_add_context) ( &ec );
+}
+
 
 /*------------------------------*/
 
@@ -963,6 +996,7 @@ static void load_one_suppressions_file ( Char* filename )
       else if (STREQ(buf, "Addr4"))  supp->skind = Addr4;
       else if (STREQ(buf, "Addr8"))  supp->skind = Addr8;
       else if (STREQ(buf, "Free"))   supp->skind = FreeS;
+      else if (STREQ(buf, "PThread")) supp->skind = PThread;
       else goto syntax_error;
 
       if (supp->skind == Param) {
@@ -1100,7 +1134,7 @@ static Suppression* is_suppressible_error ( ErrContext* ec )
    /* See if the error context matches any suppression. */
    for (su = vg_suppressions; su != NULL; su = su->next) {
       switch (su->skind) {
-         case FreeS:
+         case FreeS:  case PThread:
          case Param:  case Value0: su_size = 0; break;
          case Value1: case Addr1:  su_size = 1; break;
          case Value2: case Addr2:  su_size = 2; break;
@@ -1122,7 +1156,11 @@ static Suppression* is_suppressible_error ( ErrContext* ec )
             if (ec->size  != su_size) continue;
             break;
          case FreeS:
-            if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
+            if (ec->ekind != FreeErr 
+                && ec->ekind != FreeMismatchErr) continue;
+            break;
+         case PThread:
+            if (ec->ekind != PThreadErr) continue;
             break;
       }
 
index ba2203063c159a20f5905d01dc77f2c0069f0fb7..ec923b18814ba70f71906f87ad6293f50bc119c9 100644 (file)
@@ -487,8 +487,11 @@ extern Bool  VG_(is_empty_arena) ( ArenaId aid );
 
 #define VG_USERREQ__NUKE_OTHER_THREADS      0x3023
 
+
 /* Cosmetic ... */
 #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101
+/* Log a pthread error from client-space.  Cosmetic. */
+#define VG_USERREQ__PTHREAD_ERROR           0x3102
 
 /* 
 In vg_constants.h:
@@ -1306,6 +1309,8 @@ extern void VG_(record_param_err) ( ThreadState* tst,
                                     Char* msg );
 extern void VG_(record_user_err) ( ThreadState* tst,
                                    Addr a, Bool isWriteLack );
+extern void VG_(record_pthread_err) ( ThreadId tid, Char* msg );
+
 
 
 /* The classification of a faulting address. */
index c2b0f68e619ec9fdf8888422e0dcfdb74cada214..8a74a5c382de9da03a040184c8ee49181dca3910 100644 (file)
@@ -216,6 +216,20 @@ void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
 #include <sys/time.h> /* gettimeofday */
 
 
+/* ---------------------------------------------------
+   Ummm ..
+   ------------------------------------------------ */
+
+static
+void pthread_error ( const char* msg )
+{
+   int res;
+   VALGRIND_MAGIC_SEQUENCE(res, 0,
+                           VG_USERREQ__PTHREAD_ERROR, 
+                           msg, 0, 0, 0);
+}
+
+
 /* ---------------------------------------------------
    THREAD ATTRIBUTES
    ------------------------------------------------ */
@@ -230,8 +244,11 @@ int pthread_attr_init(pthread_attr_t *attr)
 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
 {
    if (detachstate != PTHREAD_CREATE_JOINABLE 
-       && detachstate != PTHREAD_CREATE_DETACHED)
+       && detachstate != PTHREAD_CREATE_DETACHED) {
+      pthread_error("pthread_attr_setdetachstate: "
+                    "detachstate is invalid");
       return EINVAL;
+   }
    attr->__detachstate = detachstate;
    return 0;
 }
@@ -301,6 +318,8 @@ int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
    ensure_valgrind("pthread_attr_setscope");
    if (scope == PTHREAD_SCOPE_SYSTEM)
       return 0;
+   pthread_error("pthread_attr_setscope: "
+                 "invalid or unsupported scope");
    if (scope == PTHREAD_SCOPE_PROCESS)
       return ENOTSUP;
    return EINVAL;
@@ -581,10 +600,18 @@ int pthread_detach(pthread_t th)
    VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
                            VG_USERREQ__SET_OR_GET_DETACH,
                            2 /* get */, th, 0, 0);
-   if (res == -1) /* not found */ 
+   if (res == -1) {
+      /* not found */ 
+      pthread_error("pthread_detach: "
+                    "invalid target thread");
       return ESRCH;
-   if (res == 1) /* already detached */
+   }
+   if (res == 1) { 
+      /* already detached */
+      pthread_error("pthread_detach: "
+                    "target thread is already detached");
       return EINVAL;
+   }
    if (res == 0) {
       VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
                               VG_USERREQ__SET_OR_GET_DETACH,
@@ -709,6 +736,8 @@ int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
          attr->__mutexkind = type;
          return 0;
       default:
+         pthread_error("pthread_mutexattr_settype: "
+                       "invalid type");
          return EINVAL;
    }
 }
@@ -790,12 +819,15 @@ int __pthread_mutex_destroy(pthread_mutex_t *mutex)
 {
    /* Valgrind doesn't hold any resources on behalf of the mutex, so no
       need to involve it. */
-    if (mutex->__m_count > 0)
+   if (mutex->__m_count > 0) {
+       pthread_error("pthread_mutex_destroy: "
+                     "mutex is still in use");
        return EBUSY;
-    mutex->__m_count = 0;
-    mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
-    mutex->__m_kind  = PTHREAD_MUTEX_ERRORCHECK_NP;
-    return 0;
+   }
+   mutex->__m_count = 0;
+   mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
+   mutex->__m_kind  = PTHREAD_MUTEX_ERRORCHECK_NP;
+   return 0;
 }
 
 
@@ -937,8 +969,11 @@ int pthread_setcancelstate(int state, int *oldstate)
    int res;
    ensure_valgrind("pthread_setcancelstate");
    if (state != PTHREAD_CANCEL_ENABLE
-       && state != PTHREAD_CANCEL_DISABLE) 
+       && state != PTHREAD_CANCEL_DISABLE) {
+      pthread_error("pthread_setcancelstate: "
+                    "invalid state");
       return EINVAL;
+   }
    my_assert(-1 != PTHREAD_CANCEL_ENABLE);
    my_assert(-1 != PTHREAD_CANCEL_DISABLE);
    VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
@@ -955,8 +990,11 @@ int pthread_setcanceltype(int type, int *oldtype)
    int res;
    ensure_valgrind("pthread_setcanceltype");
    if (type != PTHREAD_CANCEL_DEFERRED
-       && type != PTHREAD_CANCEL_ASYNCHRONOUS) 
+       && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
+      pthread_error("pthread_setcanceltype: "
+                    "invalid type");
       return EINVAL;
+   }
    my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
    my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
    VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
@@ -1038,7 +1076,8 @@ int pthread_sigmask(int how, const sigset_t *newmask,
       case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
       case SIG_BLOCK:   how = VKI_SIG_BLOCK; break;
       case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
-      default:          return EINVAL;
+      default: pthread_error("pthread_sigmask: invalid how");
+               return EINVAL;
    }
 
    /* Crude check */
@@ -1084,9 +1123,9 @@ int pthread_kill(pthread_t thread, int signo)
 int raise (int sig)
 {
   int retcode = pthread_kill(pthread_self(), sig);
-  if (retcode == 0)
+  if (retcode == 0) {
     return 0;
-  else {
+  else {
     errno = retcode;
     return -1;
   }
@@ -1153,7 +1192,6 @@ int __pthread_once ( pthread_once_t *once_control,
    res = __pthread_mutex_lock(&once_masterlock);
 
    if (res != 0) {
-     printf("res = %d\n",res);
       barf("pthread_once: Looks like your program's "
            "init routine calls back to pthread_once() ?!");
    }
@@ -2040,6 +2078,7 @@ int sem_init(sem_t *sem, int pshared, unsigned int value)
    vg_sem_t* vg_sem;
    ensure_valgrind("sem_init");
    if (pshared != 0) {
+      pthread_error("sem_init: unsupported pshared value");
       errno = ENOSYS;
       return -1;
    }
index fa71fb2b4727fbcbbfc7d08b8fd3e9e13bbda58f..93309b817019e80d411a15cad4b69824e966e21b 100644 (file)
@@ -1754,7 +1754,7 @@ void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
    sp = VG_(threads)[tid].custack_used;
    if (VG_(clo_trace_sched)) {
       VG_(sprintf)(msg_buf, 
-         "cleanup_pop from slot %d", sp);
+         "cleanup_pop from slot %d", sp-1);
       print_sched_event(tid, msg_buf);
    }
    vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
@@ -1932,6 +1932,8 @@ void do__set_cancelpend ( ThreadId tid,
             "set_cancelpend for invalid tid %d", cee);
          print_sched_event(tid, msg_buf);
       }
+      VG_(record_pthread_err)( tid, 
+         "pthread_cancel: target thread does not exist, or invalid");
       SET_EDX(tid, -VKI_ESRCH);
       return;
    }
@@ -1965,6 +1967,8 @@ void do_pthread_join ( ThreadId tid,
    vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
 
    if (jee == tid) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_join: attempt to join to self");
       SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
       VG_(threads)[tid].status = VgTs_Runnable;
       return;
@@ -1979,6 +1983,8 @@ void do_pthread_join ( ThreadId tid,
        || jee >= VG_N_THREADS
        || VG_(threads)[jee].status == VgTs_Empty) {
       /* Invalid thread to join to. */
+      VG_(record_pthread_err)( tid, 
+         "pthread_join: target thread does not exist, or invalid");
       SET_EDX(tid, EINVAL);
       VG_(threads)[tid].status = VgTs_Runnable;
       return;
@@ -1990,6 +1996,9 @@ void do_pthread_join ( ThreadId tid,
       if (VG_(threads)[i].status == VgTs_WaitJoinee
           && VG_(threads)[i].joiner_jee_tid == jee) {
          /* Someone already did join on this thread */
+         VG_(record_pthread_err)( tid, 
+            "pthread_join: another thread already "
+            "in join-wait for target thread");
          SET_EDX(tid, EINVAL);
          VG_(threads)[tid].status = VgTs_Runnable;
          return;
@@ -2270,7 +2279,8 @@ void do_pthread_mutex_lock( ThreadId tid,
 
    /* POSIX doesn't mandate this, but for sanity ... */
    if (mutex == NULL) {
-      /* VG_(printf)("NULL mutex\n"); */
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_lock/trylock: mutex is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2289,7 +2299,8 @@ void do_pthread_mutex_lock( ThreadId tid,
          if (mutex->__m_count >= 0) break;
          /* else fall thru */
       default:
-         /* VG_(printf)("unknown __m_kind %d in mutex\n", mutex->__m_kind); */
+         VG_(record_pthread_err)( tid, 
+            "pthread_mutex_lock/trylock: mutex is invalid");
          SET_EDX(tid, EINVAL);
          return;
    }
@@ -2367,6 +2378,8 @@ void do_pthread_mutex_unlock ( ThreadId tid,
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (mutex == NULL) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_unlock: mutex is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2385,13 +2398,25 @@ void do_pthread_mutex_unlock ( ThreadId tid,
          if (mutex->__m_count >= 0) break;
          /* else fall thru */
       default:
+         VG_(record_pthread_err)( tid, 
+            "pthread_mutex_unlock: mutex is invalid");
          SET_EDX(tid, EINVAL);
          return;
    }
 
    /* Barf if we don't currently hold the mutex. */
-   if (mutex->__m_count == 0 /* nobody holds it */
-       || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
+   if (mutex->__m_count == 0) {
+      /* nobody holds it */
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_unlock: mutex is not locked");
+      SET_EDX(tid, EPERM);
+      return;
+   }
+
+   if ((ThreadId)mutex->__m_owner != tid) {
+      /* we don't hold it */
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_unlock: mutex is locked by a different thread");
       SET_EDX(tid, EPERM);
       return;
    }
@@ -2587,6 +2612,8 @@ void do_pthread_cond_wait ( ThreadId tid,
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (mutex == NULL || cond == NULL) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_cond_wait/timedwait: cond or mutex is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2605,6 +2632,8 @@ void do_pthread_cond_wait ( ThreadId tid,
          if (mutex->__m_count >= 0) break;
          /* else fall thru */
       default:
+         VG_(record_pthread_err)( tid, 
+            "pthread_cond_wait/timedwait: mutex is invalid");
          SET_EDX(tid, EINVAL);
          return;
    }
@@ -2612,6 +2641,9 @@ void do_pthread_cond_wait ( ThreadId tid,
    /* Barf if we don't currently hold the mutex. */
    if (mutex->__m_count == 0 /* nobody holds it */
        || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
+         VG_(record_pthread_err)( tid, 
+            "pthread_cond_wait/timedwait: mutex is unlocked "
+            "or is locked but not owned by thread");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2655,6 +2687,8 @@ void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (cond == NULL) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_cond_signal/broadcast: cond is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2738,6 +2772,8 @@ void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
              && VG_(threads)[tid].status == VgTs_Runnable);
    
    if (!is_valid_key(key)) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_key_delete: key is invalid");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2770,6 +2806,8 @@ void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (!is_valid_key(key)) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_getspecific: key is invalid");
       SET_EDX(tid, (UInt)NULL);
       return;
    }
@@ -2794,6 +2832,8 @@ void do_pthread_setspecific ( ThreadId 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;
    }
@@ -2917,7 +2957,9 @@ void do_pthread_kill ( ThreadId tid, /* me */
    vg_assert(VG_(is_valid_tid)(tid) 
              && VG_(threads)[tid].status == VgTs_Runnable);
 
-   if (!VG_(is_valid_tid)(tid)) {
+   if (!VG_(is_valid_tid)(thread)) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_kill: invalid target thread");
       SET_EDX(tid, -VKI_ESRCH);
       return;
    }
@@ -3052,6 +3094,11 @@ void do_nontrivial_clientreq ( ThreadId tid )
          SET_EDX(tid, 0);
          break;
 
+      case VG_USERREQ__PTHREAD_ERROR:
+         VG_(record_pthread_err)( tid, (Char*)(arg[1]) );
+         SET_EDX(tid, 0);
+         break;
+
       case VG_USERREQ__MAKE_NOACCESS:
       case VG_USERREQ__MAKE_WRITABLE:
       case VG_USERREQ__MAKE_READABLE:
index 3320b2da7d8c078acaa1b303078fa650bcde38f7..2a3f20fa89595601e965d46c4eab9781c4468d86 100644 (file)
@@ -26,7 +26,7 @@
 <a name="title">&nbsp;</a>
 <h1 align=center>Valgrind, snapshot 20020522</h1>
 <center>This manual was majorly updated on 20020501</center>
-<center>This manual was minorly updated on 20020522</center>
+<center>This manual was minorly updated on 20020603</center>
 <p>
 
 <center>
@@ -1021,7 +1021,9 @@ You can ask to add suppressions from another file, by specifying
       memory access of 1, 2, 4 or 8 bytes respectively.  Or 
       <code>Param</code>,
       meaning an invalid system call parameter error.  Or
-      <code>Free</code>, meaning an invalid or mismatching free.</li><br>
+      <code>Free</code>, meaning an invalid or mismatching free.
+      Or <code>PThread</code>, meaning any kind of complaint to do
+      with the PThreads API.</li><br>
       <p>
 
   <li>The "immediate location" specification.  For Value and Addr
index e58567cf7efce791ec7cc1215495a83360b44e0f..2c2dafeafd25ad6ec3098f33de5f77d6f82e6a2f 100644 (file)
 #     (optionally: caller3 name)
 #  }
 
+{
+   __pthread_mutex_unlock/__register_frame_info
+   PThread
+   fun:__pthread_mutex_unlock
+   fun:__register_frame_info
+}
 
 # even more glibc suppressions ?
 {
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 3320b2da7d8c078acaa1b303078fa650bcde38f7..2a3f20fa89595601e965d46c4eab9781c4468d86 100644 (file)
@@ -26,7 +26,7 @@
 <a name="title">&nbsp;</a>
 <h1 align=center>Valgrind, snapshot 20020522</h1>
 <center>This manual was majorly updated on 20020501</center>
-<center>This manual was minorly updated on 20020522</center>
+<center>This manual was minorly updated on 20020603</center>
 <p>
 
 <center>
@@ -1021,7 +1021,9 @@ You can ask to add suppressions from another file, by specifying
       memory access of 1, 2, 4 or 8 bytes respectively.  Or 
       <code>Param</code>,
       meaning an invalid system call parameter error.  Or
-      <code>Free</code>, meaning an invalid or mismatching free.</li><br>
+      <code>Free</code>, meaning an invalid or mismatching free.
+      Or <code>PThread</code>, meaning any kind of complaint to do
+      with the PThreads API.</li><br>
       <p>
 
   <li>The "immediate location" specification.  For Value and Addr
index 03cc0da839992066bf74673bcfbea7784d0f027a..8db9b73e6c7928dc8315094799db6f538887daa5 100644 (file)
@@ -87,6 +87,9 @@ vg_memory.o: vg_memory.c $(MANUAL_DEPS)
 vg_clientfuncs.o: vg_clientfuncs.c $(MANUAL_DEPS)
        $(COMPILE) -fno-omit-frame-pointer -c $<
 
+vg_libpthread.o: vg_libpthread.c $(MANUAL_DEPS)
+       $(COMPILE) -fno-omit-frame-pointer -c $<
+
 valgrind.so$(EXEEXT): $(valgrind_so_OBJECTS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o valgrind.so \
                $(valgrind_so_OBJECTS) $(valgrind_so_LDADD)
index 61753391c00971b07510998e3f5b3431e63aac5d..d5e0abb43dfd12bebbf5a043e8f4190ec7523105 100644 (file)
@@ -53,7 +53,9 @@ typedef
       /* Invalid read/write attempt at given size */
       Addr1, Addr2, Addr4, Addr8,
       /* Invalid or mismatching free */
-      FreeS
+      FreeS,
+      /* Pthreading error */
+      PThread
    } 
    SuppressionKind;
 
@@ -108,7 +110,9 @@ typedef
 typedef 
    enum { ValueErr, AddrErr, 
           ParamErr, UserErr, /* behaves like an anonymous ParamErr */
-          FreeErr, FreeMismatchErr }
+          FreeErr, FreeMismatchErr,
+          PThreadErr /* pthread API error */
+   }
    ErrKind;
 
 /* What kind of memory access is involved in the error? */
@@ -138,7 +142,7 @@ typedef
       Addr addr;
       /* Addr, Free, Param, User */
       AddrInfo addrinfo;
-      /* Param */
+      /* Param; hijacked for PThread as a description */
       Char* syscall_param;
       /* Param, User */
       Bool isWriteableLack;
@@ -255,6 +259,12 @@ static Bool eq_ErrContext ( Bool cheap_addr_cmp,
       return False;
 
    switch (e1->ekind) {
+      case PThreadErr:
+         if (e1->syscall_param == e2->syscall_param) 
+            return True;
+         if (0 == VG_(strcmp)(e1->syscall_param, e2->syscall_param))
+            return True;
+         return False;
       case UserErr:
       case ParamErr:
          if (e1->isWriteableLack != e2->isWriteableLack) return False;
@@ -412,6 +422,10 @@ static void pp_ErrContext ( ErrContext* ec, Bool printCount )
          VG_(pp_ExeContext)(ec->where);
          pp_AddrInfo(ec->addr, &ec->addrinfo);
          break;
+      case PThreadErr:
+         VG_(message)(Vg_UserMsg, "%s", ec->syscall_param );
+         VG_(pp_ExeContext)(ec->where);
+         break;
       default: 
          VG_(panic)("pp_ErrContext");
    }
@@ -747,6 +761,25 @@ void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
    VG_(maybe_add_context) ( &ec );
 }
 
+void VG_(record_pthread_err) ( ThreadId tid, Char* msg )
+{
+   ErrContext ec;
+   if (vg_ignore_errors) return;
+   if (!VG_(clo_instrument)) return;
+   clear_ErrContext( &ec );
+   ec.count   = 1;
+   ec.next    = NULL;
+   ec.where   = VG_(get_ExeContext)( False, VG_(threads)[tid].m_eip, 
+                                            VG_(threads)[tid].m_ebp );
+   ec.ekind   = PThreadErr;
+   ec.tid     = tid;
+   ec.syscall_param = msg;
+   ec.m_eip   = VG_(threads)[tid].m_eip;
+   ec.m_esp   = VG_(threads)[tid].m_esp;
+   ec.m_ebp   = VG_(threads)[tid].m_ebp;
+   VG_(maybe_add_context) ( &ec );
+}
+
 
 /*------------------------------*/
 
@@ -963,6 +996,7 @@ static void load_one_suppressions_file ( Char* filename )
       else if (STREQ(buf, "Addr4"))  supp->skind = Addr4;
       else if (STREQ(buf, "Addr8"))  supp->skind = Addr8;
       else if (STREQ(buf, "Free"))   supp->skind = FreeS;
+      else if (STREQ(buf, "PThread")) supp->skind = PThread;
       else goto syntax_error;
 
       if (supp->skind == Param) {
@@ -1100,7 +1134,7 @@ static Suppression* is_suppressible_error ( ErrContext* ec )
    /* See if the error context matches any suppression. */
    for (su = vg_suppressions; su != NULL; su = su->next) {
       switch (su->skind) {
-         case FreeS:
+         case FreeS:  case PThread:
          case Param:  case Value0: su_size = 0; break;
          case Value1: case Addr1:  su_size = 1; break;
          case Value2: case Addr2:  su_size = 2; break;
@@ -1122,7 +1156,11 @@ static Suppression* is_suppressible_error ( ErrContext* ec )
             if (ec->size  != su_size) continue;
             break;
          case FreeS:
-            if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
+            if (ec->ekind != FreeErr 
+                && ec->ekind != FreeMismatchErr) continue;
+            break;
+         case PThread:
+            if (ec->ekind != PThreadErr) continue;
             break;
       }
 
index ba2203063c159a20f5905d01dc77f2c0069f0fb7..ec923b18814ba70f71906f87ad6293f50bc119c9 100644 (file)
@@ -487,8 +487,11 @@ extern Bool  VG_(is_empty_arena) ( ArenaId aid );
 
 #define VG_USERREQ__NUKE_OTHER_THREADS      0x3023
 
+
 /* Cosmetic ... */
 #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101
+/* Log a pthread error from client-space.  Cosmetic. */
+#define VG_USERREQ__PTHREAD_ERROR           0x3102
 
 /* 
 In vg_constants.h:
@@ -1306,6 +1309,8 @@ extern void VG_(record_param_err) ( ThreadState* tst,
                                     Char* msg );
 extern void VG_(record_user_err) ( ThreadState* tst,
                                    Addr a, Bool isWriteLack );
+extern void VG_(record_pthread_err) ( ThreadId tid, Char* msg );
+
 
 
 /* The classification of a faulting address. */
index c2b0f68e619ec9fdf8888422e0dcfdb74cada214..8a74a5c382de9da03a040184c8ee49181dca3910 100644 (file)
@@ -216,6 +216,20 @@ void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
 #include <sys/time.h> /* gettimeofday */
 
 
+/* ---------------------------------------------------
+   Ummm ..
+   ------------------------------------------------ */
+
+static
+void pthread_error ( const char* msg )
+{
+   int res;
+   VALGRIND_MAGIC_SEQUENCE(res, 0,
+                           VG_USERREQ__PTHREAD_ERROR, 
+                           msg, 0, 0, 0);
+}
+
+
 /* ---------------------------------------------------
    THREAD ATTRIBUTES
    ------------------------------------------------ */
@@ -230,8 +244,11 @@ int pthread_attr_init(pthread_attr_t *attr)
 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
 {
    if (detachstate != PTHREAD_CREATE_JOINABLE 
-       && detachstate != PTHREAD_CREATE_DETACHED)
+       && detachstate != PTHREAD_CREATE_DETACHED) {
+      pthread_error("pthread_attr_setdetachstate: "
+                    "detachstate is invalid");
       return EINVAL;
+   }
    attr->__detachstate = detachstate;
    return 0;
 }
@@ -301,6 +318,8 @@ int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
    ensure_valgrind("pthread_attr_setscope");
    if (scope == PTHREAD_SCOPE_SYSTEM)
       return 0;
+   pthread_error("pthread_attr_setscope: "
+                 "invalid or unsupported scope");
    if (scope == PTHREAD_SCOPE_PROCESS)
       return ENOTSUP;
    return EINVAL;
@@ -581,10 +600,18 @@ int pthread_detach(pthread_t th)
    VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
                            VG_USERREQ__SET_OR_GET_DETACH,
                            2 /* get */, th, 0, 0);
-   if (res == -1) /* not found */ 
+   if (res == -1) {
+      /* not found */ 
+      pthread_error("pthread_detach: "
+                    "invalid target thread");
       return ESRCH;
-   if (res == 1) /* already detached */
+   }
+   if (res == 1) { 
+      /* already detached */
+      pthread_error("pthread_detach: "
+                    "target thread is already detached");
       return EINVAL;
+   }
    if (res == 0) {
       VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
                               VG_USERREQ__SET_OR_GET_DETACH,
@@ -709,6 +736,8 @@ int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
          attr->__mutexkind = type;
          return 0;
       default:
+         pthread_error("pthread_mutexattr_settype: "
+                       "invalid type");
          return EINVAL;
    }
 }
@@ -790,12 +819,15 @@ int __pthread_mutex_destroy(pthread_mutex_t *mutex)
 {
    /* Valgrind doesn't hold any resources on behalf of the mutex, so no
       need to involve it. */
-    if (mutex->__m_count > 0)
+   if (mutex->__m_count > 0) {
+       pthread_error("pthread_mutex_destroy: "
+                     "mutex is still in use");
        return EBUSY;
-    mutex->__m_count = 0;
-    mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
-    mutex->__m_kind  = PTHREAD_MUTEX_ERRORCHECK_NP;
-    return 0;
+   }
+   mutex->__m_count = 0;
+   mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
+   mutex->__m_kind  = PTHREAD_MUTEX_ERRORCHECK_NP;
+   return 0;
 }
 
 
@@ -937,8 +969,11 @@ int pthread_setcancelstate(int state, int *oldstate)
    int res;
    ensure_valgrind("pthread_setcancelstate");
    if (state != PTHREAD_CANCEL_ENABLE
-       && state != PTHREAD_CANCEL_DISABLE) 
+       && state != PTHREAD_CANCEL_DISABLE) {
+      pthread_error("pthread_setcancelstate: "
+                    "invalid state");
       return EINVAL;
+   }
    my_assert(-1 != PTHREAD_CANCEL_ENABLE);
    my_assert(-1 != PTHREAD_CANCEL_DISABLE);
    VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
@@ -955,8 +990,11 @@ int pthread_setcanceltype(int type, int *oldtype)
    int res;
    ensure_valgrind("pthread_setcanceltype");
    if (type != PTHREAD_CANCEL_DEFERRED
-       && type != PTHREAD_CANCEL_ASYNCHRONOUS) 
+       && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
+      pthread_error("pthread_setcanceltype: "
+                    "invalid type");
       return EINVAL;
+   }
    my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
    my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
    VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
@@ -1038,7 +1076,8 @@ int pthread_sigmask(int how, const sigset_t *newmask,
       case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
       case SIG_BLOCK:   how = VKI_SIG_BLOCK; break;
       case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
-      default:          return EINVAL;
+      default: pthread_error("pthread_sigmask: invalid how");
+               return EINVAL;
    }
 
    /* Crude check */
@@ -1084,9 +1123,9 @@ int pthread_kill(pthread_t thread, int signo)
 int raise (int sig)
 {
   int retcode = pthread_kill(pthread_self(), sig);
-  if (retcode == 0)
+  if (retcode == 0) {
     return 0;
-  else {
+  else {
     errno = retcode;
     return -1;
   }
@@ -1153,7 +1192,6 @@ int __pthread_once ( pthread_once_t *once_control,
    res = __pthread_mutex_lock(&once_masterlock);
 
    if (res != 0) {
-     printf("res = %d\n",res);
       barf("pthread_once: Looks like your program's "
            "init routine calls back to pthread_once() ?!");
    }
@@ -2040,6 +2078,7 @@ int sem_init(sem_t *sem, int pshared, unsigned int value)
    vg_sem_t* vg_sem;
    ensure_valgrind("sem_init");
    if (pshared != 0) {
+      pthread_error("sem_init: unsupported pshared value");
       errno = ENOSYS;
       return -1;
    }
index fa71fb2b4727fbcbbfc7d08b8fd3e9e13bbda58f..93309b817019e80d411a15cad4b69824e966e21b 100644 (file)
@@ -1754,7 +1754,7 @@ void do__cleanup_pop ( ThreadId tid, CleanupEntry* cu )
    sp = VG_(threads)[tid].custack_used;
    if (VG_(clo_trace_sched)) {
       VG_(sprintf)(msg_buf, 
-         "cleanup_pop from slot %d", sp);
+         "cleanup_pop from slot %d", sp-1);
       print_sched_event(tid, msg_buf);
    }
    vg_assert(sp >= 0 && sp <= VG_N_CLEANUPSTACK);
@@ -1932,6 +1932,8 @@ void do__set_cancelpend ( ThreadId tid,
             "set_cancelpend for invalid tid %d", cee);
          print_sched_event(tid, msg_buf);
       }
+      VG_(record_pthread_err)( tid, 
+         "pthread_cancel: target thread does not exist, or invalid");
       SET_EDX(tid, -VKI_ESRCH);
       return;
    }
@@ -1965,6 +1967,8 @@ void do_pthread_join ( ThreadId tid,
    vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
 
    if (jee == tid) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_join: attempt to join to self");
       SET_EDX(tid, EDEADLK); /* libc constant, not a kernel one */
       VG_(threads)[tid].status = VgTs_Runnable;
       return;
@@ -1979,6 +1983,8 @@ void do_pthread_join ( ThreadId tid,
        || jee >= VG_N_THREADS
        || VG_(threads)[jee].status == VgTs_Empty) {
       /* Invalid thread to join to. */
+      VG_(record_pthread_err)( tid, 
+         "pthread_join: target thread does not exist, or invalid");
       SET_EDX(tid, EINVAL);
       VG_(threads)[tid].status = VgTs_Runnable;
       return;
@@ -1990,6 +1996,9 @@ void do_pthread_join ( ThreadId tid,
       if (VG_(threads)[i].status == VgTs_WaitJoinee
           && VG_(threads)[i].joiner_jee_tid == jee) {
          /* Someone already did join on this thread */
+         VG_(record_pthread_err)( tid, 
+            "pthread_join: another thread already "
+            "in join-wait for target thread");
          SET_EDX(tid, EINVAL);
          VG_(threads)[tid].status = VgTs_Runnable;
          return;
@@ -2270,7 +2279,8 @@ void do_pthread_mutex_lock( ThreadId tid,
 
    /* POSIX doesn't mandate this, but for sanity ... */
    if (mutex == NULL) {
-      /* VG_(printf)("NULL mutex\n"); */
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_lock/trylock: mutex is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2289,7 +2299,8 @@ void do_pthread_mutex_lock( ThreadId tid,
          if (mutex->__m_count >= 0) break;
          /* else fall thru */
       default:
-         /* VG_(printf)("unknown __m_kind %d in mutex\n", mutex->__m_kind); */
+         VG_(record_pthread_err)( tid, 
+            "pthread_mutex_lock/trylock: mutex is invalid");
          SET_EDX(tid, EINVAL);
          return;
    }
@@ -2367,6 +2378,8 @@ void do_pthread_mutex_unlock ( ThreadId tid,
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (mutex == NULL) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_unlock: mutex is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2385,13 +2398,25 @@ void do_pthread_mutex_unlock ( ThreadId tid,
          if (mutex->__m_count >= 0) break;
          /* else fall thru */
       default:
+         VG_(record_pthread_err)( tid, 
+            "pthread_mutex_unlock: mutex is invalid");
          SET_EDX(tid, EINVAL);
          return;
    }
 
    /* Barf if we don't currently hold the mutex. */
-   if (mutex->__m_count == 0 /* nobody holds it */
-       || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
+   if (mutex->__m_count == 0) {
+      /* nobody holds it */
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_unlock: mutex is not locked");
+      SET_EDX(tid, EPERM);
+      return;
+   }
+
+   if ((ThreadId)mutex->__m_owner != tid) {
+      /* we don't hold it */
+      VG_(record_pthread_err)( tid, 
+         "pthread_mutex_unlock: mutex is locked by a different thread");
       SET_EDX(tid, EPERM);
       return;
    }
@@ -2587,6 +2612,8 @@ void do_pthread_cond_wait ( ThreadId tid,
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (mutex == NULL || cond == NULL) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_cond_wait/timedwait: cond or mutex is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2605,6 +2632,8 @@ void do_pthread_cond_wait ( ThreadId tid,
          if (mutex->__m_count >= 0) break;
          /* else fall thru */
       default:
+         VG_(record_pthread_err)( tid, 
+            "pthread_cond_wait/timedwait: mutex is invalid");
          SET_EDX(tid, EINVAL);
          return;
    }
@@ -2612,6 +2641,9 @@ void do_pthread_cond_wait ( ThreadId tid,
    /* Barf if we don't currently hold the mutex. */
    if (mutex->__m_count == 0 /* nobody holds it */
        || (ThreadId)mutex->__m_owner != tid /* we don't hold it */) {
+         VG_(record_pthread_err)( tid, 
+            "pthread_cond_wait/timedwait: mutex is unlocked "
+            "or is locked but not owned by thread");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2655,6 +2687,8 @@ void do_pthread_cond_signal_or_broadcast ( ThreadId tid,
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (cond == NULL) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_cond_signal/broadcast: cond is NULL");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2738,6 +2772,8 @@ void do_pthread_key_delete ( ThreadId tid, pthread_key_t key )
              && VG_(threads)[tid].status == VgTs_Runnable);
    
    if (!is_valid_key(key)) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_key_delete: key is invalid");
       SET_EDX(tid, EINVAL);
       return;
    }
@@ -2770,6 +2806,8 @@ void do_pthread_getspecific ( ThreadId tid, pthread_key_t key )
              && VG_(threads)[tid].status == VgTs_Runnable);
 
    if (!is_valid_key(key)) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_getspecific: key is invalid");
       SET_EDX(tid, (UInt)NULL);
       return;
    }
@@ -2794,6 +2832,8 @@ void do_pthread_setspecific ( ThreadId 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;
    }
@@ -2917,7 +2957,9 @@ void do_pthread_kill ( ThreadId tid, /* me */
    vg_assert(VG_(is_valid_tid)(tid) 
              && VG_(threads)[tid].status == VgTs_Runnable);
 
-   if (!VG_(is_valid_tid)(tid)) {
+   if (!VG_(is_valid_tid)(thread)) {
+      VG_(record_pthread_err)( tid, 
+         "pthread_kill: invalid target thread");
       SET_EDX(tid, -VKI_ESRCH);
       return;
    }
@@ -3052,6 +3094,11 @@ void do_nontrivial_clientreq ( ThreadId tid )
          SET_EDX(tid, 0);
          break;
 
+      case VG_USERREQ__PTHREAD_ERROR:
+         VG_(record_pthread_err)( tid, (Char*)(arg[1]) );
+         SET_EDX(tid, 0);
+         break;
+
       case VG_USERREQ__MAKE_NOACCESS:
       case VG_USERREQ__MAKE_WRITABLE:
       case VG_USERREQ__MAKE_READABLE: