My application calls v8::V8::TerminateExecution when some JavaScript has been running too long. This works well for the most part, but I have seen some cases where TerminateExecution blocks indefinitely while trying to lock a mutex. I haven't been able to reproduce this locally, it just happens from time to time in a production environment. From looking at v8::V8::TerminateExecution, it looks like the only mutex it tries to lock is the break_access lock on the Isolate. AFAICS this mutex isn't ever held while calling outside of V8 code, so it shouldn't be possible for my code to cause V8 to hold the break_access mutex indefinitely. That said, I can't see how else it could happen. Of the other threads besides the one calling TerminateExecution, the ones that stand out are:
- One thread in GcEpilogue (waiting to acquire a mutex held by the thread calling TerminateExecution)
- A couple of threads calling v8::Locker::Initialize - although I'm pretty sure these are for different isolates.
I can probably work around this by ensuring that I release my own mutex before calling v8::V8::TerminateExecution, although this does introduce a fairly benign race condition.
My initial instinct was that perhaps GcEpilogue was being called while the break_access mutex was held. This would definitely cause what I'm seeing to happen. But from my tests and a brief reading of the code, it doesn't seem to keep break_access locked while calling GcEpilogue, although I can't be completely sure that it doesn't under some circumstances.
Does anyone have any idea what could cause the break_access mutex to be held for a long time or indefinitely?
Thanks,
David