(* $Id$ *)
(** Shared arrays *)
(** This type of array is to some degree comparable with [Array], but
there are a few extensions:
- There is a so-called header. The header can have any type, and
is typically used for managing concurrent access (e.g. mutexes).
The header also lives in shared memory.
- The arrays can be grown in size
*)
type ('e,'h) sarray
(** Arrays where the elements have type ['e] and the header has
type ['h]
*)
type ('e,'h) sarray_descr
(** The marshallable descriptor of a shared array *)
val create : Netmcore.res_id -> 'e array -> 'h -> ('e,'h) sarray
(** [create pool_id a h]:
Creates a shared array by deeply copying a normal array [a]
and using the copy of [h] as header
*)
val make : Netmcore.res_id -> int -> 'e -> 'h -> ('e,'h) sarray
(** [make pool_id n x h]:
Creates a shared array of the passed number of elements,
copies the element [x], and initializes each element of the new array
with the single copy of [x]. The value [h] is copied and used
as header.
*)
val init : Netmcore.res_id -> int -> (int -> 'e) -> 'h -> ('e,'h) sarray
(** [init pool_id n f h]:
Creates a shared array of the passed number of elements,
and for getting the element at position [k] the function
[f k] is run, and the copy of the result is written to the
position. The header is set to the copy of [h].
*)
val grow : ('e,_) sarray -> int -> 'e -> unit
(** [grow sa n x]: Grows the array to [n] elements. The new elements
are initialized to a (single) copy of [x].
If [n] is smaller than the current length, the function will do
nothing, and keep the length.
*)
val set : ('e,_) sarray -> int -> 'e -> unit
(** [set sa k x]: Sets the [k-th] element of the array [sa] to a
deep copy of [x].
*)
val get_ro : ('e,_) sarray -> int -> 'e
(** [get_ro sa k]: Gets the [k]-th element of the shared array [sa].
Note that there is no guarantee that this value still exists if
it is returned, and a parallely running [set] changes this element.
If such values are accessed the program may crash!
*)
val get_p : ('e,_) sarray -> int -> ('e -> 'a) -> 'a
(** [get_p sa k f]: Gets the [k]-th element of the shared array [sa]
and call [f] with this element, and returns the result of [f].
During the execution of [f] the requested element cannot be
garbage collected.
*)
val get_c : ('e,_) sarray -> int -> 'e
(** [get_c sa k]: Gets a copy of the [k]-th element of the shared array
[sæ]
*)
val length : (_,_) sarray -> int
(** Returns the length *)
val header : (_,'h) sarray -> 'h
(** Returns the header *)
val deref : ('e,_) sarray -> 'e array
(** Returns the raw array in shared memory for unprotected access *)
val heap : (_,_) sarray -> Obj.t Netmcore_heap.heap
(** Return the backing heap structure *)
val descr_of_sarray : ('e,'h) sarray -> ('e,'h) sarray_descr
(** Returns the descriptor *)
val sarray_of_descr : Netmcore.res_id -> ('e,'h) sarray_descr -> ('e,'h) sarray
(** Look up the buffer for this descriptor *)
(** {3 Mutating header fields}
Special care has to be taken when mutating header fields. The header
must completely live in the same heap. For adding new values, one
has to use {!Netmcore_heap.modify}. Example for a header of type:
{[
type header =
{ mutable n : int;
mutable name : string
}
]}
Here, the field [n] can be directly assigned because an [int]
is always an unboxed value. So,
{[
h.n <- new_value
]}
is legal. However, strings are heap-allocated. For an assignment
to [name] we need to use {!Netmcore_heap.modify}, as in
{[
Netmcore_heap.modify
(Netmcore_array.heap sa)
(fun mutator ->
h.name <- Netmcore_heap.add mutator new_value
)
]}
The function {!Netmcore_heap.add} pushes a copy of the [new_value]
to the heap, and this allows us to do the assignment.
During {!Netcore_heap.modify} certain operations are prohibited
because they would cause a deadlock:
- [grow]
- [set]
- [get_p]
- [get_c]
(This may be relaxed in a future version.)
*)