public void SetTimer(int MillisecondTimeout, TimeElapsedHandler CB) { lock(TimeoutList) { long Ticks = DateTime.Now.AddMilliseconds(MillisecondTimeout).Ticks; while(TimeoutList.ContainsKey(Ticks)==true) { ++Ticks; } TimeoutList.Add(Ticks,CB); if(TimeoutList.Count==1) { // First Entry mre.Reset(); handle = ThreadPool.RegisterWaitForSingleObject( mre, WOTcb, null, MillisecondTimeout, true); } else { mre.Set(); } } }
public HeartbeatSender(TimeSpan period, RestTarget heartbeatRest) { _period = period; _heartbeatRest = heartbeatRest; _registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(_disposeEvent, SendHeartBeats, null, _period, false); }
public bool unregister() { ManualResetEvent callbackThreadComplete = new ManualResetEvent(false); int timeToWait = 5000; //milliseconds System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); if (this.sessionRegisteredWait != null) { if (this.sessionRegisteredWait.Unregister(callbackThreadComplete)) { Console.WriteLine("waiting on succesful unregister"); callbackThreadComplete.WaitOne(timeToWait); } } this.sessionRegisteredWait = null; long elapsed = sw.ElapsedMilliseconds; Console.WriteLine("Elapsed: {0} millisec", elapsed); if (elapsed >= timeToWait) { Console.WriteLine("Error. Callback was not signaled"); return false; } else { Console.WriteLine("Success"); return true; } }
public CallbackInfo(Action<RawBusMessage, Exception> callback, Type replyType, ManualResetEvent ev, RegisteredWaitHandle handle) { _callback = callback; _replyType = replyType; _ev = ev; _handle = handle; }
/// <summary> /// create a buffer recorder for a stream /// </summary> /// <param name="number">ordinal for diagnostics</param> /// <param name="streamID">the stream I'm for</param> public BufferRecorder( int number, int streamID ) { isAvailable = true; this.number = number; indices = new Index[Constants.IndexCapacity]; currentIndex = 0; buffer = new byte[Constants.BufferSize]; this.streamID = streamID; // setup the db writer thread canSave = new AutoResetEvent(false); // The BufferTimeout feature is "turned off" so that the buffer won't automatically write to disk sporadically. // This is a nice safety feature we should try to turn back on. It was turned off because it was saving data // and causing frames to be written out of order in the DB. waitHandle = ThreadPool.RegisterWaitForSingleObject( canSave, new WaitOrTimerCallback(InitiateSave), this, Constants.BufferTimeout, false); Thread.Sleep(50); // Allows for the Registration to occur & get setup // Without the Sleep, if we walk into a massive session with lots of data moving, we get slammed & can't keep up. }
/// <summary> /// set ourselves up, we are pretty dumb so need to be told who we're sending for /// and where to get our data from, and when to start sending.. /// </summary> /// <remarks> /// It seems that we don't use maxFrameSize any more. hmm. Remove it? /// </remarks> public BufferPlayer(int streamID, int maxFrameSize, int maxFrameCount, int maxBufferSize) { Debug.Assert( maxBufferSize >= maxFrameSize ); // just for kicks... buffer = new BufferChunk( maxBufferSize ); indices = new Index[maxFrameCount+1]; // Pri3: why is this "+1" here? (DO NOT REMOVE YET) this.populating = false; this.streamOutOfData = false; this.streamID = streamID; this.currentIndex = 0; this.indexCount = 0; this.startingTick = 0; canPopulate = new AutoResetEvent(false); // pool a thread to re-populate ourselves waitHandle = ThreadPool.RegisterWaitForSingleObject( canPopulate, new WaitOrTimerCallback( InitiatePopulation ), this, -1, // never timeout to perform a population false ); }
private void BeginRunOnTimer(object state, bool isTimeout) { //Wait for this race condition to satisfy while (m_registeredHandle == null) ; m_registeredHandle.Unregister(null); m_registeredHandle = null; OnRunning(); }
private volatile int flushIsRunning = 0; // 0 = false, 1 = true #endregion Fields #region Constructors public QueueLogWriter() { File.Delete(aof); fileStream = new FileStream(aof, FileMode.OpenOrCreate, FileAccess.Write); flushSignalWaitHandle = ThreadPool.RegisterWaitForSingleObject(flushSignal, (state, timedOut) => Flush(), null, -1, false); flushSignal.Set(); // signal to start pump right away }
public EventsQueue(Boolean bufferedOutput, Int32 autoFlushPeriod, Action<IEnumerable<EventRecord>> flushAction) { this.bufferedOutput = bufferedOutput; this.flushAction = flushAction; this.syncObject = new Object(); this.eventsList = new List<EventRecord>(); this.flushEvent = new AutoResetEvent(false); this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( this.flushEvent, FlushEventSignaledCallback, null, autoFlushPeriod * 1000, false); }
public unsafe void CancelAsyncOperation() { this.rootedHolder.ThisHolder = null; if (this.registration != null) { this.registration.Unregister(null); this.registration = null; } this.bufferPtr = null; this.bufferHolder[0] = dummyBuffer; this.pendingCallback = null; }
private static void InitializeConnectionTimeoutHandler() { _socketTimeoutDelegate = new WaitOrTimerCallback(TimeoutConnections); _socketTimeoutWaitHandle = new AutoResetEvent(false); _registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject( _socketTimeoutWaitHandle, _socketTimeoutDelegate, "IpcConnectionTimeout", _socketTimeoutPollTime, true); // execute only once } // InitializeSocketTimeoutHandler
public void RegisterTimeout(TimeSpan interval, Action callback) { lock (m_syncRoot) { if (m_callback != null) throw new Exception("Duplicate calls are not permitted"); m_callback = callback; m_resetEvent = new ManualResetEvent(false); m_registeredHandle = ThreadPool.RegisterWaitForSingleObject(m_resetEvent, BeginRun, null, interval, true); } }
static Log() { _useDiagnostic = System.Diagnostics.Debugger.IsAttached; try { int window_height = Console.WindowHeight; _useConsole = true; } catch { _useConsole = false; } if(!Directory.Exists("../log")) { Directory.CreateDirectory("../log"); } useFile = true; _lfMask = "../log/{0}_" + Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location) + ".log"; _records = new System.Collections.Concurrent.ConcurrentQueue<LogRecord>(); _kickEv = new AutoResetEvent(false); _wh = ThreadPool.RegisterWaitForSingleObject(_kickEv, Process, null, -1, false); }
private static void TimeoutSockets(object state, bool wasSignalled) { DateTime utcNow = DateTime.UtcNow; lock (_connections) { foreach (DictionaryEntry entry in _connections) { ((RemoteConnection) entry.Value).TimeoutSockets(utcNow); } } _registeredWaitHandle.Unregister(null); _registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject(_socketTimeoutWaitHandle, _socketTimeoutDelegate, "TcpChannelSocketTimeout", _socketTimeoutPollTime, true); }
private void BeginRun(object state, bool isTimeout) { lock (m_syncRoot) { if (m_registeredHandle == null) return; m_registeredHandle.Unregister(null); m_resetEvent.Dispose(); m_callback(); m_resetEvent = null; m_registeredHandle = null; m_callback = null; } }
public void Cancel() { lock (m_syncRoot) { if (m_registeredHandle != null) { m_registeredHandle.Unregister(null); m_resetEvent.Dispose(); m_resetEvent = null; m_registeredHandle = null; m_callback = null; } } }
public void register() { this.sessionNotification = new ManualResetEvent(false); this.sessionRegisteredWait = ThreadPool.RegisterWaitForSingleObject( this.sessionNotification, ServiceCallbackOnPositionAvailable, this, /* object state */ -1, /* INFINITE */ true /* ExecuteOnlyOnce */); }
private void Begin(Func<AsyncCallback, object, IAsyncResult> beginMethod, AsyncCallback callback, object state, TimeSpan timeout) { this.asyncResult = beginMethod(callback, state); #if WINDOWS_PHONE WaitHandle asyncWaitHandle = this.fakeEvent; #else WaitHandle asyncWaitHandle = this.asyncResult.AsyncWaitHandle; #endif this.waitHandle = ThreadPool.RegisterWaitForSingleObject(asyncWaitHandle, this.WaitCallback, state, timeout, true); if (this.disposed) { this.UnregisterWaitHandle(); } }
public ConnectionCache(int keepAlive, ConnectionFactory connectionFactory) { // parameters validation if (connectionFactory == null) throw new ArgumentNullException("connectionFactory"); if (keepAlive < 1) throw new ArgumentOutOfRangeException("keepAlive"); _connectionFactory = connectionFactory; _keepAlive = TimeSpan.FromSeconds(keepAlive); // Schedule timeout method _timeoutDelegate = OnTimerElapsed; _timeoutWaitHandle = new AutoResetEvent(false); _registeredTimeoutWaitHandle = ThreadPool.RegisterWaitForSingleObject( _timeoutWaitHandle, _timeoutDelegate, null, _keepAlive, true); }
public void ServiceCallbackOnPositionAvailable(Object state, bool timedOut) { if (this.sessionRegisteredWait == null) { this.sessionNotification.Reset(); this.sessionRegisteredWait.Unregister(null); this.sessionRegisteredWait = ThreadPool.RegisterWaitForSingleObject(this.sessionNotification, ServiceCallbackOnPositionAvailable, this, /* object state */ -1, /* INFINITE */ true /* ExecuteOnlyOnce */); } Console.WriteLine("callback running"); }
} // InitializeSocketTimeoutHandler private static void TimeoutConnections(Object state, Boolean wasSignalled) { DateTime currentTime = DateTime.UtcNow; lock (_connections) { foreach (DictionaryEntry entry in _connections) { PortConnection connection = (PortConnection)entry.Value; if (DateTime.Now - connection.LastUsed > _portLifetime) connection.Port.Dispose(); } } _registeredWaitHandle.Unregister(null); _registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject( _socketTimeoutWaitHandle, _socketTimeoutDelegate, "IpcConnectionTimeout", _socketTimeoutPollTime, true); // execute only once } // TimeoutConnections
/// <summary> /// create a buffer manager for a stream /// </summary> /// <param name="number">ordinal for diagnostics</param> /// <param name="streamID">the stream I'm for</param> public BufferManager( int number, int streamID ) { isAvailable = true; this.number = number; indices = new Index[Constants.IndexCapacity]; currentIndex = 0; buffer = new byte[Constants.BufferSize]; this.streamID = streamID; // setup the db writer thread canSave = new AutoResetEvent(false); waitHandle = ThreadPool.RegisterWaitForSingleObject( canSave, new WaitOrTimerCallback(InitiateSave), this, Constants.BufferTimeout, false); Thread.Sleep(50); // Allows for the Registration to occur & get setup // Without the Sleep, if we walk into a massive session with lots of data moving, we get slammed & can't keep up. }
/// <summary> /// /// </summary> /// <param name="nextCheckSeconds">check again after X seconds</param> /// <param name="containerName">what container to sync</param> public static void CheckAsync(int nextCheckSeconds, string containerName, string rootPath) { lock (typeof(QuickDeployService)) { // clear existing handle if already exists if (RegisteredWaitHandle != null) RegisteredWaitHandle.Unregister(null); var waitHandle = new AutoResetEvent(false); RegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject( waitHandle, // Method to execute (state, timeout) => { WhenTimeComes(containerName, rootPath); }, // optional state object to pass to the method null, // Execute the method after 5 seconds TimeSpan.FromSeconds(nextCheckSeconds), // Set this to false to execute it repeatedly every 5 seconds false ); } }
private static void AddNameChanged(EventHandler<NameChangedEventArgs> callback) { Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddNameChanged()."); // // Register a wait handle if one has not been registered already // lock (LockNameChangedEvent) { if (s_nameChanged == null){ s_nameChangedEvent = new AutoResetEvent(false); // // Register callback with a wait handle // s_regNameChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(s_nameChangedEvent, //Event that triggers the callback new WaitOrTimerCallback(NameChangedCallback), //callback to be called null, //state to be passed -1, //Timeout - aplicable only for timers false //call us everytime the event is set ); PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION(); pcer.eventType = PeerCollabEventType.MyEndPointChanged; pcer.pInstance = IntPtr.Zero; // // Register event with collab // int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent( s_nameChangedEvent.SafeWaitHandle, 1, ref pcer, out s_safeNameChangedEvent); if (errorCode != 0){ Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode); throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_NameChangedRegFailed), errorCode); } } s_nameChanged += callback; } Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddNameChanged() successful."); }
// We need this to make the use of the property as an attribute // light-weight. This allows us to delay initialize everything we // need to fully function as a ContextProperty. internal virtual void InitIfNecessary() { lock(this) { if (_asyncWorkEvent == null) { // initialize thread pool event to non-signaled state. _asyncWorkEvent = new AutoResetEvent(false); _workItemQueue = new Queue(); _asyncLcidList = new ArrayList(); WaitOrTimerCallback callBackDelegate = new WaitOrTimerCallback(this.DispatcherCallBack); // Register a callback to be executed by the thread-pool // each time the event is signaled. _waitHandle = ThreadPool.RegisterWaitForSingleObject( _asyncWorkEvent, callBackDelegate, null, // state info _timeOut, false); // bExecuteOnlyOnce } } }
private void HandleTimer(Object State, bool TimedOut) { ArrayList TriggerList = new ArrayList(); lock (TimeoutList) { while (TimeoutList.Count > 0) { DateTime timeout = new DateTime((long)TimeoutList.GetKey(0)); TimeElapsedHandler cb = (TimeElapsedHandler)TimeoutList.GetByIndex(0); if (DateTime.Now.CompareTo(timeout) >= 0) { // Trigger TriggerList.Add(cb); TimeoutList.RemoveAt(0); } else { // Reset timer mre.Reset(); int MillisecondTimeout = (int)new TimeSpan(timeout.Ticks - DateTime.Now.Ticks).TotalMilliseconds; if (MillisecondTimeout <= 0) { mre.Set(); MillisecondTimeout = 0; } handle = ThreadPool.RegisterWaitForSingleObject(mre, WOTcb, null, MillisecondTimeout, true); break; } } } foreach (TimeElapsedHandler _cb in TriggerList) { _cb(this); } }
internal void StartSubscribing() { if (this.isSubscribing) throw new InvalidOperationException(); int flag = 0; if (bookmark != null) flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeStartAfterBookmark; else if (this.readExistingEvents) flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeStartAtOldestRecord; else flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeToFutureEvents; if (this.eventQuery.TolerateQueryErrors) flag |= (int)UnsafeNativeMethods.EvtSubscribeFlags.EvtSubscribeTolerateQueryErrors; EventLogPermissionHolder.GetEventLogPermission().Demand(); this.callbackThreadId = -1; this.unregisterDoneHandle = new AutoResetEvent(false); this.subscriptionWaitHandle = new AutoResetEvent(false); EventLogHandle bookmarkHandle = EventLogRecord.GetBookmarkHandleFromBookmark(bookmark); using (bookmarkHandle) { handle = NativeWrapper.EvtSubscribe(this.eventQuery.Session.Handle, this.subscriptionWaitHandle.SafeWaitHandle, this.eventQuery.Path, this.eventQuery.Query, bookmarkHandle, IntPtr.Zero, IntPtr.Zero, flag); } this.isSubscribing = true; RequestEvents(); this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( this.subscriptionWaitHandle, new WaitOrTimerCallback(SubscribedEventsAvailableCallback), null, -1, false); }
internal void StopSubscribing() { EventLogPermissionHolder.GetEventLogPermission().Demand(); // // need to set isSubscribing to false before waiting for completion of callback. // this.isSubscribing = false; if (this.registeredWaitHandle != null) { this.registeredWaitHandle.Unregister( this.unregisterDoneHandle ); if (this.callbackThreadId != Thread.CurrentThread.ManagedThreadId) { // // not calling Stop from within callback - wait for // any outstanding callbacks to complete. // if ( this.unregisterDoneHandle != null ) this.unregisterDoneHandle.WaitOne(); } this.registeredWaitHandle = null; } if (this.unregisterDoneHandle != null) { this.unregisterDoneHandle.Close(); this.unregisterDoneHandle = null; } if (this.subscriptionWaitHandle != null) { this.subscriptionWaitHandle.Close(); this.subscriptionWaitHandle = null; } for (int i = 0; i < this.numEventsInBuffer; i++) { if (eventsBuffer[i] != IntPtr.Zero) { NativeWrapper.EvtClose(eventsBuffer[i]); eventsBuffer[i] = IntPtr.Zero; } } this.numEventsInBuffer = 0; if (handle != null && !handle.IsInvalid) handle.Dispose(); }
} // InitializeSocketTimeoutHandler private void TimeoutSockets(Object state, Boolean wasSignalled) { DateTime currentTime = DateTime.Now; lock (_connections) { foreach (DictionaryEntry entry in _connections) { RemoteConnection connection = (RemoteConnection)entry.Value; connection.TimeoutSockets(currentTime); } } _registeredWaitHandle.Unregister(null); _registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject( _socketTimeoutWaitHandle, _socketTimeoutDelegate, "TcpChannelSocketTimeout", _socketTimeoutPollTime, true); // execute only once } // TimeoutSockets
public CompletedWaitHandle(RegisteredWaitHandle completedHandle, bool timedOut) { CompletedHandle = completedHandle; TimedOut = timedOut; }
/// <summary> /// The main routine for the wait thread. /// </summary> private void WaitThreadStart() { while (true) { ProcessRemovals(); int numUserWaits = _numUserWaits; int preWaitTimeMs = Environment.TickCount; // Recalculate Timeout int timeoutDurationMs = Timeout.Infinite; if (numUserWaits == 0) { timeoutDurationMs = ThreadPoolThreadTimeoutMs; } else { for (int i = 0; i < numUserWaits; i++) { if (_registeredWaits[i].IsInfiniteTimeout) { continue; } int handleTimeoutDurationMs = _registeredWaits[i].TimeoutTimeMs - preWaitTimeMs; if (timeoutDurationMs == Timeout.Infinite) { timeoutDurationMs = handleTimeoutDurationMs > 0 ? handleTimeoutDurationMs : 0; } else { timeoutDurationMs = Math.Min(handleTimeoutDurationMs > 0 ? handleTimeoutDurationMs : 0, timeoutDurationMs); } if (timeoutDurationMs == 0) { break; } } } int signaledHandleIndex = WaitHandle.WaitAny(new ReadOnlySpan<WaitHandle>(_waitHandles, 0, numUserWaits + 1), timeoutDurationMs); if (signaledHandleIndex == 0) // If we were woken up for a change in our handles, continue. { continue; } RegisteredWaitHandle signaledHandle = signaledHandleIndex != WaitHandle.WaitTimeout ? _registeredWaits[signaledHandleIndex - 1] : null; if (signaledHandle != null) { QueueWaitCompletion(signaledHandle, false); } else { if(numUserWaits == 0) { if (ThreadPoolInstance.TryRemoveWaitThread(this)) { return; } } int elapsedDurationMs = Environment.TickCount - preWaitTimeMs; // Calculate using relative time to ensure we don't have issues with overflow wraparound for (int i = 0; i < numUserWaits; i++) { RegisteredWaitHandle registeredHandle = _registeredWaits[i]; int handleTimeoutDurationMs = registeredHandle.TimeoutTimeMs - preWaitTimeMs; if (elapsedDurationMs >= handleTimeoutDurationMs) { QueueWaitCompletion(registeredHandle, true); } } } } }
public CompleteWaitThreadPoolWorkItem(RegisteredWaitHandle registeredWaitHandle, bool timedOut) { _registeredWaitHandle = registeredWaitHandle; _timedOut = timedOut; }
/// <summary> /// The main routine for the wait thread. /// </summary> private void WaitThreadStart() { while (true) { // This value is taken inside the lock after processing removals. In this iteration these are the number of // user waits that will be waited upon. Any new waits will wake the wait and the next iteration would // consider them. int numUserWaits = ProcessRemovals(); int currentTimeMs = Environment.TickCount; // Recalculate Timeout int timeoutDurationMs = Timeout.Infinite; if (numUserWaits == 0) { timeoutDurationMs = ThreadPoolThreadTimeoutMs; } else { for (int i = 0; i < numUserWaits; i++) { RegisteredWaitHandle registeredWait = _registeredWaits[i]; Debug.Assert(registeredWait != null); if (registeredWait.IsInfiniteTimeout) { continue; } int handleTimeoutDurationMs = Math.Max(0, registeredWait.TimeoutTimeMs - currentTimeMs); if (timeoutDurationMs == Timeout.Infinite) { timeoutDurationMs = handleTimeoutDurationMs; } else { timeoutDurationMs = Math.Min(handleTimeoutDurationMs, timeoutDurationMs); } if (timeoutDurationMs == 0) { break; } } } int signaledHandleIndex = WaitHandle.WaitAny(new ReadOnlySpan <SafeWaitHandle>(_waitHandles, 0, numUserWaits + 1), timeoutDurationMs); if (signaledHandleIndex >= WaitHandle.WaitAbandoned && signaledHandleIndex < WaitHandle.WaitAbandoned + 1 + numUserWaits) { // For compatibility, treat an abandoned mutex wait result as a success and ignore the abandonment Debug.Assert(signaledHandleIndex != WaitHandle.WaitAbandoned); // the first wait handle is an event signaledHandleIndex += WaitHandle.WaitSuccess - WaitHandle.WaitAbandoned; } if (signaledHandleIndex == 0) // If we were woken up for a change in our handles, continue. { continue; } if (signaledHandleIndex != WaitHandle.WaitTimeout) { RegisteredWaitHandle signaledHandle = _registeredWaits[signaledHandleIndex - 1]; Debug.Assert(signaledHandle != null); QueueWaitCompletion(signaledHandle, false); continue; } if (numUserWaits == 0 && ThreadPoolInstance.TryRemoveWaitThread(this)) { return; } currentTimeMs = Environment.TickCount; for (int i = 0; i < numUserWaits; i++) { RegisteredWaitHandle registeredHandle = _registeredWaits[i]; Debug.Assert(registeredHandle != null); if (!registeredHandle.IsInfiniteTimeout && currentTimeMs - registeredHandle.TimeoutTimeMs >= 0) { QueueWaitCompletion(registeredHandle, true); } } } }
private static void StartHelper(NetworkAddressChangedEventHandler caller, bool captureContext, StartIPOptions startIPOptions) { lock (s_callerArray) { // setup changedEvent and native overlapped struct. if(s_ipv4Socket == null){ Socket.InitializeSockets(); int blocking; if(Socket.OSSupportsIPv4){ blocking = -1; s_ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false); UnsafeNclNativeMethods.OSSOCK.ioctlsocket(s_ipv4Socket, IoctlSocketConstants.FIONBIO,ref blocking); s_ipv4WaitHandle = s_ipv4Socket.GetEventHandle(); } if(Socket.OSSupportsIPv6){ blocking = -1; s_ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false); UnsafeNclNativeMethods.OSSOCK.ioctlsocket(s_ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking); s_ipv6WaitHandle = s_ipv6Socket.GetEventHandle(); } } if ((caller != null) && (!s_callerArray.Contains(caller))) { s_callerArray.Add(caller, captureContext ? ExecutionContext.Capture() : null); } //if s_listener is not null, it means we are already actively listening if (s_isListening || s_callerArray.Count == 0) { return; } if(!s_isPending){ int length; SocketError errorCode; if(Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) !=0){ s_registeredWait = ThreadPool.UnsafeRegisterWaitForSingleObject( s_ipv4WaitHandle, new WaitOrTimerCallback(AddressChangedCallback), StartIPOptions.StartIPv4, -1, true ); errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking( s_ipv4Socket.DangerousGetHandle(), (int) IOControlCode.AddressListChange, null, 0, null, 0, out length, SafeNativeOverlapped.Zero, IntPtr.Zero); if (errorCode != SocketError.Success) { NetworkInformationException exception = new NetworkInformationException(); if (exception.ErrorCode != (uint)SocketError.WouldBlock) { throw exception; } } errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(s_ipv4Socket, s_ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange); if (errorCode != SocketError.Success) { throw new NetworkInformationException(); } } if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){ s_registeredWait = ThreadPool.UnsafeRegisterWaitForSingleObject( s_ipv6WaitHandle, new WaitOrTimerCallback(AddressChangedCallback), StartIPOptions.StartIPv6, -1, true ); errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking( s_ipv6Socket.DangerousGetHandle(), (int) IOControlCode.AddressListChange, null, 0, null, 0, out length, SafeNativeOverlapped.Zero, IntPtr.Zero); if (errorCode != SocketError.Success) { NetworkInformationException exception = new NetworkInformationException(); if (exception.ErrorCode != (uint)SocketError.WouldBlock) { throw exception; } } errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(s_ipv6Socket, s_ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange); if (errorCode != SocketError.Success) { throw new NetworkInformationException(); } } } s_isListening = true; s_isPending = true; } }
/// <summary> /// Unregisters a wait handle. /// </summary> /// <param name="handle">The handle to unregister.</param> /// <remarks> /// As per CoreCLR's behavior, if the user passes in an invalid <see cref="WaitHandle"/> /// into <see cref="RegisteredWaitHandle.Unregister(WaitHandle)"/>, then the unregistration of the wait handle is blocking. /// Otherwise, the unregistration of the wait handle is queued on the wait thread. /// </remarks> public void UnregisterWait(RegisteredWaitHandle handle) { UnregisterWait(handle, true); }
/// <summary> /// Go through the <see cref="_pendingRemoves"/> array and remove those registered wait handles from the <see cref="_registeredWaits"/> /// and <see cref="_waitHandles"/> arrays, filling the holes along the way. /// </summary> private int ProcessRemovals() { PortableThreadPool threadPoolInstance = ThreadPoolInstance; threadPoolInstance._waitThreadLock.Acquire(); try { Debug.Assert(_numPendingRemoves >= 0); Debug.Assert(_numPendingRemoves <= _pendingRemoves.Length); Debug.Assert(_numUserWaits >= 0); Debug.Assert(_numUserWaits <= _registeredWaits.Length); Debug.Assert(_numPendingRemoves <= _numUserWaits, $"Num removals {_numPendingRemoves} should be less than or equal to num user waits {_numUserWaits}"); if (_numPendingRemoves == 0 || _numUserWaits == 0) { return(_numUserWaits); // return the value taken inside the lock for the caller } int originalNumUserWaits = _numUserWaits; int originalNumPendingRemoves = _numPendingRemoves; // This is O(N^2), but max(N) = 63 and N will usually be very low for (int i = 0; i < _numPendingRemoves; i++) { RegisteredWaitHandle waitHandleToRemove = _pendingRemoves[i] !; int numUserWaits = _numUserWaits; int j = 0; for (; j < numUserWaits && waitHandleToRemove != _registeredWaits[j]; j++) { } Debug.Assert(j < numUserWaits); waitHandleToRemove.OnRemoveWait(); if (j + 1 < numUserWaits) { // Not removing the last element. Due to the possibility of there being duplicate system wait // objects in the wait array, perhaps even with different handle values due to the use of // DuplicateHandle(), don't reorder handles for fairness. When there are duplicate system wait // objects in the wait array and the wait object gets signaled, the system may release the wait in // in deterministic order based on the order in the wait array. Instead, shift the array. int removeAt = j; int count = numUserWaits; Array.Copy(_registeredWaits, removeAt + 1, _registeredWaits, removeAt, count - (removeAt + 1)); _registeredWaits[count - 1] = null !; // Corresponding elements in the wait handles array are shifted up by one removeAt++; count++; Array.Copy(_waitHandles, removeAt + 1, _waitHandles, removeAt, count - (removeAt + 1)); _waitHandles[count - 1] = null !; } else { // Removing the last element _registeredWaits[j] = null !; _waitHandles[j + 1] = null !; } _numUserWaits = numUserWaits - 1; _pendingRemoves[i] = null; waitHandleToRemove.Handle.DangerousRelease(); } _numPendingRemoves = 0; Debug.Assert(originalNumUserWaits - originalNumPendingRemoves == _numUserWaits, $"{originalNumUserWaits} - {originalNumPendingRemoves} == {_numUserWaits}"); return(_numUserWaits); // return the value taken inside the lock for the caller } finally { threadPoolInstance._waitThreadLock.Release(); } }