cristi fati - 2016-06-22

V2 - python27 support for Windows
I don't know if anyone uses it for Windows since it doesn't compile OOTB.

I discovered another issue (actually 2), which I spent ~3 days investigating X( . First of all, I am using this with Python2.7.10 (compiled with VStudio10). I am not using the whole lib, only the xml encode and decode parts (due to Unicodes), all the rest is done by xmlrpclib.py (not the one in the Py27 standard lib, but an older version that I modified: so basically that lib is trying to import functions from this module - thus loading it - , if it can't find it it uses the existing and slow implementation).

  • Problem 1
    The easiest way to reproduce it is:
    Have a TCP server app: a trivial one that simply listens for connections and when one arrives it accepts it. One more request is that to have an event to trigger a clean exit from the server app at some point (either check for keyboard inputs or the existence of a file in the program main loop, or in a separate thread). Now, have a client app that connects to that server app and reads some data. While the client is reading, if the event is triggered in the server (and the server app dies), the client listens forever. My environment was complex (at the begining it was spotted while provisioning Windows - which is an ephemeral environment), the server app is a complex Web server, and in my case the client was an executable running on Linux. So, the client app was simply waiting forever (or til I hit Enter in its console). It turned out that the pyd being loaded triggerred this behavior (I wasn't expecting this since the apps don't even use xmlrpc when communicating).

The problem was that at the module load time WSAStartup is called. Normally at the end its counterpart WSACleanup must be called (this func pair uses refcounts!!!). The usual way of performing cleanup actions at module unload time is to register an exit handler. The problem was that the handler registration func (atexit) changed in Py27 to Py_AtExit, so WSACleanup was no longer called, and when the process exited it only fred up the socket resources without gracefully shuting them down (e.g. notifying the peer).

  • Problem 2
    It is minor and benign (I can't imagine how come it doesn't have a more destuctive effect). rpcError variable althought it was used in functions that expect an exception type:e.g. PyErr_SetFromErrno, was initialized to a string: rpcError = PyString_FromString("xmlrpc.error");. I corrected that too.

Note: This patch is cumulative, so it contains the changes from the previous one, plus the ones that I recently discovered.

I recommend this lib since performance wise it is:
- ~10 times faster when xml encoding then the python implementation
- ~20 - 30 times faster when xml decoding than xmlrpclib.py from Py27 (that uses pyexpat speedup)
- ~130 times faster when decoding than xmlrpclib.py with no speedups

Note: My tests did not include Unicodes (which would slow things down a little bit).