Commit d5975363 authored by Paul Brook's avatar Paul Brook
Browse files

Multithreaded locking fixes.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4692 c046a42c-6fe2-441c-8c8c-71466251a162
parent 0a878c47
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;                                                       \
                                                                        \
+11 −14
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@
#endif

int tb_invalidated_flag;
static unsigned long next_tb;

//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
@@ -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() */
@@ -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;
}

@@ -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;
}
@@ -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;
@@ -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",
@@ -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 */
+1 −211
Original line number Diff line number Diff line
@@ -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;

+11 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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)
@@ -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
@@ -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)
+2 −2
Original line number Diff line number Diff line
@@ -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)
@@ -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
Loading