-
-
Notifications
You must be signed in to change notification settings - Fork 177
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
DOC: Clarify some details about foreign blobs #1224
Conversation
I've reverted my changes to pl-atom.c (there's a newer version in |
Thanks. Did quite a bit of rewriting. Please check and ask if you do not understand. As usual, you got some details wrong, but this points me at the possible misconceptions and allows me to clarify 😄 |
"Note that this returns \const{NULL} when called by the atom garbage collector and PL_free_blob() was used on the blob." In my documentation change for BTW, I think that "callback" is standard English usage, not "call back". (Except when "call" is a verb)
|
Oops ... I mis-read the example code for |
I don't know. Possibly you still want the release callback to be notified if the atom is gone? I don't see much reason for this check in the core. They are surely two different actions: releasing the payload and releasing the atom. They are also easily enough to distinguish, so we do not need two callback handlers. If you want to hide that in the C++ wrapper, fine.
I tried to rephrase the text. No term is deleted, only the references. This is true regardless of whether or not there are other references to the term. Indeed, the discard variation deletes the terms, but this is completely regardless of the references. Lifetime of terms is basically unrelated to the lifetime of term references except that term references to a term ensure it is not subject to GC.
I'll try to remember .... If the text is still unclear, please try to improve it. I think the current text is correct (but apparently hard to understand 😢 ) Scoping and lifetime of Prolog data is hard to understand for users of imperative languages ... |
Can a release() callback do anything when PL_free_blob() returns NULL? All the information it needs is in the blob -- the atom_t value isn't useful for anything AFIACT. Anyway, I'll add a test for NULL to the C++ callback. |
Not entirely clear. Possibly it wants to remove the handle from some table? Note that PL_free_blob() does not reclaim the handle, only the content. |
By "remove the handle from some table", I suppose you're thinking of the table of name→atom_t in rocksdb? (actually, it's PlAtom→PlAtom, but same idea) In that situation, release() will have already been called from PL_free_blob(), which is where the handle should be removed; the call to release() has no way of telling whether it's being called from PL_free_blob() or from the GC; and no expectation that it'll be called a second time. In addition, if the table has some kind of reference count (e.g., the blob in rocksdb has a count of the iterators that are using it), the call to PL_free_blob() would decrement the count; a subsequent call from GC would cause the reference count to go negative. |
Ok. Pushed ee3d08e to never call the release function if the data is already reclaimed. Note that PL_get_blob(), etc. still must be aware that the data may be NULL. |
Why not also test for NULL before calling release() from PL_free_blob()? That would guarantee PL_get_blob() never returns NULL in the release() callback. Do we also need to add a test for NULL to compare atoms(), write_stream_ref()? - currently they'll crash if PL_free_blob() has been called. |
Agree. Pushed 0bd41c3. Never considered one could call this twice 😄 |
Previously, I changed static int release(atom_t a) noexcept
{ auto data = cast(PlAtom(a));
if ( !data ) // PL_free_blob() has been used.
return true;
... I noticed that you removed the sentence from For other callbacks ( From looking at the code, it think that Does this seem correct? |
I'm not aware of that. Surely the docs for PL_blob_data() have not changed according to
That is not correct. As the "atom" still exists from Prolog's point of view any of these operations may still happen. Of course, there is no data left to inspect, so you can only do something generic. For example:
In this case we want user intervention because Python objects are written as <py_>(Ptr). |
ee3d08e line 2717 removes the warning that I'm wondering what the right behaviour is when
(Why do I care about this? I've noticed that occasionally some build unit tests fail (and not just for the HTTP tests), but haven't followed up ... there might be some non-deterministic bugs in the code. Anything that suppresses error checks such as === (Repeating Jan's comment because the formatting was messed up) === That is not correct. As the "atom" still exists from Prolog's point of view any of these operations may still happen. Of course, there is no data left to inspect, so you can only do something generic. For example: 1 ?- py_call(sys:path, Path, [py_object(true)]).
Path = <py_list>(0x7fad8b96d480). For 2 ?- py_free($Path).
Path = <py_FREED>(0x0). In this case we want user intervention because Python objects are written as <py_>(Ptr). === (End Jan's comment) === |
True. Just, this text is already so complicated. Just be more explicit in PL_blob_data(), etc. may be better. As is,
At the moment I'm only aware of http_proxy and mqi. The first is most likely a port allocation issue and the latter is some sort of timing issue. Then there are a couple of tests that are inherently unsafe because they rely on timing that may go wrong on a heavily loaded system. I think most merely print a warning rather than actually failing, but I may have missed a few. I'm pretty sure that the issues are mostly with concurrency, some with the design of the tests, others with the core. |
I've created an issue for "some build unit tests fail": SWI-Prolog/packages-cpp#73 |
I've also put some comments into pl-atom.c, to help me understand the code. You might wish to remove them. :)
There's one logic change: I added a check for the "name" field being non-null before calling the release() callback. This might be unnecessary, but it accords with a documentation change I made.
I tried changing the code in lookupBlob() for how the hash is computed, but that caused a crash when generating home/boot.prc ... that item is marked as a "TODO", which you might also want to remove.