X Tutup
Skip to content

Commit 7aeee77

Browse files
committed
Update to handling of browser and frame references (cztomczak#365)
There are still some strange issues with CEF. For example I can see that OnContextReleased is executed twice for that same frame.
1 parent 92b1895 commit 7aeee77

File tree

4 files changed

+48
-14
lines changed

4 files changed

+48
-14
lines changed

src/browser.pyx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ cdef PyBrowser GetPyBrowser(CefRefPtr[CefBrowser] cefBrowser,
7474
cdef JavascriptBindings javascriptBindings
7575
cdef PyBrowser tempPyBrowser
7676

77-
if browserId in g_unreferenced_browsers:
77+
if browserId in g_unreferenced_browsers \
78+
or browserId in g_closed_browsers:
7879
# This browser was already unreferenced due to OnBeforeClose
7980
# was already called. An incomplete new instance of Browser
8081
# object is created. This instance doesn't have the client
@@ -119,9 +120,13 @@ cdef PyBrowser GetPyBrowser(CefRefPtr[CefBrowser] cefBrowser,
119120
cdef void RemovePyBrowser(int browserId) except *:
120121
# Called from LifespanHandler_OnBeforeClose().
121122
global g_pyBrowsers, g_unreferenced_browsers
123+
cdef PyBrowser pyBrowser
122124
if browserId in g_pyBrowsers:
123125
# noinspection PyUnresolvedReferences
124126
Debug("del g_pyBrowsers[%s]" % browserId)
127+
pyBrowser = g_pyBrowsers[browserId]
128+
pyBrowser.cefBrowser.Assign(NULL)
129+
del pyBrowser
125130
del g_pyBrowsers[browserId]
126131
g_unreferenced_browsers.append(browserId)
127132
else:

src/cefpython.pyx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -843,11 +843,6 @@ def QuitMessageLoop():
843843
def Shutdown():
844844
Debug("Shutdown()")
845845

846-
# Release shared request context. This is sometimes causing
847-
# segmentation fault, so disabling it for now. See Issue #333:
848-
# https://github.com/cztomczak/cefpython/issues/333
849-
# OFF: g_shared_request_context.Assign(NULL)
850-
851846
# Run some message loop work, force closing browsers and then run
852847
# some message loop work again for the browsers to close cleanly.
853848
#
@@ -929,6 +924,12 @@ def Shutdown():
929924
NonCriticalError("Shutdown called, but there are still browser"
930925
" references alive")
931926

927+
# Release shared request context. In the past this was sometimes
928+
# causing segmentation fault. See Issue #333:
929+
# https://github.com/cztomczak/cefpython/issues/333
930+
# Debug("Free g_shared_request_context")
931+
# g_shared_request_context.Assign(NULL)
932+
932933
Debug("CefShutdown()")
933934
with nogil:
934935
CefShutdown()

src/frame.pyx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ include "browser.pyx"
77

88
cdef dict g_pyFrames = {}
99

10+
# If a frame was unreferenced (browser closed or OnContextReleased)
11+
# it shouldn't be kept global anymore.
12+
cdef list g_unreferenced_frames = [] # [str unique identifier, ..]
13+
1014
cdef object GetUniqueFrameId(int browserId, object frameId):
1115
return str(browserId) +"#"+ str(frameId)
1216

@@ -24,6 +28,11 @@ cdef PyFrame GetPyFrame(CefRefPtr[CefFrame] cefFrame):
2428

2529
cdef PyFrame pyFrame
2630
cdef object frameId = cefFrame.get().GetIdentifier() # int64
31+
if frameId < 0:
32+
# Underlying frame does not yet exist.
33+
Debug("GetPyFrame(): underlying frame does not yet exist"
34+
", frameId = {0}".format(frameId))
35+
return None
2736
cdef int browserId = cefFrame.get().GetBrowser().get().GetIdentifier()
2837
assert (frameId and browserId), "frameId or browserId empty"
2938
cdef object uniqueFrameId = GetUniqueFrameId(browserId, frameId)
@@ -46,9 +55,12 @@ cdef PyFrame GetPyFrame(CefRefPtr[CefFrame] cefFrame):
4655
pyFrame = PyFrame(browserId, frameId)
4756
pyFrame.cefFrame = cefFrame
4857

49-
if browserId in g_unreferenced_browsers:
58+
if uniqueFrameId in g_unreferenced_frames \
59+
or browserId in g_unreferenced_browsers \
60+
or browserId in g_closed_browsers:
5061
# Browser was already globally unreferenced in OnBeforeClose,
51-
# thus all frames are globally unreferenced too. Create a new
62+
# thus all frames are globally unreferenced too, or frame
63+
# was unreferenced in OnContextReleased. Create a new
5264
# incomplete instance of PyFrame object. Read comments in
5365
# browser.pyx > GetPyBrowser and in Browser.md for what
5466
# "incomplete" means.
@@ -60,17 +72,22 @@ cdef PyFrame GetPyFrame(CefRefPtr[CefFrame] cefFrame):
6072
# SIDE EFFECT: two calls to GetPyFrame for the same frame object
6173
# may return two different PyFrame objects. Compare
6274
# frame objects always using GetIdentifier().
63-
# Debug("GetPyFrame(): create new PyFrame, frameId=%s" % frameId)
75+
Debug("GetPyFrame(): create new PyFrame, frameId=%s" % frameId)
6476
g_pyFrames[uniqueFrameId] = pyFrame
6577
return pyFrame
6678

6779
cdef void RemovePyFrame(int browserId, object frameId) except *:
6880
# Called from V8ContextHandler_OnContextReleased().
6981
global g_pyFrames
82+
cdef PyFrame pyFrame
7083
cdef object uniqueFrameId = GetUniqueFrameId(browserId, frameId)
7184
if uniqueFrameId in g_pyFrames:
7285
Debug("del g_pyFrames[%s]" % uniqueFrameId)
86+
pyFrame = g_pyFrames[uniqueFrameId]
87+
pyFrame.cefFrame.Assign(NULL)
88+
del pyFrame
7389
del g_pyFrames[uniqueFrameId]
90+
g_unreferenced_frames.append(uniqueFrameId)
7491
else:
7592
Debug("RemovePyFrame() FAILED: uniqueFrameId = %s" % uniqueFrameId)
7693

@@ -85,7 +102,11 @@ cdef void RemovePyFramesForBrowser(int browserId) except *:
85102
toRemove.append(uniqueFrameId)
86103
for uniqueFrameId in toRemove:
87104
Debug("del g_pyFrames[%s]" % uniqueFrameId)
105+
pyFrame = g_pyFrames[uniqueFrameId]
106+
pyFrame.cefFrame.Assign(NULL)
107+
del pyFrame
88108
del g_pyFrames[uniqueFrameId]
109+
g_unreferenced_frames.append(uniqueFrameId)
89110

90111
cdef class PyFrame:
91112
cdef CefRefPtr[CefFrame] cefFrame

src/handlers/lifespan_handler.pyx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ cdef public void LifespanHandler_OnBeforeClose(
110110
CefRefPtr[CefBrowser] cefBrowser
111111
) except * with gil:
112112
cdef PyBrowser pyBrowser
113+
cdef int browserId
113114
cdef object callback
114115
try:
115116
Debug("LifespanHandler_OnBeforeClose")
@@ -126,14 +127,20 @@ cdef public void LifespanHandler_OnBeforeClose(
126127
callback = pyBrowser.GetClientCallback("OnBeforeClose")
127128
if callback:
128129
callback(browser=pyBrowser)
129-
RemovePythonCallbacksForBrowser(pyBrowser.GetIdentifier())
130-
RemovePyFramesForBrowser(pyBrowser.GetIdentifier())
131-
RemovePyBrowser(pyBrowser.GetIdentifier())
130+
131+
browserId = pyBrowser.GetIdentifier()
132+
pyBrowser.cefBrowser.Assign(NULL)
133+
cefBrowser.Assign(NULL)
134+
del pyBrowser
135+
136+
RemovePythonCallbacksForBrowser(browserId)
137+
RemovePyFramesForBrowser(browserId)
138+
RemovePyBrowser(browserId)
139+
132140
if g_MessageLoop_called and not len(g_pyBrowsers):
133141
# Automatically quit message loop when last browser was closed.
134142
# This is required for hello_world.py example to work.
135-
QuitMessageLoop()
136-
143+
PostTask(TID_UI, QuitMessageLoop)
137144
except:
138145
(exc_type, exc_value, exc_trace) = sys.exc_info()
139146
sys.excepthook(exc_type, exc_value, exc_trace)

0 commit comments

Comments
 (0)
X Tutup