Make garbage collection thread safe

- You can now use _gc(malloc()) in multithreaded programs
- This change fixes a bug where fork() on NT disabled TLS
- Fixed TLS code morphing on XNU/NT, for R8-R15 registers
This commit is contained in:
Justine Tunney 2022-09-08 02:33:01 -07:00
parent 571c2c3c69
commit 0e2b1bfeed
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
37 changed files with 310 additions and 189 deletions

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"

View file

@ -20,12 +20,14 @@
#include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/spawn.h"
#include "libc/x/x.h"
#define GC(x) _defer(Free, x)
@ -77,6 +79,45 @@ TEST(gclongjmp, test) {
free(x);
}
void crawl(const char *path) {
const char *dir;
if (!strcmp(path, "/") || !strcmp(path, ".")) return;
crawl(_gc(xdirname(path)));
}
int Worker(void *arg, int tid) {
crawl("a/b/c/d/a/b/c/d/a/b/c/d/a/b/c/d/a/b/c/d/a/b/c/d");
return 0;
}
TEST(gc, torture) {
int i, n = 32;
struct spawn *t = gc(malloc(sizeof(struct spawn) * n));
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i));
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
}
void crawl2(jmp_buf jb, const char *path) {
const char *dir;
if (!strcmp(path, "/") || !strcmp(path, ".")) _gclongjmp(jb, 1);
crawl2(jb, _gc(xdirname(path)));
}
int Worker2(void *arg, int tid) {
jmp_buf jb;
if (!setjmp(jb)) {
crawl2(jb, "a/b/c/d/a/b/c/d/a/b/c/d/a/b/c/d/a/b/c/d/a/b/c/d");
}
return 0;
}
TEST(_gclongjmp, torture) {
int i, n = 32;
struct spawn *t = gc(malloc(sizeof(struct spawn) * n));
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker2, 0, t + i));
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
}
dontinline void F1(void) {
/* 3x slower than F2() but sooo worth it */
gc(malloc(16));

View file

@ -36,6 +36,7 @@ TEST_LIBC_NEXGEN32E_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TESTLIB \
LIBC_X \
TOOL_VIZ_LIB \

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/errno.h"

View file

@ -34,6 +34,7 @@ TEST_LIBC_SOCK_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_LOG \
LIBC_SYSV_CALLS \
LIBC_TESTLIB \
LIBC_X \

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h"