Author: ion
Date: Tue Jan 16 18:09:53 2007
New Revision: 25486
URL: 
http://svn.reactos.org/svn/reactos?rev=25486&view=rev
Log:
- Reimplement Process/Thread/Image notification callbacks by using the new executive
lightweight callback implementation.
- Remove corresponding entry from kernel fun.
Modified:
    trunk/reactos/ntoskrnl/KrnlFun.c
    trunk/reactos/ntoskrnl/ex/callback.c
    trunk/reactos/ntoskrnl/include/internal/ex.h
    trunk/reactos/ntoskrnl/include/internal/ps.h
    trunk/reactos/ntoskrnl/include/internal/ps_x.h
    trunk/reactos/ntoskrnl/ps/notify.c
Modified: trunk/reactos/ntoskrnl/KrnlFun.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/KrnlFun.c?rev=254…
==============================================================================
--- trunk/reactos/ntoskrnl/KrnlFun.c (original)
+++ trunk/reactos/ntoskrnl/KrnlFun.c Tue Jan 16 18:09:53 2007
@@ -9,7 +9,6 @@
 //              Failure to respect this will *ACHIEVE NOTHING*.
 //
 // Ex:
-//  - Implement Generic Callback mechanism.
 //  - Use pushlocks for handle implementation.
 //
 // Ke1:
Modified: trunk/reactos/ntoskrnl/ex/callback.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/callback.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/callback.c (original)
+++ trunk/reactos/ntoskrnl/ex/callback.c Tue Jan 16 18:09:53 2007
@@ -230,31 +230,6 @@
     return CallbackRoutineBlock;
 }
-VOID
-NTAPI // FIXME: FORCEINLINE AFTER TESTING!
-ExDoCallBack(IN OUT PEX_CALLBACK Callback,
-             IN PVOID Context,
-             IN PVOID Argument1,
-             IN PVOID Argument2)
-{
-    PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock;
-    PEX_CALLBACK_FUNCTION Function;
-
-    /* Reference the block */
-    CallbackRoutineBlock = ExReferenceCallBackBlock(Callback);
-    if (CallbackRoutineBlock)
-    {
-        /* Get the function */
-        Function = ExGetCallBackBlockRoutine(CallbackRoutineBlock);
-
-        /* Do the callback */
-        Function(Context, Argument1, Argument2);
-
-        /* Now dereference it */
-        ExDereferenceCallBackBlock(Callback, CallbackRoutineBlock);
-    }
-}
-
 BOOLEAN
 NTAPI
 ExCompareExchangeCallBack(IN OUT PEX_CALLBACK CallBack,
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ex.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ex.h Tue Jan 16 18:09:53 2007
@@ -169,7 +169,59 @@
 VOID
 NTAPI
 ExInitializeCallBack(
-    IN PEX_CALLBACK Callback
+    IN OUT PEX_CALLBACK Callback
+);
+
+PEX_CALLBACK_ROUTINE_BLOCK
+NTAPI
+ExAllocateCallBack(
+    IN PEX_CALLBACK_FUNCTION Function,
+    IN PVOID Context
+);
+
+VOID
+NTAPI
+ExFreeCallBack(
+    IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
+);
+
+BOOLEAN
+NTAPI
+ExCompareExchangeCallBack (
+    IN OUT PEX_CALLBACK CallBack,
+    IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
+    IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
+);
+
+PEX_CALLBACK_ROUTINE_BLOCK
+NTAPI
+ExReferenceCallBackBlock(
+    IN OUT PEX_CALLBACK CallBack
+);
+
+VOID
+NTAPI
+ExDereferenceCallBackBlock(
+    IN OUT PEX_CALLBACK CallBack,
+    IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
+);
+
+PEX_CALLBACK_FUNCTION
+NTAPI
+ExGetCallBackBlockRoutine(
+    IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
+);
+
+PVOID
+NTAPI
+ExGetCallBackBlockContext(
+    IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
+);
+
+VOID
+NTAPI
+ExWaitForCallBacks(
+    IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
 );
 /* Rundown Functions ********************************************************/
@@ -336,6 +388,33 @@
 static __inline _SEH_FILTER(_SEH_ExSystemExceptionFilter)
 {
     return ExSystemExceptionFilter();
+}
+
+/* CALLBACKS *****************************************************************/
+
+VOID
+FORCEINLINE
+ExDoCallBack(IN OUT PEX_CALLBACK Callback,
+             IN PVOID Context,
+             IN PVOID Argument1,
+             IN PVOID Argument2)
+{
+    PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock;
+    PEX_CALLBACK_FUNCTION Function;
+
+    /* Reference the block */
+    CallbackRoutineBlock = ExReferenceCallBackBlock(Callback);
+    if (CallbackRoutineBlock)
+    {
+        /* Get the function */
+        Function = ExGetCallBackBlockRoutine(CallbackRoutineBlock);
+
+        /* Do the callback */
+        Function(Context, Argument1, Argument2);
+
+        /* Now dereference it */
+        ExDereferenceCallBackBlock(Callback, CallbackRoutineBlock);
+    }
 }
 /* RUNDOWN *******************************************************************/
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ps.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ps.h Tue Jan 16 18:09:53 2007
@@ -365,14 +365,11 @@
 extern LARGE_INTEGER ShortPsLockDelay;
 extern EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
 extern PHANDLE_TABLE PspCidTable;
-extern PCREATE_THREAD_NOTIFY_ROUTINE
-PspThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];
-extern PCREATE_PROCESS_NOTIFY_ROUTINE
-PspProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];
-extern PLOAD_IMAGE_NOTIFY_ROUTINE
-PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];
+extern EX_CALLBACK PspThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];
+extern EX_CALLBACK PspProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];
+extern EX_CALLBACK PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];
 extern PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine;
-extern ULONG PspThreadNotifyRoutineCount;
+extern ULONG PspThreadNotifyRoutineCount, PspProcessNotifyRoutineCount;
 extern BOOLEAN PsImageNotifyEnabled;
 extern PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout;
 extern PKWIN32_THREAD_CALLOUT PspW32ThreadCallout;
Modified: trunk/reactos/ntoskrnl/include/internal/ps_x.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ps_x.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ps_x.h Tue Jan 16 18:09:53 2007
@@ -33,13 +33,19 @@
                                  IN BOOLEAN Create)
 {
     ULONG i;
-    CLIENT_ID Cid = CurrentThread->Cid;
-    /* Loop the notify routines */
-    for (i = 0; i < PspThreadNotifyRoutineCount; i++)
+    /* Check if we have registered routines */
+    if (PspThreadNotifyRoutineCount)
     {
-        /* Call it */
-        PspThreadNotifyRoutine[i](Cid.UniqueProcess, Cid.UniqueThread, Create);
+        /* Loop callbacks */
+        for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
+        {
+            /* Do the callback */
+            ExDoCallBack(&PspThreadNotifyRoutine[i],
+                         CurrentThread->Cid.UniqueProcess,
+                         CurrentThread->Cid.UniqueThread,
+                         (PVOID)(ULONG_PTR)Create);
+        }
     }
 }
@@ -49,17 +55,18 @@
                                   IN BOOLEAN Create)
 {
     ULONG i;
-    HANDLE ProcessId = (HANDLE)CurrentProcess->UniqueProcessId;
-    HANDLE ParentId = CurrentProcess->InheritedFromUniqueProcessId;
-    /* Loop the notify routines */
-    for(i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; ++i)
+    /* Check if we have registered routines */
+    if (PspProcessNotifyRoutineCount)
     {
-        /* Make sure it exists */
-        if(PspProcessNotifyRoutine[i])
+        /* Loop callbacks */
+        for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
         {
-            /* Call it */
-            PspProcessNotifyRoutine[i](ParentId, ProcessId, Create);
+            /* Do the callback */
+            ExDoCallBack(&PspProcessNotifyRoutine[i],
+                         CurrentProcess->InheritedFromUniqueProcessId,
+                         (PVOID)(ULONG_PTR)Create,
+                         NULL);
         }
     }
 }
@@ -75,12 +82,11 @@
     /* Loop the notify routines */
     for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; ++ i)
     {
-        /* Make sure it exists */
-        if (PspLoadImageNotifyRoutine[i])
-        {
-            /* Call it */
-            PspLoadImageNotifyRoutine[i](FullImageName, ProcessId, ImageInfo);
-        }
+        /* Do the callback */
+        ExDoCallBack(&PspLoadImageNotifyRoutine[i],
+                     FullImageName,
+                     ProcessId,
+                     ImageInfo);
     }
 }
Modified: trunk/reactos/ntoskrnl/ps/notify.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/notify.c?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/ps/notify.c (original)
+++ trunk/reactos/ntoskrnl/ps/notify.c Tue Jan 16 18:09:53 2007
@@ -15,14 +15,12 @@
 /* GLOBALS *******************************************************************/
-BOOLEAN PsImageNotifyEnabled = TRUE;
-ULONG PspThreadNotifyRoutineCount;
-PCREATE_THREAD_NOTIFY_ROUTINE
-PspThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];
-PCREATE_PROCESS_NOTIFY_ROUTINE
-PspProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];
-PLOAD_IMAGE_NOTIFY_ROUTINE
-PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];
+BOOLEAN PsImageNotifyEnabled = FALSE;
+ULONG PspThreadNotifyRoutineCount, PspProcessNotifyRoutineCount;
+ULONG PspLoadImageNotifyRoutineCount;
+EX_CALLBACK PspThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];
+EX_CALLBACK PspProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];
+EX_CALLBACK PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];
 PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine;
 /* PUBLIC FUNCTIONS **********************************************************/
@@ -36,39 +34,78 @@
                                 IN BOOLEAN Remove)
 {
     ULONG i;
-
-    /* Check if it's a removal or addition */
+    PEX_CALLBACK_ROUTINE_BLOCK CallBack;
+    PAGED_CODE();
+
+    /* Check if we're removing */
     if (Remove)
     {
-        /* Loop the routines */
-        for(i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
-        {
-            /* Check for a match */
-            if (PspProcessNotifyRoutine[i] == NotifyRoutine)
-            {
-                /* Remove and return */
-                PspProcessNotifyRoutine[i] = NULL;
+        /* Loop all the routines */
+        for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
+        {
+            /* Reference the callback block */
+            CallBack = ExReferenceCallBackBlock(&PspProcessNotifyRoutine[i]);
+            if (!CallBack) continue;
+
+            /* Check it this is a matching block */
+            if (ExGetCallBackBlockRoutine(CallBack) != (PVOID)NotifyRoutine)
+            {
+                /* It's not, try the next one */
+                continue;
+            }
+
+            /* It is, clear the current routine */
+            if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
+                                          NULL,
+                                          CallBack))
+            {
+                /* Decrement the number of routines */
+                InterlockedDecrement(&PspProcessNotifyRoutineCount);
+
+                /* Dereference the block */
+                ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
+                                           CallBack);
+
+                /* Wait for actice callbacks */
+                ExWaitForCallBacks(CallBack);
+
+                /* Free the callback and exit */
+                ExFreeCallBack (CallBack);
                 return STATUS_SUCCESS;
             }
-        }
+
+            /* Dereference the block */
+            ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
+                                       CallBack);
+        }
+
+        /* We didn't find any matching block */
+        return STATUS_PROCEDURE_NOT_FOUND;
     }
     else
     {
-        /* Loop the routines */
-        for(i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
-        {
-            /* Find an empty one */
-            if (!PspProcessNotifyRoutine[i])
-            {
-                /* Add it */
-                PspProcessNotifyRoutine[i] = NotifyRoutine;
+        /* Allocate a callback */
+        CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
+        if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
+
+        /* Loop all callbacks */
+        for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
+        {
+            /* Add this routine if it's an empty slot */
+            if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
+                                          CallBack,
+                                          NULL))
+            {
+                /* Found and inserted into an empty slot, return */
+                InterlockedIncrement(&PspProcessNotifyRoutineCount);
                 return STATUS_SUCCESS;
             }
         }
-    }
-
-    /* Nothing found */
-    return Remove ? STATUS_PROCEDURE_NOT_FOUND : STATUS_INVALID_PARAMETER;
+
+        /* We didn't find a free slot, free the callback and fail */
+        ExFreeCallBack(CallBack);
+        return STATUS_INVALID_PARAMETER;
+    }
 }
 /*
@@ -93,90 +130,163 @@
 PsRemoveLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
 {
     ULONG i;
-
-    /* Loop the routines */
-    for(i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
-    {
-        /* Check for a match */
-        if (PspLoadImageNotifyRoutine[i] == NotifyRoutine)
-        {
-            /* Remove and return */
-            PspLoadImageNotifyRoutine[i] = NULL;
+    PEX_CALLBACK_ROUTINE_BLOCK CallBack;
+    PAGED_CODE();
+
+    /* Loop all callbacks */
+    for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
+    {
+        /* Reference this slot */
+        CallBack = ExReferenceCallBackBlock(&PspLoadImageNotifyRoutine[i]);
+        if (CallBack)
+        {
+            /* Check for a match */
+            if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
+            {
+                /* Try removing it if it matches */
+                if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
+                                              NULL,
+                                              CallBack))
+                {
+                    /* We removed it, now dereference the block */
+                    InterlockedDecrement(&PspLoadImageNotifyRoutineCount);
+                    ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i],
+                                               CallBack);
+
+                    /* Wait for active callbacks */
+                    ExWaitForCallBacks(CallBack);
+
+                    /* Free the callback and return */
+                    ExFreeCallBack(CallBack);
+                    return STATUS_SUCCESS;
+                }
+            }
+
+            /* Dereference the callback */
+            ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i], CallBack);
+        }
+    }
+
+    /* Nothing found to remove */
+    return STATUS_PROCEDURE_NOT_FOUND;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
+{
+    ULONG i;
+    PEX_CALLBACK_ROUTINE_BLOCK CallBack;
+    PAGED_CODE();
+
+    /* Allocate a callback */
+    CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
+    if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Loop callbacks */
+    for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
+    {
+        /* Add this entry if the slot is empty */
+        if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
+                                      CallBack,
+                                      NULL))
+        {
+            /* Return success */
+            InterlockedIncrement(&PspLoadImageNotifyRoutineCount);
+            PsImageNotifyEnabled = TRUE;
             return STATUS_SUCCESS;
         }
     }
-    /* Nothing found */
-    return STATUS_INVALID_PARAMETER;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
-{
-    ULONG i;
-
-    /* Loop the routines */
-    for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
-    {
-        /* Find an empty one */
-        if (!PspLoadImageNotifyRoutine[i])
-        {
-            /* Add it */
-            PspLoadImageNotifyRoutine[i] = NotifyRoutine;
+    /* No free space found, fail */
+    ExFreeCallBack(CallBack);
+    return STATUS_INSUFFICIENT_RESOURCES;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+PsRemoveCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
+{
+    ULONG i;
+    PEX_CALLBACK_ROUTINE_BLOCK CallBack;
+    PAGED_CODE();
+
+    /* Loop all callbacks */
+    for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
+    {
+        /* Reference this slot */
+        CallBack = ExReferenceCallBackBlock(&PspThreadNotifyRoutine[i]);
+        if (CallBack)
+        {
+            /* Check for a match */
+            if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
+            {
+                /* Try removing it if it matches */
+                if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
+                                              NULL,
+                                              CallBack))
+                {
+                    /* We removed it, now dereference the block */
+                    InterlockedDecrement(&PspThreadNotifyRoutineCount);
+                    ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i],
+                                               CallBack);
+
+                    /* Wait for active callbacks */
+                    ExWaitForCallBacks(CallBack);
+
+                    /* Free the callback and return */
+                    ExFreeCallBack(CallBack);
+                    return STATUS_SUCCESS;
+                }
+            }
+
+            /* Dereference the callback */
+            ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i], CallBack);
+        }
+    }
+
+    /* Nothing found to remove */
+    return STATUS_PROCEDURE_NOT_FOUND;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
+{
+    ULONG i;
+    PEX_CALLBACK_ROUTINE_BLOCK CallBack;
+    PAGED_CODE();
+
+    /* Allocate a callback */
+    CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
+    if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Loop callbacks */
+    for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
+    {
+        /* Add this entry if the slot is empty */
+        if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
+                                      CallBack,
+                                      NULL))
+        {
+            /* Return success */
+            InterlockedIncrement(&PspThreadNotifyRoutineCount);
             return STATUS_SUCCESS;
         }
     }
-    /* Nothing found */
-    return STATUS_INVALID_PARAMETER;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-PsRemoveCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
-{
-    ULONG i;
-
-    /* Loop the routines */
-    for(i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
-    {
-        /* Check for a match */
-        if (PspThreadNotifyRoutine[i] == NotifyRoutine)
-        {
-            /* Remove and return */
-            PspThreadNotifyRoutine[i] = NULL;
-            return STATUS_SUCCESS;
-        }
-    }
-
-    /* Nothing found */
-    return STATUS_INVALID_PARAMETER;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
-{
-    /* Make sure we didn't register too many */
-    if (PspThreadNotifyRoutineCount >= PSP_MAX_CREATE_THREAD_NOTIFY)
-    {
-        /* Fail */
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /* Register this one */
-    PspThreadNotifyRoutine[PspThreadNotifyRoutineCount++] = NotifyRoutine;
-    return STATUS_SUCCESS;
+    /* No free space found, fail */
+    ExFreeCallBack(CallBack);
+    return STATUS_INSUFFICIENT_RESOURCES;
 }
 /* EOF */