Commit e8ae9f76 authored by Jim Fulton's avatar Jim Fulton

It is no longer necessary to symbolically link cPickle or

ZServer. ZServer is no longer necessary at all.

Fixed a race condition in __call__.

If an exception raised on the server which could not be
unpickled on the client could cause the client connection to
fail.
parent 16ba15a2
......@@ -85,10 +85,10 @@
"""Simple rpc mechanisms
"""
__version__ = "$Revision: 1.12 $"[11:-2]
__version__ = "$Revision: 1.13 $"[11:-2]
from ZODB.cPickle import loads
from ZODB import cPickle
from cPickle import loads
import cPickle
from thread import allocate_lock
from smac import SizedMessageAsyncConnection
import socket, string, struct, asyncore, sys, time, select
......@@ -102,6 +102,9 @@ pickler=cPickle.Pickler()
pickler.fast=1 # Don't use the memo
dump=pickler.dump
class UnUnPickleableError(Exception):
"Couldn't unpickle a remote exception"
class asyncRPC(SizedMessageAsyncConnection):
__map=0
......@@ -119,6 +122,10 @@ class asyncRPC(SizedMessageAsyncConnection):
self.__r=None
l.acquire()
l=allocate_lock() # Response lock used to wait for call results
self.__call_la=l.acquire
self.__call_lr=l.release
def connect(self, tryonce=1, log_type='client'):
t=self._tmin
connection = self._connection
......@@ -152,7 +159,7 @@ class asyncRPC(SizedMessageAsyncConnection):
return 1
def finishConnect(self, s):
SizedMessageAsyncConnection.__init__(self, s, s.getpeername(), {})
SizedMessageAsyncConnection.__init__(self, s, '', {})
# we are our own socket map!
def keys(self): return (self._fileno,)
......@@ -190,30 +197,37 @@ class asyncRPC(SizedMessageAsyncConnection):
def __call__(self, *args):
args=dump(args,1)
self.message_output(args)
self.__call_la()
try:
self._last_args=args=dump(args,1)
self.message_output(args)
if self.__map: self.__Wakeup() # You dumb bastard
else: self.readLoop()
if self.__map: self.__Wakeup() # You dumb bastard
else: self.readLoop()
while 1:
r=self._read()
c=r[:1]
if c=='R':
if r=='RN.': return None # Common case!
return loads(r[1:])
if c=='E':
r=loads(r[1:])
if type(r) is TupleType: raise r[0], r[1]
raise r
oob=self._outOfBand
if oob is not None:
r=r[1:]
if r=='N.': r=None # Common case!
else: r=loads(r)
oob(c, r)
else:
raise UnrecognizedResult, r
while 1:
r=self._read()
c=r[:1]
if c=='R':
if r=='RN.': return None # Common case!
return loads(r[1:])
if c=='E':
try: r=loads(r[1:])
except:
raise UnUnPickleableError(r[1:])
if type(r) is TupleType: raise r[0], r[1]
raise r
oob=self._outOfBand
if oob is not None:
r=r[1:]
if r=='N.': r=None # Common case!
else: r=loads(r)
oob(c, r)
else:
raise UnrecognizedResult, r
finally:
self._last_args=''
self.__call_lr()
def sendMessage(self, *args):
self.message_output(dump(args,1))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment