Index: trunk/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp	(revision 19187)
+++ trunk/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp	(revision 19562)
@@ -47,4 +47,5 @@
 #include <sys/event.h>
 #include <sys/time.h>
+#include <sys/sysctl.h>
 #include <aio.h>
 #include <errno.h>
@@ -84,4 +85,6 @@
      *  element. */
     struct aiocb           AioCB;
+    /** Current state the request is in. */
+    RTFILEAIOREQSTATE      enmState;
     /** Flag whether this is a flush request. */
     bool                   fFlush;
@@ -107,4 +110,37 @@
 #define AIO_MAXIMUM_REQUESTS_PER_CONTEXT 64
 
+RTR3DECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits)
+{
+    int rcBSD = 0;
+    AssertPtrReturn(pAioLimits, VERR_INVALID_POINTER);
+
+    /*
+     * The AIO API is implemented in a kernel module which is not
+     * loaded by default.
+     * If it is loaded there are additional sysctl parameters.
+     */
+    int cReqsOutstandingMax = 0;
+    size_t cbParameter = sizeof(int);
+
+    rcBSD = sysctlbyname("vfs.aio.max_aio_per_proc", /* name */
+                         &cReqsOutstandingMax,       /* Where to store the old value. */
+                         &cbParameter,               /* Size of the memory pointed to. */
+                         NULL,                       /* Where the new value is located. */
+                         NULL);                      /* Where the size of the new value is stored. */
+    if (rcBSD == -1)
+    {
+        /* ENOENT means the value is unknown thus the module is not loaded. */
+        if (errno == ENOENT)
+            return VERR_NOT_SUPPORTED;
+        else
+            return RTErrConvertFromErrno(errno);
+    }
+
+    pAioLimits->cReqsOutstandingMax = cReqsOutstandingMax;
+    pAioLimits->cbBufferAlignment   = 0;
+
+    return VINF_SUCCESS;
+}
+
 RTR3DECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq)
 {
@@ -120,4 +156,5 @@
     pReqInt->pCtxInt                   = NULL;
     pReqInt->u32Magic                  = RTFILEAIOREQ_MAGIC;
+    RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
 
     *phReq = (RTFILEAIOREQ)pReqInt;
@@ -126,5 +163,5 @@
 }
 
-RTDECL(void) RTFileAioReqDestroy(RTFILEAIOREQ hReq)
+RTDECL(int) RTFileAioReqDestroy(RTFILEAIOREQ hReq)
 {
     /*
@@ -132,7 +169,8 @@
      */
     if (hReq == NIL_RTFILEAIOREQ)
-        return;
+        return VINF_SUCCESS;
     PRTFILEAIOREQINTERNAL pReqInt = hReq;
-    RTFILEAIOREQ_VALID_RETURN_VOID(pReqInt);
+    RTFILEAIOREQ_VALID_RETURN(pReqInt);
+    RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
 
     /*
@@ -141,4 +179,5 @@
     ASMAtomicUoWriteU32(&pReqInt->u32Magic, ~RTFILEAIOREQ_MAGIC);
     RTMemFree(pReqInt);
+    return VINF_SUCCESS;
 }
 
@@ -156,4 +195,5 @@
     PRTFILEAIOREQINTERNAL pReqInt = hReq;
     RTFILEAIOREQ_VALID_RETURN(pReqInt);
+    RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
     Assert(hFile != NIL_RTFILE);
     AssertPtr(pvBuf);
@@ -171,4 +211,5 @@
     pReqInt->pCtxInt              = NULL;
     pReqInt->Rc                   = VERR_FILE_AIO_IN_PROGRESS;
+    RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
 
     return VINF_SUCCESS;
@@ -195,8 +236,10 @@
     RTFILEAIOREQ_VALID_RETURN(pReqInt);
     Assert(hFile != NIL_RTFILE);
+    RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
 
     pReqInt->fFlush           = true;
     pReqInt->AioCB.aio_fildes = (int)hFile;
     pReqInt->pvUser           = pvUser;
+    RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
 
     return VINF_SUCCESS;
@@ -215,4 +258,6 @@
     PRTFILEAIOREQINTERNAL pReqInt = hReq;
     RTFILEAIOREQ_VALID_RETURN(pReqInt);
+    RTFILEAIOREQ_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_NOT_SUBMITTED);
+
 
     int rcBSD = aio_cancel(pReqInt->AioCB.aio_fildes, &pReqInt->AioCB);
@@ -228,4 +273,6 @@
 
         ASMAtomicDecS32(&pReqInt->pCtxInt->cRequests);
+        pReqInt->Rc = VERR_FILE_AIO_CANCELED;
+        RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
         return VINF_SUCCESS;
     }
@@ -243,6 +290,8 @@
     RTFILEAIOREQ_VALID_RETURN(pReqInt);
     AssertPtrNull(pcbTransfered);
-
-    if (  (pReqInt->Rc != VERR_FILE_AIO_IN_PROGRESS)
+    RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
+    RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, PREPARED, VERR_FILE_AIO_NOT_SUBMITTED);
+
+    if (  (RT_SUCCESS(pReqInt->Rc))
         && (pcbTransfered))
         *pcbTransfered = pReqInt->cbTransfered;
@@ -306,11 +355,10 @@
 }
 
-RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs, size_t *pcReqs)
+RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs)
 {
     /*
      * Parameter validation.
      */
-    AssertPtrReturn(pcReqs, VERR_INVALID_POINTER);
-    *pcReqs = 0;
+    int rc = VINF_SUCCESS;
     PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
     RTFILEAIOCTX_VALID_RETURN(pCtxInt);
@@ -330,8 +378,21 @@
         {
             pReqInt = pahReqs[i];
-            RTFILEAIOREQ_VALID_RETURN(pReqInt);
+            if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt))
+            {
+                /* Undo everything and stop submitting. */
+                for (size_t iUndo = 0; iUndo < i; iUndo++)
+                {
+                    pReqInt = pahReqs[iUndo];
+                    RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
+                    pReqInt->pCtxInt = NULL;
+                    pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = 0;
+                }
+                rc = VERR_INVALID_HANDLE;
+                break;
+            }
 
             pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = pCtxInt->iKQueue;
             pReqInt->pCtxInt                                = pCtxInt;
+            RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED);
 
             if (pReqInt->fFlush)
@@ -346,10 +407,36 @@
             rcBSD = lio_listio(LIO_NOWAIT, (struct aiocb **)pahReqs, cReqsSubmit, NULL);
             if (RT_UNLIKELY(rcBSD < 0))
-                return RTErrConvertFromErrno(errno);
+            {
+                if (rcBSD == EAGAIN)
+                    rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES;
+                else
+                    rc = RTErrConvertFromErrno(errno);
+
+                /* Check which requests got actually submitted and which not. */
+                for (i = 0; i < cReqs; i++)
+                {
+                    pReqInt = pahReqs[i];
+                    rcBSD = aio_error(&pReqInt->AioCB);
+                    if (rcBSD == EINVAL)
+                    {
+                        /* Was not submitted. */
+                        RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
+                        pReqInt->pCtxInt = NULL;
+                    }
+                    else if (rcBSD != EINPROGRESS)
+                    {
+                        /* The request encountered an error. */
+                        RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
+                        pReqInt->Rc = RTErrConvertFromErrno(rcBSD);
+                        pReqInt->pCtxInt      = NULL;
+                        pReqInt->cbTransfered = 0;
+                    }
+                }
+                break;
+            }
 
             ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmit);
             cReqs   -= cReqsSubmit;
             pahReqs += cReqsSubmit;
-            *pcReqs += cReqsSubmit;
         }
 
@@ -368,15 +455,19 @@
                  rcBSD = aio_fsync(O_SYNC, &pReqInt->AioCB);
                  if (RT_UNLIKELY(rcBSD < 0))
-                    return RTErrConvertFromErrno(errno);
+                 {
+                    RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
+                    pReqInt->Rc = RTErrConvertFromErrno(errno);
+                    pReqInt->cbTransfered = 0;
+                    return pReqInt->Rc;
+                 }
 
                 ASMAtomicIncS32(&pCtxInt->cRequests);
                 cReqs--;
                 pahReqs++;
-                *pcReqs++;
             }
         }
     } while (cReqs);
 
-    return VINF_SUCCESS;
+    return rc;
 }
 
@@ -447,4 +538,6 @@
         {
             PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aKEvents[i].udata;
+            AssertPtr(pReqInt);
+            Assert(pReqInt->u32Magic == RTFILEAIOREQ_MAGIC);
 
             /*
@@ -468,4 +561,5 @@
                 pReqInt->cbTransfered = cbTransfered;
             }
+            RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
             pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
         }
