public bool Acquire(int id, StCancelArgs cargs)
 {
     m.Enter();
     try {
         if (permits >= id)
         {
             permits -= id;
             return(true);
         }
         while (true)
         {
             int lastTime = Environment.TickCount;
             cv.Wait(cargs);
             if (permits >= id)
             {
                 permits -= id;
                 return(true);
             }
             if (!cargs.AdjustTimeout(ref lastTime))
             {
                 return(false);
             }
         }
     } finally {
         m.Exit();
     }
 }
        public bool Offer(T data, StCancelArgs cargs)
        {
            m.WaitOne();
            try {
                if (buffer.Count < capacity)
                {
                    buffer.Enqueue(data);
                    nonEmpty.Pulse();
                    return(true);
                }
                while (true)
                {
                    int lastTime = Environment.TickCount;
                    nonFull.Wait(cargs);

                    if (buffer.Count < capacity)
                    {
                        buffer.Enqueue(data);
                        nonEmpty.Pulse();
                        return(true);
                    }
                    if (!cargs.AdjustTimeout(ref lastTime))
                    {
                        return(false);
                    }
                }
            } finally {
                m.Exit();
            }
        }
 public bool Poll(out T di, StCancelArgs cargs)
 {
     m.WaitOne();
     try {
         if (buffer.Count > 0)
         {
             di = buffer.Dequeue();
             nonFull.Pulse();
             return(true);
         }
         while (true)
         {
             int lastTime = Environment.TickCount;
             nonEmpty.Wait(cargs);
             if (buffer.Count > 0)
             {
                 di = buffer.Dequeue();
                 nonFull.Pulse();
                 return(true);
             }
             if (!cargs.AdjustTimeout(ref lastTime))
             {
                 di = default(T);
                 return(false);
             }
         }
     } finally {
         m.Exit();
     }
 }
Example #4
0
		internal bool SlowEnter (StCancelArgs cargs)
		{
			int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0;
			StWaitBlock wb = null;
			do {
				int sc = spinCount;
#if NET_4_0
				var spinWait = new SpinWait ();
#endif
				do {
					if (state == FREE &&
					    Interlocked.CompareExchange (ref state, BUSY, FREE) == FREE) {
						return true;
					}
					if (top != null || sc-- <= 0) {
						break;
					}
#if NET_4_0
					spinWait.SpinOnce ();
#else
					Thread.SpinWait (1);
#endif
				} while (true);


				if (wb == null) {
					wb = new StWaitBlock (1);
				} else {
					wb.parker.Reset ();
				}

				do {
					StWaitBlock t;
					wb.next = t = top;
					if (Interlocked.CompareExchange (ref top, wb, t) == t) {
						break;
					}
				} while (true);

				if (TryEnter ()) {
					wb.parker.SelfCancel ();
					return true;
				}

				int ws = wb.parker.Park (cargs);

				if (ws != StParkStatus.Success) {
					cargs.ThrowIfException (ws);
					return false;
				}

				if (TryEnter ()) {
					return true;
				}
				
				if (!cargs.AdjustTimeout (ref lastTime)) {
					return false;
				}
			} while (true);
		}
Example #5
0
		/*
		 * No need to worry about inflating as this is not called by Semaphore.
		 */

		internal bool TryWait (int acquireCount, StCancelArgs cargs)
		{
			if (acquireCount <= 0 || acquireCount > maximumCount) {
				throw new ArgumentException ("acquireCount");
			}

			if (TryAcquireInternal (acquireCount)) {
				return true;
			}

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

			var wb = new StWaitBlock (WaitType.WaitAny, acquireCount);
			int sc = EnqueueAcquire (wb, acquireCount);

			int ws = wb.parker.Park (sc, cargs);
			if (ws == StParkStatus.Success) {
				return true;
			}

			CancelAcquire (wb);
			cargs.ThrowIfException (ws);
			return false;
		}
        //
        // Waits until notification, activating the specified
        // cancellers.
        //

        public bool Wait(StCancelArgs cargs)
        {
            EnsureIsOwned();

            WaitBlock wb;

            queue.Enqueue(wb = new WaitBlock(WaitType.WaitAny));

            int lockState = mlock.ExitCompletely();
            int ws        = wb.parker.Park(cargs);

            mlock.Reenter(ws, lockState);

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

            queue.Remove(wb);
            StCancelArgs.ThrowIfException(ws);
            return(false);
        }
Example #7
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;
		}
Example #8
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);
		}
Example #9
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;
		}
Example #10
0
		private int ParkSingle (StCancelArgs cargs, ref bool interrupted)
		{
			do {
				try {
					return StInternalMethods.WaitForParkSpot_internal (parkSpot, cargs.Timeout)
						  ? StParkStatus.Success
						  : StParkStatus.Timeout;
				} catch (ThreadInterruptedException) {
					if (interrupted) {
						return StParkStatus.Interrupted;
					}
					interrupted = true;
				}
			} while (true);
		}
Example #11
0
		internal bool InflatedWait (StCancelArgs cargs) 
		{
			/*
			 * Waits coming from a ManualResetEventSlim are cancellable.
			 */
#if NET_4_0 || MOBILE
			using (cargs.CancellationToken.RegisterInternal (t => ((Thread)t).Interrupt (), 
																			 Thread.CurrentThread)) 
#endif
			{
				bool release = false;
				try {
					swhandle.DangerousAddRef (ref release);
					return StInternalMethods.Wait_internal (swhandle.DangerousGetHandle (), cargs.Timeout);
#if NET_4_0 || MOBILE
				} catch (ThreadInterruptedException) {
					cargs.ThrowIfException (cargs.CancellationToken.IsCancellationRequested 
						                     ? StParkStatus.Cancelled
													: StParkStatus.Interrupted);
					return false;
#endif
				} finally {
					if (release) {
						swhandle.DangerousRelease ();
					}
				}
			}
		}
Example #12
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;
		}
Example #13
0
      internal int Park(StCancelArgs cargs) 
		{
			return Park (0, null, 0, 0, cargs);
      }
Example #14
0
 	internal int Park (int spinCount, StCancelArgs cargs)
    {
    	return Park (spinCount, null, 0, 0, cargs);
    }
Example #15
0
   	private int ParkMultiple (StWaitable[] waitables, int inflatedIndexes, int inflatedCount,
   	                          StCancelArgs cargs)
   	{
			var handles = new SafeWaitHandle[inflatedCount];
			var refs = new bool[inflatedCount];

			try
			{
   			for (int i = 0, handleIdx = 0; i < waitables.Length; ++i) {
   				if ((inflatedIndexes & (1 << i)) != 0) {
						var swhandle = waitables [i].swhandle;
						swhandle.DangerousAddRef (ref refs [handleIdx]);
   					handles [handleIdx++] = swhandle;
   				}
   			}

				int res = StInternalMethods.WaitMultiple_internal (parkSpot, handles, false, cargs.Timeout);
				return res == WaitHandle.WaitTimeout ? StParkStatus.Success : StParkStatus.Timeout;
			} finally {
				for (int i = 0; i < handles.Length; ++i) {
					if (refs [i]) {
						handles [i].DangerousRelease ();
					}
				}
			}
   	}
Example #16
0
		internal bool TryEnter (StCancelArgs cargs)
		{
			return TryEnter () || (cargs.Timeout != 0 && SlowEnter (cargs));
		}
Example #17
0
		private static int InflatedWaitMultiple (StWaitable[] ws, bool waitAll, int inflatedIndexes,
															  int inflatedCount, StCancelArgs cargs)
		{
			var handles = new SafeWaitHandle [inflatedCount];
			var refs = new bool [inflatedCount];
#if NET_4_0 || MOBILE
			var reg = default (CancellationTokenRegistration);
#endif

			try {
				for (int i = 0, handleIdx = 0; i < ws.Length; ++i) {
					if ((inflatedIndexes & (1 << i)) != 0) {
						var swhandle = ws [i].swhandle;
						swhandle.DangerousAddRef (ref refs [handleIdx]);
						handles [handleIdx++] = swhandle;
					}
				}

#if NET_4_0 || MOBILE
				reg = cargs.CancellationToken.RegisterInternal (t => ((Thread) t).Interrupt (),
				                                                Thread.CurrentThread);
#endif
				int res = StInternalMethods.WaitMultiple_internal (IntPtr.Zero, handles, waitAll,
				                                                   cargs.Timeout);
				return res == WaitHandle.WaitTimeout ? StParkStatus.Success : StParkStatus.Timeout;
#if NET_4_0 || MOBILE
			} catch (ThreadInterruptedException) {
				return cargs.CancellationToken.IsCancellationRequested 
					  ? StParkStatus.Cancelled 
					  : StParkStatus.Interrupted;
#endif
			} finally {
				for (int i = 0; i < handles.Length; ++i) {
					if (refs [i]) {
						handles [i].DangerousRelease ();
					}
				}
#if NET_4_0 || MOBILE
				reg.Dispose ();
#endif
			}
		}
Example #18
0
		internal int Park (int spinCount, StWaitable[] waitables, int inflatedIndexes, 
								 int inflatedCount, StCancelArgs cargs) 
		{
#if NET_4_0
			var spinWait = new SpinWait ();
#endif
			do {
				if (state == 0) {
					return waitStatus;
				}
#if NET_4_0
				if (cargs.CancellationToken.IsCancellationRequested && TryCancel ()) {
					return StParkStatus.Cancelled;
				}
#endif
				if (spinCount-- <= 0) {
					break;
				}
#if NET_4_0
				spinWait.SpinOnce ();
#else
			Thread.SpinWait (1);
#endif
			} while (true);

			RuntimeHelpers.PrepareConstrainedRegions ();
			try
			{
				StInternalMethods.Alloc_internal (ref parkSpot);

				if (parkSpot == IntPtr.Zero) {
					
					/*
					 * FIXME: What's the right thing to do here?
					 */
					
					throw new OutOfMemoryException ();
				}
				
				if (!TestAndClearInProgress ()) {
					return waitStatus;
				}

				bool interrupted = false;

#if NET_4_0 || MOBILE
				bool unregister = false;

				if (cargs.CancellationToken.CanBeCanceled && 
					 !(unregister = cargs.CancellationToken.cts.RegisterParker (this))) {
					
					if (TryCancel ()) {
						return StParkStatus.Cancelled;
					}

					cargs = StCancelArgs.None;
				}
#endif

				int ws = inflatedCount == 0
						 ? ParkSingle (cargs, ref interrupted)
						 : ParkMultiple (waitables, inflatedIndexes, inflatedCount, cargs);

				if (ws != StParkStatus.Success) {
					if (TryCancel ()) {
						UnparkSelf(ws > StParkStatus.Success ? GetWaitAnyIndex (inflatedIndexes, ws) : ws);
					} else {
						if (ws > StParkStatus.Success) {
							waitables[GetWaitAnyIndex (inflatedIndexes, ws)]._UndoAcquire ();
						}

						do {
							try {
								StInternalMethods.WaitForParkSpot_internal (parkSpot, Timeout.Infinite);
								break;
							} catch (Exception) { }
						} while (true);
					}
				}

#if NET_4_0
				if (unregister) {
					cargs.CancellationToken.cts.DeregisterParker (this);
				}
#endif
				
				return waitStatus;
			} finally {
				if (parkSpot != IntPtr.Zero) {
					StInternalMethods.Free_internal (parkSpot);
				}
			}
		}