Commit 1b6b029e40c4297ce9c27e0f8b8ae177085c990a
1 parent
612384d7
basic clone() support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
14 changed files
with
327 additions
and
44 deletions
TODO
| 1 | -- overrides/16bit for string ops | |
| 2 | -- optimize translated cache chaining (DLL PLT-like system) | |
| 3 | -- 64 bit syscalls | |
| 1 | +- verify thread support (clone() and various locks) | |
| 4 | 2 | - signals |
| 5 | -- threads | |
| 3 | +- optimize translated cache chaining (DLL PLT-like system) | |
| 4 | +- vm86 syscall support | |
| 5 | +- overrides/16bit for string ops | |
| 6 | +- more syscalls (in particular all 64 bit ones) | |
| 6 | 7 | - make it self runnable (use same trick as ld.so : include its own relocator and libc) |
| 7 | 8 | - improved 16 bit support |
| 8 | 9 | - fix FPU exceptions (in particular: gen_op_fpush not before mem load) | ... | ... |
exec-i386.c
| ... | ... | @@ -52,6 +52,52 @@ int nb_tbs; |
| 52 | 52 | uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; |
| 53 | 53 | uint8_t *code_gen_ptr; |
| 54 | 54 | |
| 55 | +/* thread support */ | |
| 56 | + | |
| 57 | +#ifdef __powerpc__ | |
| 58 | +static inline int testandset (int *p) | |
| 59 | +{ | |
| 60 | + int ret; | |
| 61 | + __asm__ __volatile__ ( | |
| 62 | + "0: lwarx %0,0,%1 ;" | |
| 63 | + " xor. %0,%3,%0;" | |
| 64 | + " bne 1f;" | |
| 65 | + " stwcx. %2,0,%1;" | |
| 66 | + " bne- 0b;" | |
| 67 | + "1: " | |
| 68 | + : "=&r" (ret) | |
| 69 | + : "r" (p), "r" (1), "r" (0) | |
| 70 | + : "cr0", "memory"); | |
| 71 | + return ret; | |
| 72 | +} | |
| 73 | +#endif | |
| 74 | + | |
| 75 | +#ifdef __i386__ | |
| 76 | +static inline int testandset (int *p) | |
| 77 | +{ | |
| 78 | + char ret; | |
| 79 | + long int readval; | |
| 80 | + | |
| 81 | + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" | |
| 82 | + : "=q" (ret), "=m" (*p), "=a" (readval) | |
| 83 | + : "r" (1), "m" (*p), "a" (0) | |
| 84 | + : "memory"); | |
| 85 | + return ret; | |
| 86 | +} | |
| 87 | +#endif | |
| 88 | + | |
| 89 | +int global_cpu_lock = 0; | |
| 90 | + | |
| 91 | +void cpu_lock(void) | |
| 92 | +{ | |
| 93 | + while (testandset(&global_cpu_lock)); | |
| 94 | +} | |
| 95 | + | |
| 96 | +void cpu_unlock(void) | |
| 97 | +{ | |
| 98 | + global_cpu_lock = 0; | |
| 99 | +} | |
| 100 | + | |
| 55 | 101 | #ifdef DEBUG_EXEC |
| 56 | 102 | static const char *cc_op_str[] = { |
| 57 | 103 | "DYNAMIC", |
| ... | ... | @@ -266,11 +312,15 @@ int cpu_x86_exec(CPUX86State *env1) |
| 266 | 312 | tc_ptr = tb->tc_ptr; |
| 267 | 313 | if (!tb->tc_ptr) { |
| 268 | 314 | /* if no translated code available, then translate it now */ |
| 315 | + /* XXX: very inefficient: we lock all the cpus when | |
| 316 | + generating code */ | |
| 317 | + cpu_lock(); | |
| 269 | 318 | tc_ptr = code_gen_ptr; |
| 270 | 319 | cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
| 271 | 320 | &code_gen_size, pc, cs_base, flags); |
| 272 | 321 | tb->tc_ptr = tc_ptr; |
| 273 | 322 | code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
| 323 | + cpu_unlock(); | |
| 274 | 324 | } |
| 275 | 325 | /* execute the generated code */ |
| 276 | 326 | gen_func = (void *)tc_ptr; | ... | ... |
exec-i386.h
linux-user/main.c
| ... | ... | @@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, |
| 104 | 104 | |
| 105 | 105 | uint64_t gdt_table[6]; |
| 106 | 106 | |
| 107 | +void cpu_loop(struct CPUX86State *env) | |
| 108 | +{ | |
| 109 | + for(;;) { | |
| 110 | + int err; | |
| 111 | + uint8_t *pc; | |
| 112 | + | |
| 113 | + err = cpu_x86_exec(env); | |
| 114 | + pc = env->seg_cache[R_CS].base + env->eip; | |
| 115 | + switch(err) { | |
| 116 | + case EXCP0D_GPF: | |
| 117 | + if (pc[0] == 0xcd && pc[1] == 0x80) { | |
| 118 | + /* syscall */ | |
| 119 | + env->eip += 2; | |
| 120 | + env->regs[R_EAX] = do_syscall(env, | |
| 121 | + env->regs[R_EAX], | |
| 122 | + env->regs[R_EBX], | |
| 123 | + env->regs[R_ECX], | |
| 124 | + env->regs[R_EDX], | |
| 125 | + env->regs[R_ESI], | |
| 126 | + env->regs[R_EDI], | |
| 127 | + env->regs[R_EBP]); | |
| 128 | + } else { | |
| 129 | + goto trap_error; | |
| 130 | + } | |
| 131 | + break; | |
| 132 | + default: | |
| 133 | + trap_error: | |
| 134 | + fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", | |
| 135 | + (long)pc, err); | |
| 136 | + abort(); | |
| 137 | + } | |
| 138 | + } | |
| 139 | +} | |
| 140 | + | |
| 107 | 141 | void usage(void) |
| 108 | 142 | { |
| 109 | 143 | printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" |
| ... | ... | @@ -113,8 +147,6 @@ void usage(void) |
| 113 | 147 | exit(1); |
| 114 | 148 | } |
| 115 | 149 | |
| 116 | - | |
| 117 | - | |
| 118 | 150 | int main(int argc, char **argv) |
| 119 | 151 | { |
| 120 | 152 | const char *filename; |
| ... | ... | @@ -193,35 +225,7 @@ int main(int argc, char **argv) |
| 193 | 225 | cpu_x86_load_seg(env, R_FS, __USER_DS); |
| 194 | 226 | cpu_x86_load_seg(env, R_GS, __USER_DS); |
| 195 | 227 | |
| 196 | - for(;;) { | |
| 197 | - int err; | |
| 198 | - uint8_t *pc; | |
| 199 | - | |
| 200 | - err = cpu_x86_exec(env); | |
| 201 | - pc = env->seg_cache[R_CS].base + env->eip; | |
| 202 | - switch(err) { | |
| 203 | - case EXCP0D_GPF: | |
| 204 | - if (pc[0] == 0xcd && pc[1] == 0x80) { | |
| 205 | - /* syscall */ | |
| 206 | - env->eip += 2; | |
| 207 | - env->regs[R_EAX] = do_syscall(env, | |
| 208 | - env->regs[R_EAX], | |
| 209 | - env->regs[R_EBX], | |
| 210 | - env->regs[R_ECX], | |
| 211 | - env->regs[R_EDX], | |
| 212 | - env->regs[R_ESI], | |
| 213 | - env->regs[R_EDI], | |
| 214 | - env->regs[R_EBP]); | |
| 215 | - } else { | |
| 216 | - goto trap_error; | |
| 217 | - } | |
| 218 | - break; | |
| 219 | - default: | |
| 220 | - trap_error: | |
| 221 | - fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", | |
| 222 | - (long)pc, err); | |
| 223 | - abort(); | |
| 224 | - } | |
| 225 | - } | |
| 228 | + cpu_loop(env); | |
| 229 | + /* never exits */ | |
| 226 | 230 | return 0; |
| 227 | 231 | } | ... | ... |
linux-user/qemu.h
| ... | ... | @@ -51,7 +51,7 @@ void syscall_init(void); |
| 51 | 51 | long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 52 | 52 | long arg4, long arg5, long arg6); |
| 53 | 53 | void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); |
| 54 | - | |
| 55 | - | |
| 54 | +struct CPUX86State; | |
| 55 | +void cpu_loop(struct CPUX86State *env); | |
| 56 | 56 | |
| 57 | 57 | #endif | ... | ... |
linux-user/syscall.c
| ... | ... | @@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou |
| 762 | 762 | } |
| 763 | 763 | return ret; |
| 764 | 764 | } |
| 765 | + | |
| 766 | +/* this stack is the equivalent of the kernel stack associated with a | |
| 767 | + thread/process */ | |
| 768 | +#define NEW_STACK_SIZE 8192 | |
| 769 | + | |
| 770 | +static int clone_func(void *arg) | |
| 771 | +{ | |
| 772 | + CPUX86State *env = arg; | |
| 773 | + cpu_loop(env); | |
| 774 | + /* never exits */ | |
| 775 | + return 0; | |
| 776 | +} | |
| 777 | + | |
| 778 | +int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) | |
| 779 | +{ | |
| 780 | + int ret; | |
| 781 | + uint8_t *new_stack; | |
| 782 | + CPUX86State *new_env; | |
| 783 | + | |
| 784 | + if (flags & CLONE_VM) { | |
| 785 | + if (!newsp) | |
| 786 | + newsp = env->regs[R_ESP]; | |
| 787 | + new_stack = malloc(NEW_STACK_SIZE); | |
| 788 | + | |
| 789 | + /* we create a new CPU instance. */ | |
| 790 | + new_env = cpu_x86_init(); | |
| 791 | + memcpy(new_env, env, sizeof(CPUX86State)); | |
| 792 | + new_env->regs[R_ESP] = newsp; | |
| 793 | + new_env->regs[R_EAX] = 0; | |
| 794 | + ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); | |
| 795 | + } else { | |
| 796 | + /* if no CLONE_VM, we consider it is a fork */ | |
| 797 | + if ((flags & ~CSIGNAL) != 0) | |
| 798 | + return -EINVAL; | |
| 799 | + ret = fork(); | |
| 800 | + } | |
| 801 | + return ret; | |
| 802 | +} | |
| 803 | + | |
| 765 | 804 | #endif |
| 766 | 805 | |
| 806 | + | |
| 767 | 807 | void syscall_init(void) |
| 768 | 808 | { |
| 769 | 809 | #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); |
| ... | ... | @@ -788,6 +828,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 788 | 828 | #ifdef HAVE_GPROF |
| 789 | 829 | _mcleanup(); |
| 790 | 830 | #endif |
| 831 | + /* XXX: should free thread stack and CPU env */ | |
| 791 | 832 | _exit(arg1); |
| 792 | 833 | ret = 0; /* avoid warning */ |
| 793 | 834 | break; |
| ... | ... | @@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 807 | 848 | ret = do_brk((char *)arg1); |
| 808 | 849 | break; |
| 809 | 850 | case TARGET_NR_fork: |
| 810 | - ret = get_errno(fork()); | |
| 851 | + ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); | |
| 811 | 852 | break; |
| 812 | 853 | case TARGET_NR_waitpid: |
| 813 | 854 | { |
| ... | ... | @@ -1241,7 +1282,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1241 | 1282 | case TARGET_NR_sigreturn: |
| 1242 | 1283 | goto unimplemented; |
| 1243 | 1284 | case TARGET_NR_clone: |
| 1244 | - goto unimplemented; | |
| 1285 | + ret = get_errno(do_fork(cpu_env, arg1, arg2)); | |
| 1286 | + break; | |
| 1245 | 1287 | case TARGET_NR_setdomainname: |
| 1246 | 1288 | ret = get_errno(setdomainname((const char *)arg1, arg2)); |
| 1247 | 1289 | break; |
| ... | ... | @@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1310 | 1352 | case TARGET_NR_sysfs: |
| 1311 | 1353 | goto unimplemented; |
| 1312 | 1354 | case TARGET_NR_personality: |
| 1313 | - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); | |
| 1355 | + ret = get_errno(personality(arg1)); | |
| 1314 | 1356 | break; |
| 1315 | 1357 | case TARGET_NR_afs_syscall: |
| 1316 | 1358 | goto unimplemented; |
| ... | ... | @@ -1447,7 +1489,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1447 | 1489 | case TARGET_NR_sched_get_priority_max: |
| 1448 | 1490 | case TARGET_NR_sched_get_priority_min: |
| 1449 | 1491 | case TARGET_NR_sched_rr_get_interval: |
| 1492 | + goto unimplemented; | |
| 1493 | + | |
| 1450 | 1494 | case TARGET_NR_nanosleep: |
| 1495 | + { | |
| 1496 | + struct target_timespec *target_req = (void *)arg1; | |
| 1497 | + struct target_timespec *target_rem = (void *)arg2; | |
| 1498 | + struct timespec req, rem; | |
| 1499 | + req.tv_sec = tswapl(target_req->tv_sec); | |
| 1500 | + req.tv_nsec = tswapl(target_req->tv_nsec); | |
| 1501 | + ret = get_errno(nanosleep(&req, &rem)); | |
| 1502 | + if (target_rem) { | |
| 1503 | + target_rem->tv_sec = tswapl(rem.tv_sec); | |
| 1504 | + target_rem->tv_nsec = tswapl(rem.tv_nsec); | |
| 1505 | + } | |
| 1506 | + } | |
| 1507 | + break; | |
| 1508 | + | |
| 1451 | 1509 | case TARGET_NR_mremap: |
| 1452 | 1510 | case TARGET_NR_setresuid: |
| 1453 | 1511 | case TARGET_NR_getresuid: |
| ... | ... | @@ -1481,7 +1539,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1481 | 1539 | case TARGET_NR_getpmsg: |
| 1482 | 1540 | case TARGET_NR_putpmsg: |
| 1483 | 1541 | case TARGET_NR_vfork: |
| 1484 | - ret = get_errno(vfork()); | |
| 1542 | + ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); | |
| 1485 | 1543 | break; |
| 1486 | 1544 | case TARGET_NR_ugetrlimit: |
| 1487 | 1545 | case TARGET_NR_truncate64: | ... | ... |
linux-user/syscall_defs.h
| ... | ... | @@ -24,6 +24,11 @@ struct target_timeval { |
| 24 | 24 | target_long tv_usec; |
| 25 | 25 | }; |
| 26 | 26 | |
| 27 | +struct target_timespec { | |
| 28 | + target_long tv_sec; | |
| 29 | + target_long tv_nsec; | |
| 30 | +}; | |
| 31 | + | |
| 27 | 32 | struct target_iovec { |
| 28 | 33 | target_long iov_base; /* Starting address */ |
| 29 | 34 | target_long iov_len; /* Number of bytes */ | ... | ... |
op-i386.c
| ... | ... | @@ -2272,3 +2272,14 @@ void OPPROTO op_fninit(void) |
| 2272 | 2272 | env->fptags[6] = 1; |
| 2273 | 2273 | env->fptags[7] = 1; |
| 2274 | 2274 | } |
| 2275 | + | |
| 2276 | +/* threading support */ | |
| 2277 | +void OPPROTO op_lock(void) | |
| 2278 | +{ | |
| 2279 | + cpu_lock(); | |
| 2280 | +} | |
| 2281 | + | |
| 2282 | +void OPPROTO op_unlock(void) | |
| 2283 | +{ | |
| 2284 | + cpu_unlock(); | |
| 2285 | +} | ... | ... |
opc-i386.h
tests/Makefile
| ... | ... | @@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g |
| 4 | 4 | LDFLAGS= |
| 5 | 5 | |
| 6 | 6 | ifeq ($(ARCH),i386) |
| 7 | -TESTS=test2 sha1-i386 test-i386 | |
| 7 | +TESTS=testclone testsig testthread sha1-i386 test-i386 | |
| 8 | 8 | endif |
| 9 | 9 | TESTS+=sha1 |
| 10 | 10 | |
| ... | ... | @@ -16,9 +16,15 @@ hello: hello.c |
| 16 | 16 | $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< |
| 17 | 17 | strip hello |
| 18 | 18 | |
| 19 | -test2: test2.c | |
| 19 | +testclone: testclone.c | |
| 20 | 20 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< |
| 21 | 21 | |
| 22 | +testsig: testsig.c | |
| 23 | + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< | |
| 24 | + | |
| 25 | +testthread: testthread.c | |
| 26 | + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread | |
| 27 | + | |
| 22 | 28 | # i386 emulation test (test various opcodes) */ |
| 23 | 29 | test-i386: test-i386.c test-i386-code16.S \ |
| 24 | 30 | test-i386.h test-i386-shift.h test-i386-muldiv.h | ... | ... |
tests/testclone.c
0 → 100644
| 1 | +#include <stdlib.h> | |
| 2 | +#include <stdio.h> | |
| 3 | +#include <signal.h> | |
| 4 | +#include <unistd.h> | |
| 5 | +#include <inttypes.h> | |
| 6 | +#include <pthread.h> | |
| 7 | +#include <sys/wait.h> | |
| 8 | +#include <sched.h> | |
| 9 | + | |
| 10 | +int thread1_func(void *arg) | |
| 11 | +{ | |
| 12 | + int i; | |
| 13 | + char buf[512]; | |
| 14 | + | |
| 15 | + for(i=0;i<10;i++) { | |
| 16 | + snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); | |
| 17 | + write(1, buf, strlen(buf)); | |
| 18 | + usleep(100 * 1000); | |
| 19 | + } | |
| 20 | + return 0; | |
| 21 | +} | |
| 22 | + | |
| 23 | +int thread2_func(void *arg) | |
| 24 | +{ | |
| 25 | + int i; | |
| 26 | + char buf[512]; | |
| 27 | + for(i=0;i<20;i++) { | |
| 28 | + snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); | |
| 29 | + write(1, buf, strlen(buf)); | |
| 30 | + usleep(120 * 1000); | |
| 31 | + } | |
| 32 | + return 0; | |
| 33 | +} | |
| 34 | + | |
| 35 | +#define STACK_SIZE 16384 | |
| 36 | + | |
| 37 | +void test_clone(void) | |
| 38 | +{ | |
| 39 | + uint8_t *stack1, *stack2; | |
| 40 | + int pid1, pid2, status1, status2; | |
| 41 | + | |
| 42 | + stack1 = malloc(STACK_SIZE); | |
| 43 | + pid1 = clone(thread1_func, stack1 + STACK_SIZE, | |
| 44 | + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"); | |
| 45 | + | |
| 46 | + stack2 = malloc(STACK_SIZE); | |
| 47 | + pid2 = clone(thread2_func, stack2 + STACK_SIZE, | |
| 48 | + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"); | |
| 49 | + | |
| 50 | + while (waitpid(pid1, &status1, 0) != pid1); | |
| 51 | + while (waitpid(pid2, &status2, 0) != pid2); | |
| 52 | + printf("status1=0x%x\n", status1); | |
| 53 | + printf("status2=0x%x\n", status2); | |
| 54 | + printf("End of clone test.\n"); | |
| 55 | +} | |
| 56 | + | |
| 57 | +int main(int argc, char **argv) | |
| 58 | +{ | |
| 59 | + test_clone(); | |
| 60 | + return 0; | |
| 61 | +} | ... | ... |
tests/testsig.c
0 → 100644
| 1 | +#include <stdlib.h> | |
| 2 | +#include <stdio.h> | |
| 3 | +#include <signal.h> | |
| 4 | +#include <unistd.h> | |
| 5 | + | |
| 6 | +void alarm_handler(int sig) | |
| 7 | +{ | |
| 8 | + printf("alarm signal=%d\n", sig); | |
| 9 | + alarm(1); | |
| 10 | +} | |
| 11 | + | |
| 12 | +int main(int argc, char **argv) | |
| 13 | +{ | |
| 14 | + struct sigaction act; | |
| 15 | + act.sa_handler = alarm_handler; | |
| 16 | + sigemptyset(&act.sa_mask); | |
| 17 | + act.sa_flags = 0; | |
| 18 | + sigaction(SIGALRM, &act, NULL); | |
| 19 | + alarm(1); | |
| 20 | + for(;;) { | |
| 21 | + sleep(1); | |
| 22 | + } | |
| 23 | + return 0; | |
| 24 | +} | ... | ... |
tests/testthread.c
0 → 100644
| 1 | +#include <stdlib.h> | |
| 2 | +#include <stdio.h> | |
| 3 | +#include <signal.h> | |
| 4 | +#include <unistd.h> | |
| 5 | +#include <inttypes.h> | |
| 6 | +#include <pthread.h> | |
| 7 | +#include <sys/wait.h> | |
| 8 | +#include <sched.h> | |
| 9 | + | |
| 10 | +void *thread1_func(void *arg) | |
| 11 | +{ | |
| 12 | + int i; | |
| 13 | + char buf[512]; | |
| 14 | + | |
| 15 | + for(i=0;i<10;i++) { | |
| 16 | + snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); | |
| 17 | + write(1, buf, strlen(buf)); | |
| 18 | + usleep(100 * 1000); | |
| 19 | + } | |
| 20 | + return NULL; | |
| 21 | +} | |
| 22 | + | |
| 23 | +void *thread2_func(void *arg) | |
| 24 | +{ | |
| 25 | + int i; | |
| 26 | + char buf[512]; | |
| 27 | + for(i=0;i<20;i++) { | |
| 28 | + snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); | |
| 29 | + write(1, buf, strlen(buf)); | |
| 30 | + usleep(150 * 1000); | |
| 31 | + } | |
| 32 | + return NULL; | |
| 33 | +} | |
| 34 | + | |
| 35 | +void test_pthread(void) | |
| 36 | +{ | |
| 37 | + pthread_t tid1, tid2; | |
| 38 | + | |
| 39 | + pthread_create(&tid1, NULL, thread1_func, "hello1"); | |
| 40 | + pthread_create(&tid2, NULL, thread2_func, "hello2"); | |
| 41 | + pthread_join(tid1, NULL); | |
| 42 | + pthread_join(tid2, NULL); | |
| 43 | + printf("End of pthread test.\n"); | |
| 44 | +} | |
| 45 | + | |
| 46 | +int main(int argc, char **argv) | |
| 47 | +{ | |
| 48 | + test_pthread(); | |
| 49 | + return 0; | |
| 50 | +} | ... | ... |
translate-i386.c
| ... | ... | @@ -1395,6 +1395,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 1395 | 1395 | s->aflag = aflag; |
| 1396 | 1396 | s->dflag = dflag; |
| 1397 | 1397 | |
| 1398 | + /* lock generation */ | |
| 1399 | + if (prefixes & PREFIX_LOCK) | |
| 1400 | + gen_op_lock(); | |
| 1401 | + | |
| 1398 | 1402 | /* now check op code */ |
| 1399 | 1403 | reswitch: |
| 1400 | 1404 | switch(b) { |
| ... | ... | @@ -3153,8 +3157,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3153 | 3157 | default: |
| 3154 | 3158 | goto illegal_op; |
| 3155 | 3159 | } |
| 3160 | + /* lock generation */ | |
| 3161 | + if (s->prefix & PREFIX_LOCK) | |
| 3162 | + gen_op_unlock(); | |
| 3156 | 3163 | return (long)s->pc; |
| 3157 | 3164 | illegal_op: |
| 3165 | + /* XXX: ensure that no lock was generated */ | |
| 3158 | 3166 | return -1; |
| 3159 | 3167 | } |
| 3160 | 3168 | |
| ... | ... | @@ -3609,6 +3617,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
| 3609 | 3617 | pc += count; |
| 3610 | 3618 | } |
| 3611 | 3619 | fprintf(logfile, "\n"); |
| 3620 | + fflush(logfile); | |
| 3612 | 3621 | } |
| 3613 | 3622 | #endif |
| 3614 | 3623 | return 0; | ... | ... |