Index: configure
===================================================================
RCS file: /home/wine/wine/configure,v
retrieving revision 1.470
diff -u -r1.470 configure
--- configure	16 Oct 2003 05:16:05 -0000	1.470
+++ configure	16 Oct 2003 14:40:26 -0000
@@ -16548,8 +16548,6 @@
 
           ac_config_commands="$ac_config_commands programs/regedit/tests"
 
-          ac_config_commands="$ac_config_commands scheduler"
-
           ac_config_commands="$ac_config_commands windows"
 
 
@@ -16568,7 +16566,7 @@
 MAKE_PROG_RULES=programs/Makeprog.rules
 
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrtd/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uxtheme/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/winejack/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/uuid/Makefile libs/wine/Makefile libs/wpp/Makefile miscemu/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/icmp/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrtd/Makefile dlls/msvideo/Makefile dlls/msvideo/msrle32/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uxtheme/Makefile dlls/version/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winenas/Makefile dlls/winmm/winejack/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/uuid/Makefile libs/wine/Makefile libs/wine_pthread/Makefile libs/wpp/Makefile miscemu/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/osversioncheck/Makefile programs/progman/Makefile programs/regapi/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/regtest/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
 
 
 cat >confcache <<\_ACEOF
@@ -17250,6 +17248,7 @@
   "libs/unicode/Makefile" ) CONFIG_FILES="$CONFIG_FILES libs/unicode/Makefile" ;;
   "libs/uuid/Makefile" ) CONFIG_FILES="$CONFIG_FILES libs/uuid/Makefile" ;;
   "libs/wine/Makefile" ) CONFIG_FILES="$CONFIG_FILES libs/wine/Makefile" ;;
+  "libs/wine_pthread/Makefile" ) CONFIG_FILES="$CONFIG_FILES libs/wine_pthread/Makefile" ;;
   "libs/wpp/Makefile" ) CONFIG_FILES="$CONFIG_FILES libs/wpp/Makefile" ;;
   "miscemu/Makefile" ) CONFIG_FILES="$CONFIG_FILES miscemu/Makefile" ;;
   "programs/Makefile" ) CONFIG_FILES="$CONFIG_FILES programs/Makefile" ;;
@@ -17318,7 +17317,6 @@
   "objects" ) CONFIG_COMMANDS="$CONFIG_COMMANDS objects" ;;
   "programs/regapi/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regapi/tests" ;;
   "programs/regedit/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regedit/tests" ;;
-  "scheduler" ) CONFIG_COMMANDS="$CONFIG_COMMANDS scheduler" ;;
   "windows" ) CONFIG_COMMANDS="$CONFIG_COMMANDS windows" ;;
   "include/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;;
   *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
@@ -18052,8 +18050,6 @@
 echo "$as_me: creating programs/regapi/tests" >&6;} && mkdir "programs/regapi/tests") ;;
     programs/regedit/tests ) test -d "programs/regedit/tests" || ({ echo "$as_me:$LINENO: creating programs/regedit/tests" >&5
 echo "$as_me: creating programs/regedit/tests" >&6;} && mkdir "programs/regedit/tests") ;;
-    scheduler ) test -d "scheduler" || ({ echo "$as_me:$LINENO: creating scheduler" >&5
-echo "$as_me: creating scheduler" >&6;} && mkdir "scheduler") ;;
     windows ) test -d "windows" || ({ echo "$as_me:$LINENO: creating windows" >&5
 echo "$as_me: creating windows" >&6;} && mkdir "windows") ;;
   esac
Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.192
diff -u -r1.192 configure.ac
--- configure.ac	16 Oct 2003 05:16:05 -0000	1.192
+++ configure.ac	16 Oct 2003 14:40:26 -0000
@@ -1380,7 +1380,6 @@
 WINE_CONFIG_EXTRA_DIR(objects)
 WINE_CONFIG_EXTRA_DIR(programs/regapi/tests)
 WINE_CONFIG_EXTRA_DIR(programs/regedit/tests)
-WINE_CONFIG_EXTRA_DIR(scheduler)
 WINE_CONFIG_EXTRA_DIR(windows)
 
 MAKE_RULES=Make.rules
@@ -1551,6 +1550,7 @@
 libs/unicode/Makefile
 libs/uuid/Makefile
 libs/wine/Makefile
+libs/wine_pthread/Makefile
 libs/wpp/Makefile
 miscemu/Makefile
 programs/Makefile
Index: dlls/ntdll/sysdeps.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/sysdeps.c,v
retrieving revision 1.13
diff -u -r1.13 sysdeps.c
--- dlls/ntdll/sysdeps.c	5 Sep 2003 23:08:34 -0000	1.13
+++ dlls/ntdll/sysdeps.c	16 Oct 2003 14:40:26 -0000
@@ -68,6 +68,12 @@
 static char temp_stacks[NB_TEMP_STACKS][TEMP_STACK_SIZE];
 static LONG next_temp_stack;  /* next temp stack to use */
 
+static int nptl_check = NPTL_NOT_CHECKED;
+
+void wine_nptl_check(int new_nptl_check)
+{
+    nptl_check = new_nptl_check;
+}
 
 /***********************************************************************
  *           SYSDEPS_SetCurThread
@@ -96,11 +102,10 @@
     _lwp_setprivate( teb );
 #endif
 
-#ifdef HAVE_NPTL
-    teb->pthread_data = (void *)pthread_self();
-#else
-    wine_pthread_init_thread();
-#endif
+    if (NPTL_PRESENT == nptl_check)
+        teb->pthread_data = (void *)pthread_self();
+    else
+        wine_pthread_init_thread();
 }
 
 
@@ -142,47 +147,51 @@
  */
 int SYSDEPS_SpawnThread( void (*func)(TEB *), TEB *teb )
 {
-#ifdef HAVE_NPTL
-    pthread_t id;
-    pthread_attr_t attr;
-
-    pthread_attr_init( &attr );
-    pthread_attr_setstack( &attr, teb->DeallocationStack,
-                           (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
-    if (pthread_create( &id, &attr, (void * (*)(void *))func, teb )) return -1;
-    return 0;
-#elif defined(HAVE_CLONE)
-    if (clone( (int (*)(void *))func, teb->Tib.StackBase,
-               CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, teb ) < 0)
-        return -1;
-    return 0;
+    if (NPTL_PRESENT == nptl_check) {
+        pthread_t id;
+        pthread_attr_t attr;
+
+        pthread_attr_init( &attr );
+        pthread_attr_setstack( &attr, teb->DeallocationStack,
+                               (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
+        if (pthread_create( &id, &attr, (void * (*)(void *))func, teb )) return -1;
+        return 0;
+    }
+    else
+    {
+#ifdef HAVE_CLONE
+        if (clone( (int (*)(void *))func, teb->Tib.StackBase,
+                   CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, teb ) < 0)
+            return -1;
+        return 0;
 #elif defined(HAVE_RFORK)
-    void **sp = (void **)teb->Tib.StackBase;
-    *--sp = teb;
-    *--sp = 0;
-    *--sp = func;
-    __asm__ __volatile__(
-    "pushl %2;\n\t"		/* flags */
-    "pushl $0;\n\t"		/* 0 ? */
-    "movl %1,%%eax;\n\t"	/* SYS_rfork */
-    ".byte 0x9a; .long 0; .word 7;\n\t"	/* lcall 7:0... FreeBSD syscall */
-    "cmpl $0, %%edx;\n\t"
-    "je 1f;\n\t"
-    "movl %0,%%esp;\n\t"	/* child -> new thread */
-    "ret;\n"
-    "1:\n\t"		/* parent -> caller thread */
-    "addl $8,%%esp" :
-    : "r" (sp), "g" (SYS_rfork), "g" (RFPROC | RFMEM)
-    : "eax", "edx");
-    return 0;
+        void **sp = (void **)teb->Tib.StackBase;
+        *--sp = teb;
+        *--sp = 0;
+        *--sp = func;
+        __asm__ __volatile__(
+        "pushl %2;\n\t"		/* flags */
+        "pushl $0;\n\t"		/* 0 ? */
+        "movl %1,%%eax;\n\t"	/* SYS_rfork */
+        ".byte 0x9a; .long 0; .word 7;\n\t"	/* lcall 7:0... FreeBSD syscall */
+        "cmpl $0, %%edx;\n\t"
+        "je 1f;\n\t"
+        "movl %0,%%esp;\n\t"	/* child -> new thread */
+        "ret;\n"
+        "1:\n\t"		/* parent -> caller thread */
+        "addl $8,%%esp" :
+        : "r" (sp), "g" (SYS_rfork), "g" (RFPROC | RFMEM)
+        : "eax", "edx");
+        return 0;
 #elif defined(HAVE__LWP_CREATE)
-    ucontext_t context;
-    _lwp_makecontext( &context, (void(*)(void *))func, teb,
-                      NULL, teb->DeallocationStack, (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
-    if ( _lwp_create( &context, 0, NULL ) )
-        return -1;
-    return 0;
+        ucontext_t context;
+        _lwp_makecontext( &context, (void(*)(void *))func, teb,
+                          NULL, teb->DeallocationStack, (char *)teb->Tib.StackBase - (char *)teb->DeallocationStack );
+        if ( _lwp_create( &context, 0, NULL ) )
+            return -1;
+        return 0;
 #endif
+    }
 
     FIXME("CreateThread: stub\n" );
     return -1;
@@ -199,43 +208,45 @@
     TEB *teb = NtCurrentTeb();
     DWORD size = 0;
 
-#ifdef HAVE_NPTL
-    static TEB *teb_to_free;
-    TEB *free_teb;
-
-    if ((free_teb = interlocked_xchg_ptr( (void **)&teb_to_free, teb )) != NULL)
+    if (NPTL_PRESENT == nptl_check) {
+        static TEB *teb_to_free;
+        TEB *free_teb;
+
+        if ((free_teb = interlocked_xchg_ptr( (void **)&teb_to_free, teb )) != NULL)
+        {
+            void *ptr;
+
+            TRACE("freeing prev teb %p stack %p fs %04x\n",
+                  free_teb, free_teb->DeallocationStack, free_teb->teb_sel );
+
+            pthread_join( (pthread_t)free_teb->pthread_data, &ptr );
+            wine_ldt_free_fs( free_teb->teb_sel );
+            ptr = free_teb->DeallocationStack;
+            NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
+        }
+        SYSDEPS_AbortThread( status );
+    }
+    else
     {
-        void *ptr;
+        struct thread_cleanup_info info;
+        MEMORY_BASIC_INFORMATION meminfo;
 
-        TRACE("freeing prev teb %p stack %p fs %04x\n",
-              free_teb, free_teb->DeallocationStack, free_teb->teb_sel );
-
-        pthread_join( (pthread_t)free_teb->pthread_data, &ptr );
-        wine_ldt_free_fs( free_teb->teb_sel );
-        ptr = free_teb->DeallocationStack;
-        NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
+        NtQueryVirtualMemory( GetCurrentProcess(), teb->Tib.StackBase, MemoryBasicInformation,
+                              &meminfo, sizeof(meminfo), NULL );
+        info.stack_base = meminfo.AllocationBase;
+        info.stack_size = meminfo.RegionSize + ((char *)teb->Tib.StackBase - (char *)meminfo.AllocationBase);
+        info.status     = status;
+
+        SIGNAL_Block();
+        size = 0;
+        NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE | MEM_SYSTEM );
+        close( teb->wait_fd[0] );
+        close( teb->wait_fd[1] );
+        close( teb->reply_fd );
+        close( teb->request_fd );
+        SIGNAL_Reset();
+        wine_switch_to_stack( cleanup_thread, &info, get_temp_stack() );
     }
-    SYSDEPS_AbortThread( status );
-#else
-    struct thread_cleanup_info info;
-    MEMORY_BASIC_INFORMATION meminfo;
-
-    NtQueryVirtualMemory( GetCurrentProcess(), teb->Tib.StackBase, MemoryBasicInformation,
-                          &meminfo, sizeof(meminfo), NULL );
-    info.stack_base = meminfo.AllocationBase;
-    info.stack_size = meminfo.RegionSize + ((char *)teb->Tib.StackBase - (char *)meminfo.AllocationBase);
-    info.status     = status;
-
-    SIGNAL_Block();
-    size = 0;
-    NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE | MEM_SYSTEM );
-    close( teb->wait_fd[0] );
-    close( teb->wait_fd[1] );
-    close( teb->reply_fd );
-    close( teb->request_fd );
-    SIGNAL_Reset();
-    wine_switch_to_stack( cleanup_thread, &info, get_temp_stack() );
-#endif
 }
 
 
@@ -251,9 +262,8 @@
     close( NtCurrentTeb()->wait_fd[1] );
     close( NtCurrentTeb()->reply_fd );
     close( NtCurrentTeb()->request_fd );
-#ifdef HAVE_NPTL
-    pthread_exit( (void *)status );
-#endif
+    if (NPTL_PRESENT == nptl_check)
+        pthread_exit( (void *)status );
     SIGNAL_Reset();
 #ifdef HAVE__LWP_CREATE
     _lwp_exit();
Index: include/wine/pthread.h
===================================================================
RCS file: /home/wine/wine/include/wine/pthread.h,v
retrieving revision 1.2
diff -u -r1.2 pthread.h
--- include/wine/pthread.h	23 Sep 2003 22:59:44 -0000	1.2
+++ include/wine/pthread.h	16 Oct 2003 14:40:26 -0000
@@ -65,6 +65,8 @@
                                             const struct timespec *abstime);
 };
 
+enum nptl_check_types {NPTL_NOT_CHECKED, NPTL_PRESENT, NPTL_ABSENT};
+
 extern void wine_pthread_init_process( const struct wine_pthread_functions *functions );
 extern void wine_pthread_init_thread(void);
 
Index: libs/Makefile.in
===================================================================
RCS file: /home/wine/wine/libs/Makefile.in,v
retrieving revision 1.5
diff -u -r1.5 Makefile.in
--- libs/Makefile.in	1 May 2003 03:16:21 -0000	1.5
+++ libs/Makefile.in	16 Oct 2003 14:40:26 -0000
@@ -9,15 +9,18 @@
 	unicode \
 	uuid \
 	wine \
+	wine_pthread \
 	wpp
 
 INSTALLSUBDIRS = \
 	unicode \
 	uuid \
-	wine
+	wine \
+	wine_pthread
 
 SYMLINKS = \
 	libwine.$(LIBEXT) \
+	libwine_pthread.$(LIBEXT) \
 	libwine_port.a \
 	libwine_unicode.$(LIBEXT) \
 	libwine_uuid.a \
@@ -40,6 +43,9 @@
 libwine.so libwine.so.1 libwine.dll libwine.a: wine/libwine.$(LIBEXT)
 	$(RM) $@ && $(LN_S) wine/$@ $@
 
+libwine_pthread.so libwine_pthread.so.1 libwine_pthread.dll libwine_pthread.a: wine_pthread/libwine_pthread.$(LIBEXT)
+	$(RM) $@ && $(LN_S) wine_pthread/$@ $@
+
 libwine_unicode.so libwine_unicode.so.1 libwine_unicode.dll libwine_unicode.a: unicode/libwine_unicode.$(LIBEXT)
 	$(RM) $@ && $(LN_S) unicode/$@ $@
 
@@ -55,6 +61,7 @@
 # Directory dependencies
 
 wine/libwine.$(LIBEXT): wine
+wine_pthread/libwine_pthread.$(LIBEXT): wine_pthread
 unicode/libwine_unicode.$(LIBEXT): unicode
 port/libwine_port.a: port
 uuid/libwine_uuid.a: uuid
Index: libs/wine/loader.c
===================================================================
RCS file: /home/wine/wine/libs/wine/loader.c,v
retrieving revision 1.12
diff -u -r1.12 loader.c
--- libs/wine/loader.c	10 Oct 2003 23:33:21 -0000	1.12
+++ libs/wine/loader.c	16 Oct 2003 14:40:26 -0000
@@ -40,6 +40,8 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/library.h"
+#include "wine/pthread.h"
+#include "nptl_support.h"
 
 /* argc/argv for the Windows application */
 int __wine_main_argc = 0;
@@ -420,6 +422,27 @@
     void *ntdll;
     void (*init_func)(void);
 
+#ifdef HAVE_PTHREAD_H
+    void *pthread;
+    void (*wine_nptl_check)( int new_nptl_check );
+
+    char buf[64];
+    confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf));
+    if (!strncmp(buf, "NPTL ", 5))
+        nptl_check = NPTL_PRESENT;
+    else
+        nptl_check = NPTL_ABSENT;
+    if (NPTL_PRESENT == nptl_check) {
+        if (!(pthread = wine_dlopen( "/lib/tls/libpthread.so.0", RTLD_NOW, error, error_size ))) return;
+    }
+    else
+    {
+        if (!(pthread = wine_dlopen( "libwine_pthread.so", RTLD_NOW, error, error_size ))) return;
+        if (!(wine_pthread_init_process_no_nptl = wine_dlsym( pthread, "wine_pthread_init_process_no_nptl", error, error_size ))) return;
+        if (!(wine_pthread_init_thread_no_nptl = wine_dlsym( pthread, "wine_pthread_init_thread_no_nptl", error, error_size ))) return;
+    }
+#endif
+
     build_dll_path();
     init_argv0_path( argv[0] );
     __wine_main_argc = argc;
@@ -427,6 +450,10 @@
     __wine_main_environ = environ;
 
     if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0, &file_exists ))) return;
+#ifdef HAVE_PTHREAD_H
+    if (!(wine_nptl_check = wine_dlsym( ntdll, "wine_nptl_check", error, error_size ))) return;
+    (*wine_nptl_check)(nptl_check);
+#endif
     if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return;
     init_func();
 }
Index: libs/wine/port.c
===================================================================
RCS file: /home/wine/wine/libs/wine/port.c,v
retrieving revision 1.3
diff -u -r1.3 port.c
--- libs/wine/port.c	14 Oct 2003 01:27:31 -0000	1.3
+++ libs/wine/port.c	16 Oct 2003 14:40:26 -0000
@@ -42,26 +42,33 @@
 #ifdef HAVE_PTHREAD_H
 
 #include "wine/pthread.h"
+#include "nptl_support.h"
+
+int nptl_check = NPTL_NOT_CHECKED;
+void (*wine_pthread_init_process_no_nptl)( const struct wine_pthread_functions *functions ) = NULL;
+void (*wine_pthread_init_thread_no_nptl)(void) = NULL;
 
 /***********************************************************************
  *           wine_pthread_init_process
  *
- * This function is just a placeholder, it will be overridden by the pthread support code.
+ * Initialization for a newly created process.
  */
 void wine_pthread_init_process( const struct wine_pthread_functions *functions )
 {
-    assert(0);  /* we must never get here */
+    if (NPTL_ABSENT == nptl_check)
+        (*wine_pthread_init_process_no_nptl)( functions );
 }
 
 
 /***********************************************************************
  *           wine_pthread_init_thread
  *
- * This function is just a placeholder, it will be overridden by the pthread support code.
+ * Initialization for a newly created thread.
  */
 void wine_pthread_init_thread(void)
 {
-    assert(0);  /* we must never get here */
+    if (NPTL_ABSENT == nptl_check)
+        (*wine_pthread_init_thread_no_nptl)();
 }
 
 #endif  /* HAVE_PTHREAD_H */
Index: miscemu/Makefile.in
===================================================================
RCS file: /home/wine/wine/miscemu/Makefile.in,v
retrieving revision 1.23
diff -u -r1.23 Makefile.in
--- miscemu/Makefile.in	12 Oct 2003 02:20:27 -0000	1.23
+++ miscemu/Makefile.in	16 Oct 2003 14:40:26 -0000
@@ -3,13 +3,9 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = wine
-EXTRALIBS = @LIBPTHREAD@
 
 C_SRCS = \
-	$(TOPOBJDIR)/scheduler/pthread.c \
 	main.c
-
-EXTRASUBDIRS = $(TOPOBJDIR)/scheduler
 
 all: $(MODULE)
 
--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ libs/wine/nptl_support.h	2003-10-16 00:04:21.000000000 -0400
@@ -0,0 +1,23 @@
+/*
+ * NPTL detection and usage support
+ *
+ * Copyright 2003 Vincent B�ron
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+extern int nptl_check;
+extern void (*wine_pthread_init_process_no_nptl)( const struct wine_pthread_functions *functions );
+extern void (*wine_pthread_init_thread_no_nptl)(void);
--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ libs/wine_pthread/.cvsignore	2003-10-15 23:59:01.000000000 -0400
@@ -0,0 +1,2 @@
+Makefile
+libwine_pthread.so.1
--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ libs/wine_pthread/Makefile.in	2003-10-16 10:10:54.000000000 -0400
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+LIBRARY   = wine_pthread
+SOVERSION = 1
+EXTRADEFS = -D__WINESRC__
+EXTRALIBS = $(LIBPORT) @DLLIBS@
+
+C_SRCS = \
+	pthread.c
+
+@MAKE_LIB_RULES@
+
+### Dependencies:
--- /dev/null	2003-01-30 05:24:37.000000000 -0500
+++ libs/wine_pthread/pthread.c	2003-10-15 22:46:43.000000000 -0400
@@ -0,0 +1,819 @@
+/*
+ * pthread emulation for re-entrant libcs
+ *
+ * We can't use pthreads directly, so why not let libcs
+ * that want pthreads use Wine's own threading instead...
+ *
+ * Copyright 1999 Ove K�ven
+ * Copyright 2003 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+struct _pthread_cleanup_buffer;
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
+#include "wine/pthread.h"
+
+#define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
+
+#define PSTR(str) __ASM_NAME(#str)
+
+static struct wine_pthread_functions funcs;
+
+/* thread descriptor */
+
+#define FIRST_KEY 0
+#define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
+#define MAX_TSD  16
+
+struct pthread_descr_struct
+{
+    char               dummy[2048];
+    int                thread_errno;
+    int                thread_h_errno;
+    int                cancel_state;
+    int                cancel_type;
+    struct __res_state res_state;
+    const void        *key_data[MAX_KEYS];  /* for normal pthread keys */
+    const void        *tsd_data[MAX_TSD];   /* for libc internal tsd variables */
+};
+
+typedef struct pthread_descr_struct *pthread_descr;
+
+static struct pthread_descr_struct initial_descr;
+
+pthread_descr __pthread_thread_self(void)
+{
+    struct pthread_descr_struct *descr;
+    if (!funcs.ptr_get_thread_data) return &initial_descr;
+    descr = funcs.ptr_get_thread_data();
+    if (!descr) return &initial_descr;
+    return descr;
+}
+
+static int (*libc_uselocale)(int set);
+static int *libc_multiple_threads;
+
+/***********************************************************************
+ *           __errno_location/__error/__errno/___errno/__thr_errno
+ *
+ * Get the per-thread errno location.
+ */
+int *__errno_location(void)                            /* Linux */
+{
+    pthread_descr descr = __pthread_thread_self();
+    return &descr->thread_errno;
+}
+int *__error(void)     { return __errno_location(); }  /* FreeBSD */
+int *__errno(void)     { return __errno_location(); }  /* NetBSD */
+int *___errno(void)    { return __errno_location(); }  /* Solaris */
+int *__thr_errno(void) { return __errno_location(); }  /* UnixWare */
+
+/***********************************************************************
+ *           __h_errno_location
+ *
+ * Get the per-thread h_errno location.
+ */
+int *__h_errno_location(void)
+{
+    pthread_descr descr = __pthread_thread_self();
+    return &descr->thread_h_errno;
+}
+
+struct __res_state *__res_state(void)
+{
+    pthread_descr descr = __pthread_thread_self();
+    return &descr->res_state;
+}
+
+static inline void writejump( const char *symbol, void *dest )
+{
+#if defined(__GLIBC__) && defined(__i386__)
+    unsigned char *addr = dlsym( RTLD_NEXT, symbol );
+
+    if (!addr) return;
+
+    /* write a relative jump at the function address */
+    mprotect((void*)((unsigned int)addr & ~(getpagesize()-1)), 5, PROT_READ|PROT_EXEC|PROT_WRITE);
+    addr[0] = 0xe9;
+    *(int *)(addr+1) = (unsigned char *)dest - (addr + 5);
+    mprotect((void*)((unsigned int)addr & ~(getpagesize()-1)), 5, PROT_READ|PROT_EXEC);
+
+# ifdef HAVE_VALGRIND_MEMCHECK_H
+    VALGRIND_DISCARD_TRANSLATIONS( addr, 5 );
+# endif
+#endif  /* __GLIBC__ && __i386__ */
+}
+
+/***********************************************************************
+ *           wine_pthread_init_process_no_nptl
+ *
+ * Initialization for a newly created process.
+ */
+void wine_pthread_init_process_no_nptl( const struct wine_pthread_functions *functions )
+{
+    memcpy( &funcs, functions, sizeof(funcs) );
+    funcs.ptr_set_thread_data( &initial_descr );
+}
+
+
+/***********************************************************************
+ *           wine_pthread_init_thread_no_nptl
+ *
+ * Initialization for a newly created thread.
+ */
+void wine_pthread_init_thread_no_nptl(void)
+{
+    struct pthread_descr_struct *descr;
+
+    if (funcs.ptr_set_thread_data)
+    {
+        descr = calloc( 1, sizeof(*descr) );
+        funcs.ptr_set_thread_data( descr );
+        if (libc_multiple_threads) *libc_multiple_threads = 1;
+    }
+    else  /* first thread */
+    {
+        descr = &initial_descr;
+        writejump( "__errno_location", __errno_location );
+        writejump( "__h_errno_location", __h_errno_location );
+        writejump( "__res_state", __res_state );
+    }
+    descr->cancel_state = PTHREAD_CANCEL_ENABLE;
+    descr->cancel_type  = PTHREAD_CANCEL_ASYNCHRONOUS;
+    if (libc_uselocale) libc_uselocale( -1 /*LC_GLOBAL_LOCALE*/ );
+}
+
+
+/* Currently this probably works only for glibc2,
+ * which checks for the presence of double-underscore-prepended
+ * pthread primitives, and use them if available.
+ * If they are not available, the libc defaults to
+ * non-threadsafe operation (not good). */
+
+#if defined(__GLIBC__) || defined(__FreeBSD__)
+
+#ifndef __USE_UNIX98
+#define __USE_UNIX98
+#endif
+
+#include <pthread.h>
+
+/* adapt as necessary (a construct like this is used in glibc sources) */
+#define strong_alias(orig, alias) \
+ asm(".globl " PSTR(alias) "\n" \
+     "\t.set " PSTR(alias) "," PSTR(orig))
+
+struct fork_block;
+
+/* pthread functions redirection */
+
+struct pthread_functions
+{
+  pid_t (*ptr_pthread_fork) (struct fork_block *);
+  int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
+  int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *);
+  int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *);
+  int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int);
+  int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int);
+  int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, struct sched_param *);
+  int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, const struct sched_param *);
+  int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int);
+  int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *);
+  int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int);
+  int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *);
+  int (*ptr_pthread_condattr_init) (pthread_condattr_t *);
+  int (*ptr___pthread_cond_broadcast) (pthread_cond_t *);
+  int (*ptr___pthread_cond_destroy) (pthread_cond_t *);
+  int (*ptr___pthread_cond_init) (pthread_cond_t *, const pthread_condattr_t *);
+  int (*ptr___pthread_cond_signal) (pthread_cond_t *);
+  int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
+  int (*ptr_pthread_equal) (pthread_t, pthread_t);
+  void (*ptr___pthread_exit) (void *);
+  int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *);
+  int (*ptr_pthread_setschedparam) (pthread_t, int, const struct sched_param *);
+  int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *);
+  int (*ptr_pthread_mutex_init) (pthread_mutex_t *, const pthread_mutexattr_t *);
+  int (*ptr_pthread_mutex_lock) (pthread_mutex_t *);
+  int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *);
+  int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *);
+  pthread_t (*ptr_pthread_self) (void);
+  int (*ptr_pthread_setcancelstate) (int, int *);
+  int (*ptr_pthread_setcanceltype) (int, int *);
+  void (*ptr_pthread_do_exit) (void *retval, char *currentframe);
+  void (*ptr_pthread_cleanup_upto) (jmp_buf target, char *targetframe);
+  pthread_descr (*ptr_pthread_thread_self) (void);
+  int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer);
+  void * (*ptr_pthread_internal_tsd_get) (int key);
+  void ** __attribute__ ((__const__)) (*ptr_pthread_internal_tsd_address) (int key);
+  int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act, struct sigaction *oact);
+  int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig);
+  int (*ptr_pthread_raise) (int sig);
+  int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
+  void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg);
+  void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer, int execute);
+};
+
+static pid_t (*libc_fork)(void);
+static int (*libc_sigaction)(int signum, const struct sigaction *act, struct sigaction *oldact);
+static int *(*libc_pthread_init)( const struct pthread_functions *funcs );
+
+static struct pthread_functions libc_pthread_functions;
+
+strong_alias(__pthread_thread_self, pthread_thread_self);
+
+/* redefine this to prevent libpthread from overriding our function pointers */
+int *__libc_pthread_init( const struct pthread_functions *funcs )
+{
+    return libc_multiple_threads;
+}
+
+typedef struct _wine_cleanup {
+  void (*routine)(void *);
+  void *arg;
+} *wine_cleanup;
+
+int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
+        (*start_routine)(void *), void* arg)
+{
+    assert( funcs.ptr_pthread_create );
+    return funcs.ptr_pthread_create( thread, attr, start_routine, arg );
+}
+
+int pthread_cancel(pthread_t thread)
+{
+    assert( funcs.ptr_pthread_cancel );
+    return funcs.ptr_pthread_cancel( thread );
+}
+
+int pthread_join(pthread_t thread, void **value_ptr)
+{
+    assert( funcs.ptr_pthread_join );
+    return funcs.ptr_pthread_join( thread, value_ptr );
+}
+
+int pthread_detach(pthread_t thread)
+{
+    assert( funcs.ptr_pthread_detach );
+    return funcs.ptr_pthread_detach( thread );
+}
+
+/* FIXME: we have no equivalents in win32 for the policys */
+/* so just keep this as a stub */
+int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+  P_OUTPUT("FIXME:pthread_attr_setschedpolicy\n");
+  return 0;
+}
+
+/* FIXME: no win32 equivalent for scope */
+int pthread_attr_setscope(pthread_attr_t *attr, int scope)
+{
+  P_OUTPUT("FIXME:pthread_attr_setscope\n");
+  return 0; /* return success */
+}
+
+/* FIXME: no win32 equivalent for schedule param */
+int pthread_attr_setschedparam(pthread_attr_t *attr,
+    const struct sched_param *param)
+{
+  P_OUTPUT("FIXME:pthread_attr_setschedparam\n");
+  return 0; /* return success */
+}
+
+/* FIXME */
+int pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size)
+{
+  return 0; /* return success */
+}
+
+int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+    static pthread_once_t the_once = PTHREAD_ONCE_INIT;
+    long once_now;
+
+    memcpy(&once_now,&the_once,sizeof(once_now));
+    if (interlocked_cmpxchg((long*)once_control, once_now+1, once_now) == once_now)
+        (*init_routine)();
+    return 0;
+}
+strong_alias(__pthread_once, pthread_once);
+
+void __pthread_kill_other_threads_np(void)
+{
+    /* we don't need to do anything here */
+}
+strong_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np);
+
+/***** atfork *****/
+
+#define MAX_ATFORK 8  /* libc doesn't need that many anyway */
+
+static pthread_mutex_t atfork_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+typedef void (*atfork_handler)();
+static atfork_handler atfork_prepare[MAX_ATFORK];
+static atfork_handler atfork_parent[MAX_ATFORK];
+static atfork_handler atfork_child[MAX_ATFORK];
+static int atfork_count;
+
+int __pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+    pthread_mutex_lock( &atfork_mutex );
+    assert( atfork_count < MAX_ATFORK );
+    atfork_prepare[atfork_count] = prepare;
+    atfork_parent[atfork_count] = parent;
+    atfork_child[atfork_count] = child;
+    atfork_count++;
+    pthread_mutex_unlock( &atfork_mutex );
+    return 0;
+}
+strong_alias(__pthread_atfork, pthread_atfork);
+
+pid_t __fork(void)
+{
+    pid_t pid;
+    int i;
+
+    if (!libc_fork)
+    {
+        libc_fork = dlsym( RTLD_NEXT, "fork" );
+        assert( libc_fork );
+    }
+    pthread_mutex_lock( &atfork_mutex );
+    /* prepare handlers are called in reverse insertion order */
+    for (i = atfork_count - 1; i >= 0; i--) if (atfork_prepare[i]) atfork_prepare[i]();
+    if (!(pid = libc_fork()))
+    {
+        pthread_mutex_init( &atfork_mutex, NULL );
+        for (i = 0; i < atfork_count; i++) if (atfork_child[i]) atfork_child[i]();
+    }
+    else
+    {
+        for (i = 0; i < atfork_count; i++) if (atfork_parent[i]) atfork_parent[i]();
+        pthread_mutex_unlock( &atfork_mutex );
+    }
+    return pid;
+}
+strong_alias(__fork, fork);
+
+/***** MUTEXES *****/
+
+int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
+{
+    if (!funcs.ptr_pthread_mutex_init) return 0;
+    return funcs.ptr_pthread_mutex_init( mutex, mutexattr );
+}
+strong_alias(__pthread_mutex_init, pthread_mutex_init);
+
+int __pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+    if (!funcs.ptr_pthread_mutex_lock) return 0;
+    return funcs.ptr_pthread_mutex_lock( mutex );
+}
+strong_alias(__pthread_mutex_lock, pthread_mutex_lock);
+
+int __pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+    if (!funcs.ptr_pthread_mutex_trylock) return 0;
+    return funcs.ptr_pthread_mutex_trylock( mutex );
+}
+strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock);
+
+int __pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+    if (!funcs.ptr_pthread_mutex_unlock) return 0;
+    return funcs.ptr_pthread_mutex_unlock( mutex );
+}
+strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock);
+
+int __pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+    if (!funcs.ptr_pthread_mutex_destroy) return 0;
+    return funcs.ptr_pthread_mutex_destroy( mutex );
+}
+strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy);
+
+
+/***** MUTEX ATTRIBUTES *****/
+/* just dummies, since critical sections are always recursive */
+
+int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+  return 0;
+}
+strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init);
+
+int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+  return 0;
+}
+strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy);
+
+int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
+{
+  return 0;
+}
+strong_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
+
+int __pthread_mutexattr_getkind_np(pthread_mutexattr_t *attr, int *kind)
+{
+  *kind = PTHREAD_MUTEX_RECURSIVE;
+  return 0;
+}
+strong_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
+
+int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
+{
+  return 0;
+}
+strong_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype);
+
+int __pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *kind)
+{
+  *kind = PTHREAD_MUTEX_RECURSIVE;
+  return 0;
+}
+strong_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype);
+
+
+/***** THREAD-SPECIFIC VARIABLES (KEYS) *****/
+
+int __pthread_key_create(pthread_key_t *key, void (*destr_function)(void *))
+{
+    static long keycnt = FIRST_KEY;
+    *key = interlocked_xchg_add(&keycnt, 1);
+    return 0;
+}
+strong_alias(__pthread_key_create, pthread_key_create);
+
+int __pthread_key_delete(pthread_key_t key)
+{
+  return 0;
+}
+strong_alias(__pthread_key_delete, pthread_key_delete);
+
+int __pthread_setspecific(pthread_key_t key, const void *pointer)
+{
+    pthread_descr descr = __pthread_thread_self();
+    descr->key_data[key] = pointer;
+    return 0;
+}
+strong_alias(__pthread_setspecific, pthread_setspecific);
+
+void *__pthread_getspecific(pthread_key_t key)
+{
+    pthread_descr descr = __pthread_thread_self();
+    return (void *)descr->key_data[key];
+}
+strong_alias(__pthread_getspecific, pthread_getspecific);
+
+static int pthread_internal_tsd_set( int key, const void *pointer )
+{
+    pthread_descr descr = __pthread_thread_self();
+    descr->tsd_data[key] = pointer;
+    return 0;
+}
+int (*__libc_internal_tsd_set)(int, const void *) = pthread_internal_tsd_set;
+
+static void *pthread_internal_tsd_get( int key )
+{
+    pthread_descr descr = __pthread_thread_self();
+    return (void *)descr->tsd_data[key];
+}
+void* (*__libc_internal_tsd_get)(int) = pthread_internal_tsd_get;
+
+static void ** __attribute__((const)) pthread_internal_tsd_address( int key )
+{
+    pthread_descr descr = __pthread_thread_self();
+    return (void **)&descr->tsd_data[key];
+}
+void** (*__libc_internal_tsd_address)(int) = pthread_internal_tsd_address;
+
+/***** "EXCEPTION" FRAMES *****/
+/* not implemented right now */
+
+void _pthread_cleanup_push(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
+{
+  ((wine_cleanup)buffer)->routine = routine;
+  ((wine_cleanup)buffer)->arg = arg;
+}
+
+void _pthread_cleanup_pop(struct _pthread_cleanup_buffer *buffer, int execute)
+{
+  if (execute) (*(((wine_cleanup)buffer)->routine))(((wine_cleanup)buffer)->arg);
+}
+
+void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine)(void *), void *arg)
+{
+  _pthread_cleanup_push(buffer, routine, arg);
+}
+
+void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute)
+{
+  _pthread_cleanup_pop(buffer, execute);
+}
+
+void __pthread_cleanup_upto(jmp_buf target, char *frame)
+{
+    /* FIXME */
+}
+
+/***** CONDITIONS *****/
+
+int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
+{
+    if (!funcs.ptr_pthread_cond_init) return 0;
+    return funcs.ptr_pthread_cond_init(cond, cond_attr);
+}
+strong_alias(__pthread_cond_init, pthread_cond_init);
+
+int __pthread_cond_destroy(pthread_cond_t *cond)
+{
+    if (!funcs.ptr_pthread_cond_destroy) return 0;
+    return funcs.ptr_pthread_cond_destroy(cond);
+}
+strong_alias(__pthread_cond_destroy, pthread_cond_destroy);
+
+int __pthread_cond_signal(pthread_cond_t *cond)
+{
+    if (!funcs.ptr_pthread_cond_signal) return 0;
+    return funcs.ptr_pthread_cond_signal(cond);
+}
+strong_alias(__pthread_cond_signal, pthread_cond_signal);
+
+int __pthread_cond_broadcast(pthread_cond_t *cond)
+{
+    if (!funcs.ptr_pthread_cond_broadcast) return 0;
+    return funcs.ptr_pthread_cond_broadcast(cond);
+}
+strong_alias(__pthread_cond_broadcast, pthread_cond_broadcast);
+
+int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+    if (!funcs.ptr_pthread_cond_wait) return 0;
+    return funcs.ptr_pthread_cond_wait(cond, mutex);
+}
+strong_alias(__pthread_cond_wait, pthread_cond_wait);
+
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+    if (!funcs.ptr_pthread_cond_timedwait) return 0;
+    return funcs.ptr_pthread_cond_timedwait(cond, mutex, abstime);
+}
+strong_alias(__pthread_cond_timedwait, pthread_cond_timedwait);
+
+/**** CONDITION ATTRIBUTES *****/
+/* not implemented right now */
+
+int pthread_condattr_init(pthread_condattr_t *attr)
+{
+  return 0;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+  return 0;
+}
+
+/***** READ-WRITE LOCKS *****/
+
+int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
+{
+    assert( funcs.ptr_pthread_rwlock_init );
+    return funcs.ptr_pthread_rwlock_init( rwlock, rwlock_attr );
+}
+strong_alias(__pthread_rwlock_init, pthread_rwlock_init);
+
+int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
+{
+    assert( funcs.ptr_pthread_rwlock_destroy );
+    return funcs.ptr_pthread_rwlock_destroy( rwlock );
+}
+strong_alias(__pthread_rwlock_destroy, pthread_rwlock_destroy);
+
+int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
+{
+    if (!funcs.ptr_pthread_rwlock_rdlock) return 0;
+    return funcs.ptr_pthread_rwlock_rdlock( rwlock );
+}
+strong_alias(__pthread_rwlock_rdlock, pthread_rwlock_rdlock);
+
+int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
+{
+    assert( funcs.ptr_pthread_rwlock_tryrdlock );
+    return funcs.ptr_pthread_rwlock_tryrdlock( rwlock );
+}
+strong_alias(__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock);
+
+int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
+{
+    assert( funcs.ptr_pthread_rwlock_wrlock );
+    return funcs.ptr_pthread_rwlock_wrlock( rwlock );
+}
+strong_alias(__pthread_rwlock_wrlock, pthread_rwlock_wrlock);
+
+int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
+{
+    assert( funcs.ptr_pthread_rwlock_trywrlock );
+    return funcs.ptr_pthread_rwlock_trywrlock( rwlock );
+}
+strong_alias(__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock);
+
+int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
+{
+    if (!funcs.ptr_pthread_rwlock_unlock) return 0;
+    return funcs.ptr_pthread_rwlock_unlock( rwlock );
+}
+strong_alias(__pthread_rwlock_unlock, pthread_rwlock_unlock);
+
+/**** READ-WRITE LOCK ATTRIBUTES *****/
+/* not implemented right now */
+
+int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
+{
+  return 0;
+}
+
+int __pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
+{
+  return 0;
+}
+strong_alias(__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy);
+
+int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref)
+{
+  *pref = 0;
+  return 0;
+}
+
+int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref)
+{
+  return 0;
+}
+
+/***** MISC *****/
+
+pthread_t pthread_self(void)
+{
+    assert( funcs.ptr_pthread_self );
+    return funcs.ptr_pthread_self();
+}
+
+int pthread_equal(pthread_t thread1, pthread_t thread2)
+{
+    assert( funcs.ptr_pthread_equal );
+    return funcs.ptr_pthread_equal( thread1, thread2 );
+}
+
+void __pthread_do_exit(void *retval, char *currentframe)
+{
+    assert( funcs.ptr_pthread_exit );
+    return funcs.ptr_pthread_exit( retval, currentframe );
+}
+
+void __pthread_exit(void *retval)
+{
+    __pthread_do_exit( retval, NULL );
+}
+strong_alias(__pthread_exit, pthread_exit);
+
+int pthread_setcancelstate(int state, int *oldstate)
+{
+    pthread_descr descr = __pthread_thread_self();
+    if (oldstate) *oldstate = descr->cancel_state;
+    descr->cancel_state = state;
+    return 0;
+}
+
+int pthread_setcanceltype(int type, int *oldtype)
+{
+    pthread_descr descr = __pthread_thread_self();
+    if (oldtype) *oldtype = descr->cancel_type;
+    descr->cancel_type = type;
+    return 0;
+}
+
+/***** ANTI-OVERRIDES *****/
+/* pthreads tries to override these, point them back to libc */
+
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+    if (!libc_sigaction)
+    {
+        libc_sigaction = dlsym( RTLD_NEXT, "sigaction" );
+        assert( libc_sigaction );
+    }
+    return libc_sigaction(signum, act, oldact);
+}
+
+void __pthread_initialize(void)
+{
+    static int done;
+
+    if (!done)
+    {
+        done = 1;
+        libc_fork = dlsym( RTLD_NEXT, "fork" );
+        libc_sigaction = dlsym( RTLD_NEXT, "sigaction" );
+        libc_uselocale = dlsym( RTLD_NEXT, "uselocale" );
+        libc_pthread_init = dlsym( RTLD_NEXT, "__libc_pthread_init" );
+        if (libc_pthread_init) libc_multiple_threads = libc_pthread_init( &libc_pthread_functions );
+    }
+}
+DECL_GLOBAL_CONSTRUCTOR(init) { __pthread_initialize(); }
+
+static struct pthread_functions libc_pthread_functions =
+{
+    NULL,                          /* ptr_pthread_fork */
+    NULL, /* FIXME */              /* ptr_pthread_attr_destroy */
+    NULL, /* FIXME */              /* ptr___pthread_attr_init_2_0 */
+    NULL, /* FIXME */              /* ptr___pthread_attr_init_2_1 */
+    NULL, /* FIXME */              /* ptr_pthread_attr_getdetachstate */
+    NULL, /* FIXME */              /* ptr_pthread_attr_setdetachstate */
+    NULL, /* FIXME */              /* ptr_pthread_attr_getinheritsched */
+    NULL, /* FIXME */              /* ptr_pthread_attr_setinheritsched */
+    NULL, /* FIXME */              /* ptr_pthread_attr_getschedparam */
+    pthread_attr_setschedparam,    /* ptr_pthread_attr_setschedparam */
+    NULL, /* FIXME */              /* ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); */
+    NULL, /* FIXME */              /* ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); */
+    NULL, /* FIXME */              /* ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); */
+    NULL, /* FIXME */              /* ptr_pthread_attr_setscope) (pthread_attr_t *, int); */
+    pthread_condattr_destroy,      /* ptr_pthread_condattr_destroy */
+    pthread_condattr_init,         /* ptr_pthread_condattr_init */
+    __pthread_cond_broadcast,      /* ptr___pthread_cond_broadcast */
+    __pthread_cond_destroy,        /* ptr___pthread_cond_destroy */
+    __pthread_cond_init,           /* ptr___pthread_cond_init */
+    __pthread_cond_signal,         /* ptr___pthread_cond_signal */
+    __pthread_cond_wait,           /* ptr___pthread_cond_wait */
+    pthread_equal,                 /* ptr_pthread_equal */
+    __pthread_exit,                /* ptr___pthread_exit */
+    NULL, /* FIXME */              /* ptr_pthread_getschedparam */
+    NULL, /* FIXME */              /* ptr_pthread_setschedparam */
+    __pthread_mutex_destroy,       /* ptr_pthread_mutex_destroy */
+    __pthread_mutex_init,          /* ptr_pthread_mutex_init */
+    __pthread_mutex_lock,          /* ptr_pthread_mutex_lock */
+    __pthread_mutex_trylock,       /* ptr_pthread_mutex_trylock */
+    __pthread_mutex_unlock,        /* ptr_pthread_mutex_unlock */
+    pthread_self,                  /* ptr_pthread_self */
+    pthread_setcancelstate,        /* ptr_pthread_setcancelstate */
+    pthread_setcanceltype,         /* ptr_pthread_setcanceltype */
+    __pthread_do_exit,             /* ptr_pthread_do_exit */
+    __pthread_cleanup_upto,        /* ptr_pthread_cleanup_upto */
+    __pthread_thread_self,         /* ptr_pthread_thread_self */
+    pthread_internal_tsd_set,      /* ptr_pthread_internal_tsd_set */
+    pthread_internal_tsd_get,      /* ptr_pthread_internal_tsd_get */
+    pthread_internal_tsd_address,  /* ptr_pthread_internal_tsd_address */
+    NULL,                          /* ptr_pthread_sigaction */
+    NULL,                          /* ptr_pthread_sigwait */
+    NULL,                          /* ptr_pthread_raise */
+    __pthread_cond_timedwait,      /* ptr___pthread_cond_timedwait */
+    _pthread_cleanup_push,         /* ptr__pthread_cleanup_push */
+    _pthread_cleanup_pop           /* ptr__pthread_cleanup_pop */
+};
+
+#endif /* __GLIBC__ || __FREEBSD__ */
