about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--linuxthreads/ChangeLog1
-rw-r--r--linuxthreads/Versions3
-rw-r--r--linuxthreads/semaphore.c125
-rw-r--r--linuxthreads/semaphore.h10
-rw-r--r--locale/programs/localedef.c4
-rw-r--r--malloc/Versions4
-rw-r--r--malloc/mcheck.c95
-rw-r--r--malloc/mcheck.h9
9 files changed, 255 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 4655cc37c0..70d4a9d8ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2000-03-26  Ulrich Drepper  <drepper@redhat.com>
+
+	* include/features.h: Undef and document __USE_XOPEN2K.
+
+	* malloc/mcheck.c: Implement pedantic checking of all allocated blocks
+	whenever a function is called.  Initiated by calling mcheck_pedantic
+	instead of mcheck.
+	* malloc/mcheck.h: Declare mcheck_pedantic.
+	* malloc/Versions [libc] (GLIBC_2.2): Add mcheck_pedantic.
+	* locale/programs/localdef.c: Use mcheck_pedantic instead of mcheck
+	for now.
+
 2000-03-26  Roland McGrath  <roland@baalperazim.frob.com>
 
 	* dlfcn/dlopen.c: Use <shlib-compat.h> macros.
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 2c513dc8f3..5039a12ba8 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -3,6 +3,7 @@
 	* semaphore.c (sem_timedwait): New function.
 	Patch by Carl Mailloux <carlm@oricom.ca>.
 	* semaphore.h: Declare sem_timedwait.
+	* Versions [libpthread] (GLIBC_2.2): Add sem_timedwait.
 
 2000-03-26  Roland McGrath  <roland@baalperazim.frob.com>
 
diff --git a/linuxthreads/Versions b/linuxthreads/Versions
index 1b9de67b67..2e3673e1a1 100644
--- a/linuxthreads/Versions
+++ b/linuxthreads/Versions
@@ -129,5 +129,8 @@ libpthread {
     __pthread_rwlock_init; __pthread_rwlock_destroy; __pthread_rwlock_rdlock;
     __pthread_rwlock_tryrdlock; __pthread_rwlock_wrlock;
     __pthread_rwlock_trywrlock; __pthread_rwlock_unlock;
+
+    # New functions from IEEE Std. 10003.1-200x.
+    sem_timedwait;
   }
 }
diff --git a/linuxthreads/semaphore.c b/linuxthreads/semaphore.c
index c4a4f6e042..3344d0d859 100644
--- a/linuxthreads/semaphore.c
+++ b/linuxthreads/semaphore.c
@@ -190,6 +190,131 @@ int sem_unlink(const char *name)
   return -1;
 }
 
+int sem_timedwait(sem_t *sem, const struct timespec *abstime)
+{
+  pthread_descr self = thread_self();
+  pthread_extricate_if extr;
+  int already_canceled = 0;
+  int was_signalled = 0;
+  sigjmp_buf jmpbuf;
+  sigset_t unblock;
+  sigset_t initial_mask;
+
+  __pthread_lock((struct _pthread_fastlock *) &sem->__sem_lock, self);
+  if (sem->__sem_value > 0) {
+    --sem->__sem_value;
+    __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
+    return 0;
+  }
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
+    /* The standard requires that if the function would block and the
+       time value is illegal, the function returns with an error.  */
+    __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
+    return EINVAL;
+  }
+
+  /* Set up extrication interface */
+  extr.pu_object = sem;
+  extr.pu_extricate_func = new_sem_extricate_func;
+
+  /* Register extrication interface */
+  __pthread_set_own_extricate_if(self, &extr);
+  /* Enqueue only if not already cancelled. */
+  if (!(THREAD_GETMEM(self, p_canceled)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
+    enqueue(&sem->__sem_waiting, self);
+  else
+    already_canceled = 1;
+  __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
+
+  if (already_canceled) {
+    __pthread_set_own_extricate_if(self, 0);
+    pthread_exit(PTHREAD_CANCELED);
+  }
+
+  /* Set up a longjmp handler for the restart signal, unblock
+     the signal and sleep. */
+
+  if (sigsetjmp(jmpbuf, 1) == 0) {
+    THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
+    THREAD_SETMEM(self, p_signal, 0);
+    /* Unblock the restart signal */
+    sigemptyset(&unblock);
+    sigaddset(&unblock, __pthread_sig_restart);
+    sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
+
+    while (1) {
+        struct timeval now;
+        struct timespec reltime;
+
+        /* Compute a time offset relative to now.  */
+        __gettimeofday (&now, NULL);
+        reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
+        reltime.tv_sec = abstime->tv_sec - now.tv_sec;
+        if (reltime.tv_nsec < 0) {
+          reltime.tv_nsec += 1000000000;
+          reltime.tv_sec -= 1;
+        }
+
+        /* Sleep for the required duration. If woken by a signal,
+           resume waiting as required by Single Unix Specification.  */
+        if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
+          break;
+      }
+
+    /* Block the restart signal again */
+    sigprocmask(SIG_SETMASK, &initial_mask, NULL);
+    was_signalled = 0;
+  } else {
+    was_signalled = 1;
+  }
+  THREAD_SETMEM(self, p_signal_jmp, NULL);
+
+  /* Now was_signalled is true if we exited the above code
+     due to the delivery of a restart signal.  In that case,
+     everything is cool. We have been removed from the queue
+     by the other thread, and consumed its signal.
+
+     Otherwise we this thread woke up spontaneously, or due to a signal other
+     than restart. The next thing to do is to try to remove the thread
+     from the queue. This may fail due to a race against another thread
+     trying to do the same. In the failed case, we know we were signalled,
+     and we may also have to consume a restart signal. */
+
+  if (!was_signalled) {
+    int was_on_queue;
+
+    /* __pthread_lock will queue back any spurious restarts that
+       may happen to it. */
+
+    __pthread_lock((struct _pthread_fastlock *)&sem->__sem_lock, self);
+    was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
+    __pthread_unlock((struct _pthread_fastlock *)&sem->__sem_lock);
+
+    if (was_on_queue) {
+      __pthread_set_own_extricate_if(self, 0);
+      return ETIMEDOUT;
+    }
+
+    /* Eat the outstanding restart() from the signaller */
+    suspend(self);
+  }
+ __pthread_set_own_extricate_if(self, 0);
+
+  /* Terminate only if the wakeup came from cancellation. */
+  /* Otherwise ignore cancellation because we got the semaphore. */
+
+  if (THREAD_GETMEM(self, p_woken_by_cancel)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+    THREAD_SETMEM(self, p_woken_by_cancel, 0);
+    pthread_exit(PTHREAD_CANCELED);
+  }
+  /* We got the semaphore */
+  return 0;
+}
+
+
 versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
 versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
 versioned_symbol (libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1);
diff --git a/linuxthreads/semaphore.h b/linuxthreads/semaphore.h
index 21a9deaafe..583b65ea18 100644
--- a/linuxthreads/semaphore.h
+++ b/linuxthreads/semaphore.h
@@ -17,6 +17,10 @@
 
 #include <features.h>
 #include <sys/types.h>
+#ifdef __USE_XOPEN2K
+# define __need_timespec
+# include <time.h>
+#endif
 
 #ifndef _PTHREAD_DESCR_DEFINED
 /* Thread descriptors.  Needed for `sem_t' definition.  */
@@ -66,6 +70,12 @@ extern int sem_unlink (__const char *__name) __THROW;
 /* Wait for SEM being posted.  */
 extern int sem_wait (sem_t *__sem) __THROW;
 
+#ifdef __USE_XOPEN2K
+/* Similar to `sem_wait' but wait only until ABSTIME.  */
+extern int sem_timedwait (sem_t *__sem, __const struct timespec *__abstime)
+     __THROW;
+#endif
+
 /* Test whether SEM is posted.  */
 extern int sem_trywait (sem_t *__sem) __THROW;
 
diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index 86b8bff5da..9def7a38ad 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
 
@@ -136,7 +136,7 @@ main (int argc, char *argv[])
   int remaining;
 
   /* Enable `malloc' debugging.  */
-  mcheck (NULL);
+  mcheck_pedantic (NULL);
 
   /* Set initial values for global variables.  */
   copy_list = NULL;
diff --git a/malloc/Versions b/malloc/Versions
index 1a4454f22e..43207549a6 100644
--- a/malloc/Versions
+++ b/malloc/Versions
@@ -48,4 +48,8 @@ libc {
     # Special functions.
     __libc_freeres;
   }
+  GLIBC_2.2 {
+    # m*
+    mcheck_pedantic;
+  }
 }
diff --git a/malloc/mcheck.c b/malloc/mcheck.c
index 85258e9dd0..42e8e71174 100644
--- a/malloc/mcheck.c
+++ b/malloc/mcheck.c
@@ -1,5 +1,5 @@
 /* Standard debugging hooks for `malloc'.
-   Copyright (C) 1990,91,92,93,94,95,96,97,99 Free Software Foundation, Inc.
+   Copyright (C) 1990-1997, 1999, 2000 Free Software Foundation, Inc.
    Written May 1989 by Mike Haertel.
 
    This library is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
 # define _MALLOC_INTERNAL
 # include <malloc.h>
 # include <mcheck.h>
+# include <stdint.h>
 # include <stdio.h>
 # include <libintl.h>
 #endif
@@ -46,10 +47,19 @@ static void (*abortfunc) __P ((enum mcheck_status));
 
 struct hdr
   {
-    __malloc_size_t size;		/* Exact size requested by user.  */
+    __malloc_size_t size;	/* Exact size requested by user.  */
     unsigned long int magic;	/* Magic number to check header integrity.  */
+    struct hdr *prev;
+    struct hdr *next;
   };
 
+/* This is the beginning of the list of all memory blocks allocated.
+   It is only constructed if the pedantic testing is requested.  */
+static struct hdr *root;
+
+/* Nonzero if pedentic checking of all blocks is requested.  */
+static int pedantic;
+
 #if defined _LIBC || defined STDC_HEADERS || defined USG
 # include <string.h>
 # define flood memset
@@ -73,7 +83,7 @@ checkhdr (hdr)
      const struct hdr *hdr;
 {
   enum mcheck_status status;
-  switch (hdr->magic)
+  switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
     {
     default:
       status = MCHECK_HEAD;
@@ -93,17 +103,77 @@ checkhdr (hdr)
   return status;
 }
 
+static void check_all __P ((void));
+static void
+check_all ()
+{
+  /* Walk through all the active blocks and test whether they were tempered
+     with.  */
+  struct hdr *runp = root;
+
+  while (runp != NULL)
+    {
+      (void) checkhdr (runp);
+
+      runp = runp->next;
+    }
+}
+
+static void unlink_blk __P ((struct hdr *ptr));
+static void
+unlink_blk (ptr)
+     struct hdr *ptr;
+{
+  if (ptr->next != NULL)
+    {
+      ptr->next->prev = ptr->prev;
+      ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
+				      + (uintptr_t) ptr->next->next);
+    }
+  if (ptr->prev != NULL)
+    {
+      ptr->prev->next = ptr->next;
+      ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
+				      + (uintptr_t) ptr->prev->next);
+    }
+  else
+    root = ptr->next;
+}
+
+static void link_blk  __P ((struct hdr *ptr));
+static void
+link_blk (hdr)
+     struct hdr *hdr;
+{
+  hdr->prev = NULL;
+  hdr->next = root;
+  root = hdr;
+  hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
+
+  /* And the next block.  */
+  if (hdr->next != NULL)
+    {
+      hdr->next->prev = hdr;
+      hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
+				      + (uintptr_t) hdr->next->next);
+    }
+}
+
 static void freehook __P ((__ptr_t, const __ptr_t));
 static void
 freehook (ptr, caller)
      __ptr_t ptr;
      const __ptr_t caller;
 {
+  if (pedantic)
+    check_all ();
   if (ptr)
     {
       struct hdr *hdr = ((struct hdr *) ptr) - 1;
       checkhdr (hdr);
       hdr->magic = MAGICFREE;
+      unlink_blk (hdr);
+      hdr->prev = hdr->next = NULL;
       flood (ptr, FREEFLOOD, hdr->size);
       ptr = (__ptr_t) hdr;
     }
@@ -123,6 +193,9 @@ mallochook (size, caller)
 {
   struct hdr *hdr;
 
+  if (pedantic)
+    check_all ();
+
   __malloc_hook = old_malloc_hook;
   if (old_malloc_hook != NULL)
     hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
@@ -134,7 +207,7 @@ mallochook (size, caller)
     return NULL;
 
   hdr->size = size;
-  hdr->magic = MAGICWORD;
+  link_blk (hdr);
   ((char *) &hdr[1])[size] = MAGICBYTE;
   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
   return (__ptr_t) (hdr + 1);
@@ -150,12 +223,16 @@ reallochook (ptr, size, caller)
   struct hdr *hdr;
   __malloc_size_t osize;
 
+  if (pedantic)
+    check_all ();
+
   if (ptr)
     {
       hdr = ((struct hdr *) ptr) - 1;
       osize = hdr->size;
 
       checkhdr (hdr);
+      unlink_blk (hdr);
       if (size < osize)
 	flood ((char *) ptr + size, FREEFLOOD, osize - size);
     }
@@ -181,7 +258,7 @@ reallochook (ptr, size, caller)
     return NULL;
 
   hdr->size = size;
-  hdr->magic = MAGICWORD;
+  link_blk (hdr);
   ((char *) &hdr[1])[size] = MAGICBYTE;
   if (size > osize)
     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
@@ -244,6 +321,14 @@ mcheck (func)
   return mcheck_used ? 0 : -1;
 }
 
+int
+mcheck_pedantic (func)
+      void (*func) __P ((enum mcheck_status));
+{
+  pedantic = 1;
+  return mcheck (func);
+}
+
 enum mcheck_status
 mprobe (__ptr_t ptr)
 {
diff --git a/malloc/mcheck.h b/malloc/mcheck.h
index 5cf2bcd598..9460547d08 100644
--- a/malloc/mcheck.h
+++ b/malloc/mcheck.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -41,6 +41,13 @@ enum mcheck_status
    null, the standard function prints on stderr and then calls `abort'.  */
 extern int mcheck (void (*__abortfunc) (enum mcheck_status)) __THROW;
 
+/* Similar to `mcheck´ but performs checks for all block whenever one of
+   the memory handling functions is called.  This can be very slow.  */
+extern int mcheck_pedantic (void (*__abortfunc) (enum mcheck_status)) __THROW;
+
+/* Similar to `mcheck', but perform tests on all blocks every time.  */
+extern int mcheck_verbose (void (*func) __P ((enum mcheck_status)));
+
 /* Check for aberrations in a particular malloc'd block.  You must have
    called `mcheck' already.  These are the same checks that `mcheck' does
    when you free or reallocate a block.  */