ryao        14/10/05 13:17:36

  Added:                wine-1.7.28-gstreamer-v4.patch
  Log:
  Version bump, see http://www.winehq.org/announce/1.7.28 for the announcement, 
bug #518792, #516006
  Version bump, see http://www.winehq.org/announce/1.7.22 for the announcement.
  
  I am updating app-emulation/wine after maintainer timeout on bug #518792. It
  was trivial to do a bump to wine 1.7.22, so I am taking the opportunity to
  provide both wine 1.7.22 and wine 1.7.28. The latter of which is the latest.
  Newer versions require revised patch sets, so I have opted to change our we
  apply patches by obtaining pulseaudio patches from the compholio patchset,
  which includes them.
  
  Previously, we bundled the gstreamer patch in our pulseaudio patch set, but 
the
  compholio patches do not include it. In addition, Andreas Sturmlechner points
  out that there is a gstreamer v4 patch. It is a small enough patch that is a
  small enough patch that I have opted to add it to the files directory. This
  should simplify ebuild maintenance because bumps will not require updating
  external tarballs. If time shows that this assumption is wrong, we can always
  move the patch to an external tarball later.
  
  In addition, wine 1.7.25 (if I recall correctly) introduced an optional
  dependency on libpcap. net-libs/libpcap is not multilib capable and none of 
the
  app-emulation/emul-linux-x86-* packages appear to include it. Adding USE=pcap
  requires making net-libs/libpcap multilib capable, which is a task for which I
  do not have time. Since this should not block a new wine ebuild, I have opted
  to add --without-pcap to the 1.7.28 ebuild.
  
  Lastly, the wine 1.7.28 bump was initially written independently, but Andreas
  Sturmlechner contributed his own changes in bug #518792 to provide a working
  1.7.28 ebuild. Some of his changes were rather good, so I have adopted them in
  the wine 1.7.28 bump to produce an ebuild better than what either of us had
  created on our own.
  
  (Portage version: 2.2.8-r2/cvs/Linux x86_64, signed Manifest commit with key 
0xBEE84C64)

Revision  Changes    Path
1.1                  app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch

file : 
http://sources.gentoo.org/viewvc.cgi/gentoo-x86/app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch?rev=1.1&view=markup
plain: 
http://sources.gentoo.org/viewvc.cgi/gentoo-x86/app-emulation/wine/files/wine-1.7.28-gstreamer-v4.patch?rev=1.1&content-type=text/plain

Index: wine-1.7.28-gstreamer-v4.patch
===================================================================
>From 9e081cd4a04e3326d4927aa082695f15432590e2 Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <maarten.lankho...@canonical.com>
Date: Thu, 14 Aug 2014 11:49:20 +0200
Subject: [PATCH] TESTING -- override pthreads to fix gstreamer v4

I believe the code is ready and will work properly now in all cases.
but please test before cherry picking this patch, and report
success or failure to me please.

Changes since v1:
  - Call pthread_yield to make sure that we link against libpthread.
    This fixes the build on saucy.
Changes since v2:
  - Set thread_data->detached before creating the thread to prevent
    a race condition.
Changes since v3:
  - Set thread_data->detached CORRECTLY. Fix a small race between
    thread creation and pthread_detach.
---
 dlls/ntdll/ntdll_misc.h         |    3 +
 dlls/ntdll/thread.c             |  307 +++++++++++++++++++++++++++++++++++++--
 dlls/winegstreamer/glibthread.c |   13 ++
 libs/wine/loader.c              |    7 +
 libs/wine/wine.map              |    6 +
 loader/Makefile.in              |    2 +-
 loader/main.c                   |   41 +++++
 7 files changed, 362 insertions(+), 17 deletions(-)

diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 4370084..1af819b 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -28,6 +28,7 @@
 #include "winnt.h"
 #include "winternl.h"
 #include "wine/server.h"
+#include "wine/list.h"
 
 #define MAX_NT_PATH_LENGTH 277
 
@@ -235,6 +236,8 @@ struct ntdll_thread_data
     WINE_VM86_TEB_INFO vm86;          /* 1fc vm86 private data */
     void              *exit_frame;    /* 204 exit frame pointer */
 #endif
+    struct list entry;
+    BOOL detached;
 };
 
 static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index c8461b0..8d5470e 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -33,6 +33,7 @@
 #ifdef HAVE_SYS_SYSCALL_H
 #include <sys/syscall.h>
 #endif
+#include <errno.h>
 
 #define NONAMELESSUNION
 #include "ntstatus.h"
@@ -58,6 +59,7 @@ struct startup_info
     TEB                            *teb;
     PRTL_THREAD_START_ROUTINE       entry_point;
     void                           *entry_arg;
+    BOOL                            native_thread;
 };
 
 static PEB *peb;
@@ -202,6 +204,78 @@ static ULONG get_dyld_image_info_addr(void)
 }
 #endif  /* __APPLE__ */
 
+#ifdef __linux__
+extern typeof(pthread_create) *__glob_pthread_create, *call_pthread_create;
+extern typeof(pthread_join) *__glob_pthread_join, *call_pthread_join;
+extern typeof(pthread_detach) *__glob_pthread_detach, *call_pthread_detach;
+
+static typeof(pthread_create) __hook_pthread_create;
+static typeof(pthread_join) __hook_pthread_join;
+static typeof(pthread_detach) __hook_pthread_detach;
+
+static pthread_mutex_t thread_lock;
+
+static void thread_wrap_init(void)
+{
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
+    pthread_mutex_init(&thread_lock, &attr);
+    pthread_mutexattr_destroy(&attr);
+
+    call_pthread_create = __hook_pthread_create;
+    call_pthread_join = __hook_pthread_join;
+    call_pthread_detach = __hook_pthread_detach;
+}
+
+static TEB *dead_teb;
+static struct list active_list = LIST_INIT(active_list);
+
+static void take_thread_lock(void)
+{
+    int ret = pthread_mutex_lock(&thread_lock);
+    if (ret == EOWNERDEAD)
+        pthread_mutex_consistent(&thread_lock);
+}
+
+static void detach_thread_unlock(TEB *own_teb)
+{
+    struct ntdll_thread_data *thread_data;
+    TEB *teb = dead_teb;
+
+    dead_teb = own_teb;
+
+    pthread_mutex_unlock(&thread_lock);
+    if (!teb)
+        return;
+
+    thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
+    __glob_pthread_join(thread_data->pthread_id, NULL);
+    signal_free_thread(teb);
+}
+
+static void reap_thread(TEB *teb)
+{
+    struct ntdll_thread_data *thread_data = (struct ntdll_thread_data 
*)teb->SpareBytes1;
+    take_thread_lock();
+    if (thread_data->detached)
+        detach_thread_unlock(teb);
+    else {
+        /*
+         * Do not unlock, wait until the thread is thoroughly dead.
+         * This prevents a race condition where detach is called
+         * after the thread has not finished dying yet.
+         */
+    }
+}
+
+#else
+#define __glob_pthread_create pthread_create
+#define __glob_pthread_join pthread_join
+#define __glob_pthread_detach pthread_detach
+#define thread_wrap_init()
+#endif
+
 /***********************************************************************
  *           thread_init
  *
@@ -220,6 +294,7 @@ HANDLE thread_init(void)
     struct ntdll_thread_data *thread_data;
     static struct debug_info debug_info;  /* debug info for initial thread */
 
+    thread_wrap_init();
     virtual_init();
 
     /* reserve space for shared user data */
@@ -349,14 +424,12 @@ void terminate_thread( int status )
     pthread_exit( UIntToPtr(status) );
 }
 
-
-/***********************************************************************
- *           exit_thread
- */
-void exit_thread( int status )
+static void exit_thread_common( int status )
 {
+#ifndef __linux__
     static void *prev_teb;
     TEB *teb;
+#endif
 
     if (status)  /* send the exit code to the server (0 is already the 
default) */
     {
@@ -380,24 +453,177 @@ void exit_thread( int status )
 
     pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
 
+#ifndef __linux__
     if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() )))
     {
         struct ntdll_thread_data *thread_data = (struct ntdll_thread_data 
*)teb->SpareBytes1;
 
         if (thread_data->pthread_id)
         {
-            pthread_join( thread_data->pthread_id, NULL );
+            __glob_pthread_join( thread_data->pthread_id, NULL );
             signal_free_thread( teb );
         }
     }
+#else
+    reap_thread(NtCurrentTeb());
+#endif
 
     close( ntdll_get_thread_data()->wait_fd[0] );
     close( ntdll_get_thread_data()->wait_fd[1] );
     close( ntdll_get_thread_data()->reply_fd );
     close( ntdll_get_thread_data()->request_fd );
+}
+
+void exit_thread( int status )
+{
+    exit_thread_common(status);
     pthread_exit( UIntToPtr(status) );
 }
 
+#ifdef __linux__
+
+struct unix_arg {
+    void *(*start)(void *);
+    void *arg;
+};
+
+/* dummy used for comparison */
+static DWORD native_unix_start;
+
+static void call_native_cleanup(void *arg)
+{
+    exit_thread_common(0);
+}
+
+static int
+__hook_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                     void *(*start_routine) (void *), void *parm)
+{
+    NTSTATUS ret;
+    pthread_t tid;
+    size_t stack = 8 * 1024 * 1024;
+    struct unix_arg arg;
+    arg.start = start_routine;
+    arg.arg = parm;
+
+    if (!thread)
+        thread = &tid;
+
+    TRACE("Overriding thread creation!\n");
+    if (attr) {
+        static int once;
+        if (!once++)
+            FIXME("most thread attributes ignored!\n");
+        else
+            WARN("most thread attributes ignored!\n");
+
+        pthread_attr_getstacksize(attr, &stack);
+    }
+
+    ret = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, stack, 
0, (void*)&native_unix_start, &arg, NULL, (void*)thread );
+    if (ret != STATUS_SUCCESS)
+        FIXME("ret: %08x\n", ret);
+    switch (ret) {
+    case STATUS_SUCCESS:
+        TRACE("created thread %lx for %p/%p\n", *thread, start_routine, parm);
+        return 0;
+    case STATUS_NO_MEMORY:
+        return ENOMEM;
+    case STATUS_TOO_MANY_OPENED_FILES:
+        return EMFILE;
+    default:
+        ERR("Unhandled ntstatus %08x\n", ret);
+        return ENOMEM;
+    }
+}
+
+static int __hook_pthread_detach(pthread_t thread)
+{
+    struct ntdll_thread_data *thread_data;
+    TEB *teb = NULL;
+
+    if (pthread_equal(thread, pthread_self())) {
+        TRACE("Detached self: %lx\n", pthread_self());
+        ntdll_get_thread_data()->detached = 1;
+        return 0;
+    }
+
+    take_thread_lock();
+    LIST_FOR_EACH_ENTRY(thread_data, &active_list, typeof(*thread_data), 
entry) {
+        if (pthread_equal(thread_data->pthread_id, thread)) {
+            teb = CONTAINING_RECORD(thread_data, typeof(*teb), SpareBytes1);
+
+            list_remove(&thread_data->entry);
+            if (!pthread_tryjoin_np(thread, NULL)) {
+                detach_thread_unlock(NULL);
+                TRACE("Thread %lx was dead, cleaning up\n", thread);
+                signal_free_thread(teb);
+                return 0;
+            }
+            thread_data->detached = 1;
+            break;
+        }
+    }
+    detach_thread_unlock(NULL);
+    if (!teb)
+        TRACE("Could not find thread %lx to detach\n", thread);
+    else
+        TRACE("Changed thread %lx to detached\n", thread);
+    return teb ? 0 : ESRCH;
+}
+
+static int __hook_pthread_join(pthread_t thread, void **retval)
+{
+    struct ntdll_thread_data *thread_data, *t2;
+    int ret = ESRCH;
+
+    if (pthread_equal(thread, pthread_self()))
+        return EDEADLK;
+
+    take_thread_lock();
+    LIST_FOR_EACH_ENTRY(thread_data, &active_list, typeof(*thread_data), 
entry) {
+        TEB *teb = CONTAINING_RECORD(thread_data, typeof(*teb), SpareBytes1);
+
+        if (pthread_equal(thread, thread_data->pthread_id)) {
+
+            ret = pthread_tryjoin_np(thread, retval);
+            if (!ret) {
+                TRACE("Thread %lx was dead fastpath, cleaning up\n", thread);
+                goto free;
+            }
+            detach_thread_unlock(NULL);
+
+            ret = __glob_pthread_join(thread, retval);
+            if (ret) {
+                TRACE("Thread %lx join failed with %i, ignoring\n", thread, 
ret);
+                return ret;
+            }
+
+            take_thread_lock();
+            /* Check if someone else freed the thread yet */
+            LIST_FOR_EACH_ENTRY(t2, &active_list, typeof(*thread_data), entry)
+                if (t2 == thread_data) {
+                    TRACE("Cleaning up after successful join\n");
+                    goto free;
+                }
+            TRACE("No clean up after successful join, multiple 
pthread_join's?\n");
+            break;
+
+free:
+            list_remove(&thread_data->entry);
+            detach_thread_unlock(NULL);
+            signal_free_thread(teb);
+            return 0;
+        }
+    }
+
+    detach_thread_unlock(NULL);
+    if (ret)
+        TRACE("failed with %i\n", ret);
+    return ret;
+}
+
+#endif
 
 /***********************************************************************
  *           start_thread
@@ -426,9 +652,19 @@ static void start_thread( struct startup_info *info )
     if (TRACE_ON(relay))
         DPRINTF( "%04x:Starting thread proc %p (arg=%p)\n", 
GetCurrentThreadId(), func, arg );
 
-    call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );
-}
+#ifdef __linux__
+    if (info->native_thread) {
+        void *(*start)(void*) = (void*)func;
 
+        FIXME("Started native thread %08x\n", GetCurrentThreadId());
+        pthread_cleanup_push(call_native_cleanup, NULL);
+        pthread_exit(start(arg));
+        pthread_cleanup_pop(1);
+        return;
+    }
+#endif
+        call_thread_entry_point( (LPTHREAD_START_ROUTINE)func, arg );
+}
 
 /***********************************************************************
  *              RtlCreateUserThread   (NTDLL.@)
@@ -440,14 +676,13 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, 
const SECURITY_DESCRIPTOR *
                                      HANDLE *handle_ptr, CLIENT_ID *id )
 {
     sigset_t sigset;
-    pthread_t pthread_id;
     pthread_attr_t attr;
     struct ntdll_thread_data *thread_data;
     struct startup_info *info = NULL;
     HANDLE handle = 0, actctx = 0;
     TEB *teb = NULL;
     DWORD tid = 0;
-    int request_pipe[2];
+    int request_pipe[2], ret;
     NTSTATUS status;
 
     if (process != NtCurrentProcess())
@@ -472,10 +707,14 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, 
const SECURITY_DESCRIPTOR *
             if (handle_ptr) *handle_ptr = wine_server_ptr_handle( 
result.create_thread.handle );
             else NtClose( wine_server_ptr_handle( result.create_thread.handle 
));
         }
+        TRACE("CreateThread for other process returns %08x\n", 
result.create_thread.status);
         return result.create_thread.status;
     }
 
-    if (server_pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
+    if (server_pipe( request_pipe ) == -1) {
+        TRACE("CreateThread cannot create request pipe: %m\n");
+        return STATUS_TOO_MANY_OPENED_FILES;
+    }
     wine_server_send_fd( request_pipe[0] );
 
     SERVER_START_REQ( new_thread )
@@ -496,12 +735,16 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, 
const SECURITY_DESCRIPTOR *
     if (status)
     {
         close( request_pipe[1] );
+        TRACE("CreateThread server request failed with %08x\n", status);
         return status;
     }
 
     pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
 
-    if ((status = signal_alloc_thread( &teb ))) goto error;
+    if ((status = signal_alloc_thread( &teb ))) {
+        TRACE("CreateThread signal thread allocation failed with %08x\n", 
status);
+        goto error;
+    }
 
     teb->Peb = NtCurrentTeb()->Peb;
     teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId());
@@ -524,32 +767,64 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, 
const SECURITY_DESCRIPTOR *
 
     info = (struct startup_info *)(teb + 1);
     info->teb         = teb;
-    info->entry_point = start;
-    info->entry_arg   = param;
+#ifdef __linux__
+    info->native_thread = (void*)start == (void*)&native_unix_start;
+    if (info->native_thread) {
+        struct unix_arg *arg = param;
+        info->entry_point = (void*)arg->start;
+        info->entry_arg = arg->arg;
+    } else
+#endif
+    {
+        info->entry_point = start;
+        info->entry_arg   = param;
+    }
 
     thread_data = (struct ntdll_thread_data *)teb->SpareBytes1;
+#ifdef __linux__
+    thread_data->detached = !info->native_thread;
+#endif
     thread_data->request_fd  = request_pipe[1];
     thread_data->reply_fd    = -1;
     thread_data->wait_fd[0]  = -1;
     thread_data->wait_fd[1]  = -1;
+    thread_data->entry.next = NULL;
 
-    if ((status = virtual_alloc_thread_stack( teb, stack_reserve, stack_commit 
))) goto error;
+    if ((status = virtual_alloc_thread_stack( teb, stack_reserve ?: (8 << 20), 
stack_commit ?: (1 << 20) ))) {
+        TRACE("Allocating virtual stack for %p (%li/%li) failed with %08x\n", 
start, stack_reserve, stack_commit, status);
+        goto error;
+    }
 
     pthread_attr_init( &attr );
     pthread_attr_setstack( &attr, teb->DeallocationStack,
                            (char *)teb->Tib.StackBase - (char 
*)teb->DeallocationStack );
     pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a 
kernel thread */
     interlocked_xchg_add( &nb_threads, 1 );
-    if (pthread_create( &pthread_id, &attr, (void * (*)(void *))start_thread, 
info ))
+
+    take_thread_lock();
+    ret = __glob_pthread_create( &thread_data->pthread_id, &attr, (void * 
(*)(void *))start_thread, info );
+    if (ret)
     {
+        TRACE("pthread create failed with %i/%m\n", ret);
         interlocked_xchg_add( &nb_threads, -1 );
         pthread_attr_destroy( &attr );
         status = STATUS_NO_MEMORY;
         goto error;
     }
+    if (!thread_data->detached)
+        list_add_tail(&active_list, &thread_data->entry);
+    detach_thread_unlock(NULL);
+
     pthread_attr_destroy( &attr );
     pthread_sigmask( SIG_SETMASK, &sigset, NULL );
 
+    TRACE("Created thread succesfully, win handle: %04x, pthread: %lx\n", tid, 
thread_data->pthread_id);
+
+#ifdef __linux__
+    if ((void*)start == (void*)&native_unix_start && id)
+        *(pthread_t*)id = thread_data->pthread_id;
+    else
+#endif
     if (id) id->UniqueThread = ULongToHandle(tid);
     if (handle_ptr) *handle_ptr = handle;
     else NtClose( handle );
diff --git a/dlls/winegstreamer/glibthread.c b/dlls/winegstreamer/glibthread.c
index 0d829a0..46e22f4 100644
--- a/dlls/winegstreamer/glibthread.c
+++ b/dlls/winegstreamer/glibthread.c
@@ -43,6 +43,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#if 0
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
@@ -388,3 +389,15 @@ void g_thread_impl_init (void)
   g_thread_self_tls = TlsAlloc ();
   g_thread_init(&g_thread_functions_for_glib_use_default);
 }
+
+#else
+
+void g_thread_impl_init (void)
+{
+  static gboolean beenhere = FALSE;
+
+  if (!beenhere++)
+    g_thread_init(NULL);
+}
+
+#endif
diff --git a/libs/wine/loader.c b/libs/wine/loader.c
index 7261522..a8c31b9 100644
--- a/libs/wine/loader.c
+++ b/libs/wine/loader.c
@@ -73,6 +73,13 @@ char **__wine_main_argv = NULL;
 WCHAR **__wine_main_wargv = NULL;
 char **__wine_main_environ = NULL;
 
+#ifdef __linux__
+#include <pthread.h>
+typeof(pthread_create) *call_pthread_create, *__glob_pthread_create;
+typeof(pthread_join) *call_pthread_join, *__glob_pthread_join;
+typeof(pthread_detach) *call_pthread_detach, *__glob_pthread_detach;
+#endif
+
 struct dll_path_context
 {
     unsigned int index; /* current index in the dll path list */
diff --git a/libs/wine/wine.map b/libs/wine/wine.map
index 2159fac..fb3b951 100644
--- a/libs/wine/wine.map
+++ b/libs/wine/wine.map
@@ -117,6 +117,12 @@ WINE_1.0
     wine_utf8_mbstowcs;
     wine_utf8_wcstombs;
     wine_wctype_table;
+    __glob_pthread_create;
+    call_pthread_create;
+    __glob_pthread_join;
+    call_pthread_join;
+    __glob_pthread_detach;
+    call_pthread_detach;
 
   local: *;
 };
diff --git a/loader/Makefile.in b/loader/Makefile.in
index 95e4798..a18dd02 100644
--- a/loader/Makefile.in
+++ b/loader/Makefile.in
@@ -1,4 +1,4 @@
-EXTRALIBS = $(PTHREAD_LIBS)
+EXTRALIBS = $(PTHREAD_LIBS) $(DL_LIBS)
 
 C_SRCS = \
        main.c \
diff --git a/loader/main.c b/loader/main.c
index ac67290..76609e1 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -202,6 +202,45 @@ static int pre_exec(void)
 
 #endif
 
+#ifdef __linux__
+
+extern typeof(pthread_create) *call_pthread_create, *__glob_pthread_create;
+extern typeof(pthread_detach) *call_pthread_detach, *__glob_pthread_detach;
+extern typeof(pthread_join) *call_pthread_join, *__glob_pthread_join;
+
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                  void *(*start_routine) (void *), void *arg)
+{
+    return call_pthread_create(thread, attr, start_routine, arg);
+}
+
+int pthread_detach(pthread_t thread)
+{
+    return call_pthread_detach(thread);
+}
+
+int pthread_join(pthread_t thread, void **retval)
+{
+    return call_pthread_join(thread, retval);
+}
+
+static void init_thread_hook(void) {
+    call_pthread_create = __glob_pthread_create = dlvsym(RTLD_NEXT, 
"pthread_create", "GLIBC_2.2.5");
+    if (!__glob_pthread_create)
+        call_pthread_create = __glob_pthread_create = dlvsym(RTLD_NEXT, 
"pthread_create", "GLIBC_2.1");
+
+    call_pthread_detach = __glob_pthread_detach = dlsym(RTLD_NEXT, 
"pthread_detach");
+    call_pthread_join = __glob_pthread_join = dlsym(RTLD_NEXT, "pthread_join");
+
+    /* Call a function from libpthread to ensure being linked against it */
+    pthread_yield();
+}
+
+#else
+
+#define init_thread_hook()
+
+#endif
 
 /**********************************************************************
  *           main
@@ -211,6 +250,8 @@ int main( int argc, char *argv[] )
     char error[1024];
     int i;
 
+    init_thread_hook();
+
     if (!getenv( "WINELOADERNOEXEC" ))  /* first time around */
     {
         static char noexec[] = "WINELOADERNOEXEC=1";
-- 
1.7.6.6.GIT





Reply via email to