Home | History | Annotate | Download | only in tests
      1 #include <sys/mman.h>
      2 #include <pthread.h>
      3 #include <unistd.h>
      4 #include <assert.h>
      5 #include <unistd.h>
      6 #include <sys/syscall.h>
      7 #include "../../config.h"
      8 
      9 #define VG_STRINGIFZ(__str)  #__str
     10 #define VG_STRINGIFY(__str)  VG_STRINGIFZ(__str)
     11 
     12 extern void _exit_with_stack_teardown(void*, size_t);
     13 
     14 /* Below code is modified version of android bionic
     15    pthread_exit: when a detached thread exits: it munmaps
     16    its stack and then exits. We cannot do that in C,
     17    as we cannot touch the stack after the munmap
     18    and before the exit. */
     19 
     20 #if defined(VGP_x86_linux)
     21 asm("\n"
     22     ".text\n"
     23     "\t.globl _exit_with_stack_teardown\n"
     24     "\t.type  _exit_with_stack_teardown,@function\n"
     25     "_exit_with_stack_teardown:\n"
     26     // We can trash registers because this function never returns.
     27     "\tmov 4(%esp), %ebx\n"             // stackBase
     28     "\tmov 8(%esp), %ecx\n"             // stackSize
     29     "\tmov $"VG_STRINGIFY(__NR_munmap)", %eax\n"
     30     "\tint $0x80\n"
     31     // If munmap failed, we ignore the failure and exit anyway.
     32 
     33     "\tmov $0, %ebx\n"                  // status
     34     "\tmovl $"VG_STRINGIFY(__NR_exit)", %eax\n"
     35     "\tint $0x80\n");
     36     // The exit syscall does not return.
     37 
     38 #elif defined(VGP_amd64_linux)
     39 asm("\n"
     40     ".text\n"
     41     "\t.globl _exit_with_stack_teardown\n"
     42     "\t.type  _exit_with_stack_teardown,@function\n"
     43     "_exit_with_stack_teardown:\n"
     44     "\tmov $"VG_STRINGIFY(__NR_munmap)", %eax\n"
     45     "\tsyscall\n"
     46     // If munmap failed, we ignore the failure and exit anyway.
     47     "\tmov $0, %rdi\n"
     48     "\tmov $"VG_STRINGIFY(__NR_exit)", %eax\n"
     49     "\tsyscall\n");
     50   // The exit syscall does not return.
     51 
     52 #elif defined(VGP_arm_linux)
     53 asm("\n"
     54     ".text\n"
     55     "\t.globl _exit_with_stack_teardown\n"
     56     "\t.type  _exit_with_stack_teardown,%function\n"
     57     "_exit_with_stack_teardown:\n"
     58     "\tldr r7, ="VG_STRINGIFY(__NR_munmap)"\n"
     59     "\tswi #0\n"
     60     // If munmap failed, we ignore the failure and exit anyway.
     61 
     62     "\tmov r0, #0\n"
     63     "\tldr r7, ="VG_STRINGIFY(__NR_exit)"\n"
     64     "\tswi #0\n");
     65   // The exit syscall does not return.
     66 
     67 #else
     68 void _exit_with_stack_teardown(void*stack, size_t sz)
     69 {
     70    // asm code not done for this platform.
     71    // Do nothing, just return. The thread will exit spontaneously
     72 }
     73 
     74 #endif
     75 static void *stack;
     76 static size_t sz = 64 * 1024;
     77 
     78 /* This one detaches, does its own thing. */
     79 void* child_fn ( void* arg )
     80 {
     81   int r;
     82   r= pthread_detach( pthread_self() ); assert(!r);
     83   _exit_with_stack_teardown(stack, sz);
     84   return NULL;
     85 }
     86 
     87 /* Parent creates 1 child, that will detach, and exit after destroying
     88    its own stack. */
     89 int main ( void )
     90 {
     91    int r;
     92    pthread_attr_t attr;
     93    pthread_t child;
     94 
     95    r = pthread_attr_init(&attr); assert(!r);
     96 # if !defined(VGO_darwin)
     97    stack = mmap(NULL, sz, PROT_READ|PROT_WRITE,  MAP_PRIVATE | MAP_ANONYMOUS,
     98                 -1, 0);
     99 # else
    100    stack = mmap(NULL, sz, PROT_READ|PROT_WRITE,  MAP_PRIVATE | MAP_ANON,
    101                 -1, 0);
    102 # endif
    103    assert(stack != (void *)-1);
    104    r = pthread_attr_setstack(&attr, stack, sz);
    105    r = pthread_create(&child, &attr, child_fn, NULL); assert(!r);
    106    sleep(1);
    107 
    108    return 0;
    109 }
    110