From bb368aad297fe3ad40cf397e6fc85aa471429a28 Mon Sep 17 00:00:00 2001 From: Vladimir Mezentsev Date: Fri, 11 Mar 2022 08:58:31 +0000 Subject: gprofng: a new GNU profiler top-level * Makefile.def: Add gprofng module. * configure.ac: Add --enable-gprofng option. * src-release.sh: Add gprofng. * Makefile.in: Regenerate. * configure: Regenerate. * gprofng: New directory. binutils * MAINTAINERS: Add gprofng maintainer. * README-how-to-make-a-release: Add gprofng. include. * collectorAPI.h: New file. * libcollector.h: New file. * libfcollector.h: New file. --- gprofng/libcollector/tsd.c | 149 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 gprofng/libcollector/tsd.c (limited to 'gprofng/libcollector/tsd.c') diff --git a/gprofng/libcollector/tsd.c b/gprofng/libcollector/tsd.c new file mode 100644 index 0000000..416c3e7 --- /dev/null +++ b/gprofng/libcollector/tsd.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include + +#include "collector.h" +#include "libcol_util.h" +#include "tsd.h" +#include "memmgr.h" + +/* TprintfT(,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* + * Build our thread-specific-data support on pthread interfaces. + */ +#define MAXNKEYS 64 /* hard-wired? really? well, it depends only on us and we have a sense for how many keys we will use */ +static pthread_key_t tsd_pkeys[MAXNKEYS]; +static size_t tsd_sizes[MAXNKEYS]; +static unsigned tsd_nkeys = 0; + +int +__collector_tsd_init () +{ + return 0; +} + +void +__collector_tsd_fini () +{ + Tprintf (DBG_LT1, "tsd_fini()\n"); + while (tsd_nkeys) + { + tsd_nkeys--; + pthread_key_delete (tsd_pkeys[tsd_nkeys]); + tsd_sizes[tsd_nkeys] = 0; // should be unneeded + } +} + +int +__collector_tsd_allocate () +{ + return 0; +} + +void +__collector_tsd_release () { } + +static void +tsd_destructor (void *p) +{ + if (p) + __collector_freeCSize (__collector_heap, p, *((size_t *) p)); +} + +unsigned +__collector_tsd_create_key (size_t sz, void (*init)(void*), void (*fini)(void*)) +{ + /* + * We no longer support init and fini arguments (and weren't using them anyhow). + * Our hard-wired MAXNKEYS presumably is considerably higher than the number of keys we use. + */ + if (init || fini || (tsd_nkeys >= MAXNKEYS)) + return COLLECTOR_TSD_INVALID_KEY; + + /* + * A pthread key has a value that is (void *). + * We don't know where it is stored, and can access its value only through {get|set}specific. + * But libcollector expects a pointer to memory that it can modify. + * So we have to allocate that memory and store the pointer. + * + * For now, we just have to register a destructor that will free the memory + * when the thread finishes. + */ + if (pthread_key_create (&tsd_pkeys[tsd_nkeys], &tsd_destructor)) + return COLLECTOR_TSD_INVALID_KEY; + tsd_sizes[tsd_nkeys] = sz; + tsd_nkeys++; + return (tsd_nkeys - 1); +} + +void * +__collector_tsd_get_by_key (unsigned key_index) +{ + if (key_index == COLLECTOR_TSD_INVALID_KEY) + return NULL; + if (key_index < 0 || key_index >= tsd_nkeys) + return NULL; + pthread_key_t key = tsd_pkeys[key_index]; + size_t sz = tsd_sizes[key_index]; + + /* + * When we use __collector_freeCSize(), we need to know the + * size that had been allocated. So, stick a header to the + * front of the allocation to hold the size. The header could + * just be sizeof(size_t), but pad it to preserve alignment for + * the usable area. + */ + size_t header = 8; + void *value = pthread_getspecific (key); + + // check whether we have allocated the memory + if (value == NULL) + { + // add room to record the size + value = __collector_allocCSize (__collector_heap, sz + header, 0); + if (value == NULL) + { + // do we need to guard against trying to alloc each time? + return NULL; + } + // write the size of the allocation + *((size_t *) value) = sz + header; + CALL_UTIL (memset)(((char *) value) + header, 0, sz); + + // record the allocation for future retrieval + if (pthread_setspecific (key, value)) + return NULL; + } + // return the pointer, skipping the header + return ((char *) value) +header; +} + +void +__collector_tsd_fork_child_cleanup () +{ + __collector_tsd_fini (); +} -- cgit v1.1