Robert Shearman : rpcrt4: Implement a process-wide connection pool for client connections,

Alexandre Julliard julliard at wine.codeweavers.com
Thu Jun 8 05:06:02 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: 58ec282bfb245991ba439818a320f7650d094ad8
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=58ec282bfb245991ba439818a320f7650d094ad8

Author: Robert Shearman <rob at codeweavers.com>
Date:   Wed Jun  7 20:12:34 2006 +0100

rpcrt4: Implement a process-wide connection pool for client connections,
rather than relying on the restriction of one connection per
binding. This also avoids the problem of two threads using the same
connection at the same time.

---

 dlls/rpcrt4/rpc_binding.c   |   34 ++++++++++++++++++++------------
 dlls/rpcrt4/rpc_binding.h   |    6 ++++++
 dlls/rpcrt4/rpc_transport.c |   46 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+), 13 deletions(-)

diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c
index bb691f6..2e9b40b 100644
--- a/dlls/rpcrt4/rpc_binding.c
+++ b/dlls/rpcrt4/rpc_binding.c
@@ -237,16 +237,15 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding
 
   TRACE("(Binding == ^%p)\n", Binding);
 
-  /* if we try to bind a new interface and the connection is already opened,
-   * close the current connection and create a new with the new binding. */ 
-  if (!Binding->server && Binding->FromConn &&
-      (Binding->AuthInfo == Binding->FromConn->AuthInfo) &&
-      memcmp(&Binding->FromConn->ActiveInterface, InterfaceId,
-             sizeof(RPC_SYNTAX_IDENTIFIER))) {
-
-    TRACE("releasing pre-existing connection\n");
-    RPCRT4_DestroyConnection(Binding->FromConn);
-    Binding->FromConn = NULL;
+  if (!Binding->server) {
+    /* try to find a compatible connection from the connection pool */
+    NewConnection = RPCRT4_GetIdleConnection(InterfaceId, TransferSyntax,
+        Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint,
+        Binding->AuthInfo);
+    if (NewConnection) {
+      *Connection = NewConnection;
+      return RPC_S_OK;
+    }
   } else {
     /* we already have a connection with acceptable binding, so use it */
     if (Binding->FromConn) {
@@ -307,7 +306,8 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding
     RPCRT4_FreeHeader(response_hdr);
   }
 
-  Binding->FromConn = NewConnection;
+  if (Binding->server)
+    Binding->FromConn = NewConnection;
   *Connection = NewConnection;
 
   return RPC_S_OK;
@@ -317,8 +317,16 @@ RPC_STATUS RPCRT4_CloseBinding(RpcBindin
 {
   TRACE("(Binding == ^%p)\n", Binding);
   if (!Connection) return RPC_S_OK;
-  if (Binding->FromConn == Connection) return RPC_S_OK;
-  return RPCRT4_DestroyConnection(Connection);
+  if (Binding->server) {
+    /* don't destroy a connection that is cached in the binding */
+    if (Binding->FromConn == Connection)
+      return RPC_S_OK;
+    return RPCRT4_DestroyConnection(Connection);
+  }
+  else {
+    RPCRT4_ReleaseIdleConnection(Connection);
+    return RPC_S_OK;
+  }
 }
 
 /* utility functions for string composing and parsing */
diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h
index 49f20b0..0723a22 100644
--- a/dlls/rpcrt4/rpc_binding.h
+++ b/dlls/rpcrt4/rpc_binding.h
@@ -23,6 +23,7 @@ #define __WINE_RPC_BINDING_H
 
 #include "wine/rpcss_shared.h"
 #include "security.h"
+#include "wine/list.h"
 
 
 typedef struct _RpcAuthInfo
@@ -55,6 +56,9 @@ typedef struct _RpcConnection
   TimeStamp exp;
   ULONG attr;
   RpcAuthInfo *AuthInfo;
+
+  /* client-only */
+  struct list conn_pool_entry;
 } RpcConnection;
 
 struct protseq_ops {
@@ -101,6 +105,8 @@ #define RPCRT4_strdupW(x) RPCRT4_strndup
 ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo);
 ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo);
 
+RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, RpcAuthInfo* AuthInfo);
+void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection);
 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding);
 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection);
 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection);
diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index b50f839..c9028bb 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -68,6 +68,17 @@ #include "epm_towers.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
 
+static CRITICAL_SECTION connection_pool_cs;
+static CRITICAL_SECTION_DEBUG connection_pool_cs_debug =
+{
+    0, 0, &connection_pool_cs,
+    { &connection_pool_cs_debug.ProcessLocksList, &connection_pool_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": connection_pool") }
+};
+static CRITICAL_SECTION connection_pool_cs = { &connection_pool_cs_debug, -1, 0, 0, 0, 0 };
+
+static struct list connection_pool = LIST_INIT(connection_pool);
+
 /**** ncacn_np support ****/
 
 typedef struct _RpcConnection_np
@@ -777,6 +788,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcCo
   NewConnection->NextCallId = 1;
   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
   NewConnection->AuthInfo = AuthInfo;
+  list_init(&NewConnection->conn_pool_entry);
 
   TRACE("connection: %p\n", NewConnection);
   *Connection = NewConnection;
@@ -784,6 +796,40 @@ RPC_STATUS RPCRT4_CreateConnection(RpcCo
   return RPC_S_OK;
 }
 
+RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId,
+    const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr,
+    LPCSTR Endpoint, RpcAuthInfo* AuthInfo)
+{
+  RpcConnection *Connection;
+  /* try to find a compatible connection from the connection pool */
+  EnterCriticalSection(&connection_pool_cs);
+  LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry)
+    if ((Connection->AuthInfo == AuthInfo) &&
+        !memcmp(&Connection->ActiveInterface, InterfaceId,
+           sizeof(RPC_SYNTAX_IDENTIFIER)) &&
+        !strcmp(rpcrt4_conn_get_name(Connection), Protseq) &&
+        !strcmp(Connection->NetworkAddr, NetworkAddr) &&
+        !strcmp(Connection->Endpoint, Endpoint))
+    {
+      list_remove(&Connection->conn_pool_entry);
+      LeaveCriticalSection(&connection_pool_cs);
+      TRACE("got connection from pool %p\n", Connection);
+      return Connection;
+    }
+
+  LeaveCriticalSection(&connection_pool_cs);
+  return NULL;
+}
+
+void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection)
+{
+  assert(!Connection->server);
+  EnterCriticalSection(&connection_pool_cs);
+  list_add_head(&connection_pool, &Connection->conn_pool_entry);
+  LeaveCriticalSection(&connection_pool_cs);
+}
+
+
 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
 {
   RPC_STATUS err;




More information about the wine-cvs mailing list