Skip to content

Commit ff79f58

Browse files
committed
Avoid a deadlock when issuing a request while another thread is reading events
from the server. This occurs when both threads block on the select call but the response has already been read by the event thread.
1 parent df65a09 commit ff79f58

2 files changed

Lines changed: 70 additions & 0 deletions

File tree

Xlib/protocol/display.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ def send_and_recv(self, flush = None, event = None, request = None, recv = None)
371371
# If waiting for an event, we want to recv
372372
# If just trying to receive anything we can, we want to recv
373373

374+
# FIXME: It would be good if we could also sleep when we're waiting on
375+
# a response to a request that has already been sent.
376+
374377
if (((flush or request is not None) and self.send_active)
375378
or ((event or recv) and self.recv_active)):
376379

@@ -472,6 +475,10 @@ def send_and_recv(self, flush = None, event = None, request = None, recv = None)
472475
# for the network to fire up
473476
self.send_recv_lock.release()
474477

478+
# There's no longer anything useful we can do here.
479+
if not (sending or recieving):
480+
break
481+
475482
# If we're flushing, figure out how many bytes we
476483
# have to send so that we're not caught in an interminable
477484
# loop if other threads continuously append requests.

examples/eventthread.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env python
2+
#
3+
# examples/eventthread.py -- Tests multithreaded event handling
4+
#
5+
# Copyright (C) 2010-2011 Outpost Embedded, LLC
6+
# Forest Bond <forest.bond@rapidrollout.com>
7+
#
8+
# This program is free software; you can redistribute it and/or modify
9+
# it under the terms of the GNU General Public License as published by
10+
# the Free Software Foundation; either version 2 of the License, or
11+
# (at your option) any later version.
12+
#
13+
# This program is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU General Public License
19+
# along with this program; if not, write to the Free Software
20+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21+
22+
import sys, time
23+
from threading import Thread
24+
25+
from Xlib import X, Xatom, threaded
26+
from Xlib.display import Display
27+
28+
29+
class EventThread(Thread):
30+
display = None
31+
_stop = None
32+
33+
def __init__(self, display):
34+
super(EventThread, self).__init__()
35+
self.display = display
36+
self.daemon = True
37+
38+
def run(self):
39+
while True:
40+
event = self.display.next_event()
41+
print 'event: %r' % event
42+
43+
44+
def main(argv):
45+
display = Display()
46+
47+
thread = EventThread(display)
48+
thread.start()
49+
time.sleep(1)
50+
51+
screen = display.screen()
52+
53+
# The get_property call should not deadlock, despite the blocking next_event
54+
# call in the thread.
55+
atom = display.intern_atom('_XROOTPMAP_ID', True)
56+
response = screen.root.get_property(atom, Xatom.PIXMAP, 0, 1)
57+
print 'get_property response: %r' % response
58+
59+
display.close()
60+
61+
62+
if __name__ == '__main__':
63+
sys.exit(main(sys.argv))

0 commit comments

Comments
 (0)