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);
                }
            }
Exemple #2
0
            private AsyncOperation?CompleteOperationAndGetNext(AsyncOperation op, AsyncExecutionResult result)
            {
                if (result == AsyncExecutionResult.Finished)
                {
                    op.Status = OperationStatus.Completed;
                }
                else // AsyncExecutionResult.WaitForPoll or Cancelled
                {
                    if (result == AsyncExecutionResult.WaitForPoll)
                    {
                        OperationStatus previous = op.CompareExchangeStatus(OperationStatus.Queued, OperationStatus.Executing);
                        if (previous == OperationStatus.Executing)
                        {
                            // We've changed from executing to queued.
                            return(null);
                        }
                        Debug.Assert((previous & OperationStatus.CancellationRequested) != 0);
                    }
                    op.Status = (op.Status & ~(OperationStatus.CancellationRequested | OperationStatus.Executing)) | OperationStatus.Cancelled;
                }

                AsyncOperation?next = DequeueFirstAndGetNext(op);

                op.Complete();

                return(next);
            }
Exemple #3
0
            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);
                }
            }
Exemple #4
0
            public void ExecuteQueued(bool triggeredByPoll, AsyncOperation?op = null)
            {
                if (triggeredByPoll)
                {
                    Interlocked.Increment(ref _eventCounter);
                }

                op ??= QueueGetFirst();
                do
                {
                    var spin = new SpinWait();
                    while (true)
                    {
                        if (op is null)
                        {
                            return;
                        }
                        OperationStatus previous = op.CompareExchangeStatus(OperationStatus.Executing, OperationStatus.Queued);
                        if (previous == OperationStatus.Queued)
                        {
                            // We've changed from queued to executing.
                            break;
                        }
                        else if ((previous & OperationStatus.Executing) != 0) // Also set when CancellationRequested.
                        {
                            // Already executing.
                            return;
                        }
                        // Operation was cancelled, but not yet removed from queue.
                        Debug.Assert((previous & OperationStatus.Cancelled) != 0);
                        spin.SpinOnce();
                        op = QueueGetFirst();
                    }

                    AsyncExecutionResult result = op.TryExecuteEpollAsync(triggeredByPoll, _thread.ExecutionQueue, this);

                    if (result == AsyncExecutionResult.Executing)
                    {
                        _executingOperation = op;
                        return;
                    }

                    op = CompleteOperationAndGetNext(op, result);
                } while (op != null);
            }
Exemple #5
0
 private unsafe AsyncExecutionResult SendMultipleBuffers(IList <ArraySegment <byte> > buffers, bool isCancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult asyncResult)
 {
     // TODO: really support multi-buffer sends...
     for (; _bufferIndex < buffers.Count; _bufferIndex++)
     {
         AsyncExecutionResult bufferSendResult = SendSingleBuffer(buffers[_bufferIndex], isCancellationRequested, asyncOnly, executionQueue, callback, state, data, asyncResult);
         if (bufferSendResult == AsyncExecutionResult.WaitForPoll || bufferSendResult == AsyncExecutionResult.Executing)
         {
             return(bufferSendResult);
         }
         if (SocketError != SocketError.Success)
         {
             break;
         }
         BytesTransferred = 0; // TODO... not really correct
     }
     return(AsyncExecutionResult.Finished);
 }
            private AsyncOperation?CompleteOperationAndGetNext(AsyncOperation op, AsyncExecutionResult result)
            {
                if (result == AsyncExecutionResult.Finished)
                {
                    op.Status = OperationStatus.Completed;
                }
                else // Cancelled
                {
                    op.Status = (op.Status & ~(OperationStatus.CancellationRequested | OperationStatus.Executing)) | OperationStatus.Cancelled;
                }

                Volatile.Write(ref _cancellingOperation, null);

                AsyncOperation?next = DequeueFirstAndGetNext(op);

                op.Complete();

                return(next);
            }
Exemple #7
0
        private AsyncExecutionResult SendSingleBuffer(Memory <byte> memory, bool isCancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult asyncResult)
        {
            SocketError          socketError = SocketError.SocketError;
            AsyncExecutionResult result      = AsyncExecutionResult.Executing;

            if (asyncResult.HasResult)
            {
                if (asyncResult.IsError)
                {
                    if (asyncResult.Errno == EINTR)
                    {
                        result = AsyncExecutionResult.Executing;
                    }
                    else if (asyncResult.Errno == EAGAIN)
                    {
                        result = AsyncExecutionResult.WaitForPoll;
                    }
                    else
                    {
                        socketError = SocketPal.GetSocketErrorForErrno(asyncResult.Errno);
                        result      = AsyncExecutionResult.Finished;
                    }
                }
                else
                {
                    BytesTransferred += asyncResult.IntValue;
                    if (BytesTransferred == memory.Length)
                    {
                        socketError = SocketError.Success;
                        result      = AsyncExecutionResult.Finished;
                    }
                }
            }

            if (isCancellationRequested && result != AsyncExecutionResult.Finished)
            {
                SocketError = SocketError.OperationAborted;
                return(AsyncExecutionResult.Cancelled);
            }

            // When there is a pollable executionQueue, use it to poll, and then try the operation.
            if (result == AsyncExecutionResult.Executing ||
                (result == AsyncExecutionResult.WaitForPoll && executionQueue?.SupportsPolling == true))
            {
                Socket socket = Socket !;
                if (socket == null)
                {
                    ThrowHelper.ThrowInvalidOperationException();
                }

                if (executionQueue != null)
                {
                    Memory <byte> remaining = memory.Slice(BytesTransferred);
                    executionQueue.AddWrite(socket.SafeHandle, remaining, callback !, state, data);
                    result = AsyncExecutionResult.Executing;
                }
                else if (result == AsyncExecutionResult.Executing)
                {
                    if (asyncOnly)
                    {
                        result = AsyncExecutionResult.WaitForPoll;
                    }
                    else
                    {
                        while (true)
                        {
                            Memory <byte> remaining = memory.Slice(BytesTransferred);
                            int           bytesTransferred;
                            (socketError, bytesTransferred) = SocketPal.Send(socket.SafeHandle, remaining);
                            if (socketError == SocketError.Success)
                            {
                                BytesTransferred += bytesTransferred;
                                if (BytesTransferred == memory.Length || bytesTransferred == 0)
                                {
                                    break;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        result = socketError == SocketError.WouldBlock ? AsyncExecutionResult.WaitForPoll : AsyncExecutionResult.Finished;
                    }
                }
            }

            if (result == AsyncExecutionResult.Finished)
            {
                SocketError = socketError;
            }

            return(result);
        }
Exemple #8
0
        public override AsyncExecutionResult TryExecute(bool triggeredByPoll, bool isCancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult asyncResult)
        {
            SocketError          socketError      = SocketError.SocketError;
            int                  bytesTransferred = -1;
            AsyncExecutionResult result           = AsyncExecutionResult.Executing;

            if (asyncResult.HasResult)
            {
                if (asyncResult.IsError)
                {
                    if (asyncResult.Errno == EINTR)
                    {
                        result = AsyncExecutionResult.Executing;
                    }
                    else if (asyncResult.Errno == EAGAIN)
                    {
                        result = AsyncExecutionResult.WaitForPoll;
                    }
                    else
                    {
                        bytesTransferred = 0;
                        socketError      = SocketPal.GetSocketErrorForErrno(asyncResult.Errno);
                        result           = AsyncExecutionResult.Finished;
                    }
                }
                else
                {
                    bytesTransferred = asyncResult.IntValue;
                    socketError      = SocketError.Success;
                    result           = AsyncExecutionResult.Finished;
                }
            }

            if (isCancellationRequested && result != AsyncExecutionResult.Finished)
            {
                SocketError = SocketError.OperationAborted;
                return(AsyncExecutionResult.Cancelled);
            }

            // When there is a pollable executionQueue, use it to poll, and then try the operation.
            if (result == AsyncExecutionResult.Executing ||
                (result == AsyncExecutionResult.WaitForPoll && executionQueue?.SupportsPolling == true))
            {
                Memory <byte> memory            = MemoryBuffer;
                bool          isPollingReadable = memory.Length == 0; // A zero-byte read is a poll.
                if (triggeredByPoll && isPollingReadable)
                {
                    // No need to make a syscall, poll told us we're readable.
                    (socketError, bytesTransferred) = (SocketError.Success, 0);
                    result = AsyncExecutionResult.Finished;
                }
                else
                {
                    Socket socket = Socket !;

                    // Using Linux AIO executionQueue, we can't check when there is no
                    // data available. Instead of return value EAGAIN, a 0-byte read returns '0'.
                    if (executionQueue != null &&
                        (!isPollingReadable || executionQueue.SupportsPolling)) // Don't use Linux AIO for 0-byte reads.
                    {
                        executionQueue.AddRead(socket.SafeHandle, memory, callback !, state, data);
                        result = AsyncExecutionResult.Executing;
                    }
                    else if (result == AsyncExecutionResult.Executing)
                    {
                        if (asyncOnly)
                        {
                            result = AsyncExecutionResult.WaitForPoll;
                        }
                        else
                        {
                            (socketError, bytesTransferred) = SocketPal.Recv(socket.SafeHandle, memory);
                            result = socketError == SocketError.WouldBlock ? AsyncExecutionResult.WaitForPoll : AsyncExecutionResult.Finished;
                        }
                    }
                }
            }

            if (result == AsyncExecutionResult.Finished)
            {
                Debug.Assert(bytesTransferred != -1);
                BytesTransferred = bytesTransferred;
                SocketError      = socketError;
            }

            return(result);
        }