basic clone() support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									612384d771
								
							
						
					
					
						commit
						1b6b029e40
					
				
							
								
								
									
										9
									
								
								TODO
								
								
								
								
							
							
						
						
									
										9
									
								
								TODO
								
								
								
								
							| 
						 | 
				
			
			@ -1,8 +1,9 @@
 | 
			
		|||
- overrides/16bit for string ops
 | 
			
		||||
- optimize translated cache chaining (DLL PLT-like system)
 | 
			
		||||
- 64 bit syscalls
 | 
			
		||||
- verify thread support (clone() and various locks)
 | 
			
		||||
- signals
 | 
			
		||||
- threads
 | 
			
		||||
- optimize translated cache chaining (DLL PLT-like system)
 | 
			
		||||
- vm86 syscall support
 | 
			
		||||
- overrides/16bit for string ops
 | 
			
		||||
- more syscalls (in particular all 64 bit ones)
 | 
			
		||||
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
 | 
			
		||||
- improved 16 bit support 
 | 
			
		||||
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								exec-i386.c
								
								
								
								
							
							
						
						
									
										50
									
								
								exec-i386.c
								
								
								
								
							| 
						 | 
				
			
			@ -52,6 +52,52 @@ int nb_tbs;
 | 
			
		|||
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
 | 
			
		||||
uint8_t *code_gen_ptr;
 | 
			
		||||
 | 
			
		||||
/* thread support */
 | 
			
		||||
 | 
			
		||||
#ifdef __powerpc__
 | 
			
		||||
static inline int testandset (int *p)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    __asm__ __volatile__ (
 | 
			
		||||
                          "0:    lwarx %0,0,%1 ;"
 | 
			
		||||
                          "      xor. %0,%3,%0;"
 | 
			
		||||
                          "      bne 1f;"
 | 
			
		||||
                          "      stwcx. %2,0,%1;"
 | 
			
		||||
                          "      bne- 0b;"
 | 
			
		||||
                          "1:    "
 | 
			
		||||
                          : "=&r" (ret)
 | 
			
		||||
                          : "r" (p), "r" (1), "r" (0)
 | 
			
		||||
                          : "cr0", "memory");
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __i386__
 | 
			
		||||
static inline int testandset (int *p)
 | 
			
		||||
{
 | 
			
		||||
    char ret;
 | 
			
		||||
    long int readval;
 | 
			
		||||
    
 | 
			
		||||
    __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
 | 
			
		||||
                          : "=q" (ret), "=m" (*p), "=a" (readval)
 | 
			
		||||
                          : "r" (1), "m" (*p), "a" (0)
 | 
			
		||||
                          : "memory");
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int global_cpu_lock = 0;
 | 
			
		||||
 | 
			
		||||
void cpu_lock(void)
 | 
			
		||||
{
 | 
			
		||||
    while (testandset(&global_cpu_lock));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_unlock(void)
 | 
			
		||||
{
 | 
			
		||||
    global_cpu_lock = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_EXEC
 | 
			
		||||
static const char *cc_op_str[] = {
 | 
			
		||||
    "DYNAMIC",
 | 
			
		||||
| 
						 | 
				
			
			@ -266,11 +312,15 @@ int cpu_x86_exec(CPUX86State *env1)
 | 
			
		|||
            tc_ptr = tb->tc_ptr;
 | 
			
		||||
            if (!tb->tc_ptr) {
 | 
			
		||||
                /* if no translated code available, then translate it now */
 | 
			
		||||
                /* XXX: very inefficient: we lock all the cpus when
 | 
			
		||||
                   generating code */
 | 
			
		||||
                cpu_lock();
 | 
			
		||||
                tc_ptr = code_gen_ptr;
 | 
			
		||||
                cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
 | 
			
		||||
                                 &code_gen_size, pc, cs_base, flags);
 | 
			
		||||
                tb->tc_ptr = tc_ptr;
 | 
			
		||||
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 | 
			
		||||
                cpu_unlock();
 | 
			
		||||
            }
 | 
			
		||||
            /* execute the generated code */
 | 
			
		||||
            gen_func = (void *)tc_ptr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,3 +139,5 @@ typedef struct CCTable {
 | 
			
		|||
extern CCTable cc_table[];
 | 
			
		||||
 | 
			
		||||
void load_seg(int seg_reg, int selector);
 | 
			
		||||
void cpu_lock(void);
 | 
			
		||||
void cpu_unlock(void);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit,
 | 
			
		|||
 | 
			
		||||
uint64_t gdt_table[6];
 | 
			
		||||
 | 
			
		||||
void cpu_loop(struct CPUX86State *env)
 | 
			
		||||
{
 | 
			
		||||
    for(;;) {
 | 
			
		||||
        int err;
 | 
			
		||||
        uint8_t *pc;
 | 
			
		||||
        
 | 
			
		||||
        err = cpu_x86_exec(env);
 | 
			
		||||
        pc = env->seg_cache[R_CS].base + env->eip;
 | 
			
		||||
        switch(err) {
 | 
			
		||||
        case EXCP0D_GPF:
 | 
			
		||||
            if (pc[0] == 0xcd && pc[1] == 0x80) {
 | 
			
		||||
                /* syscall */
 | 
			
		||||
                env->eip += 2;
 | 
			
		||||
                env->regs[R_EAX] = do_syscall(env, 
 | 
			
		||||
                                              env->regs[R_EAX], 
 | 
			
		||||
                                              env->regs[R_EBX],
 | 
			
		||||
                                              env->regs[R_ECX],
 | 
			
		||||
                                              env->regs[R_EDX],
 | 
			
		||||
                                              env->regs[R_ESI],
 | 
			
		||||
                                              env->regs[R_EDI],
 | 
			
		||||
                                              env->regs[R_EBP]);
 | 
			
		||||
            } else {
 | 
			
		||||
                goto trap_error;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
        trap_error:
 | 
			
		||||
            fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", 
 | 
			
		||||
                    (long)pc, err);
 | 
			
		||||
            abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usage(void)
 | 
			
		||||
{
 | 
			
		||||
    printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -113,8 +147,6 @@ void usage(void)
 | 
			
		|||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    const char *filename;
 | 
			
		||||
| 
						 | 
				
			
			@ -193,35 +225,7 @@ int main(int argc, char **argv)
 | 
			
		|||
    cpu_x86_load_seg(env, R_FS, __USER_DS);
 | 
			
		||||
    cpu_x86_load_seg(env, R_GS, __USER_DS);
 | 
			
		||||
 | 
			
		||||
    for(;;) {
 | 
			
		||||
        int err;
 | 
			
		||||
        uint8_t *pc;
 | 
			
		||||
        
 | 
			
		||||
        err = cpu_x86_exec(env);
 | 
			
		||||
        pc = env->seg_cache[R_CS].base + env->eip;
 | 
			
		||||
        switch(err) {
 | 
			
		||||
        case EXCP0D_GPF:
 | 
			
		||||
            if (pc[0] == 0xcd && pc[1] == 0x80) {
 | 
			
		||||
                /* syscall */
 | 
			
		||||
                env->eip += 2;
 | 
			
		||||
                env->regs[R_EAX] = do_syscall(env, 
 | 
			
		||||
                                              env->regs[R_EAX], 
 | 
			
		||||
                                              env->regs[R_EBX],
 | 
			
		||||
                                              env->regs[R_ECX],
 | 
			
		||||
                                              env->regs[R_EDX],
 | 
			
		||||
                                              env->regs[R_ESI],
 | 
			
		||||
                                              env->regs[R_EDI],
 | 
			
		||||
                                              env->regs[R_EBP]);
 | 
			
		||||
            } else {
 | 
			
		||||
                goto trap_error;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
        trap_error:
 | 
			
		||||
            fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", 
 | 
			
		||||
                    (long)pc, err);
 | 
			
		||||
            abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    cpu_loop(env);
 | 
			
		||||
    /* never exits */
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ void syscall_init(void);
 | 
			
		|||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
 | 
			
		||||
                long arg4, long arg5, long arg6);
 | 
			
		||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct CPUX86State;
 | 
			
		||||
void cpu_loop(struct CPUX86State *env);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou
 | 
			
		|||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* this stack is the equivalent of the kernel stack associated with a
 | 
			
		||||
   thread/process */
 | 
			
		||||
#define NEW_STACK_SIZE 8192
 | 
			
		||||
 | 
			
		||||
static int clone_func(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    CPUX86State *env = arg;
 | 
			
		||||
    cpu_loop(env);
 | 
			
		||||
    /* never exits */
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    uint8_t *new_stack;
 | 
			
		||||
    CPUX86State *new_env;
 | 
			
		||||
    
 | 
			
		||||
    if (flags & CLONE_VM) {
 | 
			
		||||
        if (!newsp)
 | 
			
		||||
            newsp = env->regs[R_ESP];
 | 
			
		||||
        new_stack = malloc(NEW_STACK_SIZE);
 | 
			
		||||
        
 | 
			
		||||
        /* we create a new CPU instance. */
 | 
			
		||||
        new_env = cpu_x86_init();
 | 
			
		||||
        memcpy(new_env, env, sizeof(CPUX86State));
 | 
			
		||||
        new_env->regs[R_ESP] = newsp;
 | 
			
		||||
        new_env->regs[R_EAX] = 0;
 | 
			
		||||
        ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
 | 
			
		||||
    } else {
 | 
			
		||||
        /* if no CLONE_VM, we consider it is a fork */
 | 
			
		||||
        if ((flags & ~CSIGNAL) != 0)
 | 
			
		||||
            return -EINVAL;
 | 
			
		||||
        ret = fork();
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void syscall_init(void)
 | 
			
		||||
{
 | 
			
		||||
#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,
 | 
			
		|||
#ifdef HAVE_GPROF
 | 
			
		||||
        _mcleanup();
 | 
			
		||||
#endif
 | 
			
		||||
        /* XXX: should free thread stack and CPU env */
 | 
			
		||||
        _exit(arg1);
 | 
			
		||||
        ret = 0; /* avoid warning */
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
			
		|||
        ret = do_brk((char *)arg1);
 | 
			
		||||
        break;
 | 
			
		||||
    case TARGET_NR_fork:
 | 
			
		||||
        ret = get_errno(fork());
 | 
			
		||||
        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
 | 
			
		||||
        break;
 | 
			
		||||
    case TARGET_NR_waitpid:
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -1241,7 +1282,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
			
		|||
    case TARGET_NR_sigreturn:
 | 
			
		||||
        goto unimplemented;
 | 
			
		||||
    case TARGET_NR_clone:
 | 
			
		||||
        goto unimplemented;
 | 
			
		||||
        ret = get_errno(do_fork(cpu_env, arg1, arg2));
 | 
			
		||||
        break;
 | 
			
		||||
    case TARGET_NR_setdomainname:
 | 
			
		||||
        ret = get_errno(setdomainname((const char *)arg1, arg2));
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
			
		|||
    case TARGET_NR_sysfs:
 | 
			
		||||
        goto unimplemented;
 | 
			
		||||
    case TARGET_NR_personality:
 | 
			
		||||
        ret = get_errno(mprotect((void *)arg1, arg2, arg3));
 | 
			
		||||
        ret = get_errno(personality(arg1));
 | 
			
		||||
        break;
 | 
			
		||||
    case TARGET_NR_afs_syscall:
 | 
			
		||||
        goto unimplemented;
 | 
			
		||||
| 
						 | 
				
			
			@ -1447,7 +1489,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
			
		|||
    case TARGET_NR_sched_get_priority_max:
 | 
			
		||||
    case TARGET_NR_sched_get_priority_min:
 | 
			
		||||
    case TARGET_NR_sched_rr_get_interval:
 | 
			
		||||
        goto unimplemented;
 | 
			
		||||
        
 | 
			
		||||
    case TARGET_NR_nanosleep:
 | 
			
		||||
        {
 | 
			
		||||
            struct target_timespec *target_req = (void *)arg1;
 | 
			
		||||
            struct target_timespec *target_rem = (void *)arg2;
 | 
			
		||||
            struct timespec req, rem;
 | 
			
		||||
            req.tv_sec = tswapl(target_req->tv_sec);
 | 
			
		||||
            req.tv_nsec = tswapl(target_req->tv_nsec);
 | 
			
		||||
            ret = get_errno(nanosleep(&req, &rem));
 | 
			
		||||
            if (target_rem) {
 | 
			
		||||
                target_rem->tv_sec = tswapl(rem.tv_sec);
 | 
			
		||||
                target_rem->tv_nsec = tswapl(rem.tv_nsec);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case TARGET_NR_mremap:
 | 
			
		||||
    case TARGET_NR_setresuid:
 | 
			
		||||
    case TARGET_NR_getresuid:
 | 
			
		||||
| 
						 | 
				
			
			@ -1481,7 +1539,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
			
		|||
    case TARGET_NR_getpmsg:
 | 
			
		||||
    case TARGET_NR_putpmsg:
 | 
			
		||||
    case TARGET_NR_vfork:
 | 
			
		||||
        ret = get_errno(vfork());
 | 
			
		||||
        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
 | 
			
		||||
        break;
 | 
			
		||||
    case TARGET_NR_ugetrlimit:
 | 
			
		||||
    case TARGET_NR_truncate64:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,11 @@ struct target_timeval {
 | 
			
		|||
    target_long tv_usec;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct target_timespec {
 | 
			
		||||
    target_long tv_sec;
 | 
			
		||||
    target_long tv_nsec;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct target_iovec {
 | 
			
		||||
    target_long iov_base;   /* Starting address */
 | 
			
		||||
    target_long iov_len;   /* Number of bytes */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								op-i386.c
								
								
								
								
							
							
						
						
									
										11
									
								
								op-i386.c
								
								
								
								
							| 
						 | 
				
			
			@ -2272,3 +2272,14 @@ void OPPROTO op_fninit(void)
 | 
			
		|||
    env->fptags[6] = 1;
 | 
			
		||||
    env->fptags[7] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* threading support */
 | 
			
		||||
void OPPROTO op_lock(void)
 | 
			
		||||
{
 | 
			
		||||
    cpu_lock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OPPROTO op_unlock(void)
 | 
			
		||||
{
 | 
			
		||||
    cpu_unlock();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -530,3 +530,5 @@ DEF(fnstcw_A0)
 | 
			
		|||
DEF(fldcw_A0)
 | 
			
		||||
DEF(fclex)
 | 
			
		||||
DEF(fninit)
 | 
			
		||||
DEF(lock)
 | 
			
		||||
DEF(unlock)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g
 | 
			
		|||
LDFLAGS=
 | 
			
		||||
 | 
			
		||||
ifeq ($(ARCH),i386)
 | 
			
		||||
TESTS=test2 sha1-i386 test-i386
 | 
			
		||||
TESTS=testclone testsig testthread sha1-i386 test-i386
 | 
			
		||||
endif
 | 
			
		||||
TESTS+=sha1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,9 +16,15 @@ hello: hello.c
 | 
			
		|||
	$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
 | 
			
		||||
	strip hello
 | 
			
		||||
 | 
			
		||||
test2: test2.c
 | 
			
		||||
testclone: testclone.c
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
 | 
			
		||||
 | 
			
		||||
testsig: testsig.c
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
 | 
			
		||||
 | 
			
		||||
testthread: testthread.c
 | 
			
		||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
 | 
			
		||||
 | 
			
		||||
# i386 emulation test (test various opcodes) */
 | 
			
		||||
test-i386: test-i386.c test-i386-code16.S \
 | 
			
		||||
           test-i386.h test-i386-shift.h test-i386-muldiv.h
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <sched.h>
 | 
			
		||||
 | 
			
		||||
int thread1_func(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    char buf[512];
 | 
			
		||||
 | 
			
		||||
    for(i=0;i<10;i++) {
 | 
			
		||||
        snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
 | 
			
		||||
        write(1, buf, strlen(buf));
 | 
			
		||||
        usleep(100 * 1000);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int thread2_func(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    char buf[512];
 | 
			
		||||
    for(i=0;i<20;i++) {
 | 
			
		||||
        snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
 | 
			
		||||
        write(1, buf, strlen(buf));
 | 
			
		||||
        usleep(120 * 1000);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define STACK_SIZE 16384
 | 
			
		||||
 | 
			
		||||
void test_clone(void)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *stack1, *stack2;
 | 
			
		||||
    int pid1, pid2, status1, status2;
 | 
			
		||||
 | 
			
		||||
    stack1 = malloc(STACK_SIZE);
 | 
			
		||||
    pid1 = clone(thread1_func, stack1 + STACK_SIZE, 
 | 
			
		||||
                 CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
 | 
			
		||||
 | 
			
		||||
    stack2 = malloc(STACK_SIZE);
 | 
			
		||||
    pid2 = clone(thread2_func, stack2 + STACK_SIZE, 
 | 
			
		||||
                 CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
 | 
			
		||||
 | 
			
		||||
    while (waitpid(pid1, &status1, 0) != pid1);
 | 
			
		||||
    while (waitpid(pid2, &status2, 0) != pid2);
 | 
			
		||||
    printf("status1=0x%x\n", status1);
 | 
			
		||||
    printf("status2=0x%x\n", status2);
 | 
			
		||||
    printf("End of clone test.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    test_clone();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
void alarm_handler(int sig)
 | 
			
		||||
{
 | 
			
		||||
    printf("alarm signal=%d\n", sig);
 | 
			
		||||
    alarm(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    struct sigaction act;
 | 
			
		||||
    act.sa_handler = alarm_handler;
 | 
			
		||||
    sigemptyset(&act.sa_mask);
 | 
			
		||||
    act.sa_flags = 0;
 | 
			
		||||
    sigaction(SIGALRM, &act, NULL);
 | 
			
		||||
    alarm(1);
 | 
			
		||||
    for(;;) {
 | 
			
		||||
        sleep(1);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <sched.h>
 | 
			
		||||
 | 
			
		||||
void *thread1_func(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    char buf[512];
 | 
			
		||||
 | 
			
		||||
    for(i=0;i<10;i++) {
 | 
			
		||||
        snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
 | 
			
		||||
        write(1, buf, strlen(buf));
 | 
			
		||||
        usleep(100 * 1000);
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *thread2_func(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    char buf[512];
 | 
			
		||||
    for(i=0;i<20;i++) {
 | 
			
		||||
        snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
 | 
			
		||||
        write(1, buf, strlen(buf));
 | 
			
		||||
        usleep(150 * 1000);
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_pthread(void)
 | 
			
		||||
{
 | 
			
		||||
    pthread_t tid1, tid2;
 | 
			
		||||
 | 
			
		||||
    pthread_create(&tid1, NULL, thread1_func, "hello1");
 | 
			
		||||
    pthread_create(&tid2, NULL, thread2_func, "hello2");
 | 
			
		||||
    pthread_join(tid1, NULL);
 | 
			
		||||
    pthread_join(tid2, NULL);
 | 
			
		||||
    printf("End of pthread test.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    test_pthread();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1395,6 +1395,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
 | 
			
		|||
    s->aflag = aflag;
 | 
			
		||||
    s->dflag = dflag;
 | 
			
		||||
 | 
			
		||||
    /* lock generation */
 | 
			
		||||
    if (prefixes & PREFIX_LOCK)
 | 
			
		||||
        gen_op_lock();
 | 
			
		||||
 | 
			
		||||
    /* now check op code */
 | 
			
		||||
 reswitch:
 | 
			
		||||
    switch(b) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3153,8 +3157,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
 | 
			
		|||
    default:
 | 
			
		||||
        goto illegal_op;
 | 
			
		||||
    }
 | 
			
		||||
    /* lock generation */
 | 
			
		||||
    if (s->prefix & PREFIX_LOCK)
 | 
			
		||||
        gen_op_unlock();
 | 
			
		||||
    return (long)s->pc;
 | 
			
		||||
 illegal_op:
 | 
			
		||||
    /* XXX: ensure that no lock was generated */
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3609,6 +3617,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
 | 
			
		|||
            pc += count;
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(logfile, "\n");
 | 
			
		||||
        fflush(logfile);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue