Skip to content

Commit b92c116

Browse files
committed
allow initial main thread to terminate before the process terminates (see issue #1287)
1 parent 7e6c550 commit b92c116

8 files changed

Lines changed: 75 additions & 28 deletions

File tree

include/mimalloc/prim.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,9 @@ extern mi_decl_hidden bool _mi_process_is_initialized; // has mi_
248248
// fast path of `_mi_free` and we specialize for various platforms as
249249
// inlined definitions. Regular code should call `init.c:_mi_thread_id()`.
250250
// We only require _mi_prim_thread_id() to return a unique id
251-
// for each thread (unequal to zero).
251+
// for each thread (unequal to zero) with the bottom 2 bits clear.
252252
//-------------------------------------------------------------------
253253

254-
255254
// Do we have __builtin_thread_pointer? This would be the preferred way to get a unique thread id
256255
// but unfortunately, it seems we cannot test for this reliably at this time (see issue #883)
257256
// Nevertheless, it seems needed on older graviton platforms (see issue #851).

src/alloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static mi_decl_forceinline mi_decl_restrict void* mi_theap_malloc_small_zero_non
133133
mi_assert(size <= MI_SMALL_SIZE_MAX);
134134
#if MI_DEBUG
135135
const uintptr_t tid = _mi_thread_id();
136-
mi_assert(theap->tld->thread_id == 0 || theap->tld->thread_id == tid); // theaps are thread local
136+
mi_assert(theap->tld->thread_id == ~0UL || theap->tld->thread_id == tid); // theaps are thread local
137137
#endif
138138
#if (MI_PADDING || MI_GUARDED)
139139
if mi_unlikely(size == 0) { size = sizeof(void*); }

src/init.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,13 @@ mi_decl_cache_align const mi_theap_t _mi_theap_empty_wrong = {
163163

164164
// Heap for the main thread
165165

166+
#define MI_THREADID_UNINIT ((mi_threadid_t)(~0))
167+
166168
extern mi_decl_hidden mi_decl_cache_align mi_theap_t theap_main;
167169
extern mi_decl_hidden mi_decl_cache_align mi_heap_t heap_main;
168170

169171
static mi_decl_cache_align mi_tld_t tld_main = {
170-
0, // thread_id
172+
MI_THREADID_UNINIT, // thread_id
171173
0, // thread_seq
172174
0, // numa node
173175
&subproc_main, // subproc
@@ -214,7 +216,7 @@ mi_decl_cache_align mi_heap_t heap_main
214216
mi_decl_hidden mi_decl_thread mi_theap_t* __mi_theap_main = NULL;
215217

216218
mi_threadid_t _mi_thread_id(void) mi_attr_noexcept {
217-
mi_threadid_t tid = _mi_prim_thread_id();
219+
const mi_threadid_t tid = _mi_prim_thread_id();
218220
mi_assert_internal( (tid & 0x03) == 0 ); // mimalloc reserves the bottom 2 bits
219221
return tid;
220222
}
@@ -298,7 +300,7 @@ static void mi_subproc_main_init(void) {
298300

299301
// Initialize main tld
300302
static void mi_tld_main_init(void) {
301-
if (tld_main.thread_id == 0) {
303+
if (tld_main.thread_id == MI_THREADID_UNINIT) {
302304
tld_main.thread_id = _mi_prim_thread_id();
303305
mi_lock_init(&tld_main.theaps_lock);
304306
}
@@ -379,17 +381,11 @@ static mi_tld_t* mi_tld_alloc(void) {
379381
#define MI_TLD_INVALID ((mi_tld_t*)1)
380382

381383
mi_decl_noinline static void mi_tld_free(mi_tld_t* tld) {
382-
mi_lock_done(&tld->theaps_lock);
383-
if (tld != NULL && tld != MI_TLD_INVALID) {
384-
mi_atomic_decrement_relaxed(&tld->subproc->thread_count);
385-
_mi_meta_free(tld, sizeof(mi_tld_t), tld->memid);
386-
}
387-
#if 0
388-
// do not read/write to `thread_tld` on older macOS <= 14 as that will re-initialize the thread local storage
389-
// (since we are calling this during pthread shutdown)
390-
// (and this could happen on other systems as well, so let's never do it)
391-
thread_tld = MI_TLD_INVALID;
392-
#endif
384+
if (tld==NULL || tld==MI_TLD_INVALID) return;
385+
mi_atomic_decrement_relaxed(&tld->subproc->thread_count);
386+
tld->thread_id = 0;
387+
mi_lock_done(&tld->theaps_lock);
388+
_mi_meta_free(tld, sizeof(mi_tld_t), tld->memid); // note: safe for static tld_main
393389
}
394390

395391
// return the thread local heap ensuring it is initialized (and not `NULL` or `&_mi_theap_empty`);
@@ -704,7 +700,7 @@ static void mi_process_setup_auto_thread_done(void) {
704700

705701

706702
bool _mi_is_main_thread(void) {
707-
return (tld_main.thread_id==0 || tld_main.thread_id == _mi_thread_id());
703+
return (tld_main.thread_id==MI_THREADID_UNINIT || tld_main.thread_id == _mi_thread_id());
708704
}
709705

710706

src/prim/prim.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ terms of the MIT license. A copy of the license can be found in the file
2727
#endif
2828

2929
// Generic process initialization
30-
#ifndef MI_PRIM_HAS_PROCESS_ATTACH
30+
#if !defined(MI_PRIM_HAS_PROCESS_ATTACH)
3131
#if defined(__GNUC__) || defined(__clang__)
3232
// gcc,clang: use the constructor/destructor attribute
3333
// which for both seem to run before regular constructors/destructors

src/theap.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ void _mi_theap_incref(mi_theap_t* theap) {
289289
}
290290

291291
void _mi_theap_decref(mi_theap_t* theap) {
292-
if (theap!=NULL && theap->memid.memkind > MI_MEM_STATIC) {
292+
if (theap!=NULL && !mi_memid_needs_no_free(theap->memid)) {
293293
if (mi_atomic_decrement_acq_rel(&theap->refcount) == 1) {
294294
mi_theap_free_mem(theap);
295295
}
@@ -324,8 +324,9 @@ bool _mi_theap_free(mi_theap_t* theap, bool acquire_heap_theaps_lock, bool acqui
324324
if (theap->tnext != NULL) { theap->tnext->tprev = theap->tprev; }
325325
if (theap->tprev != NULL) { theap->tprev->tnext = theap->tnext; }
326326
else { mi_assert_internal(theap->tld->theaps == theap); theap->tld->theaps = theap->tnext; }
327-
theap->tnext = theap->tprev = NULL;
327+
theap->tnext = theap->tprev = NULL;
328328
}
329+
329330
theap->tld = NULL;
330331
_mi_theap_decref(theap);
331332
return true;

test/main-static-dep.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ static Static s = Static();
2424

2525
void Test(void) {
2626
char* s = mi_mallocn_tp(char, 128);
27-
strcpy_s(s, 128, "hello world!");
27+
strlcpy(s, "hello world!", 128);
2828
printf("message from static dll: %s\n", s);
2929
mi_free(s);
3030
}
3131

32-
32+
#ifdef WIN32
3333
#include <windows.h>
3434

3535
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) {
@@ -44,3 +44,4 @@ BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) {
4444
}
4545
return TRUE;
4646
}
47+
#endif

test/main-static-dep.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
#pragma once
22

3-
typedef void (__stdcall * TestFun)(void);
4-
53
#if __cplusplus
6-
extern "C"
4+
extern "C" {
75
#endif
8-
__declspec(dllexport) void __cdecl Test(void);
9-
106

7+
#ifdef WIN32
8+
typedef void (__cdecl *TestFun)(void);
9+
__declspec(dllexport) void __cdecl Test(void);
10+
#else
11+
typedef void (*TestFun)(void);
12+
void Test(void);
13+
#endif
1114

15+
#if __cplusplus
16+
}
17+
#endif

test/main-static.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <stdlib.h>
2+
#include <stdio.h>
3+
#include <assert.h>
4+
#include <string.h>
5+
#include <stdint.h>
6+
7+
#include <mimalloc.h>
8+
#include <new>
9+
#include <vector>
10+
#include <future>
11+
#include <iostream>
12+
#include <thread>
13+
#include <random>
14+
#include <chrono>
15+
#include <assert.h>
16+
17+
#include <dlfcn.h>
18+
19+
#include "main-static-dep.h"
20+
21+
TestFun fun;
22+
void* so;
23+
24+
void testso() {
25+
fun();
26+
}
27+
28+
void loadso() {
29+
so = dlopen("./libstatic.so", RTLD_LAZY);
30+
fun = (TestFun)dlsym(so,"Test");
31+
testso();
32+
}
33+
34+
static void test_static(void) {
35+
auto t1 = std::thread(&loadso);
36+
t1.join();
37+
auto t2 = std::thread(&testso);
38+
t2.join();
39+
}
40+
41+
int main(int argc, char** argv) {
42+
test_static();
43+
return 0;
44+
}

0 commit comments

Comments
 (0)