Commit d597536303d762c4209cbab7e379819b8eb14536

Authored by pbrook
1 parent 0a878c47

Multithreaded locking fixes.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4692 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-defs.h
... ... @@ -166,6 +166,7 @@ typedef struct CPUTLBEntry {
166 166 \
167 167 void *next_cpu; /* next CPU sharing TB cache */ \
168 168 int cpu_index; /* CPU index (informative) */ \
  169 + int running; /* Nonzero if cpu is currently running(usermode). */ \
169 170 /* user data */ \
170 171 void *opaque; \
171 172 \
... ...
cpu-exec.c
... ... @@ -44,7 +44,6 @@
44 44 #endif
45 45  
46 46 int tb_invalidated_flag;
47   -static unsigned long next_tb;
48 47  
49 48 //#define DEBUG_EXEC
50 49 //#define DEBUG_SIGNAL
... ... @@ -93,8 +92,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
93 92 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
94 93 uint8_t *tc_ptr;
95 94  
96   - spin_lock(&tb_lock);
97   -
98 95 tb_invalidated_flag = 0;
99 96  
100 97 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
... ... @@ -155,7 +152,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
155 152 found:
156 153 /* we add the TB in the virtual pc hash table */
157 154 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
158   - spin_unlock(&tb_lock);
159 155 return tb;
160 156 }
161 157  
... ... @@ -228,14 +224,6 @@ static inline TranslationBlock *tb_find_fast(void)
228 224 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
229 225 tb->flags != flags, 0)) {
230 226 tb = tb_find_slow(pc, cs_base, flags);
231   - /* Note: we do it here to avoid a gcc bug on Mac OS X when
232   - doing it in tb_find_slow */
233   - if (tb_invalidated_flag) {
234   - /* as some TB could have been invalidated because
235   - of memory exceptions while generating the code, we
236   - must recompute the hash index here */
237   - next_tb = 0;
238   - }
239 227 }
240 228 return tb;
241 229 }
... ... @@ -249,6 +237,7 @@ int cpu_exec(CPUState *env1)
249 237 int ret, interrupt_request;
250 238 TranslationBlock *tb;
251 239 uint8_t *tc_ptr;
  240 + unsigned long next_tb;
252 241  
253 242 if (cpu_halted(env1) == EXCP_HALTED)
254 243 return EXCP_HALTED;
... ... @@ -577,7 +566,16 @@ int cpu_exec(CPUState *env1)
577 566 #endif
578 567 }
579 568 #endif
  569 + spin_lock(&tb_lock);
580 570 tb = tb_find_fast();
  571 + /* Note: we do it here to avoid a gcc bug on Mac OS X when
  572 + doing it in tb_find_slow */
  573 + if (tb_invalidated_flag) {
  574 + /* as some TB could have been invalidated because
  575 + of memory exceptions while generating the code, we
  576 + must recompute the hash index here */
  577 + next_tb = 0;
  578 + }
581 579 #ifdef DEBUG_EXEC
582 580 if ((loglevel & CPU_LOG_EXEC)) {
583 581 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
... ... @@ -594,11 +592,10 @@ int cpu_exec(CPUState *env1)
594 592 (env->kqemu_enabled != 2) &&
595 593 #endif
596 594 tb->page_addr[1] == -1) {
597   - spin_lock(&tb_lock);
598 595 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
599   - spin_unlock(&tb_lock);
600 596 }
601 597 }
  598 + spin_unlock(&tb_lock);
602 599 tc_ptr = tb->tc_ptr;
603 600 env->current_tb = tb;
604 601 /* execute the generated code */
... ...
exec-all.h
... ... @@ -302,217 +302,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
302 302 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
303 303 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
304 304  
305   -#if defined(__hppa__)
306   -
307   -typedef int spinlock_t[4];
308   -
309   -#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
310   -
311   -static inline void resetlock (spinlock_t *p)
312   -{
313   - (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
314   -}
315   -
316   -#else
317   -
318   -typedef int spinlock_t;
319   -
320   -#define SPIN_LOCK_UNLOCKED 0
321   -
322   -static inline void resetlock (spinlock_t *p)
323   -{
324   - *p = SPIN_LOCK_UNLOCKED;
325   -}
326   -
327   -#endif
328   -
329   -#if defined(__powerpc__)
330   -static inline int testandset (int *p)
331   -{
332   - int ret;
333   - __asm__ __volatile__ (
334   - "0: lwarx %0,0,%1\n"
335   - " xor. %0,%3,%0\n"
336   - " bne 1f\n"
337   - " stwcx. %2,0,%1\n"
338   - " bne- 0b\n"
339   - "1: "
340   - : "=&r" (ret)
341   - : "r" (p), "r" (1), "r" (0)
342   - : "cr0", "memory");
343   - return ret;
344   -}
345   -#elif defined(__i386__)
346   -static inline int testandset (int *p)
347   -{
348   - long int readval = 0;
349   -
350   - __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
351   - : "+m" (*p), "+a" (readval)
352   - : "r" (1)
353   - : "cc");
354   - return readval;
355   -}
356   -#elif defined(__x86_64__)
357   -static inline int testandset (int *p)
358   -{
359   - long int readval = 0;
360   -
361   - __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
362   - : "+m" (*p), "+a" (readval)
363   - : "r" (1)
364   - : "cc");
365   - return readval;
366   -}
367   -#elif defined(__s390__)
368   -static inline int testandset (int *p)
369   -{
370   - int ret;
371   -
372   - __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
373   - " jl 0b"
374   - : "=&d" (ret)
375   - : "r" (1), "a" (p), "0" (*p)
376   - : "cc", "memory" );
377   - return ret;
378   -}
379   -#elif defined(__alpha__)
380   -static inline int testandset (int *p)
381   -{
382   - int ret;
383   - unsigned long one;
384   -
385   - __asm__ __volatile__ ("0: mov 1,%2\n"
386   - " ldl_l %0,%1\n"
387   - " stl_c %2,%1\n"
388   - " beq %2,1f\n"
389   - ".subsection 2\n"
390   - "1: br 0b\n"
391   - ".previous"
392   - : "=r" (ret), "=m" (*p), "=r" (one)
393   - : "m" (*p));
394   - return ret;
395   -}
396   -#elif defined(__sparc__)
397   -static inline int testandset (int *p)
398   -{
399   - int ret;
400   -
401   - __asm__ __volatile__("ldstub [%1], %0"
402   - : "=r" (ret)
403   - : "r" (p)
404   - : "memory");
405   -
406   - return (ret ? 1 : 0);
407   -}
408   -#elif defined(__arm__)
409   -static inline int testandset (int *spinlock)
410   -{
411   - register unsigned int ret;
412   - __asm__ __volatile__("swp %0, %1, [%2]"
413   - : "=r"(ret)
414   - : "0"(1), "r"(spinlock));
415   -
416   - return ret;
417   -}
418   -#elif defined(__mc68000)
419   -static inline int testandset (int *p)
420   -{
421   - char ret;
422   - __asm__ __volatile__("tas %1; sne %0"
423   - : "=r" (ret)
424   - : "m" (p)
425   - : "cc","memory");
426   - return ret;
427   -}
428   -#elif defined(__hppa__)
429   -
430   -/* Because malloc only guarantees 8-byte alignment for malloc'd data,
431   - and GCC only guarantees 8-byte alignment for stack locals, we can't
432   - be assured of 16-byte alignment for atomic lock data even if we
433   - specify "__attribute ((aligned(16)))" in the type declaration. So,
434   - we use a struct containing an array of four ints for the atomic lock
435   - type and dynamically select the 16-byte aligned int from the array
436   - for the semaphore. */
437   -#define __PA_LDCW_ALIGNMENT 16
438   -static inline void *ldcw_align (void *p) {
439   - unsigned long a = (unsigned long)p;
440   - a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
441   - return (void *)a;
442   -}
443   -
444   -static inline int testandset (spinlock_t *p)
445   -{
446   - unsigned int ret;
447   - p = ldcw_align(p);
448   - __asm__ __volatile__("ldcw 0(%1),%0"
449   - : "=r" (ret)
450   - : "r" (p)
451   - : "memory" );
452   - return !ret;
453   -}
454   -
455   -#elif defined(__ia64)
456   -
457   -#include <ia64intrin.h>
458   -
459   -static inline int testandset (int *p)
460   -{
461   - return __sync_lock_test_and_set (p, 1);
462   -}
463   -#elif defined(__mips__)
464   -static inline int testandset (int *p)
465   -{
466   - int ret;
467   -
468   - __asm__ __volatile__ (
469   - " .set push \n"
470   - " .set noat \n"
471   - " .set mips2 \n"
472   - "1: li $1, 1 \n"
473   - " ll %0, %1 \n"
474   - " sc $1, %1 \n"
475   - " beqz $1, 1b \n"
476   - " .set pop "
477   - : "=r" (ret), "+R" (*p)
478   - :
479   - : "memory");
480   -
481   - return ret;
482   -}
483   -#else
484   -#error unimplemented CPU support
485   -#endif
486   -
487   -#if defined(CONFIG_USER_ONLY)
488   -static inline void spin_lock(spinlock_t *lock)
489   -{
490   - while (testandset(lock));
491   -}
492   -
493   -static inline void spin_unlock(spinlock_t *lock)
494   -{
495   - resetlock(lock);
496   -}
497   -
498   -static inline int spin_trylock(spinlock_t *lock)
499   -{
500   - return !testandset(lock);
501   -}
502   -#else
503   -static inline void spin_lock(spinlock_t *lock)
504   -{
505   -}
506   -
507   -static inline void spin_unlock(spinlock_t *lock)
508   -{
509   -}
510   -
511   -static inline int spin_trylock(spinlock_t *lock)
512   -{
513   - return 1;
514   -}
515   -#endif
  305 +#include "qemu-lock.h"
516 306  
517 307 extern spinlock_t tb_lock;
518 308  
... ...
... ... @@ -1341,10 +1341,20 @@ void cpu_set_log_filename(const char *filename)
1341 1341 /* mask must never be zero, except for A20 change call */
1342 1342 void cpu_interrupt(CPUState *env, int mask)
1343 1343 {
  1344 +#if !defined(USE_NPTL)
1344 1345 TranslationBlock *tb;
1345 1346 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
  1347 +#endif
1346 1348  
  1349 + /* FIXME: This is probably not threadsafe. A different thread could
  1350 + be in the mittle of a read-modify-write operation. */
1347 1351 env->interrupt_request |= mask;
  1352 +#if defined(USE_NPTL)
  1353 + /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
  1354 + problem and hope the cpu will stop of its own accord. For userspace
  1355 + emulation this often isn't actually as bad as it sounds. Often
  1356 + signals are used primarily to interrupt blocking syscalls. */
  1357 +#else
1348 1358 /* if the cpu is currently executing code, we must unlink it and
1349 1359 all the potentially executing TB */
1350 1360 tb = env->current_tb;
... ... @@ -1353,6 +1363,7 @@ void cpu_interrupt(CPUState *env, int mask)
1353 1363 tb_reset_jump_recursive(tb);
1354 1364 resetlock(&interrupt_lock);
1355 1365 }
  1366 +#endif
1356 1367 }
1357 1368  
1358 1369 void cpu_reset_interrupt(CPUState *env, int mask)
... ... @@ -2015,7 +2026,6 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
2015 2026 end = TARGET_PAGE_ALIGN(end);
2016 2027 if (flags & PAGE_WRITE)
2017 2028 flags |= PAGE_WRITE_ORG;
2018   - spin_lock(&tb_lock);
2019 2029 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2020 2030 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
2021 2031 /* 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)
2027 2037 }
2028 2038 p->flags = flags;
2029 2039 }
2030   - spin_unlock(&tb_lock);
2031 2040 }
2032 2041  
2033 2042 int page_check_range(target_ulong start, target_ulong len, int flags)
... ...
linux-user/elfload.c
... ... @@ -89,7 +89,7 @@ enum {
89 89 static const char *get_elf_platform(void)
90 90 {
91 91 static char elf_platform[] = "i386";
92   - int family = (global_env->cpuid_version >> 8) & 0xff;
  92 + int family = (thread_env->cpuid_version >> 8) & 0xff;
93 93 if (family > 6)
94 94 family = 6;
95 95 if (family >= 3)
... ... @@ -101,7 +101,7 @@ static const char *get_elf_platform(void)
101 101  
102 102 static uint32_t get_elf_hwcap(void)
103 103 {
104   - return global_env->cpuid_features;
  104 + return thread_env->cpuid_features;
105 105 }
106 106  
107 107 #ifdef TARGET_X86_64
... ...
linux-user/main.c
... ... @@ -26,6 +26,8 @@
26 26  
27 27 #include "qemu.h"
28 28 #include "qemu-common.h"
  29 +/* For tb_lock */
  30 +#include "exec-all.h"
29 31  
30 32 #define DEBUG_LOGFILE "/tmp/qemu.log"
31 33  
... ... @@ -123,6 +125,135 @@ int64_t cpu_get_real_ticks(void)
123 125  
124 126 #endif
125 127  
  128 +#if defined(USE_NPTL)
  129 +/***********************************************************/
  130 +/* Helper routines for implementing atomic operations. */
  131 +
  132 +/* To implement exclusive operations we force all cpus to syncronise.
  133 + We don't require a full sync, only that no cpus are executing guest code.
  134 + The alternative is to map target atomic ops onto host equivalents,
  135 + which requires quite a lot of per host/target work. */
  136 +static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
  137 +static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
  138 +static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
  139 +static int pending_cpus;
  140 +
  141 +/* Make sure everything is in a consistent state for calling fork(). */
  142 +void fork_start(void)
  143 +{
  144 + mmap_fork_start();
  145 + pthread_mutex_lock(&tb_lock);
  146 + pthread_mutex_lock(&exclusive_lock);
  147 +}
  148 +
  149 +void fork_end(int child)
  150 +{
  151 + if (child) {
  152 + /* Child processes created by fork() only have a single thread.
  153 + Discard information about the parent threads. */
  154 + first_cpu = thread_env;
  155 + thread_env->next_cpu = NULL;
  156 + pending_cpus = 0;
  157 + pthread_mutex_init(&exclusive_lock, NULL);
  158 + pthread_cond_init(&exclusive_cond, NULL);
  159 + pthread_cond_init(&exclusive_resume, NULL);
  160 + pthread_mutex_init(&tb_lock, NULL);
  161 + } else {
  162 + pthread_mutex_unlock(&exclusive_lock);
  163 + pthread_mutex_unlock(&tb_lock);
  164 + }
  165 + mmap_fork_end(child);
  166 +}
  167 +
  168 +/* Wait for pending exclusive operations to complete. The exclusive lock
  169 + must be held. */
  170 +static inline void exclusive_idle(void)
  171 +{
  172 + while (pending_cpus) {
  173 + pthread_cond_wait(&exclusive_resume, &exclusive_lock);
  174 + }
  175 +}
  176 +
  177 +/* Start an exclusive operation.
  178 + Must only be called from outside cpu_arm_exec. */
  179 +static inline void start_exclusive(void)
  180 +{
  181 + CPUState *other;
  182 + pthread_mutex_lock(&exclusive_lock);
  183 + exclusive_idle();
  184 +
  185 + pending_cpus = 1;
  186 + /* Make all other cpus stop executing. */
  187 + for (other = first_cpu; other; other = other->next_cpu) {
  188 + if (other->running) {
  189 + pending_cpus++;
  190 + cpu_interrupt(other, CPU_INTERRUPT_EXIT);
  191 + }
  192 + }
  193 + if (pending_cpus > 1) {
  194 + pthread_cond_wait(&exclusive_cond, &exclusive_lock);
  195 + }
  196 +}
  197 +
  198 +/* Finish an exclusive operation. */
  199 +static inline void end_exclusive(void)
  200 +{
  201 + pending_cpus = 0;
  202 + pthread_cond_broadcast(&exclusive_resume);
  203 + pthread_mutex_unlock(&exclusive_lock);
  204 +}
  205 +
  206 +/* Wait for exclusive ops to finish, and begin cpu execution. */
  207 +static inline void cpu_exec_start(CPUState *env)
  208 +{
  209 + pthread_mutex_lock(&exclusive_lock);
  210 + exclusive_idle();
  211 + env->running = 1;
  212 + pthread_mutex_unlock(&exclusive_lock);
  213 +}
  214 +
  215 +/* Mark cpu as not executing, and release pending exclusive ops. */
  216 +static inline void cpu_exec_end(CPUState *env)
  217 +{
  218 + pthread_mutex_lock(&exclusive_lock);
  219 + env->running = 0;
  220 + if (pending_cpus > 1) {
  221 + pending_cpus--;
  222 + if (pending_cpus == 1) {
  223 + pthread_cond_signal(&exclusive_cond);
  224 + }
  225 + }
  226 + exclusive_idle();
  227 + pthread_mutex_unlock(&exclusive_lock);
  228 +}
  229 +#else /* if !USE_NPTL */
  230 +/* These are no-ops because we are not threadsafe. */
  231 +static inline void cpu_exec_start(CPUState *env)
  232 +{
  233 +}
  234 +
  235 +static inline void cpu_exec_end(CPUState *env)
  236 +{
  237 +}
  238 +
  239 +static inline void start_exclusive(void)
  240 +{
  241 +}
  242 +
  243 +static inline void end_exclusive(void)
  244 +{
  245 +}
  246 +
  247 +void fork_start(void)
  248 +{
  249 +}
  250 +
  251 +void fork_end(int child)
  252 +{
  253 +}
  254 +#endif
  255 +
  256 +
126 257 #ifdef TARGET_I386
127 258 /***********************************************************/
128 259 /* CPUX86 core interface */
... ... @@ -378,8 +509,11 @@ do_kernel_trap(CPUARMState *env)
378 509 /* ??? No-op. Will need to do better for SMP. */
379 510 break;
380 511 case 0xffff0fc0: /* __kernel_cmpxchg */
381   - /* ??? This is not really atomic. However we don't support
382   - threads anyway, so it doesn't realy matter. */
  512 + /* XXX: This only works between threads, not between processes.
  513 + It's probably possible to implement this with native host
  514 + operations. However things like ldrex/strex are much harder so
  515 + there's not much point trying. */
  516 + start_exclusive();
383 517 cpsr = cpsr_read(env);
384 518 addr = env->regs[2];
385 519 /* FIXME: This should SEGV if the access fails. */
... ... @@ -396,6 +530,7 @@ do_kernel_trap(CPUARMState *env)
396 530 cpsr &= ~CPSR_C;
397 531 }
398 532 cpsr_write(env, cpsr, CPSR_C);
  533 + end_exclusive();
399 534 break;
400 535 case 0xffff0fe0: /* __kernel_get_tls */
401 536 env->regs[0] = env->cp15.c13_tls2;
... ... @@ -422,7 +557,9 @@ void cpu_loop(CPUARMState *env)
422 557 uint32_t addr;
423 558  
424 559 for(;;) {
  560 + cpu_exec_start(env);
425 561 trapnr = cpu_arm_exec(env);
  562 + cpu_exec_end(env);
426 563 switch(trapnr) {
427 564 case EXCP_UDEF:
428 565 {
... ... @@ -2044,8 +2181,7 @@ void usage(void)
2044 2181 _exit(1);
2045 2182 }
2046 2183  
2047   -/* XXX: currently only used for async signals (see signal.c) */
2048   -CPUState *global_env;
  2184 +THREAD CPUState *thread_env;
2049 2185  
2050 2186 void init_task_state(TaskState *ts)
2051 2187 {
... ... @@ -2203,7 +2339,7 @@ int main(int argc, char **argv)
2203 2339 fprintf(stderr, "Unable to find CPU definition\n");
2204 2340 exit(1);
2205 2341 }
2206   - global_env = env;
  2342 + thread_env = env;
2207 2343  
2208 2344 if (getenv("QEMU_STRACE")) {
2209 2345 do_strace = 1;
... ...
linux-user/mmap.c
... ... @@ -46,6 +46,22 @@ void mmap_unlock(void)
46 46 pthread_mutex_unlock(&mmap_mutex);
47 47 }
48 48 }
  49 +
  50 +/* Grab lock to make sure things are in a consistent state after fork(). */
  51 +void mmap_fork_start(void)
  52 +{
  53 + if (mmap_lock_count)
  54 + abort();
  55 + pthread_mutex_lock(&mmap_mutex);
  56 +}
  57 +
  58 +void mmap_fork_end(int child)
  59 +{
  60 + if (child)
  61 + pthread_mutex_init(&mmap_mutex, NULL);
  62 + else
  63 + pthread_mutex_unlock(&mmap_mutex);
  64 +}
49 65 #else
50 66 /* We aren't threadsafe to start with, so no need to worry about locking. */
51 67 void mmap_lock(void)
... ...
linux-user/qemu.h
... ... @@ -37,6 +37,12 @@ typedef target_long abi_long;
37 37 #include "target_signal.h"
38 38 #include "gdbstub.h"
39 39  
  40 +#if defined(USE_NPTL)
  41 +#define THREAD __thread
  42 +#else
  43 +#define THREAD
  44 +#endif
  45 +
40 46 /* This struct is used to hold certain information about the image.
41 47 * Basically, it replicates in user space what would be certain
42 48 * task_struct fields in the kernel
... ... @@ -184,12 +190,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
184 190 abi_long arg2, abi_long arg3, abi_long arg4,
185 191 abi_long arg5, abi_long arg6);
186 192 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
187   -extern CPUState *global_env;
  193 +extern THREAD CPUState *thread_env;
188 194 void cpu_loop(CPUState *env);
189 195 void init_paths(const char *prefix);
190 196 const char *path(const char *pathname);
191 197 char *target_strerror(int err);
192 198 int get_osversion(void);
  199 +void fork_start(void);
  200 +void fork_end(int child);
193 201  
194 202 extern int loglevel;
195 203 extern FILE *logfile;
... ... @@ -235,6 +243,10 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
235 243 extern unsigned long last_brk;
236 244 void mmap_lock(void);
237 245 void mmap_unlock(void);
  246 +#if defined(USE_NPTL)
  247 +void mmap_fork_start(void);
  248 +void mmap_fork_end(int child);
  249 +#endif
238 250  
239 251 /* user access */
240 252  
... ...
linux-user/signal.c
... ... @@ -424,9 +424,9 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
424 424 fprintf(stderr, "qemu: got signal %d\n", sig);
425 425 #endif
426 426 host_to_target_siginfo_noswap(&tinfo, info);
427   - if (queue_signal(global_env, sig, &tinfo) == 1) {
  427 + if (queue_signal(thread_env, sig, &tinfo) == 1) {
428 428 /* interrupt the virtual CPU as soon as possible */
429   - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
  429 + cpu_interrupt(thread_env, CPU_INTERRUPT_EXIT);
430 430 }
431 431 }
432 432  
... ...
qemu-lock.h 0 โ†’ 100644
  1 +/*
  2 + * Copyright (c) 2003 Fabrice Bellard
  3 + *
  4 + * This library is free software; you can redistribute it and/or
  5 + * modify it under the terms of the GNU Lesser General Public
  6 + * License as published by the Free Software Foundation; either
  7 + * version 2 of the License, or (at your option) any later version.
  8 + *
  9 + * This library is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12 + * Lesser General Public License for more details.
  13 + *
  14 + * You should have received a copy of the GNU Lesser General Public
  15 + * License along with this library; if not, write to the Free Software
  16 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17 + */
  18 +
  19 +/* Locking primitives. Most of this code should be redundant -
  20 + system emulation doesn't need/use locking, NPTL userspace uses
  21 + pthread mutexes, and non-NPTL userspace isn't threadsafe anyway.
  22 + In either case a spinlock is probably the wrong kind of lock.
  23 + Spinlocks are only good if you know annother CPU has the lock and is
  24 + likely to release it soon. In environments where you have more threads
  25 + than physical CPUs (the extreme case being a single CPU host) a spinlock
  26 + simply wastes CPU until the OS decides to preempt it. */
  27 +#if defined(USE_NPTL)
  28 +
  29 +#include <pthread.h>
  30 +#define spin_lock pthread_mutex_lock
  31 +#define spin_unlock pthread_mutex_unlock
  32 +#define spinlock_t pthread_mutex_t
  33 +#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
  34 +
  35 +#else
  36 +
  37 +#if defined(__hppa__)
  38 +
  39 +typedef int spinlock_t[4];
  40 +
  41 +#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
  42 +
  43 +static inline void resetlock (spinlock_t *p)
  44 +{
  45 + (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
  46 +}
  47 +
  48 +#else
  49 +
  50 +typedef int spinlock_t;
  51 +
  52 +#define SPIN_LOCK_UNLOCKED 0
  53 +
  54 +static inline void resetlock (spinlock_t *p)
  55 +{
  56 + *p = SPIN_LOCK_UNLOCKED;
  57 +}
  58 +
  59 +#endif
  60 +
  61 +#if defined(__powerpc__)
  62 +static inline int testandset (int *p)
  63 +{
  64 + int ret;
  65 + __asm__ __volatile__ (
  66 + "0: lwarx %0,0,%1\n"
  67 + " xor. %0,%3,%0\n"
  68 + " bne 1f\n"
  69 + " stwcx. %2,0,%1\n"
  70 + " bne- 0b\n"
  71 + "1: "
  72 + : "=&r" (ret)
  73 + : "r" (p), "r" (1), "r" (0)
  74 + : "cr0", "memory");
  75 + return ret;
  76 +}
  77 +#elif defined(__i386__)
  78 +static inline int testandset (int *p)
  79 +{
  80 + long int readval = 0;
  81 +
  82 + __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
  83 + : "+m" (*p), "+a" (readval)
  84 + : "r" (1)
  85 + : "cc");
  86 + return readval;
  87 +}
  88 +#elif defined(__x86_64__)
  89 +static inline int testandset (int *p)
  90 +{
  91 + long int readval = 0;
  92 +
  93 + __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
  94 + : "+m" (*p), "+a" (readval)
  95 + : "r" (1)
  96 + : "cc");
  97 + return readval;
  98 +}
  99 +#elif defined(__s390__)
  100 +static inline int testandset (int *p)
  101 +{
  102 + int ret;
  103 +
  104 + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
  105 + " jl 0b"
  106 + : "=&d" (ret)
  107 + : "r" (1), "a" (p), "0" (*p)
  108 + : "cc", "memory" );
  109 + return ret;
  110 +}
  111 +#elif defined(__alpha__)
  112 +static inline int testandset (int *p)
  113 +{
  114 + int ret;
  115 + unsigned long one;
  116 +
  117 + __asm__ __volatile__ ("0: mov 1,%2\n"
  118 + " ldl_l %0,%1\n"
  119 + " stl_c %2,%1\n"
  120 + " beq %2,1f\n"
  121 + ".subsection 2\n"
  122 + "1: br 0b\n"
  123 + ".previous"
  124 + : "=r" (ret), "=m" (*p), "=r" (one)
  125 + : "m" (*p));
  126 + return ret;
  127 +}
  128 +#elif defined(__sparc__)
  129 +static inline int testandset (int *p)
  130 +{
  131 + int ret;
  132 +
  133 + __asm__ __volatile__("ldstub [%1], %0"
  134 + : "=r" (ret)
  135 + : "r" (p)
  136 + : "memory");
  137 +
  138 + return (ret ? 1 : 0);
  139 +}
  140 +#elif defined(__arm__)
  141 +static inline int testandset (int *spinlock)
  142 +{
  143 + register unsigned int ret;
  144 + __asm__ __volatile__("swp %0, %1, [%2]"
  145 + : "=r"(ret)
  146 + : "0"(1), "r"(spinlock));
  147 +
  148 + return ret;
  149 +}
  150 +#elif defined(__mc68000)
  151 +static inline int testandset (int *p)
  152 +{
  153 + char ret;
  154 + __asm__ __volatile__("tas %1; sne %0"
  155 + : "=r" (ret)
  156 + : "m" (p)
  157 + : "cc","memory");
  158 + return ret;
  159 +}
  160 +#elif defined(__hppa__)
  161 +
  162 +/* Because malloc only guarantees 8-byte alignment for malloc'd data,
  163 + and GCC only guarantees 8-byte alignment for stack locals, we can't
  164 + be assured of 16-byte alignment for atomic lock data even if we
  165 + specify "__attribute ((aligned(16)))" in the type declaration. So,
  166 + we use a struct containing an array of four ints for the atomic lock
  167 + type and dynamically select the 16-byte aligned int from the array
  168 + for the semaphore. */
  169 +#define __PA_LDCW_ALIGNMENT 16
  170 +static inline void *ldcw_align (void *p) {
  171 + unsigned long a = (unsigned long)p;
  172 + a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
  173 + return (void *)a;
  174 +}
  175 +
  176 +static inline int testandset (spinlock_t *p)
  177 +{
  178 + unsigned int ret;
  179 + p = ldcw_align(p);
  180 + __asm__ __volatile__("ldcw 0(%1),%0"
  181 + : "=r" (ret)
  182 + : "r" (p)
  183 + : "memory" );
  184 + return !ret;
  185 +}
  186 +
  187 +#elif defined(__ia64)
  188 +
  189 +#include <ia64intrin.h>
  190 +
  191 +static inline int testandset (int *p)
  192 +{
  193 + return __sync_lock_test_and_set (p, 1);
  194 +}
  195 +#elif defined(__mips__)
  196 +static inline int testandset (int *p)
  197 +{
  198 + int ret;
  199 +
  200 + __asm__ __volatile__ (
  201 + " .set push \n"
  202 + " .set noat \n"
  203 + " .set mips2 \n"
  204 + "1: li $1, 1 \n"
  205 + " ll %0, %1 \n"
  206 + " sc $1, %1 \n"
  207 + " beqz $1, 1b \n"
  208 + " .set pop "
  209 + : "=r" (ret), "+R" (*p)
  210 + :
  211 + : "memory");
  212 +
  213 + return ret;
  214 +}
  215 +#else
  216 +#error unimplemented CPU support
  217 +#endif
  218 +
  219 +#if defined(CONFIG_USER_ONLY)
  220 +static inline void spin_lock(spinlock_t *lock)
  221 +{
  222 + while (testandset(lock));
  223 +}
  224 +
  225 +static inline void spin_unlock(spinlock_t *lock)
  226 +{
  227 + resetlock(lock);
  228 +}
  229 +
  230 +static inline int spin_trylock(spinlock_t *lock)
  231 +{
  232 + return !testandset(lock);
  233 +}
  234 +#else
  235 +static inline void spin_lock(spinlock_t *lock)
  236 +{
  237 +}
  238 +
  239 +static inline void spin_unlock(spinlock_t *lock)
  240 +{
  241 +}
  242 +
  243 +static inline int spin_trylock(spinlock_t *lock)
  244 +{
  245 + return 1;
  246 +}
  247 +#endif
  248 +
  249 +#endif
... ...