1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/* Copyright (C) 2021-2026 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 <pthread.h>
#include "collector.h"
#include "libcol_util.h"
#include "tsd.h"
#include "memmgr.h"
/*
* 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 ();
}
|