[omniORB-dev] Forking python servants

Moriarty predator777 at gmail.com
Mon Dec 29 18:58:47 GMT 2008


Hi!

There is a big problem in Python, which doesn't allow to use it in
heavy loaded applications as simple, as C++. The problem is GIL.
You can create a simple multi-threaded python servant, but you should
be VERY CAREFUL with any external libraries - every piece of code,
which doesn't release GIL, will hang your servant for a (small) amount
of time.

All python FastCGI implementations solves this problem with fork()
call. The parent creates listening socket, then fork()s. After that,
all childs just accept() on this socket and do they job. It would be
great to be able to do such things with omniORB.

I've made a patch, which allows to fork omniORB(py) servants.

Part 1. Just bind the socket, don't accept().
It's just additional export in python bindings:

@@ -161,6 +161,7 @@
 #include <omnipy.h>
 #include <pyThreadCache.h>
 #include <initialiser.h>
+#include <omniORB4/internal/objectAdapter.h>

 OMNI_USING_NAMESPACE(omni)
@@ -588,6 +595,19 @@ extern "C" {
     return Py_None;
   }

+  static PyObject* omnipy_ORB_bind(PyObject* self, PyObject* args){
+    omniObjAdapter::initialise();
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+
@@ -1028,6 +1048,8 @@ OMNIORB_FOR_EACH_SYS_EXCEPTION(DO_CALL_D
     {(char*)"ensureInit",        omnipy_ensureInit,              METH_VARARGS},

     // Wrappers for functions in CORBA::
+    {(char*)"ORB_bind",          omnipy_ORB_bind,                METH_VARARGS},
--- omniORBpy-3.3.old/python/omniORB/CORBA.py   2006-09-07
19:29:57.000000000 +0400
+++ omniORBpy-3.3.new/python/omniORB/CORBA.py   2008-12-24
14:17:04.000000000 +0300
@@ -550,6 +550,12 @@ class ORB:
         if self.__release:
             self.__release(self)

+    def bind(self):
+        _omnipy.ORB_bind()


It works. Now, servant code looks like this:
    orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
    orb.bind()   # <----

    for x in xrange(10):
        p = os.fork()
        if p == 0:
             #start servant here

    if is_parent:
        #wait to die

Part 2. Solving problems.
But it's not enough. There is a problem in omniORB, in
SocketColection. It uses a process-wide pipes for waking up poll() (on
Unix) calls. Forked children will inherit this pipes, which cause a
problem. My solution is to reinit pipes before starting polling
sockets.

--- omniORB-4.1.1.original/include/omniORB4/giopEndpoint.h
2006-06-22 17:53:49.000000000 +0400
+++ omniORB-4.1.1.new/include/omniORB4/giopEndpoint.h   2008-12-24
19:14:31.000000000 +0300
@@ -330,6 +330,8 @@ public:
   // call the callback function <func> with the <cookie> and the pointer to
   // the connection as the arguments.

+   inline virtual void reinit(){};
+
--- omniORB-4.1.1.original/include/omniORB4/internal/SocketCollection.h
2007-07-31 20:36:50.000000000 +0400
+++ omniORB-4.1.1.new/include/omniORB4/internal/SocketCollection.h
 2008-12-24 19:06:57.000000000 +0300
@@ -402,6 +402,7 @@ class SocketCollection {
 public:

   SocketCollection();
+  void reinitPipes();

   virtual ~SocketCollection();
--- omniORB-4.1.1.original/src/lib/omniORB/orbcore/giopRendezvouser.cc
 2005-11-17 20:03:26.000000000 +0300
+++ omniORB-4.1.1.new/src/lib/omniORB/orbcore/giopRendezvouser.cc
 2008-12-24 19:14:01.000000000 +0300
@@ -84,6 +84,7 @@ giopRendezvouser::execute()
   }

   CORBA::Boolean exit_on_error;
+  pd_endpoint->reinit();

--- omniORB-4.1.1.original/src/lib/omniORB/orbcore/SocketCollection.cc
 2007-07-04 13:13:32.000000000 +0400
+++ omniORB-4.1.1.new/src/lib/omniORB/orbcore/SocketCollection.cc
 2008-12-24 18:46:46.000000000 +0300
@@ -374,6 +374,10 @@ SocketCollection::SocketCollection()
   initPipe(pd_pipe_read, pd_pipe_write);
 }

+void SocketCollection::reinitPipes(){
+  initPipe(pd_pipe_read, pd_pipe_write);
+}
+
 SocketCollection::~SocketCollection()
--- omniORB-4.1.1.original/src/lib/omniORB/orbcore/tcp/tcpEndpoint.h
 2006-04-09 23:52:30.000000000 +0400
+++ omniORB-4.1.1.new/src/lib/omniORB/orbcore/tcp/tcpEndpoint.h
2008-12-24 19:16:55.000000000 +0300
@@ -90,6 +90,7 @@ public:
   giopConnection* AcceptAndMonitor(giopConnection::notifyReadable_t,void*);
   void Poke();
   void Shutdown();
+   inline virtual void reinit() {this->reinitPipes();}

   ~tcpEndpoint();



-- 
With best wishes && regards, Morarenko Kirill



More information about the omniORB-dev mailing list