diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
| commit | dcacc00e3750300617ba6e16eb346713f91a783a (patch) | |
| tree | 38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/deps/jemalloc/src/prof_sys.c | |
| parent | 58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff) | |
| download | crep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz | |
Remove testing data
Diffstat (limited to 'examples/redis-unstable/deps/jemalloc/src/prof_sys.c')
| -rw-r--r-- | examples/redis-unstable/deps/jemalloc/src/prof_sys.c | 669 |
1 files changed, 0 insertions, 669 deletions
diff --git a/examples/redis-unstable/deps/jemalloc/src/prof_sys.c b/examples/redis-unstable/deps/jemalloc/src/prof_sys.c deleted file mode 100644 index b5f1f5b..0000000 --- a/examples/redis-unstable/deps/jemalloc/src/prof_sys.c +++ /dev/null | |||
| @@ -1,669 +0,0 @@ | |||
| 1 | #define JEMALLOC_PROF_SYS_C_ | ||
| 2 | #include "jemalloc/internal/jemalloc_preamble.h" | ||
| 3 | #include "jemalloc/internal/jemalloc_internal_includes.h" | ||
| 4 | |||
| 5 | #include "jemalloc/internal/buf_writer.h" | ||
| 6 | #include "jemalloc/internal/ctl.h" | ||
| 7 | #include "jemalloc/internal/prof_data.h" | ||
| 8 | #include "jemalloc/internal/prof_sys.h" | ||
| 9 | |||
| 10 | #ifdef JEMALLOC_PROF_LIBUNWIND | ||
| 11 | #define UNW_LOCAL_ONLY | ||
| 12 | #include <libunwind.h> | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #ifdef JEMALLOC_PROF_LIBGCC | ||
| 16 | /* | ||
| 17 | * We have a circular dependency -- jemalloc_internal.h tells us if we should | ||
| 18 | * use libgcc's unwinding functionality, but after we've included that, we've | ||
| 19 | * already hooked _Unwind_Backtrace. We'll temporarily disable hooking. | ||
| 20 | */ | ||
| 21 | #undef _Unwind_Backtrace | ||
| 22 | #include <unwind.h> | ||
| 23 | #define _Unwind_Backtrace JEMALLOC_TEST_HOOK(_Unwind_Backtrace, test_hooks_libc_hook) | ||
| 24 | #endif | ||
| 25 | |||
| 26 | /******************************************************************************/ | ||
| 27 | |||
| 28 | malloc_mutex_t prof_dump_filename_mtx; | ||
| 29 | |||
| 30 | bool prof_do_mock = false; | ||
| 31 | |||
| 32 | static uint64_t prof_dump_seq; | ||
| 33 | static uint64_t prof_dump_iseq; | ||
| 34 | static uint64_t prof_dump_mseq; | ||
| 35 | static uint64_t prof_dump_useq; | ||
| 36 | |||
| 37 | static char *prof_prefix = NULL; | ||
| 38 | |||
| 39 | /* The fallback allocator profiling functionality will use. */ | ||
| 40 | base_t *prof_base; | ||
| 41 | |||
| 42 | void | ||
| 43 | bt_init(prof_bt_t *bt, void **vec) { | ||
| 44 | cassert(config_prof); | ||
| 45 | |||
| 46 | bt->vec = vec; | ||
| 47 | bt->len = 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | #ifdef JEMALLOC_PROF_LIBUNWIND | ||
| 51 | static void | ||
| 52 | prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) { | ||
| 53 | int nframes; | ||
| 54 | |||
| 55 | cassert(config_prof); | ||
| 56 | assert(*len == 0); | ||
| 57 | assert(vec != NULL); | ||
| 58 | assert(max_len == PROF_BT_MAX); | ||
| 59 | |||
| 60 | nframes = unw_backtrace(vec, PROF_BT_MAX); | ||
| 61 | if (nframes <= 0) { | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | *len = nframes; | ||
| 65 | } | ||
| 66 | #elif (defined(JEMALLOC_PROF_LIBGCC)) | ||
| 67 | static _Unwind_Reason_Code | ||
| 68 | prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) { | ||
| 69 | cassert(config_prof); | ||
| 70 | |||
| 71 | return _URC_NO_REASON; | ||
| 72 | } | ||
| 73 | |||
| 74 | static _Unwind_Reason_Code | ||
| 75 | prof_unwind_callback(struct _Unwind_Context *context, void *arg) { | ||
| 76 | prof_unwind_data_t *data = (prof_unwind_data_t *)arg; | ||
| 77 | void *ip; | ||
| 78 | |||
| 79 | cassert(config_prof); | ||
| 80 | |||
| 81 | ip = (void *)_Unwind_GetIP(context); | ||
| 82 | if (ip == NULL) { | ||
| 83 | return _URC_END_OF_STACK; | ||
| 84 | } | ||
| 85 | data->vec[*data->len] = ip; | ||
| 86 | (*data->len)++; | ||
| 87 | if (*data->len == data->max) { | ||
| 88 | return _URC_END_OF_STACK; | ||
| 89 | } | ||
| 90 | |||
| 91 | return _URC_NO_REASON; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void | ||
| 95 | prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) { | ||
| 96 | prof_unwind_data_t data = {vec, len, max_len}; | ||
| 97 | |||
| 98 | cassert(config_prof); | ||
| 99 | assert(vec != NULL); | ||
| 100 | assert(max_len == PROF_BT_MAX); | ||
| 101 | |||
| 102 | _Unwind_Backtrace(prof_unwind_callback, &data); | ||
| 103 | } | ||
| 104 | #elif (defined(JEMALLOC_PROF_GCC)) | ||
| 105 | static void | ||
| 106 | prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) { | ||
| 107 | #define BT_FRAME(i) \ | ||
| 108 | if ((i) < max_len) { \ | ||
| 109 | void *p; \ | ||
| 110 | if (__builtin_frame_address(i) == 0) { \ | ||
| 111 | return; \ | ||
| 112 | } \ | ||
| 113 | p = __builtin_return_address(i); \ | ||
| 114 | if (p == NULL) { \ | ||
| 115 | return; \ | ||
| 116 | } \ | ||
| 117 | vec[(i)] = p; \ | ||
| 118 | *len = (i) + 1; \ | ||
| 119 | } else { \ | ||
| 120 | return; \ | ||
| 121 | } | ||
| 122 | |||
| 123 | cassert(config_prof); | ||
| 124 | assert(vec != NULL); | ||
| 125 | assert(max_len == PROF_BT_MAX); | ||
| 126 | |||
| 127 | BT_FRAME(0) | ||
| 128 | BT_FRAME(1) | ||
| 129 | BT_FRAME(2) | ||
| 130 | BT_FRAME(3) | ||
| 131 | BT_FRAME(4) | ||
| 132 | BT_FRAME(5) | ||
| 133 | BT_FRAME(6) | ||
| 134 | BT_FRAME(7) | ||
| 135 | BT_FRAME(8) | ||
| 136 | BT_FRAME(9) | ||
| 137 | |||
| 138 | BT_FRAME(10) | ||
| 139 | BT_FRAME(11) | ||
| 140 | BT_FRAME(12) | ||
| 141 | BT_FRAME(13) | ||
| 142 | BT_FRAME(14) | ||
| 143 | BT_FRAME(15) | ||
| 144 | BT_FRAME(16) | ||
| 145 | BT_FRAME(17) | ||
| 146 | BT_FRAME(18) | ||
| 147 | BT_FRAME(19) | ||
| 148 | |||
| 149 | BT_FRAME(20) | ||
| 150 | BT_FRAME(21) | ||
| 151 | BT_FRAME(22) | ||
| 152 | BT_FRAME(23) | ||
| 153 | BT_FRAME(24) | ||
| 154 | BT_FRAME(25) | ||
| 155 | BT_FRAME(26) | ||
| 156 | BT_FRAME(27) | ||
| 157 | BT_FRAME(28) | ||
| 158 | BT_FRAME(29) | ||
| 159 | |||
| 160 | BT_FRAME(30) | ||
| 161 | BT_FRAME(31) | ||
| 162 | BT_FRAME(32) | ||
| 163 | BT_FRAME(33) | ||
| 164 | BT_FRAME(34) | ||
| 165 | BT_FRAME(35) | ||
| 166 | BT_FRAME(36) | ||
| 167 | BT_FRAME(37) | ||
| 168 | BT_FRAME(38) | ||
| 169 | BT_FRAME(39) | ||
| 170 | |||
| 171 | BT_FRAME(40) | ||
| 172 | BT_FRAME(41) | ||
| 173 | BT_FRAME(42) | ||
| 174 | BT_FRAME(43) | ||
| 175 | BT_FRAME(44) | ||
| 176 | BT_FRAME(45) | ||
| 177 | BT_FRAME(46) | ||
| 178 | BT_FRAME(47) | ||
| 179 | BT_FRAME(48) | ||
| 180 | BT_FRAME(49) | ||
| 181 | |||
| 182 | BT_FRAME(50) | ||
| 183 | BT_FRAME(51) | ||
| 184 | BT_FRAME(52) | ||
| 185 | BT_FRAME(53) | ||
| 186 | BT_FRAME(54) | ||
| 187 | BT_FRAME(55) | ||
| 188 | BT_FRAME(56) | ||
| 189 | BT_FRAME(57) | ||
| 190 | BT_FRAME(58) | ||
| 191 | BT_FRAME(59) | ||
| 192 | |||
| 193 | BT_FRAME(60) | ||
| 194 | BT_FRAME(61) | ||
| 195 | BT_FRAME(62) | ||
| 196 | BT_FRAME(63) | ||
| 197 | BT_FRAME(64) | ||
| 198 | BT_FRAME(65) | ||
| 199 | BT_FRAME(66) | ||
| 200 | BT_FRAME(67) | ||
| 201 | BT_FRAME(68) | ||
| 202 | BT_FRAME(69) | ||
| 203 | |||
| 204 | BT_FRAME(70) | ||
| 205 | BT_FRAME(71) | ||
| 206 | BT_FRAME(72) | ||
| 207 | BT_FRAME(73) | ||
| 208 | BT_FRAME(74) | ||
| 209 | BT_FRAME(75) | ||
| 210 | BT_FRAME(76) | ||
| 211 | BT_FRAME(77) | ||
| 212 | BT_FRAME(78) | ||
| 213 | BT_FRAME(79) | ||
| 214 | |||
| 215 | BT_FRAME(80) | ||
| 216 | BT_FRAME(81) | ||
| 217 | BT_FRAME(82) | ||
| 218 | BT_FRAME(83) | ||
| 219 | BT_FRAME(84) | ||
| 220 | BT_FRAME(85) | ||
| 221 | BT_FRAME(86) | ||
| 222 | BT_FRAME(87) | ||
| 223 | BT_FRAME(88) | ||
| 224 | BT_FRAME(89) | ||
| 225 | |||
| 226 | BT_FRAME(90) | ||
| 227 | BT_FRAME(91) | ||
| 228 | BT_FRAME(92) | ||
| 229 | BT_FRAME(93) | ||
| 230 | BT_FRAME(94) | ||
| 231 | BT_FRAME(95) | ||
| 232 | BT_FRAME(96) | ||
| 233 | BT_FRAME(97) | ||
| 234 | BT_FRAME(98) | ||
| 235 | BT_FRAME(99) | ||
| 236 | |||
| 237 | BT_FRAME(100) | ||
| 238 | BT_FRAME(101) | ||
| 239 | BT_FRAME(102) | ||
| 240 | BT_FRAME(103) | ||
| 241 | BT_FRAME(104) | ||
| 242 | BT_FRAME(105) | ||
| 243 | BT_FRAME(106) | ||
| 244 | BT_FRAME(107) | ||
| 245 | BT_FRAME(108) | ||
| 246 | BT_FRAME(109) | ||
| 247 | |||
| 248 | BT_FRAME(110) | ||
| 249 | BT_FRAME(111) | ||
| 250 | BT_FRAME(112) | ||
| 251 | BT_FRAME(113) | ||
| 252 | BT_FRAME(114) | ||
| 253 | BT_FRAME(115) | ||
| 254 | BT_FRAME(116) | ||
| 255 | BT_FRAME(117) | ||
| 256 | BT_FRAME(118) | ||
| 257 | BT_FRAME(119) | ||
| 258 | |||
| 259 | BT_FRAME(120) | ||
| 260 | BT_FRAME(121) | ||
| 261 | BT_FRAME(122) | ||
| 262 | BT_FRAME(123) | ||
| 263 | BT_FRAME(124) | ||
| 264 | BT_FRAME(125) | ||
| 265 | BT_FRAME(126) | ||
| 266 | BT_FRAME(127) | ||
| 267 | #undef BT_FRAME | ||
| 268 | } | ||
| 269 | #else | ||
| 270 | static void | ||
| 271 | prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) { | ||
| 272 | cassert(config_prof); | ||
| 273 | not_reached(); | ||
| 274 | } | ||
| 275 | #endif | ||
| 276 | |||
| 277 | void | ||
| 278 | prof_backtrace(tsd_t *tsd, prof_bt_t *bt) { | ||
| 279 | cassert(config_prof); | ||
| 280 | prof_backtrace_hook_t prof_backtrace_hook = prof_backtrace_hook_get(); | ||
| 281 | assert(prof_backtrace_hook != NULL); | ||
| 282 | |||
| 283 | pre_reentrancy(tsd, NULL); | ||
| 284 | prof_backtrace_hook(bt->vec, &bt->len, PROF_BT_MAX); | ||
| 285 | post_reentrancy(tsd); | ||
| 286 | } | ||
| 287 | |||
| 288 | void | ||
| 289 | prof_hooks_init() { | ||
| 290 | prof_backtrace_hook_set(&prof_backtrace_impl); | ||
| 291 | prof_dump_hook_set(NULL); | ||
| 292 | } | ||
| 293 | |||
| 294 | void | ||
| 295 | prof_unwind_init() { | ||
| 296 | #ifdef JEMALLOC_PROF_LIBGCC | ||
| 297 | /* | ||
| 298 | * Cause the backtracing machinery to allocate its internal | ||
| 299 | * state before enabling profiling. | ||
| 300 | */ | ||
| 301 | _Unwind_Backtrace(prof_unwind_init_callback, NULL); | ||
| 302 | #endif | ||
| 303 | } | ||
| 304 | |||
| 305 | static int | ||
| 306 | prof_sys_thread_name_read_impl(char *buf, size_t limit) { | ||
| 307 | #if defined(JEMALLOC_HAVE_PTHREAD_GETNAME_NP) | ||
| 308 | return pthread_getname_np(pthread_self(), buf, limit); | ||
| 309 | #elif defined(JEMALLOC_HAVE_PTHREAD_GET_NAME_NP) | ||
| 310 | pthread_get_name_np(pthread_self(), buf, limit); | ||
| 311 | return 0; | ||
| 312 | #else | ||
| 313 | return ENOSYS; | ||
| 314 | #endif | ||
| 315 | } | ||
| 316 | prof_sys_thread_name_read_t *JET_MUTABLE prof_sys_thread_name_read = | ||
| 317 | prof_sys_thread_name_read_impl; | ||
| 318 | |||
| 319 | void | ||
| 320 | prof_sys_thread_name_fetch(tsd_t *tsd) { | ||
| 321 | #define THREAD_NAME_MAX_LEN 16 | ||
| 322 | char buf[THREAD_NAME_MAX_LEN]; | ||
| 323 | if (!prof_sys_thread_name_read(buf, THREAD_NAME_MAX_LEN)) { | ||
| 324 | prof_thread_name_set_impl(tsd, buf); | ||
| 325 | } | ||
| 326 | #undef THREAD_NAME_MAX_LEN | ||
| 327 | } | ||
| 328 | |||
| 329 | int | ||
| 330 | prof_getpid(void) { | ||
| 331 | #ifdef _WIN32 | ||
| 332 | return GetCurrentProcessId(); | ||
| 333 | #else | ||
| 334 | return getpid(); | ||
| 335 | #endif | ||
| 336 | } | ||
| 337 | |||
| 338 | /* | ||
| 339 | * This buffer is rather large for stack allocation, so use a single buffer for | ||
| 340 | * all profile dumps; protected by prof_dump_mtx. | ||
| 341 | */ | ||
| 342 | static char prof_dump_buf[PROF_DUMP_BUFSIZE]; | ||
| 343 | |||
| 344 | typedef struct prof_dump_arg_s prof_dump_arg_t; | ||
| 345 | struct prof_dump_arg_s { | ||
| 346 | /* | ||
| 347 | * Whether error should be handled locally: if true, then we print out | ||
| 348 | * error message as well as abort (if opt_abort is true) when an error | ||
| 349 | * occurred, and we also report the error back to the caller in the end; | ||
| 350 | * if false, then we only report the error back to the caller in the | ||
| 351 | * end. | ||
| 352 | */ | ||
| 353 | const bool handle_error_locally; | ||
| 354 | /* | ||
| 355 | * Whether there has been an error in the dumping process, which could | ||
| 356 | * have happened either in file opening or in file writing. When an | ||
| 357 | * error has already occurred, we will stop further writing to the file. | ||
| 358 | */ | ||
| 359 | bool error; | ||
| 360 | /* File descriptor of the dump file. */ | ||
| 361 | int prof_dump_fd; | ||
| 362 | }; | ||
| 363 | |||
| 364 | static void | ||
| 365 | prof_dump_check_possible_error(prof_dump_arg_t *arg, bool err_cond, | ||
| 366 | const char *format, ...) { | ||
| 367 | assert(!arg->error); | ||
| 368 | if (!err_cond) { | ||
| 369 | return; | ||
| 370 | } | ||
| 371 | |||
| 372 | arg->error = true; | ||
| 373 | if (!arg->handle_error_locally) { | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | |||
| 377 | va_list ap; | ||
| 378 | char buf[PROF_PRINTF_BUFSIZE]; | ||
| 379 | va_start(ap, format); | ||
| 380 | malloc_vsnprintf(buf, sizeof(buf), format, ap); | ||
| 381 | va_end(ap); | ||
| 382 | malloc_write(buf); | ||
| 383 | |||
| 384 | if (opt_abort) { | ||
| 385 | abort(); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | static int | ||
| 390 | prof_dump_open_file_impl(const char *filename, int mode) { | ||
| 391 | return creat(filename, mode); | ||
| 392 | } | ||
| 393 | prof_dump_open_file_t *JET_MUTABLE prof_dump_open_file = | ||
| 394 | prof_dump_open_file_impl; | ||
| 395 | |||
| 396 | static void | ||
| 397 | prof_dump_open(prof_dump_arg_t *arg, const char *filename) { | ||
| 398 | arg->prof_dump_fd = prof_dump_open_file(filename, 0644); | ||
| 399 | prof_dump_check_possible_error(arg, arg->prof_dump_fd == -1, | ||
| 400 | "<jemalloc>: failed to open \"%s\"\n", filename); | ||
| 401 | } | ||
| 402 | |||
| 403 | prof_dump_write_file_t *JET_MUTABLE prof_dump_write_file = malloc_write_fd; | ||
| 404 | |||
| 405 | static void | ||
| 406 | prof_dump_flush(void *opaque, const char *s) { | ||
| 407 | cassert(config_prof); | ||
| 408 | prof_dump_arg_t *arg = (prof_dump_arg_t *)opaque; | ||
| 409 | if (!arg->error) { | ||
| 410 | ssize_t err = prof_dump_write_file(arg->prof_dump_fd, s, | ||
| 411 | strlen(s)); | ||
| 412 | prof_dump_check_possible_error(arg, err == -1, | ||
| 413 | "<jemalloc>: failed to write during heap profile flush\n"); | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 417 | static void | ||
| 418 | prof_dump_close(prof_dump_arg_t *arg) { | ||
| 419 | if (arg->prof_dump_fd != -1) { | ||
| 420 | close(arg->prof_dump_fd); | ||
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 424 | #ifndef _WIN32 | ||
| 425 | JEMALLOC_FORMAT_PRINTF(1, 2) | ||
| 426 | static int | ||
| 427 | prof_open_maps_internal(const char *format, ...) { | ||
| 428 | int mfd; | ||
| 429 | va_list ap; | ||
| 430 | char filename[PATH_MAX + 1]; | ||
| 431 | |||
| 432 | va_start(ap, format); | ||
| 433 | malloc_vsnprintf(filename, sizeof(filename), format, ap); | ||
| 434 | va_end(ap); | ||
| 435 | |||
| 436 | #if defined(O_CLOEXEC) | ||
| 437 | mfd = open(filename, O_RDONLY | O_CLOEXEC); | ||
| 438 | #else | ||
| 439 | mfd = open(filename, O_RDONLY); | ||
| 440 | if (mfd != -1) { | ||
| 441 | fcntl(mfd, F_SETFD, fcntl(mfd, F_GETFD) | FD_CLOEXEC); | ||
| 442 | } | ||
| 443 | #endif | ||
| 444 | |||
| 445 | return mfd; | ||
| 446 | } | ||
| 447 | #endif | ||
| 448 | |||
| 449 | static int | ||
| 450 | prof_dump_open_maps_impl() { | ||
| 451 | int mfd; | ||
| 452 | |||
| 453 | cassert(config_prof); | ||
| 454 | #if defined(__FreeBSD__) || defined(__DragonFly__) | ||
| 455 | mfd = prof_open_maps_internal("/proc/curproc/map"); | ||
| 456 | #elif defined(_WIN32) | ||
| 457 | mfd = -1; // Not implemented | ||
| 458 | #else | ||
| 459 | int pid = prof_getpid(); | ||
| 460 | |||
| 461 | mfd = prof_open_maps_internal("/proc/%d/task/%d/maps", pid, pid); | ||
| 462 | if (mfd == -1) { | ||
| 463 | mfd = prof_open_maps_internal("/proc/%d/maps", pid); | ||
| 464 | } | ||
| 465 | #endif | ||
| 466 | return mfd; | ||
| 467 | } | ||
| 468 | prof_dump_open_maps_t *JET_MUTABLE prof_dump_open_maps = | ||
| 469 | prof_dump_open_maps_impl; | ||
| 470 | |||
| 471 | static ssize_t | ||
| 472 | prof_dump_read_maps_cb(void *read_cbopaque, void *buf, size_t limit) { | ||
| 473 | int mfd = *(int *)read_cbopaque; | ||
| 474 | assert(mfd != -1); | ||
| 475 | return malloc_read_fd(mfd, buf, limit); | ||
| 476 | } | ||
| 477 | |||
| 478 | static void | ||
| 479 | prof_dump_maps(buf_writer_t *buf_writer) { | ||
| 480 | int mfd = prof_dump_open_maps(); | ||
| 481 | if (mfd == -1) { | ||
| 482 | return; | ||
| 483 | } | ||
| 484 | |||
| 485 | buf_writer_cb(buf_writer, "\nMAPPED_LIBRARIES:\n"); | ||
| 486 | buf_writer_pipe(buf_writer, prof_dump_read_maps_cb, &mfd); | ||
| 487 | close(mfd); | ||
| 488 | } | ||
| 489 | |||
| 490 | static bool | ||
| 491 | prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, | ||
| 492 | bool leakcheck) { | ||
| 493 | cassert(config_prof); | ||
| 494 | assert(tsd_reentrancy_level_get(tsd) == 0); | ||
| 495 | |||
| 496 | prof_tdata_t * tdata = prof_tdata_get(tsd, true); | ||
| 497 | if (tdata == NULL) { | ||
| 498 | return true; | ||
| 499 | } | ||
| 500 | |||
| 501 | prof_dump_arg_t arg = {/* handle_error_locally */ !propagate_err, | ||
| 502 | /* error */ false, /* prof_dump_fd */ -1}; | ||
| 503 | |||
| 504 | pre_reentrancy(tsd, NULL); | ||
| 505 | malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); | ||
| 506 | |||
| 507 | prof_dump_open(&arg, filename); | ||
| 508 | buf_writer_t buf_writer; | ||
| 509 | bool err = buf_writer_init(tsd_tsdn(tsd), &buf_writer, prof_dump_flush, | ||
| 510 | &arg, prof_dump_buf, PROF_DUMP_BUFSIZE); | ||
| 511 | assert(!err); | ||
| 512 | prof_dump_impl(tsd, buf_writer_cb, &buf_writer, tdata, leakcheck); | ||
| 513 | prof_dump_maps(&buf_writer); | ||
| 514 | buf_writer_terminate(tsd_tsdn(tsd), &buf_writer); | ||
| 515 | prof_dump_close(&arg); | ||
| 516 | |||
| 517 | prof_dump_hook_t dump_hook = prof_dump_hook_get(); | ||
| 518 | if (dump_hook != NULL) { | ||
| 519 | dump_hook(filename); | ||
| 520 | } | ||
| 521 | malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); | ||
| 522 | post_reentrancy(tsd); | ||
| 523 | |||
| 524 | return arg.error; | ||
| 525 | } | ||
| 526 | |||
| 527 | /* | ||
| 528 | * If profiling is off, then PROF_DUMP_FILENAME_LEN is 1, so we'll end up | ||
| 529 | * calling strncpy with a size of 0, which triggers a -Wstringop-truncation | ||
| 530 | * warning (strncpy can never actually be called in this case, since we bail out | ||
| 531 | * much earlier when config_prof is false). This function works around the | ||
| 532 | * warning to let us leave the warning on. | ||
| 533 | */ | ||
| 534 | static inline void | ||
| 535 | prof_strncpy(char *UNUSED dest, const char *UNUSED src, size_t UNUSED size) { | ||
| 536 | cassert(config_prof); | ||
| 537 | #ifdef JEMALLOC_PROF | ||
| 538 | strncpy(dest, src, size); | ||
| 539 | #endif | ||
| 540 | } | ||
| 541 | |||
| 542 | static const char * | ||
| 543 | prof_prefix_get(tsdn_t* tsdn) { | ||
| 544 | malloc_mutex_assert_owner(tsdn, &prof_dump_filename_mtx); | ||
| 545 | |||
| 546 | return prof_prefix == NULL ? opt_prof_prefix : prof_prefix; | ||
| 547 | } | ||
| 548 | |||
| 549 | static bool | ||
| 550 | prof_prefix_is_empty(tsdn_t *tsdn) { | ||
| 551 | malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); | ||
| 552 | bool ret = (prof_prefix_get(tsdn)[0] == '\0'); | ||
| 553 | malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); | ||
| 554 | return ret; | ||
| 555 | } | ||
| 556 | |||
| 557 | #define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) | ||
| 558 | #define VSEQ_INVALID UINT64_C(0xffffffffffffffff) | ||
| 559 | static void | ||
| 560 | prof_dump_filename(tsd_t *tsd, char *filename, char v, uint64_t vseq) { | ||
| 561 | cassert(config_prof); | ||
| 562 | |||
| 563 | assert(tsd_reentrancy_level_get(tsd) == 0); | ||
| 564 | const char *prefix = prof_prefix_get(tsd_tsdn(tsd)); | ||
| 565 | |||
| 566 | if (vseq != VSEQ_INVALID) { | ||
| 567 | /* "<prefix>.<pid>.<seq>.v<vseq>.heap" */ | ||
| 568 | malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, | ||
| 569 | "%s.%d.%"FMTu64".%c%"FMTu64".heap", prefix, prof_getpid(), | ||
| 570 | prof_dump_seq, v, vseq); | ||
| 571 | } else { | ||
| 572 | /* "<prefix>.<pid>.<seq>.<v>.heap" */ | ||
| 573 | malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, | ||
| 574 | "%s.%d.%"FMTu64".%c.heap", prefix, prof_getpid(), | ||
| 575 | prof_dump_seq, v); | ||
| 576 | } | ||
| 577 | prof_dump_seq++; | ||
| 578 | } | ||
| 579 | |||
| 580 | void | ||
| 581 | prof_get_default_filename(tsdn_t *tsdn, char *filename, uint64_t ind) { | ||
| 582 | malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); | ||
| 583 | malloc_snprintf(filename, PROF_DUMP_FILENAME_LEN, | ||
| 584 | "%s.%d.%"FMTu64".json", prof_prefix_get(tsdn), prof_getpid(), ind); | ||
| 585 | malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); | ||
| 586 | } | ||
| 587 | |||
| 588 | void | ||
| 589 | prof_fdump_impl(tsd_t *tsd) { | ||
| 590 | char filename[DUMP_FILENAME_BUFSIZE]; | ||
| 591 | |||
| 592 | assert(!prof_prefix_is_empty(tsd_tsdn(tsd))); | ||
| 593 | malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 594 | prof_dump_filename(tsd, filename, 'f', VSEQ_INVALID); | ||
| 595 | malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 596 | prof_dump(tsd, false, filename, opt_prof_leak); | ||
| 597 | } | ||
| 598 | |||
| 599 | bool | ||
| 600 | prof_prefix_set(tsdn_t *tsdn, const char *prefix) { | ||
| 601 | cassert(config_prof); | ||
| 602 | ctl_mtx_assert_held(tsdn); | ||
| 603 | malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); | ||
| 604 | if (prof_prefix == NULL) { | ||
| 605 | malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); | ||
| 606 | /* Everything is still guarded by ctl_mtx. */ | ||
| 607 | char *buffer = base_alloc(tsdn, prof_base, | ||
| 608 | PROF_DUMP_FILENAME_LEN, QUANTUM); | ||
| 609 | if (buffer == NULL) { | ||
| 610 | return true; | ||
| 611 | } | ||
| 612 | malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); | ||
| 613 | prof_prefix = buffer; | ||
| 614 | } | ||
| 615 | assert(prof_prefix != NULL); | ||
| 616 | |||
| 617 | prof_strncpy(prof_prefix, prefix, PROF_DUMP_FILENAME_LEN - 1); | ||
| 618 | prof_prefix[PROF_DUMP_FILENAME_LEN - 1] = '\0'; | ||
| 619 | malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); | ||
| 620 | |||
| 621 | return false; | ||
| 622 | } | ||
| 623 | |||
| 624 | void | ||
| 625 | prof_idump_impl(tsd_t *tsd) { | ||
| 626 | malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 627 | if (prof_prefix_get(tsd_tsdn(tsd))[0] == '\0') { | ||
| 628 | malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 629 | return; | ||
| 630 | } | ||
| 631 | char filename[PATH_MAX + 1]; | ||
| 632 | prof_dump_filename(tsd, filename, 'i', prof_dump_iseq); | ||
| 633 | prof_dump_iseq++; | ||
| 634 | malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 635 | prof_dump(tsd, false, filename, false); | ||
| 636 | } | ||
| 637 | |||
| 638 | bool | ||
| 639 | prof_mdump_impl(tsd_t *tsd, const char *filename) { | ||
| 640 | char filename_buf[DUMP_FILENAME_BUFSIZE]; | ||
| 641 | if (filename == NULL) { | ||
| 642 | /* No filename specified, so automatically generate one. */ | ||
| 643 | malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 644 | if (prof_prefix_get(tsd_tsdn(tsd))[0] == '\0') { | ||
| 645 | malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 646 | return true; | ||
| 647 | } | ||
| 648 | prof_dump_filename(tsd, filename_buf, 'm', prof_dump_mseq); | ||
| 649 | prof_dump_mseq++; | ||
| 650 | malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); | ||
| 651 | filename = filename_buf; | ||
| 652 | } | ||
| 653 | return prof_dump(tsd, true, filename, false); | ||
| 654 | } | ||
| 655 | |||
| 656 | void | ||
| 657 | prof_gdump_impl(tsd_t *tsd) { | ||
| 658 | tsdn_t *tsdn = tsd_tsdn(tsd); | ||
| 659 | malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); | ||
| 660 | if (prof_prefix_get(tsdn)[0] == '\0') { | ||
| 661 | malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); | ||
| 662 | return; | ||
| 663 | } | ||
| 664 | char filename[DUMP_FILENAME_BUFSIZE]; | ||
| 665 | prof_dump_filename(tsd, filename, 'u', prof_dump_useq); | ||
| 666 | prof_dump_useq++; | ||
| 667 | malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); | ||
| 668 | prof_dump(tsd, false, filename, false); | ||
| 669 | } | ||
