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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
|
// vm_tree.c
//
// AUTHOR NOTE:
//
// a great deal of this code is lifted and adapted straight from wikipedia at
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
//
// i reserve no rights under copyright law to this material, but i agree to be
// bound by the terms of the Creative Commons Share-Alike by Attribution license
//
// if any of the following is found to be in violation please contact the author
// at ada.christine.18+sophia _at_ gmail _dot_ com
//
// -Ada Christine Fontaine, 1/1/2022
//
// LICENSE NOTIFICATION
//
// THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
// COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
// COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
// AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
// BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO
// BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE
// CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
// HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
//
// The full text of the CC-BY-SA 3.0 license can be found here:
// https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License
#include "vm_tree.h"
#include "panic.h"
#include "kprint.h"
#include <sophialib.h>
#define assert(expr)
#define NIL NULL
#define left child[LEFT]
#define right child[RIGHT]
// the direction of the child node
#define childDir(vmn) (vmn == (vmn->parent)->right ? RIGHT : LEFT)
static int compare(uintptr_t a1, size_t s1, uintptr_t a2, size_t s2)
{
// case 1: a1:a1+s1 occupies a region entirely below a2
// and is therefore less than.
if ((a1 + s1) <= a2)
{
return -1;
}
// case 2: a1:a1+s1 occupies a region entirely above (a2+s2)
// and is therefore greater than.
else if (a1 >= (a2 + s2))
{
return 1;
}
// case 3: the above conditions are not satisfied and therefore
// the regions overlap and are considered equivalent.
return 0;
}
static int compare_key(struct vm_tree_key const * const k1,
struct vm_tree_key const * const k2)
{
return compare(k1->address, k1->size, k2->address, k2->size);
}
void vmt_init_node(
struct vm_tree *tree,
struct vm_tree_node *node,
struct vm_object *object,
void *base,
void *head)
{
memset(node, 0, sizeof(*node));
node->key =
(struct vm_tree_key)
{
(uintptr_t)base,
(uintptr_t)head - (uintptr_t)base
};
struct vm_tree_node *ek = NULL;
if (!(ek = vmt_search_key(tree, &node->key)))
{
struct vm_tree_node *p = vmn_predecessor_key(
tree->root,
&node->key);
if (!p)
{
// the tree root should be in place of a missing predecessor
p = tree->root;
}
vmt_insert(
tree,
node,
p,
vmn_child_direction(node, p));
node->object = object;
}
else
{
kprintf("fatal: attempt to insert overlapping vm node\n"
"node 1: %p: %p @ %zu bytes\n"
"node 2: %p: %p @ %zu bytes\n",
node->key.address, node->key.size,
ek->key.address, ek->key.size);
PANIC(GENERAL_PANIC);
}
}
static struct vm_tree_node* RotateDirRoot(
struct vm_tree* T, // red–black tree
struct vm_tree_node* P, // root of subtree (may be the root of T)
enum vm_tree_direction dir) { // dir ∈ { LEFT, RIGHT }
struct vm_tree_node* G = P->parent;
struct vm_tree_node* S = P->child[1-dir];
struct vm_tree_node* C;
assert(S != NIL); // pointer to true node required
C = S->child[dir];
P->child[1-dir] = C; if (C != NIL) C->parent = P;
S->child[ dir] = P; P->parent = S;
S->parent = G;
if (G != NULL)
G->child[ P == G->right ? RIGHT : LEFT ] = S;
else
T->root = S;
return S; // new root of subtree
}
#define RotateDir(N,dir) RotateDirRoot(T,N,dir)
#define RotateLeft(N) RotateDirRoot(T,N,LEFT)
#define RotateRight(N) RotateDirRoot(T,N,RIGHT)
void vmt_insert(
struct vm_tree* T, // -> red–black tree
struct vm_tree_node* N, // -> node to be inserted
struct vm_tree_node* P, // -> parent node of N ( may be NULL )
enum vm_tree_direction dir) // side ( LEFT or RIGHT ) of P where to insert N
{
struct vm_tree_node* G; // -> parent node of P
struct vm_tree_node* U; // -> uncle of N
N->color = RED;
N->left = NIL;
N->right = NIL;
N->parent = P;
if (P == NULL) { // There is no parent
T->root = N; // N is the new root of the tree T.
return; // insertion complete
}
P->child[dir] = N; // insert N as dir-child of P
// start of the (do while)-loop:
do {
if (P->color == BLACK) {
// Case_I1 (P black):
return; // insertion complete
}
// From now on P is red.
if ((G = P->parent) == NULL)
goto Case_I4; // P red and root
// else: P red and G!=NULL.
dir = childDir(P); // the side of parent G on which node P is located
U = G->child[1-dir]; // uncle
if (U == NIL || U->color == BLACK) // considered black
goto Case_I56; // P red && U black
// Case_I2 (P+U red):
P->color = BLACK;
U->color = BLACK;
G->color = RED;
N = G; // new current node
// iterate 1 black level higher
// (= 2 tree levels)
} while ((P = N->parent) != NULL);
// end of the (do while)-loop
// Leaving the (do while)-loop (after having fallen through from Case_I2).
// Case_I3: N is the root and red.
return; // insertion complete
Case_I4: // P is the root and red:
P->color = BLACK;
return; // insertion complete
Case_I56: // P red && U black:
if (N == P->child[1-dir])
{ // Case_I5 (P red && U black && N inner grandchild of G):
RotateDir(P,dir); // P is never the root
N = P; // new current node
P = G->child[dir]; // new parent of N
// fall through to Case_I6
}
// Case_I6 (P red && U black && N outer grandchild of G):
RotateDirRoot(T,G,1-dir); // G may be the root
P->color = BLACK;
G->color = RED;
return; // insertion complete
} // end of RBinsert1
void vmt_delete(
struct vm_tree* T, // -> red–black tree
struct vm_tree_node* N) // -> node to be deleted
{
struct vm_tree_node* P = N->parent; // -> parent node of N
enum vm_tree_direction dir; // side of P on which N is located (∈ { LEFT, RIGHT })
struct vm_tree_node* S; // -> sibling of N
struct vm_tree_node* C; // -> close nephew
struct vm_tree_node* D; // -> distant nephew
// P != NULL, since N is not the root.
dir = childDir(N); // side of parent P on which the node N is located
// Replace N at its parent P by NIL:
P->child[dir] = NIL;
goto Start_D; // jump into the loop
// start of the (do while)-loop:
do {
dir = childDir(N); // side of parent P on which node N is located
Start_D:
S = P->child[1-dir]; // sibling of N (has black height >= 1)
D = S->child[1-dir]; // distant nephew
C = S->child[ dir]; // close nephew
if (S->color == RED)
goto Case_D3; // S red ===> P+C+D black
// S is black:
if (D != NIL && D->color == RED) // not considered black
goto Case_D6; // D red && S black
if (C != NIL && C->color == RED) // not considered black
goto Case_D5; // C red && S+D black
// Here both nephews are == NIL (first iteration) or black (later).
if (P->color == RED)
goto Case_D4; // P red && C+S+D black
// Case_D1 (P+C+S+D black):
S->color = RED;
N = P; // new current node (maybe the root)
// iterate 1 black level
// (= 1 tree level) higher
} while ((P = N->parent) != NULL);
// end of the (do while)-loop
// Case_D2 (P == NULL):
return; // deletion complete
Case_D3: // S red && P+C+D black:
RotateDirRoot(T,P,dir); // P may be the root
P->color = RED;
S->color = BLACK;
S = C; // != NIL
// now: P red && S black
D = S->child[1-dir]; // distant nephew
if (D != NIL && D->color == RED)
goto Case_D6; // D red && S black
C = S->child[ dir]; // close nephew
if (C != NIL && C->color == RED)
goto Case_D5; // C red && S+D black
// Otherwise C+D considered black.
// fall through to Case_D4
// Case_D4: // P red && S+C+D black:
S->color = RED;
P->color = BLACK;
return; // deletion complete
Case_D4: // P red && S+C+D black:
S->color = RED;
P->color = BLACK;
return; // deletion complete
Case_D5: // C red && S+D black:
RotateDir(S,1-dir); // S is never the root
S->color = RED;
C->color = BLACK;
D = S;
S = C;
// now: D red && S black
// fall through to Case_D6
Case_D6: // D red && S black:
RotateDirRoot(T,P,dir); // P may be the root
S->color = P->color;
P->color = BLACK;
D->color = BLACK;
return; // deletion complete
} // end of RBdelete2
enum vm_tree_direction vmn_child_direction(
struct vm_tree_node *n,
struct vm_tree_node *p
)
{
if (p && (compare_key(&p->key, &n->key) > 0))
{
return LEFT;
}
return RIGHT;
}
struct vm_tree_node *vmt_search_key(
struct vm_tree *tree,
struct vm_tree_key *key)
{
struct vm_tree_node *N = tree->root;
while (N && (compare_key(&N->key, key) != 0))
{
if (compare_key(&N->key, key) > 0)
{
N = N->left;
}
else
{
N = N->right;
}
}
return N;
}
// search for the predecessor node for a given key
struct vm_tree_node *vmn_predecessor_key(
struct vm_tree_node *N,
struct vm_tree_key *key)
{
struct vm_tree_node *P = NULL;
while (N && (compare_key(&N->key, key) != 0))
{
if (compare_key(&N->key, key) > 0)
{
N = N->left;
}
else
{
P = N;
N = N->right;
}
}
return P;
}
// search for the successor node for a given key
struct vm_tree_node *vmn_successor_node(
struct vm_tree_node *N)
{
if (N && N->right)
{
return vmn_min(N->right);
}
struct vm_tree_node *p = N->parent;
while (p && N == p->right)
{
N = p;
p = p->parent;
}
return p;
}
struct vm_tree_node *vmn_min(struct vm_tree_node *node)
{
while (node && node->left)
{
node = node->left;
}
return node;
}
struct vm_tree_node *vmn_max(struct vm_tree_node *node)
{
while (node && node->right)
{
node = node->right;
}
return node;
}
struct vm_object *vmt_get_object(struct vm_tree *tree, void *address)
{
// find the object for a page.
struct vm_tree_key key = {(uintptr_t)address, 1};
struct vm_tree_node *node = vmt_search_key(tree, &key);
if (node)
{
return node->object;
}
return NULL;
}
|