1- # $Id: display.py,v 1.5 2000-08-21 10:03:45 petli Exp $
1+ # $Id: display.py,v 1.6 2000-09-06 01:51:34 petli Exp $
22#
33# Xlib.protocol.display -- core display communication
44#
2020
2121# Standard modules
2222import sys
23- import os
2423import select
25- import string
2624import struct
27- import socket
28- import re
29- import fcntl
30- import FCNTL
3125
3226# Xlib modules
3327from Xlib import error
3428
35- from Xlib .support import lock
29+ from Xlib .support import lock , connect
3630
3731# Xlib.protocol modules
3832import rq
3933import event
4034
41- display_re = re .compile (r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$' )
42-
4335class Display :
4436 resource_classes = {}
4537 extension_major_opcodes = {}
4638 error_classes = error .xerror_class .copy ()
4739 event_classes = event .event_class .copy ()
4840
4941 def __init__ (self , display = None ):
50- # Use $DISPLAY if display isn't provided
51- if display is None :
52- display = os .environ .get ('DISPLAY' , '' )
53-
54- m = display_re .match (display )
55- if not m :
56- raise error .DisplayNameError (display )
57-
58- self .display_name = display
59- host = m .group (1 )
60- dno = int (m .group (2 ))
61- screen = m .group (4 )
62- if screen :
63- self .default_screen = int (screen )
64- else :
65- self .default_screen = 0
42+ name , host , displayno , screenno = connect .get_display (display )
6643
67- try :
68- # If hostname (or IP) is provided, use TCP socket
69- if host :
70- self .socket = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
71- self .socket .connect ((host , 6000 + dno ))
44+ self .display_name = name
45+ self .default_screen = screenno
7246
73- # Else use Unix socket
74- else :
75- self .socket = socket .socket (socket .AF_UNIX , socket .SOCK_STREAM )
76- self .socket .connect ('/tmp/.X11-unix/X%d' % dno )
77- except socket .error , val :
78- raise error .DisplayConnectionError (display , str (val ))
47+ self .socket = connect .get_socket (name , host , displayno )
7948
80- # Make sure that the connection isn't inherited in child processes
81- fcntl .fcntl (self .socket .fileno (), FCNTL .F_SETFD , FCNTL .FD_CLOEXEC )
82-
83- # Find authorization cookie
84- authorization = ('' , '' )
85- try :
86- # We could parse .Xauthority, but xauth is simpler
87- # although more inefficient
88- data = os .popen ('xauth list %s 2>/dev/null' % self .display_name ).read ()
89-
90- # If there's a cookie, it is of the format
91- # DISPLAY SCHEME COOKIE
92- # We're interested in the two last parts for the
93- # connection establishment
94- lines = string .split (data , '\n ' )
95- if len (lines ) >= 1 :
96- parts = string .split (lines [0 ], None , 2 )
97- if len (parts ) == 3 :
98- scheme = parts [1 ]
99- hexauth = parts [2 ]
100- auth = ''
101-
102- # Translate hexcode into binary
103- for i in range (0 , len (hexauth ), 2 ):
104- auth = auth + chr (string .atoi (hexauth [i :i + 2 ], 16 ))
105-
106- authorization = (scheme , auth )
107-
108- except os .error :
109- pass
110-
49+ auth_name , auth_data = connect .get_auth (name , host , displayno )
11150
11251 # Internal structures for communication, grouped
11352 # by their function and locks
@@ -130,7 +69,9 @@ def __init__(self, display = None):
13069 # Send-and-recieve loop, see function send_and_recive
13170 # for a detailed explanation
13271 self .send_recv_lock = lock .allocate_lock ()
133- self .send_recv_active = 0
72+ self .send_active = 0
73+ self .recv_active = 0
74+
13475 self .event_waiting = 0
13576 self .event_wait_lock = lock .allocate_lock ()
13677 self .request_waiting = 0
@@ -168,8 +109,8 @@ def __init__(self, display = None):
168109 byte_order = order ,
169110 protocol_major = 11 ,
170111 protocol_minor = 0 ,
171- auth_prot_name = authorization [ 0 ] ,
172- auth_prot_data = authorization [ 1 ] )
112+ auth_prot_name = auth_name ,
113+ auth_prot_data = auth_data )
173114
174115 # Did connection fail?
175116 if r .status != 1 :
@@ -403,9 +344,15 @@ def send_and_recv(self, flush = None, event = None, request = None):
403344 fulfilled when the function returns, so the caller has to loop
404345 until it is finished.
405346 """
347+
348+ # We go to sleep if there is already a thread doing what we
349+ # want to do:
350+
351+ # If flushing or waiting for a request we want to send
352+ # If waiting for an event we want to recv
406353
407- # There is an active send_and_recieve, go to sleep
408- if self .send_recv_active :
354+ if ((( flush or request is not None ) and self . send_active )
355+ or ( event and self .recv_active )) :
409356
410357 # Signal that we are waiting for something. These locks
411358 # together with the *_waiting variables are used as
@@ -460,60 +407,86 @@ def send_and_recv(self, flush = None, event = None, request = None):
460407 return
461408
462409
463- # We're the only active send_and_recv, so perform
464- # all our needed network stuff.
465-
466- # Tell other threads that we are active, and lock
467- # all wait locks to give later threads something to
468- # hand on.
469-
470- self .send_recv_active = 1
410+ # There's no thread doing what we need to do. Find out exactly
411+ # what to do
471412
472- # Finally release send_recv and start doing some useful work
473- self .send_recv_lock .release ()
413+ # There must always be some thread recieving data, but it must not
414+ # necessarily be us
415+
416+ if not self .recv_active :
417+ recieving = 1
418+ self .recv_active = 1
419+ else :
420+ recieving = 0
474421
475422 flush_bytes = None
423+ sending = 0
476424
477425 # Loop, recieving and sending data.
478426 while 1 :
479427
480- # Turn all requests on request queue into binary form
481- # and append them to self.data_send
482-
483- self .request_queue_lock .acquire ()
484-
485- for req , wait in self .request_queue :
486- self .data_send = self .data_send + req ._binary
487- if wait :
488- self .sent_requests .append (req )
428+ # We might want to start sending data
429+ if sending or not self .send_active :
489430
490- del self .request_queue [:]
491-
492- self .request_queue_lock .release ()
431+ # Turn all requests on request queue into binary form
432+ # and append them to self.data_send
433+
434+ self .request_queue_lock .acquire ()
435+ for req , wait in self .request_queue :
436+ self .data_send = self .data_send + req ._binary
437+ if wait :
438+ self .sent_requests .append (req )
439+
440+ del self .request_queue [:]
441+ self .request_queue_lock .release ()
442+
443+ # If there now is data to send, mark us as senders
444+
445+ if self .data_send :
446+ self .send_active = 1
447+ sending = 1
448+ else :
449+ self .send_active = 0
450+ sending = 0
451+
452+ # We've done all setup, so release the lock and start waiting
453+ # for the network to fire up
454+ self .send_recv_lock .release ()
493455
494456 # If we're flushing, figure out how many bytes we
495457 # have to send so that we're not caught in an interminable
496458 # loop if other threads continuously append requests.
497459 if flush and flush_bytes is None :
498460 flush_bytes = self .data_sent_bytes + len (self .data_send )
499461
500- # Wait for socket to be ready for sending data (if any)
501- # and recieving data (always).
502- if self .data_send :
503- writeset = [self .socket ]
504- else :
505- writeset = []
506462
507463 try :
464+ # We're only checking for the socket to be writable
465+ # if we're the sending thread. We always check for it
466+ # to become readable: either we are the recieving thread
467+ # and should take care of the data, or the recieving thread
468+ # might finish recieving after having read the data
469+
470+ if sending :
471+ writeset = [self .socket ]
472+ else :
473+ writeset = []
474+
508475 rs , ws , es = select .select ([self .socket ], writeset , [])
509476
510477 # Ignore errors caused by a signal recieved while blocking.
511478 # All other errors are re-raised.
512479 except select .error , err :
513480 if err [0 ] != errno .EINTR :
514481 raise err
482+
483+ # We must lock send_and_recv before we can loop to
484+ # the start of the loop
485+
486+ self .send_recv_lock .acquire ()
515487 continue
516488
489+
517490 # Socket is ready for sending data, send as much as possible.
518491 if ws :
519492 try :
@@ -526,23 +499,39 @@ def send_and_recv(self, flush = None, event = None, request = None):
526499 self .data_sent_bytes = self .data_sent_bytes + i
527500
528501
529- # There is data to read. Do so and parse recieved data.
502+ # There is data to read
530503 gotreq = 0
531504 if rs :
532- try :
533- recv = self .socket .recv (2048 )
534- except socket .error , err :
535- self .close_internal ('server: %s' % err [1 ])
536- raise self .socket_error
537505
538- if not recv :
539- # Clear up, set a connection closed indicator and raise it
540- self .close_internal ('server' )
541- raise self .socket_error
542-
543- self .data_recv = self .data_recv + recv
544- gotreq = self .parse_response (request )
506+ # We're the recieving thread, parse the data
507+ if recieving :
508+ try :
509+ recv = self .socket .recv (2048 )
510+ except socket .error , err :
511+ self .close_internal ('server: %s' % err [1 ])
512+ raise self .socket_error
513+
514+ if not recv :
515+ # Clear up, set a connection closed indicator and raise it
516+ self .close_internal ('server' )
517+ raise self .socket_error
518+
519+ self .data_recv = self .data_recv + recv
520+ gotreq = self .parse_response (request )
521+
522+ # Otherwise return, allowing the calling thread to figure
523+ # out if it has got the data it needs
524+ else :
525+ # We must be a sending thread if we're here, so reset
526+ # that indicator.
527+ self .send_recv_lock .acquire ()
528+ self .send_active = 0
529+ self .send_recv_lock .release ()
530+
531+ # And return to the caller
532+ return
545533
534+
546535 # There are three different end of send-recv-loop conditions.
547536 # However, we don't leave the loop immediately, instead we
548537 # try to send and recieve any data that might be left. We
@@ -561,16 +550,22 @@ def send_and_recv(self, flush = None, event = None, request = None):
561550 if request is not None and gotreq :
562551 break
563552
564- # Else there's still data which must be sent,
565- # so loop around to another blocking select
553+ # Else there's may still data which must be sent, or
554+ # we haven't got the data we waited for. Lock and loop
555+
556+ self .send_recv_lock .acquire ()
566557
567558
568559 # We have accomplished the callers request.
569560 # Record that there are now no active send_and_recv,
570561 # and wake up all waiting thread
571562
572563 self .send_recv_lock .acquire ()
573- self .send_recv_active = 0
564+
565+ if sending :
566+ self .send_active = 0
567+ if recieving :
568+ self .recv_active = 0
574569
575570 if self .event_waiting :
576571 self .event_waiting = 0
0 commit comments