rpcrt4: Create a server thread for each protseq.

Robert Shearman rob at codeweavers.com
Mon Oct 16 10:47:22 CDT 2006


---
  dlls/rpcrt4/rpc_server.c |  173 
++++++++++++++++++++++++++--------------------
  dlls/rpcrt4/rpc_server.h |    9 ++
  2 files changed, 105 insertions(+), 77 deletions(-)
-------------- next part --------------
diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c
index a57617c..818ee3a 100644
--- a/dlls/rpcrt4/rpc_server.c
+++ b/dlls/rpcrt4/rpc_server.c
@@ -93,12 +93,6 @@ static BOOL std_listen;
 static LONG manual_listen_count;
 /* total listeners including auto listeners */
 static LONG listen_count;
-/* set on change of configuration (e.g. listening on new protseq) */
-static HANDLE mgr_event;
-/* mutex for ensuring only one thread can change state at a time */
-static HANDLE mgr_mutex;
-/* set when server thread has finished opening connections */
-static HANDLE server_ready_event;
 
 static UUID uuid_nil;
 
@@ -355,30 +349,28 @@ static void RPCRT4_new_client(RpcConnect
 
 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
 {
-  HANDLE m_event = mgr_event, b_handle;
+  HANDLE m_event, b_handle;
   HANDLE *objs = NULL;
   DWORD count, res;
-  RpcServerProtseq* cps;
+  RpcServerProtseq* cps = the_arg;
   RpcConnection* conn;
   RpcConnection* cconn;
   BOOL set_ready_event = FALSE;
 
   TRACE("(the_arg == ^%p)\n", the_arg);
 
+  m_event = cps->mgr_event;
+
   for (;;) {
     EnterCriticalSection(&server_cs);
     /* open and count connections */
     count = 1;
-    cps = protseqs;
-    while (cps) {
-      conn = cps->conn;
-      while (conn) {
-        RPCRT4_OpenConnection(conn);
-        if (rpcrt4_conn_get_wait_object(conn))
-          count++;
-        conn = conn->Next;
-      }
-      cps = cps->Next;
+    conn = cps->conn;
+    while (conn) {
+      RPCRT4_OpenConnection(conn);
+      if (rpcrt4_conn_get_wait_object(conn))
+        count++;
+      conn = conn->Next;
     }
     /* make array of connections */
     if (objs)
@@ -388,22 +380,18 @@ static DWORD CALLBACK RPCRT4_server_thre
 
     objs[0] = m_event;
     count = 1;
-    cps = protseqs;
-    while (cps) {
-      conn = cps->conn;
-      while (conn) {
-        if ((objs[count] = rpcrt4_conn_get_wait_object(conn)))
-          count++;
-        conn = conn->Next;
-      }
-      cps = cps->Next;
+    conn = cps->conn;
+    while (conn) {
+      if ((objs[count] = rpcrt4_conn_get_wait_object(conn)))
+        count++;
+      conn = conn->Next;
     }
     LeaveCriticalSection(&server_cs);
 
     if (set_ready_event)
     {
         /* signal to function that changed state that we are now sync'ed */
-        SetEvent(server_ready_event);
+        SetEvent(cps->server_ready_event);
         set_ready_event = FALSE;
     }
 
@@ -412,7 +400,7 @@ static DWORD CALLBACK RPCRT4_server_thre
     if (res == WAIT_OBJECT_0) {
       if (!std_listen)
       {
-        SetEvent(server_ready_event);
+        SetEvent(cps->server_ready_event);
         break;
       }
       set_ready_event = TRUE;
@@ -424,16 +412,10 @@ static DWORD CALLBACK RPCRT4_server_thre
       b_handle = objs[res - WAIT_OBJECT_0];
       /* find which connection got a RPC */
       EnterCriticalSection(&server_cs);
-      conn = NULL;
-      cps = protseqs;
-      while (cps) {
-        conn = cps->conn;
-        while (conn) {
-          if (b_handle == rpcrt4_conn_get_wait_object(conn)) break;
-          conn = conn->Next;
-        }
-        if (conn) break;
-        cps = cps->Next;
+      conn = cps->conn;
+      while (conn) {
+        if (b_handle == rpcrt4_conn_get_wait_object(conn)) break;
+        conn = conn->Next;
       }
       cconn = NULL;
       if (conn)
@@ -447,14 +429,10 @@ static DWORD CALLBACK RPCRT4_server_thre
   HeapFree(GetProcessHeap(), 0, objs);
   EnterCriticalSection(&server_cs);
   /* close connections */
-  cps = protseqs;
-  while (cps) {
-    conn = cps->conn;
-    while (conn) {
-      RPCRT4_CloseConnection(conn);
-      conn = conn->Next;
-    }
-    cps = cps->Next;
+  conn = cps->conn;
+  while (conn) {
+    RPCRT4_CloseConnection(conn);
+    conn = conn->Next;
   }
   LeaveCriticalSection(&server_cs);
   return 0;
@@ -462,23 +440,49 @@ static DWORD CALLBACK RPCRT4_server_thre
 
 /* tells the server thread that the state has changed and waits for it to
  * make the changes */
-static void RPCRT4_sync_with_server_thread(void)
+static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps)
 {
   /* make sure we are the only thread sync'ing the server state, otherwise
    * there is a race with the server thread setting an older state and setting
    * the server_ready_event when the new state hasn't yet been applied */
-  WaitForSingleObject(mgr_mutex, INFINITE);
+  WaitForSingleObject(ps->mgr_mutex, INFINITE);
 
-  SetEvent(mgr_event);
+  SetEvent(ps->mgr_event);
   /* wait for server thread to make the requested changes before returning */
-  WaitForSingleObject(server_ready_event, INFINITE);
+  WaitForSingleObject(ps->server_ready_event, INFINITE);
 
-  ReleaseMutex(mgr_mutex);
+  ReleaseMutex(ps->mgr_mutex);
+}
+
+static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen)
+{
+  RPC_STATUS status = RPC_S_OK;
+  HANDLE server_thread;
+
+  EnterCriticalSection(&listen_cs);
+  if (ps->is_listening) goto done;
+
+  if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
+  if (!ps->mgr_event) ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+  if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+  server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL);
+  if (!server_thread)
+  {
+    status = RPC_S_OUT_OF_RESOURCES;
+    goto done;
+  }
+  ps->is_listening = TRUE;
+  CloseHandle(server_thread);
+
+done:
+  LeaveCriticalSection(&listen_cs);
+  return status;
 }
 
 static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
 {
   RPC_STATUS status = RPC_S_ALREADY_LISTENING;
+  RpcServerProtseq *cps;
 
   TRACE("\n");
 
@@ -486,19 +490,26 @@ static RPC_STATUS RPCRT4_start_listen(BO
   if (auto_listen || (manual_listen_count++ == 0))
   {
     status = RPC_S_OK;
-    if (++listen_count == 1) {
-      HANDLE server_thread;
-      /* first listener creates server thread */
-      if (!mgr_mutex) mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
-      if (!mgr_event) mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
-      if (!server_ready_event) server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+    if (++listen_count == 1)
       std_listen = TRUE;
-      server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
-      CloseHandle(server_thread);
-    }
   }
   LeaveCriticalSection(&listen_cs);
 
+  if (std_listen)
+  {
+    cps = protseqs;
+    while (cps && status == RPC_S_OK)
+    {
+      status = RPCRT4_start_listen_protseq(cps, TRUE);
+      
+      /* make sure server is actually listening on the interface before
+      * returning */
+      if (status == RPC_S_OK)
+        RPCRT4_sync_with_server_thread(cps);
+      cps = cps->Next;
+    }
+  }
+
   return status;
 }
 
@@ -508,9 +519,16 @@ static void RPCRT4_stop_listen(BOOL auto
   if (auto_listen || (--manual_listen_count == 0))
   {
     if (listen_count != 0 && --listen_count == 0) {
+      RpcServerProtseq *cps;
+
       std_listen = FALSE;
       LeaveCriticalSection(&listen_cs);
-      RPCRT4_sync_with_server_thread();
+
+      cps = protseqs;
+      while (cps) {
+        RPCRT4_sync_with_server_thread(cps);
+        cps = cps->Next;
+      }
       return;
     }
     assert(listen_count >= 0);
@@ -520,17 +538,26 @@ static void RPCRT4_stop_listen(BOOL auto
 
 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
 {
-  RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint,
-                          NULL, NULL, NULL);
+  RPC_STATUS status;
+
+  status = RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL,
+                                   ps->Endpoint, NULL, NULL, NULL);
+  if (status != RPC_S_OK)
+    return status;
 
   EnterCriticalSection(&server_cs);
   ps->Next = protseqs;
   protseqs = ps;
   LeaveCriticalSection(&server_cs);
 
-  if (std_listen) RPCRT4_sync_with_server_thread();
+  if (std_listen)
+  {
+    status = RPCRT4_start_listen_protseq(ps, FALSE);
+    if (status == RPC_S_OK)
+      RPCRT4_sync_with_server_thread(ps);
+  }
 
-  return RPC_S_OK;
+  return status;
 }
 
 /***********************************************************************
@@ -758,13 +785,8 @@ RPC_STATUS WINAPI RpcServerRegisterIf2( 
   ifs = sif;
   LeaveCriticalSection(&server_cs);
 
-  if (sif->Flags & RPC_IF_AUTOLISTEN) {
-    RPCRT4_start_listen(TRUE);
-
-    /* make sure server is actually listening on the interface before
-     * returning */
-    RPCRT4_sync_with_server_thread();
-  }
+  if (sif->Flags & RPC_IF_AUTOLISTEN)
+      RPCRT4_start_listen(TRUE);
 
   return RPC_S_OK;
 }
@@ -882,7 +904,7 @@ RPC_STATUS WINAPI RpcServerRegisterAuthI
  */
 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
 {
-  RPC_STATUS status;
+  RPC_STATUS status = RPC_S_OK;
 
   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
 
@@ -891,9 +913,6 @@ RPC_STATUS WINAPI RpcServerListen( UINT 
 
   status = RPCRT4_start_listen(FALSE);
 
-  if (status == RPC_S_OK)
-    RPCRT4_sync_with_server_thread();
-
   if (DontWait || (status != RPC_S_OK)) return status;
 
   return RpcMgmtWaitServerListen();
diff --git a/dlls/rpcrt4/rpc_server.h b/dlls/rpcrt4/rpc_server.h
index 67a7ac7..3a24112 100644
--- a/dlls/rpcrt4/rpc_server.h
+++ b/dlls/rpcrt4/rpc_server.h
@@ -30,6 +30,15 @@ typedef struct _RpcServerProtseq
   LPSTR Endpoint;
   UINT MaxCalls;
   RpcConnection* conn;
+
+  /* is the server currently listening? */
+  BOOL is_listening;
+  /* set on change of configuration (e.g. listening on new protseq) */
+  HANDLE mgr_event;
+  /* mutex for ensuring only one thread can change state at a time */
+  HANDLE mgr_mutex;
+  /* set when server thread has finished opening connections */
+  HANDLE server_ready_event;
 } RpcServerProtseq;
 
 typedef struct _RpcServerInterface


More information about the wine-patches mailing list