xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/libcollector/tsd.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1*c42dbd0eSchristos /* Copyright (C) 2021 Free Software Foundation, Inc.
2*c42dbd0eSchristos    Contributed by Oracle.
3*c42dbd0eSchristos 
4*c42dbd0eSchristos    This file is part of GNU Binutils.
5*c42dbd0eSchristos 
6*c42dbd0eSchristos    This program is free software; you can redistribute it and/or modify
7*c42dbd0eSchristos    it under the terms of the GNU General Public License as published by
8*c42dbd0eSchristos    the Free Software Foundation; either version 3, or (at your option)
9*c42dbd0eSchristos    any later version.
10*c42dbd0eSchristos 
11*c42dbd0eSchristos    This program is distributed in the hope that it will be useful,
12*c42dbd0eSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c42dbd0eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*c42dbd0eSchristos    GNU General Public License for more details.
15*c42dbd0eSchristos 
16*c42dbd0eSchristos    You should have received a copy of the GNU General Public License
17*c42dbd0eSchristos    along with this program; if not, write to the Free Software
18*c42dbd0eSchristos    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19*c42dbd0eSchristos    MA 02110-1301, USA.  */
20*c42dbd0eSchristos 
21*c42dbd0eSchristos #include "config.h"
22*c42dbd0eSchristos #include <pthread.h>
23*c42dbd0eSchristos 
24*c42dbd0eSchristos #include "collector.h"
25*c42dbd0eSchristos #include "libcol_util.h"
26*c42dbd0eSchristos #include "tsd.h"
27*c42dbd0eSchristos #include "memmgr.h"
28*c42dbd0eSchristos 
29*c42dbd0eSchristos /* TprintfT(<level>,...) definitions.  Adjust per module as needed */
30*c42dbd0eSchristos #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
31*c42dbd0eSchristos #define DBG_LT1 1 // for configuration details, warnings
32*c42dbd0eSchristos #define DBG_LT2 2
33*c42dbd0eSchristos #define DBG_LT3 3
34*c42dbd0eSchristos 
35*c42dbd0eSchristos /*
36*c42dbd0eSchristos  * Build our thread-specific-data support on pthread interfaces.
37*c42dbd0eSchristos  */
38*c42dbd0eSchristos #define MAXNKEYS    64  /* hard-wired? really? well, it depends only on us and we have a sense for how many keys we will use */
39*c42dbd0eSchristos static pthread_key_t tsd_pkeys[MAXNKEYS];
40*c42dbd0eSchristos static size_t tsd_sizes[MAXNKEYS];
41*c42dbd0eSchristos static unsigned tsd_nkeys = 0;
42*c42dbd0eSchristos 
43*c42dbd0eSchristos int
__collector_tsd_init()44*c42dbd0eSchristos __collector_tsd_init ()
45*c42dbd0eSchristos {
46*c42dbd0eSchristos   return 0;
47*c42dbd0eSchristos }
48*c42dbd0eSchristos 
49*c42dbd0eSchristos void
__collector_tsd_fini()50*c42dbd0eSchristos __collector_tsd_fini ()
51*c42dbd0eSchristos {
52*c42dbd0eSchristos   Tprintf (DBG_LT1, "tsd_fini()\n");
53*c42dbd0eSchristos   while (tsd_nkeys)
54*c42dbd0eSchristos     {
55*c42dbd0eSchristos       tsd_nkeys--;
56*c42dbd0eSchristos       pthread_key_delete (tsd_pkeys[tsd_nkeys]);
57*c42dbd0eSchristos       tsd_sizes[tsd_nkeys] = 0; // should be unneeded
58*c42dbd0eSchristos     }
59*c42dbd0eSchristos }
60*c42dbd0eSchristos 
61*c42dbd0eSchristos int
__collector_tsd_allocate()62*c42dbd0eSchristos __collector_tsd_allocate ()
63*c42dbd0eSchristos {
64*c42dbd0eSchristos   return 0;
65*c42dbd0eSchristos }
66*c42dbd0eSchristos 
67*c42dbd0eSchristos void
__collector_tsd_release()68*c42dbd0eSchristos __collector_tsd_release () { }
69*c42dbd0eSchristos 
70*c42dbd0eSchristos static void
tsd_destructor(void * p)71*c42dbd0eSchristos tsd_destructor (void *p)
72*c42dbd0eSchristos {
73*c42dbd0eSchristos   if (p)
74*c42dbd0eSchristos     __collector_freeCSize (__collector_heap, p, *((size_t *) p));
75*c42dbd0eSchristos }
76*c42dbd0eSchristos 
77*c42dbd0eSchristos unsigned
__collector_tsd_create_key(size_t sz,void (* init)(void *),void (* fini)(void *))78*c42dbd0eSchristos __collector_tsd_create_key (size_t sz, void (*init)(void*), void (*fini)(void*))
79*c42dbd0eSchristos {
80*c42dbd0eSchristos   /*
81*c42dbd0eSchristos    * We no longer support init and fini arguments (and weren't using them anyhow).
82*c42dbd0eSchristos    * Our hard-wired MAXNKEYS presumably is considerably higher than the number of keys we use.
83*c42dbd0eSchristos    */
84*c42dbd0eSchristos   if (init || fini || (tsd_nkeys >= MAXNKEYS))
85*c42dbd0eSchristos     return COLLECTOR_TSD_INVALID_KEY;
86*c42dbd0eSchristos 
87*c42dbd0eSchristos   /*
88*c42dbd0eSchristos    * A pthread key has a value that is (void *).
89*c42dbd0eSchristos    * We don't know where it is stored, and can access its value only through {get|set}specific.
90*c42dbd0eSchristos    * But libcollector expects a pointer to memory that it can modify.
91*c42dbd0eSchristos    * So we have to allocate that memory and store the pointer.
92*c42dbd0eSchristos    *
93*c42dbd0eSchristos    * For now, we just have to register a destructor that will free the memory
94*c42dbd0eSchristos    * when the thread finishes.
95*c42dbd0eSchristos    */
96*c42dbd0eSchristos   if (pthread_key_create (&tsd_pkeys[tsd_nkeys], &tsd_destructor))
97*c42dbd0eSchristos    return COLLECTOR_TSD_INVALID_KEY;
98*c42dbd0eSchristos   tsd_sizes[tsd_nkeys] = sz;
99*c42dbd0eSchristos   tsd_nkeys++;
100*c42dbd0eSchristos   return (tsd_nkeys - 1);
101*c42dbd0eSchristos }
102*c42dbd0eSchristos 
103*c42dbd0eSchristos void *
__collector_tsd_get_by_key(unsigned key_index)104*c42dbd0eSchristos __collector_tsd_get_by_key (unsigned key_index)
105*c42dbd0eSchristos {
106*c42dbd0eSchristos   if (key_index == COLLECTOR_TSD_INVALID_KEY)
107*c42dbd0eSchristos     return NULL;
108*c42dbd0eSchristos   if (key_index < 0 || key_index >= tsd_nkeys)
109*c42dbd0eSchristos     return NULL;
110*c42dbd0eSchristos   pthread_key_t key = tsd_pkeys[key_index];
111*c42dbd0eSchristos   size_t sz = tsd_sizes[key_index];
112*c42dbd0eSchristos 
113*c42dbd0eSchristos   /*
114*c42dbd0eSchristos    * When we use __collector_freeCSize(), we need to know the
115*c42dbd0eSchristos    * size that had been allocated.  So, stick a header to the
116*c42dbd0eSchristos    * front of the allocation to hold the size.  The header could
117*c42dbd0eSchristos    * just be sizeof(size_t), but pad it to preserve alignment for
118*c42dbd0eSchristos    * the usable area.
119*c42dbd0eSchristos    */
120*c42dbd0eSchristos   size_t header = 8;
121*c42dbd0eSchristos   void *value = pthread_getspecific (key);
122*c42dbd0eSchristos 
123*c42dbd0eSchristos   // check whether we have allocated the memory
124*c42dbd0eSchristos   if (value == NULL)
125*c42dbd0eSchristos     {
126*c42dbd0eSchristos       // add room to record the size
127*c42dbd0eSchristos       value = __collector_allocCSize (__collector_heap, sz + header, 0);
128*c42dbd0eSchristos       if (value == NULL)
129*c42dbd0eSchristos 	{
130*c42dbd0eSchristos 	  // do we need to guard against trying to alloc each time?
131*c42dbd0eSchristos 	  return NULL;
132*c42dbd0eSchristos 	}
133*c42dbd0eSchristos       // write the size of the allocation
134*c42dbd0eSchristos       *((size_t *) value) = sz + header;
135*c42dbd0eSchristos       CALL_UTIL (memset)(((char *) value) + header, 0, sz);
136*c42dbd0eSchristos 
137*c42dbd0eSchristos       // record the allocation for future retrieval
138*c42dbd0eSchristos       if (pthread_setspecific (key, value))
139*c42dbd0eSchristos 	return NULL;
140*c42dbd0eSchristos     }
141*c42dbd0eSchristos   // return the pointer, skipping the header
142*c42dbd0eSchristos   return ((char *) value) +header;
143*c42dbd0eSchristos }
144*c42dbd0eSchristos 
145*c42dbd0eSchristos void
__collector_tsd_fork_child_cleanup()146*c42dbd0eSchristos __collector_tsd_fork_child_cleanup ()
147*c42dbd0eSchristos {
148*c42dbd0eSchristos   __collector_tsd_fini ();
149*c42dbd0eSchristos }
150