Commit d865bab55244797cce4f67a2a8196cbb0ceabc47

Authored by pbrook
1 parent d5975363

Implement thread creation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4693 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 137 additions and 11 deletions
linux-user/syscall.c
... ... @@ -74,6 +74,11 @@
74 74  
75 75 #if defined(USE_NPTL)
76 76 #include <linux/futex.h>
  77 +#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
  78 + CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
  79 +#else
  80 +/* XXX: Hardcode the above values. */
  81 +#define CLONE_NPTL_FLAGS2 0
77 82 #endif
78 83  
79 84 //#define DEBUG
... ... @@ -2706,6 +2711,48 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
2706 2711  
2707 2712 #endif /* defined(TARGET_I386) */
2708 2713  
  2714 +#if defined(USE_NPTL)
  2715 +
  2716 +#define NEW_STACK_SIZE PTHREAD_STACK_MIN
  2717 +
  2718 +static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
  2719 +typedef struct {
  2720 + CPUState *env;
  2721 + pthread_mutex_t mutex;
  2722 + pthread_cond_t cond;
  2723 + pthread_t thread;
  2724 + uint32_t tid;
  2725 + abi_ulong child_tidptr;
  2726 + abi_ulong parent_tidptr;
  2727 + sigset_t sigmask;
  2728 +} new_thread_info;
  2729 +
  2730 +static void *clone_func(void *arg)
  2731 +{
  2732 + new_thread_info *info = arg;
  2733 + CPUState *env;
  2734 +
  2735 + env = info->env;
  2736 + thread_env = env;
  2737 + info->tid = gettid();
  2738 + if (info->child_tidptr)
  2739 + put_user_u32(info->tid, info->child_tidptr);
  2740 + if (info->parent_tidptr)
  2741 + put_user_u32(info->tid, info->parent_tidptr);
  2742 + /* Enable signals. */
  2743 + sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
  2744 + /* Signal to the parent that we're ready. */
  2745 + pthread_mutex_lock(&info->mutex);
  2746 + pthread_cond_broadcast(&info->cond);
  2747 + pthread_mutex_unlock(&info->mutex);
  2748 + /* Wait until the parent has finshed initializing the tls state. */
  2749 + pthread_mutex_lock(&clone_lock);
  2750 + pthread_mutex_unlock(&clone_lock);
  2751 + cpu_loop(env);
  2752 + /* never exits */
  2753 + return NULL;
  2754 +}
  2755 +#else
2709 2756 /* this stack is the equivalent of the kernel stack associated with a
2710 2757 thread/process */
2711 2758 #define NEW_STACK_SIZE 8192
... ... @@ -2717,24 +2764,27 @@ static int clone_func(void *arg)
2717 2764 /* never exits */
2718 2765 return 0;
2719 2766 }
  2767 +#endif
2720 2768  
2721 2769 /* do_fork() Must return host values and target errnos (unlike most
2722 2770 do_*() functions). */
2723   -int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
  2771 +static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
  2772 + abi_ulong parent_tidptr, target_ulong newtls,
  2773 + abi_ulong child_tidptr)
2724 2774 {
2725 2775 int ret;
2726 2776 TaskState *ts;
2727 2777 uint8_t *new_stack;
2728 2778 CPUState *new_env;
  2779 +#if defined(USE_NPTL)
  2780 + unsigned int nptl_flags;
  2781 + sigset_t sigmask;
  2782 +#endif
2729 2783  
2730 2784 if (flags & CLONE_VM) {
2731 2785 #if defined(USE_NPTL)
2732   - /* qemu is not threadsafe. Bail out immediately if application
2733   - tries to create a thread. */
2734   - if (!(flags & CLONE_VFORK)) {
2735   - gemu_log ("clone(CLONE_VM) not supported\n");
2736   - return -EINVAL;
2737   - }
  2786 + new_thread_info info;
  2787 + pthread_attr_t attr;
2738 2788 #endif
2739 2789 ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
2740 2790 init_task_state(ts);
... ... @@ -2744,19 +2794,94 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
2744 2794 /* Init regs that differ from the parent. */
2745 2795 cpu_clone_regs(new_env, newsp);
2746 2796 new_env->opaque = ts;
  2797 +#if defined(USE_NPTL)
  2798 + nptl_flags = flags;
  2799 + flags &= ~CLONE_NPTL_FLAGS2;
  2800 +
  2801 + /* TODO: Implement CLONE_CHILD_CLEARTID. */
  2802 + if (nptl_flags & CLONE_SETTLS)
  2803 + cpu_set_tls (new_env, newtls);
  2804 +
  2805 + /* Grab a mutex so that thread setup appears atomic. */
  2806 + pthread_mutex_lock(&clone_lock);
  2807 +
  2808 + memset(&info, 0, sizeof(info));
  2809 + pthread_mutex_init(&info.mutex, NULL);
  2810 + pthread_mutex_lock(&info.mutex);
  2811 + pthread_cond_init(&info.cond, NULL);
  2812 + info.env = new_env;
  2813 + if (nptl_flags & CLONE_CHILD_SETTID)
  2814 + info.child_tidptr = child_tidptr;
  2815 + if (nptl_flags & CLONE_PARENT_SETTID)
  2816 + info.parent_tidptr = parent_tidptr;
  2817 +
  2818 + ret = pthread_attr_init(&attr);
  2819 + ret = pthread_attr_setstack(&attr, new_stack, NEW_STACK_SIZE);
  2820 + /* It is not safe to deliver signals until the child has finished
  2821 + initializing, so temporarily block all signals. */
  2822 + sigfillset(&sigmask);
  2823 + sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
  2824 +
  2825 + ret = pthread_create(&info.thread, &attr, clone_func, &info);
  2826 +
  2827 + sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
  2828 + pthread_attr_destroy(&attr);
  2829 + if (ret == 0) {
  2830 + /* Wait for the child to initialize. */
  2831 + pthread_cond_wait(&info.cond, &info.mutex);
  2832 + ret = info.tid;
  2833 + if (flags & CLONE_PARENT_SETTID)
  2834 + put_user_u32(ret, parent_tidptr);
  2835 + } else {
  2836 + ret = -1;
  2837 + }
  2838 + pthread_mutex_unlock(&info.mutex);
  2839 + pthread_cond_destroy(&info.cond);
  2840 + pthread_mutex_destroy(&info.mutex);
  2841 + pthread_mutex_unlock(&clone_lock);
  2842 +#else
  2843 + if (flags & CLONE_NPTL_FLAGS2)
  2844 + return -EINVAL;
  2845 + /* This is probably going to die very quickly, but do it anyway. */
2747 2846 #ifdef __ia64__
2748 2847 ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
2749 2848 #else
2750 2849 ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
2751 2850 #endif
  2851 +#endif
2752 2852 } else {
2753 2853 /* if no CLONE_VM, we consider it is a fork */
2754   - if ((flags & ~CSIGNAL) != 0)
  2854 + if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
2755 2855 return -EINVAL;
  2856 + fork_start();
2756 2857 ret = fork();
  2858 +#if defined(USE_NPTL)
  2859 + /* There is a race condition here. The parent process could
  2860 + theoretically read the TID in the child process before the child
  2861 + tid is set. This would require using either ptrace
  2862 + (not implemented) or having *_tidptr to point at a shared memory
  2863 + mapping. We can't repeat the spinlock hack used above because
  2864 + the child process gets its own copy of the lock. */
  2865 + if (ret == 0) {
  2866 + cpu_clone_regs(env, newsp);
  2867 + fork_end(1);
  2868 + /* Child Process. */
  2869 + if (flags & CLONE_CHILD_SETTID)
  2870 + put_user_u32(gettid(), child_tidptr);
  2871 + if (flags & CLONE_PARENT_SETTID)
  2872 + put_user_u32(gettid(), parent_tidptr);
  2873 + ts = (TaskState *)env->opaque;
  2874 + if (flags & CLONE_SETTLS)
  2875 + cpu_set_tls (env, newtls);
  2876 + /* TODO: Implement CLONE_CHILD_CLEARTID. */
  2877 + } else {
  2878 + fork_end(0);
  2879 + }
  2880 +#else
2757 2881 if (ret == 0) {
2758 2882 cpu_clone_regs(env, newsp);
2759 2883 }
  2884 +#endif
2760 2885 }
2761 2886 return ret;
2762 2887 }
... ... @@ -3153,7 +3278,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
3153 3278 ret = do_brk(arg1);
3154 3279 break;
3155 3280 case TARGET_NR_fork:
3156   - ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
  3281 + ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
3157 3282 break;
3158 3283 #ifdef TARGET_NR_waitpid
3159 3284 case TARGET_NR_waitpid:
... ... @@ -4531,7 +4656,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4531 4656 ret = get_errno(fsync(arg1));
4532 4657 break;
4533 4658 case TARGET_NR_clone:
4534   - ret = get_errno(do_fork(cpu_env, arg1, arg2));
  4659 + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
4535 4660 break;
4536 4661 #ifdef __NR_exit_group
4537 4662 /* new thread calls */
... ... @@ -4967,7 +5092,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
4967 5092 #endif
4968 5093 #ifdef TARGET_NR_vfork
4969 5094 case TARGET_NR_vfork:
4970   - ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
  5095 + ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD,
  5096 + 0, 0, 0, 0));
4971 5097 break;
4972 5098 #endif
4973 5099 #ifdef TARGET_NR_ugetrlimit
... ...