[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyKDE] QCustomEvent Subclass and Seg Faults
From:       Phil Thompson <phil () riverbankcomputing ! co ! uk>
Date:       2003-06-17 13:20:52
[Download RAW message or body]

On Monday 16 June 2003 11:00 pm, Troy Melhase wrote:
> Hi All:
>
> I have a QCustomEvent class that's somehow related to intermittant
> segfaults. My app ismulti-threaded, and one of the threads reads socket
> data, turns the data into an object,and delivers the object to other
> interested objects.
>
> The socket-reader thread calls methods of a proxy class, listed below. 
> These methods then create the QCustomEvent subclass instances and post them
> to the application.  Here's the proxy and it's helper function:
>
> def mk_signal(signal_name):
>     def inner_ib_method(self, event):
>         self.count_incoming()
> 	## this creates an instance of the custom event subclass
> 	## 'event' is the object created by the socket reader thread
>         broker_event = BrokerSocketDataEvent(signal_name, event)
> 	try:
>             QApplication.postEvent(self.parent, broker_event)
>         except AttributeError:
>             pass
>     return inner_ib_method
>
> class BrokerEventGuiProxy(QObject):
>     def __init__(self, parent, connection):
>         self.parent = parent
>         self.message_counters = {}
>
>     def count_incoming(self):
>         hour = time.localtime()[3]
>         self.message_counters.setdefault(hour, 0)
>         self.message_counters[hour] += 1
>
>     ib_account = mk_signal('BrokerUpdateAccountValue')
>     ib_error = mk_signal('BrokerError')
>     ib_execution_details = mk_signal('BrokerExecutionDetails')
>     ib_open_order = mk_signal('BrokerOpenOrder')
>     ib_order_status = mk_signal('BrokerOrderStatus')
>     ib_ticker = mk_signal('BrokerTickerMessage')
>     ib_market_depth = mk_signal('BrokerUpdateMarketDepth')
>     ib_portfolio = mk_signal('BrokerUpdatePortfolio')
>     ib_reader_stop = mk_signal('BrokerDisconnected')
>
> And here is the QCustomEvent subclass:
>
> class BrokerSocketDataEvent(QCustomEvent):
>     names = ['BrokerError',
>              'BrokerExecutionDetails',
>              'BrokerOpenOrder',
>              'BrokerOrderStatus',
>              'BrokerTickerMessage',
>              'BrokerUpdateAccountValue',
>              'BrokerUpdateMarketDepth',
>              'BrokerUpdatePortfolio',
>              'BrokerDisconnected', ]
>     names_lookup = dict(zip(names, range(QEvent.User, \
>     	QEvent.User + len(names))))
>
>     def __init__(self, name, data):
>         event_key = self.names_lookup[name]
>         QCustomEvent.__init__(self, event_key, (name, data))
>
>
> In my main window, I have a customEvent method defined to handle
> these events:
>
>     def customEvent(self, event):
>         if isinstance(event, (BrokerSocketDataEvent, )):
>             sig, broker_signal = event.data()
>             self.emit(PYSIGNAL(sig), (broker_signal, ))
>
>
> Typically, this app processes about 10-15 of these objects per second.
> Sometimes the app will segfault after just a few hours, sometimes not at
> all. There doesn't seem to be a repeatable sequence of user actions that
> causes the behavior.
>
> Originally, I was propagating the objects by first acquiring the Qt library
> mutex and calling GUI object methods directly.  This worked and never
> caused a segfault, but chewed up 10% more CPU and made the GUI feel much
> less responsive.  Those reasons led me to the proxy solution above.
>
> Interestingly, the BrokerSocketDataEvent objects never get garbage
> collected -- I'm not certain if that'srelated to the segfaults or not. 
> When this app is run without any GUI, I don't see any leaks --the gc counts
> look constant. In the GUI code, I'm not explicitly maintaining a reference
> to the event objects as they're processed, so I'm at a loss to explain this
> behavior as well.

The PyQt documentation for QCustomEvent says that your code has to delete the 
event's data in order to avoid memory leaks. However, because of the way it 
is implemented, it's actually impossible to do. Try the attached patch - it 
includes updated documentation.

I suspect that this won't fix your original problem - but one thing at a time.

> I'm using Python 2.3b1, Qt 3.1.2, PyQt and SIP 3.6, gcc 3.2.2.  I'm a babe
> lost in the woods when it comes to debugging and debugging python
> extensions, so please forgive me if I've omitted something or stated
> something incorrectly.
>
> Any ideas?  Suggestions?  Am I doing something obviously wrong?  Known or
> fixed bug?  Thanks.

Phil
["qevent.sip.diff" (text/x-diff)]

--- qevent.sip.orig	Tue Jun 17 13:55:30 2003
+++ qevent.sip	Tue Jun 17 14:15:19 2003
@@ -57,8 +57,12 @@
 <Para>
 <Literal>QCustomEvent</Literal> is fully implemented.  Any Python object can be
 passed as the event data.  The ownership of that object is also passed to the
-<Literal>QCustomEvent</Literal>, but it is the responsibility of the code that
-handles the event to make sure that the object is deleted.
+<Literal>QCustomEvent</Literal> instance.  When
+<Literal>QCustomEvent.data()</Literal> is called, ownership is relinquished by
+the <Literal>QCustomEvent</Literal> instance so that it can be garbage
+collected.  Subsequent calls to <Literal>QCustomEvent.data()</Literal> on the
+same instance will raise an exception.  To restore ownership of the object to
+the instance, pass it to <Literal>QCustomEvent.setData()</Literal>.
 </Para>
 </Sect2>
 
@@ -1129,7 +1133,8 @@
 
 	SIP_PYOBJECT data() const;
 %MemberCode
-		// We need to cast the result and so need handwritten code.
+		// We need to cast the result and deal with ownership issues,
+		// so need handwritten code.
 
 		QCustomEvent *self;
 
@@ -1139,9 +1144,13 @@
 
 			Py_BEGIN_ALLOW_THREADS
 			res = reinterpret_cast<PyObject *>(self -> QCustomEvent::data());
+			self -> QCustomEvent::setData(0);
 			Py_END_ALLOW_THREADS
 
-			Py_XINCREF(res);
+			// Note we don't increase the reference count.
+			if (!res)
+				PyErr_SetString(PyExc_RuntimeError,"QCustomEvent.data() has already been called");
+
 			return res;
 		}
 %End

_______________________________________________
PyKDE mailing list    PyKDE@mats.imk.fraunhofer.de
http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic