Threading on Solaris

Gregg Mattinson gm138242 at scot.canada.sun.com
Tue Aug 13 06:52:40 CDT 2002


This is a patch against wine-20020710 to fix threading in Solaris.  I submitted 
it over two weeks ago, and I was wondering what's happened to it.  Unfortunatly, 
Sun has moved it's focus away from Wine, so I no longer have time to submit 
patches.  I just wanted to make sure this patch gets in because it will 
*hopefully* fix many issues for OSs which use LWPs.

Thanks,
Gregg Mattinson
Co-op Developer
Sun Microsystems of Canada


------------- Begin Forwarded Message -------------

From: Gregg Mattinson <gm138242 at opcom-mail.canada.sun.com>
Subject: Threading on Solaris
To: wine-patches at winehq.com
Date: Fri, 26 Jul 2002 13:48:42 -0400 (EDT)

Here is my first attempt at fixing threads for Solaris.  This patch is based on 
the comments from and bug entered by Francois Gouget.

I compiled the wineserver under i386-solaris, and it runs.  I do not have the 
resources to compile ALL of wine under i386, or on any OS other than Solaris so 
the linux and BSD portions of this code are completly un-tested.

ChangeLog:
  include/wine/server_protocol.h
  scheduler/client.c
  scheduler/process.c
  server/console.c
  server/context_i386.c
  server/context_sparc.c
  server/debugger.c
  server/process.c
  server/process.h
  server/ptrace.c
  server/thread.c
  server/thread.h
  server/trace.c
 - Improved wineserver's handling of LWPs by following recommendations from 
http://bugs.winehq.com/show_bug.cgi?id=904  With LWPs (Solaris), each wine 
process contains the unix_pid, and each thread contains the LWP id.  Without 
LWPs (Linux, BSD, ...) each process contains the unix_pid 0, and each thread 
contains the actual unix pid in it's tid member.
 

------------- End Forwarded Message -------------
-------------- next part --------------
Index: include/wine/server_protocol.h
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/include/wine/server_protocol.h,v
retrieving revision 1.1
diff -u -r1.1 server_protocol.h
--- /tmp/T0usaaXl	Fri Jul 26 09:17:16 2002
+++ server_protocol.h	Wed Jul 24 10:28:34 2002
@@ -248,7 +248,9 @@
 {
     struct request_header __header;
     void*        ldt_copy;
-    int          ppid;
+    int          unix_pid;
+    int          unix_ppid;
+    int          unix_ptid;
 };
 struct init_process_reply
 {
@@ -298,7 +300,7 @@
 struct init_thread_request
 {
     struct request_header __header;
-    int          unix_pid;
+    int          unix_tid;
     void*        teb;
     void*        entry;
     int          reply_fd;
Index: scheduler/client.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/scheduler/client.c,v
retrieving revision 1.2
diff -u -r1.2 client.c
--- /tmp/T07na42l	Fri Jul 26 09:17:40 2002
+++ client.c	Tue Jul 23 15:51:27 2002
@@ -686,7 +686,11 @@
 
     SERVER_START_REQ( init_thread )
     {
-        req->unix_pid    = getpid();
+#ifdef HAVE__LWP_CREATE
+        req->unix_tid    = _lwp_self();
+#else
+        req->unix_tid    = getpid();
+#endif
         req->teb         = teb;
         req->entry       = teb->entry_point;
         req->reply_fd    = reply_pipe[1];
Index: scheduler/process.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/scheduler/process.c,v
retrieving revision 1.2
diff -u -r1.2 process.c
--- /tmp/T0Dwaq3l	Fri Jul 26 09:17:41 2002
+++ process.c	Wed Jul 24 10:29:04 2002
@@ -241,6 +241,25 @@
 }
 
 
+static void wine_get_parent_id( int *ppid, int *ptid )
+{
+#ifdef HAVE__LWP_CREATE
+    char *env_ppid;
+
+    env_ppid = getenv( "WINE_PARENT_LWPID" );
+    if ((env_ppid == NULL) || (sscanf( env_ppid, "%d:%d", ppid, ptid ) != 2) ||
+        (*ppid != getppid())) {
+        /* Maybe the parent is not a Wine process */
+        *ppid = getppid();
+        *ptid = 0;
+    }
+#else
+    *ppid = 0;
+    *ptid = getppid();
+#endif
+}
+
+
 /***********************************************************************
  *           get_basename
  */
@@ -380,7 +399,8 @@
     SERVER_START_REQ( init_process )
     {
         req->ldt_copy  = &wine_ldt_copy;
-        req->ppid      = getppid();
+	req->unix_pid  = getpid();
+        wine_get_parent_id( &req->unix_ppid, &req->unix_ptid );
         if ((ret = !wine_server_call_err( req )))
         {
             main_exe_file     = reply->exe_file;
@@ -541,7 +561,7 @@
  */
 void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win16_exe_file )
 {
-    char error[100];
+    char error[1024];
     DWORD stack_size = 0;
 
     /* Initialize everything */
@@ -844,6 +864,10 @@
     int pid, err;
     char *extra_env = NULL;
 
+#ifdef HAVE__LWP_CREATE
+    int ptid = _lwp_self();
+#endif
+
     if (!env)
     {
         env = GetEnvironmentStringsA();
@@ -862,6 +886,13 @@
         char **envp = build_envp( env, extra_env );
         close( fd[0] );
 
+#ifdef HAVE__LWP_CREATE
+        {
+            char *env_ppid = malloc( 40 );
+            sprintf( env_ppid, "WINE_PARENT_LWPID=%d:%d", getppid(), ptid );
+            putenv( env_ppid );
+        }
+#endif
         /* Reset signals that we previously set to SIG_IGN */
         signal( SIGPIPE, SIG_DFL );
         signal( SIGCHLD, SIG_DFL );
Index: server/console.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/console.c,v
retrieving revision 1.2
diff -u -r1.2 console.c
--- /tmp/T0pNaa4l	Fri Jul 26 09:17:42 2002
+++ console.c	Tue Jul 23 07:47:51 2002
@@ -404,7 +404,7 @@
         while (thread)
         {
             struct thread *next = thread->proc_next;
-            kill( thread->unix_pid, csi->signal );
+            signal_thread( thread, csi->signal );
             thread = next;
         }
     }
Index: server/context_i386.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/context_i386.c,v
retrieving revision 1.1
diff -u -r1.1 context_i386.c
--- /tmp/T0qSay4l	Fri Jul 26 09:17:42 2002
+++ context_i386.c	Fri Jul 26 09:13:25 2002
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
 #endif
@@ -37,6 +38,7 @@
 
 #include "winbase.h"
 #include "thread.h"
+#include "process.h"
 #include "request.h"
 
 #ifndef PTRACE_PEEKUSER
@@ -68,6 +70,8 @@
 #define PTRACE_SETFPREGS PT_SETFPREGS
 #endif
 
+#ifndef HAVE__LWP_CREATE
+
 #ifdef linux
 #ifdef HAVE_SYS_USER_H
 # include <sys/user.h>
@@ -104,7 +108,7 @@
 /* retrieve a thread context */
 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
 {
-    int pid = thread->unix_pid;
+    int pid = thread->unix_tid;
     if (flags & CONTEXT_FULL)
     {
         struct kernel_user_regs_struct regs;
@@ -160,7 +164,7 @@
 /* set a thread context */
 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
 {
-    int pid = thread->unix_pid;
+    int pid = thread->unix_tid;
     if (flags & CONTEXT_FULL)
     {
         struct kernel_user_regs_struct regs;
@@ -215,15 +219,16 @@
     file_set_error();
 }
 
-#elif defined(__sun) || defined(__sun__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#include <machine/reg.h>
 
 /* retrieve a thread context */
 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
 {
-    int pid = thread->unix_pid;
+    int pid = thread->unix_tid;
     if (flags & CONTEXT_FULL)
     {
-        struct regs regs;
+        struct reg regs;
         if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
         if (flags & CONTEXT_INTEGER)
         {
@@ -241,7 +246,7 @@
             context->Eip    = regs.r_eip;
             context->SegCs  = regs.r_cs & 0xffff;
             context->SegSs  = regs.r_ss & 0xffff;
-            context->EFlags = regs.r_efl;
+            context->EFlags = regs.r_eflags;
         }
         if (flags & CONTEXT_SEGMENTS)
         {
@@ -253,7 +258,7 @@
     }
     if (flags & CONTEXT_DEBUG_REGISTERS)
     {
-        /* FIXME: How is this done on Solaris? */
+        /* FIXME: How is this done on FreeBSD? */
     }
     if (flags & CONTEXT_FLOATING_POINT)
     {
@@ -271,10 +276,10 @@
 /* set a thread context */
 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
 {
-    int pid = thread->unix_pid;
+    int pid = thread->unix_tid;
     if (flags & CONTEXT_FULL)
     {
-        struct regs regs;
+        struct reg regs;
         if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
         {
             /* need to preserve some registers */
@@ -296,7 +301,7 @@
             regs.r_eip = context->Eip;
             regs.r_cs = context->SegCs;
             regs.r_ss = context->SegSs;
-            regs.r_efl = context->EFlags;
+            regs.r_eflags = context->EFlags;
         }
         if (flags & CONTEXT_SEGMENTS)
         {
@@ -309,7 +314,7 @@
     }
     if (flags & CONTEXT_DEBUG_REGISTERS)
     {
-        /* FIXME: How is this done on Solaris? */
+        /* FIXME: How is this done on FreeBSD? */
     }
     if (flags & CONTEXT_FLOATING_POINT)
     {
@@ -322,53 +327,70 @@
     file_set_error();
 }
 
-#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
-#include <machine/reg.h>
+#else  /* linux || __FreeBSD__ */
+#error You must implement get/set_thread_context for your platform
+#endif  /* linux || __FreeBSD__ */
+
+#else /* HAVE__LWP_CREATE */
+
+#undef _FILE_OFFSET_BITS
+#include <procfs.h>
+
+static BOOL get_thread_status( struct thread *thread, struct lwpstatus *status)
+{
+    char   sStatusFile[30];
+    int    fd;
+
+    sprintf( sStatusFile, "/proc/%d/lwp/%d/lwpstatus",
+	     thread->process->unix_pid, thread->unix_tid );
+    if (-1 == (fd = open( sStatusFile, O_RDONLY ))) return FALSE;
+    if (sizeof(status) != read(fd, &status, sizeof(status))) return FALSE;
+    close(fd);
+
+    return TRUE;
+}
+
 
 /* retrieve a thread context */
 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
 {
-    int pid = thread->unix_pid;
-    if (flags & CONTEXT_FULL)
+    struct lwpstatus status;
+
+    if (!get_thread_status(thread, &status)) goto error;
+
+    if (flags & CONTEXT_INTEGER)
     {
-        struct reg regs;
-        if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
-        if (flags & CONTEXT_INTEGER)
-        {
-            context->Eax = regs.r_eax;
-            context->Ebx = regs.r_ebx;
-            context->Ecx = regs.r_ecx;
-            context->Edx = regs.r_edx;
-            context->Esi = regs.r_esi;
-            context->Edi = regs.r_edi;
-        }
-        if (flags & CONTEXT_CONTROL)
-        {
-            context->Ebp    = regs.r_ebp;
-            context->Esp    = regs.r_esp;
-            context->Eip    = regs.r_eip;
-            context->SegCs  = regs.r_cs & 0xffff;
-            context->SegSs  = regs.r_ss & 0xffff;
-            context->EFlags = regs.r_eflags;
-        }
-        if (flags & CONTEXT_SEGMENTS)
-        {
-            context->SegDs = regs.r_ds & 0xffff;
-            context->SegEs = regs.r_es & 0xffff;
-            context->SegFs = regs.r_fs & 0xffff;
-            context->SegGs = regs.r_gs & 0xffff;
-        }
+	context->Eax = status.pr_reg[EAX];
+	context->Ebx = status.pr_reg[EBX];
+	context->Ecx = status.pr_reg[ECX];
+	context->Edx = status.pr_reg[EDX];
+	context->Esi = status.pr_reg[ESI];
+	context->Edi = status.pr_reg[EDI];
+    }
+    if (flags & CONTEXT_CONTROL)
+    {
+	context->Ebp    = status.pr_reg[EBP];
+	context->Esp    = status.pr_reg[ESP];
+	context->Eip    = status.pr_reg[EIP];
+	context->SegCs  = status.pr_reg[CS] & 0xffff;
+	context->SegSs  = status.pr_reg[SS] & 0xffff;
+	context->EFlags = status.pr_reg[EFL];
+    }
+    if (flags & CONTEXT_SEGMENTS)
+    {
+	context->SegDs = status.pr_reg[DS] & 0xffff;
+	context->SegEs = status.pr_reg[ES] & 0xffff;
+	context->SegFs = status.pr_reg[FS] & 0xffff;
+	context->SegGs = status.pr_reg[GS] & 0xffff;
     }
     if (flags & CONTEXT_DEBUG_REGISTERS)
     {
-        /* FIXME: How is this done on FreeBSD? */
+        /* FIXME: How is this done with procfs? */
     }
     if (flags & CONTEXT_FLOATING_POINT)
     {
-        /* we can use context->FloatSave directly as it is using the */
-        /* correct structure (the same as fsave/frstor) */
-        if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
-        context->FloatSave.Cr0NpxState = 0;  /* FIXME */
+        /* FIXME status.pr_fpreg should be used here,
+	 * but it's format is different from context->FloatSave */
     }
     return;
  error:
@@ -379,60 +401,55 @@
 /* set a thread context */
 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
 {
-    int pid = thread->unix_pid;
+    struct lwpstatus status;
+
+    if (!get_thread_status(thread, &status)) goto error;
+
     if (flags & CONTEXT_FULL)
     {
-        struct reg regs;
-        if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
-        {
-            /* need to preserve some registers */
-            if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
-        }
-        if (flags & CONTEXT_INTEGER)
-        {
-            regs.r_eax = context->Eax;
-            regs.r_ebx = context->Ebx;
-            regs.r_ecx = context->Ecx;
-            regs.r_edx = context->Edx;
-            regs.r_esi = context->Esi;
-            regs.r_edi = context->Edi;
-        }
-        if (flags & CONTEXT_CONTROL)
-        {
-            regs.r_ebp = context->Ebp;
-            regs.r_esp = context->Esp;
-            regs.r_eip = context->Eip;
-            regs.r_cs = context->SegCs;
-            regs.r_ss = context->SegSs;
-            regs.r_eflags = context->EFlags;
-        }
-        if (flags & CONTEXT_SEGMENTS)
-        {
-            regs.r_ds = context->SegDs;
-            regs.r_es = context->SegEs;
-            regs.r_fs = context->SegFs;
-            regs.r_gs = context->SegGs;
-        }
-        if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
+	if (flags & CONTEXT_INTEGER)
+	{
+	    status.pr_reg[EAX] = context->Eax;
+	    status.pr_reg[EBX] = context->Ebx;
+	    status.pr_reg[ECX] = context->Ecx;
+	    status.pr_reg[EDX] = context->Edx;
+	    status.pr_reg[ESI] = context->Esi;
+	    status.pr_reg[EDI] = context->Edi;
+	}
+	if (flags & CONTEXT_CONTROL)
+	{
+	    status.pr_reg[EBP] = context->Ebp;
+	    status.pr_reg[ESP] = context->Esp;
+	    status.pr_reg[EIP] = context->Eip;
+	    status.pr_reg[CS]  = context->SegCs;
+	    status.pr_reg[SS]  = context->SegSs;
+	    status.pr_reg[EFL] = context->EFlags;
+	}
+	if (flags & CONTEXT_SEGMENTS)
+	{
+	    status.pr_reg[DS] = context->SegDs;
+	    status.pr_reg[ES] = context->SegEs;
+	    status.pr_reg[FS] = context->SegFs;
+	    status.pr_reg[GS] = context->SegGs;
+	}
+	lwpctl( thread, PCSREG, &status.pr_reg, sizeof(status.pr_reg) );
     }
     if (flags & CONTEXT_DEBUG_REGISTERS)
     {
-        /* FIXME: How is this done on FreeBSD? */
+        /* FIXME: How is this done with procfs? */
     }
     if (flags & CONTEXT_FLOATING_POINT)
     {
-        /* we can use context->FloatSave directly as it is using the */
-        /* correct structure (the same as fsave/frstor) */
-        if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
+        /* FIXME status.pr_fpreg should be used here,
+	 * but it's format is different from context->FloatSave */
+	lwpctl( thread, PCSFPREG, &status.pr_fpreg, sizeof(status.pr_reg) );
     }
     return;
  error:
     file_set_error();
 }
 
-#else  /* linux || __sun__ || __FreeBSD__ */
-#error You must implement get/set_thread_context for your platform
-#endif  /* linux || __sun__ || __FreeBSD__ */
+#endif /* HAVE__LWP_CREATE */
 
 
 /* copy a context structure according to the flags */
Index: server/context_sparc.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/context_sparc.c,v
retrieving revision 1.1
diff -u -r1.1 context_sparc.c
--- /tmp/T0mWaW4l	Fri Jul 26 09:17:42 2002
+++ context_sparc.c	Wed Jul 24 09:45:08 2002
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #ifdef HAVE_SYS_REG_H
 # include <sys/reg.h>
@@ -36,15 +37,164 @@
 #include "winbase.h"
 
 #include "thread.h"
+#include "process.h"
 #include "request.h"
 
 
-#if defined(__sun) || defined(__sun__)
+#ifdef HAVE__LWP_CREATE
+
+#undef _FILE_OFFSET_BITS
+#include <procfs.h>
+
+static BOOL get_thread_status( struct thread *thread, struct lwpstatus *status)
+{
+    char   sStatusFile[30];
+    int    fd;
+
+    sprintf( sStatusFile, "/proc/%d/lwp/%d/lwpstatus",
+	     thread->process->unix_pid, thread->unix_tid );
+    if (-1 == (fd = open( sStatusFile, O_RDONLY ))) return FALSE;
+    if (sizeof(status) != read(fd, &status, sizeof(status))) return FALSE;
+    close(fd);
+
+    return TRUE;
+}
+
 
 /* retrieve a thread context */
 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
 {
-    int pid = thread->unix_pid;
+    struct lwpstatus status;
+
+    if (!get_thread_status( thread, &status )) goto error;
+    if (flags & CONTEXT_INTEGER)
+    {
+	context->g0 = status.pr_reg[R_G0];
+	context->g1 = status.pr_reg[R_G1];
+	context->g2 = status.pr_reg[R_G2];
+	context->g3 = status.pr_reg[R_G3];
+	context->g4 = status.pr_reg[R_G4];
+	context->g5 = status.pr_reg[R_G5];
+	context->g6 = status.pr_reg[R_G6];
+	context->g7 = status.pr_reg[R_G7];
+
+	context->o0 = status.pr_reg[R_O0];
+	context->o1 = status.pr_reg[R_O1];
+	context->o2 = status.pr_reg[R_O2];
+	context->o3 = status.pr_reg[R_O3];
+	context->o4 = status.pr_reg[R_O4];
+	context->o5 = status.pr_reg[R_O5];
+	context->o6 = status.pr_reg[R_O6];
+	context->o7 = status.pr_reg[R_O7];
+
+	context->l0 = status.pr_reg[R_L0];
+	context->l1 = status.pr_reg[R_L1];
+	context->l2 = status.pr_reg[R_L2];
+	context->l3 = status.pr_reg[R_L3];
+	context->l4 = status.pr_reg[R_L4];
+	context->l5 = status.pr_reg[R_L5];
+	context->l6 = status.pr_reg[R_L6];
+	context->l7 = status.pr_reg[R_L7];
+
+	context->i0 = status.pr_reg[R_I0];
+	context->i1 = status.pr_reg[R_I1];
+	context->i2 = status.pr_reg[R_I2];
+	context->i3 = status.pr_reg[R_I3];
+	context->i4 = status.pr_reg[R_I4];
+	context->i5 = status.pr_reg[R_I5];
+	context->i6 = status.pr_reg[R_I6];
+	context->i7 = status.pr_reg[R_I7];
+    }
+    if (flags & CONTEXT_CONTROL)
+    {
+	context->psr = status.pr_reg[R_PSR];
+	context->pc  = status.pr_reg[R_PC];
+	context->npc = status.pr_reg[R_nPC];
+	context->y   = status.pr_reg[R_Y];
+	context->wim = status.pr_reg[R_WIM];
+	context->tbr = status.pr_reg[R_TBR];
+    }
+    if (flags & CONTEXT_FLOATING_POINT)
+    {
+        /* FIXME, contained in status.pr_fpreg, but not defined in context */
+    }
+    return;
+ error:
+    file_set_error();
+}
+
+
+/* set a thread context */
+static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
+{
+    struct lwpstatus status;
+
+    if (!get_thread_status(thread, &status)) goto error;
+    if (flags & CONTEXT_INTEGER)
+    {
+        status.pr_reg[R_G0] = context->g0;
+        status.pr_reg[R_G1] = context->g1;
+        status.pr_reg[R_G2] = context->g2;
+        status.pr_reg[R_G3] = context->g3;
+        status.pr_reg[R_G4] = context->g4;
+        status.pr_reg[R_G5] = context->g5;
+        status.pr_reg[R_G6] = context->g6;
+        status.pr_reg[R_G7] = context->g7;
+
+        status.pr_reg[R_O0] = context->o0;
+        status.pr_reg[R_O1] = context->o1;
+        status.pr_reg[R_O2] = context->o2;
+        status.pr_reg[R_O3] = context->o3;
+        status.pr_reg[R_O4] = context->o4;
+        status.pr_reg[R_O5] = context->o5;
+        status.pr_reg[R_O6] = context->o6;
+        status.pr_reg[R_O7] = context->o7;
+
+        status.pr_reg[R_L0] = context->l0;
+        status.pr_reg[R_L1] = context->l1;
+        status.pr_reg[R_L2] = context->l2;
+        status.pr_reg[R_L3] = context->l3;
+        status.pr_reg[R_L4] = context->l4;
+        status.pr_reg[R_L5] = context->l5;
+        status.pr_reg[R_L6] = context->l6;
+        status.pr_reg[R_L7] = context->l7;
+
+        status.pr_reg[R_I0] = context->i0;
+        status.pr_reg[R_I1] = context->i1;
+        status.pr_reg[R_I2] = context->i2;
+        status.pr_reg[R_I3] = context->i3;
+        status.pr_reg[R_I4] = context->i4;
+        status.pr_reg[R_I5] = context->i5;
+        status.pr_reg[R_I6] = context->i6;
+        status.pr_reg[R_I7] = context->i7;
+    }
+    if (flags & CONTEXT_CONTROL)
+    {
+        status.pr_reg[R_PSR] = context->psr;
+        status.pr_reg[R_PC]  = context->pc;
+        status.pr_reg[R_nPC] = context->npc;
+        status.pr_reg[R_Y]   = context->y;
+        status.pr_reg[R_WIM] = context->wim;
+        status.pr_reg[R_TBR] = context->tbr;
+    }
+    lwpctl( thread, PCSREG, &status.pr_reg, sizeof(status.pr_reg) );
+    if (flags & CONTEXT_FLOATING_POINT)
+    {
+        /* FIXME, contained in status.pr_fpreg, but not defined in context */
+	lwpctl( thread, PCSFPREG, &status.pr_fpreg, sizeof(status.pr_reg) );
+    }
+    return;
+ error:
+    file_set_error();
+}
+
+
+#else /* !HAVE__LWP_CREATE */
+
+
+static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
+{
+    int pid = thread->unix_tid;
     if (flags & CONTEXT_FULL)
     {
         struct regs regs;
@@ -97,9 +247,7 @@
     /* FIXME */
 }
 
-#else  /* __sun__ */
-#error You must implement get/set_thread_context for your platform
-#endif  /* __sun__ */
+#endif
 
 
 /* copy a context structure according to the flags */
Index: server/debugger.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/debugger.c,v
retrieving revision 1.1
diff -u -r1.1 debugger.c
--- /tmp/T0F2ai5l	Fri Jul 26 09:17:43 2002
+++ debugger.c	Wed Jul 24 09:39:25 2002
@@ -730,9 +730,9 @@
         struct thread *thread;
         for (thread = process->thread_list; thread; thread = thread->proc_next)
         {
-            if (thread->unix_pid)
+            if (thread->unix_tid)
             {
-                kill( thread->unix_pid, SIGTRAP );
+                signal_thread( thread, SIGTRAP );
                 break;
             }
         }
Index: server/process.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/process.c,v
retrieving revision 1.2
diff -u -r1.2 process.c
--- /tmp/T01.aG5l	Fri Jul 26 09:17:43 2002
+++ process.c	Wed Jul 24 10:28:11 2002
@@ -251,10 +251,10 @@
 }
 
 /* initialize the current process and fill in the request */
-static struct startup_info *init_process( int ppid, struct init_process_reply *reply )
+static struct startup_info *init_process( int unix_pid, int unix_ppid, int unix_ptid, struct init_process_reply *reply )
 {
     struct process *process = current->process;
-    struct thread *parent_thread = get_thread_from_pid( ppid );
+    struct thread *parent_thread = get_thread_from_pid( unix_ppid, unix_ptid );
     struct process *parent = NULL;
     struct startup_info *info = NULL;
 
@@ -269,6 +269,7 @@
         }
         process->parent = (struct process *)grab_object( parent );
     }
+    process->unix_pid = unix_pid;
 
     /* set the process flags */
     process->create_flags = info ? info->create_flags : 0;
@@ -568,7 +569,7 @@
         while (thread)
         {
             struct thread *next = thread->proc_next;
-            if (!thread->suspend) continue_thread( thread );
+            if (!thread->suspend) continue_thread( thread, SIGSTOP );
             thread = next;
         }
     }
@@ -869,7 +870,7 @@
 /* initialize a new process */
 DECL_HANDLER(init_process)
 {
-    if (!current->unix_pid)
+    if (!current->unix_tid)
     {
         fatal_protocol_error( current, "init_process: init_thread not called yet\n" );
         return;
@@ -881,7 +882,7 @@
     }
     reply->info_size = 0;
     current->process->ldt_copy = req->ldt_copy;
-    current->process->startup_info = init_process( req->ppid, reply );
+    current->process->startup_info = init_process( req->unix_pid, req->unix_ppid, req->unix_ptid, reply );
 }
 
 /* signal the end of the process initialization */
Index: server/process.h
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/process.h,v
retrieving revision 1.1
diff -u -r1.1 process.h
--- /tmp/T06ca45l	Fri Jul 26 09:17:44 2002
+++ process.h	Tue Jul 23 07:45:18 2002
@@ -73,6 +73,7 @@
     void                *ldt_copy;        /* pointer to LDT copy in client addr space */
     void                *ldt_flags;       /* pointer to LDT flags in client addr space */
     void                *group_id;        /* group ID of the process */
+    int                  unix_pid;        /* Unix PID of entire process (Solaris) */
 };
 
 struct process_snapshot
Index: server/ptrace.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/ptrace.c,v
retrieving revision 1.1
diff -u -r1.1 ptrace.c
--- /tmp/T0aiaq6l	Fri Jul 26 09:17:44 2002
+++ ptrace.c	Wed Jul 24 15:53:10 2002
@@ -66,6 +66,17 @@
 inline static int ptrace(int req, ...) { errno = EPERM; return -1; /*FAIL*/ }
 #endif  /* HAVE_SYS_PTRACE_H */
 
+#ifdef HAVE__LWP_CREATE
+#undef _FILE_OFFSET_BITS
+#include <procfs.h>
+
+#define PID(thread) thread->process->unix_pid
+#define PIDTID(pid) pid, 1
+#else
+#define PID(thread) thread->unix_tid
+#define PIDTID(pid) 0, pid
+#endif
+
 static const int use_ptrace = 1;  /* set to 0 to disable ptrace */
 
 /* handle a status returned by wait4 */
@@ -82,10 +93,7 @@
             if (thread && (thread->process->suspend + thread->suspend)) break;
             /* fall through */
         default:  /* ignore other signals for now */
-            if (thread && get_thread_single_step( thread ))
-                ptrace( PTRACE_SINGLESTEP, pid, (caddr_t)1, sig );
-            else
-                ptrace( PTRACE_CONT, pid, (caddr_t)1, sig );
+	    continue_thread(thread, sig);
             break;
         }
         return sig;
@@ -93,7 +101,7 @@
     if (thread && (WIFSIGNALED(status) || WIFEXITED(status)))
     {
         thread->attached = 0;
-        thread->unix_pid = 0;
+        thread->unix_tid = 0;
         if (debug_level)
         {
             if (WIFSIGNALED(status))
@@ -115,7 +123,8 @@
     for (;;)
     {
         if (!(pid = wait4( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
-        if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status );
+        if (pid != -1) handle_child_status( get_thread_from_pid( PIDTID(pid) ),
+					    pid, status );
         else break;
     }
 }
@@ -127,7 +136,7 @@
 
     do
     {
-        if ((res = wait4( thread->unix_pid, &status, WUNTRACED, NULL )) == -1)
+        if ((res = wait4( PID(thread), &status, WUNTRACED, NULL )) == -1)
         {
             perror( "wait4" );
             return;
@@ -141,9 +150,9 @@
 {
     /* this may fail if the client is already being debugged */
     if (!use_ptrace) return 0;
-    if (ptrace( PTRACE_ATTACH, thread->unix_pid, 0, 0 ) == -1)
+    if (ptrace( PTRACE_ATTACH, PID(thread), 0, 0 ) == -1)
     {
-        if (errno == ESRCH) thread->unix_pid = 0;  /* process got killed */
+        if (errno == ESRCH) thread->unix_tid = 0;  /* process got killed */
         return 0;
     }
     if (debug_level) fprintf( stderr, "%08x: *attached*\n", (unsigned int)thread );
@@ -155,21 +164,24 @@
 /* detach from a Unix thread and kill it */
 void detach_thread( struct thread *thread, int sig )
 {
-    if (!thread->unix_pid) return;
+    if (!thread->unix_tid) return;
     if (thread->attached)
     {
         /* make sure it is stopped */
         suspend_thread( thread, 0 );
-        if (sig) kill( thread->unix_pid, sig );
+        if (sig) signal_thread( thread, sig );
         if (debug_level) fprintf( stderr, "%08x: *detached*\n", (unsigned int)thread );
-        ptrace( PTRACE_DETACH, thread->unix_pid, (caddr_t)1, sig );
+        ptrace( PTRACE_DETACH, PID(thread), (caddr_t)1, sig );
         thread->suspend = 0;  /* detach makes it continue */
         thread->attached = 0;
     }
     else
     {
-        if (sig) kill( thread->unix_pid, sig );
-        if (thread->suspend + thread->process->suspend) continue_thread( thread );
+#ifndef HAVE__LWP_CREATE
+        if (sig) signal_thread( thread, sig );
+#endif
+        if (thread->suspend + thread->process->suspend)
+	    continue_thread( thread, SIGSTOP );
     }
 }
 
@@ -177,23 +189,43 @@
 void stop_thread( struct thread *thread )
 {
     /* can't stop a thread while initialisation is in progress */
-    if (!thread->unix_pid || !is_process_init_done(thread->process)) return;
+    if (!thread->unix_tid || !is_process_init_done(thread->process)) return;
+#ifdef HAVE__LWP_CREATE
+    lwpctl( thread, PCSTOP, 0, 0 );
+#else
     /* first try to attach to it */
     if (!thread->attached)
         if (attach_thread( thread )) return;  /* this will have stopped it */
     /* attached already, or attach failed -> send a signal */
-    if (!thread->unix_pid) return;
-    kill( thread->unix_pid, SIGSTOP );
+    if (!thread->unix_tid) return;
+    signal_thread( thread, SIGSTOP );
     if (thread->attached) wait4_thread( thread, SIGSTOP );
+#endif
 }
 
 /* make a thread continue (at the Unix level) */
-void continue_thread( struct thread *thread )
+void continue_thread( struct thread *thread, int sig )
 {
-    if (!thread->unix_pid) return;
-    if (!thread->attached) kill( thread->unix_pid, SIGCONT );
-    else ptrace( get_thread_single_step(thread) ? PTRACE_SINGLESTEP : PTRACE_CONT,
-                 thread->unix_pid, (caddr_t)1, SIGSTOP );
+    if (!thread || !thread->unix_tid) return;
+#ifdef HAVE__LWP_CREATE
+    {
+	int temp;
+	if (get_thread_single_step( thread ))
+	    temp = PRSTEP;
+	else
+	    temp = 0;
+	lwpctl( thread, PCRUN, &temp, sizeof(int) );
+    }
+#else
+    if (!thread->attached) signal_thread( thread, SIGCONT );
+    else
+    {
+	if (get_thread_single_step( thread ))
+	    ptrace( PTRACE_SINGLESTEP, pid, (caddr_t)1, sig );
+	else
+	    ptrace( PTRACE_CONT, pid, (caddr_t)1, sig );
+    }
+#endif
 }
 
 /* suspend a thread to allow using ptrace on it */
@@ -206,7 +238,7 @@
         return 1;
     }
     /* can't stop a thread while initialisation is in progress */
-    if (!thread->unix_pid || !is_process_init_done(thread->process)) goto error;
+    if (!thread->unix_tid || !is_process_init_done(thread->process)) goto error;
     thread->suspend++;
     if (attach_thread( thread )) return 1;
     thread->suspend--;
@@ -218,7 +250,7 @@
 /* read an int from a thread address space */
 int read_thread_int( struct thread *thread, const int *addr, int *data )
 {
-    *data = ptrace( PTRACE_PEEKDATA, thread->unix_pid, (caddr_t)addr, 0 );
+    *data = ptrace( PTRACE_PEEKDATA, PID(thread), (caddr_t)addr, 0 );
     if ( *data == -1 && errno)
     {
         file_set_error();
@@ -236,7 +268,7 @@
         if (read_thread_int( thread, addr, &res ) == -1) return -1;
         data = (data & mask) | (res & ~mask);
     }
-    if ((res = ptrace( PTRACE_POKEDATA, thread->unix_pid, (caddr_t)addr, data )) == -1)
+    if ((res = ptrace( PTRACE_POKEDATA, PID(thread), (caddr_t)addr, data )) == -1)
         file_set_error();
     return res;
 }
Index: server/thread.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/thread.c,v
retrieving revision 1.2
diff -u -r1.2 thread.c
--- /tmp/T0_paO6l	Fri Jul 26 09:17:44 2002
+++ thread.c	Wed Jul 24 09:34:11 2002
@@ -41,6 +41,8 @@
 #include "request.h"
 #include "user.h"
 
+#undef _FILE_OFFSET_BITS
+#include <procfs.h>
 
 /* thread queues */
 
@@ -103,7 +105,7 @@
 {
     int i;
 
-    thread->unix_pid        = 0;  /* not known yet */
+    thread->unix_tid        = 0;  /* not known yet */
     thread->context         = NULL;
     thread->teb             = NULL;
     thread->mutex           = NULL;
@@ -242,8 +244,9 @@
     struct thread *thread = (struct thread *)obj;
     assert( obj->ops == &thread_ops );
 
-    fprintf( stderr, "Thread pid=%d teb=%p state=%d\n",
-             thread->unix_pid, thread->teb, thread->state );
+    fprintf( stderr, "Thread tid=%d.%d teb=%p state=%d\n",
+             thread->process->unix_pid, thread->unix_tid,
+	     thread->teb, thread->state );
 }
 
 static int thread_signaled( struct object *obj, struct thread *thread )
@@ -270,10 +273,13 @@
 }
 
 /* find a thread from a Unix pid */
-struct thread *get_thread_from_pid( int pid )
+struct thread *get_thread_from_pid( int unix_pid, int unix_tid )
 {
     struct thread *t = first_thread;
-    while (t && (t->unix_pid != pid)) t = t->next;
+    while (t &&
+	   (t->unix_tid != unix_tid) &&
+	   (t->process->unix_pid != unix_pid))
+      t = t->next;
     return t;
 }
 
@@ -308,7 +314,8 @@
     int old_count = thread->suspend;
     if (thread->suspend > 0)
     {
-        if (!(--thread->suspend + thread->process->suspend)) continue_thread( thread );
+        if (!(--thread->suspend + thread->process->suspend))
+	    continue_thread( thread, SIGSTOP );
     }
     return old_count;
 }
@@ -736,6 +743,42 @@
     release_object( thread );
 }
 
+
+#ifdef HAVE__LWP_CREATE
+void lwpctl( struct thread *thread, int cmd, void *arg, int size )
+{
+    char sCtlFile[30];
+    int  fd;
+    int *msg;
+
+    sprintf( sCtlFile, "/proc/%d/lwp/%d/lwpctl",
+	     thread->process->unix_pid, thread->unix_tid );
+    fd = open( sCtlFile, O_WRONLY );
+    if( fd >= 0 )
+    {
+	msg = (int*)malloc(size + sizeof(int));
+	msg[0] = cmd;
+	memcpy(msg + 1, arg, size);
+	write( fd, msg, size + sizeof(int) );
+	close( fd );
+    }
+}
+#endif
+
+
+/* Send signal to thread.
+ * On linux, this is equivilant to kill(thread->unix_tid, signal).
+ * On Solaris, the above can't be done, so this function is needed. */
+void signal_thread( struct thread *thread, int signal)
+{
+#ifdef HAVE__LWP_CREATE
+    lwpctl( thread, PCKILL, &signal, sizeof(int) );
+#else
+    kill( thread->unix_tid, signal );
+#endif
+}
+
+
 /* take a snapshot of currently running threads */
 struct thread_snapshot *thread_snap( int *count )
 {
@@ -805,7 +848,7 @@
     int reply_fd = thread_get_inflight_fd( current, req->reply_fd );
     int wait_fd = thread_get_inflight_fd( current, req->wait_fd );
 
-    if (current->unix_pid)
+    if (current->unix_tid)
     {
         fatal_protocol_error( current, "init_thread: already running\n" );
         goto error;
@@ -821,7 +864,7 @@
         goto error;
     }
 
-    current->unix_pid = req->unix_pid;
+    current->unix_tid = req->unix_tid;
     current->teb      = req->teb;
     current->reply_fd = reply_fd;
     current->wait_fd  = wait_fd;
Index: server/thread.h
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/thread.h,v
retrieving revision 1.1
diff -u -r1.1 thread.h
--- /tmp/T0puaa7l	Fri Jul 26 09:17:45 2002
+++ thread.h	Wed Jul 24 09:32:51 2002
@@ -84,7 +84,7 @@
     enum run_state         state;         /* running state */
     int                    attached;      /* is thread attached with ptrace? */
     int                    exit_code;     /* thread exit code */
-    int                    unix_pid;      /* Unix pid of client */
+    int                    unix_tid;      /* Unix tid of client */
     CONTEXT               *context;       /* current context if in an exception handler */
     void                  *teb;           /* TEB address (in client address space) */
     int                    priority;      /* priority level */
@@ -106,12 +106,16 @@
 extern struct thread *create_thread( int fd, struct process *process );
 extern struct thread *get_thread_from_id( void *id );
 extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access );
-extern struct thread *get_thread_from_pid( int pid );
+extern struct thread *get_thread_from_pid( int unix_pid, int unix_tid );
 extern int suspend_thread( struct thread *thread, int check_limit );
 extern int resume_thread( struct thread *thread );
 extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
 extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
 extern void kill_thread( struct thread *thread, int violent_death );
+#ifdef HAVE__LWP_CREATE
+extern void lwpctl( struct thread *thread, int cmd, void *arg, int size );
+#endif
+extern void signal_thread( struct thread *thread, int signal);
 extern void wake_up( struct object *obj, int max );
 extern int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
                              enum apc_type type, int system, int nb_args, ... );
@@ -125,7 +129,7 @@
 extern void sigchld_handler();
 extern void wait4_thread( struct thread *thread, int signal );
 extern void stop_thread( struct thread *thread );
-extern void continue_thread( struct thread *thread );
+extern void continue_thread( struct thread *thread, int sig );
 extern void detach_thread( struct thread *thread, int sig );
 extern int suspend_for_ptrace( struct thread *thread );
 extern int read_thread_int( struct thread *thread, const int *addr, int *data );
Index: server/trace.c
===================================================================
RCS file: /opcom/comp/ws/wine/CVSROOT/wine/server/trace.c,v
retrieving revision 1.1
diff -u -r1.1 trace.c
--- /tmp/T0wAay7l	Fri Jul 26 09:17:45 2002
+++ trace.c	Wed Jul 24 09:38:08 2002
@@ -400,7 +400,8 @@
 static void dump_init_process_request( const struct init_process_request *req )
 {
     fprintf( stderr, " ldt_copy=%p,", req->ldt_copy );
-    fprintf( stderr, " ppid=%d", req->ppid );
+    fprintf( stderr, " unix_ppid=%d", req->unix_ppid );
+    fprintf( stderr, " unix_ptid=%d", req->unix_ptid );
 }
 
 static void dump_init_process_reply( const struct init_process_reply *req )
@@ -443,7 +444,7 @@
 
 static void dump_init_thread_request( const struct init_thread_request *req )
 {
-    fprintf( stderr, " unix_pid=%d,", req->unix_pid );
+    fprintf( stderr, " unix_tid=%d,", req->unix_tid );
     fprintf( stderr, " teb=%p,", req->teb );
     fprintf( stderr, " entry=%p,", req->entry );
     fprintf( stderr, " reply_fd=%d,", req->reply_fd );


More information about the wine-patches mailing list