From 8e605e789df868763e388dca7040538c1de41b85 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 27 Mar 2000 05:36:34 +0000 Subject: [PATCH] Update. 2000-03-26 Ulrich Drepper * 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. --- ChangeLog | 12 +++++ linuxthreads/ChangeLog | 1 + linuxthreads/Versions | 3 ++ linuxthreads/semaphore.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ linuxthreads/semaphore.h | 10 ++++ locale/programs/localedef.c | 4 +- malloc/Versions | 4 ++ malloc/mcheck.c | 95 +++++++++++++++++++++++++++++++-- malloc/mcheck.h | 9 +++- 9 files changed, 255 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4655cc3..70d4a9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2000-03-26 Ulrich Drepper + + * 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 * dlfcn/dlopen.c: Use macros. diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index 2c513dc..5039a12 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -3,6 +3,7 @@ * semaphore.c (sem_timedwait): New function. Patch by Carl Mailloux . * semaphore.h: Declare sem_timedwait. + * Versions [libpthread] (GLIBC_2.2): Add sem_timedwait. 2000-03-26 Roland McGrath diff --git a/linuxthreads/Versions b/linuxthreads/Versions index 1b9de67..2e3673e 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 c4a4f6e..3344d0d 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 21a9dea..583b65e 100644 --- a/linuxthreads/semaphore.h +++ b/linuxthreads/semaphore.h @@ -17,6 +17,10 @@ #include #include +#ifdef __USE_XOPEN2K +# define __need_timespec +# include +#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 86b8bff..9def7a3 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 , 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 1a4454f..4320754 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 85258e9..42e8e71 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 # include +# include # include # include #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 # 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 5cf2bcd..9460547 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. */ -- 2.7.4