- Some NDK fixes when compiling with PSDK.
[reactos.git] / reactos / subsys / csr / csrsrv / wait.c
index e836407..08a8402 100644 (file)
-/* $Id$
- *
- * subsys/csr/csrsrv/wait.c - CSR server - wait management
- * 
- * ReactOS Operating System
- * 
- * --------------------------------------------------------------------
- *
- * This software is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING.LIB. If not, write
- * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
- * MA 02139, USA.  
- *
- * --------------------------------------------------------------------
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS CSR Sub System
+ * FILE:            subsys/csr/csrsrv/wait.c
+ * PURPOSE:         CSR Server DLL Wait Implementation
+ * PROGRAMMERS:     Emanuele Aliberti
+ *                  Alex Ionescu (alex@relsoft.net)
  */
+
+/* INCLUDES ******************************************************************/
+
 #include "srv.h"
 
-//#define NDEBUG
+#define NDEBUG
 #include <debug.h>
 
-/*=====================================================================
- *     PUBLIC API
- *===================================================================*/
+/* DATA **********************************************************************/
+
+RTL_CRITICAL_SECTION CsrWaitListsLock;
 
-NTSTATUS STDCALL CsrCreateWait (PCSR_THREAD pCsrThread, PCSR_WAIT * ppCsrWait)
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrInitializeWait
+ *
+ * The CsrInitializeWait routine initializes a CSR Wait Object.
+ *
+ * @param WaitFunction
+ *        Pointer to the function that will handle this wait.
+ *
+ * @param CsrWaitThread
+ *        Pointer to the CSR Thread that will perform the wait.
+ *
+ * @param WaitApiMessage
+ *        Pointer to the CSR API Message associated to this wait.
+ *
+ * @param WaitContext
+ *        Pointer to a user-defined parameter associated to this wait.
+ *
+ * @param NewWaitBlock
+ *        Pointed to the initialized CSR Wait Block for this wait.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction,
+                  IN PCSR_THREAD CsrWaitThread,
+                  IN OUT PCSR_API_MESSAGE WaitApiMessage,
+                  IN PVOID WaitContext,
+                  OUT PCSR_WAIT_BLOCK *NewWaitBlock)
 {
-       NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-       
-       DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-       
-       return Status;
+    ULONG Size;
+    PCSR_WAIT_BLOCK WaitBlock;
+
+    /* Calculate the size of the wait block */
+    Size = sizeof(CSR_WAIT_BLOCK) -
+           sizeof(WaitBlock->WaitApiMessage) +
+           WaitApiMessage->Header.u1.s1.TotalLength;
+
+    /* Allocate the Wait Block */
+    if (!(WaitBlock = RtlAllocateHeap(CsrHeap, 0, Size)))
+    {
+        /* Fail */
+        WaitApiMessage->Status = STATUS_NO_MEMORY;
+        return FALSE;
+    }
+
+    /* Initialize it */
+    WaitBlock->Size = Size;
+    WaitBlock->WaitThread = CsrWaitThread;
+    WaitBlock->WaitContext = WaitContext;
+    WaitBlock->WaitFunction = WaitFunction;
+    InitializeListHead(&WaitBlock->UserWaitList);
+    InitializeListHead(&WaitBlock->WaitList);
+
+    /* Copy the message */
+    RtlMoveMemory(&WaitBlock->WaitApiMessage,
+                  WaitApiMessage,
+                  WaitApiMessage->Header.u1.s1.TotalLength);
+
+    /* Return the block */
+    *NewWaitBlock = WaitBlock;
+    return TRUE;
 }
 
-NTSTATUS STDCALL CsrDereferenceWait (PCSR_WAIT pCsrWait)
+/*++
+ * @name CsrNotifyWaitBlock
+ *
+ * The CsrNotifyWaitBlock routine calls the wait function for a registered
+ * CSR Wait Block, and replies to the attached CSR API Message, if any.
+ *
+ * @param WaitBlock
+ *        Pointer to the CSR Wait Block
+ *
+ * @param WaitList
+ *        Pointer to the wait list for this wait.
+ *
+ * @param WaitArgument[1-2]
+ *        User-defined values to pass to the wait function.
+ *
+ * @param WaitFlags
+ *        Wait flags for this wait.
+ *
+ * @param DereferenceThread
+ *        Specifies whether the CSR Thread should be dereferenced at the
+ *        end of this wait.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks After a wait block is notified, the wait function becomes invalid.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock,
+                   IN PLIST_ENTRY WaitList,
+                   IN PVOID WaitArgument1,
+                   IN PVOID WaitArgument2,
+                   IN ULONG WaitFlags,
+                   IN BOOLEAN DereferenceThread)
 {
-       NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-       
-       DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-       
-       return Status;
+    /* Call the wait function */
+    if ((WaitBlock->WaitFunction)(WaitList,
+                                  WaitBlock->WaitThread,
+                                  &WaitBlock->WaitApiMessage,
+                                  WaitBlock->WaitContext,
+                                  WaitArgument1,
+                                  WaitArgument2,
+                                  WaitFlags))
+    {
+        /* The wait is done, clear the block */
+        WaitBlock->WaitThread->WaitBlock = NULL;
+
+        /* Check for captured arguments */
+        if (WaitBlock->WaitApiMessage.CsrCaptureData)
+        {
+            /* Release them */
+            CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage);
+        }
+
+        /* Reply to the port */
+        NtReplyPort(WaitBlock->WaitThread->Process->ClientPort,
+                    (PPORT_MESSAGE)&WaitBlock->WaitApiMessage);
+
+        /* Check if we should dereference the thread */
+        if (DereferenceThread)
+        {
+            /* Remove it from the Wait List */
+            if (WaitBlock->WaitList.Flink)
+            {
+                RemoveEntryList(&WaitBlock->WaitList);
+            }
+
+            /* Remove it from the User Wait List */
+            if (WaitBlock->UserWaitList.Flink)
+            {
+                RemoveEntryList(&WaitBlock->UserWaitList);
+            }
+
+            /* Dereference teh thread */
+            CsrDereferenceThread(WaitBlock->WaitThread);
+
+            /* Free the wait block */
+            RtlFreeHeap(CsrHeap, 0, WaitBlock);
+        }
+        else
+        {
+            /* The wait is complete, but the thread is being kept alive */
+            WaitBlock->WaitFunction = NULL;
+        }
+    
+        /* The wait suceeded*/
+        return TRUE;
+    }
+    
+    /* The wait failed */
+    return FALSE;
 }
 
-NTSTATUS STDCALL CsrMoveSatisfiedWait (PCSR_WAIT pCsrWait)
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*++
+ * @name CsrCreateWait
+ * @implemented NT4
+ *
+ * The CsrCreateWait routine creates a CSR Wait.
+ *
+ * @param WaitList
+ *        Pointer to a list entry of the waits to associate.
+ *
+ * @param WaitFunction
+ *        Pointer to the function that will handle this wait.
+ *
+ * @param CsrWaitThread
+ *        Pointer to the CSR Thread that will perform the wait.
+ *
+ * @param WaitApiMessage
+ *        Pointer to the CSR API Message associated to this wait.
+ *
+ * @param WaitContext
+ *        Pointer to a user-defined parameter associated to this wait.
+ *
+ * @param UserWaitList
+ *        Pointer to a list entry of the user-defined waits to associate.
+ *
+ * @return TRUE in case of success, FALSE otherwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrCreateWait(IN PLIST_ENTRY WaitList,
+              IN CSR_WAIT_FUNCTION WaitFunction,
+              IN PCSR_THREAD CsrWaitThread,
+              IN OUT PCSR_API_MESSAGE WaitApiMessage,
+              IN PVOID WaitContext,
+              IN PLIST_ENTRY UserWaitList OPTIONAL)
 {
-       NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-       
-       DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-       
-       return Status;
+    PCSR_WAIT_BLOCK WaitBlock;
+
+    /* Initialize the wait */
+    if (!CsrInitializeWait(WaitFunction,
+                           CsrWaitThread,
+                           WaitApiMessage,
+                           WaitContext,
+                           &WaitBlock))
+    {
+        return FALSE;
+    }
+
+    /* Acquire the Wait Lock */
+    CsrAcquireWaitLock();
+
+    /* Make sure the thread wasn't destroyed */
+    if (CsrWaitThread && (CsrWaitThread->Flags & CsrThreadTerminated))
+    {
+        /* Fail the wait */
+        CsrWaitThread->WaitBlock = NULL;
+        RtlFreeHeap(CsrHeap, 0, WaitBlock);
+        CsrReleaseWaitLock();
+        return FALSE;
+    }
+
+    /* Insert the wait in the queue */
+    InsertTailList(WaitList, &WaitBlock->WaitList);
+
+    /* Insert the User Wait too, if one was given */
+    if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList);
+
+    /* Return */
+    CsrReleaseWaitLock();
+    return TRUE;
 }
 
-NTSTATUS STDCALL CsrNotifyWait (PCSR_WAIT pCsrWait)
+/*++
+ * @name CsrDereferenceWait
+ * @implemented NT4
+ *
+ * The CsrDereferenceWait routine derefences a CSR Wait Block.
+ *
+ * @param WaitList
+ *        Pointer to the Wait List associated to the wait.
+
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrDereferenceWait(IN PLIST_ENTRY WaitList)
 {
-       NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-       
-       DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-       
-       return Status;
+    PLIST_ENTRY ListHead, NextEntry;
+    PCSR_WAIT_BLOCK WaitBlock;
+
+    /* Acquire the Process and Wait Locks */
+    CsrAcquireProcessLock();
+    CsrAcquireWaitLock();
+
+    /* Set the list pointers */
+    ListHead = WaitList;
+    NextEntry = ListHead->Flink;
+
+    /* Start the loop */
+    while (NextEntry != ListHead)
+    {
+        /* Get the wait block */
+        WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+        /* Move to the next entry */
+        NextEntry = NextEntry->Flink;
+
+        /* Check if there's no Wait Routine */
+        if (!WaitBlock->WaitFunction)
+        {
+            /* Remove it from the Wait List */
+            if (WaitBlock->WaitList.Flink)
+            {
+                RemoveEntryList(&WaitBlock->WaitList);
+            }
+
+            /* Remove it from the User Wait List */
+            if (WaitBlock->UserWaitList.Flink)
+            {
+                RemoveEntryList(&WaitBlock->UserWaitList);
+            }
+
+            /* Dereference the thread waiting on it */
+            CsrDereferenceThread(WaitBlock->WaitThread);
+
+            /* Free the block */
+            RtlFreeHeap(CsrHeap, 0, WaitBlock);
+        }
+    }
+
+    /* Release the locks */
+    CsrReleaseWaitLock();
+    CsrReleaseProcessLock();
 }
 
+/*++
+ * @name CsrMoveSatisfiedWait
+ * @implemented NT5
+ *
+ * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list
+ * to another list entry.
+ *
+ * @param NewEntry
+ *        Pointer to a list entry where the satisfied waits will be added.
+ *
+ * @param WaitList
+ *        Pointer to a list entry to analyze for satisfied waits.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry,
+                     IN PLIST_ENTRY WaitList)
+{
+    PLIST_ENTRY ListHead, NextEntry;
+    PCSR_WAIT_BLOCK WaitBlock;
+
+    /* Acquire the Wait Lock */
+    CsrAcquireWaitLock();
+
+    /* Set the List pointers */
+    ListHead = WaitList;
+    NextEntry = ListHead->Flink;
+
+    /* Start looping */
+    while (NextEntry != ListHead)
+    {
+        /* Get the Wait block */
+        WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+        /* Go to the next entry */
+        NextEntry = NextEntry->Flink;
+
+        /* Check if there is a Wait Callback */
+        if (WaitBlock->WaitFunction)
+        {
+            /* Remove it from the Wait Block Queue */
+            RemoveEntryList(&WaitBlock->WaitList);
+
+            /* Insert the new entry */
+            InsertTailList(&WaitBlock->WaitList, NewEntry);
+        }
+    }
+
+    /* Release the wait lock */
+    CsrReleaseWaitLock();
+}
+
+/*++
+ * @name CsrNotifyWait
+ * @implemented NT4
+ *
+ * The CsrNotifyWait notifies a CSR Wait Block.
+ *
+ * @param WaitList
+ *        Pointer to the list entry for this wait.
+ *
+ * @param WaitType
+ *        Type of the wait to perform, either WaitAny or WaitAll.
+ *
+ * @param WaitArgument[1-2]
+ *        User-defined argument to pass on to the wait function.
+ *
+ * @return TRUE in case of success, FALSE othwerwise.
+ *
+ * @remarks None.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+CsrNotifyWait(IN PLIST_ENTRY WaitList,
+              IN ULONG WaitType,
+              IN PVOID WaitArgument1,
+              IN PVOID WaitArgument2)
+{
+    PLIST_ENTRY ListHead, NextEntry;
+    PCSR_WAIT_BLOCK WaitBlock;
+    BOOLEAN NotifySuccess = FALSE;
+
+    /* Acquire the Wait Lock */
+    CsrAcquireWaitLock();
+
+    /* Set the List pointers */
+    ListHead = WaitList;
+    NextEntry = ListHead->Flink;
+
+    /* Start looping */
+    while (NextEntry != ListHead)
+    {
+        /* Get the Wait block */
+        WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList);
+
+        /* Go to the next entry */
+        NextEntry = NextEntry->Flink;
+
+        /* Check if there is a Wait Callback */
+        if (WaitBlock->WaitFunction)
+        {
+            /* Notify the Waiter */
+            NotifySuccess |= CsrNotifyWaitBlock(WaitBlock,
+                                                WaitList,
+                                                WaitArgument1,
+                                                WaitArgument2,
+                                                0,
+                                                FALSE);
+            
+            /* We've already done a wait, so leave unless this is a Wait All */
+            if (WaitType != WaitAll) break;
+        }
+    }
+
+    /* Release the wait lock and return */
+    CsrReleaseWaitLock();
+    return NotifySuccess;
+}
 
 /* EOF */