mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-01-24 15:25:00 +08:00
317 lines
10 KiB
C
317 lines
10 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* Copyright by the Board of Trustees of the University of Illinois. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the COPYING file, which can be found at the root of the source code *
|
|
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*
|
|
* Purpose: Provides internal function tracing in the form of a stack.
|
|
* The FUNC_ENTER() macro adds the function name to the function
|
|
* stack whenever a function is entered.
|
|
* As the functions return with FUNC_LEAVE,
|
|
* entries are removed from the stack.
|
|
*
|
|
* A function stack has a fixed maximum size. If this size is
|
|
* exceeded then the stack will be truncated and only the
|
|
* first called functions will have entries on the stack. This is
|
|
* expected to be a rare condition.
|
|
*
|
|
*/
|
|
|
|
#include "H5private.h" /* Generic Functions */
|
|
#include "H5CSprivate.h" /* Function stack */
|
|
#include "H5Eprivate.h" /* Error handling */
|
|
|
|
#ifdef H5_HAVE_CODESTACK
|
|
|
|
#define H5CS_MIN_NSLOTS 16 /* Minimum number of records in an function stack */
|
|
|
|
/* A function stack */
|
|
typedef struct H5CS_t {
|
|
unsigned nused; /* Number of records currently used in stack */
|
|
unsigned nalloc; /* Number of records current allocated for stack */
|
|
const char **rec; /* Array of function records */
|
|
} H5CS_t;
|
|
|
|
#ifdef H5_HAVE_THREADSAFE
|
|
/*
|
|
* The per-thread function stack. pthread_once() initializes a special
|
|
* key that will be used by all threads to create a stack specific to
|
|
* each thread individually. The association of stacks to threads will
|
|
* be handled by the pthread library.
|
|
*
|
|
* In order for this macro to work, H5CS_get_my_stack() must be preceeded
|
|
* by "H5CS_t *fstack =".
|
|
*/
|
|
static H5CS_t *H5CS__get_stack(void);
|
|
#define H5CS_get_my_stack() H5CS__get_stack()
|
|
#else /* H5_HAVE_THREADSAFE */
|
|
/*
|
|
* The function stack. Eventually we'll have some sort of global table so each
|
|
* thread has it's own stack. The stacks will be created on demand when the
|
|
* thread first calls H5CS_push(). */
|
|
H5CS_t H5CS_stack_g[1];
|
|
#define H5CS_get_my_stack() (H5CS_stack_g + 0)
|
|
#endif /* H5_HAVE_THREADSAFE */
|
|
|
|
#ifdef H5_HAVE_THREADSAFE
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5CS__get_stack
|
|
*
|
|
* Purpose: Support function for H5CS_get_my_stack() to initialize and
|
|
* acquire per-thread function stack.
|
|
*
|
|
* Return: Success: function stack (H5CS_t *)
|
|
*
|
|
* Failure: NULL
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
* February 6, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static H5CS_t *
|
|
H5CS__get_stack(void)
|
|
{
|
|
H5CS_t *fstack;
|
|
|
|
FUNC_ENTER_STATIC_NOERR_NOFS
|
|
|
|
fstack = H5TS_get_thread_local_value(H5TS_funcstk_key_g);
|
|
if (!fstack) {
|
|
/* No associated value with current thread - create one */
|
|
#ifdef H5_HAVE_WIN_THREADS
|
|
fstack = (H5CS_t *)LocalAlloc(
|
|
LPTR, sizeof(H5CS_t)); /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */
|
|
#else
|
|
fstack = (H5CS_t *)HDmalloc(
|
|
sizeof(H5CS_t)); /* Don't use H5MM_malloc() here, it causes infinite recursion */
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
HDassert(fstack);
|
|
|
|
/* Set the thread-specific info */
|
|
fstack->nused = 0;
|
|
fstack->nalloc = 0;
|
|
fstack->rec = NULL;
|
|
|
|
/* (It's not necessary to release this in this API, it is
|
|
* released by the "key destructor" set up in the H5TS
|
|
* routines. See calls to pthread_key_create() in H5TS.c -QAK)
|
|
*/
|
|
H5TS_set_thread_local_value(H5TS_funcstk_key_g, (void *)fstack);
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI_NOFS(fstack)
|
|
} /* end H5CS__get_stack() */
|
|
#endif /* H5_HAVE_THREADSAFE */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5CS_print_stack
|
|
*
|
|
* Purpose: Prints a function stack.
|
|
*
|
|
* Return: Non-negative on success/Negative on failure
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
* Thursday, February 6, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5CS_print_stack(const H5CS_t *fstack, FILE *stream)
|
|
{
|
|
const int indent = 2; /* Indention level */
|
|
int i; /* Local index ariable */
|
|
|
|
/* Don't push this function on the function stack... :-) */
|
|
FUNC_ENTER_NOAPI_NOERR_NOFS
|
|
|
|
/* Sanity check */
|
|
HDassert(fstack);
|
|
|
|
/* Default to outputting information to stderr */
|
|
if (!stream)
|
|
stream = stderr;
|
|
|
|
HDfprintf(stream, "HDF5-DIAG: Function stack from %s ", H5_lib_vers_info_g);
|
|
/* try show the process or thread id in multiple processes cases*/
|
|
HDfprintf(stream, "thread %" PRIu64 ".", H5TS_thread_id());
|
|
if (fstack && fstack->nused > 0)
|
|
HDfprintf(stream, " Back trace follows.");
|
|
HDfputc('\n', stream);
|
|
|
|
for (i = fstack->nused - 1; i >= 0; --i)
|
|
HDfprintf(stream, "%*s#%03d: Routine: %s\n", indent, "", i, fstack->rec[i]);
|
|
|
|
FUNC_LEAVE_NOAPI_NOFS(SUCCEED)
|
|
} /* end H5CS_print_stack() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5CS_push
|
|
*
|
|
* Purpose: Pushes a new record onto function stack for the current
|
|
* thread.
|
|
*
|
|
* Return: Non-negative on success/Negative on failure
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
* Thursday, February 6, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5CS_push(const char *func_name)
|
|
{
|
|
H5CS_t *fstack = H5CS_get_my_stack(); /* Current function stack for library */
|
|
|
|
/* Don't push this function on the function stack... :-) */
|
|
FUNC_ENTER_NOAPI_NOERR_NOFS
|
|
|
|
/* Sanity check */
|
|
HDassert(fstack);
|
|
HDassert(fstack->nused <= fstack->nalloc);
|
|
HDassert(func_name);
|
|
|
|
/* Check if we need to expand the stack of records */
|
|
if (fstack->nused == fstack->nalloc) {
|
|
size_t na = MAX((fstack->nalloc * 2), H5CS_MIN_NSLOTS);
|
|
|
|
/* Don't use H5MM_realloc here */
|
|
const char **x = (const char **)HDrealloc(fstack->rec, na * sizeof(const char *));
|
|
|
|
/* (Avoid returning an error from this routine, currently -QAK) */
|
|
HDassert(x);
|
|
fstack->rec = x;
|
|
fstack->nalloc = na;
|
|
} /* end if */
|
|
|
|
/* Push the function name */
|
|
fstack->rec[fstack->nused] = func_name;
|
|
fstack->nused++;
|
|
|
|
FUNC_LEAVE_NOAPI_NOFS(SUCCEED)
|
|
} /* end H5CS_push() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5CS_pop
|
|
*
|
|
* Purpose: Pops a record off function stack for the current thread.
|
|
*
|
|
* Return: Non-negative on success/Negative on failure
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
* Thursday, February 6, 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5CS_pop(void)
|
|
{
|
|
H5CS_t *fstack = H5CS_get_my_stack();
|
|
|
|
/* Don't push this function on the function stack... :-) */
|
|
FUNC_ENTER_NOAPI_NOERR_NOFS
|
|
|
|
/* Sanity check */
|
|
HDassert(fstack);
|
|
HDassert(fstack->nused > 0);
|
|
|
|
/* Pop the function. */
|
|
fstack->nused--;
|
|
|
|
FUNC_LEAVE_NOAPI_NOFS(SUCCEED);
|
|
} /* end H5CS_pop() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5CS_copy_stack
|
|
*
|
|
* Purpose: Makes a copy of the current stack
|
|
*
|
|
* Return: Non-negative on success/Negative on failure
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
* Tuesday, August 9, 2005
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
H5CS_t *
|
|
H5CS_copy_stack(void)
|
|
{
|
|
H5CS_t * old_stack = H5CS_get_my_stack(); /* Existing function stack for library */
|
|
H5CS_t * new_stack; /* New function stack, for copy */
|
|
unsigned u; /* Local index variable */
|
|
H5CS_t * ret_value = NULL; /* Return value */
|
|
|
|
/* Don't push this function on the function stack... :-) */
|
|
FUNC_ENTER_NOAPI_NOFS
|
|
|
|
/* Sanity check */
|
|
HDassert(old_stack);
|
|
|
|
/* Allocate a new stack */
|
|
/* (Don't use library allocate code, since this code stack supports it) */
|
|
if (NULL == (new_stack = HDcalloc(1, sizeof(H5CS_t))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate function stack")
|
|
if (NULL == (new_stack->rec = HDcalloc(old_stack->nused, sizeof(const char *))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "can't allocate function stack records")
|
|
|
|
/* Copy old stack to new one, duplicating the strings */
|
|
for (u = 0; u < old_stack->nused; u++)
|
|
new_stack->rec[u] = HDstrdup(old_stack->rec[u]);
|
|
new_stack->nused = new_stack->nalloc = old_stack->nused;
|
|
|
|
/* Set the return value */
|
|
ret_value = new_stack;
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI_NOFS(ret_value)
|
|
} /* end H5CS_copy_stack() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5CS_close_stack
|
|
*
|
|
* Purpose: Closes and frees a copy of a stack
|
|
*
|
|
* Return: Non-negative on success/Negative on failure
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
* Tuesday, August 9, 2005
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5CS_close_stack(H5CS_t *stack)
|
|
{
|
|
unsigned u; /* Local index variable */
|
|
|
|
/* Don't push this function on the function stack... :-) */
|
|
FUNC_ENTER_NOAPI_NOERR_NOFS
|
|
|
|
/* Sanity check */
|
|
HDassert(stack);
|
|
|
|
/* Free stack */
|
|
for (u = 0; u < stack->nused; u++) {
|
|
if (stack->rec[u])
|
|
HDfree((void *)stack->rec[u]);
|
|
stack->rec[u] = NULL;
|
|
} /* end for */
|
|
if (stack->rec) {
|
|
HDfree(stack->rec);
|
|
stack->rec = NULL;
|
|
} /* end if */
|
|
if (stack)
|
|
HDfree(stack);
|
|
|
|
FUNC_LEAVE_NOAPI_NOFS(SUCCEED)
|
|
} /* end H5CS_close_stack() */
|
|
|
|
#endif /* H5_HAVE_CODESTACK */
|