-
Notifications
You must be signed in to change notification settings - Fork 2
/
Util.cs
215 lines (178 loc) · 8.16 KB
/
Util.cs
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.
The Original Code is DataMangler Key-Value Store.
The Initial Developer of the Original Code is Mozilla Corporation.
Original Author: Kevin Gadd ([email protected])
*/
using System;
using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.IO;
using System.Linq.Expressions;
using Squared.Task;
namespace Squared.Data.Mangler.Internal {
delegate SafeBuffer GetSafeBufferFunc (UnmanagedMemoryAccessor accessor);
delegate Int64 GetPointerOffsetFunc (MemoryMappedViewAccessor accessor);
public static class InternalExtensions {
private static readonly GetSafeBufferFunc _GetSafeBuffer;
private static readonly GetPointerOffsetFunc _GetPointerOffset;
static InternalExtensions () {
_GetSafeBuffer = CreateGetSafeBuffer();
_GetPointerOffset = CreateGetPointerOffset();
}
// To manipulate structures directly in mapped memory, we have
// to be able to get a pointer to the mapping. While this is possible,
// the classes for using mapped files do not expose a way to do this
// directly. So, we pull out the SafeBuffer object associated with the
// mapping and then use a public method to get a pointer.
// Kind of nasty, but what else can you do?
private static GetSafeBufferFunc CreateGetSafeBuffer () {
var t = typeof(UnmanagedMemoryAccessor);
var field = t.GetField(
"_buffer",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance
);
if (field == null)
throw new ArgumentNullException();
var argument = Expression.Parameter(t, "accessor");
var expr = Expression.Field(argument, field);
return Expression.Lambda<GetSafeBufferFunc>(
expr, "GetSafeBuffer", new[] { argument }
).Compile();
}
// When we get a pointer from a SafeBuffer associated with a mapped
// view, the pointer is going to be wrong unless the offset into
// the file that we mapped was aligned with a page boundary.
// So, once we get the pointer, we have to find out the alignment
// necessary to line it up with a page, and add that to the pointer
// so that we are looking at the start of the mapping, instead of
// the start of the page containing the mapping.
// This is a bit messier than the SafeBuffer hack, because one of the
// relevant types - MemoryMappedView - is internal.
private static GetPointerOffsetFunc CreateGetPointerOffset () {
var tAccessor = typeof(MemoryMappedViewAccessor);
var tView = tAccessor.Assembly.GetType(
"System.IO.MemoryMappedFiles.MemoryMappedView", true
);
var fieldView = tAccessor.GetField(
"m_view",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance
);
if (fieldView == null)
throw new ArgumentNullException();
var fieldOffset = tView.GetField(
"m_pointerOffset",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance
);
if (fieldOffset == null)
throw new ArgumentNullException();
var argument = Expression.Parameter(tAccessor, "accessor");
var expr = Expression.Field(
Expression.Field(argument, fieldView), fieldOffset
);
return Expression.Lambda<GetPointerOffsetFunc>(
expr, "GetPointerOffset", new[] { argument }
).Compile();
}
internal static SafeBuffer GetSafeBuffer (this UnmanagedMemoryAccessor accessor) {
var buffer = _GetSafeBuffer(accessor);
if (buffer == null)
throw new InvalidDataException();
return buffer;
}
internal static Int64 GetPointerOffset (this MemoryMappedViewAccessor accessor) {
return _GetPointerOffset(accessor);
}
public static ArraySegment<byte> GetSegment (this MemoryStream stream) {
if (stream.Length >= int.MaxValue)
throw new InvalidDataException();
return new ArraySegment<byte>(stream.GetBuffer(), 0, (int)stream.Length);
}
public static IEnumerable<T> AsEnumerable<T> (this ArraySegment<T> segment) {
var a = segment.Array;
for (int i = 0, c = segment.Count, o = segment.Offset; i < c; i++)
yield return a[i + o];
}
}
public unsafe delegate void GenericPtrToStructureFunc<T> (byte* source, out T destination, uint size)
where T : struct;
public unsafe delegate void GenericStructureToPtrFunc<T> (ref T source, byte* destination, uint size)
where T : struct;
public unsafe static class Unsafe {
public static void ReadBytes (byte* ptr, long offset, byte[] buffer, long bufferOffset, uint count) {
fixed (byte* pDest = &buffer[bufferOffset])
Native.memmove(pDest, ptr + offset, new UIntPtr((uint)count));
}
public static void WriteBytes (byte* ptr, long offset, ArraySegment<byte> bytes) {
WriteBytes(ptr, offset, bytes.Array, bytes.Offset, bytes.Count);
}
public static void WriteBytes (byte* ptr, long offset, byte[] source, int sourceOffset, int count) {
fixed (byte* pSource = &source[sourceOffset])
Native.memmove(ptr + offset, pSource, new UIntPtr((uint)count));
}
public static void ZeroBytes (byte* ptr, long offset, uint count) {
Native.memset(ptr + offset, 0, new UIntPtr((uint)count));
}
}
public unsafe static class Unsafe<T>
where T : struct {
public static readonly GenericPtrToStructureFunc<T> PtrToStructure;
public static readonly GenericStructureToPtrFunc<T> StructureToPtr;
static Unsafe () {
var tSafeBuffer = typeof(SafeBuffer);
var method = tSafeBuffer.GetMethod(
"GenericPtrToStructure",
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic
).MakeGenericMethod(typeof(T));
PtrToStructure = (GenericPtrToStructureFunc<T>)Delegate.CreateDelegate(
typeof(GenericPtrToStructureFunc<T>), method, true
);
method = tSafeBuffer.GetMethod(
"GenericStructureToPtr",
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic
).MakeGenericMethod(typeof(T));
StructureToPtr = (GenericStructureToPtrFunc<T>)Delegate.CreateDelegate(
typeof(GenericStructureToPtrFunc<T>), method, true
);
}
}
public static class IntegerUtil {
public static int Log2 (uint value) {
int result = 0;
while ((value >>= 1) != 0)
result += 1;
return result;
}
public static bool IsPowerOfTwo (uint value) {
unchecked {
return (value != 0) &&
((value & (value - 1)) != 0);
}
}
public static uint NextPowerOfTwo (uint value) {
unchecked {
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value++;
}
return value;
}
}
}