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@opcom-mail.canada.sun.com> Subject: Threading on Solaris To: wine-patches@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 -------------
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) ®s ) == -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) ®s ) == -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) ®s ) == -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) ®s ) == -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 );