示例#1
0
        public void DisposeHandles()
        {
            // Ensure that disposed handles correctly remove their virtual and physical regions.

            RegionHandle handle = _tracking.BeginTracking(0, PageSize);

            handle.Reprotect();

            Assert.AreEqual((1, 1), _tracking.GetRegionCounts());

            handle.Dispose();

            Assert.AreEqual((0, 0), _tracking.GetRegionCounts());

            // Two handles, small entirely contains big.
            // We expect there to be three regions after creating both, one for the small region and two covering the big one around it.
            // Regions are always split to avoid overlapping, which is why there are three instead of two.

            RegionHandle handleSmall = _tracking.BeginTracking(PageSize, PageSize);
            RegionHandle handleBig   = _tracking.BeginTracking(0, PageSize * 4);

            Assert.AreEqual((3, 3), _tracking.GetRegionCounts());

            // After disposing the big region, only the small one will remain.
            handleBig.Dispose();

            Assert.AreEqual((1, 1), _tracking.GetRegionCounts());

            handleSmall.Dispose();

            Assert.AreEqual((0, 0), _tracking.GetRegionCounts());
        }
示例#2
0
        public void SingleRegion()
        {
            RegionHandle handle = _tracking.BeginTracking(0, PageSize);

            (ulong address, ulong size)? readTrackingTriggered = null;
            handle.RegisterAction((address, size) =>
            {
                readTrackingTriggered = (address, size);
            });

            bool dirtyInitial = handle.Dirty;

            Assert.True(dirtyInitial); // Handle starts dirty.

            handle.Reprotect();

            bool dirtyAfterReprotect = handle.Dirty;

            Assert.False(dirtyAfterReprotect); // Handle is no longer dirty.

            _tracking.VirtualMemoryEvent(PageSize * 2, 4, true);
            _tracking.VirtualMemoryEvent(PageSize * 2, 4, false);

            bool dirtyAfterUnrelatedReadWrite = handle.Dirty;

            Assert.False(dirtyAfterUnrelatedReadWrite); // Not dirtied, as the write was to an unrelated address.

            Assert.IsNull(readTrackingTriggered);       // Hasn't been triggered yet

            _tracking.VirtualMemoryEvent(0, 4, false);

            bool dirtyAfterRelatedRead = handle.Dirty;

            Assert.False(dirtyAfterRelatedRead);                // Only triggers on write.
            Assert.AreEqual(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered.

            readTrackingTriggered = null;
            _tracking.VirtualMemoryEvent(0, 4, true);

            bool dirtyAfterRelatedWrite = handle.Dirty;

            Assert.True(dirtyAfterRelatedWrite); // Dirty flag should now be set.

            _tracking.VirtualMemoryEvent(4, 4, true);
            bool dirtyAfterRelatedWrite2 = handle.Dirty;

            Assert.True(dirtyAfterRelatedWrite2); // Dirty flag should still be set.

            handle.Reprotect();

            bool dirtyAfterReprotect2 = handle.Dirty;

            Assert.False(dirtyAfterReprotect2); // Handle is no longer dirty.

            handle.Dispose();

            bool dirtyAfterDispose = TestSingleWrite(handle, 0, 4);

            Assert.False(dirtyAfterDispose); // Handle cannot be triggered when disposed
        }
示例#3
0
        protected override LResult WindowProcedure(WindowHandle window, MessageType message, WParam wParam, LParam lParam)
        {
            switch (message)
            {
            case MessageType.Size:
                cxClient = lParam.LowWord;
                cyClient = lParam.HighWord;

                CursorHandle hCursor = Windows.SetCursor(CursorId.Wait);
                Windows.ShowCursor(true);

                hRgnClip.Dispose();

                Span <RegionHandle> hRgnTemp = stackalloc RegionHandle[6];

                hRgnTemp[0] = Gdi.CreateEllipticRegion(Rectangle.FromLTRB(0, cyClient / 3, cxClient / 2, 2 * cyClient / 3));
                hRgnTemp[1] = Gdi.CreateEllipticRegion(Rectangle.FromLTRB(cxClient / 2, cyClient / 3, cxClient, 2 * cyClient / 3));
                hRgnTemp[2] = Gdi.CreateEllipticRegion(Rectangle.FromLTRB(cxClient / 3, 0, 2 * cxClient / 3, cyClient / 2));
                hRgnTemp[3] = Gdi.CreateEllipticRegion(Rectangle.FromLTRB(cxClient / 3, cyClient / 2, 2 * cxClient / 3, cyClient));
                hRgnTemp[4] = Gdi.CreateRectangleRegion(Rectangle.FromLTRB(0, 0, 1, 1));
                hRgnTemp[5] = Gdi.CreateRectangleRegion(Rectangle.FromLTRB(0, 0, 1, 1));
                hRgnClip    = Gdi.CreateRectangleRegion(Rectangle.FromLTRB(0, 0, 1, 1));
                hRgnTemp[4].CombineRegion(hRgnTemp[0], hRgnTemp[1], CombineRegionMode.Or);
                hRgnTemp[5].CombineRegion(hRgnTemp[2], hRgnTemp[3], CombineRegionMode.Or);
                hRgnClip.CombineRegion(hRgnTemp[4], hRgnTemp[5], CombineRegionMode.Xor);
                for (int i = 0; i < 6; i++)
                {
                    hRgnTemp[i].Dispose();
                }

                Windows.SetCursor(hCursor);
                Windows.ShowCursor(false);

                return(0);

            case MessageType.Paint:
                using (DeviceContext dc = window.BeginPaint())
                {
                    dc.SetViewportOrigin(new Point(cxClient / 2, cyClient / 2));
                    dc.SelectClippingRegion(hRgnClip);

                    double fRadius = Hypotenuse(cxClient / 2.0, cyClient / 2.0);

                    for (double fAngle = 0.0; fAngle < TWO_PI; fAngle += TWO_PI / 360)
                    {
                        dc.MoveTo(default);
                        dc.LineTo(new Point(
                                      (int)(fRadius * Math.Cos(fAngle) + 0.5),
                                      (int)(-fRadius * Math.Sin(fAngle) + 0.5)));
                    }
                }
示例#4
0
 public void Dispose() => _impl.Dispose();
示例#5
0
        public void Multithreading()
        {
            // Multithreading sanity test
            // Multiple threads can easily read/write memory regions from any existing handle.
            // Handles can also be owned by different threads, though they should have one owner thread.
            // Handles can be created and disposed at any time, by any thread.

            // This test should not throw or deadlock due to invalid state.

            const int threadCount      = 1;
            const int handlesPerThread = 16;
            long      finishedTime     = 0;

            RegionHandle[] handles    = new RegionHandle[threadCount * handlesPerThread];
            Random         globalRand = new Random();

            for (int i = 0; i < handles.Length; i++)
            {
                handles[i] = _tracking.BeginTracking((ulong)i * PageSize, PageSize);
                handles[i].Reprotect();
            }

            List <Thread> testThreads = new List <Thread>();

            // Dirty flag consumer threads
            int dirtyFlagReprotects = 0;

            for (int i = 0; i < threadCount; i++)
            {
                int randSeed = i;
                testThreads.Add(new Thread(() =>
                {
                    int handleBase = randSeed * handlesPerThread;
                    while (Stopwatch.GetTimestamp() < finishedTime)
                    {
                        Random random       = new Random(randSeed);
                        RegionHandle handle = handles[handleBase + random.Next(handlesPerThread)];

                        if (handle.Dirty)
                        {
                            handle.Reprotect();
                            Interlocked.Increment(ref dirtyFlagReprotects);
                        }
                    }
                }));
            }

            // Write trigger threads
            int writeTriggers = 0;

            for (int i = 0; i < threadCount; i++)
            {
                int randSeed = i;
                testThreads.Add(new Thread(() =>
                {
                    Random random    = new Random(randSeed);
                    ulong handleBase = (ulong)(randSeed * handlesPerThread * PageSize);
                    while (Stopwatch.GetTimestamp() < finishedTime)
                    {
                        _tracking.VirtualMemoryEvent(handleBase + (ulong)random.Next(PageSize * handlesPerThread), PageSize / 2, true);
                        Interlocked.Increment(ref writeTriggers);
                    }
                }));
            }

            // Handle create/delete threads
            int handleLifecycles = 0;

            for (int i = 0; i < threadCount; i++)
            {
                int randSeed = i;
                testThreads.Add(new Thread(() =>
                {
                    int maxAddress = threadCount * handlesPerThread * PageSize;
                    Random random  = new Random(randSeed + 512);
                    while (Stopwatch.GetTimestamp() < finishedTime)
                    {
                        RegionHandle handle = _tracking.BeginTracking((ulong)random.Next(maxAddress), (ulong)random.Next(65536));

                        handle.Dispose();

                        Interlocked.Increment(ref handleLifecycles);
                    }
                }));
            }

            finishedTime = Stopwatch.GetTimestamp() + Stopwatch.Frequency / 2; // Run for 500ms;

            foreach (Thread thread in testThreads)
            {
                thread.Start();
            }

            foreach (Thread thread in testThreads)
            {
                thread.Join();
            }

            Assert.Greater(dirtyFlagReprotects, 10);
            Assert.Greater(writeTriggers, 10);
            Assert.Greater(handleLifecycles, 10);
        }
示例#6
0
        public void ReadAndWriteProtection()
        {
            MemoryPermission protection = MemoryPermission.ReadAndWrite;

            _memoryManager.OnProtect += (va, size, newProtection) =>
            {
                Assert.AreEqual((0, PageSize), (va, size)); // Should protect the exact region all the operations use.
                protection = newProtection;
            };

            RegionHandle handle = _tracking.BeginTracking(0, PageSize);

            // After creating the handle, there is no protection yet.
            Assert.AreEqual(MemoryPermission.ReadAndWrite, protection);

            bool dirtyInitial = handle.Dirty;

            Assert.True(dirtyInitial); // Handle starts dirty.

            handle.Reprotect();

            // After a reprotect, there is write protection, which will set a dirty flag when any write happens.
            Assert.AreEqual(MemoryPermission.Read, protection);

            (ulong address, ulong size)? readTrackingTriggered = null;
            handle.RegisterAction((address, size) =>
            {
                readTrackingTriggered = (address, size);
            });

            // Registering an action adds read/write protection.
            Assert.AreEqual(MemoryPermission.None, protection);

            bool dirtyAfterReprotect = handle.Dirty;

            Assert.False(dirtyAfterReprotect); // Handle is no longer dirty.

            // First we should read, which will trigger the action. This _should not_ remove write protection on the memory.

            _tracking.VirtualMemoryEvent(0, 4, false);

            bool dirtyAfterRead = handle.Dirty;

            Assert.False(dirtyAfterRead);                       // Not dirtied, as this was a read.

            Assert.AreEqual(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered.

            Assert.AreEqual(MemoryPermission.Read, protection); // Write protection is still present.

            readTrackingTriggered = null;

            // Now, perform a write.

            _tracking.VirtualMemoryEvent(0, 4, true);

            bool dirtyAfterWriteAfterRead = handle.Dirty;

            Assert.True(dirtyAfterWriteAfterRead);                      // Should be dirty.

            Assert.AreEqual(MemoryPermission.ReadAndWrite, protection); // All protection is now be removed from the memory.

            Assert.IsNull(readTrackingTriggered);                       // Read tracking was removed when the action fired, as it can only fire once.

            handle.Dispose();
        }
示例#7
0
        static LRESULT WindowProcedure(WindowHandle window, WindowMessage message, WPARAM wParam, LPARAM lParam)
        {
            switch (message)
            {
            case WindowMessage.Size:
                cxClient = lParam.LowWord;
                cyClient = lParam.HighWord;

                CursorHandle hCursor = Windows.SetCursor(CursorId.Wait);
                Windows.ShowCursor(true);

                hRgnClip?.Dispose();

                RegionHandle[] hRgnTemp = new RegionHandle[6];

                hRgnTemp[0] = Windows.CreateEllipticRegion(0, cyClient / 3, cxClient / 2, 2 * cyClient / 3);
                hRgnTemp[1] = Windows.CreateEllipticRegion(cxClient / 2, cyClient / 3, cxClient, 2 * cyClient / 3);
                hRgnTemp[2] = Windows.CreateEllipticRegion(cxClient / 3, 0, 2 * cxClient / 3, cyClient / 2);
                hRgnTemp[3] = Windows.CreateEllipticRegion(cxClient / 3, cyClient / 2, 2 * cxClient / 3, cyClient);
                hRgnTemp[4] = Windows.CreateRectangleRegion(0, 0, 1, 1);
                hRgnTemp[5] = Windows.CreateRectangleRegion(0, 0, 1, 1);
                hRgnClip    = Windows.CreateRectangleRegion(0, 0, 1, 1);
                hRgnTemp[4].CombineRegion(hRgnTemp[0], hRgnTemp[1], CombineRegionMode.Or);
                hRgnTemp[5].CombineRegion(hRgnTemp[2], hRgnTemp[3], CombineRegionMode.Or);
                hRgnClip.CombineRegion(hRgnTemp[4], hRgnTemp[5], CombineRegionMode.Xor);
                for (int i = 0; i < 6; i++)
                {
                    hRgnTemp[i]?.Dispose();
                }

                Windows.SetCursor(hCursor);
                Windows.ShowCursor(false);

                return(0);

            case WindowMessage.Paint:
                using (DeviceContext dc = window.BeginPaint())
                {
                    dc.SetViewportOrigin(cxClient / 2, cyClient / 2);
                    dc.SelectClippingRegion(hRgnClip);

                    double fRadius = Hypotenuse(cxClient / 2.0, cyClient / 2.0);

                    for (double fAngle = 0.0; fAngle < TWO_PI; fAngle += TWO_PI / 360)
                    {
                        dc.MoveTo(0, 0);
                        dc.LineTo(
                            (int)(fRadius * Math.Cos(fAngle) + 0.5),
                            (int)(-fRadius * Math.Sin(fAngle) + 0.5));
                    }
                }
                return(0);

            case WindowMessage.Destroy:
                hRgnClip?.Dispose();
                Windows.PostQuitMessage(0);
                return(0);
            }

            return(Windows.DefaultWindowProcedure(window, message, wParam, lParam));
        }