public LibuvThread(LibuvFunctions libuv, IHostApplicationLifetime appLifetime, MemoryPool <byte> pool, ILogger log, int maxLoops = 8) { _libuv = libuv; _appLifetime = appLifetime; _log = log; _loop = new UvLoopHandle(_log); _post = new UvAsyncHandle(_log); _maxLoops = maxLoops; _thread = new Thread(ThreadStart); #if !INNER_LOOP _thread.Name = nameof(LibuvThread); #endif #if !DEBUG // Mark the thread as being as unimportant to keeping the process alive. // Don't do this for debug builds, so we know if the thread isn't terminating. _thread.IsBackground = true; #endif QueueCloseHandle = PostCloseHandle; QueueCloseAsyncHandle = EnqueueCloseHandle; MemoryPool = pool; WriteReqPool = new WriteReqPool(this, _log); }
private void ThreadStart(object parameter) { lock (_startSync) { var tcs = (TaskCompletionSource <int>)parameter; try { _loop.Init(_transport.Libuv); _post.Init(_loop, OnPost, EnqueueCloseHandle); _initCompleted = true; tcs.SetResult(0); } catch (Exception ex) { tcs.SetException(ex); return; } } try { _loop.Run(); if (_stopImmediate) { // thread-abort form of exit, resources will be leaked return; } // run the loop one more time to delete the open handles _post.Reference(); _post.Dispose(); // We need this walk because we call ReadStop on on accepted connections when there's back pressure // Calling ReadStop makes the handle as in-active which means the loop can // end while there's still valid handles around. This makes loop.Dispose throw // with an EBUSY. To avoid that, we walk all of the handles and dispose them. Walk(ptr => { var handle = UvMemory.FromIntPtr <UvHandle>(ptr); // handle can be null because UvMemory.FromIntPtr looks up a weak reference handle?.Dispose(); }); // Ensure the Dispose operations complete in the event loop. _loop.Run(); _loop.Dispose(); } catch (Exception ex) { _closeError = ExceptionDispatchInfo.Capture(ex); // Request shutdown so we can rethrow this exception // in Stop which should be observable. _appLifetime.StopApplication(); } finally { BufferPool.Dispose(); WriteReqPool.Dispose(); _threadTcs.SetResult(null); #if DEBUG // Check for handle leaks after disposing everything CheckUvReqLeaks(); #endif } }