Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify (or fix) the semantics of Oo.id #5436

Closed
vicuna opened this issue Dec 20, 2011 · 8 comments

Comments

Projects
None yet
2 participants
@vicuna
Copy link

commented Dec 20, 2011

Original bug ID: 5436
Reporter: @alainfrisch
Assigned to: @garrigue
Status: closed (set by @xavierleroy on 2013-08-31T10:48:51Z)
Resolution: fixed
Priority: normal
Severity: minor
Fixed in version: 3.13.0+dev
Category: ~DO NOT USE (was: OCaml general)
Monitored by: @protz @dbuenzli

Bug description

It should be clarified how Oo.id behaves in the following cases:

  • Multi-threaded program: is it guaranteed that two different threads cannot create objects with the same id (I think so).

  • Serialized objects: currently, unmarshaling does not assign fresh ids to objects. It is thus possible to have two different objects in the same run of the program. Shouldn't unmarshaling reassign ids instead? One could then make clear in the documentation that Oo.id (and thus, generic hash/comparison) is not stable across "marshaling" boundaries, but at least one would keep the uniqueness property.

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 20, 2011

Comment author: @garrigue

For the second point, this is oops! : indeed ids should be fresh upon unmarshaling.
It seems that I forgot to implement it (there is a subtle interaction between C code
and ocaml code).

For the first point, we have to check the code.
Maybe it would be better to move the id handling to the C side, since it would avoid the risk of races too.

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 22, 2011

Comment author: @garrigue

For point 1, ids are guaranteed to be different in different threads:
CamlinternalOO.set_id only reads and assigns to records fields, so no thread switch can occur during its execution.
(At least I believe so. Reading the code in interp.c and systhreads doesn't help me much about
when thread switches can occur.)

For point 2, indeed the behavior was incorrect, and ids were not updated when unmarshaling.
This is now fixed in revision 11930.
One must be careful however that ids cached inside data structures lose their meaning as a result.

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 22, 2011

Comment author: @alainfrisch

I've added some words of warning the documentation for Oo.id.

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 28, 2011

Comment author: @xavierleroy

I agree with Jacques that we should probably move the generation of fresh IDs to C code, to simplify unmarshaling and to provide clear atomicity guarantees.

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 28, 2011

Comment author: @dbuenzli

Would it be possible to also expose the unique id generation as a function in pervasives or Sys ?

That's a useful function beyond ids for objects. I use the id of empty objects as thread safe runtime unique ids in more than one program to implement the keys of type safe heterogenous dictionaries (on Alan's F. suggestion btw. [1]).

let ruid () = Oo.id (object end)

This would avoid linking against Oo in these programs.

Best,

Daniel

[1] http://alan.petitepomme.net/cwn/2010.02.09.html#1

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 29, 2011

Comment author: @garrigue

To xleroy:
My fix in revision 11930 keeps the id generation in CamlinternalOO, just exporting the current id through Callback.register_value.
The code is:

let set_id o id =
let id0 = !id in
Array.unsafe_set (Obj.magic o : int array) 1 id0;
id := id0 + 1

Is there any risk of race?
I thought that thread switch could only occur at function calls.

Before doing that, I tried a version with id generation on the C side, but I was afraid that this would make object creation slower. If you think this wouldn't have any impact, I'll revert to that solution.
You can find the patch in experimental/garrigue/caml_set_oid.diffs.

By the way, if the code generating ids in CamlinternalOO is already safe, there is clearly no need to include CamlinternalOO to do that: you just have to duplicate the above 4 lines.

@vicuna

This comment has been minimized.

Copy link
Author

commented Dec 29, 2011

Comment author: @dbuenzli

By the way, if the code generating ids in CamlinternalOO is already safe, there is clearly no need to
include CamlinternalOO to do that: you just have to duplicate the above 4 lines.

Oh right. You mean that what I thought was not thread-safe :

let create =
let c = ref min_int in
fun () ->
let id = !c in
incr c; if id > !c then assert false (* too many ids *) else id

is in fact thread-safe because no allocation occurs between let id = !c, incr c and the conditional ?

@vicuna

This comment has been minimized.

Copy link
Author

commented Mar 24, 2012

Comment author: @dbuenzli

Still this would rely on an implementation detail, I'd prefer if something was given to me by the runtime system.

@vicuna vicuna closed this Aug 31, 2013

@vicuna vicuna added the bug label Mar 20, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.