Commit 1b6b029e40c4297ce9c27e0f8b8ae177085c990a

Authored by bellard
1 parent 612384d7

basic clone() support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162
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 - signals 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 - make it self runnable (use same trick as ld.so : include its own relocator and libc) 7 - make it self runnable (use same trick as ld.so : include its own relocator and libc)
7 - improved 16 bit support 8 - improved 16 bit support
8 - fix FPU exceptions (in particular: gen_op_fpush not before mem load) 9 - fix FPU exceptions (in particular: gen_op_fpush not before mem load)
exec-i386.c
@@ -52,6 +52,52 @@ int nb_tbs; @@ -52,6 +52,52 @@ int nb_tbs;
52 uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; 52 uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
53 uint8_t *code_gen_ptr; 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 #ifdef DEBUG_EXEC 101 #ifdef DEBUG_EXEC
56 static const char *cc_op_str[] = { 102 static const char *cc_op_str[] = {
57 "DYNAMIC", 103 "DYNAMIC",
@@ -266,11 +312,15 @@ int cpu_x86_exec(CPUX86State *env1) @@ -266,11 +312,15 @@ int cpu_x86_exec(CPUX86State *env1)
266 tc_ptr = tb->tc_ptr; 312 tc_ptr = tb->tc_ptr;
267 if (!tb->tc_ptr) { 313 if (!tb->tc_ptr) {
268 /* if no translated code available, then translate it now */ 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 tc_ptr = code_gen_ptr; 318 tc_ptr = code_gen_ptr;
270 cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 319 cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
271 &code_gen_size, pc, cs_base, flags); 320 &code_gen_size, pc, cs_base, flags);
272 tb->tc_ptr = tc_ptr; 321 tb->tc_ptr = tc_ptr;
273 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); 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 /* execute the generated code */ 325 /* execute the generated code */
276 gen_func = (void *)tc_ptr; 326 gen_func = (void *)tc_ptr;
exec-i386.h
@@ -139,3 +139,5 @@ typedef struct CCTable { @@ -139,3 +139,5 @@ typedef struct CCTable {
139 extern CCTable cc_table[]; 139 extern CCTable cc_table[];
140 140
141 void load_seg(int seg_reg, int selector); 141 void load_seg(int seg_reg, int selector);
  142 +void cpu_lock(void);
  143 +void cpu_unlock(void);
linux-user/main.c
@@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, @@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit,
104 104
105 uint64_t gdt_table[6]; 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 void usage(void) 141 void usage(void)
108 { 142 {
109 printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" 143 printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
@@ -113,8 +147,6 @@ void usage(void) @@ -113,8 +147,6 @@ void usage(void)
113 exit(1); 147 exit(1);
114 } 148 }
115 149
116 -  
117 -  
118 int main(int argc, char **argv) 150 int main(int argc, char **argv)
119 { 151 {
120 const char *filename; 152 const char *filename;
@@ -193,35 +225,7 @@ int main(int argc, char **argv) @@ -193,35 +225,7 @@ int main(int argc, char **argv)
193 cpu_x86_load_seg(env, R_FS, __USER_DS); 225 cpu_x86_load_seg(env, R_FS, __USER_DS);
194 cpu_x86_load_seg(env, R_GS, __USER_DS); 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 return 0; 230 return 0;
227 } 231 }
linux-user/qemu.h
@@ -51,7 +51,7 @@ void syscall_init(void); @@ -51,7 +51,7 @@ void syscall_init(void);
51 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 51 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
52 long arg4, long arg5, long arg6); 52 long arg4, long arg5, long arg6);
53 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); 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 #endif 57 #endif
linux-user/syscall.c
@@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou @@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou
762 } 762 }
763 return ret; 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 #endif 804 #endif
766 805
  806 +
767 void syscall_init(void) 807 void syscall_init(void)
768 { 808 {
769 #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); 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,6 +828,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
788 #ifdef HAVE_GPROF 828 #ifdef HAVE_GPROF
789 _mcleanup(); 829 _mcleanup();
790 #endif 830 #endif
  831 + /* XXX: should free thread stack and CPU env */
791 _exit(arg1); 832 _exit(arg1);
792 ret = 0; /* avoid warning */ 833 ret = 0; /* avoid warning */
793 break; 834 break;
@@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, @@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
807 ret = do_brk((char *)arg1); 848 ret = do_brk((char *)arg1);
808 break; 849 break;
809 case TARGET_NR_fork: 850 case TARGET_NR_fork:
810 - ret = get_errno(fork()); 851 + ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
811 break; 852 break;
812 case TARGET_NR_waitpid: 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,7 +1282,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1241 case TARGET_NR_sigreturn: 1282 case TARGET_NR_sigreturn:
1242 goto unimplemented; 1283 goto unimplemented;
1243 case TARGET_NR_clone: 1284 case TARGET_NR_clone:
1244 - goto unimplemented; 1285 + ret = get_errno(do_fork(cpu_env, arg1, arg2));
  1286 + break;
1245 case TARGET_NR_setdomainname: 1287 case TARGET_NR_setdomainname:
1246 ret = get_errno(setdomainname((const char *)arg1, arg2)); 1288 ret = get_errno(setdomainname((const char *)arg1, arg2));
1247 break; 1289 break;
@@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, @@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1310 case TARGET_NR_sysfs: 1352 case TARGET_NR_sysfs:
1311 goto unimplemented; 1353 goto unimplemented;
1312 case TARGET_NR_personality: 1354 case TARGET_NR_personality:
1313 - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); 1355 + ret = get_errno(personality(arg1));
1314 break; 1356 break;
1315 case TARGET_NR_afs_syscall: 1357 case TARGET_NR_afs_syscall:
1316 goto unimplemented; 1358 goto unimplemented;
@@ -1447,7 +1489,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, @@ -1447,7 +1489,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1447 case TARGET_NR_sched_get_priority_max: 1489 case TARGET_NR_sched_get_priority_max:
1448 case TARGET_NR_sched_get_priority_min: 1490 case TARGET_NR_sched_get_priority_min:
1449 case TARGET_NR_sched_rr_get_interval: 1491 case TARGET_NR_sched_rr_get_interval:
  1492 + goto unimplemented;
  1493 +
1450 case TARGET_NR_nanosleep: 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 case TARGET_NR_mremap: 1509 case TARGET_NR_mremap:
1452 case TARGET_NR_setresuid: 1510 case TARGET_NR_setresuid:
1453 case TARGET_NR_getresuid: 1511 case TARGET_NR_getresuid:
@@ -1481,7 +1539,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, @@ -1481,7 +1539,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1481 case TARGET_NR_getpmsg: 1539 case TARGET_NR_getpmsg:
1482 case TARGET_NR_putpmsg: 1540 case TARGET_NR_putpmsg:
1483 case TARGET_NR_vfork: 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 break; 1543 break;
1486 case TARGET_NR_ugetrlimit: 1544 case TARGET_NR_ugetrlimit:
1487 case TARGET_NR_truncate64: 1545 case TARGET_NR_truncate64:
linux-user/syscall_defs.h
@@ -24,6 +24,11 @@ struct target_timeval { @@ -24,6 +24,11 @@ struct target_timeval {
24 target_long tv_usec; 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 struct target_iovec { 32 struct target_iovec {
28 target_long iov_base; /* Starting address */ 33 target_long iov_base; /* Starting address */
29 target_long iov_len; /* Number of bytes */ 34 target_long iov_len; /* Number of bytes */
op-i386.c
@@ -2272,3 +2272,14 @@ void OPPROTO op_fninit(void) @@ -2272,3 +2272,14 @@ void OPPROTO op_fninit(void)
2272 env->fptags[6] = 1; 2272 env->fptags[6] = 1;
2273 env->fptags[7] = 1; 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
@@ -530,3 +530,5 @@ DEF(fnstcw_A0) @@ -530,3 +530,5 @@ DEF(fnstcw_A0)
530 DEF(fldcw_A0) 530 DEF(fldcw_A0)
531 DEF(fclex) 531 DEF(fclex)
532 DEF(fninit) 532 DEF(fninit)
  533 +DEF(lock)
  534 +DEF(unlock)
tests/Makefile
@@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g @@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g
4 LDFLAGS= 4 LDFLAGS=
5 5
6 ifeq ($(ARCH),i386) 6 ifeq ($(ARCH),i386)
7 -TESTS=test2 sha1-i386 test-i386 7 +TESTS=testclone testsig testthread sha1-i386 test-i386
8 endif 8 endif
9 TESTS+=sha1 9 TESTS+=sha1
10 10
@@ -16,9 +16,15 @@ hello: hello.c @@ -16,9 +16,15 @@ hello: hello.c
16 $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< 16 $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
17 strip hello 17 strip hello
18 18
19 -test2: test2.c 19 +testclone: testclone.c
20 $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< 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 # i386 emulation test (test various opcodes) */ 28 # i386 emulation test (test various opcodes) */
23 test-i386: test-i386.c test-i386-code16.S \ 29 test-i386: test-i386.c test-i386-code16.S \
24 test-i386.h test-i386-shift.h test-i386-muldiv.h 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,6 +1395,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
1395 s->aflag = aflag; 1395 s->aflag = aflag;
1396 s->dflag = dflag; 1396 s->dflag = dflag;
1397 1397
  1398 + /* lock generation */
  1399 + if (prefixes & PREFIX_LOCK)
  1400 + gen_op_lock();
  1401 +
1398 /* now check op code */ 1402 /* now check op code */
1399 reswitch: 1403 reswitch:
1400 switch(b) { 1404 switch(b) {
@@ -3153,8 +3157,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) @@ -3153,8 +3157,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3153 default: 3157 default:
3154 goto illegal_op; 3158 goto illegal_op;
3155 } 3159 }
  3160 + /* lock generation */
  3161 + if (s->prefix & PREFIX_LOCK)
  3162 + gen_op_unlock();
3156 return (long)s->pc; 3163 return (long)s->pc;
3157 illegal_op: 3164 illegal_op:
  3165 + /* XXX: ensure that no lock was generated */
3158 return -1; 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,6 +3617,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3609 pc += count; 3617 pc += count;
3610 } 3618 }
3611 fprintf(logfile, "\n"); 3619 fprintf(logfile, "\n");
  3620 + fflush(logfile);
3612 } 3621 }
3613 #endif 3622 #endif
3614 return 0; 3623 return 0;