-
-
Notifications
You must be signed in to change notification settings - Fork 422
Add a GC.callLocked() function to execute a delegate with the GC lock held. #213
Conversation
|
BTW: I know there's a GSoC project working towards getting rid of the GC lock. Even then, I think having this in place adds value because whether the GC actually has a lock is an implementation detail. A GC without a lock can simply call the delegate straight away. |
|
Ping? |
|
Can we at least merge this for 2.060? It's a ridiculously simple change... |
|
It's not ridiculously simple.
there is not even a rationale for this change. |
Even
It's a GC. It's low-level. Not everything can (or should) be encapsulated. But I'd actually argue that this does not break encapsulation; in fact, it does the exact opposite: It makes you able to do an operation safely regardless of whether the GC uses a lock or not, i.e. you don't rely on the implementation detail that the GC has a lock. All you do is say "OK, if the GC does have a lock, I've got myself covered".
It is essential to implementing weak references without using dirty and oftentimes error-prone |
|
Can you elaborate a little more about how your weak ref mechanism works. Would it be possible to use gc_enable/gc_disable? |
First, you allocate a block of memory wide enough to hold a pointer. You then mark this block as Now, when you want to fetch the pointer again, you have to tell the GC "I don't want you to collect while I do this tiny operation". So what you do is, you acquire the GC lock, then fetch the reference from memory, restore it to the correct reference (again, just one's complement and you have the original reference), and finally release the GC lock. You need to lock this sequence because you don''t want the object to be collected in the middle of this sequence (e.g. just before you do the restore operation). By the time you've restored the pointer, the object is live again, and releasing the lock is safe.
Consider what would happen if you disable the GC, and start to fetch the weak reference, and in the meantime, some other thread starts filling up the heap: What you end up with is quite likely an irrecoverable out of memory condition because, being disabled, the GC can't do anything. By using a lock, it is ensured that other threads that attempt to allocate while weak references are being fetched can't cause out of memory conditions. |
|
Oh, also, fun fact: For weak references in particular, critical regions (#204) would be sufficient. ;) They tell the GC not to interrupt what the pointer fetch + pointer restore operation is doing, while ensuring out of memory conditions can't be caused as a side-effect, and even better, they don't involve locks! But that said, critical regions are error-prone, much less flexible, and so on (as mentioned in #204's description). Also, it seems like that one's not being merged for 2.060, so this is a reasonable (and more general) solution to the weak reference problem in particular. |
|
After descrambling the pointer you'd need to query the GC
gc_enable/gc_disable could be made lock free too. |
Nope, that won't work. The reason is tricky: By the time you've restored the pointer, it may not necessarily point to the same memory it originally did, even if It's a tricky sequence to get right...
Aren't they already? Anyway, they still have the problem I mentioned about OOM conditions. |
|
I thought quite a lot about this and concluded that it would be a bad idea to add this functionality.
For GC.callLocked to be useful we'd need to specify what operations are locked out. I've sketched out an alternative WeakRef (https://gist.github.com/2852438) implementation. It uses addrOf to synchronize with the GC. That's not perfect either but at least it doesn't acquire new technical debt. Besides I'm not sure what the state of rt_attachDisposeEvent is, see the recent discussion on the object monitor. |
No description provided.