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.
This commit is contained in:
Ulrich Drepper 2000-03-27 05:36:34 +00:00
parent 1edf26ffc6
commit 8e605e789d
9 changed files with 255 additions and 8 deletions

View File

@ -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.

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -48,4 +48,8 @@ libc {
# Special functions.
__libc_freeres;
}
GLIBC_2.2 {
# m*
mcheck_pedantic;
}
}

View File

@ -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)
{

View File

@ -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. */