Hi everyone,

I've tried to debug issues with "struct.error: unpack requires a string 
argument of length 4" I experience on my machine 
(http://code.google.com/p/spyderlib/issues/detail?id=113#c6). So I've 
inserted a lot of debug statements all over bsdsocket.debug.diff - I don't 
remember the exact reason why I chose to write debug info to file - 
probably printing caused a deadlock.

Anyway, the corresponding diff for debugging bsdsocket is in attach, and 
instead of solving my issue I've run into a bigger problem - with this diff 
applied Spyder freezes after several seconds after editor becomes 
operational. I suspect this happens when object inspector fires, but I am 
not sure.

I've debugged deadlock using the method I've just described at 
http://code.google.com/p/spyderlib/wiki/HowToDebugDeadlock and it seems 
that the problem is that in bsdsocket.communicate() something fails to 
respond to socket read, probably waiting for a lock.

I could dig further, but the thing that bugs me most is that even if it is 
a race condition - it is 100% time repeatable with debug patch turned on, 
and doesn't appear without it. I need some help from the experts in 
threading to answer if a file I/O writes to the single debug log file from 
multiple threads can be the reason for the proactive heisenbug deadlock?

-- 
anatoly t.

-- 
You received this message because you are subscribed to the Google Groups 
"spyder" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/spyderlib/-/bSvi9j6Q_2gJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/spyderlib?hl=en.

diff -r b922b235bf68 spyderlib/utils/bsdsocket.py
--- a/spyderlib/utils/bsdsocket.py	Sat Mar 17 12:32:26 2012 +0300
+++ b/spyderlib/utils/bsdsocket.py	Sat Mar 17 19:02:17 2012 +0300
@@ -15,17 +15,47 @@
 import cPickle as pickle
 import threading
 
+DEBUG = True
+#DEBUG = False
+
+if DEBUG:
+    logfile = open('bsdsocket_debug.log', 'w', 0)
+    logfile.write('---[debug log started]---\n')
+    logfile.write('R/W.SOCKET.COUNTER (LEN) <TYPE/PICKLED>  DUMP\n')
+    
+    def tohex(data):
+        import binascii
+        return binascii.hexlify(data)
+
+
+# [ ] todo - move it into a socket class
+write_counter = 0
+read_counter = 0
+
 
 SZ = struct.calcsize("l")
 
 
 def write_packet(sock, data, already_pickled=False):
     """Write *data* to socket *sock*"""
+    global write_counter
+    write_counter += 1
+    if DEBUG:
+        prefix = "W%02d.%02d" % (sock.fileno(), write_counter)
+        logfile.write("%s (%s) <%s/%s>" % 
+            (prefix, len(data), type(data).__name__, already_pickled))
+        logfile.write(" %s\n" % (repr(data)))
     if already_pickled:
         sent_data = data
     else:
         sent_data = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
-    sock.send(struct.pack("l", len(sent_data)) + sent_data)
+    packet = struct.pack("l", len(sent_data)) + sent_data
+    # [ ] check the number of bytes sent
+    sent = sock.send(packet)
+    if DEBUG:
+        # SOCKET/COUNTER  (sent/len) hexdump
+        logfile.write("%s   (%s/%s) %s\n" % 
+            (prefix, sent, len(packet), tohex(packet)))
 
 
 def read_packet(sock, timeout=None):
@@ -33,24 +63,41 @@
     Read data from socket *sock*
     Returns None if something went wrong
     """
+    global read_counter
+    read_counter += 1
+    if DEBUG:
+        prefix = "R%02d.%02d" % (sock.fileno(), read_counter)
+        logfile.write("%s " % (prefix))
     sock.settimeout(timeout)
     dlen, data = None, None
     try:
         datalen = sock.recv(SZ)
+        if DEBUG:
+            logfile.write("len(len):%s\n" % (len(datalen)))
         dlen, = struct.unpack("l", datalen)
+        if DEBUG:
+            logfile.write("%s   (%s) " % (prefix, dlen))
         data = ''
         while len(data) < dlen:
             data += sock.recv(dlen)
+        if DEBUG:
+            logfile.write("%s\n" % (tohex(data)))
     except socket.timeout:
         raise
     except socket.error:
+        if DEBUG:
+            logfile.write("%s ERROR: socket.error\n" % prefix)
         data = None
     finally:
         sock.settimeout(None)
     if data is not None:
         try:
+            if DEBUG:
+                logfile.write("%s   %s\n" % (prefix, repr(pickle.loads(data))))
             return pickle.loads(data)
         except (EOFError, pickle.UnpicklingError):
+            if DEBUG:
+                logfile.write("%s ERROR: unpickling\n" % prefix)
             return
 
 

Reply via email to