void IAsyncExecutionResultHandler.HandleAsyncResult(AsyncOperationResult aResult) { AsyncOperation?op = _executingOperation !; AsyncExecutionResult result = op.HandleAsyncResult(aResult); if (result != AsyncExecutionResult.Finished && op.IsCancellationRequested) { result = AsyncExecutionResult.Cancelled; } if (result == AsyncExecutionResult.Executing || result == AsyncExecutionResult.WaitForPoll) { result = op.TryExecuteIOUringAsync(_thread.ExecutionQueue, this, _keyForOperation); Debug.Assert(result == AsyncExecutionResult.Executing); return; } _executingOperation = null; AsyncOperation?next = CompleteOperationAndGetNext(op, result); if (next != null) { ExecuteQueued(next); } }
public void ExecuteQueued(AsyncOperationResult asyncResult) { AsyncOperation?completedTail = null; lock (Gate) { if (_tail is { } && _tail != AsyncOperation.DisposedSentinel)
void IAsyncExecutionResultHandler.HandleAsyncResult(AsyncOperationResult result) { if (result.IsError && result.Errno != EAGAIN) { PlatformException.Throw(); } }
void IAsyncExecutionResultHandler.HandleAsyncResult(AsyncOperationResult aResult) { AsyncOperation?op = _executingOperation !; AsyncExecutionResult result = op.HandleAsyncResult(aResult); if (result != AsyncExecutionResult.Finished && op.IsCancellationRequested) { result = AsyncExecutionResult.Cancelled; } if (result == AsyncExecutionResult.Executing) { result = op.TryExecuteEpollAsync(triggeredByPoll: false, _thread.ExecutionQueue, this); if (result == AsyncExecutionResult.Executing) { return; } } _executingOperation = null; AsyncOperation?next = CompleteOperationAndGetNext(op, result); if (next != null) { ExecuteQueued(triggeredByPoll: false, next); } }
public void ExecuteQueued(bool triggeredByPoll, AsyncOperationResult asyncResult) { AsyncOperation?completedTail = null; lock (Gate) { _eventCounter++; if (_tail is { } && _tail != AsyncOperation.DisposedSentinel)
void IAsyncExecutionResultHandler.HandleAsyncResult(AsyncOperationResult asyncResult) { // TODO: do we need to do a volatile read of _disposed? if (asyncResult.Errno == EAGAIN || (!asyncResult.IsError && asyncResult.Value == 8)) { AddReadFromEventFd(); } else if (asyncResult.IsError) { PlatformException.Throw(asyncResult.Errno); } else { ThrowHelper.ThrowIndexOutOfRange(asyncResult.Value); } }
public override AsyncExecutionResult HandleAsyncResult(AsyncOperationResult result) => throw new System.InvalidOperationException();
public unsafe bool ExecuteOperations() { List <Operation>?scheduled = _scheduledOperations; if (scheduled == null) { return(false); } _scheduledOperations = _cachedOperationsList; _cachedOperationsList = null; if (_results == null || _results.Length < scheduled.Count) { _results = new AsyncOperationResult[Math.Max(scheduled.Count, 2 * (_results?.Length ?? 0))]; } AsyncOperationResult[] results = _results; int queueLength = scheduled.Count; int queueOffset = 0; while (queueOffset < queueLength) { int nr = Math.Min((queueLength - queueOffset), IocbLength); try { iocb *aioCbs = AioCbs; for (int i = queueOffset; i < (queueOffset + nr); i++) { Operation op = scheduled[i]; int fd = op.Handle.DangerousGetHandle().ToInt32(); // TODO: make safe MemoryHandle handle = op.Memory.Pin(); _memoryHandles.Add(handle); aioCbs->aio_fildes = fd; aioCbs->aio_data = (ulong)i; aioCbs->aio_lio_opcode = op.IsReadNotWrite ? IOCB_CMD_PREAD : IOCB_CMD_PWRITE; aioCbs->aio_buf = (ulong)handle.Pointer; aioCbs->aio_nbytes = (ulong)op.Memory.Length; aioCbs++; } iocb **iocbpp = AioCbsTable; int toSubmit = nr; while (toSubmit > 0) { int rv = io_submit(_ctx, toSubmit, iocbpp); if (rv == -1) { PlatformException.Throw(); } int toReceive = rv; toSubmit -= rv; iocbpp += rv; while (toReceive > 0) { do { rv = IoGetEvents(_ctx, toReceive, AioEvents); } while (rv == -1 && errno == EINTR); if (rv == -1) { PlatformException.Throw(); } io_event *events = AioEvents; for (int i = 0; i < rv; i++) { results[(int)events->data] = new AsyncOperationResult(events->res); events++; } toReceive -= rv; } } } finally { foreach (var handle in _memoryHandles) { handle.Dispose(); } _memoryHandles.Clear(); } // Callbacks for (int i = queueOffset; i < (queueOffset + nr); i++) { Operation op = scheduled[i]; op.Callback(results[i], op.State, op.Data); } queueOffset += nr; } scheduled.Clear(); if (_scheduledOperations == null) { _scheduledOperations = scheduled; return(false); } else { _cachedOperationsList = scheduled; return(_scheduledOperations.Count > 0); } }
// Continues execution of this operation. // When the operation is finished, AsyncExecutionResult.Finished is returned. // The executionQueue, when not null, can be used to batch operations. // The callback, state, and data arguments must be passed on to the executionQueue. // When the executionQueue is used, AsyncExecutionResult.Executing is returned. // When the batched operations completes, the method is called again and 'result' has a value. // The execution queue may or may not support poll operations (ExecutionQueue.SupportsPolling). // In case there is no execution queue, or the queue does not support polling, the method // can return WaitForPoll. The method will be called again when poll indicates the handle is ready, // (and triggeredByPoll is true). // When asyncOnly is set, the execution queue must be used. If it cannot be used, WaitForPoll // must be returned. // When cancellationRequested is set, the operation must finish with // AsyncExecutionResult.Finished when the operation completed using 'result'; and // AsyncOperationResult.Cancelled otherwise. public abstract AsyncExecutionResult TryExecute(bool triggeredByPoll, bool cancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult result);
public override AsyncExecutionResult TryExecute(bool triggeredByPoll, bool cancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult result) => throw new System.InvalidOperationException();