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 | - 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
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; |