private unsafe void ReadFromPipe(AsyncExecutionQueue?executionEngine)
 {
     if (executionEngine == null)
     {
         Span <byte> buffer = stackalloc byte[128];
         int         rv     = IoPal.Read(_pipeReadEnd !, buffer);
         if (rv == -1)
         {
             if (errno != EAGAIN)
             {
                 PlatformException.Throw();
             }
         }
     }
     else
     {
         if (_dummyReadBuffer == null)
         {
             _dummyReadBuffer = new byte[128];
         }
         executionEngine.AddRead(_pipeReadEnd !, _dummyReadBuffer,
                                 (AsyncOperationResult result, object?state, int data) =>
         {
             if (result.IsError && result.Errno != EAGAIN)
             {
                 PlatformException.Throw();
             }
         }, state: null, data: 0);
     }
 }
 private unsafe void ReadFromPipe(AsyncExecutionQueue?executionEngine)
 {
     if (executionEngine == null)
     {
         Span <byte> buffer = stackalloc byte[128];
         int         rv     = IoPal.Read(_pipeReadEnd !, buffer);
         if (rv == -1)
         {
             if (errno != EAGAIN)
             {
                 PlatformException.Throw();
             }
         }
     }
     else
     {
         if (_dummyReadBuffer == null)
         {
             _dummyReadBuffer = new byte[128];
         }
         executionEngine.AddRead(_pipeReadEnd !, _dummyReadBuffer, this, data: 0);
     }
 }
Beispiel #3
0
 public override AsyncExecutionResult TryExecuteEpollAsync(bool triggeredByPoll, AsyncExecutionQueue?executionQueue, IAsyncExecutionResultHandler callback)
 => throw new System.InvalidOperationException();
        public override AsyncExecutionResult TryExecute(bool triggeredByPoll, bool isCancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult asyncResult)
        {
            Socket socket = Socket !;

            // When there is a pollable executionQueue, use it to poll, and then try the operation.
            bool hasPollableExecutionQueue = executionQueue?.SupportsPolling == true;
            bool trySync = !hasPollableExecutionQueue && !asyncOnly;

            if (trySync || asyncResult.HasResult)
            {
                (SocketError socketError, Socket? acceptedSocket) = SocketPal.Accept(socket.SafeHandle);
                if (socketError != SocketError.WouldBlock)
                {
                    SocketError    = socketError;
                    AcceptedSocket = acceptedSocket;
                    return(AsyncExecutionResult.Finished);
                }
            }

            if (isCancellationRequested)
            {
                SocketError = SocketError.OperationAborted;
                return(AsyncExecutionResult.Cancelled);
            }

            // poll
            if (hasPollableExecutionQueue)
            {
                executionQueue !.AddPollIn(socket.SafeHandle, callback !, state, data);;
                return(AsyncExecutionResult.Executing);
            }
            else
            {
                return(AsyncExecutionResult.WaitForPoll);
            }
        }
        public override AsyncExecutionResult TryExecuteEpollAsync(bool triggeredByPoll, AsyncExecutionQueue?executionQueue, IAsyncExecutionResultHandler callback)
        {
            bool finished = TryExecuteSync();

            return(finished ? AsyncExecutionResult.Finished : AsyncExecutionResult.WaitForPoll);
        }
Beispiel #6
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);
        }
Beispiel #7
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);
 }
Beispiel #8
0
        public override AsyncExecutionResult TryExecute(bool triggeredByPoll, bool isCancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult asyncResult)
        {
            IList <ArraySegment <byte> >?bufferList = BufferList;

            if (bufferList == null)
            {
                return(SendSingleBuffer(MemoryBuffer, isCancellationRequested, asyncOnly, executionQueue, callback, state, data, asyncResult));
            }
            else
            {
                return(SendMultipleBuffers(bufferList, isCancellationRequested, asyncOnly, executionQueue, callback, state, data, asyncResult));
            }
        }
Beispiel #9
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);
Beispiel #10
0
        public override AsyncExecutionResult TryExecute(bool triggeredByPoll, bool isCancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult asyncResult)
        {
            Socket     socket     = Socket !;
            IPEndPoint?ipEndPoint = EndPoint as IPEndPoint;

            if (ipEndPoint == null)
            {
                ThrowHelper.ThrowInvalidOperationException();
            }

            // When there is a pollable executionQueue, use it to poll, and then try the operation.
            bool hasPollableExecutionQueue = executionQueue?.SupportsPolling == true;
            bool trySync = !hasPollableExecutionQueue && !asyncOnly;

            if (trySync || asyncResult.HasResult)
            {
                SocketError socketError;
                if (!_connectCalled)
                {
                    socketError    = SocketPal.Connect(socket.SafeHandle, ipEndPoint);
                    _connectCalled = true;
                }
                else
                {
                    // TODO: read SOL_SOCKET, SO_ERROR to get errorcode...
                    socketError = SocketError.Success;
                }
                if (socketError != SocketError.InProgress)
                {
                    SocketError = socketError;
                    return(AsyncExecutionResult.Finished);
                }
            }

            if (isCancellationRequested)
            {
                SocketError = SocketError.OperationAborted;
                return(AsyncExecutionResult.Cancelled);
            }

            // poll
            if (hasPollableExecutionQueue)
            {
                executionQueue !.AddPollOut(socket.SafeHandle, callback !, state, data);
                return(AsyncExecutionResult.Executing);
            }
            else
            {
                return(AsyncExecutionResult.WaitForPoll);
            }
        }
Beispiel #11
0
 public override AsyncExecutionResult TryExecute(bool triggeredByPoll, bool cancellationRequested, bool asyncOnly, AsyncExecutionQueue?executionQueue, AsyncExecutionCallback?callback, object?state, int data, AsyncOperationResult result)
 => throw new System.InvalidOperationException();
 public override AsyncExecutionResult TryExecuteEpollAsync(bool triggeredByPoll, AsyncExecutionQueue?executionQueue, IAsyncExecutionResultHandler callback)
 {
     if (!_connectCalled)
     {
         _connectCalled = true;
         bool finished = TryExecuteSync();
         return(finished ? AsyncExecutionResult.Finished : AsyncExecutionResult.WaitForPoll);
     }
     else
     {
         if (triggeredByPoll)
         {
             // TODO: read SOL_SOCKET, SO_ERROR to get errorcode...
             SocketError = SocketError.Success;
             return(AsyncExecutionResult.Finished);
         }
         return(AsyncExecutionResult.WaitForPoll);
     }
 }
Beispiel #13
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);
        }
 public override AsyncExecutionResult TryExecuteEpollAsync(bool triggeredByPoll, AsyncExecutionQueue?executionQueue, IAsyncExecutionResultHandler callback)
 {
     if (executionQueue != null)
     {
         return(TryExecuteAsync(executionQueue, callback, data: 0));
     }
     else
     {
         bool finished = TryExecuteSync();
         return(finished ? AsyncExecutionResult.Finished : AsyncExecutionResult.WaitForPoll);
     }
 }
        public override AsyncExecutionResult TryExecuteEpollAsync(bool triggeredByPoll, AsyncExecutionQueue?executionQueue, IAsyncExecutionResultHandler callback)
        {
            Memory <byte> memory            = MemoryBuffer;
            bool          isPollingReadable = memory.Length == 0; // A zero-byte read is a poll.

            if (executionQueue != null && !isPollingReadable)
            {
                Socket socket = Socket !;
                executionQueue.AddRead(socket.SafeHandle, MemoryBuffer, callback !, data: 0);
                return(AsyncExecutionResult.Executing);
            }
            else
            {
                if (triggeredByPoll && isPollingReadable)
                {
                    // No need to make a syscall, poll told us we're readable.
                    SocketError      = SocketError.Success;
                    BytesTransferred = 0;
                    return(AsyncExecutionResult.Finished);
                }
                bool finished = TryExecuteSync();
                return(finished ? AsyncExecutionResult.Finished : AsyncExecutionResult.WaitForPoll);
            }
        }