Jason House, el 23 de abril a las 16:48 me escribiste: > > What I'm not sure is if it's really necessary to do that step. What can go > > wrong with this simple approach? > > > > T opCall() { > > if (!pool.mark.test(index)) > > t = null; > > return t; > > } > > What happens when a collection runs after test returns? You need to copy > t onto the stack in order to be safe.
You're right, I definitely underestimated the problem. Now I see that this sequence breaks that implementation: 1) WeakRef.opCall() is called (whick stores a reference to R) 2) The mark bit for R is tested and returns true 3) CPU time is given to other threads with reference to R, which are removed 4) Other thread triggers a collection and the world is stopped 5) R gets unmarked because there are no other references to it 6) The world is started 7) WeakRef.opCall() returns R when it should returned null The problem I see with your original proposal: T opCall(){ T tmp = t; // force future conservative GC scan to find the pointer if ( (tmp is null) || (pool.mark[index] == false) ){ t = null; return null; } tmp = t; // avoid race where t was replaced with new data return tmp; } Is that I guess is very likely that 'tmp' get optimized out. Would declaring it as volatile help? If not, I guess the only way to avoid that race is add a root manually to the GC (or mark the weakref again as no NO_SCAN). But both requires synchronization. =( > > Weakref only reads the reference *if* the mark bit is set, in which case > > is safe to assume that the object is live. > > How do you check the mark bit? In the sample code, it used the > reference... Admittedly, one could store the right info to avoid that, > but it hardly matters. Right. > > If the object is garbage, the mark bit is unset and in that case the > > reference is only *written* (the only race it could happen is the sweep() > > can be called but in that case the reference is written to null too, so > > there should be no problem with that, I guess... > > > > As long as the test are successful (t is not overwritten to null), the GC > > should be able to find the reference in the stack when the function > > returns. > > > > I'm probably missing something else... > > You're not considering what can happen if the weak ref dereferencing > thread stops and the rest of the world wreaks havoc on the state of the > world. A collection could run after checking the mark. If one is careful > with that, and a copy of t is kept on the stack, will the optimizer > reuse it? Or will it reread the value? That matters if the finalizer > runs. The mark bit check can fail from reallocation after deletion. > > I hope that helps... Yes, thank you. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- - Que hacés, ratita? - Espero un ratito...