Closed Bug 52936 Opened 24 years ago Closed 24 years ago

JS Component loader is not threadsafe

Categories

(Core :: XPConnect, defect, P3)

defect

Tracking

()

RESOLVED FIXED

People

(Reporter: jonsmirl, Assigned: jband_mozilla)

Details

Attachments

(4 files)

1) do first inital load of a JS component from a worker thread. This will cause mozJSComponentLoader to allocate a JS context from the worker thread. 2) Shut down XPCOM from main thread. This will cause an assert in js_GetSlotWhileLocked. #ifndef NSPR_LOCK, JS_ASSERT(me == CurrentThreadId()); The problem is that the context was created on the worker thread and then destroyed from the main thread.
Changing bug bugzilla "Component" to XPConnect (because the JS loader does not have its own Component in bugzilla). and reassigning to shaver. Shaver, do you still own the JS loader or what? Do you want me to own it? I sometimes wonder if we shouldn't just merge it into the xpconnect module.
Assignee: rogerl → shaver
Component: Javascript Engine → XPConnect
Status: UNCONFIRMED → NEW
Ever confirmed: true
mozJSComponentLoader.cpp line 241 I needed to change to the threadsafe version NS_IMPL_THREADSAFE_ISUPPORTS(mozJSComponentLoader, NS_GET_IID (nsIComponentLoader));
I tried three different work arounds without success. Component loader needs to support per thread contexts if this is ever going to work.
Shaver's in Washington, D.C., should be back in a day or two. /be
This is a temporary patch to get around the problem. It does not fix the complete problem. A lock is used to completely serialize JS component creation. Current thread id is set into the shared JS context before it is used. cvs diff mozJSComponentLoader.h (in directory d:\cvs\mozilla\js\src\xpconnect\loader\) Index: mozJSComponentLoader.h =================================================================== RCS file: /cvsroot/mozilla/js/src/xpconnect/loader/mozJSComponentLoader.h,v retrieving revision 1.12 diff -r1.12 mozJSComponentLoader.h 70a71 > PRLock* mSerialize; *****CVS exited normally with code 1***** cvs diff mozJSComponentLoader.cpp (in directory d:\cvs\mozilla\js\src\xpconnect\loader\) Index: mozJSComponentLoader.cpp =================================================================== RCS file: /cvsroot/mozilla/js/src/xpconnect/loader/mozJSComponentLoader.cpp,v retrieving revision 1.48 diff -r1.48 mozJSComponentLoader.cpp 191a192 > mSerialize = PR_NewLock(); 226a228 > JS_SetContextThread(mContext); 238a241 > PR_DestroyLock(mSerialize); 241c244 < NS_IMPL_ISUPPORTS(mozJSComponentLoader, NS_GET_IID(nsIComponentLoader)); --- > NS_IMPL_THREADSAFE_ISUPPORTS(mozJSComponentLoader, NS_GET_IID (nsIComponentLoader)); 258a262 > PR_Lock(mSerialize); 259a264,265 > PR_Unlock(mSerialize); > 886a893 > JS_SetContextThread(mContext); 973a981 > JS_SetContextThread(mContext); 1105a1114 > JS_SetContextThread(mContext); *****CVS exited normally with code 1*****
Jon, diff -u format patches attached to the bug, not inserted in comments, are the way to go. I haven't had a chance to study your patch, but it may just be papering over those assertbotches -- JS_SetContextThread is not enough, you must use a JSContext on at most one thread at a time. You can share a JSContext among threads only by serializing batches of JS API calls using that context. Is that what the lock you added does, in all cases (including destruction)? /be
The context in the js loader is only used for compiling the script. During method calls XPConnect provides me with the safe context on each call. I don't think there is a need for per thread contexts in the js loader if the jsloader has been serialized to allow only a single createInstance to happen at a time. That's what my patch did. My patch didn't deal with things like registration. Note that thread safe issues in createInstance are broader than just the JS loader. http://bugzilla.mozilla.org/show_bug.cgi?id=52718
Attached patch Same patch in diff -u format (deleted) — Splinter Review
I don't much like the idea of holding a lock while the JS executes. I think the thing to do is to not even create a JSContext in this code. We can get one from the js thread context service. It should be the component manager's job to ensure that calls to the loader are serialized (and don't nest on the same thread!). We ought to fix that problem in the component manager, not in each loader. The JS loader *should* protect its mutable state, however. It also needs to use Begin/End Request. I'll do some work on this and attach a patch later.
Why would we want to avoid nesting on the same thread? Does that rule exist for the native loader as well? I guess it's part of only doing a minimal amount of infallible work in the constructor, but I'm not sure the codebase is up to the challenge. And what should the component mgr do if it detects that it's about to nest? Return failure?
I forgot about nesting. What if the JS code being compiled loads another JS component? Obviously my lock won't work. These issues may also be the source of my double GC problem which does a nested createInstance. I was very surprised to discover that CreateInstance was not thread safe for creating any components, JS or otherwise. This is probably worth a code review and some test cases.
Shaver, if loading 'a' calls 'b' which asks that we load 'a' then we're likely to go into a stack blowing cycle. This is a coding error that the component manager ought to catch and return an error.
Attached patch Proposed patch (deleted) — Splinter Review
Attached file proposed cvs checkin comment (deleted) —
Assuming that the component manager gets fixed to serialize and detect nested calls to GetFactory, then I think this will pretty much do it. I assume that other calls into the loader are only going to happen on the main thread. I did not add any explicit locking here. This is still playing things loosly. There is also more JS loader stuff to fix: - I still have bug 50611 regarding shutdown errors that I thought were fixed. - grinda has changes for his subscript loader. - I'm wondering why we don't do any exception cleanup when we call directly into JS from the loader. - And, I was serious about the idea of just moving the whole thing into xpconnect. Thoughts?
I'm going to try the new patches right now. Has the case of a JS component createInstancing another JS component from createInstance be allowed for? I'm thinking of just a normal case, not a pair of creates causing infinite recursion. When doing createInstance I hit the threadsafe assert in these files too. This implies that there are five more components that need to be checked for thread safety. nsComponentManager.cpp lines: 403, 513 nsRegistry.cpp lines: 341, 1946 nsCategoryManager.cpp line: 152 I'm hitting the shut down assert that you mention too.
WTF is that PRUnichar thing, indeed? Must predate the decision to use the normal XPCOM naming stuff. Just lose it, don't preserve the (my?) shame. Cute autoclasses -- I blame brendan for my goto affliction. r=shaver I guess we might as well move the loader into XPConnect. I just liked the idea of having it be its own, independently-replaceable component, but I can get past my childish dreams in the name of fewer libraries and build directories. Rename to nsJSComponentLoader when you relocate it to xpconnect/src? Lack of exception cleanup is a bug, and another source of shame. You want to get it, or should I try to find time?
Compiler errors from xpcom standalone environment on Windows. My CVS is a couple days old so I'm pulling and building a new one. D:\CVS\mozilla\js\src\xpconnect\shell>..\..\..\..\config\makecopy.exe .\WIN32_D. OBJ\xpcshell.exe ..\..\..\..\dist\WIN32_D.OBJ\bin w95make: Leaving Directory d:\cvs\mozilla\js\src\xpconnect\shell with target ins tall w95make: Entering Directory d:\cvs\mozilla\js\src\xpconnect\loader with target i nstall mozJSComponentLoader.cpp d:\cvs\mozilla\js\src\xpconnect\loader\mozJSComponentLoader.cpp(72) : error C206 5: 'NS_SCRIPTSECURITYMANAGER_CONTRACTID' : undeclared identifier d:\cvs\mozilla\js\src\xpconnect\loader\mozJSComponentLoader.cpp(72) : error C244 0: 'initializing' : cannot convert from 'int' to 'const char []' There are no conversions to array types, although there are conversions to references or pointers to arrays d:\cvs\mozilla\js\src\xpconnect\loader\mozJSComponentLoader.cpp(73) : error C206 5: 'NS_OBSERVERSERVICE_CONTRACTID' : undeclared identifier d:\cvs\mozilla\js\src\xpconnect\loader\mozJSComponentLoader.cpp(73) : error C244 0: 'initializing' : cannot convert from 'int' to 'const char []' There are no conversions to array types, although there are conversions to references or pointers to arrays d:\cvs\mozilla\js\src\xpconnect\loader\mozJSComponentLoader.cpp(1186) : error C2 065: 'NS_CATEGORYMANAGER_CONTRACTID' : undeclared identifier NMAKE : fatal error U1077: 'D:\PROGRA~1\MICROS~2\VC98\BIN\cl.exe' : return code '0x2' Stop. w95make: nmake failed in directory loader with error code 2 NMAKE : fatal error U1077: '..\..\..\config\w95make.exe' : return code '0x2' Stop. w95make: nmake failed in directory xpconnect with error code 2 NMAKE : fatal error U1077: '..\..\config\w95make.exe' : return code '0x2' Stop. NMAKE : fatal error U1077: '"D:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\BIN\N MAKE.exe"' : return code '0x2' Stop. NMAKE : fatal error U1077: '"D:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\BIN\N MAKE.exe"' : return code '0x2' Stop. D:\CVS\mozilla>
How embarrassing to miss that on review. I rescind my r=shaver until this atrocity is repaired!
Assignee: shaver → jband
Shaver, You're joking right? Jon's tree clearly predates the progid->contractid renaming.
Accepting the bug. I'll fix the remaining stuff mentioned.
Status: NEW → ASSIGNED
Your right, I just had 500 new files come down. That why it is taking me so long to build.
New attachment is the same as before except that I moved one line inside a #ifndef XPCONNECT_STANDALONE block to correctly deal with #defined string from scriptsecuritymanager.
I have it built and installed now. It will take me a couple of hours to verify that it is working. I'm still worried about the other components referenced in http://bugzilla.mozilla.org/show_bug.cgi?id=52718. Ray's comment leads me to believe this is not being worked on. Using XPCOM in a server environment requires that createInstance be threadsafe.
I'm getting an assert at shutdown. It only happens when a JS component is loaded. I get the same assert if I register a JS component with regxpcom. Other that this assert I seem to be functioning. I'm only walking it through with the debugger so I'm not really stressing threading issues. Apache/1.3.12 (Win32) PX7/0.9 running... Type Manifest File: d:\testdll\components\xpti.dat ###!!! ASSERTION: Component Manager being held past XPCOM shutdown.: 'cnt == 0', file d:\cvs\mozilla\xpcom\build\nsXPComInit.cpp, line 667 Press any key to continue Stack trace: nsDebug::Assertion(const char * 0x00c80180, const char * 0x00c80174, const char * 0x00c80148, int 0x0000029b) line 215 + 22 bytes nsDebug::WarnIfFalse(const char * 0x00c80180, const char * 0x00c80174, const char * 0x00c80148, int 0x0000029b) line 358 + 21 bytes NS_ShutdownXPCOM(nsIServiceManager * 0x00000000) line 667 + 31 bytes PX7Servlet::childTerm() line 81 + 10 bytes ChildTerm(server_rec * 0x008762dc, pool * 0x008762b4) line 40 ap_child_exit_modules(pool * 0x008762b4, server_rec * 0x008762dc) line 1537 + 14 bytes worker_main() line 6040 + 18 bytes apache_main(int 0x00000007, char * * 0x00981f50) line 6874 main(int 0x00000007, char * * 0x00981f50) line 15 + 13 bytes mainCRTStartup() line 338 + 17 bytes KERNEL32! bff89349() KERNEL32! bff891fb() KERNEL32! bff87c38()
That's been around forever. It seems harmless. I can't find a bug number. I dug in once and did not see a clear way to makeit go away.
marking fixed. My patches when in the on Sept 21.
Status: ASSIGNED → RESOLVED
Closed: 24 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: