mirror of
git://sourceware.org/git/glibc.git
synced 2025-02-17 13:00:43 +08:00
Update.
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:
parent
1edf26ffc6
commit
8e605e789d
12
ChangeLog
12
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.
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -48,4 +48,8 @@ libc {
|
||||
# Special functions.
|
||||
__libc_freeres;
|
||||
}
|
||||
GLIBC_2.2 {
|
||||
# m*
|
||||
mcheck_pedantic;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user