Inline the storage for thread name in prof_tdata_t.
The previous approach managed the thread name in a separate buffer, which causes races because the thread name update (triggered by new samples) can happen at the same time as prof dumping (which reads the thread names) -- these two operations are under separate locks to avoid blocking each other. Implemented the thread name storage as part of the tdata struct, which resolves the lifetime issue and also avoids internal alloc / dalloc during prof_sample.
This commit is contained in:
@@ -18,7 +18,6 @@ bool prof_bt_keycomp(const void *k1, const void *k2);
|
||||
|
||||
bool prof_data_init(tsd_t *tsd);
|
||||
prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt);
|
||||
char *prof_thread_name_alloc(tsd_t *tsd, const char *thread_name);
|
||||
int prof_thread_name_set_impl(tsd_t *tsd, const char *thread_name);
|
||||
void prof_unbias_map_init();
|
||||
void prof_dump_impl(tsd_t *tsd, write_cb_t *prof_dump_write, void *cbopaque,
|
||||
|
@@ -38,6 +38,22 @@ prof_gdump_get_unlocked(void) {
|
||||
return prof_gdump_val;
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
prof_thread_name_assert(prof_tdata_t *tdata) {
|
||||
if (!config_debug) {
|
||||
return;
|
||||
}
|
||||
prof_active_assert();
|
||||
|
||||
bool terminated = false;
|
||||
for (unsigned i = 0; i < PROF_THREAD_NAME_MAX_LEN; i++) {
|
||||
if (tdata->thread_name[i] == '\0') {
|
||||
terminated = true;
|
||||
}
|
||||
}
|
||||
assert(terminated);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE prof_tdata_t *
|
||||
prof_tdata_get(tsd_t *tsd, bool create) {
|
||||
prof_tdata_t *tdata;
|
||||
@@ -59,6 +75,10 @@ prof_tdata_get(tsd_t *tsd, bool create) {
|
||||
assert(tdata == NULL || tdata->attached);
|
||||
}
|
||||
|
||||
if (tdata != NULL) {
|
||||
prof_thread_name_assert(tdata);
|
||||
}
|
||||
|
||||
return tdata;
|
||||
}
|
||||
|
||||
@@ -255,4 +275,18 @@ prof_free(tsd_t *tsd, const void *ptr, size_t usize,
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE bool
|
||||
prof_thread_name_empty(prof_tdata_t *tdata) {
|
||||
prof_active_assert();
|
||||
|
||||
return (tdata->thread_name[0] == '\0');
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
prof_thread_name_clear(prof_tdata_t *tdata) {
|
||||
prof_active_assert();
|
||||
|
||||
tdata->thread_name[0] = '\0';
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_PROF_INLINES_H */
|
||||
|
@@ -156,9 +156,6 @@ struct prof_tdata_s {
|
||||
*/
|
||||
uint64_t thr_discrim;
|
||||
|
||||
/* Included in heap profile dumps if non-NULL. */
|
||||
char *thread_name;
|
||||
|
||||
bool attached;
|
||||
bool expired;
|
||||
|
||||
@@ -179,6 +176,9 @@ struct prof_tdata_s {
|
||||
*/
|
||||
ckh_t bt2tctx;
|
||||
|
||||
/* Included in heap profile dumps if has content. */
|
||||
char thread_name[PROF_THREAD_NAME_MAX_LEN];
|
||||
|
||||
/* State used to avoid dumping while operating on prof internals. */
|
||||
bool enq;
|
||||
bool enq_idump;
|
||||
|
@@ -77,4 +77,7 @@ typedef struct prof_recent_s prof_recent_t;
|
||||
/* Default number of recent allocations to record. */
|
||||
#define PROF_RECENT_ALLOC_MAX_DEFAULT 0
|
||||
|
||||
/* Thread name storage size limit. */
|
||||
#define PROF_THREAD_NAME_MAX_LEN 16
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_PROF_TYPES_H */
|
||||
|
Reference in New Issue
Block a user