blob: 3a51c9ea565f4881e47e299df1e6326eade9c971 [file] [edit]
#define _GNU_SOURCE
#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
typedef void* (*mi_malloc_fn)(size_t);
typedef void (*mi_free_fn)(void*);
static const char* lib_path;
static mi_malloc_fn mi_malloc_p;
static mi_free_fn mi_free_p;
static void alloc_and_free(void) {
void* p[4];
for (int i = 0; i < 4; i++) p[i] = mi_malloc_p((size_t)64 << i);
for (int i = 0; i < 4; i++) mi_free_p(p[i]);
}
// T1: loads mimalloc (constructor -> mi_process_init runs here), allocates, exits.
static void* t1(void* arg) {
(void)arg;
printf("T1 pthread_self=%p (dlopen + first mi_malloc happen here, then T1 exits)\n", (void*)pthread_self());
void* h = dlopen(lib_path, RTLD_NOW); // never dlclose'd: the library stays loaded
if (h == NULL) { fprintf(stderr, "dlopen: %s\n", dlerror()); exit(2); }
mi_malloc_p = (mi_malloc_fn)dlsym(h, "mi_malloc");
mi_free_p = (mi_free_fn)dlsym(h, "mi_free");
if (mi_malloc_p == NULL || mi_free_p == NULL) { fprintf(stderr, "dlsym: %s\n", dlerror()); exit(2); }
alloc_and_free();
return (void*)pthread_self();
}
// T2: a fresh thread; with the same stack size glibc's stack cache hands it T1's TCB.
static void* t2(void* arg) {
(void)arg;
printf("T2 pthread_self=%p (calling mi_malloc on this thread)\n", (void*)pthread_self());
fflush(stdout);
alloc_and_free();
return (void*)pthread_self();
}
int main(int argc, char** argv) {
if (argc < 2) { fprintf(stderr, "usage: %s <libmimalloc.so>\n", argv[0]); return 2; }
lib_path = argv[1];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, (size_t)4 << 20); // same size for every thread
pthread_t th; void* t1_self; void* t2_self;
if (pthread_create(&th, &attr, t1, NULL) != 0 || pthread_join(th, &t1_self) != 0) return 2;
int n = 0;
do { // usually the very first T2 reuses T1's TCB; loop just in case
n++;
if (pthread_create(&th, &attr, t2, NULL) != 0 || pthread_join(th, &t2_self) != 0) return 2;
} while (t2_self != t1_self && n < 64);
printf("%s (after %d T2 thread%s)\n", t2_self == t1_self ? "T2 reused T1's TCB" : "no TCB reuse observed", n, n == 1 ? "" : "s");
printf("OK\n");
return 0;
}