/* Tests that the process can exit even if daemon thread is still running. This test does *not* use any libc; it interfaces only with kernel. */ #include <sys/lwp.h> #include <sys/mman.h> #include <sys/regset.h> #include <sys/syscall.h> #include <sys/ucontext.h> #if defined(__amd64) || defined(__i386) #include <sys/segments.h> #endif extern void bzero(void *ptr, size_t n); #if defined(VGP_x86_solaris) asm("\n" ".text\n" ".globl bzero\n" "bzero:\n" " push %edi\n" " movl $0, %eax\n" " movl 12(%esp), %ecx\n" " movl 8(%esp), %edi\n" " rep stosb\n" " pop %edi\n" " ret\n" ); #elif defined(VGP_amd64_solaris) asm("\n" ".text\n" ".globl bzero\n" "bzero:\n" " push %rdi\n" " movq %rsi, %rcx\n" " movq $0, %rax\n" " rep stosb\n" " pop %rdi\n" " ret\n" ); #else # error "Unknown platform" #endif static void sleep(unsigned int sec) { timespec_t ts; ts.tv_sec = (time_t)sec; ts.tv_nsec = 0; #if defined(VGP_x86_solaris) __asm__ __volatile__ ( "pushl $0\n" "pushl %[TS]\n" "pushl $0xdeadbeef\n" "movl %[SYSNO], %%eax\n" "int $0x91\n" "addl $12, %%esp\n" : : [TS] "g" (&ts), [SYSNO] "n" (SYS_nanosleep) : "eax", "edx", "cc", "memory"); #elif defined(VGP_amd64_solaris) __asm__ __volatile__ ( "movq %[SYSNO], %%rax\n" "movq %[TS], %%rdi\n" "movq $0, %%rsi\n" "syscall\n" : : [TS] "g" (&ts), [SYSNO] "n" (SYS_nanosleep) : "rax", "rdx", "rdi", "rsi", "cc", "memory"); #else # error "Unknown platform" #endif } static void lwp_exit(void) { #if defined(VGP_x86_solaris) __asm__ __volatile__ ( "movl %[SYSNO], %%eax\n" "int $0x91\n" : : [SYSNO] "n" (SYS_lwp_exit) : "eax", "edx", "cc", "memory"); #elif defined(VGP_amd64_solaris) __asm__ __volatile__ ( "movq %[SYSNO], %%rax\n" "syscall\n" : : [SYSNO] "n" (SYS_lwp_exit) : "rax", "rdx", "cc", "memory"); #else # error "Unknown platform" #endif } #define STACK_FLAGS (MAP_PRIVATE | MAP_NORESERVE | MAP_ANON) #define STACK_PROT (PROT_READ | PROT_WRITE) static void *allocate_stack(size_t stacksize) { void *address = NULL; #if defined(VGP_x86_solaris) __asm__ __volatile__ ( "pushl $0\n" "pushl $-1\n" "pushl %[FLAGS]\n" "pushl %[PROT]\n" "pushl %[SIZE]\n" "pushl $0\n" "pushl $0xdeadbeef\n" "movl %[SYSNO], %%eax\n" "int $0x91\n" "addl $28, %%esp\n" "movl %%eax, %[ADDRESS]\n" : [ADDRESS] "=r" (address) : [FLAGS] "n" (STACK_FLAGS), [PROT] "n" (STACK_PROT), [SIZE] "g" (stacksize), [SYSNO] "n" (SYS_mmap) : "eax", "edx", "cc", "memory"); #elif defined(VGP_amd64_solaris) __asm__ __volatile__ ( "movq %[SYSNO], %%rax\n" "movq $0, %%rdi\n" "movq %[SIZE], %%rsi\n" "movq %[PROT], %%rdx\n" "movq %[FLAGS], %%r10\n" "movq $-1, %%r8\n" "movq $0, %%r9\n" "syscall\n" "movq %%rax, %[ADDRESS]\n" : [ADDRESS] "=r" (address) : [FLAGS] "n" (STACK_FLAGS), [PROT] "n" (STACK_PROT), [SIZE] "g" (stacksize), [SYSNO] "n" (SYS_mmap) : "rax", "rdx", "rdi", "rsi", "r10", "r8", "r9", "cc", "memory"); #else # error "Unknown platform" #endif return address; } #undef STACK_FLAGS #undef STACK_PROT static void thread_func(void) { sleep(10000); } #define LWP_FLAGS (LWP_SUSPENDED | LWP_DETACHED | LWP_DAEMON) static id_t lwp_create(void *stack) { id_t tid; ucontext_t ucontext; bzero(&ucontext, sizeof(ucontext)); ucontext.uc_flags = UC_CPU; #if defined(VGP_x86_solaris) __asm__ __volatile__ ( "mov %%ss, %[STACK_SEG]\n" : [STACK_SEG] "=r" (ucontext.uc_mcontext.gregs[SS]) : :); ucontext.uc_mcontext.gregs[EIP] = (greg_t) thread_func; ucontext.uc_mcontext.gregs[UESP] = (greg_t) stack; ucontext.uc_mcontext.gregs[EBP] = (greg_t) stack; #elif defined(VGP_amd64_solaris) ucontext.uc_mcontext.gregs[REG_SS] = UDS_SEL; ucontext.uc_mcontext.gregs[REG_RIP] = (greg_t) thread_func; ucontext.uc_mcontext.gregs[REG_RSP] = (greg_t) stack; ucontext.uc_mcontext.gregs[REG_RBP] = (greg_t) stack; #else # error "Unknown platform" #endif #if defined(VGP_x86_solaris) __asm__ __volatile__ ( "pushl $0\n" "pushl %[FLAGS]\n" "pushl %[UCONTEXT]\n" "pushl $0xdeadbeef\n" "movl %[SYSNO], %%eax\n" "int $0x91\n" "addl $16, %%esp\n" "movl %%eax, %[TID]\n" : [TID] "=r" (tid) : [FLAGS] "n" (LWP_FLAGS), [UCONTEXT] "g" (&ucontext), [SYSNO] "n" (SYS_lwp_create) : "eax", "edx", "cc", "memory"); #elif defined(VGP_amd64_solaris) __asm__ __volatile__ ( "movq %[SYSNO], %%rax\n" "movq %[UCONTEXT], %%rdi\n" "movq %[FLAGS], %%rsi\n" "movq $0, %%rdx\n" "syscall\n" "movl %%eax, %[TID]\n" : [TID] "=r" (tid) : [FLAGS] "n" (LWP_FLAGS), [UCONTEXT] "g" (&ucontext), [SYSNO] "n" (SYS_lwp_create) : "rax", "rdx", "rdi", "rsi", "cc", "memory"); #else # error "Unknown platform" #endif return tid; } static void lwp_continue(id_t tid) { #if defined(VGP_x86_solaris) __asm__ __volatile__ ( "pushl %[TID]\n" "pushl $0xdeadbeef\n" "movl %[SYSNO], %%eax\n" "int $0x91\n" "addl $8, %%esp\n" : : [TID] "m" (tid), [SYSNO] "n" (SYS_lwp_continue) : "eax", "edx", "cc", "memory"); #elif defined(VGP_amd64_solaris) __asm__ __volatile__ ( "movq %[SYSNO], %%rax\n" "xor %%rdi, %%rdi\n" "movl %[TID], %%edi\n" "syscall\n" : : [TID] "r" (tid), [SYSNO] "n" (SYS_lwp_continue) : "rax", "rdx", "rdi", "cc", "memory"); #else # error "Unknown platform" #endif } #define STACK_SIZE 16384 void _start(void) { void *stack = allocate_stack(STACK_SIZE); id_t tid = lwp_create((char *) stack + STACK_SIZE); lwp_continue(tid); sleep(5); lwp_exit(); return; /* not reached */ }