Skip to content

Commit

Permalink
Multithreaded locking fixes.
Browse files Browse the repository at this point in the history
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4692 c046a42c-6fe2-441c-8c8c-71466251a162
  • Loading branch information
pbrook committed Jun 7, 2008
1 parent 0a878c4 commit d597536
Show file tree
Hide file tree
Showing 10 changed files with 447 additions and 237 deletions.
1 change: 1 addition & 0 deletions cpu-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ typedef struct CPUTLBEntry {
\
void *next_cpu; /* next CPU sharing TB cache */ \
int cpu_index; /* CPU index (informative) */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
/* user data */ \
void *opaque; \
\
Expand Down
25 changes: 11 additions & 14 deletions cpu-exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
#endif

int tb_invalidated_flag;
static unsigned long next_tb;

//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
Expand Down Expand Up @@ -93,8 +92,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
uint8_t *tc_ptr;

spin_lock(&tb_lock);

tb_invalidated_flag = 0;

regs_to_env(); /* XXX: do it just before cpu_gen_code() */
Expand Down Expand Up @@ -155,7 +152,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
found:
/* we add the TB in the virtual pc hash table */
env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
spin_unlock(&tb_lock);
return tb;
}

Expand Down Expand Up @@ -228,14 +224,6 @@ static inline TranslationBlock *tb_find_fast(void)
if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
tb->flags != flags, 0)) {
tb = tb_find_slow(pc, cs_base, flags);
/* Note: we do it here to avoid a gcc bug on Mac OS X when
doing it in tb_find_slow */
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
next_tb = 0;
}
}
return tb;
}
Expand All @@ -249,6 +237,7 @@ int cpu_exec(CPUState *env1)
int ret, interrupt_request;
TranslationBlock *tb;
uint8_t *tc_ptr;
unsigned long next_tb;

if (cpu_halted(env1) == EXCP_HALTED)
return EXCP_HALTED;
Expand Down Expand Up @@ -577,7 +566,16 @@ int cpu_exec(CPUState *env1)
#endif
}
#endif
spin_lock(&tb_lock);
tb = tb_find_fast();
/* Note: we do it here to avoid a gcc bug on Mac OS X when
doing it in tb_find_slow */
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
next_tb = 0;
}
#ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_EXEC)) {
fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
Expand All @@ -594,11 +592,10 @@ int cpu_exec(CPUState *env1)
(env->kqemu_enabled != 2) &&
#endif
tb->page_addr[1] == -1) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
spin_unlock(&tb_lock);
}
}
spin_unlock(&tb_lock);
tc_ptr = tb->tc_ptr;
env->current_tb = tb;
/* execute the generated code */
Expand Down
212 changes: 1 addition & 211 deletions exec-all.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,217 +302,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];

#if defined(__hppa__)

typedef int spinlock_t[4];

#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }

static inline void resetlock (spinlock_t *p)
{
(*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
}

#else

typedef int spinlock_t;

#define SPIN_LOCK_UNLOCKED 0

static inline void resetlock (spinlock_t *p)
{
*p = SPIN_LOCK_UNLOCKED;
}

#endif

#if defined(__powerpc__)
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ (
"0: lwarx %0,0,%1\n"
" xor. %0,%3,%0\n"
" bne 1f\n"
" stwcx. %2,0,%1\n"
" bne- 0b\n"
"1: "
: "=&r" (ret)
: "r" (p), "r" (1), "r" (0)
: "cr0", "memory");
return ret;
}
#elif defined(__i386__)
static inline int testandset (int *p)
{
long int readval = 0;

__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
: "+m" (*p), "+a" (readval)
: "r" (1)
: "cc");
return readval;
}
#elif defined(__x86_64__)
static inline int testandset (int *p)
{
long int readval = 0;

__asm__ __volatile__ ("lock; cmpxchgl %2, %0"
: "+m" (*p), "+a" (readval)
: "r" (1)
: "cc");
return readval;
}
#elif defined(__s390__)
static inline int testandset (int *p)
{
int ret;

__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#elif defined(__alpha__)
static inline int testandset (int *p)
{
int ret;
unsigned long one;

__asm__ __volatile__ ("0: mov 1,%2\n"
" ldl_l %0,%1\n"
" stl_c %2,%1\n"
" beq %2,1f\n"
".subsection 2\n"
"1: br 0b\n"
".previous"
: "=r" (ret), "=m" (*p), "=r" (one)
: "m" (*p));
return ret;
}
#elif defined(__sparc__)
static inline int testandset (int *p)
{
int ret;

__asm__ __volatile__("ldstub [%1], %0"
: "=r" (ret)
: "r" (p)
: "memory");

return (ret ? 1 : 0);
}
#elif defined(__arm__)
static inline int testandset (int *spinlock)
{
register unsigned int ret;
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(ret)
: "0"(1), "r"(spinlock));

return ret;
}
#elif defined(__mc68000)
static inline int testandset (int *p)
{
char ret;
__asm__ __volatile__("tas %1; sne %0"
: "=r" (ret)
: "m" (p)
: "cc","memory");
return ret;
}
#elif defined(__hppa__)

/* Because malloc only guarantees 8-byte alignment for malloc'd data,
and GCC only guarantees 8-byte alignment for stack locals, we can't
be assured of 16-byte alignment for atomic lock data even if we
specify "__attribute ((aligned(16)))" in the type declaration. So,
we use a struct containing an array of four ints for the atomic lock
type and dynamically select the 16-byte aligned int from the array
for the semaphore. */
#define __PA_LDCW_ALIGNMENT 16
static inline void *ldcw_align (void *p) {
unsigned long a = (unsigned long)p;
a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
return (void *)a;
}

static inline int testandset (spinlock_t *p)
{
unsigned int ret;
p = ldcw_align(p);
__asm__ __volatile__("ldcw 0(%1),%0"
: "=r" (ret)
: "r" (p)
: "memory" );
return !ret;
}

#elif defined(__ia64)

#include <ia64intrin.h>

static inline int testandset (int *p)
{
return __sync_lock_test_and_set (p, 1);
}
#elif defined(__mips__)
static inline int testandset (int *p)
{
int ret;

__asm__ __volatile__ (
" .set push \n"
" .set noat \n"
" .set mips2 \n"
"1: li $1, 1 \n"
" ll %0, %1 \n"
" sc $1, %1 \n"
" beqz $1, 1b \n"
" .set pop "
: "=r" (ret), "+R" (*p)
:
: "memory");

return ret;
}
#else
#error unimplemented CPU support
#endif

#if defined(CONFIG_USER_ONLY)
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
}

static inline void spin_unlock(spinlock_t *lock)
{
resetlock(lock);
}

static inline int spin_trylock(spinlock_t *lock)
{
return !testandset(lock);
}
#else
static inline void spin_lock(spinlock_t *lock)
{
}

static inline void spin_unlock(spinlock_t *lock)
{
}

static inline int spin_trylock(spinlock_t *lock)
{
return 1;
}
#endif
#include "qemu-lock.h"

extern spinlock_t tb_lock;

Expand Down
13 changes: 11 additions & 2 deletions exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1341,10 +1341,20 @@ void cpu_set_log_filename(const char *filename)
/* mask must never be zero, except for A20 change call */
void cpu_interrupt(CPUState *env, int mask)
{
#if !defined(USE_NPTL)
TranslationBlock *tb;
static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
#endif

/* FIXME: This is probably not threadsafe. A different thread could
be in the mittle of a read-modify-write operation. */
env->interrupt_request |= mask;
#if defined(USE_NPTL)
/* FIXME: TB unchaining isn't SMP safe. For now just ignore the
problem and hope the cpu will stop of its own accord. For userspace
emulation this often isn't actually as bad as it sounds. Often
signals are used primarily to interrupt blocking syscalls. */
#else
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
tb = env->current_tb;
Expand All @@ -1353,6 +1363,7 @@ void cpu_interrupt(CPUState *env, int mask)
tb_reset_jump_recursive(tb);
resetlock(&interrupt_lock);
}
#endif
}

void cpu_reset_interrupt(CPUState *env, int mask)
Expand Down Expand Up @@ -2015,7 +2026,6 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
end = TARGET_PAGE_ALIGN(end);
if (flags & PAGE_WRITE)
flags |= PAGE_WRITE_ORG;
spin_lock(&tb_lock);
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
p = page_find_alloc(addr >> TARGET_PAGE_BITS);
/* if the write protection is set, then we invalidate the code
Expand All @@ -2027,7 +2037,6 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
}
p->flags = flags;
}
spin_unlock(&tb_lock);
}

int page_check_range(target_ulong start, target_ulong len, int flags)
Expand Down
4 changes: 2 additions & 2 deletions linux-user/elfload.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ enum {
static const char *get_elf_platform(void)
{
static char elf_platform[] = "i386";
int family = (global_env->cpuid_version >> 8) & 0xff;
int family = (thread_env->cpuid_version >> 8) & 0xff;
if (family > 6)
family = 6;
if (family >= 3)
Expand All @@ -101,7 +101,7 @@ static const char *get_elf_platform(void)

static uint32_t get_elf_hwcap(void)
{
return global_env->cpuid_features;
return thread_env->cpuid_features;
}

#ifdef TARGET_X86_64
Expand Down
Loading

0 comments on commit d597536

Please sign in to comment.