aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Memory/ReservedRegion.cs
blob: 521019adeb21830a25c6fbc89d1d5119f2a10989 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
using System.Collections.Generic;
using System.Text;

namespace ARMeilleure.Memory
{
    class ReservedRegion
    {
        private const int DefaultGranularity = 65536; // Mapping granularity in Windows.

        public IntPtr Pointer { get; }

        private ulong _maxSize;
        private ulong _sizeGranularity;
        private ulong _currentSize;

        public ReservedRegion(ulong maxSize, ulong granularity = 0)
        {
            if (granularity == 0)
            {
                granularity = DefaultGranularity;
            }

            Pointer = MemoryManagement.Reserve(maxSize);
            _maxSize = maxSize;
            _sizeGranularity = granularity;
            _currentSize = 0;
        }

        public void ExpandIfNeeded(ulong desiredSize)
        {
            if (desiredSize > _maxSize)
            {
                throw new OutOfMemoryException();
            }

            if (desiredSize > _currentSize)
            {
                // Lock, and then check again. We only want to commit once.
                lock (this)
                {
                    if (desiredSize >= _currentSize)
                    {
                        ulong overflowBytes = desiredSize - _currentSize;
                        ulong moreToCommit = (((_sizeGranularity - 1) + overflowBytes) / _sizeGranularity) * _sizeGranularity; // Round up.
                        MemoryManagement.Commit(new IntPtr((long)Pointer + (long)_currentSize), moreToCommit);
                        _currentSize += moreToCommit;
                    }
                }
            }
        }
    }
}