mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-04 19:10:09 +01:00
Regardless of the command-line flag there are a few methods that should always release the GIL, those that are expected to block or to take a long time. Add the annotations now in case I ever decide to change the default again.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@70984 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
15
etg/app.py
15
etg/app.py
@@ -51,7 +51,6 @@ def run():
|
||||
|
||||
c.find('HandleEvent').ignore()
|
||||
c.find('UsesEventLoop').ignore()
|
||||
|
||||
|
||||
# We will use OnAssertFailure, but I don't think we should let it be
|
||||
# overridden in Python.
|
||||
@@ -65,8 +64,12 @@ def run():
|
||||
c.find('OnFatalException').ignore()
|
||||
c.find('OnUnhandledException').ignore()
|
||||
|
||||
c.find('ExitMainLoop').isVirtual = False
|
||||
c.find('ExitMainLoop').isVirtual = False
|
||||
|
||||
# Release the GIL for potentially blocking or long-running functions
|
||||
c.find('MainLoop').releaseGIL()
|
||||
c.find('ProcessPendingEvents').releaseGIL()
|
||||
c.find('Yield').releaseGIL()
|
||||
|
||||
c.addProperty('AppDisplayName GetAppDisplayName SetAppDisplayName')
|
||||
c.addProperty('AppName GetAppName SetAppName')
|
||||
@@ -116,7 +119,7 @@ def run():
|
||||
# TODO: Add them as etg method objects instead of a WigCode block so the
|
||||
# documentation generators will see them too
|
||||
c.addItem(etgtools.WigCode("""\
|
||||
virtual int MainLoop();
|
||||
virtual int MainLoop() /ReleaseGIL/;
|
||||
virtual void OnPreInit();
|
||||
virtual bool OnInit();
|
||||
virtual bool OnInitGui();
|
||||
@@ -168,6 +171,9 @@ def run():
|
||||
display, or whatever the equivallent is for the platform.""",
|
||||
className=c.name))
|
||||
|
||||
# Release the GIL for potentially blocking or long-running functions
|
||||
c.find('SafeYield').releaseGIL()
|
||||
c.find('SafeYieldFor').releaseGIL()
|
||||
|
||||
c.addProperty('AssertMode GetAssertMode SetAssertMode')
|
||||
c.addProperty('DisplayMode GetDisplayMode SetDisplayMode')
|
||||
@@ -204,6 +210,9 @@ def run():
|
||||
f.detailedDoc = []
|
||||
|
||||
|
||||
module.find('wxYield').releaseGIL()
|
||||
module.find('wxSafeYield').releaseGIL()
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
# Now add extractor objects for the main App class as a Python class,
|
||||
|
||||
@@ -49,6 +49,9 @@ def run():
|
||||
# doc this method then...
|
||||
c.find('SetModal').ignore()
|
||||
|
||||
# Release the GIL for potentially blocking or long-running functions
|
||||
c.find('ShowModal').releaseGIL()
|
||||
|
||||
# context manager methods
|
||||
c.addPyMethod('__enter__', '(self)', 'return self')
|
||||
c.addPyMethod('__exit__', '(self, exc_type, exc_val, exc_tb)', 'self.Destroy()')
|
||||
|
||||
@@ -245,6 +245,11 @@ def run():
|
||||
tools.removeVirtuals(c)
|
||||
c.find('ProcessEvent').isVirtual = True
|
||||
|
||||
# Release the GIL for potentially blocking or long-running functions
|
||||
c.find('ProcessEvent').releaseGIL()
|
||||
c.find('ProcessEventLocally').releaseGIL()
|
||||
c.find('SafelyProcessEvent').releaseGIL()
|
||||
c.find('ProcessPendingEvents').releaseGIL()
|
||||
|
||||
|
||||
c.addPyMethod('Bind', '(self, event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)',
|
||||
|
||||
@@ -38,6 +38,10 @@ def run():
|
||||
c = module.find('wxEventLoopBase')
|
||||
assert isinstance(c, etgtools.ClassDef)
|
||||
c.abstract = True
|
||||
|
||||
c.find('Yield').releaseGIL()
|
||||
c.find('YieldFor').releaseGIL()
|
||||
|
||||
|
||||
c = module.find('wxEventLoopActivator')
|
||||
c.addPrivateAssignOp()
|
||||
|
||||
@@ -130,7 +130,12 @@ def run():
|
||||
#---------------------------------------
|
||||
# wxSize tweaks
|
||||
c = module.find('wxSize')
|
||||
|
||||
|
||||
# Used for testing releaseing or holding the GIL in giltest.py
|
||||
#c.find('wxSize').findOverload('int width, int height').releaseGIL()
|
||||
#c.find('DecBy').findOverload('int dx, int dy').releaseGIL()
|
||||
#c.find('IncBy').findOverload('int dx, int dy').releaseGIL()
|
||||
|
||||
c.addProperty("width GetWidth SetWidth")
|
||||
c.addProperty("height GetHeight SetHeight")
|
||||
|
||||
|
||||
@@ -53,10 +53,11 @@ def run():
|
||||
|
||||
c.find('SetYesNoLabels.yes').type = 'const wxString&'
|
||||
c.find('SetYesNoLabels.no').type = 'const wxString&'
|
||||
|
||||
|
||||
|
||||
tools.fixTopLevelWindowClass(c)
|
||||
|
||||
module.find('wxMessageBox').releaseGIL()
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
tools.doCommonTweaks(module)
|
||||
tools.runGenerators(module)
|
||||
|
||||
@@ -70,6 +70,12 @@ def run():
|
||||
c.find('GetScreenPosition').findOverload('int *').ignore()
|
||||
c.find('ClientToScreen').findOverload('int *').ignore()
|
||||
c.find('ScreenToClient').findOverload('int *').ignore()
|
||||
|
||||
# Release the GIL for potentially blocking or long-running functions
|
||||
c.find('PopupMenu').releaseGIL()
|
||||
c.find('ProcessEvent').releaseGIL()
|
||||
c.find('ProcessWindowEvent').releaseGIL()
|
||||
c.find('ProcessWindowEventLocally').releaseGIL()
|
||||
|
||||
# Add a couple wrapper functions for symmetry with the getters of the same name
|
||||
c.addPyMethod('SetRect', '(self, rect)', 'return self.SetSize(rect)')
|
||||
|
||||
85
samples/simple/giltest.py
Normal file
85
samples/simple/giltest.py
Normal file
@@ -0,0 +1,85 @@
|
||||
#
|
||||
# A simple test to verify that the GIL is released while in long running
|
||||
# wrappers like MainLoop, ShowModal, and PopupMenu so background threads can
|
||||
# be allowed to run at those times.
|
||||
#
|
||||
|
||||
import wx
|
||||
import threading
|
||||
import time
|
||||
import random
|
||||
|
||||
print wx.version()
|
||||
|
||||
|
||||
class ThreadedTask(threading.Thread):
|
||||
def __init__(self, *args, **kw):
|
||||
threading.Thread.__init__(self, *args, **kw)
|
||||
self.counter = 0
|
||||
self.sleepTime = random.random()/2
|
||||
self.timeToDie = False
|
||||
|
||||
def run(self):
|
||||
while not self.timeToDie:
|
||||
time.sleep(self.sleepTime)
|
||||
self.counter += 1
|
||||
print 'thread: %5s count: %d' % (self.name, self.counter)
|
||||
|
||||
|
||||
|
||||
class MainFrame(wx.Frame):
|
||||
def __init__(self):
|
||||
wx.Frame.__init__(self, None, title="GIL Test")
|
||||
self.pnl = wx.Panel(self)
|
||||
btn = wx.Button(self.pnl, label='modal dialog', pos=(10,10))
|
||||
self.Bind(wx.EVT_BUTTON, self.onButton, btn)
|
||||
self.pnl.Bind(wx.EVT_CONTEXT_MENU, self.onShowMenu)
|
||||
btn = wx.Button(self.pnl, label='timed test', pos=(10, 60))
|
||||
self.Bind(wx.EVT_BUTTON, self.onOtherButton, btn)
|
||||
|
||||
|
||||
def onButton(self, evt):
|
||||
dlg = wx.Dialog(self, title='close this dialog', size=(300,150))
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
|
||||
def onOtherButton(self, evt):
|
||||
# A simplistic benchmark test that times many repititions of some
|
||||
# simple operations so they can be tested with and without releasing
|
||||
# the GIL
|
||||
start = time.time()
|
||||
reps = 100000
|
||||
for x in range(reps):
|
||||
s = wx.Size(100, 100)
|
||||
for n in range(10):
|
||||
s.DecBy(4,6)
|
||||
for n in range(10):
|
||||
s.IncBy(4,6)
|
||||
wx.MessageBox('%d reps performed in %f seconds' % (reps, time.time() - start),
|
||||
'Results')
|
||||
|
||||
|
||||
def onShowMenu(self, evt):
|
||||
menu = wx.Menu()
|
||||
menu.Append(-1, 'one')
|
||||
menu.Append(-1, 'two')
|
||||
menu.Append(-1, 'three')
|
||||
self.pnl.PopupMenu(menu)
|
||||
menu.Destroy()
|
||||
|
||||
|
||||
|
||||
threads = [ ThreadedTask(name='one'), ThreadedTask(name='two'), ThreadedTask(name='three') ]
|
||||
for t in threads:
|
||||
t.start()
|
||||
|
||||
app = wx.App()
|
||||
frm = MainFrame()
|
||||
frm.Show()
|
||||
app.MainLoop()
|
||||
|
||||
for t in threads:
|
||||
t.timeToDie = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user