+2006-08-02 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin.
+
+ Bug 10200: [Drosera] Deadlock between Drosera and Safari while loading page
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=10200
+
+ Prevent reentrancy in our debugger callbacks. This was causing a deadlock in Drosera because
+ suspendProcessIfPaused was being called during a DO call into Safari.
+
+ Preventing reentrancy also prevents scripts that Drosera injects and evaluates from showing
+ up in rare cases (such as a iframe loading about:blank). I thought this would prevent cases
+ where you call a function from the console and expect it to break on a breakpoint in them, but
+ this appears to never have worked even without this change. When that is figured out we can
+ reconsider a better solution to reentrancy. I have filed that as bug 10214.
+
+ I also removed the NSRunLoop runMode:beforeDate: calls since DO handles this for us since
+ we don't use "onway void" as the return type for the callbacks. Note: using onway void for
+ the listener callbacks causes bad synchronization issues and obscure crashes.
+
+ * DefaultDelegates/WebScriptDebugServer.m:
+ (-[WebScriptDebugServer webView:didLoadMainResourceForDataSource:]):
+ (-[WebScriptDebugServer webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:]):
+ (-[WebScriptDebugServer webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:]):
+ (-[WebScriptDebugServer webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[WebScriptDebugServer webView:willExecuteStatement:sourceId:line:forWebFrame:]):
+ (-[WebScriptDebugServer webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ (-[WebScriptDebugServer webView:exceptionWasRaised:sourceId:line:forWebFrame:]):
+ * DefaultDelegates/WebScriptDebugServerPrivate.h:
+
2006-08-02 Maciej Stachowiak <mjs@apple.com>
Reviewed by John.
- (void)webView:(WebView *)webView didLoadMainResourceForDataSource:(WebDataSource *)dataSource
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
if ([[listener connectionForProxy] isValid])
[listener webView:webView didLoadMainResourceForDataSource:dataSource];
}
+
+ inCallback = NO;
}
- (void)webView:(WebView *)webView didParseSource:(NSString *)source
sourceId:(int)sid
forWebFrame:(WebFrame *)webFrame
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
if ([[listener connectionForProxy] isValid])
[listener webView:webView didParseSource:source baseLineNumber:lineNumber fromURL:url sourceId:sid forWebFrame:webFrame];
}
+
+ inCallback = NO;
}
- (void)webView:(WebView *)webView failedToParseSource:(NSString *)source
withError:(NSError *)error
forWebFrame:(WebFrame *)webFrame
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
if ([[listener connectionForProxy] isValid])
[listener webView:webView failedToParseSource:source baseLineNumber:lineNumber fromURL:url withError:error forWebFrame:webFrame];
}
+
+ inCallback = NO;
}
- (void)webView:(WebView *)webView didEnterCallFrame:(WebScriptCallFrame *)frame
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
[listener webView:webView didEnterCallFrame:frame sourceId:sid line:lineno forWebFrame:webFrame];
}
- // check for messages from the listeners, so they can pause immediately
- [[NSRunLoop currentRunLoop] runMode:NSConnectionReplyMode beforeDate:[NSDate distantPast]];
-
[self suspendProcessIfPaused];
+
+ inCallback = NO;
}
- (void)webView:(WebView *)webView willExecuteStatement:(WebScriptCallFrame *)frame
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
[listener webView:webView willExecuteStatement:frame sourceId:sid line:lineno forWebFrame:webFrame];
}
- // check for messages from the listeners, so they can pause immediately
- [[NSRunLoop currentRunLoop] runMode:NSConnectionReplyMode beforeDate:[NSDate distantPast]];
-
[self suspendProcessIfPaused];
+
+ inCallback = NO;
}
- (void)webView:(WebView *)webView willLeaveCallFrame:(WebScriptCallFrame *)frame
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
[listener webView:webView willLeaveCallFrame:frame sourceId:sid line:lineno forWebFrame:webFrame];
}
- // check for messages from the listeners, so they can pause immediately
- [[NSRunLoop currentRunLoop] runMode:NSConnectionReplyMode beforeDate:[NSDate distantPast]];
-
[self suspendProcessIfPaused];
+
+ inCallback = NO;
}
- (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
- if (![listeners count])
+ if (![listeners count] || inCallback)
return;
+ inCallback = YES;
+
NSEnumerator *enumerator = [listeners objectEnumerator];
NSDistantObject <WebScriptDebugListener> *listener = nil;
[listener webView:webView exceptionWasRaised:frame sourceId:sid line:lineno forWebFrame:webFrame];
}
- // check for messages from the listeners, so they can pause immediately
- [[NSRunLoop currentRunLoop] runMode:NSConnectionReplyMode beforeDate:[NSDate distantPast]];
-
[self suspendProcessIfPaused];
+
+ inCallback = NO;
}
@end