Well, I've been investigating the issue with our clos.lisp not being thread safe and me seeing NullPointerExceptions. It turns out that GENSYM was not thread safe in case there were no thread-local special bindings: the SYMBOL-VALUE wasn't protected against being manipulated from 2 threads at the same time.
I changed that. Now, even though clos.lisp is not thread safe, I'm not seeing any NullPointerExceptions anymore.
The NullPointerExceptions were caused by the fact that COMPILE was running in 2 threads at the same time, generating the same symbol at the same time. Then, it called REMEMBER from both threads, one overwriting the value stored by the other. That doesn't cause NullPointerExceptions by itself, but when each thread loads its COMPILEd function, the constructor calls Lisp.recall(), which removes the key from the hash used for temp-storage. The second function then finds 'null' instead of the value it stored.
So, that's another mystery solved. Fixed in trunk now.
However, what remains is the fact that the remember/recall combo uses global keys while COMPILE may be generating thread-local key values. I'm wondering what to do about that. Possibly I should just create a ThreadLocal which has a temp-storage hash table per thread and document remember/recall are a thread-local storage mechanism.
Of course, your opinions are welcome as always, especially with respect to the last paragraph.
Bye,
Erik.
The NullPointerExceptions were caused by the fact that COMPILE was running in 2 threads at the same time, generating the same symbol at the same time. Then, it called REMEMBER from both threads, one overwriting the value stored by the other. That doesn't cause NullPointerExceptions by itself, but when each thread loads its COMPILEd function, the constructor calls Lisp.recall(), which removes the key from the hash used for temp-storage. The second function then finds 'null' instead of the value it stored.
So, that's another mystery solved. Fixed in trunk now.
However, what remains is the fact that the remember/recall combo uses global keys while COMPILE may be generating thread-local key values. I'm wondering what to do about that. Possibly I should just create a ThreadLocal which has a temp-storage hash table per thread and document remember/recall are a thread-local storage mechanism.
I slept on this and think that I'll move the remember/recall functionality to the LispThread object, which is by itself thread-local. However, this allows cross-thread retrieval if necessary after all.
The proposed change is to have a Hashmap object in the LispThread object which is initialized upon instantiation. Access to this object will be synchronized, however, if I understand the synchronization can be eliminated by the JIT compiler after it determines there's no contention on the resource (the usual case).
How about that?
Bye,
Erik.
armedbear-devel@common-lisp.net