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,6 +166,7 @@ typedef struct CPUTLBEntry {
166 \ 166 \
167 void *next_cpu; /* next CPU sharing TB cache */ \ 167 void *next_cpu; /* next CPU sharing TB cache */ \
168 int cpu_index; /* CPU index (informative) */ \ 168 int cpu_index; /* CPU index (informative) */ \
  169 + int running; /* Nonzero if cpu is currently running(usermode). */ \
169 /* user data */ \ 170 /* user data */ \
170 void *opaque; \ 171 void *opaque; \
171 \ 172 \
cpu-exec.c
@@ -44,7 +44,6 @@ @@ -44,7 +44,6 @@
44 #endif 44 #endif
45 45
46 int tb_invalidated_flag; 46 int tb_invalidated_flag;
47 -static unsigned long next_tb;  
48 47
49 //#define DEBUG_EXEC 48 //#define DEBUG_EXEC
50 //#define DEBUG_SIGNAL 49 //#define DEBUG_SIGNAL
@@ -93,8 +92,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc, @@ -93,8 +92,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
93 target_ulong phys_pc, phys_page1, phys_page2, virt_page2; 92 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
94 uint8_t *tc_ptr; 93 uint8_t *tc_ptr;
95 94
96 - spin_lock(&tb_lock);  
97 -  
98 tb_invalidated_flag = 0; 95 tb_invalidated_flag = 0;
99 96
100 regs_to_env(); /* XXX: do it just before cpu_gen_code() */ 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,7 +152,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
155 found: 152 found:
156 /* we add the TB in the virtual pc hash table */ 153 /* we add the TB in the virtual pc hash table */
157 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; 154 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
158 - spin_unlock(&tb_lock);  
159 return tb; 155 return tb;
160 } 156 }
161 157
@@ -228,14 +224,6 @@ static inline TranslationBlock *tb_find_fast(void) @@ -228,14 +224,6 @@ static inline TranslationBlock *tb_find_fast(void)
228 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base || 224 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
229 tb->flags != flags, 0)) { 225 tb->flags != flags, 0)) {
230 tb = tb_find_slow(pc, cs_base, flags); 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 return tb; 228 return tb;
241 } 229 }
@@ -249,6 +237,7 @@ int cpu_exec(CPUState *env1) @@ -249,6 +237,7 @@ int cpu_exec(CPUState *env1)
249 int ret, interrupt_request; 237 int ret, interrupt_request;
250 TranslationBlock *tb; 238 TranslationBlock *tb;
251 uint8_t *tc_ptr; 239 uint8_t *tc_ptr;
  240 + unsigned long next_tb;
252 241
253 if (cpu_halted(env1) == EXCP_HALTED) 242 if (cpu_halted(env1) == EXCP_HALTED)
254 return EXCP_HALTED; 243 return EXCP_HALTED;
@@ -577,7 +566,16 @@ int cpu_exec(CPUState *env1) @@ -577,7 +566,16 @@ int cpu_exec(CPUState *env1)
577 #endif 566 #endif
578 } 567 }
579 #endif 568 #endif
  569 + spin_lock(&tb_lock);
580 tb = tb_find_fast(); 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 #ifdef DEBUG_EXEC 579 #ifdef DEBUG_EXEC
582 if ((loglevel & CPU_LOG_EXEC)) { 580 if ((loglevel & CPU_LOG_EXEC)) {
583 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", 581 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
@@ -594,11 +592,10 @@ int cpu_exec(CPUState *env1) @@ -594,11 +592,10 @@ int cpu_exec(CPUState *env1)
594 (env->kqemu_enabled != 2) && 592 (env->kqemu_enabled != 2) &&
595 #endif 593 #endif
596 tb->page_addr[1] == -1) { 594 tb->page_addr[1] == -1) {
597 - spin_lock(&tb_lock);  
598 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); 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 tc_ptr = tb->tc_ptr; 599 tc_ptr = tb->tc_ptr;
603 env->current_tb = tb; 600 env->current_tb = tb;
604 /* execute the generated code */ 601 /* execute the generated code */
exec-all.h
@@ -302,217 +302,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; @@ -302,217 +302,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
302 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; 302 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
303 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; 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 extern spinlock_t tb_lock; 307 extern spinlock_t tb_lock;
518 308
@@ -1341,10 +1341,20 @@ void cpu_set_log_filename(const char *filename) @@ -1341,10 +1341,20 @@ void cpu_set_log_filename(const char *filename)
1341 /* mask must never be zero, except for A20 change call */ 1341 /* mask must never be zero, except for A20 change call */
1342 void cpu_interrupt(CPUState *env, int mask) 1342 void cpu_interrupt(CPUState *env, int mask)
1343 { 1343 {
  1344 +#if !defined(USE_NPTL)
1344 TranslationBlock *tb; 1345 TranslationBlock *tb;
1345 static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; 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 env->interrupt_request |= mask; 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 /* if the cpu is currently executing code, we must unlink it and 1358 /* if the cpu is currently executing code, we must unlink it and
1349 all the potentially executing TB */ 1359 all the potentially executing TB */
1350 tb = env->current_tb; 1360 tb = env->current_tb;
@@ -1353,6 +1363,7 @@ void cpu_interrupt(CPUState *env, int mask) @@ -1353,6 +1363,7 @@ void cpu_interrupt(CPUState *env, int mask)
1353 tb_reset_jump_recursive(tb); 1363 tb_reset_jump_recursive(tb);
1354 resetlock(&interrupt_lock); 1364 resetlock(&interrupt_lock);
1355 } 1365 }
  1366 +#endif
1356 } 1367 }
1357 1368
1358 void cpu_reset_interrupt(CPUState *env, int mask) 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,7 +2026,6 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
2015 end = TARGET_PAGE_ALIGN(end); 2026 end = TARGET_PAGE_ALIGN(end);
2016 if (flags & PAGE_WRITE) 2027 if (flags & PAGE_WRITE)
2017 flags |= PAGE_WRITE_ORG; 2028 flags |= PAGE_WRITE_ORG;
2018 - spin_lock(&tb_lock);  
2019 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { 2029 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
2020 p = page_find_alloc(addr >> TARGET_PAGE_BITS); 2030 p = page_find_alloc(addr >> TARGET_PAGE_BITS);
2021 /* if the write protection is set, then we invalidate the code 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,7 +2037,6 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
2027 } 2037 }
2028 p->flags = flags; 2038 p->flags = flags;
2029 } 2039 }
2030 - spin_unlock(&tb_lock);  
2031 } 2040 }
2032 2041
2033 int page_check_range(target_ulong start, target_ulong len, int flags) 2042 int page_check_range(target_ulong start, target_ulong len, int flags)
linux-user/elfload.c
@@ -89,7 +89,7 @@ enum { @@ -89,7 +89,7 @@ enum {
89 static const char *get_elf_platform(void) 89 static const char *get_elf_platform(void)
90 { 90 {
91 static char elf_platform[] = "i386"; 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 if (family > 6) 93 if (family > 6)
94 family = 6; 94 family = 6;
95 if (family >= 3) 95 if (family >= 3)
@@ -101,7 +101,7 @@ static const char *get_elf_platform(void) @@ -101,7 +101,7 @@ static const char *get_elf_platform(void)
101 101
102 static uint32_t get_elf_hwcap(void) 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 #ifdef TARGET_X86_64 107 #ifdef TARGET_X86_64
linux-user/main.c
@@ -26,6 +26,8 @@ @@ -26,6 +26,8 @@
26 26
27 #include "qemu.h" 27 #include "qemu.h"
28 #include "qemu-common.h" 28 #include "qemu-common.h"
  29 +/* For tb_lock */
  30 +#include "exec-all.h"
29 31
30 #define DEBUG_LOGFILE "/tmp/qemu.log" 32 #define DEBUG_LOGFILE "/tmp/qemu.log"
31 33
@@ -123,6 +125,135 @@ int64_t cpu_get_real_ticks(void) @@ -123,6 +125,135 @@ int64_t cpu_get_real_ticks(void)
123 125
124 #endif 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 #ifdef TARGET_I386 257 #ifdef TARGET_I386
127 /***********************************************************/ 258 /***********************************************************/
128 /* CPUX86 core interface */ 259 /* CPUX86 core interface */
@@ -378,8 +509,11 @@ do_kernel_trap(CPUARMState *env) @@ -378,8 +509,11 @@ do_kernel_trap(CPUARMState *env)
378 /* ??? No-op. Will need to do better for SMP. */ 509 /* ??? No-op. Will need to do better for SMP. */
379 break; 510 break;
380 case 0xffff0fc0: /* __kernel_cmpxchg */ 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 cpsr = cpsr_read(env); 517 cpsr = cpsr_read(env);
384 addr = env->regs[2]; 518 addr = env->regs[2];
385 /* FIXME: This should SEGV if the access fails. */ 519 /* FIXME: This should SEGV if the access fails. */
@@ -396,6 +530,7 @@ do_kernel_trap(CPUARMState *env) @@ -396,6 +530,7 @@ do_kernel_trap(CPUARMState *env)
396 cpsr &= ~CPSR_C; 530 cpsr &= ~CPSR_C;
397 } 531 }
398 cpsr_write(env, cpsr, CPSR_C); 532 cpsr_write(env, cpsr, CPSR_C);
  533 + end_exclusive();
399 break; 534 break;
400 case 0xffff0fe0: /* __kernel_get_tls */ 535 case 0xffff0fe0: /* __kernel_get_tls */
401 env->regs[0] = env->cp15.c13_tls2; 536 env->regs[0] = env->cp15.c13_tls2;
@@ -422,7 +557,9 @@ void cpu_loop(CPUARMState *env) @@ -422,7 +557,9 @@ void cpu_loop(CPUARMState *env)
422 uint32_t addr; 557 uint32_t addr;
423 558
424 for(;;) { 559 for(;;) {
  560 + cpu_exec_start(env);
425 trapnr = cpu_arm_exec(env); 561 trapnr = cpu_arm_exec(env);
  562 + cpu_exec_end(env);
426 switch(trapnr) { 563 switch(trapnr) {
427 case EXCP_UDEF: 564 case EXCP_UDEF:
428 { 565 {
@@ -2044,8 +2181,7 @@ void usage(void) @@ -2044,8 +2181,7 @@ void usage(void)
2044 _exit(1); 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 void init_task_state(TaskState *ts) 2186 void init_task_state(TaskState *ts)
2051 { 2187 {
@@ -2203,7 +2339,7 @@ int main(int argc, char **argv) @@ -2203,7 +2339,7 @@ int main(int argc, char **argv)
2203 fprintf(stderr, "Unable to find CPU definition\n"); 2339 fprintf(stderr, "Unable to find CPU definition\n");
2204 exit(1); 2340 exit(1);
2205 } 2341 }
2206 - global_env = env; 2342 + thread_env = env;
2207 2343
2208 if (getenv("QEMU_STRACE")) { 2344 if (getenv("QEMU_STRACE")) {
2209 do_strace = 1; 2345 do_strace = 1;
linux-user/mmap.c
@@ -46,6 +46,22 @@ void mmap_unlock(void) @@ -46,6 +46,22 @@ void mmap_unlock(void)
46 pthread_mutex_unlock(&mmap_mutex); 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 #else 65 #else
50 /* We aren't threadsafe to start with, so no need to worry about locking. */ 66 /* We aren't threadsafe to start with, so no need to worry about locking. */
51 void mmap_lock(void) 67 void mmap_lock(void)
linux-user/qemu.h
@@ -37,6 +37,12 @@ typedef target_long abi_long; @@ -37,6 +37,12 @@ typedef target_long abi_long;
37 #include "target_signal.h" 37 #include "target_signal.h"
38 #include "gdbstub.h" 38 #include "gdbstub.h"
39 39
  40 +#if defined(USE_NPTL)
  41 +#define THREAD __thread
  42 +#else
  43 +#define THREAD
  44 +#endif
  45 +
40 /* This struct is used to hold certain information about the image. 46 /* This struct is used to hold certain information about the image.
41 * Basically, it replicates in user space what would be certain 47 * Basically, it replicates in user space what would be certain
42 * task_struct fields in the kernel 48 * task_struct fields in the kernel
@@ -184,12 +190,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, @@ -184,12 +190,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
184 abi_long arg2, abi_long arg3, abi_long arg4, 190 abi_long arg2, abi_long arg3, abi_long arg4,
185 abi_long arg5, abi_long arg6); 191 abi_long arg5, abi_long arg6);
186 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); 192 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
187 -extern CPUState *global_env; 193 +extern THREAD CPUState *thread_env;
188 void cpu_loop(CPUState *env); 194 void cpu_loop(CPUState *env);
189 void init_paths(const char *prefix); 195 void init_paths(const char *prefix);
190 const char *path(const char *pathname); 196 const char *path(const char *pathname);
191 char *target_strerror(int err); 197 char *target_strerror(int err);
192 int get_osversion(void); 198 int get_osversion(void);
  199 +void fork_start(void);
  200 +void fork_end(int child);
193 201
194 extern int loglevel; 202 extern int loglevel;
195 extern FILE *logfile; 203 extern FILE *logfile;
@@ -235,6 +243,10 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); @@ -235,6 +243,10 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
235 extern unsigned long last_brk; 243 extern unsigned long last_brk;
236 void mmap_lock(void); 244 void mmap_lock(void);
237 void mmap_unlock(void); 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 /* user access */ 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,9 +424,9 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
424 fprintf(stderr, "qemu: got signal %d\n", sig); 424 fprintf(stderr, "qemu: got signal %d\n", sig);
425 #endif 425 #endif
426 host_to_target_siginfo_noswap(&tinfo, info); 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 /* interrupt the virtual CPU as soon as possible */ 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