/*--------------------------------------------------------------------*/ /*--- ARM-specific libpthread code. arm/libpthread.c ---*/ /*--------------------------------------------------------------------*/ /* This file is part of Valgrind, an extensible x86 protected-mode emulator for monitoring program execution on x86-Unixes. Copyright (C) 2000-2004 Julian Seward jseward@acm.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. The GNU General Public License is contained in the file COPYING. */ /* ALL THIS CODE RUNS ON THE SIMULATED CPU. See the comments at the top of coregrind/vg_libpthread.c for some caveats. */ #include "core.h" /* For the VG_USERREQ__* constants */ #define __USE_UNIX98 #include #undef __USE_UNIX98 #define __USE_GNU #include #undef __USE_GNU #include // Struct used to describe a TDB header, copied from glibc. typedef struct { void *tcb; void *dtv; void *self; int multiple_threads; unsigned long sysinfo; } tcbhead_t; /* --------------------------------------------------- Helper functions for running a thread and for clearing up afterwards. ------------------------------------------------ */ #if 0 typedef void *(*__attribute__ ((stdcall)) REGPARM(3) allocate_tls_t) (void *result); typedef void (*__attribute__ ((stdcall)) REGPARM(3) deallocate_tls_t) (void *tcb, int dealloc_tcb); static allocate_tls_t allocate_tls = NULL; static deallocate_tls_t deallocate_tls = NULL; static int get_gs() { int gs; asm volatile ("movw %%gs, %w0" : "=q" (gs)); return gs & 0xffff; } static void set_gs( int gs ) { I_die_here; asm volatile ("movw %w0, %%gs" :: "q" (gs)); } static void *get_tcb() { void *tcb; asm volatile ("movl %%gs:0, %0" : "=r" (tcb)); return tcb; } #endif Bool VGA_(has_tls)(void) { I_die_here; #if 0 return (get_gs() & 7) == 3; #endif } void VGA_(thread_create)(ThreadArchAux *aux) { I_die_here; #if 0 if (VGA_(has_tls)()) { tcbhead_t *tcb = get_tcb(); if (allocate_tls == NULL || deallocate_tls == NULL) { allocate_tls = (allocate_tls_t)dlsym(RTLD_DEFAULT, "_dl_allocate_tls"); deallocate_tls = (deallocate_tls_t)dlsym(RTLD_DEFAULT, "_dl_deallocate_tls"); } my_assert(allocate_tls != NULL); aux->tls_data = allocate_tls(NULL); aux->tls_segment = get_gs() >> 3; aux->sysinfo = tcb->sysinfo; tcb->multiple_threads = 1; } else { aux->tls_data = NULL; aux->tls_segment = -1; aux->sysinfo = 0; } #endif } void VGA_(thread_wrapper)(ThreadArchAux *aux) { I_die_here; #if 0 void* tls_data; int tls_segment; unsigned long sysinfo; tls_data = aux->tls_data; tls_segment = aux->tls_segment; sysinfo = aux->sysinfo; if (tls_data) { tcbhead_t *tcb = tls_data; vki_modify_ldt_t ldt_info; /* Fill in the TCB header */ tcb->tcb = tcb; tcb->self = tcb; tcb->multiple_threads = 1; tcb->sysinfo = sysinfo; /* Fill in an LDT descriptor */ ldt_info.entry_number = tls_segment; ldt_info.base_addr = (unsigned long)tls_data; ldt_info.limit = 0xfffff; ldt_info.seg_32bit = 1; ldt_info.contents = 0; ldt_info.read_exec_only = 0; ldt_info.limit_in_pages = 1; ldt_info.seg_not_present = 0; ldt_info.useable = 1; ldt_info.reserved = 0; /* Install the thread area */ VG_(do_syscall)(__NR_set_thread_area, &ldt_info); /* Setup the GS segment register */ set_gs(ldt_info.entry_number * 8 + 3); } #endif } void VGA_(thread_exit)(void) { I_die_here; #if 0 /* Free up any TLS data */ if ((get_gs() & 7) == 3 && pthread_self() > 1) { my_assert(deallocate_tls != NULL); deallocate_tls(get_tcb(), 1); } #endif } /* POSIX spinlocks, taken from glibc linuxthreads/sysdeps/i386 */ typedef volatile int pthread_spinlock_t; /* Huh? Guarded by __USE_XOPEN2K */ int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { I_die_here; #if 0 /* We can ignore the `pshared' parameter. Since we are busy-waiting all processes which can access the memory location `lock' points to can use the spinlock. */ *lock = 1; return 0; #endif } int pthread_spin_lock(pthread_spinlock_t *lock) { I_die_here; #if 0 asm volatile ("\n" "1:\n\t" "lock; decl %0\n\t" "js 2f\n\t" ".section .text.spinlock,\"ax\"\n" "2:\n\t" "cmpl $0,%0\n\t" "rep; nop\n\t" "jle 2b\n\t" "jmp 1b\n\t" ".previous" : "=m" (*lock)); return 0; #endif } int pthread_spin_unlock(pthread_spinlock_t *lock) { I_die_here; #if 0 asm volatile ("movl $1,%0" : "=m" (*lock)); return 0; #endif } int pthread_spin_destroy(pthread_spinlock_t *lock) { I_die_here; #if 0 /* Nothing to do. */ return 0; #endif } int pthread_spin_trylock(pthread_spinlock_t *lock) { I_die_here; #if 0 int oldval; asm volatile ("xchgl %0,%1" : "=r" (oldval), "=m" (*lock) : "0" (0)); return oldval > 0 ? 0 : EBUSY; #endif } /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/