Что нужно сделать, чтобы выделить бессмертный объект OCaml вне кучи в функции C?В частности, как сделать значение OCaml, которое выглядит во время выполнения как глобальная переменная в исходном коде OCaml.
Вот моя попытка создать намеренно неработающую программу, которая не регистрирует значение как GCroot.
Вот исходный файл OCaml, управляющий всем.
(* immortal_string.ml *)
external make_string : string -> unit = "make_string"
external get_string : unit -> string = "get_string"
let () = make_string "a"
let () = Gc.full_major ()
let () = Printf.printf "%s\n" (get_string ())
И реализация C.Вероятно, есть лучшие способы сделать это, чем использовать 0
в качестве значения часового и статической функции, но я думаю, что цель ясна.Обратите внимание, что множественные вызовы make_string
приведут к значению, которое изначально было там, но это нормально.Я хочу, чтобы память, на которую ссылались старые значения, была возвращена сборщиком мусора.
// lib_immortal_string.c
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
value *storage(void) {
// BAD! we haven't registered this thing
// as a GC root. No clue how you do that.
static value data = 0; // sentinel, will never be valid OCaml value
if (data == 0) {
data = caml_copy_string("");
}
return &data;
}
CAMLprim value
make_string(value ml_string) {
CAMLparam1(ml_string);
*storage() = ml_string;
CAMLreturn(Val_unit);
}
CAMLprim value
get_string(value ml_unit) {
CAMLparam1(ml_unit);
CAMLreturn(*storage());
}
Я ожидал, что эта программа перестанет работать, так как нет ничего очевидного в том, что data
в функции storage
в действии.data
не является глобальным и не находится в стеке.Тем не менее, программа , по-видимому, запускается без восстановления строки.
$ ocamlopt immortal_string.ml lib_immortal_string.c
./a.out
a
Итак, мой вопрос: как правильно сделать глобальное значение OCaml / вне кучи?И, кроме того, почему вышеуказанная программа работает, а не падает?