Ejemplo n.º 1
0
		private void Deactivate ()
		{
			state = INACTIVE;

			waitObject = null;
			waitBlock = null;
			hint = null;
			callback = null;
			cbparker = null;
			cbState = null;

			WaitHandle no;
			if ((no = notificationObject) != null) {
				notificationObject = null;
				no.Signal ();
			}
		}
Ejemplo n.º 2
0
		internal override StWaitBlock _WaitAllPrologue (StParker pk, ref StWaitBlock hint, ref int sc)
		{
			hint = INFLATED;
			return null;
		}
Ejemplo n.º 3
0
		internal override void _CancelAcquire (StWaitBlock wb, StWaitBlock hint)
		{ }
Ejemplo n.º 4
0
		internal abstract void _CancelAcquire (StWaitBlock wb, StWaitBlock hint);
Ejemplo n.º 5
0
		protected override bool EnqueueWaiter (StWaitBlock wb, out StWaitBlock pred)
		{
			wb.request = Thread.CurrentThreadId;

			do {
				StWaitBlock t, tn;
				if ((tn = (t = tail).next) == SET) {
					pred = null;
					return false;
				}

				if (tn != null) {
					AdvanceTail (t, tn);
					continue;
				}

				if (Interlocked.CompareExchange (ref t.next, wb, null) == null) {
					AdvanceTail (t, wb);
					pred = t;
					return true;
				}
			} while (true);
		}
Ejemplo n.º 6
0
 internal override StWaitBlock _WaitAllPrologue (StParker pk, ref StWaitBlock hint,
                                                 ref int sc)
 {
    return WaitWithParker (pk, WaitType.WaitAll, StParkStatus.StateChange, ref hint, ref sc);
 }
Ejemplo n.º 7
0
		internal abstract StWaitBlock _WaitAllPrologue (StParker pk,
		                                                ref StWaitBlock hint, ref int sc);
Ejemplo n.º 8
0
		internal static int WaitAny (StWaitable[] ws, StCancelArgs cargs)
		{
			if (ws == null) {
				throw new ArgumentNullException ("ws");
			}

			int len = ws.Length;

			for (int i = 0; i < len; i++) {
				if (ws [i]._TryAcquire ()) {
					return StParkStatus.Success + i;
				}
			}

			if (cargs.Timeout == 0) {
				return StParkStatus.Timeout;
			}

		retry:

			/*
			 * Create a parker and execute the WaitAny prologue on all
			 * waitables. We stop executing prologues as soon as we detect
			 * that the acquire operation was accomplished.
			 */ 

			var pk = new StParker (1);
			int inflated = 0;
			int inflatedCount = 0;
			var wbs = new StWaitBlock [len];
			var hints = new StWaitBlock [len];

			int lv = -1;
			int gsc = 0;

			for (int i = 0; !pk.IsLocked && i < len; i++) {
				StWaitable w = ws [i];
				int sc = 0;

				if ((wbs [i] = w._WaitAnyPrologue (pk, i, ref hints [i], ref sc)) == null) {
					if (hints [i] == INFLATED) {
						inflated |= 1 << i;
						inflatedCount += 1;
					} else {
						if (pk.TryLock ()) {
							pk.UnparkSelf (i);
						} else {
							w._UndoAcquire ();
						}
						break;
					}
				} else if (gsc < sc) {
					gsc = sc;
				}
				lv = i;
			}

			int wst = inflatedCount == len ? InflatedWaitMultiple (ws, false, inflated, inflatedCount, cargs)
					  : inflatedCount > 0 ? pk.Park (gsc, ws, inflated, inflatedCount, cargs)
					  : pk.Park (gsc, cargs);
			 
			StWaitable acq = wst >= StParkStatus.Success ? ws [wst] : null;

			/*
			 * Cancel the acquire attempt on all waitables where we executed the WaitAny
			 * prologue, except the one we acquired and the ones that are inflated.
			 */

			for (int i = 0; i <= lv; i++) {
				StWaitable w = ws [i];
				StWaitBlock wb = wbs [i];
				if (w != acq && wb != null) {
					w._CancelAcquire (wb, hints [i]);
				}
			}

			if (acq != null) {
				try {
					acq._WaitEpilogue ();
				} catch (AbandonedMutexException e) {
					e.MutexIndex = wst;
					throw;
				}
				return wst;
			}

			if (wst == StParkStatus.Inflated) {
				goto retry;
			}

			cargs.ThrowIfException (wst);
			return StParkStatus.Timeout;
		}
Ejemplo n.º 9
0
		internal static bool WaitAll (StWaitable[] ws, StCancelArgs cargs)
		{
			if (ws == null) {
				throw new ArgumentNullException ("ws");
			}

			int nevts;
			int len = ws.Length;
			var sws = new StWaitable [len];

			int waitHint = SortAndCheckAllowAcquire (ws, sws, out nevts);

			if (waitHint < 0) {
				throw new DuplicateWaitObjectException ();
			}

			/*
			 * Return success if all synchronizers are notification events and are set.
			 */

			if (waitHint != 0) {
				if (nevts == 0) {
					return true;
				}
			} else if (cargs.Timeout == 0) {
				return false;
			}

			/*
			 * If a timeout was specified, get the current time in order
			 * to adjust the timeout value later, if we re-wait.
			 */

			int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0;
			StWaitBlock[] wbs = null;
			StWaitBlock[] hints = null;
			do {
				int inflated = 0;
				AbandonedMutexException ame = null;

				if (waitHint == 0) {

					if (wbs == null) {
						wbs = new StWaitBlock [len];
						hints = new StWaitBlock [len];
					}

					/*
					 * Create a parker for cooperative release, specifying as many
					 * releasers as the number of waitables. The parker is not reused
					 * because other threads may have references to it.
					 */

					var pk = new StParker (len);
					int inflatedCount = 0;

					int gsc = 1;
					int sc = 0;
					for (int i = 0; i < len; i++) {
						if ((wbs [i] = sws [i]._WaitAllPrologue (pk, ref hints [i], ref sc)) == null) {
							if (hints [i] == INFLATED) {
								inflated |= 1 << i;
								inflatedCount += 1;
							} else if (pk.TryLock ()) {
								pk.UnparkSelf (StParkStatus.StateChange);
							}
						} else if (gsc != 0) {
							if (sc == 0) {
								gsc = 0;
							} else if (sc > gsc) {
								gsc = sc;
							}
						}
					}

					if (inflatedCount > 0 && pk.TryLock (inflatedCount)) {
						pk.UnparkSelf (StParkStatus.StateChange);
					}
					
					int wst = pk.Park (gsc, cargs);

					/*
					 * We opt for a less efficient but simpler implementation instead
					 * of using the same approach as the WaitAny operation, because:
					 *  - When parking, the thread would have to call into the park spot
					 *    even if it was already unparked, since we have to wait for the
					 *    other handles as well;
					 *  - We would have to deal with cancellation in a different way,
					 *    relying on interrupts instead of the TryCancel/Unpark pair;
					 *  - The Unpark operation might not wake the target thread, which
					 *    could lead to bugs.
					 */ 

					if (wst == StParkStatus.StateChange && inflatedCount > 0) {
						if (!cargs.AdjustTimeout (ref lastTime)) {
							return false;
						}
						wst = InflatedWaitMultiple (ws, true, inflated, inflatedCount, cargs);
					}
				
					if (wst != StParkStatus.StateChange) {
						for (int i = 0; i < len; i++) {
							StWaitBlock wb = wbs [i];
							if (wb != null) {
								sws [i]._CancelAcquire (wb, hints [i]);
							}
						}

						if (wst == StParkStatus.Inflated) {
							waitHint = 0;
							continue;
						}

						cargs.ThrowIfException (wst);
						return false;
					}
				}

				/*
				 * All waitables where we inserted wait blocks seem to allow an 
				 * immediate acquire operation; so, try to acquire all non-inflated
				 * waitables that are not notification events.
				 */

				int idx;
				for (idx = 0; idx < nevts; idx++) {
					try {
						if ((inflated & (1 << idx)) == 0 && !sws[idx]._TryAcquire()) {
							break;
						}
					} catch (AbandonedMutexException e) {
						ame = e;
						ame.MutexIndex = idx;
					}
				}

				if (idx == nevts) {
					if (ame != null) {
						throw ame;
					}
					return true;
				}

				/*
				 * We failed to acquire all waitables, so undo the acquires
				 * that we did above.
				 */

				for (int i = idx + 1; i < nevts; ++i) {
					if ((inflated & (1 << idx)) != 0) {
						sws[i]._UndoAcquire ();	
					}
				}

				while (--idx >= 0) {
					sws[idx]._UndoAcquire ();
				}
				
				if (!cargs.AdjustTimeout (ref lastTime)) {
					return false;
				}

				waitHint = 0;
			} while (true);
		}
Ejemplo n.º 10
0
      private void SlowUnlink (StWaitBlock wb)
      {
         StWaitBlock next;
         if ((next = wb.next) != null && next.parker.IsLocked) {
            next = next.next;
         }

         StWaitBlock p = state;
			StWaitBlock s;

         while (p != null && p != next && (s = state) != null && s != SET && s != INFLATED) {
            StWaitBlock n;
            if ((n = p.next) != null && n.parker.IsLocked) {
               p.CasNext (n, n.next);
            } else {
               p = n;
            }
         }
      }
Ejemplo n.º 11
0
      internal StNotificationEventBase (bool initialState, int sc)
      {
			id = NOTIFICATION_EVENT_ID;
         state = initialState ? SET : null;
         spinCount = Environment.ProcessorCount > 0 ? sc : 0;
      }
Ejemplo n.º 12
0
		internal void Unlink (StWaitBlock wb)
      {
         StWaitBlock s;
         if ((s = state) == SET || s == null || s == INFLATED ||
				 (wb.next == null && s == wb && Interlocked.CompareExchange (ref state, null, s) == s)) {
				return;
         }
         SlowUnlink (wb);
      }
Ejemplo n.º 13
0
 internal override void _CancelAcquire (StWaitBlock wb, StWaitBlock ignored)
 {
    Unlink (wb);
 }
Ejemplo n.º 14
0
		private StWaitBlock WaitWithParker (StParker pk, WaitType type, int key, 
														ref StWaitBlock hint, ref int sc)
      {
         StWaitBlock wb = null;
         do {
            StWaitBlock s;
            if ((s = state) == SET) {
               return null;
            }

				if (s == INFLATED) {
					hint = INFLATED;
					return null;
				}

            if (wb == null) {
               wb = new StWaitBlock (pk, type, 0, key);
            }

            wb.next = s;
            if (Interlocked.CompareExchange (ref state, wb, s) == s) {
               sc = s == null ? spinCount : 0;
               return wb;
            }
         } while (true);
      }
Ejemplo n.º 15
0
		internal RegisteredWaitHandle (WaitHandle waitObject, WaitOrTimerCallback callback, 
												 object cbState, int timeout, bool executeOnlyOnce)
		{
			this.waitObject = waitObject;
			this.callback = callback;
			this.cbState = cbState;
			this.timeout = timeout;
         this.executeOnlyOnce = executeOnlyOnce;

			StWaitable waitable;
			if ((waitable = waitObject.waitable) == null) {

				/*
				 * Either we're dealing with a disposed wait handle
				 * or with some other derived class.
				 */
 
				UnparkCallback (StParkStatus.Inflated);
				return;
			}

			cbparker = new CbParker (UnparkCallback, false, true);
			int ignored = 0;
         waitBlock = waitable._WaitAnyPrologue (cbparker, StParkStatus.Success, ref hint, ref ignored);

			state = ACTIVE;
         int ws = cbparker.EnableCallback (timeout);
         if (ws != StParkStatus.Pending) {
				UnparkCallback (ws);
	      }
		}
Ejemplo n.º 16
0
		internal abstract StWaitBlock _WaitAnyPrologue (StParker pk, int key,
		                                                ref StWaitBlock hint, ref int sc);
Ejemplo n.º 17
0
		private void UnparkCallback (int ws)
		{
			var waitable = waitObject.waitable;

			if (ws == StParkStatus.Cancelled) {
				waitable._CancelAcquire (waitBlock, hint);
		      return;
	      }

			ThreadPool.QueueUserWorkItem (_ =>
			{
				do {
					if (ws == StParkStatus.Inflated) {
						InflatedWait ();
						return;
					}
					
					if (ws != StParkStatus.Success) {
						waitable._CancelAcquire (waitBlock, hint);
					}

					if (ws != StParkStatus.Cancelled) {
						cbtid = Thread.CurrentThread.ManagedThreadId;
						callback (cbState, ws == StParkStatus.Timeout);
						cbtid = 0;
					}

					if (executeOnlyOnce || ws == StParkStatus.Cancelled) {
						FinishExecution ();
						return;
					}

					/*
					 * We must re-register with the waitable. So, initialize the 
					 * parker and execute the WaitAny prologue.
					 */

					cbparker.Reset (1);
					Thread.MemoryBarrier ();

					if (state != ACTIVE) {
						if (cbparker.TryCancel ()) {
							cbparker.Unpark (StParkStatus.Cancelled);
						}
						WaitUntilUnregistered ();
						Deactivate ();
						return;
					}
					
					int ignored = 0;
					waitBlock = waitable._WaitAnyPrologue (cbparker, StParkStatus.Success, ref hint,
					                                       ref ignored);

					ws = cbparker.EnableCallback (timeout);

					if (ws == StParkStatus.Pending) {
						return;
					}

					/*
					 * The waitable was already signalled. So, execute the unpark
					 * callback inline.
					 */ 

				} while (true);
			});
      }
Ejemplo n.º 18
0
 internal override StWaitBlock _WaitAnyPrologue (StParker pk, int key,
                                                 ref StWaitBlock hint, ref int sc)
 {
    return WaitWithParker (pk, WaitType.WaitAny, key, ref hint, ref sc);
 }