예제 #1
0
        // Plinq supresses OCE(externalCT) occuring in worker threads and then throws a single OCE(ct)
        // if a manual OCE(ct) is thrown but ct is not canceled, Plinq should not suppress it, else things
        // get confusing...
        // ONLY an OCE(ct) for ct.IsCancellationRequested=true is co-operative cancellation
        private static bool Bugfix632544_OnlySuppressOCEifCTCanceled()
        {
            bool passed = true;

#if !PFX_LEGACY_3_5
            TestHarness.TestLog("* PlinqCancellationTests.Bugfix632544_OnlySuppressOCEifCTCanceled()");

            AggregateException      caughtException = null;
            CancellationTokenSource cts             = new CancellationTokenSource();
            CancellationToken       externalToken   = cts.Token;
            try
            {
                Enumerable.Range(1, 10).AsParallel()
                .WithCancellation(externalToken)
                .Select(
                    x =>
                {
                    if (x % 2 == 0)
                    {
                        throw new OperationCanceledException(externalToken);
                    }
                    return(x);
                }
                    )
                .ToArray();
            }
            catch (AggregateException ae)
            {
                caughtException = ae;
            }

            passed &= TestHarnessAssert.IsNotNull(caughtException, "We expect this OCE(ct) to merely be aggregated.");
#endif
            return(passed);
        }
예제 #2
0
        // a specific repro where inner queries would see an ODE on the merged cancellation token source
        // when the implementation involved disposing and recreating the token on each worker thread
        private static bool Cancellation_ODEIssue()
        {
            bool passed = true;
            AggregateException caughtException = null;

            try
            {
                Enumerable.Range(0, 1999).ToArray()
                .AsParallel().AsUnordered()
                .WithExecutionMode(ParallelExecutionMode.ForceParallelism)
                .Zip <int, int, int>(
                    Enumerable.Range(1000, 20).Select <int, int>(_item => (int)_item).AsParallel().AsUnordered(),
                    (first, second) => { throw new OperationCanceledException(); })
                .ForAll(x => { });
            }
            catch (AggregateException ae)
            {
                caughtException = ae;
            }

            //the failure was an ODE coming out due to an ephemeral disposed merged cancellation token source.
            passed &= TestHarnessAssert.IsTrue(caughtException != null,
                                               "We expect an aggregate exception with OCEs in it.");

            return(passed);
        }
예제 #3
0
        /// <summary>
        ///
        /// Bug535510:
        ///   This bug occured because the QuerySettings structure was not being deep-cloned during
        ///   query-opening.  As a result, the concurrent inner-enumerators (for the RHS operators)
        ///   that occur in SelectMany were sharing CancellationState that they should not have.
        ///   The result was that enumerators could falsely believe they had been canceled when
        ///   another inner-enumerator was disposed.
        ///
        ///   Note: the failure was intermittent.  this test would fail about 1 in 2 times on mikelid1 (4-core).
        /// </summary>
        /// <returns></returns>
        private static bool BugFix535510_CloningQuerySettingsForSelectMany()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.BugFix535510_CloningQuerySettingsForSelectMany()");

            var       plinq_src       = ParallelEnumerable.Range(0, 1999).AsParallel();
            Exception caughtException = null;

            try
            {
                var inner  = ParallelEnumerable.Range(0, 20).AsParallel().Select(_item => _item);
                var output = plinq_src
                             .SelectMany(
                    _x => inner,
                    (_x, _y) => _x
                    )
                             .ToArray();
            }
            catch (Exception ex)
            {
                caughtException = ex;
            }

            passed &= TestHarnessAssert.IsNull(caughtException, "No exception should occur.");
            return(passed);
        }
예제 #4
0
        private static bool MultiplesWithCancellationIsIllegal()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.MultiplesWithCancellationIsIllegal()");

            InvalidOperationException caughtException = null;

            try
            {
                CancellationTokenSource cs = new CancellationTokenSource();
                CancellationToken       ct = cs.Token;
                var query = Enumerable.Range(1, 10).AsParallel().WithDegreeOfParallelism(2).WithDegreeOfParallelism(2);
                query.ToArray();
            }
            catch (InvalidOperationException ex)
            {
                caughtException = ex;
                //Console.WriteLine("IOE caught. message = " + ex.Message);
            }

            passed &= TestHarnessAssert.IsNotNull(caughtException, "An exception should be thrown.");

            return(passed);
        }
예제 #5
0
        public static bool PreCanceledToken_SimpleEnumerator()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.PreCanceledToken_SimpleEnumerator()");

            OperationCanceledException caughtException = null;
            var cs = new CancellationTokenSource();

            cs.Cancel();

            int[] srcEnumerable = Enumerable.Range(0, 1000).ToArray();
            ThrowOnFirstEnumerable <int> throwOnFirstEnumerable = new ThrowOnFirstEnumerable <int>(srcEnumerable);

            try
            {
                var query = throwOnFirstEnumerable
                            .AsParallel()
                            .WithCancellation(cs.Token);

                foreach (var item in query)
                {
                }
            }
            catch (OperationCanceledException ex)
            {
                caughtException = ex;
            }

            passed &= TestHarnessAssert.IsNotNull(caughtException, "an OCE should be throw during query opening");
            passed &= TestHarnessAssert.AreEqual(cs.Token, OCEHelper.ExtractCT(caughtException), "The OCE should reference the cancellation token.");

            return(passed);
        }
예제 #6
0
        // throwing a fake OCE(ct) when the ct isn't canceled should produce an AggregateException.
        private static bool Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_2()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_2()");

            try
            {
                CancellationTokenSource cs = new CancellationTokenSource();
                var plinq = Enumerable.Range(0, 50)
                            .AsParallel().WithCancellation(cs.Token)
                            .WithDegreeOfParallelism(1)
#if PFX_LEGACY_3_5
                            .Union(Enumerable.Range(0, 10).AsParallel().Select <int, int>(x => { throw new OperationCanceledException(); }));
#else
                            .Union(Enumerable.Range(0, 10).AsParallel().Select <int, int>(x => { throw new OperationCanceledException(cs.Token); }));
#endif


                var walker = plinq.GetEnumerator();
                while (walker.MoveNext())
                {
                    Thread.Sleep(1);
                }
                walker.MoveNext();
                passed &= TestHarnessAssert.Fail("AggregateException was expected, but no exception occured.");
            }
예제 #7
0
        // After running a plinq query, we expect the internal cancellation token source to have been disposed.
        // The critical thing is that there are no callbacks left hanging on the external tokens callback list, else we
        // could be causing an accumulation of junk that will not GC until the external token goes away (possibly never).
        private static bool Bugfix626345_PlinqShouldDisposeLinkedToken()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.Bugfix626345_PlinqShouldDisposeLinkedToken()");

#if DEBUG
            // Only run these in debug mode, because they rely on a debug-only property.
            PropertyInfo callbackCountProperty =
                typeof(CancellationTokenSource).
                GetProperty("CallbackCount", BindingFlags.Instance | BindingFlags.NonPublic);
            if (callbackCountProperty == null)
            {
                TestHarness.TestLog("    - Error: CancellationTokenSource.CallbackCount property not found; was it removed?");
                return(false);
            }
            Func <CancellationTokenSource, int> getCallbackCount =
                _ => (int)callbackCountProperty.GetValue(_, null);

            CancellationTokenSource cts = new CancellationTokenSource();
            CancellationToken       ct  = cts.Token;

            // ForAll
            Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).ForAll((x) => { });
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");

            // Built-in-aggregation
            Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Average();
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");

            // Manual aggregation
            Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Aggregate((a, b) => a + b);
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");

            // ToArray  (uses ToList, which enumerates the query with foreach())
            Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).ToArray();
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");

            // AsynchronousChannelMergeEnumerator
            foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Select(xx => xx))
            {
            }
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");

            // SynchronousChannelMergeEnumerator
            foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).WithMergeOptions(ParallelMergeOptions.FullyBuffered))
            {
            }
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");

            // Fallback to sequential
            foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Where(xx => true).Skip(4))
            {
            }
            passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty.");
#endif

            return(passed);
        }
예제 #8
0
        // Tests that the shared state variable seems to be working correctly.
        private static bool RunManualResetEventSlimTest4_CombinedStateTests()
        {
            bool passed = true;

            TestHarness.TestLog("* RunManualResetEventSlimTest4_CombinedStateTests()");

            ManualResetEventSlim mres = new ManualResetEventSlim(false, 100);
            int expectedCount         = Environment.ProcessorCount == 1 ? 1 : 100;

            passed &= TestHarnessAssert.AreEqual(expectedCount, mres.SpinCount, "Spin count did not write/read correctly, expected " + expectedCount + ", actual " + mres.SpinCount);
            passed &= TestHarnessAssert.IsFalse(mres.IsSet, "Set did not read correctly.");
            mres.Set();
            passed &= TestHarnessAssert.IsTrue(mres.IsSet, "Set did not write/read correctly.");

            return(passed);
        }
예제 #9
0
        private static bool CancellationTokenTest_NonSorting_SynchronousMergerEnumeratorDispose()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.CancellationTokenTest_NonSorting_SynchronousMergerEnumeratorDispose()");

            int size = 10000;
            CancellationTokenSource tokenSource = new CancellationTokenSource();
            Exception caughtException           = null;

            var query =
                Enumerable.Range(1, size).AsParallel()
                .WithCancellation(tokenSource.Token)
                .Select(
                    i =>
            {
                Thread.Sleep(100);
                return(i);
            }).WithMergeOptions(ParallelMergeOptions.FullyBuffered);

            IEnumerator <int> enumerator = query.GetEnumerator();

            ThreadPool.QueueUserWorkItem(
                (arg) =>
            {
                Thread.Sleep(1000);
                enumerator.Dispose();
            });

            try
            {
                // This query should run for at least a few seconds due to the sleeps in the select-delegate
                for (int j = 0; j < 1000; j++)
                {
                    enumerator.MoveNext();
                }
            }
            catch (ObjectDisposedException ex)
            {
                caughtException = ex;
            }

            passed &= TestHarnessAssert.IsNotNull(caughtException, "An ObjectDisposedException should be thrown");

            return(passed);
        }
예제 #10
0
        // Tests timeout on an event that is never set.
        private static bool RunManualResetEventSlimTest3_ConstructorTests()
        {
            bool passed = true;

            TestHarness.TestLog("* RunManualResetEventSlimTest3_ConstructorTests()");
            passed &= TestHarnessAssert.EnsureExceptionThrown(
                () => new ManualResetEventSlim(false, 2048),           //max value is 2047.
                typeof(ArgumentOutOfRangeException),
                "The max value for spin count is 2047. An ArgumentException should be thrown.");

            passed &= TestHarnessAssert.EnsureExceptionThrown(
                () => new ManualResetEventSlim(false, -1),
                typeof(ArgumentOutOfRangeException),
                "The min value for spin count is 0. An ArgumentException should be thrown.");

            return(passed);
        }
예제 #11
0
        private static bool CancellationTokenTest_Sorting_ToArray()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.CancellationTokenTest_Sorting_ToArray()");

            int size = 10000;
            CancellationTokenSource tokenSource = new CancellationTokenSource();

            ThreadPool.QueueUserWorkItem(
                (arg) =>
            {
                Thread.Sleep(500);
                tokenSource.Cancel();
            });

            OperationCanceledException caughtException = null;

            try
            {
                // This query should run for at least a few seconds due to the sleeps in the select-delegate
                var query =
                    Enumerable.Range(1, size).AsParallel()
                    .WithCancellation(tokenSource.Token)
                    .Select(
                        i =>
                {
                    Thread.Sleep(1);
                    return(i);
                });

                query.ToArray();
            }
            catch (OperationCanceledException ex)
            {
                caughtException = ex;
            }

            passed &= TestHarnessAssert.IsNotNull(caughtException, "An OCE should be thrown");
            passed &= TestHarnessAssert.AreEqual(tokenSource.Token, OCEHelper.ExtractCT(caughtException),
                                                 "The OCE should reference the external token.");
            return(passed);
        }
예제 #12
0
        private static bool RunThreadLocalTest5_Dispose()
        {
            TestHarness.TestLog("* RunThreadLocalTest5_Dispose()");

            ThreadLocal <string> tl = new ThreadLocal <string>(() => "dispose test");
            string value            = tl.Value;

            tl.Dispose();

            if (!TestHarnessAssert.EnsureExceptionThrown(() => { string tmp = tl.Value; }, typeof(ObjectDisposedException), "The Value property of the disposed ThreadLocal object should throw ODE"))
            {
                return(false);
            }

            if (!TestHarnessAssert.EnsureExceptionThrown(() => { bool tmp = tl.IsValueCreated; }, typeof(ObjectDisposedException), "The IsValueCreated property of the disposed ThreadLocal object should throw ODE"))
            {
                return(false);
            }

            if (!TestHarnessAssert.EnsureExceptionThrown(() => { string tmp = tl.ToString(); }, typeof(ObjectDisposedException), "The ToString method of the disposed ThreadLocal object should throw ODE"))
            {
                return(false);
            }


            // test recycling the combination index;

            tl = new ThreadLocal <string>(() => null);
            if (tl.IsValueCreated)
            {
                TestHarness.TestLog("* Filed, reusing the same index kept the old value and didn't use the new value.");
                return(false);
            }
            if (tl.Value != null)
            {
                TestHarness.TestLog("* Filed, reusing the same index kept the old value and didn't use the new value.");
                return(false);
            }


            return(true);
        }
예제 #13
0
        private static bool RunManualResetEventSlimTest5_Dispose()
        {
            bool passed = true;

            TestHarness.TestLog("* RunManualResetEventSlimTest5_Dispose()");
            ManualResetEventSlim mres = new ManualResetEventSlim(false);

            mres.Dispose();

            passed &= TestHarnessAssert.EnsureExceptionThrown(
                () => mres.Reset(),
                typeof(ObjectDisposedException),
                "The object has been disposed, should throw ObjectDisposedException.");

            passed &= TestHarnessAssert.EnsureExceptionThrown(
                () => mres.Wait(0),
                typeof(ObjectDisposedException),
                "The object has been disposed, should throw ObjectDisposedException.");


            passed &= TestHarnessAssert.EnsureExceptionThrown(
                () =>
            {
                WaitHandle handle = mres.WaitHandle;
            },
                typeof(ObjectDisposedException),
                "The object has been disposed, should throw ObjectDisposedException.");

            mres = new ManualResetEventSlim(false);;
            ManualResetEvent mre = (ManualResetEvent)mres.WaitHandle;

            mres.Dispose();

            passed &= TestHarnessAssert.EnsureExceptionThrown(
                () => mre.WaitOne(0, false),
                typeof(ObjectDisposedException),
                "The underlying event object has been disposed, should throw ObjectDisposedException.");

            return(passed);
        }
예제 #14
0
        private static bool CancellationTokenTest_NonSorting_ToArray_ExternalCancel()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.CancellationTokenTest_NonSorting_ToArray_ExternalCancel()");

            int size = 10000;
            CancellationTokenSource    tokenSource     = new CancellationTokenSource();
            OperationCanceledException caughtException = null;

            ThreadPool.QueueUserWorkItem(
                (arg) =>
            {
                Thread.Sleep(1000);
                tokenSource.Cancel();
            });

            try
            {
                int[] output = Enumerable.Range(1, size).AsParallel()
                               .WithCancellation(tokenSource.Token)
                               .Select(
                    i =>
                {
                    Thread.Sleep(100);
                    return(i);
                }).ToArray();
            }
            catch (OperationCanceledException ex)
            {
                caughtException = ex;
            }

            passed &= TestHarnessAssert.IsNotNull(caughtException, "An ObjectDisposedException should be thrown");
            passed &= TestHarnessAssert.AreEqual(tokenSource.Token, OCEHelper.ExtractCT(caughtException), "The OCE should reference the external cancellation token.");

            return(passed);
        }
예제 #15
0
        private static bool Bug599487_MoveNextAfterQueryOpeningFailsIsIllegal()
        {
            TestHarness.TestLog("* MoveNextAfterQueryOpeningFailsIsIllegal()");
            bool success = true;
            var  query   = Enumerable.Range(0, 10)
                           .AsParallel()
                           .Select <int, int>(x => { throw new ApplicationException(); })
                           .OrderBy(x => x);

            IEnumerator <int> enumerator = query.GetEnumerator();

            //moveNext will cause queryOpening to fail (no element generated)
            success &= TestHarnessAssert.EnsureExceptionThrown(
                () => enumerator.MoveNext(),
                typeof(AggregateException), "An AggregateException(containing ApplicationException) should be thrown");

            //moveNext after queryOpening failed
            success &= TestHarnessAssert.EnsureExceptionThrown(
                () => enumerator.MoveNext(),
                typeof(InvalidOperationException), "A second attempt to enumerate should cause InvalidOperationException");

            return(success);
        }
예제 #16
0
        /// <summary>Tests for the Value factory throws an exception.</summary>
        /// <returns>True if the tests succeeds, false otherwise.</returns>
        private static bool RunLazyTest9_Exceptions()
        {
            TestHarness.TestLog("* RunLazyTest9_Exceptions()");
            int           counter = m_exceptionCounter;
            Lazy <string> l       = new Lazy <string>(() =>
            {
                m_exceptionCounter++;
                int zero = 0;
                int x    = 1 / zero;
                return("");
            }, true);
            string s;

            if (!TestHarnessAssert.EnsureExceptionThrown(() => s = l.Value, typeof(DivideByZeroException), "Expected DivideByZeroException"))
            {
                TestHarness.TestLog("failed");
                return(false);
            }
            if (!TestHarnessAssert.EnsureExceptionThrown(() => s = l.Value, typeof(DivideByZeroException), "Expected DivideByZeroException"))
            {
                TestHarness.TestLog("failed");
                return(false);
            }
            if (!TestHarnessAssert.AreEqual <int>(counter + 1, m_exceptionCounter, "value factory has been called twise and it should be called only once."))
            {
                TestHarness.TestLog("failed");
                return(false);
            }

            if (l.IsValueCreated)
            {
                TestHarness.TestLog("failed* IsValueCreated should return false.");
                return(false);
            }

            return(true);
        }
예제 #17
0
        // REPRO 1 -- cancellation
        private static bool Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_1()
        {
            bool passed = true;

            TestHarness.TestLog("* PlinqCancellationTests.Bugfix640886_SetOperationsThrowAggregateOnCancelOrDispose_1()");

            var mre       = new ManualResetEvent(false);
            var plinq_src =
                Enumerable.Range(0, 5000000).Select(x =>
            {
                if (x == 0)
                {
                    mre.Set();
                }
                return(x);
            });

            Task t = null;

            try
            {
                CancellationTokenSource cs = new CancellationTokenSource();
                var plinq = plinq_src
                            .AsParallel().WithCancellation(cs.Token)
                            .WithDegreeOfParallelism(1)
                            .Union(Enumerable.Range(0, 10).AsParallel());

                var walker = plinq.GetEnumerator();

                t = Task.Factory.StartNew(() =>
                {
                    mre.WaitOne();
                    cs.Cancel();
                });
                while (walker.MoveNext())
                {
                    Thread.Sleep(1);
                    var item = walker.Current;
                }
                walker.MoveNext();
                passed &= TestHarnessAssert.Fail("OperationCanceledException was expected, but no exception occured.");
            }
            catch (OperationCanceledException)
            {
                //This is expected.
            }

            catch (Exception e)
            {
                passed &= TestHarnessAssert.Fail("OperationCanceledException was expected, but a different exception occured.");
                TestHarness.TestLog(e.ToString());
            }

            if (t != null)
            {
                t.Wait();
            }


            return(passed);
        }