Here a mail from David that comments on a mail from Richard in reply to this
bug report. Most likely this will get completely unreadable, but I don't want
that information to get lost.
> On 11 Jan 2012, at 09:16, Fred Kiefer wrote:
>> To Richard's comment that we could adopt the GCC runtime solution:
> I don't think I actually advocated that.
>> I wrote the
>> patch that did that in the GCC runtime originally, and it's what the
>> runtime used to do.
> Not sure what he's talking about here ... the current GCC behavior was
written by me and then improved by Nicola ... so perhaps he's talking about
the earlier version of the +initialize code which wasn't thread-safe?
No, I wrote the code in the version of GCC libobjc in GNUstep svn that
implemented this. I assumed that had been ported upstream to GCC, I hadn't
realised that you reinvented the wheel.
>> I fixed this behaviour because people rely on the Apple
>> behaviour - there are lots of fun deadlock scenarios you can get into from
>> only being able to enter one +initialize method at once in each thread.
> Not clear on this either ... the Apple behavior? In the GCC runtime there's
a global lock so, once one thread enters a +initialize *no* other thread can
do so until the first thread exits again, but the first thread can enter
+initialize in any/all classes. That means that, as long as your +initialize
implementation doesn't wait for any other thread (directly or indirectly), the
GCC runtime avoids deadlocks. That's why I (slightly) prefer the GCC runtime
behavior ... it 's relatively easy to avoid deadlock.
I initially implemented the single-lock version in GNUstep libobjc. The
reason that I implemented the Apple-compatible behaviour was that I got
reports of deadlocks with the single-lock version. This is because there are
existing applications that do things like spawn a new thread in +initialize
and send messages from that thread and exit the +initialize once the thread
returned. These then hit the global lock and deadlock.
They only deadlocked on GNUstep, so from the user perspective this is a bug:
my code works on Cocoa, doesn't work on GNUstep = GNUstep sucks.
People notified me of a bug, which was also an Apple incompatibility, and I
fixed it. Now other people are complaining that their code - which uses a
GCC-specific, undocumented, behaviour - does not work.
>> Reverting to the old behaviour would just mean getting a different set of
>> potential deadlocks, and they would be deadlocks that a) only showed up on
>> GNUstep and not Cocoa, and b) made it hard to write code that was
>> deadlock-free on both Cocoa and GNUstep.
> Valid point ... but these deadlocks are rare (so far we have one bug report
for the apple behavior, and have not had any for the gcc behavior). So I
don't think it makes sense to change the GCC runtime to copy an undocumented
behavior of the Apple runtime which is rarely relevant and doesn't actually
improve things. What we do need to be aware of is that existing
initialization code which is fine with the GCC runtime might deadlock with the
> It sounds like David is saying he won't fix libobjc2 and wants libobc to
reproduce the apple bug instead.
No, I'm saying that I won't reintroduce a bug that I already fixed.
> I'd rather not bother trying to get GCC libobjc changed until/unless we can
find a fix which cures both deadlocks (it's a hard argument to say to a FSF
project they should change something to fix one by replacing it with a worse
one which is Apple compatible).
Fixing the GCC runtime is the correct fix, because it is buggy. +initialize
is supposed to block all messages to that class until it completes. There are
two buggy behaviours:
- Not blocking (GCC used to do this)
- Blocking all unrelated +initialize methods (GCC and GNUstep used to do
Apple does not document that it does not block other classes receiving
+initialize methods any more than NSLock's -lock method doesn't block any
other locks. It is implicit. The exact phrase in the documentation is:
> The runtime sends initialize to each class in a program exactly one time
just before the class, or any class that inherits from it, is sent its first
message from within the program. (Thus the method may never be invoked if the
class is not used.) The runtime sends the initialize message to classes in a
Nowhere in this does it say that the +initialize method will block anything
else, only that it will complete before any other messages sent to *that
class* or its subclasses (other than ones sent from within the +initialize
method). The GCC runtime (and old versions of the GNUstep runtime) introduced
undocumented serialisation constraints. This was / is a bug.