Beispiel #1
0
		internal static bool SignalAndWait (StWaitable tos, StWaitable tow, StCancelArgs cargs)
		{
			if (tos == tow) {
				return true;
			}

			var pk = new StParker ();
			StWaitBlock hint = null;
			int sc = 0;
			StWaitBlock wb = tow._WaitAnyPrologue (pk, StParkStatus.Success, ref hint, ref sc);

			if (!tos._Release ()) {
				if (wb != null && pk.TryCancel ()) {
               tow._CancelAcquire (wb, hint);
            } else {
					if (wb != null) { 
						pk.Park ();
					}
					tow._UndoAcquire ();
				}

				throw tos._SignalException;
			}

			int ws;
			
			if (hint == INFLATED || (ws = pk.Park (sc, cargs)) == StParkStatus.Inflated) {
				return tow.InflatedWait (cargs);
			}

			if (ws == StParkStatus.Success) {
				tow._WaitEpilogue ();
				return true;
			}

			tow._CancelAcquire (wb, hint);
			cargs.ThrowIfException (ws);
			return false;
		}
Beispiel #2
0
		internal abstract StWaitBlock _WaitAnyPrologue (StParker pk, int key,
		                                                ref StWaitBlock hint, ref int sc);
Beispiel #3
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;
		}
Beispiel #4
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);
		}
      private CancellationTokenSource (bool cancelled)
      {
			state = cancelled ? CANCELLED : CANNOT_BE_CANCELLED;
      }
Beispiel #6
0
		internal bool TryWaitOne (StCancelArgs cargs)
		{
			if (_TryAcquire ()) {
				return true;
			}

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

			var pk = new StParker ();
			StWaitBlock hint = null;
			int sc = 0;
			StWaitBlock wb;
			if ((wb = _WaitAnyPrologue (pk, StParkStatus.Success, ref hint, ref sc)) == null) {
				return hint != INFLATED || InflatedWait (cargs);
			}

			int ws = pk.Park (sc, cargs);

			if (ws == StParkStatus.Success) {
				_WaitEpilogue ();
				return true;
			}

			if (ws == StParkStatus.Inflated) {
				return InflatedWait (cargs);
			}

			_CancelAcquire (wb, hint);
			cargs.ThrowIfException (ws);
			return false;
		}
		private void SlowDeregisterParker (StParker pk) 
		{
         StParker next;
         if ((next = pk.pnext) != null && next.IsLocked) {
            next = next.pnext;
         }

         StParker p = state;

         while (p != null && p != next && state != null && !(state is SentinelParker)) {
				StParker n = p.pnext;
            if (n != null && n.IsLocked) {
               p.CasNext (n, n.pnext);
            } else {
               p = n;
            }
         }     
      }
Beispiel #8
0
      internal void Reset (int releasers) 
		{
         pnext = null;
         state = releasers | WAIT_IN_PROGRESS;
      }
		internal bool RegisterParker (StParker pk) 
		{
			ThrowIfDisposed ();

			if (state == CANNOT_BE_CANCELLED) {
            throw new InvalidOperationException ("CancellationTokenSource can't be cancelled");
         }

			do {
            StParker s;

            if ((s = state) == CANCELLED) {
               return false;
            }

            pk.pnext = s;
            if (Interlocked.CompareExchange (ref state, pk, s) == s) {
               return true;
            }
         } while (true);
		}
Beispiel #10
0
		internal void DeregisterParker (StParker pk) 
		{
			if (pk.pnext == null && Interlocked.CompareExchange (ref state, null, pk) == pk) {
				return;
			}
			SlowDeregisterParker (pk);
		}
Beispiel #11
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);
      }
Beispiel #12
0
 internal override StWaitBlock _WaitAllPrologue (StParker pk, ref StWaitBlock hint,
                                                 ref int sc)
 {
    return WaitWithParker (pk, WaitType.WaitAll, StParkStatus.StateChange, ref hint, ref sc);
 }
Beispiel #13
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);
 }
Beispiel #14
0
		internal abstract StWaitBlock _WaitAllPrologue (StParker pk,
		                                                ref StWaitBlock hint, ref int sc);
Beispiel #15
0
 public CancellationTokenSource ()
 {
    state = NOT_CANCELLED;
 }
Beispiel #16
0
		internal override StWaitBlock _WaitAllPrologue (StParker pk, ref StWaitBlock hint, ref int sc)
		{
			hint = INFLATED;
			return null;
		}
Beispiel #17
0
      internal bool CasNext (StParker n, StParker nn) 
		{
			return pnext == n &&
                Interlocked.CompareExchange (ref pnext, nn, n) == n;
      }