Index: loader/kthread.c
===================================================================
RCS file: /home/wine/wine/loader/kthread.c,v
retrieving revision 1.11
diff -u -3 -p -r1.11 kthread.c
--- loader/kthread.c	2 Dec 2004 18:19:25 -0000	1.11
+++ loader/kthread.c	6 May 2005 21:22:11 -0000
@@ -68,6 +68,16 @@ struct _pthread_cleanup_buffer;
 #include <sched.h>
 #endif
 
+#ifdef HAVE_THREAD_H
+
+/* Fixme: Wine creates a namespace problem since it has it's own thread.h,
++for the time being explicitly load the system header"
+*/
+
+#include <errno.h>
+#include </usr/include/thread.h>
+#endif
+
 #include "wine/library.h"
 #include "wine/pthread.h"
 
@@ -83,6 +93,31 @@ static struct wine_pthread_functions fun
 #define MAX_KEYS 16 /* libc6 doesn't use that many, but... */
 #define MAX_TSD  16
 
+#define THREADS_SYSV 1
+#define THREADS_LWP 2
+#define THREADS_PTHREAD 3
+#define THREADS_CLONE 4
+#define THREADS_RFORK 5
+#define THREADS_NONE 6
+
+#if defined (HAVE_NPTL) || defined (HAVE_PTHREAD)
+#define THREADS_DEFAULT THREADS_PTHREAD
+#elif defined( HAVE_CLONE)
+#define THREADS_DEFAULT THREADS_CLONE
+#elif defined (HAVE_RFORK)
+#define THREADS_DEFAULT THREADS_RFORK
+#elif defined (HAVE_THR)
+#define THREADS_DEFAULT THREADS_SYSV
+#elif defined (HAVE__LWP_CREATE)
+#define THREADS_DEFAULT THREADS_LWP
+#else
+#define THREADS_DEFAULT THREADS_NONE
+#endif
+
+#define TRACE printf
+#define ERR printf
+
+int threadmode =0;
 struct pthread_descr_struct
 {
     char               dummy[2048];
@@ -123,7 +158,7 @@ int *__errno_location(void)             
 }
 int *__error(void)     { return __errno_location(); }  /* FreeBSD */
 int *__errno(void)     { return __errno_location(); }  /* NetBSD */
-int *___errno(void)    { return __errno_location(); }  /* Solaris */
+//int *___errno(void)    { return __errno_location(); }  /* Solaris */
 int *__thr_errno(void) { return __errno_location(); }  /* UnixWare */
 
 /***********************************************************************
@@ -179,6 +214,44 @@ inline static char *get_temp_stack(void)
     return temp_stacks[next % NB_TEMP_STACKS] + TEMP_STACK_SIZE;
 }
 
+#ifdef HAVE_THR
+/*
+ * THR library specific, store thread specific data
+*/
+#define THREAD_GET_DATA 0
+#define THREAD_SET_DATA 1
+void * solaris_thread_data(int op, void *data)
+{
+       static mutex_t keylock; /* static ensures only one copy of keylock */
+       static thread_key_t key;
+       static int once_per_keyname = 0;
+       void *tsd = NULL;
+
+       if (!once_per_keyname) {
+            mutex_lock(&keylock);
+            if (!once_per_keyname)  {
+                  thr_keycreate(&key, free);
+                  once_per_keyname++;
+       }
+            mutex_unlock(&keylock);
+       }
+       
+       thr_getspecific(key, &tsd);
+       if(op==THREAD_GET_DATA) return(tsd);
+       if (tsd == NULL) {
+            thr_setspecific(key, data);
+              }
+	      else
+	      ERR("Thread private data already set !\n");
+        thr_getspecific(key, &tsd);
+	return((void *) tsd);
+}  
+     /* end thread_specific_data */
+#endif
+ 
+     
+
+
 
 /***********************************************************************
  *           cleanup_thread
@@ -192,9 +265,18 @@ static void cleanup_thread( void *ptr )
     wine_ldt_free_fs( info.teb_sel );
     munmap( info.stack_base, info.stack_size );
     munmap( info.teb_base, info.teb_size );
-#ifdef HAVE__LWP_CREATE
-    _lwp_exit();
+#ifdef HAVE_THR
+    if (threadmode==THREADS_SYSV) {
+       thr_exit((void * ) &info.exit_status);
+    }
 #endif
+#ifdef  HAVE__LWP_CREATE
+    if(threadmode==THREADS_LWP)
+    {
+     _lwp_exit();
+    }
+#endif
+if((threadmode!=THREADS_SYSV) && (threadmode!=THREADS_LWP))
     _exit( info.exit_status );
 }
 
@@ -235,7 +317,9 @@ void wine_pthread_init_thread( struct wi
     }
     descr->cancel_state = PTHREAD_CANCEL_ENABLE;
     descr->cancel_type  = PTHREAD_CANCEL_ASYNCHRONOUS;
+#ifndef sun
     if (libc_uselocale) libc_uselocale( -1 /*LC_GLOBAL_LOCALE*/ );
+#endif
 }
 
 
@@ -244,6 +328,48 @@ void wine_pthread_init_thread( struct wi
  */
 int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
 {
+    
+    /*   Runtime Threadmode support, initially set shared threadmode
+     *  
+     *  Implementation note, 
+      * we determine the threadmode from the environment variable WINE_THREADMODE
+     */
+    char *env;
+
+ TRACE("Starting New Thread stack base = %lx size =%d\n",info->stack_base, (char *)info->stack_size);
+ if(!threadmode)
+    {
+     	env=getenv("WINE_THREADMODE");
+	threadmode=THREADS_DEFAULT;
+
+     	if(env)
+	{
+#ifdef HAVE_THR
+     		if(!strcasecmp(env,"SYSV") ) threadmode=THREADS_SYSV;
+#endif
+#ifdef HAVE__LWP_CREATE
+     		if(!strcasecmp(env,"LWP") ) threadmode=THREADS_LWP;
+#endif
+     		if(!strcasecmp(env,"PTHREAD"))  threadmode=THREADS_PTHREAD;
+#ifdef HAVE_RFORK
+     		if(!strcasecmp(env,"RFORK") ) threadmode=THREADS_RFORK;
+#endif
+#ifdef HAVE_CLONE
+     		if(!strcasecmp(env,"CLONE") ) threadmode=THREADS_CLONE;
+#endif
+      		if(!strcasecmp(env,"NONE") ) threadmode=THREADS_NONE;
+
+TRACE("Setting Threading mode to %d (%s)\n",threadmode,env);
+     	}//env
+  } //! threaadmode
+
+
+if (threadmode == THREADS_NONE)
+{   	TRACE("Threads disabled - Returning an error");
+	return -1;
+ }
+    
+
     if (!info->stack_base)
     {
         info->stack_base = wine_anon_mmap( NULL, info->stack_size,
@@ -251,11 +377,17 @@ int wine_pthread_create_thread( struct w
         if (info->stack_base == (void *)-1) return -1;
     }
 #ifdef HAVE_CLONE
-    if (clone( (int (*)(void *))info->entry, (char *)info->stack_base + info->stack_size,
+    if(threadmode==THREADS_CLONE)
+    {
+      if (clone( (int (*)(void *))info->entry, (char *)info->stack_base + info->stack_size,
                CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, info ) < 0)
         return -1;
     return 0;
-#elif defined(HAVE_RFORK)
+    }
+#endif
+
+#ifdef HAVE_RFORK
+    if(threadmode==THREADS_RFORK)
     {
         void **sp = (void **)((char *)info->stack_base + info->stack_size);
         *--sp = info;
@@ -276,15 +408,78 @@ int wine_pthread_create_thread( struct w
             : "eax", "edx");
         return 0;
     }
-#elif defined(HAVE__LWP_CREATE)
-    {
+
+#endif
+#ifdef HAVE_THR
+ 	if(threadmode==THREADS_SYSV)
+	{
+ 		thread_t tid;
+		int err;
+
+		TRACE("Starting New Thread Via thr_create\n");
+ 	err=thr_create(info->stack_base, ( int )info->stack_size,  (void * (*) (void*)) info->entry, info,THR_BOUND|THR_DETACHED,&tid) ;
+ 		if(err)
+ 		{
+   			switch(err)
+   			{
+      			case EAGAIN:
+        			ERR("Thread creation failed EAGAIN - System is out of threads or lwps\n");
+        			break;
+      			case EINVAL:
+        			ERR("Thread creation failed EINVAL - The stack_base argument is not NULL and stack_size  is  less  than the value returned by thr_min_stack,  or the stack_base argument is NULL and  stack_size  is   not   0  and  is  less  than  the  value  returned  by          thr_min_stack\n");
+        			break;
+      			case ENOMEM:
+        			ERR("Thread creation failed ENOMEM - here is not enough memory to allocate the stack for the thread\n");
+        			break;
+       			case -1:
+        			ERR("Thread creation failed (-1) - Application is not linked with threading libraryn");
+        			break;
+      			default:
+        			ERR("Thread creation failed Unknown %d - Possible mmap failure check mmap results\n",err);
+        			break;
+   			}
+    			return -1;
+ 		}
+		else
+    			TRACE("Started New Thread Via thr_create\n");
+    		return 0;
+	} /* threadmode*/
+#endif
+
+#ifdef HAVE__LWP_CREATE
+  if(threadmode==THREADS_LWP)
+  {
+      int err;
+
         ucontext_t context;
         _lwp_makecontext( &context, (void(*)(void *))info->entry, info,
                           NULL, info->stack_base, info->stack_size );
-        if ( _lwp_create( &context, 0, NULL ) )
-            return -1;
-        return 0;
-    }
+        if ( (err=_lwp_create( &context, 0, NULL )) )
+	{
+
+  		switch (err)
+		{
+      		case EFAULT:
+        		ERR("lwp_create: Either the context parameter or the new_lwp  parameter  point to invalid addresses.");
+        		break;
+      		case EAGAIN:
+        		ERR("lwp_create: Resources depleted, probably too many lwps");
+        		break;
+      		case EINVAL:
+        		ERR("lwp_create: FLAGS argument invalid\n");
+        		break;
+       		case -1:
+        		ERR("Thread creation failed\n");
+        		break;
+      		default:
+        		ERR("Thread creation failed Unknown %d \n",err);
+        		break;
+   		}
+           return -1;
+        } /* if err*/
+	return 0;
+    } /* Threadmode = THREADS_LWP */
+
 #endif
     return -1;
 }
@@ -305,9 +500,19 @@ void wine_pthread_init_current_teb( stru
     wine_ldt_set_limit( &fs_entry, info->teb_size - 1 );
     wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
     wine_ldt_init_fs( info->teb_sel, &fs_entry );
-#elif defined(HAVE__LWP_CREATE)
-    /* On non-i386 Solaris, we use the LWP private pointer */
-    _lwp_setprivate( info->teb_base );
+
+#elif defined(HAVE__LWP_CREATE) || defined (HAVE_THR)
+
+#ifdef HAVE__LWP_CREATE
+   /* On non-i386 Solaris, we use the LWP private pointer */
+ if(threadmode==THREADS_LWP)    ret = _lwp_setprivate(info->teb_base);
+#endif
+
+#ifdef HAVE_THR
+   /* On non-i386 Solaris, we can also use the threads private pointer */
+   if(threadmode==THREADS_SYSV) ret=solaris_thread_data(THREAD_SET_DATA,info->teb_base);
+#endif
+
 #elif defined(__powerpc__)
     /* On PowerPC, the current TEB is in the gpr13 register */
 # ifdef __APPLE__
@@ -324,8 +529,21 @@ void wine_pthread_init_current_teb( stru
 
     /* set pid and tid */
     info->pid = getpid();
-#ifdef HAVE__LWP_SELF
-    info->tid = _lwp_self();
+
+
+
+#if defined ( HAVE__LWP_SELF ) || defined (HAVE_THR)
+ 	info->tid = -1;
+#if defined ( HAVE__LWP_SELF )
+	if(threadmode==THREADS_LWP)   info->tid = _lwp_self();
+#endif
+
+#if defined (HAVE_THR)
+	if(threadmode==THREADS_SYSV)  info->tid=thr_self();
+#endif
+    
+
+
 #else
     info->tid = -1;
 #endif
@@ -341,8 +559,18 @@ void *wine_pthread_get_current_teb(void)
 
 #ifdef __i386__
     __asm__( ".byte 0x64\n\tmovl 0x18,%0" : "=r" (ret) );
-#elif defined(HAVE__LWP_CREATE)
-    ret = _lwp_getprivate();
+#elif defined(HAVE__LWP_CREATE) || defined (HAVE_THR)
+
+#ifdef HAVE__LWP_CREATE
+if(threadmode==THREADS_LWP)    ret = _lwp_getprivate();
+#endif
+
+#ifdef HAVE_THR
+ if(threadmode==THREADS_SYSV) ret=solaris_thread_data(THREAD_GET_DATA,NULL);
+#endif
+   
+    
+    
 #elif defined(__powerpc__)
 # ifdef __APPLE__
     __asm__( "mr %0,r13" : "=r" (ret) );
@@ -379,9 +607,20 @@ void wine_pthread_exit_thread( struct wi
  */
 void wine_pthread_abort_thread( int status )
 {
-#ifdef HAVE__LWP_CREATE
-    _lwp_exit();
+
+#ifdef HAVE_THR
+if (threadmode==THREADS_SYSV) {
+    thr_exit((void * ) &status);
+}
+#endif
+#ifdef  HAVE__LWP_CREATE
+  if(threadmode==THREADS_LWP)
+  {
+     _lwp_exit();
+ }
 #endif
+
+
     _exit( status );
 }
 
