1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
24 #include "collector.h"
25 #include "libcol_util.h"
29 /* TprintfT(<level>,...) definitions. Adjust per module as needed */
30 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
31 #define DBG_LT1 1 // for configuration details, warnings
36 * Build our thread-specific-data support on pthread interfaces.
38 #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 static pthread_key_t tsd_pkeys
[MAXNKEYS
];
40 static size_t tsd_sizes
[MAXNKEYS
];
41 static unsigned tsd_nkeys
= 0;
44 __collector_tsd_init ()
50 __collector_tsd_fini ()
52 Tprintf (DBG_LT1
, "tsd_fini()\n");
56 pthread_key_delete (tsd_pkeys
[tsd_nkeys
]);
57 tsd_sizes
[tsd_nkeys
] = 0; // should be unneeded
62 __collector_tsd_allocate ()
68 __collector_tsd_release () { }
71 tsd_destructor (void *p
)
74 __collector_freeCSize (__collector_heap
, p
, *((size_t *) p
));
78 __collector_tsd_create_key (size_t sz
, void (*init
)(void*), void (*fini
)(void*))
81 * We no longer support init and fini arguments (and weren't using them anyhow).
82 * Our hard-wired MAXNKEYS presumably is considerably higher than the number of keys we use.
84 if (init
|| fini
|| (tsd_nkeys
>= MAXNKEYS
))
85 return COLLECTOR_TSD_INVALID_KEY
;
88 * A pthread key has a value that is (void *).
89 * We don't know where it is stored, and can access its value only through {get|set}specific.
90 * But libcollector expects a pointer to memory that it can modify.
91 * So we have to allocate that memory and store the pointer.
93 * For now, we just have to register a destructor that will free the memory
94 * when the thread finishes.
96 if (pthread_key_create (&tsd_pkeys
[tsd_nkeys
], &tsd_destructor
))
97 return COLLECTOR_TSD_INVALID_KEY
;
98 tsd_sizes
[tsd_nkeys
] = sz
;
100 return (tsd_nkeys
- 1);
104 __collector_tsd_get_by_key (unsigned key_index
)
106 if (key_index
== COLLECTOR_TSD_INVALID_KEY
)
108 if (key_index
< 0 || key_index
>= tsd_nkeys
)
110 pthread_key_t key
= tsd_pkeys
[key_index
];
111 size_t sz
= tsd_sizes
[key_index
];
114 * When we use __collector_freeCSize(), we need to know the
115 * size that had been allocated. So, stick a header to the
116 * front of the allocation to hold the size. The header could
117 * just be sizeof(size_t), but pad it to preserve alignment for
121 void *value
= pthread_getspecific (key
);
123 // check whether we have allocated the memory
126 // add room to record the size
127 value
= __collector_allocCSize (__collector_heap
, sz
+ header
, 0);
130 // do we need to guard against trying to alloc each time?
133 // write the size of the allocation
134 *((size_t *) value
) = sz
+ header
;
135 CALL_UTIL (memset
)(((char *) value
) + header
, 0, sz
);
137 // record the allocation for future retrieval
138 if (pthread_setspecific (key
, value
))
141 // return the pointer, skipping the header
142 return ((char *) value
) +header
;
146 __collector_tsd_fork_child_cleanup ()
148 __collector_tsd_fini ();