2001-08-11 10:36:38 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
|
|
|
/* Objective Caml */
|
|
|
|
/* */
|
|
|
|
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
|
|
|
|
/* */
|
|
|
|
/* Copyright 2001 Institut National de Recherche en Informatique et */
|
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
2001-08-11 10:36:38 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
/* Registration of global memory roots */
|
|
|
|
|
|
|
|
#include "memory.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "mlvalues.h"
|
|
|
|
#include "globroots.h"
|
|
|
|
|
|
|
|
/* The set of global memory roots is represented as a skip list
|
2001-08-13 01:47:23 -07:00
|
|
|
(see William Pugh, "Skip lists: a probabilistic alternative to
|
|
|
|
balanced binary trees", Comm. ACM 33(6), 1990). */
|
2001-08-11 10:36:38 -07:00
|
|
|
|
|
|
|
/* Generate a random level for a new node: 0 with probability 3/4,
|
|
|
|
1 with probability 3/16, 2 with probability 3/64, etc.
|
|
|
|
We use a simple linear congruential PRNG (see Knuth vol 2) instead
|
|
|
|
of random(), because we need exactly 32 bits of pseudo-random data
|
|
|
|
(i.e. 2 * (MAX_LEVEL + 1)). Moreover, the congruential PRNG
|
|
|
|
is faster and guaranteed to be deterministic (to reproduce bugs). */
|
|
|
|
|
|
|
|
static uint32 random_seed = 0;
|
|
|
|
|
|
|
|
static int random_level(void)
|
|
|
|
{
|
|
|
|
uint32 r;
|
|
|
|
int level = 0;
|
|
|
|
|
2001-08-13 01:47:23 -07:00
|
|
|
/* Linear congruence with modulus = 2^32, multiplier = 69069
|
|
|
|
(Knuth vol 2 p. 106, line 15 of table 1), additive = 25173. */
|
|
|
|
r = random_seed = random_seed * 69069 + 25173;
|
|
|
|
/* Knuth (vol 2 p. 13) shows that the least significant bits are
|
|
|
|
"less random" than the most significant bits with a modulus of 2^m,
|
|
|
|
so consume most significant bits first */
|
|
|
|
while ((r & 0xC0000000U) == 0xC0000000U) { level++; r = r << 2; }
|
2001-08-11 10:36:38 -07:00
|
|
|
Assert(level <= MAX_LEVEL);
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The initial global root list */
|
|
|
|
|
|
|
|
struct global_root_list caml_global_roots = { NULL, { NULL, }, 0 };
|
|
|
|
|
|
|
|
/* Register a global C root */
|
|
|
|
|
2004-01-05 12:26:19 -08:00
|
|
|
CAMLexport void caml_register_global_root(value *r)
|
2001-08-11 10:36:38 -07:00
|
|
|
{
|
|
|
|
struct global_root * update[MAX_LEVEL];
|
|
|
|
struct global_root * e, * f;
|
|
|
|
int i, new_level;
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
Assert (((intnat) r & 3) == 0); /* compact.c demands this (for now) */
|
2001-08-11 10:36:38 -07:00
|
|
|
|
|
|
|
/* Init "cursor" to list head */
|
|
|
|
e = (struct global_root *) &caml_global_roots;
|
|
|
|
/* Find place to insert new node */
|
|
|
|
for (i = caml_global_roots.level; i >= 0; i--) {
|
|
|
|
while (1) {
|
|
|
|
f = e->forward[i];
|
|
|
|
if (f == NULL || f->root >= r) break;
|
|
|
|
e = f;
|
|
|
|
}
|
|
|
|
update[i] = e;
|
|
|
|
}
|
|
|
|
e = e->forward[0];
|
|
|
|
/* If already present, don't do anything */
|
|
|
|
if (e != NULL && e->root == r) return;
|
|
|
|
/* Insert additional element, updating list level if necessary */
|
|
|
|
new_level = random_level();
|
|
|
|
if (new_level > caml_global_roots.level) {
|
|
|
|
for (i = caml_global_roots.level + 1; i <= new_level; i++)
|
|
|
|
update[i] = (struct global_root *) &caml_global_roots;
|
|
|
|
caml_global_roots.level = new_level;
|
|
|
|
}
|
2003-12-31 06:20:40 -08:00
|
|
|
e = caml_stat_alloc(sizeof(struct global_root) +
|
|
|
|
new_level * sizeof(struct global_root *));
|
2001-08-11 10:36:38 -07:00
|
|
|
e->root = r;
|
|
|
|
for (i = 0; i <= new_level; i++) {
|
|
|
|
e->forward[i] = update[i]->forward[i];
|
|
|
|
update[i]->forward[i] = e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Un-register a global C root */
|
|
|
|
|
2004-01-05 12:26:19 -08:00
|
|
|
CAMLexport void caml_remove_global_root(value *r)
|
2001-08-11 10:36:38 -07:00
|
|
|
{
|
|
|
|
struct global_root * update[MAX_LEVEL];
|
|
|
|
struct global_root * e, * f;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Init "cursor" to list head */
|
|
|
|
e = (struct global_root *) &caml_global_roots;
|
|
|
|
/* Find element in list */
|
|
|
|
for (i = caml_global_roots.level; i >= 0; i--) {
|
|
|
|
while (1) {
|
|
|
|
f = e->forward[i];
|
|
|
|
if (f == NULL || f->root >= r) break;
|
|
|
|
e = f;
|
|
|
|
}
|
|
|
|
update[i] = e;
|
|
|
|
}
|
|
|
|
e = e->forward[0];
|
|
|
|
/* If not found, nothing to do */
|
|
|
|
if (e == NULL || e->root != r) return;
|
|
|
|
/* Rebuild list without node */
|
|
|
|
for (i = 0; i <= caml_global_roots.level; i++) {
|
|
|
|
if (update[i]->forward[i] == e)
|
|
|
|
update[i]->forward[i] = e->forward[i];
|
|
|
|
}
|
|
|
|
/* Reclaim list element */
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(e);
|
2001-08-11 10:36:38 -07:00
|
|
|
/* Down-correct list level */
|
|
|
|
while (caml_global_roots.level > 0 &&
|
|
|
|
caml_global_roots.forward[caml_global_roots.level] == NULL)
|
|
|
|
caml_global_roots.level--;
|
|
|
|
}
|