Make sure that the driver only exists when all it's threads are dead. (Rev 334)
authortzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 21 Nov 2005 12:23:11 +0000 (12:23 +0000)
committertzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Mon, 21 Nov 2005 12:23:11 +0000 (12:23 +0000)
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@174 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

ulp/sdp/kernel/Precompile.h
ulp/sdp/kernel/SdpDriver.cpp
ulp/sdp/kernel/SdpDriver.h
ulp/sdp/kernel/SdpGenUtils.cpp
ulp/sdp/kernel/SdpGenUtils.h
ulp/sdp/kernel/SdpSocket.cpp
ulp/sdp/kernel/SdpSocket.h
ulp/sdp/todo

index ffcdb34..55ac814 100644 (file)
@@ -20,10 +20,10 @@ class SdpArp;
 #include "SdpTrace.h"\r
 #include "sdpLock.h"\r
 #include "RefCount.h"\r
+#include "SdpBufferPool.h"\r
 #include "sdpdriver.h"\r
 #include "SdpShared.h"\r
 #include "SdpUserFile.h"\r
-#include "SdpBufferPool.h"\r
 #include "SdpRecvPool.h"\r
 #include "SdpConnectionList.h"\r
 #include "SdpSocket.h"\r
index 40e8784..cff0f6d 100644 (file)
@@ -12,6 +12,8 @@ VOID DriverUnload (
     SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("called pDriverObject = 0x%x\n", pDriverObject ));\r
     ib_api_status_t ib_status;\r
 \r
+    g_pSdpDriver->WaitForAllThreadsToDie();\r
+\r
 \r
     ib_status = ib_close_al(g_pSdpDriver->m_al_handle);\r
     g_pSdpDriver->m_al_handle = NULL;\r
@@ -32,7 +34,7 @@ extern "C" NTSTATUS DriverEntry (
     IN PDRIVER_OBJECT pDriverObject,\r
     IN PUNICODE_STRING pRegistryPath   )\r
 {\r
-    NTSTATUS rc;\r
+    NTSTATUS rc = STATUS_SUCCESS;\r
     ib_api_status_t ib_status;\r
     PDEVICE_OBJECT pDevObj;\r
     SdpDriver *pSdpDriver;\r
@@ -74,7 +76,7 @@ extern "C" NTSTATUS DriverEntry (
     }\r
     DeviceCreated =  true;\r
 \r
-    pSdpDriver = (SdpDriver *) pDevObj->DeviceExtension;\r
+    pSdpDriver = new (pDevObj->DeviceExtension) SdpDriver;\r
     rc = pSdpDriver->Init(pDevObj);\r
 \r
     if (!NT_SUCCESS(rc)) {\r
@@ -302,7 +304,8 @@ if ((InputBufferLength < sizeof (InStruct)) ||
         goto Cleanup;                                                               \\r
 }\r
 \r
-NTSTATUS SdpDriver::Init(PDEVICE_OBJECT pDevObj) \r
+NTSTATUS \r
+SdpDriver::Init(PDEVICE_OBJECT pDevObj) \r
 {\r
     NTSTATUS rc = STATUS_SUCCESS;\r
     m_pDevObj = pDevObj;\r
@@ -317,12 +320,21 @@ NTSTATUS SdpDriver::Init(PDEVICE_OBJECT pDevObj)
         SDP_PRINT(SDP_ERR, SDP_DRIVER, ("m_pSdpArp->Init failed rc = 0x%x\n", rc ));        \r
         goto Cleanup;\r
     }\r
-Cleanup:        \r
+\r
+    ExInitializeFastMutex(&m_ThreadsMutex);\r
+    \r
+Cleanup:\r
+    if (!NT_SUCCESS(rc)) {\r
+        if (m_pSdpArp) {\r
+            delete m_pSdpArp;\r
+        }\r
+    }\r
     return rc;\r
 }\r
 \r
 \r
-NTSTATUS SdpDriver::DispatchDeviceIoControl(\r
+NTSTATUS \r
+SdpDriver::DispatchDeviceIoControl(\r
         IN PFILE_OBJECT pDeviceObject,\r
         IN PIRP pIrp,\r
         IN PIO_STACK_LOCATION pIrpSp,\r
@@ -578,4 +590,77 @@ Cleanup:
     return rc;\r
 }\r
 \r
+VOID \r
+SdpDriver::AddThread(ThreadHandle *pThreadHandle)\r
+{\r
+    SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x\n", this ));\r
+    // Check if there is any next thread that can be removed from the queue\r
+    LARGE_INTEGER  WaitTime;\r
+    WaitTime.QuadPart = 0; // Don't wait for them to die\r
+\r
+    ExAcquireFastMutex(&m_ThreadsMutex);\r
+\r
+    WaitForThreadsToDie(&WaitTime);\r
+\r
+    // Add me to the list of threads that should be removed\r
+    m_ShutDownThreads.InsertTailList(&pThreadHandle->m_List);\r
+    ExReleaseFastMutex(&m_ThreadsMutex);\r
+\r
+}\r
+\r
+VOID \r
+SdpDriver::WaitForAllThreadsToDie()\r
+{\r
+    SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x\n", this ));\r
+\r
+    ExAcquireFastMutex(&m_ThreadsMutex);\r
+    // Timeout of null will cause a wait forever\r
+    WaitForThreadsToDie(NULL);\r
+    ExReleaseFastMutex(&m_ThreadsMutex);\r
+}\r
+\r
+\r
+// This function has to be called with the mutex held\r
+VOID \r
+SdpDriver::WaitForThreadsToDie(LARGE_INTEGER  *pWaitTime)\r
+{\r
+    SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x\n", this ));\r
+    // Check if there is any next thread that can be removed from the queue\r
+    NTSTATUS rc = STATUS_SUCCESS;\r
+\r
+    LIST_ENTRY *pNextItem;\r
+    ThreadHandle *pNextThreadHandle;\r
+    while (m_ShutDownThreads.Size() > 0) {\r
+        pNextItem = m_ShutDownThreads.Head();\r
+        pNextThreadHandle = CONTAINING_RECORD(pNextItem, ThreadHandle, m_List);\r
+\r
+        rc = MyKeWaitForSingleObject(\r
+            pNextThreadHandle->ThreadObject,         \r
+            Executive,\r
+            KernelMode,\r
+            FALSE,\r
+            pWaitTime\r
+            );\r
+        ASSERT((rc == STATUS_SUCCESS) ||\r
+               (rc == STATUS_TIMEOUT));\r
+\r
+        if (rc == STATUS_TIMEOUT) {\r
+            // Nothing that we should do, the thread is not ready yet\r
+            SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x Former thread is not dead yet\n", this ));\r
+            break;\r
+        }\r
+        // SUCESS means that the thread is dead, we can remove it\r
+        // from the list\r
+        SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x Former thread is already dead\n", this ));\r
+\r
+        m_ShutDownThreads.RemoveHeadList();\r
+        ObDereferenceObject(pNextThreadHandle->ThreadObject);\r
+        delete pNextThreadHandle;\r
+        \r
+        // We now continue and try to remove the next object\r
+\r
+    }\r
+\r
+}\r
+\r
 \r
index f509fab..057e292 100644 (file)
@@ -3,6 +3,16 @@
 #ifndef H_SDP_DRIVER_H\r
 #define H_SDP_DRIVER_H \r
 \r
+// This struct is being used to hold an object that we can wait on\r
+// for threads to die.\r
+\r
+struct ThreadHandle {\r
+    // As this object has a simple life cycle I don't use refferance counting\r
+    // for it. This might have to change.\r
+    PVOID ThreadObject;\r
+    LIST_ENTRY m_List;\r
+};\r
+\r
 \r
 class SdpDriver {\r
 public:\r
@@ -35,8 +45,12 @@ public:
         IN ULONG IoControlCode,\r
         OUT ULONG &OutputDataSize\r
         );\r
-        \r
-        \r
+\r
+    // The following functions are being used so that the driver\r
+    // will wait for all the created threads to end\r
+    VOID AddThread(ThreadHandle *pThreadHandle);\r
+\r
+    VOID WaitForAllThreadsToDie();        \r
 \r
 public:\r
     ib_al_handle_t m_al_handle ;\r
@@ -44,8 +58,14 @@ public:
 \r
 private:\r
 \r
+    VOID WaitForThreadsToDie(LARGE_INTEGER  *pWWaitTime);\r
+\r
+\r
        PDEVICE_OBJECT m_pDevObj;\r
 \r
+    LinkedList m_ShutDownThreads;\r
+\r
+    FAST_MUTEX  m_ThreadsMutex;\r
     \r
 };\r
 \r
index 34ccce2..399bcff 100644 (file)
@@ -207,3 +207,8 @@ void __cdecl operator delete(void* p) {
     ExFreePoolWithTag(p, GLOBAL_ALLOCATION_TAG);\r
 }\r
 \r
+void* __cdecl operator new(size_t n, void *addr ) throw() {\r
+    return addr;\r
+}\r
+\r
+\r
index ebd95ff..458f289 100644 (file)
@@ -76,6 +76,7 @@ LARGE_INTEGER  TimeFromLong(ULONG HandredNanos);
 \r
 NTSTATUS Sleep(ULONG HandredNanos);\r
 \r
+void* __cdecl operator new(size_t n, void *addr ) throw();\r
 \r
 /* Convert an IBAL error to a Winsock error. */\r
 int IbalToWsaError(const       ib_api_status_t ib_status );\r
index 6bdccb3..d8f31d0 100644 (file)
@@ -47,10 +47,8 @@ cm_apr_callback(
 static void AL_API\r
 cm_dreq_callback(IN ib_cm_dreq_rec_t    *p_cm_dreq_rec )\r
 {\r
-    SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("dispatch level = %d\n", KeGetCurrentIrql()));\r
     SdpSocket *pSocket = (SdpSocket *) p_cm_dreq_rec->qp_context;\r
     pSocket->CmDreqCallback(p_cm_dreq_rec);\r
-\r
 }\r
 \r
 static void AL_API\r
@@ -154,6 +152,16 @@ NTSTATUS SdpSocket::Init(
 \r
     m_ConnectionList.Init(this);\r
 \r
+    // We now allocate the needed structure for the close socket, so that \r
+    // we won't be in trouble after the thread was created\r
+    m_pCloseSocketThread = new ThreadHandle;\r
+    if (m_pCloseSocketThread == NULL) {\r
+        SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Failed to allocate new SocketThread this = 0x%p \n",this));\r
+        rc = STATUS_NO_MEMORY;\r
+        goto Cleanup;\r
+    }\r
+    \r
+Cleanup:\r
     return rc;\r
 }\r
 \r
@@ -886,8 +894,8 @@ SdpSocket::WSPAccept(
     }    \r
 \r
     // I want to copy this data before releasing the lock\r
-    ULONG IP = m_DstIp;\r
-    USHORT Port = m_DstPort;    \r
+    ULONG IP = pNewSocket->m_DstIp;\r
+    USHORT Port = pNewSocket->m_DstPort;    \r
     \r
     ASSERT(Locked == true);\r
     rc = m_Lock.Unlock();\r
@@ -962,7 +970,7 @@ SdpSocket::WSPCloseSocket(
     )\r
 {\r
     NTSTATUS rc = STATUS_SUCCESS;\r
-    SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p\n",this));\r
+    SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p state = %s \n",this, SS2String(m_state)));\r
     OBJECT_ATTRIBUTES   attr;\r
 \r
     if (!m_Lock.Lock()) {\r
@@ -999,39 +1007,56 @@ SdpSocket::WSPCloseSocket(
             m_Lock.Unlock(); // Error ignored as this is already an error pass\r
             goto Cleanup;\r
         }\r
-    }\r
 \r
-    // We will now create a thread that will be resposible for the\r
-    // destruction of this socket\r
-    AddRef();\r
+        // We will now create a thread that will be resposible for the\r
+        // destruction of this socket\r
+        AddRef();\r
 \r
 \r
-    /* Create a new thread, storing both the handle and thread id. */\r
-    InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );\r
-    \r
-    HANDLE  ThreadHandle;\r
-    rc = PsCreateSystemThread(\r
-        &ThreadHandle, \r
-        THREAD_ALL_ACCESS,\r
-        &attr,\r
-        NULL,\r
-        NULL,\r
-        ::CloseSocketThread,\r
-        this\r
-        );\r
+        /* Create a new thread, storing both the handle and thread id. */\r
+        InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );\r
+        \r
+        HANDLE  ThreadHandle;\r
+        rc = PsCreateSystemThread(\r
+            &ThreadHandle, \r
+            THREAD_ALL_ACCESS,\r
+            &attr,\r
+            NULL,\r
+            NULL,\r
+            ::CloseSocketThread,\r
+            this\r
+            );\r
+\r
+        if (!NT_SUCCESS(rc)) {\r
+            SDP_PRINT(SDP_ERR, SDP_SOCKET, ("PsCreateSystemThread failed rc = 0x%x\n", rc ));\r
+            m_Lock.Unlock(); // Error ignored as this is already an error pass\r
+            // The thread wasn't created so we should remove the refferance\r
+            Release();  \r
+            goto Cleanup;\r
+        }\r
+\r
+        ASSERT(m_pCloseSocketThread != NULL);\r
+        // Convert the thread into a handle\r
+        rc = ObReferenceObjectByHandle(\r
+              ThreadHandle,\r
+              THREAD_ALL_ACCESS,\r
+              NULL,\r
+              KernelMode,\r
+              &m_pCloseSocketThread->ThreadObject,\r
+              NULL\r
+              );\r
+        ASSERT(rc == STATUS_SUCCESS); // According to MSDN, if I set the params\r
+                                     // correctly I shouldn't get an error\r
+        \r
+        rc = ZwClose(ThreadHandle);\r
+        ASSERT(NT_SUCCESS(rc)); // Should always succeed\r
+\r
+        g_pSdpDriver->AddThread(m_pCloseSocketThread);\r
+        m_pCloseSocketThread = NULL; // Will be delated when the callback thread is deleted\r
 \r
-    if (!NT_SUCCESS(rc)) {\r
-        SDP_PRINT(SDP_ERR, SDP_SOCKET, ("PsCreateSystemThread failed rc = 0x%x\n", rc ));\r
-        m_Lock.Unlock(); // Error ignored as this is already an error pass\r
-        // The thread wasn't created so we should remove the refferance\r
-        Release();  \r
-        goto Cleanup;\r
     }\r
 \r
-    // BUGBUG: Replace this with a mechanism that will allow\r
-    // to close the thered when the driver goes down\r
-    rc = ZwClose(ThreadHandle);\r
-    ASSERT(NT_SUCCESS(rc)); // Should succeed\r
+\r
 \r
     rc = m_Lock.Unlock();\r
     if (!NT_SUCCESS(rc)) {\r
@@ -1615,7 +1640,7 @@ ErrorLocked:
 VOID \r
 SdpSocket::CmDreqCallback(IN   ib_cm_dreq_rec_t *p_cm_dreq_rec)\r
 {\r
-    SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p\n", this));\r
+    SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p, dispatch level = %d\n", this, KeGetCurrentIrql()));\r
     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
     NTSTATUS rc = STATUS_SUCCESS;\r
     ib_cm_drep_t cm_drep;\r
@@ -1646,7 +1671,7 @@ SdpSocket::CmDreqCallback(IN   ib_cm_dreq_rec_t *p_cm_dreq_rec)
         goto ErrorLocked;\r
     }\r
 \r
-    // last step is to change our state\r
+    // last step is to change our state (this will affect close socket for example)\r
     m_state = SS_CONNECTED_DREP_SENT;\r
 \r
     // We should close the connection know ??????????/\r
@@ -2331,6 +2356,11 @@ VOID SdpSocket::Shutdown()
         m_pListeningSocket->Release();\r
         m_pListeningSocket = NULL;\r
     }\r
+\r
+    if (m_pCloseSocketThread != NULL) {\r
+        delete m_pCloseSocketThread;\r
+        m_pCloseSocketThread = NULL;\r
+    }\r
     \r
 \r
     // Now that all ibal operations have finished we can free the memory\r
index 653c915..b70706c 100644 (file)
@@ -119,6 +119,8 @@ private:
     bool                    m_ShutdownCalled;\r
     bool                    m_DisconnectConnectionRecieved;\r
 \r
+    ThreadHandle*           m_pCloseSocketThread;\r
+\r
     \r
 \r
     VOID SignalShutdown();\r
index 07c1f1b..0f59b5d 100644 (file)
@@ -33,6 +33,4 @@ USER MODE:
 * check the way that errors are reported to the user mode. It seems that returning an error\r
 in rc means that the output buffer won't pass out.\r
 \r
-* make sure that the "terminator thread" is being killed before we exit.\r
-\r
 * Check why sometimes the QP and so are not valid when you come to kill them\r