implement arch-generic version of __unmapself
authorRich Felker <dalias@aerifal.cx>
Wed, 10 Jun 2015 02:27:40 +0000 (02:27 +0000)
committerRich Felker <dalias@aerifal.cx>
Wed, 10 Jun 2015 02:27:40 +0000 (02:27 +0000)
this can be used to put off writing an asm version of __unmapself for
new archs, or as a permanent solution on archs where it's not
practical or even possible to run momentarily with no stack.

the concept here is simple: the caller takes a lock on a global shared
stack and uses it to make the munmap and exit syscalls. the only trick
is unlocking, which must be done after the thread exits, and this is
achieved by using the set_tid_address syscall to have the kernel zero
and futex-wake the lock word as part of the exit syscall.

src/thread/__unmapself.c

index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1d3bee1d9b0404494db6d2745e31ebe780ed682e 100644 (file)
@@ -0,0 +1,29 @@
+#include "pthread_impl.h"
+#include "atomic.h"
+#include "syscall.h"
+/* cheat and reuse CRTJMP macro from dynlink code */
+#include "dynlink.h"
+
+static volatile int lock;
+static void *unmap_base;
+static size_t unmap_size;
+static char shared_stack[256];
+
+static void do_unmap()
+{
+       __syscall(SYS_munmap, unmap_base, unmap_size);
+       __syscall(SYS_exit);
+}
+
+void __unmapself(void *base, size_t size)
+{
+       int tid=__pthread_self()->tid;
+       char *stack = shared_stack + sizeof shared_stack;
+       stack -= (uintptr_t)stack % 16;
+       while (lock || a_cas(&lock, 0, tid))
+               a_spin();
+       __syscall(SYS_set_tid_address, &lock);
+       unmap_base = base;
+       unmap_size = size;
+       CRTJMP(do_unmap, stack);
+}