- Changed IopCompleteRequest back to the old schematics (rev 14933) with some minor corrections.    
- The status results are always set before an event is signaled.    
- Some checks for ASYNC irp's were wrong (missing brackets, now replaced with SyncIrp).    
- Don't signal the FO event if it is the same as the UserEvent.  
- Set the IOSB on error for async irp's with a sync FO (fix bug #609).    

IMHO, the old schematics is wrong, because on error it is possible that an event
isn't signaled if the driver has previous returned STATUS_PENDING.   
In this case, the caller will wait forever.
Modified: trunk/reactos/ntoskrnl/io/irp.c

Modified: trunk/reactos/ntoskrnl/io/irp.c
--- trunk/reactos/ntoskrnl/io/irp.c	2005-05-08 06:22:12 UTC (rev 15116)
+++ trunk/reactos/ntoskrnl/io/irp.c	2005-05-08 10:26:34 UTC (rev 15117)
@@ -117,6 +117,162 @@
     RemoveEntryList(&Irp->ThreadListEntry);
     InitializeListHead(&Irp->ThreadListEntry);  
 
+#if 1
+    /* Check for Success but allow failure for Async IRPs */
+    if (NT_SUCCESS(Irp->IoStatus.Status) || 
+        (Irp->PendingReturned &&
+        !SyncIrp &&
+        (FileObject == NULL || FileObject->Flags & FO_SYNCHRONOUS_IO)))
+    {    
+        _SEH_TRY
+        {
+            /*  Save the IOSB Information */
+            *Irp->UserIosb = Irp->IoStatus;
+        }
+        _SEH_HANDLE
+        {
+            /* Ignore any error */
+        }
+        _SEH_END;
+    
+        /* Check if there's an event */
+        if (UserEvent)
+        {
+            /* Check if we should signal the File Object Event as well */
+            if (FileObject)
+            {
+                 /* If the File Object is SYNC, then we need to signal its event too */
+                if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+                {
+                    /* Set the Status */
+                    FileObject->FinalStatus = Irp->IoStatus.Status;
+
+                    /* Signal Event */
+                    KeSetEvent(&FileObject->Event, 0, FALSE);
+                }
+            }
+            /* Signal the Event */
+            KeSetEvent(UserEvent, 0, FALSE);
+
+            /* Dereference the Event if this is an ASYNC IRP */
+	    if (FileObject && !SyncIrp && UserEvent != &FileObject->Event)
+	    {
+                ObDereferenceObject(UserEvent);
+	    }
+        }
+        else if (FileObject)
+        {
+            /* Set the Status */
+            FileObject->FinalStatus = Irp->IoStatus.Status;
+
+            /* Signal the File Object Instead */
+            KeSetEvent(&FileObject->Event, 0, FALSE);
+        
+        }
+    
+        /* Now call the User APC if one was requested */
+        if (Irp->Overlay.AsynchronousParameters.UserApcRoutine != NULL)
+        {
+            KeInitializeApc(&Irp->Tail.Apc,
+                            KeGetCurrentThread(),
+                            CurrentApcEnvironment,
+                            IopFreeIrpKernelApc,
+                            IopAbortIrpKernelApc,
+                            (PKNORMAL_ROUTINE)Irp->Overlay.AsynchronousParameters.UserApcRoutine,
+                            Irp->RequestorMode,
+                            Irp->Overlay.AsynchronousParameters.UserApcContext);
+
+            KeInsertQueueApc(&Irp->Tail.Apc,
+                             Irp->UserIosb,
+                             NULL,
+                             2);
+	    Irp = NULL;
+        }
+        else if (FileObject && FileObject->CompletionContext)
+        {
+            /* Call the IO Completion Port if we have one, instead */
+            IoSetIoCompletion(FileObject->CompletionContext->Port,
+                              FileObject->CompletionContext->Key,
+                              Irp->Overlay.AsynchronousParameters.UserApcContext,
+                              Irp->IoStatus.Status,
+                              Irp->IoStatus.Information,
+                              FALSE);
+	    Irp = NULL;
+        }
+    }
+    else
+    {   
+        /* Signal the Events only if PendingReturned and we have a File Object */
+        if (FileObject && Irp->PendingReturned)
+        {
+            /* Check for SYNC IRP */
+            if (SyncIrp)
+            {
+                /* Set the status in this case only */
+		_SEH_TRY
+		{
+		    *Irp->UserIosb = Irp->IoStatus;
+		}
+		_SEH_HANDLE
+		{
+		    /* Ignore any error */
+		}
+		_SEH_END;
+            
+                /* Signal our event if we have one */
+                if (UserEvent)
+                {
+                    KeSetEvent(UserEvent, 0, FALSE);
+                }
+                else
+                {
+                    /* Signal the File's Event instead */
+                    KeSetEvent(&FileObject->Event, 0, FALSE);
+                }
+            }
+            else
+            {
+#if 1
+		/* FIXME: This is necessary to fix bug #609 */ 
+		_SEH_TRY
+		{
+		    *Irp->UserIosb = Irp->IoStatus;
+		}
+		_SEH_HANDLE
+		{
+		    /* Ignore any error */
+		}
+		_SEH_END;
+#endif
+                /* We'll report the Status to the File Object, not the IRP */
+                FileObject->FinalStatus = Irp->IoStatus.Status;
+                
+                /* Signal the File Object ONLY if this was Async */
+                KeSetEvent(&FileObject->Event, 0, FALSE);
+            }
+        }
+        
+        /* Dereference the Event if it's an ASYNC IRP on a File Object */
+        if (UserEvent && !SyncIrp && FileObject)
+        {
+            if (UserEvent != &FileObject->Event)
+            {
+                ObDereferenceObject(UserEvent);
+            }   
+        }
+    }        
+    
+    /* Dereference the File Object */
+    if (FileObject) ObDereferenceObject(FileObject);
+        
+    if (Irp)
+    {
+	/* Free the IRP */
+        IoFreeIrp(Irp);
+    }
+
+#else
+
     if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->PendingReturned)
     {
         _SEH_TRY
@@ -198,6 +354,7 @@
         /* Dereference the File Object */
         ObDereferenceObject(FileObject);
     }
+#endif
 }
 
 /* FUNCTIONS *****************************************************************/