/// <remarks>PORT NOTE: matches behavior of NioEventLoop.processSelectedKey</remarks> static void OnIoCompleted(object sender, SocketAsyncEventArgs args) { var operation = (SocketChannelAsyncOperation)args; AbstractSocketChannel channel = operation.Channel; var @unsafe = (ISocketChannelUnsafe)channel.Unsafe; IEventLoop eventLoop = channel.EventLoop; switch (args.LastOperation) { case SocketAsyncOperation.Accept: if (eventLoop.InEventLoop) { @unsafe.FinishRead(operation); } else { eventLoop.Execute(ReadCallbackAction, @unsafe, operation); } break; case SocketAsyncOperation.Connect: if (eventLoop.InEventLoop) { @unsafe.FinishConnect(operation); } else { eventLoop.Execute(ConnectCallbackAction, @unsafe, operation); } break; case SocketAsyncOperation.Receive: case SocketAsyncOperation.ReceiveFrom: if (eventLoop.InEventLoop) { @unsafe.FinishRead(operation); } else { eventLoop.Execute(ReadCallbackAction, @unsafe, operation); } break; case SocketAsyncOperation.Send: case SocketAsyncOperation.SendTo: if (eventLoop.InEventLoop) { @unsafe.FinishWrite(operation); } else { eventLoop.Execute(WriteCallbackAction, @unsafe, operation); } break; default: // todo: think of a better way to comm exception throw new ArgumentException("The last operation completed on the socket was not expected"); } }
public Task ShutdownOutputAsync() { var tcs = new TaskCompletionSource(); // todo: use closeExecutor if available //Executor closeExecutor = ((TcpSocketChannelUnsafe) unsafe()).closeExecutor(); //if (closeExecutor != null) { // closeExecutor.execute(new OneTimeTask() { // public void run() { // shutdownOutput0(promise); // } // }); //} else { IEventLoop loop = this.EventLoop; if (loop.InEventLoop) { this.ShutdownOutput0(tcs); } else { loop.Execute(promise => this.ShutdownOutput0((TaskCompletionSource)promise), tcs); } //} return(tcs.Task); }
public virtual async Task <bool> ReleaseAsync(IChannel channel) { if (channel is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.channel); } try { IEventLoop loop = channel.EventLoop; if (loop.InEventLoop) { return(await DoReleaseChannel(channel)); } else { var promise = new TaskCompletionSource <bool>(); loop.Execute(DoReleaseChannel, channel, promise); return(await promise.Task); } } catch (Exception) { CloseChannel(channel); throw; } }
public async ValueTask <bool> ReleaseAsync(IChannel channel) { Contract.Requires(channel != null); log.Debug("ReleaseAsync for " + channel.Id); try { IEventLoop loop = channel.EventLoop; log.Debug("ReleaseAsync -0- for " + loop.InEventLoop); if (loop.InEventLoop) { return(await this.DoReleaseChannel(channel)); } else { var promise = new TaskCompletionSource <bool>(); loop.Execute(this.DoReleaseChannel, channel, promise); return(await promise.Task); } } catch (Exception) { CloseChannel(channel); throw; } }
void DispatchCallback() { var observers = _observers.ToArray(); _queued = false; foreach (var observer in observers) { _loop.Execute(observer.Trigger); } }
public override void ChannelActive(IChannelHandlerContext ctx) { IEventLoop loop = _group.GetNext(); if (_sameEventLoop) { Deregister(ctx, loop); } else { loop.Execute(() => Deregister(ctx, loop)); } }
public Task RegisterAsync(IEventLoop eventLoop) { Contract.Requires(eventLoop != null); if (this._channel.Registered) { return(TaskEx.FromException(new InvalidOperationException("registered to an event loop already"))); } if (!this._channel.IsCompatible(eventLoop)) { return (TaskEx.FromException( new InvalidOperationException("incompatible event loop type: " + eventLoop.GetType().Name))); } // It's necessary to reuse the wrapped eventloop object. Otherwise the user will end up with multiple // objects that do not share a common state. if (this._channel._eventLoop == null) { this._channel._eventLoop = new PausableChannelEventLoop(this._channel, eventLoop); } else { this._channel._eventLoop.Unwrapped = eventLoop; } var promise = new TaskCompletionSource(); if (eventLoop.InEventLoop) { this.Register0(promise); } else { try { eventLoop.Execute(() => this.Register0(promise)); } catch (Exception ex) { Logger.Warning( "Force-closing a channel whose registration task was not accepted by an event loop: {0}; Cause: {1}", _channel, ex); CloseForcibly(); _channel._closeTask.TryComplete(); PromiseUtil.SafeSetFailure(promise, ex, Logger); } } return(promise.Task); }
public Task RegisterAsync(IEventLoop eventLoop) { if (eventLoop is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.eventLoop); } var ch = _channel; if (ch.Registered) { return(ThrowHelper.ThrowInvalidOperationException_RegisteredToEventLoopAlready()); } if (!ch.IsCompatible(eventLoop)) { return(ThrowHelper.ThrowInvalidOperationException_IncompatibleEventLoopType(eventLoop)); } _ = Interlocked.Exchange(ref ch.eventLoop, eventLoop); var promise = ch.NewPromise(); if (eventLoop.InEventLoop) { Register0(promise); } else { try { eventLoop.Execute(RegisterAction, this, promise); } catch (Exception ex) { if (Logger.WarnEnabled) { Logger.ForceClosingAChannel(ch, ex); } CloseForcibly(); ch._closeFuture.Complete(); Util.SafeSetFailure(promise, ex, Logger); } } return(promise.Task); }
public async virtual ValueTask <IChannel> AcquireNewOr(long timeout) { IChannel chl; bool b = this.store.TryDequeue(out chl); this.timeout = timeout; if (!b) { Bootstrap bs = this.bootstrap.Clone(); //Bootstrap bs = new Bootstrap(); bs.Attribute(PoolKey, this); log.Debug(" ... try get parent pool channel ... " + parentPool); try { IChannel chnl = await parentPool.AcquireAsync(); log.Debug(" ... Channel " + chnl); await ConnectChannel(chnl, timeout); return(chnl); } catch (Exception e) { log.Error("Something went wromg here: .. " + e.Message); } return(null); } IEventLoop eventLoop = chl.EventLoop; if (eventLoop.InEventLoop) { return(await this.DoHealthCheck(chl, timeout)); } else { var completionSource = new TaskCompletionSource <IChannel>(); eventLoop.Execute(this.DoHealthCheck, chl, completionSource); return(await completionSource.Task); } // return acquire(bootstrap.Config().group().next().newPromise<IChannel>()); }
public void GracefulShutdownAfterStart() { IEventLoop loop = NewEventLoopGroup().GetNext(); CountdownEvent latch = new CountdownEvent(1); loop.Execute(() => latch.Signal()); // Wait for the event loop thread to start. Assert.True(latch.Wait(TimeSpan.FromMinutes(1))); // Request the event loop thread to stop. loop.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(200), TimeSpan.FromSeconds(3)); // Wait until the event loop is terminated. Assert.True(loop.TerminationCompletion.Wait(TimeSpan.FromMilliseconds(500))); AssertRejection(loop); }
public virtual ValueTask <IChannel> AcquireAsync() { if (!this.TryPollChannel(out IChannel channel)) { Bootstrap bs = this.Bootstrap.Clone(); bs.Attribute(PoolKey, this); return(new ValueTask <IChannel>(this.ConnectChannel(bs))); } IEventLoop eventLoop = channel.EventLoop; if (eventLoop.InEventLoop) { return(this.DoHealthCheck(channel)); } else { var completionSource = new TaskCompletionSource <IChannel>(); eventLoop.Execute(this.DoHealthCheck, channel, completionSource); return(new ValueTask <IChannel>(completionSource.Task)); } }
public void FireNextRead(object msg) { IEventLoop loop = _channel.Loop; if (loop.InCurrentThread()) { if (Next != null) { Next.Handler.ChannelRead(Next, msg); } } else { loop.Execute(new SimpleRunnable(() => { if (Next != null) { Next.Handler.ChannelRead(Next, msg); } })); } }
public void FireNextInactive() { IEventLoop loop = _channel.Loop; if (loop.InCurrentThread()) { if (Next != null) { Next.Handler.ChannelInactive(Next); } } else { loop.Execute(new SimpleRunnable(() => { if (Next != null) { Next.Handler.ChannelInactive(Next); } })); } }
public void FireNextAccept(object accepter) { IEventLoop loop = _channel.Loop; if (loop.InCurrentThread()) { if (Next != null) { Next.Handler.ChannelAccept(Next, accepter); } } else { loop.Execute(new SimpleRunnable(() => { if (Next != null) { Next.Handler.ChannelAccept(Next, accepter); } })); } }
public void FirePreWrite(object msg) { IEventLoop loop = _channel.Loop; if (loop.InCurrentThread()) { if (Prev != null) { Prev.Handler.ChannelWrite(Prev, msg); } } else { loop.Execute(new SimpleRunnable(() => { if (Prev != null) { Prev.Handler.ChannelWrite(Prev, msg); } })); } }
/// <summary> /// Set read pending to <c>false</c>. /// </summary> protected internal void ClearReadPending() { if (this.Registered) { IEventLoop eventLoop = this.EventLoop; if (eventLoop.InEventLoop) { this.ClearReadPending0(); } else { eventLoop.Execute(channel => ((AbstractSocketChannel)channel).ClearReadPending0(), this); } } else { // Best effort if we are not registered yet clear ReadPending. This happens during channel initialization. // NB: We only set the boolean field instead of calling ClearReadPending0(), because the SelectionKey is // not set yet so it would produce an assertion failure. this.ReadPending = false; } }
public Task RegisterAsync(IEventLoop eventLoop) { Contract.Requires(eventLoop != null); if (this.channel.Registered) { return(TaskEx.FromException(new InvalidOperationException("registered to an event loop already"))); } if (!this.channel.IsCompatible(eventLoop)) { return(TaskEx.FromException(new InvalidOperationException("incompatible event loop type: " + eventLoop.GetType().Name))); } this.channel.eventLoop = eventLoop; var promise = new TaskCompletionSource(); if (eventLoop.InEventLoop) { this.Register0(promise); } else { try { eventLoop.Execute((u, p) => ((AbstractUnsafe)u).Register0((TaskCompletionSource)p), this, promise); } catch (Exception ex) { Logger.Warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", this.channel, ex); this.CloseForcibly(); this.channel.closeFuture.Complete(); Util.SafeSetFailure(promise, ex, Logger); } } return(promise.Task); }
public void Execute(Action action) { ThrowIfNotRunning(); _workerThread.Execute(action); }
public void Execute(Action action) { ThrowIfDisposed(); _workerThread.Execute(action); }
protected override void DoClose() { var peer = Volatile.Read(ref v_peer); var oldState = Volatile.Read(ref v_state); try { if (oldState != State.Closed) { // Update all internal state before the closeFuture is notified. var thisLocalAddr = Volatile.Read(ref v_localAddress); if (thisLocalAddr is object) { if (Parent is null) { LocalChannelRegistry.Unregister(thisLocalAddr); } _ = Interlocked.Exchange(ref v_localAddress, null); } // State change must happen before finishPeerRead to ensure writes are released either in doWrite or // channelRead. _ = Interlocked.Exchange(ref v_state, State.Closed); // Preserve order of event and force a read operation now before the close operation is processed. if (SharedConstants.False < (uint)Volatile.Read(ref v_writeInProgress) && peer is object) { FinishPeerRead(peer); } TaskCompletionSource promise = Volatile.Read(ref v_connectPromise); if (promise is object) { // Use tryFailure() instead of setFailure() to avoid the race against cancel(). _ = promise.TrySetException(DoCloseClosedChannelException); _ = Interlocked.Exchange(ref v_connectPromise, null); } } if (peer is object) { _ = Interlocked.Exchange(ref v_peer, null); // Always call peer.eventLoop().execute() even if peer.eventLoop().inEventLoop() is true. // This ensures that if both channels are on the same event loop, the peer's channelInActive // event is triggered *after* this peer's channelInActive event IEventLoop peerEventLoop = peer.EventLoop; bool peerIsActive = peer.IsActive; try { peerEventLoop.Execute(() => peer.TryClose(peerIsActive)); } catch (Exception cause) { Logger.Warn("Releasing Inbound Queues for channels {}-{} because exception occurred!", this, peer, cause); if (peerEventLoop.InEventLoop) { peer.ReleaseInboundBuffers(); } else { // inboundBuffers is a SPSC so we may leak if the event loop is shutdown prematurely or // rejects the close Runnable but give a best effort. _ = peer.CloseAsync(); } throw; } } } finally { // Release all buffers if the Channel was already registered in the past and if it was not closed before. if (oldState != State.Closed) { // We need to release all the buffers that may be put into our inbound queue since we closed the Channel // to ensure we not leak any memory. This is fine as it basically gives the same guarantees as TCP which // means even if the promise was notified before its not really guaranteed that the "remote peer" will // see the buffer at all. ReleaseInboundBuffers(); } } }
public Task RegisterAsync(IEventLoop eventLoop) { Contract.Requires(eventLoop != null); if (this._channel.Registered) { return TaskEx.FromException(new InvalidOperationException("registered to an event loop already")); } if (!this._channel.IsCompatible(eventLoop)) { return TaskEx.FromException( new InvalidOperationException("incompatible event loop type: " + eventLoop.GetType().Name)); } // It's necessary to reuse the wrapped eventloop object. Otherwise the user will end up with multiple // objects that do not share a common state. if (this._channel._eventLoop == null) { this._channel._eventLoop = new PausableChannelEventLoop(this._channel, eventLoop); } else { this._channel._eventLoop.Unwrapped = eventLoop; } var promise = new TaskCompletionSource(); if (eventLoop.InEventLoop) { this.Register0(promise); } else { try { eventLoop.Execute(() => this.Register0(promise)); } catch (Exception ex) { Logger.Warning( "Force-closing a channel whose registration task was not accepted by an event loop: {0}; Cause: {1}", _channel, ex); CloseForcibly(); _channel._closeTask.TryComplete(); PromiseUtil.SafeSetFailure(promise, ex, Logger); } } return promise.Task; }
protected override void DoClose() { var peer = this.peer; var oldState = this.state; try { if (oldState != State.Closed) { // Update all internal state before the closeFuture is notified. if (this.localAddress != null) { if (this.Parent == null) { LocalChannelRegistry.Unregister(this.localAddress); } this.localAddress = null; } // State change must happen before finishPeerRead to ensure writes are released either in doWrite or // channelRead. this.state = State.Closed; // Preserve order of event and force a read operation now before the close operation is processed. this.FinishPeerRead(this); TaskCompletionSource promise = this.connectPromise; if (promise != null) { // Use tryFailure() instead of setFailure() to avoid the race against cancel(). promise.TrySetException(DoCloseClosedChannelException); this.connectPromise = null; } } if (peer != null) { this.peer = null; // Need to execute the close in the correct EventLoop (see https://github.com/netty/netty/issues/1777). // Also check if the registration was not done yet. In this case we submit the close to the EventLoop // to make sure its run after the registration completes // (see https://github.com/netty/netty/issues/2144). IEventLoop peerEventLoop = peer.EventLoop; bool peerIsActive = peer.Active; if (peerEventLoop.InEventLoop && !this.registerInProgress) { peer.TryClose(peerIsActive); } else { try { peerEventLoop.Execute(() => peer.TryClose(peerIsActive)); } catch (Exception cause) { Logger.Warn("Releasing Inbound Queues for channels {}-{} because exception occurred!", this, peer, cause); if (peerEventLoop.InEventLoop) { peer.ReleaseInboundBuffers(); } else { // inboundBuffers is a SPSC so we may leak if the event loop is shutdown prematurely or // rejects the close Runnable but give a best effort. peer.CloseAsync(); } throw; } } } } finally { // Release all buffers if the Channel was already registered in the past and if it was not closed before. if (oldState != State.Closed) { // We need to release all the buffers that may be put into our inbound queue since we closed the Channel // to ensure we not leak any memory. This is fine as it basically gives the same guarantees as TCP which // means even if the promise was notified before its not really guaranteed that the "remote peer" will // see the buffer at all. this.ReleaseInboundBuffers(); } } }
public Task RegisterAsync(IEventLoop eventLoop) { Contract.Requires(eventLoop != null); if (this.channel.Registered) { return TaskEx.FromException(new InvalidOperationException("registered to an event loop already")); } if (!this.channel.IsCompatible(eventLoop)) { return TaskEx.FromException(new InvalidOperationException("incompatible event loop type: " + eventLoop.GetType().Name)); } this.channel.eventLoop = eventLoop; var promise = new TaskCompletionSource(); if (eventLoop.InEventLoop) { this.Register0(promise); } else { try { eventLoop.Execute((u, p) => ((AbstractUnsafe)u).Register0((TaskCompletionSource)p), this, promise); } catch (Exception ex) { Logger.Warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", this.channel, ex); this.CloseForcibly(); this.channel.closeFuture.Complete(); Util.SafeSetFailure(promise, ex, Logger); } } return promise.Task; }