diff options
Diffstat (limited to 'src/H5CS.c')
-rw-r--r-- | src/H5CS.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/src/H5CS.c b/src/H5CS.c new file mode 100644 index 0000000..0a3dcce --- /dev/null +++ b/src/H5CS.c @@ -0,0 +1,330 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +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*/ +#ifdef H5_HAVE_THREADSAFE + HDfprintf(stream, "thread %lu.", HDpthread_self_ulong()); +#else /* H5_HAVE_THREADSAFE */ + HDfprintf(stream, "thread 0."); +#endif /* H5_HAVE_THREADSAFE */ + 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 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +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 */ + |