Support remote operations in wineserver

Alexander Yaworsky yaworsky at migusoft.ru
Thu Sep 23 05:31:26 CDT 2004


Hello

> Well, I'm not going to commit that part since it doesn't actually do
> anything with the remote operation, and it's not clear at all that the
> requests you added will be appropriate to whatever mechanism we use to
> do the remote operation.

Ok, here is a draft working implementation of NtAllocateVirtualMemory.
There are four mechanisms at all: signals, ptrace, service thread and wait. This
implementation uses so-called wait approach: request is passed via wait_fd.
The drawback is that request may not always be handled but most sane
applications sooner or later fall into wait state. Also i'm going to try other
mechanisms but their implementations seem will be very similar.

I hope that people will give suggestions.
-------------- next part --------------
Index: dlls/ntdll/ntdll_misc.h
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/ntdll_misc.h,v
retrieving revision 1.49
diff -u -r1.49 ntdll_misc.h
--- dlls/ntdll/ntdll_misc.h	21 Sep 2004 00:23:50 -0000	1.49
+++ dlls/ntdll/ntdll_misc.h	23 Sep 2004 09:22:44 -0000
@@ -95,6 +95,8 @@
 
 extern BOOL is_current_process( HANDLE handle );
 
+extern void remote_op_handler(void);
+
 /* code pages */
 extern int ntdll_umbstowcs(DWORD flags, const char* src, int srclen, WCHAR* dst, int dstlen);
 extern int ntdll_wcstoumbs(DWORD flags, const WCHAR* src, int srclen, char* dst, int dstlen,
Index: dlls/ntdll/sync.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/sync.c,v
retrieving revision 1.35
diff -u -r1.35 sync.c
--- dlls/ntdll/sync.c	1 Apr 2004 21:01:53 -0000	1.35
+++ dlls/ntdll/sync.c	23 Sep 2004 09:22:46 -0000
@@ -480,6 +480,15 @@
         if (ret == sizeof(reply))
         {
             if (!reply.cookie) break;  /* thread got killed */
+#define REMOTE_OPERATION_APPROACH_WAIT
+#ifdef REMOTE_OPERATION_APPROACH_WAIT
+            if (reply.cookie == (void*) 1 )
+            {
+                TRACE("CATCH\n");
+                remote_op_handler();
+                continue;
+            }
+#endif
             if (reply.cookie == cookie) return reply.signaled;
             /* we stole another reply, wait for the real one */
             signaled = wait_reply( cookie );
@@ -627,6 +636,10 @@
         if (alertable) flags |= SELECT_ALERTABLE;
         return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
     }
+
+#ifdef REMOTE_OPERATION_APPROACH_WAIT
+    return NTDLL_wait_for_multiple_objects( 0, NULL, 0, timeout );
+#endif
 
     if (!timeout)  /* sleep forever */
     {
Index: dlls/ntdll/virtual.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/virtual.c,v
retrieving revision 1.40
diff -u -r1.40 virtual.c
--- dlls/ntdll/virtual.c	22 Sep 2004 04:03:10 -0000	1.40
+++ dlls/ntdll/virtual.c	23 Sep 2004 09:22:53 -0000
@@ -140,6 +140,220 @@
 static void *user_space_limit = USER_SPACE_LIMIT;
 
 
+#define REMOTE_OPERATION_ALLOWED 0
+#define SUSPEND_REMOTE_OPERATION 1
+#define PENDING_REMOTE_OPERATION 2
+
+/***********************************************************************
+ *           execute_remote_operation
+ *
+ */
+static void execute_remote_operation()
+{
+    TEB *teb = NtCurrentTeb();
+    NTSTATUS status;
+    void *result_buf = NULL;
+    DWORD size;
+
+    switch( teb->remote_op_code )
+    {
+        case REMOTE_OP_NEW_THREAD:
+            status = STATUS_NOT_IMPLEMENTED;
+            break;
+        case REMOTE_OP_VM_ALLOC:
+        {
+            struct remote_op_params_vm_alloc *params = teb->remote_op_params;
+            struct remote_op_result_vm_alloc *result;
+
+            size = sizeof(struct remote_op_result_vm_alloc);
+            result_buf = RtlAllocateHeap( GetProcessHeap(), 0, size );
+            if( NULL == result_buf )
+            {
+                ERR("cannot allocate memory\n");
+                break;
+            }
+            result = result_buf;
+            status = NtAllocateVirtualMemory( GetCurrentProcess(), &result->base, params->addr,
+                                              &params->size, params->type, params->protect );
+            TRACE("status=%08X\n",status);
+            result->size = params->size;
+            break;
+        }
+        case REMOTE_OP_VM_FREE:
+        case REMOTE_OP_VM_PROTECT:
+        case REMOTE_OP_VM_QUERY:
+        case REMOTE_OP_VM_MAP:
+        case REMOTE_OP_VM_UNMAP:
+        case REMOTE_OP_VM_FLUSH:
+            status = STATUS_NOT_IMPLEMENTED;
+            break;
+        default:
+            ERR("invalid operation code %d\n", teb->remote_op_code);
+            status = STATUS_INVALID_PARAMETER; /* ??? */
+            break;
+    }
+
+    TRACE("sending remote_operation_complete\n");
+    SERVER_START_REQ( remote_operation_complete )
+    {
+        req->originator = teb->remote_op_originator;
+        req->status     = status;
+        if (result_buf) wine_server_add_data( req, result_buf, size );
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+
+    TRACE("done\n");
+    if( result_buf ) RtlFreeHeap( GetProcessHeap(), 0, result_buf );
+    RtlFreeHeap( GetProcessHeap(), 0, teb->remote_op_params );
+    teb->remote_op_params = NULL;
+}
+
+
+/***********************************************************************
+ * Workaround for remote operations.
+ * Thread may be interrupted inside critical section so deadlock
+ * will occur because of nested RtlEnterCriticalSection.
+ */
+
+/***********************************************************************
+ *           enter_critical_section
+ *
+ * Indicate that remote operation for this thread must be suspended
+ * and enter csVirtual critical section.
+ */
+static void enter_critical_section(void)
+{
+    NtCurrentTeb()->remote_op_flag = SUSPEND_REMOTE_OPERATION;
+    RtlEnterCriticalSection(&csVirtual);
+}
+
+
+/***********************************************************************
+ *           leave_critical_section
+ *
+ * Leave csVirtual critical section and check remote operation flag
+ * in TEB. Also set this flag to allow immediate execution of
+ * remote operation.
+ * If there is a pending operation at this point, execute it.
+ */
+static void leave_critical_section(void)
+{
+    RtlLeaveCriticalSection(&csVirtual);
+    if (interlocked_xchg( &NtCurrentTeb()->remote_op_flag,
+                          REMOTE_OPERATION_ALLOWED ) == PENDING_REMOTE_OPERATION)
+        execute_remote_operation();
+}
+
+
+/***********************************************************************
+ *           remote_op_handler
+ *
+ */
+void remote_op_handler(void)
+{
+    TEB *teb = NtCurrentTeb();
+    struct remote_op_request request;
+
+    /* sanity check*/
+    if( PENDING_REMOTE_OPERATION == teb->remote_op_flag )
+        ERR("nested remote operations");
+    if( teb->remote_op_params )
+        ERR("params not null");
+
+    /* get request & params */
+#define REMOTE_OPERATION_APPROACH_WAIT
+#ifdef REMOTE_OPERATION_APPROACH_WAIT
+    for (;;)
+    {
+        int ret;
+        TRACE("reading request\n");
+        ret = read( teb->wait_fd[0], &request, sizeof(struct remote_op_request) );
+        if (ret == sizeof(struct remote_op_request))
+            break;
+        if (ret >= 0) server_protocol_error( "partial remote operation opcode read %d\n", ret );
+        if (errno == EINTR) continue;
+        server_protocol_perror("remote operation opcode read");
+    }
+    TRACE("params size=%d\n", request.params_size);
+    teb->remote_op_params = RtlAllocateHeap( GetProcessHeap(), 0, request.params_size );
+    if( NULL == teb->remote_op_params )
+        return;
+    for (;;)
+    {
+        int ret;
+        ret = read( teb->wait_fd[0], teb->remote_op_params, request.params_size );
+        if (ret == request.params_size)
+            break;
+        if (ret >= 0) server_protocol_error( "partial remote operation request read %d\n", ret );
+        if (errno == EINTR) continue;
+        server_protocol_perror("remote operation request read");
+    }
+    teb->remote_op_originator = request.originator;
+    teb->remote_op_code = request.op_code;
+#endif
+
+    /* Check remote_operation_flag in TEB and either execute operation
+     * immediately or suspend. */
+    if (SUSPEND_REMOTE_OPERATION == teb->remote_op_flag)
+        teb->remote_op_flag = PENDING_REMOTE_OPERATION;
+    else
+        execute_remote_operation();
+}
+
+
+/***********************************************************************
+ *           remote_op
+ *
+ * helper function
+ */
+NTSTATUS remote_op( HANDLE process, int opcode,
+                    void* params, int params_size, void* result, int* result_size )
+{
+    HANDLE event;
+    NTSTATUS status, remote_status;
+
+    /* send params */
+    SERVER_START_REQ( remote_operation )
+    {
+        req->handle = process;
+        req->code   = opcode;
+        if (params) wine_server_add_data( req, params, params_size );
+        if (!(status = wine_server_call( req )))
+            event = reply->event;
+    }
+    SERVER_END_REQ;
+    if (status)
+        return status;
+
+    /* wait for completion */
+    TRACE("waiting for completion on %p\n", event);
+    status = NtWaitForMultipleObjects( 1, &event, FALSE, FALSE, NULL );
+    NtClose( event );
+    /* FIXME: check abandoned status */
+    if (HIWORD(status))
+        return status;
+
+    /* get result */
+    TRACE("getting result\n");
+    remote_status = 0; /* make compiler happy */
+    SERVER_START_REQ( remote_operation_result )
+    {
+        wine_server_set_reply( req, result, *result_size );
+        if (!(status = wine_server_call( req )))
+        {
+            remote_status = reply->status;
+            if (result)
+                *result_size = wine_server_reply_size( reply );
+            TRACE("result_size=%d\n", *result_size );
+        }
+    }
+    SERVER_END_REQ;
+
+    return status? status : remote_status;
+}
+
+
 /***********************************************************************
  *           VIRTUAL_GetProtStr
  */
@@ -198,7 +412,7 @@
     struct list *ptr;
 
     DPRINTF( "\nDump of all virtual memory views:\n\n" );
-    RtlEnterCriticalSection(&csVirtual);
+    enter_critical_section();
     LIST_FOR_EACH( ptr, &views_list )
     {
         VIRTUAL_DumpView( LIST_ENTRY( ptr, struct file_view, entry ) );
@@ -832,7 +1046,7 @@
 
     /* zero-map the whole range */
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
 
     if (base >= (char *)0x110000)  /* make sure the DOS area remains free */
         status = map_view( &view, base, total_size,
@@ -1011,14 +1225,14 @@
         if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC;
         VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot );
     }
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
 
     *addr_ptr = ptr;
     return STATUS_SUCCESS;
 
  error:
     if (view) delete_view( view );
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
     return status;
 }
 
@@ -1068,14 +1282,14 @@
     FILE_VIEW *view;
     BOOL ret = FALSE;
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
     if ((view = VIRTUAL_FindView( addr )))
     {
         view->handlerProc = proc;
         view->handlerArg  = arg;
         ret = TRUE;
     }
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
     return ret;
 }
 
@@ -1087,14 +1301,14 @@
     FILE_VIEW *view;
     DWORD ret = EXCEPTION_ACCESS_VIOLATION;
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
     if ((view = VIRTUAL_FindView( addr )))
     {
         if (view->handlerProc)
         {
             HANDLERPROC proc = view->handlerProc;
             void *arg = view->handlerArg;
-            RtlLeaveCriticalSection( &csVirtual );
+            leave_critical_section();
             if (proc( arg, addr )) ret = 0;  /* handled */
             return ret;
         }
@@ -1113,7 +1327,7 @@
                 ret = STATUS_STACK_OVERFLOW;
         }
     }
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
     return ret;
 }
 
@@ -1127,9 +1341,9 @@
     FILE_VIEW *view;
     BOOL ret = FALSE;
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
     if ((view = VIRTUAL_FindView( addr ))) ret = (view->mapping != 0);
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
     return ret;
 }
 
@@ -1142,10 +1356,10 @@
 void VIRTUAL_UseLargeAddressSpace(void)
 {
     if (user_space_limit >= ADDRESS_SPACE_LIMIT) return;
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
     remove_reserved_area( user_space_limit, (char *)ADDRESS_SPACE_LIMIT - (char *)user_space_limit );
     user_space_limit = ADDRESS_SPACE_LIMIT;
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
 }
 
 
@@ -1168,8 +1382,23 @@
 
     if (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        struct remote_op_params_vm_alloc alloc_params;
+        struct remote_op_result_vm_alloc alloc_result;
+        int result_size = sizeof(struct remote_op_result_vm_alloc);
+
+        alloc_params.addr    = addr;
+        alloc_params.size    = size;
+        alloc_params.type    = type;
+        alloc_params.protect = protect;
+        status = remote_op( process, REMOTE_OP_VM_ALLOC,
+                            &alloc_params, sizeof(alloc_params),
+                            &alloc_result, &result_size );
+        if (!status)
+        {
+            *ret = alloc_result.base;
+            *size_ptr = alloc_result.size;
+        }
+        return status;
     }
 
     /* Round parameters to a page boundary */
@@ -1217,7 +1446,7 @@
 
     /* Reserve the memory */
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
 
     if (type & MEM_SYSTEM)
     {
@@ -1245,7 +1474,7 @@
         else if (!VIRTUAL_SetProt( view, base, size, vprot )) status = STATUS_ACCESS_DENIED;
     }
 
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
 
     if (status == STATUS_SUCCESS)
     {
@@ -1281,7 +1510,7 @@
     size = ROUND_SIZE( addr, size );
     base = ROUND_ADDR( addr, page_mask );
 
-    RtlEnterCriticalSection(&csVirtual);
+    enter_critical_section();
 
     if (!(view = VIRTUAL_FindView( base )) ||
         (base + size > (char *)view->base + view->size) ||
@@ -1324,7 +1553,7 @@
         status = STATUS_INVALID_PARAMETER;
     }
 
-    RtlLeaveCriticalSection(&csVirtual);
+    leave_critical_section();
     return status;
 }
 
@@ -1357,7 +1586,7 @@
     size = ROUND_SIZE( addr, size );
     base = ROUND_ADDR( addr, page_mask );
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
 
     if (!(view = VIRTUAL_FindView( base )) || (base + size > (char *)view->base + view->size))
     {
@@ -1384,7 +1613,7 @@
             if (!VIRTUAL_SetProt( view, base, size, vprot )) status = STATUS_ACCESS_DENIED;
         }
     }
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
 
     if (status == STATUS_SUCCESS)
     {
@@ -1423,7 +1652,7 @@
 
     /* Find the view containing the address */
 
-    RtlEnterCriticalSection(&csVirtual);
+    enter_critical_section();
     ptr = list_head( &views_list );
     for (;;)
     {
@@ -1435,7 +1664,7 @@
             {
                 if (user_space_limit && base >= (char *)user_space_limit)
                 {
-                    RtlLeaveCriticalSection( &csVirtual );
+                    leave_critical_section();
                     return STATUS_WORKING_SET_LIMIT_RANGE;
                 }
                 size = (char *)user_space_limit - alloc_base;
@@ -1481,7 +1710,7 @@
         else if (view->flags & VFLAG_VALLOC) info->Type = MEM_PRIVATE;
         else info->Type = MEM_MAPPED;
     }
-    RtlLeaveCriticalSection(&csVirtual);
+    leave_critical_section();
 
     info->BaseAddress    = (LPVOID)base;
     info->AllocationBase = (LPVOID)alloc_base;
@@ -1714,12 +1943,12 @@
 
     /* Reserve a properly aligned area */
 
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
 
     res = map_view( &view, *addr_ptr, size, prot );
     if (res)
     {
-        RtlLeaveCriticalSection( &csVirtual );
+        leave_critical_section();
         goto done;
     }
 
@@ -1746,7 +1975,7 @@
         delete_view( view );
     }
 
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
 
 done:
     wine_server_release_fd( handle, unix_handle );
@@ -1769,13 +1998,13 @@
         ERR("Unsupported on other process\n");
         return STATUS_ACCESS_DENIED;
     }
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
     if ((view = VIRTUAL_FindView( base )) && (base == view->base))
     {
         delete_view( view );
         status = STATUS_SUCCESS;
     }
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
     return status;
 }
 
@@ -1796,7 +2025,7 @@
         ERR("Unsupported on other process\n");
         return STATUS_ACCESS_DENIED;
     }
-    RtlEnterCriticalSection( &csVirtual );
+    enter_critical_section();
     if (!(view = VIRTUAL_FindView( addr ))) status = STATUS_INVALID_PARAMETER;
     else
     {
@@ -1804,7 +2033,7 @@
         *addr_ptr = addr;
         if (msync( addr, *size_ptr, MS_SYNC )) status = STATUS_NOT_MAPPED_DATA;
     }
-    RtlLeaveCriticalSection( &csVirtual );
+    leave_critical_section();
     return status;
 }
 
Index: include/thread.h
===================================================================
RCS file: /home/wine/wine/include/thread.h,v
retrieving revision 1.96
diff -u -r1.96 thread.h
--- include/thread.h	10 May 2004 19:58:48 -0000	1.96
+++ include/thread.h	23 Sep 2004 09:23:00 -0000
@@ -117,10 +117,14 @@
     DWORD        dpmi_vif;       /* --3 22c Protected mode virtual interrupt flag */
     DWORD        vm86_pending;   /* --3 230 Data for vm86 mode */
     void        *vm86_ptr;       /* --3 234 Data for vm86 mode */
+    void        *remote_op_params;       /* --3 238  */
+    DWORD        remote_op_originator;   /* --3 23C thread id */
+    int          remote_op_code;         /* --3 240  */
+    LONG         remote_op_flag;         /* --3 244  */
     /* here is plenty space for wine specific fields (don't forget to change pad6!!) */
 
     /* the following are nt specific fields */
-    DWORD        pad6[624];                  /* --n 238 */
+    DWORD        pad6[620];                  /* --n 248 */
     UNICODE_STRING StaticUnicodeString;      /* -2- bf8 used by advapi32 */
     WCHAR        StaticUnicodeBuffer[261];   /* -2- c00 used by advapi32 */
     PVOID        DeallocationStack;          /* -2- e0c Base of the stack */
Index: server/process.c
===================================================================
RCS file: /home/wine/wine/server/process.c,v
retrieving revision 1.117
diff -u -r1.117 process.c
--- server/process.c	14 Jun 2004 17:02:00 -0000	1.117
+++ server/process.c	23 Sep 2004 09:23:12 -0000
@@ -22,6 +22,7 @@
 #include "wine/port.h"
 
 #include <assert.h>
+#include <errno.h>
 #include <limits.h>
 #include <signal.h>
 #include <string.h>
@@ -1188,5 +1189,183 @@
             reply->event = alloc_handle( current->process, process->idle_event,
                                          EVENT_ALL_ACCESS, 0 );
         release_object( process );
+    }
+}
+
+/* Accept parameters for remote operation and start it */
+DECL_HANDLER(remote_operation)
+{
+    int access, ret;
+    struct process *process;
+    struct event *event;
+    struct thread *thread;
+    struct remote_op_request request;
+
+    /* define required access rights */
+    switch( req->code )
+    {
+        case REMOTE_OP_NEW_THREAD:
+            access = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION
+                     | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE;
+            break;
+        case REMOTE_OP_VM_ALLOC:   access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_FREE:    access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_PROTECT: access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_QUERY:   access = PROCESS_QUERY_INFORMATION; break;
+        case REMOTE_OP_VM_MAP:     access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_UNMAP:   access = PROCESS_VM_OPERATION; break;
+        case REMOTE_OP_VM_FLUSH:   access = PROCESS_VM_OPERATION; break; /* FIXME: is access right? */
+        default:
+            set_error( STATUS_INVALID_PARAMETER );
+            return;
+    }
+
+    /* get process object */
+    if (!(process = get_process_from_handle( req->handle, access ))) return;
+
+    /* dispose result data buffer if allocated */
+    if (current->result_data)
+    {
+        free( current->result_data );
+        current->result_data = NULL;
+    }
+
+    /* create event object */
+    reply->event = NULL;
+    if (current->result_event)
+    {
+        release_object( current->result_event );
+        current->result_event = NULL;
+    }
+    if (!(event = create_event( NULL, 0, 1, 0 )))
+        goto error;
+
+    if (!(reply->event = alloc_handle( current->process, event, EVENT_ALL_ACCESS, FALSE )))
+        goto error;
+
+#define REMOTE_OPERATION_APPROACH_WAIT
+#ifdef REMOTE_OPERATION_APPROACH_WAIT
+
+    /* find waithing thread */
+    thread = process->thread_list;
+    if (!thread)
+    {
+        fprintf( stderr, "no threads\n" );
+        /* FIXME: is status correct? */
+        set_error( STATUS_ACCESS_DENIED );
+        goto error;
+    }
+    while (!thread->wait)
+    {
+        fprintf( stderr, "thread %08X not waiting\n", thread->id );
+        thread = thread->proc_next;
+        if (!thread)
+        {
+            fprintf( stderr, "no waiting threads\n" );
+            set_error( STATUS_ACCESS_DENIED );
+            goto error;
+        }
+    }
+    fprintf( stderr, "found waiting thread %08X\n", thread->id );
+
+    /* wakeup thread with magic cookie */
+    if (send_thread_wakeup( thread, (void*) 1, 0 ) == -1)
+        goto error;
+
+    /* send request */
+    request.op_code = req->code;
+    request.originator = current->id;
+    request.params_size = get_req_data_size();
+    fprintf(stderr,"opcode=%d, originator=%d, params size=%d\n",req->code,thread->id,request.params_size);
+    ret = write( get_unix_fd( thread->wait_fd ), &request, sizeof(request) );
+    if(ret != sizeof(request))
+    {
+        if (ret >= 0)
+            fatal_protocol_error( thread, "partial request write %d\n", ret );
+        else if (errno == EPIPE)
+            kill_thread( thread, 0 );  /* normal death */
+        else
+            fatal_protocol_perror( thread, "write" );
+    }
+    /* send params */
+    ret = write( get_unix_fd( thread->wait_fd ), get_req_data(), request.params_size );
+    if(ret != request.params_size)
+    {
+        if (ret >= 0)
+            fatal_protocol_error( thread, "partial request write %d\n", ret );
+        else if (errno == EPIPE)
+            kill_thread( thread, 0 );  /* normal death */
+        else
+            fatal_protocol_perror( thread, "write" );
+    }
+
+#else
+    /* FIXME: pass somehow operation code, params and originator thread id
+       for some thread in the process and force execution of operation */
+    set_error( STATUS_NOT_IMPLEMENTED );
+    close_handle( current->process, reply->event, NULL );
+#endif
+
+    /* save event object in thread structure for future set operation;
+       we do not release it here */
+    current->result_event = event;
+    fprintf( stderr, "thread %p, id=%d, event=%p\n", current, current->id, event );
+    release_object( process );
+    return;
+
+error:
+    if (reply->event) close_handle( current->process, reply->event, NULL );
+    if (event) release_object( event );
+    release_object( process );
+}
+
+/* save result of remote operation and wakeup originator */
+DECL_HANDLER(remote_operation_complete)
+{
+    struct thread *thread = get_thread_from_id( req->originator );
+
+    fprintf(stderr,"remote_operation_complete: originator=%d, thread=%p, id=%d\n",req->originator, thread, thread->id);
+    if (!thread) return;
+
+    /* save status */
+    thread->remote_status = req->status;
+    fprintf(stderr,"remote_operation_complete: status=%08X\n",req->status);
+
+    /* allocate buffer for result data, if required */
+    if (thread->result_data)
+    {
+        free( thread->result_data );
+        thread->result_data = NULL;
+    }
+    if ((thread->result_size = get_req_data_size()))
+    {
+        if ((thread->result_data = mem_alloc( thread->result_size )))
+            memcpy( thread->result_data, get_req_data(), thread->result_size );
+        else
+            thread->remote_status = get_error();
+    }
+
+    /* set event */
+    fprintf(stderr,"setting event %p\n", thread->result_event);
+    if (thread->result_event)
+    {
+        set_event( thread->result_event );
+        release_object( thread->result_event );
+        thread->result_event = NULL;
+    }
+    release_object( thread );
+}
+
+/* return status and result data from remote opertaion */
+DECL_HANDLER(remote_operation_result)
+{
+    reply->status = current->remote_status;
+    fprintf(stderr,"remote_operation_result: status=%08X\n",reply->status);
+
+    if (current->result_data)
+    {
+        void *result = current->result_data;
+        current->result_data = NULL;
+        set_reply_data_ptr( result, current->result_size );
     }
 }
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.110
diff -u -r1.110 protocol.def
--- server/protocol.def	18 Aug 2004 00:04:58 -0000	1.110
+++ server/protocol.def	23 Sep 2004 09:23:18 -0000
@@ -2166,3 +2166,134 @@
 #define SET_GLOBAL_SHELL_WINDOWS   0x01  /* set both main shell and listview windows */
 #define SET_GLOBAL_PROGMAN_WINDOW  0x02
 #define SET_GLOBAL_TASKMAN_WINDOW  0x04
+
+/* Accept parameters for remote operation and start it */
+ at REQ(remote_operation)
+    obj_handle_t handle;       /* process handle */
+    int          code;         /* operation code (see below) */
+    VARARG(data,bytes);        /* operation parameters (see below) */
+ at REPLY
+    obj_handle_t event;        /* originator waits on it */
+ at END
+enum remote_op_code
+{
+    REMOTE_OP_NEW_THREAD,
+    REMOTE_OP_VM_ALLOC,
+    REMOTE_OP_VM_FREE,
+    REMOTE_OP_VM_PROTECT,
+    REMOTE_OP_VM_QUERY,
+    REMOTE_OP_VM_MAP,
+    REMOTE_OP_VM_UNMAP,
+    REMOTE_OP_VM_FLUSH
+};
+
+/* Notify that remote operation has been complete */
+ at REQ(remote_operation_complete)
+    thread_id_t  originator;   /* originator thread id */
+    unsigned int status;       /* operation status */
+    VARARG(data,bytes);        /* operation result data (see below) */
+ at END
+
+/* Get result of remote opertaion */
+ at REQ(remote_operation_result)
+ at REPLY
+    unsigned int status;       /* operation status */
+    VARARG(data,bytes);        /* operation result data (see below) */
+ at END
+
+struct remote_op_params_new_thread
+{
+    int           suspend;
+    void         *stack_addr;
+    unsigned int  stack_reserve;
+    unsigned int  stack_commit;
+    void         *start;
+    void         *param;
+};
+struct remote_op_result_new_thread
+{
+    obj_handle_t  handle;
+    thread_id_t   tid;
+};
+
+struct remote_op_params_vm_alloc
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  type;
+    unsigned long  protect;
+};
+struct remote_op_result_vm_alloc
+{
+    void          *base;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_free
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  type;
+};
+struct remote_op_result_vm_free
+{
+    void          *base;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_protect
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  new_prot;
+};
+struct remote_op_result_vm_protect
+{
+    void          *base;
+    unsigned long  size;
+    unsigned long  old_prot;
+};
+
+struct remote_op_params_vm_query
+{
+    void  *addr;
+    int    info_class;
+};
+
+struct remote_op_params_vm_map
+{
+    void          *addr;
+    unsigned long  zero_bits;
+    unsigned long  commit_size;
+    unsigned long  offset_low;
+    long           offset_high;
+    unsigned long  size;
+    int            inherit;
+    unsigned long  alloc_type;
+    unsigned long  protect;
+};
+struct remote_op_result_vm_map
+{
+    void          *base;
+    unsigned long  size;
+};
+
+struct remote_op_params_vm_flush
+{
+    void          *addr;
+    unsigned long  size;
+    unsigned long  unknown;
+};
+struct remote_op_result_vm_flush
+{
+    void          *base;
+    unsigned long  size;
+};
+
+/* structure for marshalling remote operation requests */
+struct remote_op_request
+{
+    enum remote_op_code op_code;
+    thread_id_t         originator;
+    int                 params_size;
+};
Index: server/thread.c
===================================================================
RCS file: /home/wine/wine/server/thread.c,v
retrieving revision 1.103
diff -u -r1.103 thread.c
--- server/thread.c	27 Oct 2003 22:10:22 -0000	1.103
+++ server/thread.c	23 Sep 2004 09:23:23 -0000
@@ -142,6 +142,8 @@
     thread->suspend         = 0;
     thread->creation_time   = time(NULL);
     thread->exit_time       = 0;
+    thread->result_data     = NULL;
+    thread->result_event    = NULL;
 
     for (i = 0; i < MAX_INFLIGHT_FDS; i++)
         thread->inflight[i].server = thread->inflight[i].client = -1;
@@ -210,6 +212,8 @@
     if (thread->request_fd) release_object( thread->request_fd );
     if (thread->reply_fd) release_object( thread->reply_fd );
     if (thread->wait_fd) release_object( thread->wait_fd );
+    if (thread->result_data) free( thread->result_data );
+    if (thread->result_event) release_object( thread->result_event );
     free_msg_queue( thread );
     cleanup_clipboard_thread(thread);
     destroy_thread_windows( thread );
@@ -226,6 +230,8 @@
     thread->request_fd = NULL;
     thread->reply_fd = NULL;
     thread->wait_fd = NULL;
+    thread->result_data = NULL;
+    thread->result_event = NULL;
 
     if (thread == booting_thread)  /* killing booting thread */
     {
@@ -462,7 +468,12 @@
 }
 
 /* send the wakeup signal to a thread */
+#define REMOTE_OPERATION_APPROACH_WAIT
+#ifdef REMOTE_OPERATION_APPROACH_WAIT
+int send_thread_wakeup( struct thread *thread, void *cookie, int signaled )
+#else
 static int send_thread_wakeup( struct thread *thread, void *cookie, int signaled )
+#endif
 {
     struct wake_up_reply reply;
     int ret;
Index: server/thread.h
===================================================================
RCS file: /home/wine/wine/server/thread.h,v
retrieving revision 1.56
diff -u -r1.56 thread.h
--- server/thread.h	10 Dec 2003 01:12:18 -0000	1.56
+++ server/thread.h	23 Sep 2004 09:23:24 -0000
@@ -94,6 +94,10 @@
     time_t                 creation_time; /* Thread creation time */
     time_t                 exit_time;     /* Thread exit time */
     struct token          *token;         /* security token associated with this thread */
+    unsigned int           remote_status; /* error code from remote operation */
+    void                  *result_data;   /* result data from remote operation */
+    int                    result_size;   /* size of result data */
+    struct event          *result_event;  /* originator of remote operation waits on it */
 };
 
 struct thread_snapshot
@@ -112,6 +116,10 @@
 extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access );
 extern struct thread *get_thread_from_pid( int pid );
 extern void stop_thread( struct thread *thread );
+#define REMOTE_OPERATION_APPROACH_WAIT
+#ifdef REMOTE_OPERATION_APPROACH_WAIT
+extern int send_thread_wakeup( struct thread *thread, void *cookie, int signaled );
+#endif
 extern int wake_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 );
-------------- next part --------------
A non-text attachment was scrubbed...
Name: remotetest.c
Type: application/octet-stream
Size: 1017 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20040923/39b981ce/remotetest.obj


More information about the wine-devel mailing list