diff --git a/configure b/configure index b3d7fd8642..8eec675eec 100755 --- a/configure +++ b/configure @@ -112,6 +112,7 @@ darwin_user="no" build_docs="no" uname_release="" curses="yes" +nptl="yes" # OS specific targetos=`uname -s` @@ -331,6 +332,8 @@ for opt do ;; --disable-curses) curses="no" ;; + --disable-nptl) nptl="no" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -424,6 +427,7 @@ echo " --enable-dsound enable DirectSound audio driver" echo " --disable-brlapi disable BrlAPI" echo " --disable-vnc-tls disable TLS encryption for VNC server" echo " --disable-curses disable curses output" +echo " --disable-nptl disable usermode NPTL support" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets" @@ -641,6 +645,24 @@ int main(void) { } EOF +# Check host NPTL support +cat > $TMPC < +#include +void foo() +{ +#if !defined(CLONE_SETTLS) || !defined(FUTEX_WAIT) +#error bork +#endif +} +EOF + +if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC 2> /dev/null ; then + : +else + nptl="no" +fi + ########################################## # SDL probe @@ -839,6 +861,7 @@ echo "brlapi support $brlapi" echo "Documentation $build_docs" [ ! -z "$uname_release" ] && \ echo "uname -r $uname_release" +echo "NPTL support $nptl" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -1190,6 +1213,7 @@ echo "#include \"../config-host.h\"" >> $config_h bflt="no" elfload32="no" +target_nptl="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h @@ -1232,6 +1256,7 @@ case "$target_cpu" in echo "#define TARGET_ARCH \"arm\"" >> $config_h echo "#define TARGET_ARM 1" >> $config_h bflt="yes" + target_nptl="yes" ;; cris) echo "TARGET_ARCH=cris" >> $config_mak @@ -1379,6 +1404,10 @@ if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then echo "TARGET_HAS_BFLT=yes" >> $config_mak echo "#define TARGET_HAS_BFLT 1" >> $config_h fi +if test "$target_user_only" = "yes" \ + -a "$nptl" = "yes" -a "$target_nptl" = "yes"; then + echo "#define USE_NPTL 1" >> $config_h +fi # 32 bit ELF loader in addition to native 64 bit loader? if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fe97be1c9a..0c5f0a2ae9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -52,6 +52,9 @@ //#include #include #include +#if defined(USE_NPTL) +#include +#endif #define termios host_termios #define winsize host_winsize @@ -160,6 +163,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_tkill __NR_tkill #define __NR_sys_unlinkat __NR_unlinkat #define __NR_sys_utimensat __NR_utimensat +#define __NR_sys_futex __NR_futex #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -241,6 +245,11 @@ _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, const struct timespec *,tsp,int,flags) #endif +#if defined(TARGET_NR_futex) && defined(__NR_futex) +_syscall6(int,sys_futex,int *,uaddr,int,op,int,val, + const struct timespec *,timeout,int *,uaddr2,int,val3) + +#endif extern int personality(int); extern int flock(int, int); @@ -2718,6 +2727,14 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp) CPUState *new_env; if (flags & CLONE_VM) { +#if defined(USE_NPTL) + /* qemu is not threadsafe. Bail out immediately if application + tries to create a thread. */ + if (!(flags & CLONE_VFORK)) { + gemu_log ("clone(CLONE_VM) not supported\n"); + return -EINVAL; + } +#endif ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); memset(ts, 0, sizeof(TaskState)); new_stack = ts->stack; @@ -3056,6 +3073,45 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr, return 0; } +#if defined(USE_NPTL) +/* ??? Using host futex calls even when target atomic operations + are not really atomic probably breaks things. However implementing + futexes locally would make futexes shared between multiple processes + tricky. However they're probably useless because guest atomic + operations won't work either. */ +int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, + target_ulong uaddr2, int val3) +{ + struct timespec ts, *pts; + + /* ??? We assume FUTEX_* constants are the same on both host + and target. */ + switch (op) { + case FUTEX_WAIT: + if (timeout) { + pts = &ts; + target_to_host_timespec(pts, timeout); + } else { + pts = NULL; + } + return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val), + pts, NULL, 0)); + case FUTEX_WAKE: + return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0)); + case FUTEX_FD: + return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0)); + case FUTEX_REQUEUE: + return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val, + NULL, g2h(uaddr2), 0)); + case FUTEX_CMP_REQUEUE: + return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val, + NULL, g2h(uaddr2), tswap32(val3))); + default: + return -TARGET_ENOSYS; + } +} +#endif + int get_osversion(void) { static int osversion; @@ -5614,6 +5670,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#if defined(USE_NPTL) + case TARGET_NR_futex: + ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif default: unimplemented: