All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] bitbake server: create common server infrastructure
@ 2013-05-31 11:06 Alex DAMIAN
  2013-05-31 11:06 ` [PATCH 2/4] xmlrpc: fixes for bitbake resident server Alex DAMIAN
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Alex DAMIAN @ 2013-05-31 11:06 UTC (permalink / raw)
  To: bitbake-devel, richard.purdie; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

In an attempt to minimize code duplication, create
clear interfaces, and maximize code reuse through OOP,
bb.server adds base classes for the BitBakeServer,
BitBakeServerConnection and actual server implementations
instructed in particular server types.

These classes document the minimum interfaces that the
derived classes must implement, and provide boilerplate code.

Changes to None, Process and XMLRPC servers as to use
the common server infrastructure.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/server/__init__.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/bb/server/process.py  | 54 +++++++++++---------------
 lib/bb/server/xmlrpc.py   | 64 ++++++++++++-------------------
 3 files changed, 142 insertions(+), 72 deletions(-)

diff --git a/lib/bb/server/__init__.py b/lib/bb/server/__init__.py
index e69de29..2e1c619 100644
--- a/lib/bb/server/__init__.py
+++ b/lib/bb/server/__init__.py
@@ -0,0 +1,96 @@
+#
+# BitBake Base Server Code
+#
+# Copyright (C) 2006 - 2007  Michael 'Mickey' Lauer
+# Copyright (C) 2006 - 2008  Richard Purdie
+# Copyright (C) 2013         Alexandru Damian
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+""" Base code for Bitbake server process
+
+Have a common base for that all Bitbake server classes ensures a consistent
+approach to the interface, and minimize risks associated with code duplication.
+
+"""
+
+"""  BaseImplServer() the base class for all XXServer() implementations.
+
+    These classes contain the actual code that runs the server side, i.e.
+    listens for the commands and executes them. Although these implementations
+    contain all the data of the original bitbake command, i.e the cooker instance,
+    they may well run on a different process or even machine.
+
+"""
+
+class BaseImplServer():
+    def __init__(self):
+        self._idlefuns = {}
+
+    def addcooker(self, cooker):
+        self.cooker = cooker
+
+    def register_idle_function(self, function, data):
+        """Register a function to be called while the server is idle"""
+        assert hasattr(function, '__call__')
+        self._idlefuns[function] = data
+
+
+
+""" BitBakeBaseServerConnection class is the common ancestor to all
+    BitBakeServerConnection classes.
+
+    These classes control the remote server. The only command currently
+    implemented is the terminate() command.
+
+"""
+
+class BitBakeBaseServerConnection():
+    def __init__(self, serverImpl):
+        pass
+
+    def terminate(self):
+        pass
+
+
+""" BitBakeBaseServer class is the common ancestor to all Bitbake servers
+
+    Derive this class in order to implement a BitBakeServer which is the
+    controlling stub for the actual server implementation
+
+"""
+class BitBakeBaseServer(object):
+    def initServer(self):
+        self.serverImpl = None  # we ensure a runtime crash if not overloaded
+        self.connection = None
+        return
+
+    def addcooker(self, cooker):
+        self.cooker = cooker
+        self.serverImpl.addcooker(cooker)
+
+    def getServerIdleCB(self):
+        return self.serverImpl.register_idle_function
+
+    def saveConnectionDetails(self):
+        return
+
+    def detach(self):
+        return
+
+    def establishConnection(self):
+        raise   "Must redefine the %s.establishConnection()" % self.__class__.__name__
+
+    def endSession(self):
+        self.connection.terminate()
diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
index 163dbbb..900c377 100644
--- a/lib/bb/server/process.py
+++ b/lib/bb/server/process.py
@@ -32,6 +32,8 @@ import time
 from Queue import Empty
 from multiprocessing import Event, Process, util, Queue, Pipe, queues
 
+from . import BitBakeBaseServer, BitBakeBaseServerConnection, BaseImplServer
+
 logger = logging.getLogger('BitBake')
 
 class ServerCommunicator():
@@ -68,26 +70,21 @@ class EventAdapter():
             print("EventAdapter puked: %s" % str(err))
 
 
-class ProcessServer(Process):
+class ProcessServer(Process, BaseImplServer):
     profile_filename = "profile.log"
     profile_processed_filename = "profile.log.processed"
 
     def __init__(self, command_channel, event_queue):
+        BaseImplServer.__init__(self)
         Process.__init__(self)
         self.command_channel = command_channel
         self.event_queue = event_queue
         self.event = EventAdapter(event_queue)
-        self._idlefunctions = {}
         self.quit = False
 
         self.keep_running = Event()
         self.keep_running.set()
 
-    def register_idle_function(self, function, data):
-        """Register a function to be called while the server is idle"""
-        assert hasattr(function, '__call__')
-        self._idlefunctions[function] = data
-
     def run(self):
         for event in bb.event.ui_queue:
             self.event_queue.put(event)
@@ -117,11 +114,11 @@ class ProcessServer(Process):
     def idle_commands(self, delay):
         nextsleep = delay
 
-        for function, data in self._idlefunctions.items():
+        for function, data in self._idlefuns.items():
             try:
                 retval = function(self, data, False)
                 if retval is False:
-                    del self._idlefunctions[function]
+                    del self._idlefuns[function]
                 elif retval is True:
                     nextsleep = None
                 elif nextsleep is None:
@@ -191,12 +188,13 @@ class ProcessServer(Process):
     if (2, 6, 0) <= sys.version_info < (2, 6, 3):
         _bootstrap = bootstrap_2_6_6
 
-class BitBakeServerConnection():
-    def __init__(self, server):
-        self.server = server
-        self.procserver = server.server
-        self.connection = ServerCommunicator(server.ui_channel)
-        self.events = server.event_queue
+class BitBakeProcessServerConnection(BitBakeBaseServerConnection):
+    def __init__(self, serverImpl, ui_channel, event_queue):
+        self.procserver = serverImpl
+        self.ui_channel = ui_channel
+        self.event_queue = event_queue
+        self.connection = ServerCommunicator(self.ui_channel)
+        self.events = self.event_queue
 
     def terminate(self, force = False):
         signal.signal(signal.SIGINT, signal.SIG_IGN)
@@ -210,13 +208,14 @@ class BitBakeServerConnection():
             self.procserver.join()
         while True:
             try:
-                event = self.server.event_queue.get(block=False)
+                event = self.event_queue.get(block=False)
             except (Empty, IOError):
                 break
             if isinstance(event, logging.LogRecord):
                 logger.handle(event)
-        self.server.ui_channel.close()
-        self.server.event_queue.close()
+        # TODO: adamian: figure out who should actually cleanup these resources
+        self.ui_channel.close()
+        self.event_queue.close()
         if force:
             sys.exit(1)
 
@@ -235,7 +234,7 @@ class ProcessEventQueue(multiprocessing.queues.Queue):
             return None
 
 
-class BitBakeServer(object):
+class BitBakeServer(BitBakeBaseServer):
     def initServer(self):
         # establish communication channels.  We use bidirectional pipes for
         # ui <--> server command/response pairs
@@ -243,24 +242,13 @@ class BitBakeServer(object):
         #
         self.ui_channel, self.server_channel = Pipe()
         self.event_queue = ProcessEventQueue(0)
-
-        self.server = ProcessServer(self.server_channel, self.event_queue)
-
-    def addcooker(self, cooker):
-        self.cooker = cooker
-        self.server.cooker = cooker
-
-    def getServerIdleCB(self):
-        return self.server.register_idle_function
-
-    def saveConnectionDetails(self):
-        return
+        self.serverImpl = ProcessServer(self.server_channel, self.event_queue)
 
     def detach(self):
-        self.server.start() 
+        self.serverImpl.start()
         return
 
     def establishConnection(self):
-        self.connection = BitBakeServerConnection(self)
+        self.connection = BitBakeProcessServerConnection(self.serverImpl, self.ui_channel, self.event_queue)
         signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True))
         return self.connection
diff --git a/lib/bb/server/xmlrpc.py b/lib/bb/server/xmlrpc.py
index 56a643c..2747ed8 100644
--- a/lib/bb/server/xmlrpc.py
+++ b/lib/bb/server/xmlrpc.py
@@ -49,6 +49,8 @@ DEBUG = False
 from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
 import inspect, select
 
+from . import BitBakeBaseServer, BitBakeBaseServerConnection, BaseImplServer
+
 if sys.hexversion < 0x020600F0:
     print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode")
     sys.exit(1)
@@ -286,7 +288,6 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
         """
         Register a remote UI Event Handler
         """
-        print "registering handler %s:%s" % (host,port) 
         connection = xmlrpclib.ServerProxy("http://%s:%d/" % (host, port), allow_none=True)
         client_hash = "%s:%d" % (host, port)
         if self.clients.has_key(client_hash):
@@ -301,7 +302,6 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
         """
         Unregister a remote UI Event Handler
         """
-        print "unregistering handler %s:%s" % (host,port)
         client_thread = self.clients[client_hash]
         if client_thread:
             bb.event.unregister_UIHhandler(self.clients_ui_ids[client_hash])
@@ -323,7 +323,16 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
             self.handle_request()
         self.server_close()
 
-class BitBakeXMLRPCServer(SimpleXMLRPCServer):
+
+class XMLRPCProxyServer(BaseImplServer):
+    """ not a real working server, but a stub for a proxy server connection
+
+    """
+    def __init__(self, host, port):
+        self.host = host
+        self.port = port
+
+class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
     # remove this when you're done with debugging
     # allow_reuse_address = True
 
@@ -331,10 +340,10 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
         """
         Constructor
         """
+        BaseImplServer.__init__(self)
         SimpleXMLRPCServer.__init__(self, interface,
                                     requestHandler=BitBakeXMLRPCRequestHandler,
                                     logRequests=False, allow_none=True)
-        self._idlefuns = {}
         self.host, self.port = self.socket.getsockname()
         self.connection_token = None
         #self.register_introspection_functions()
@@ -343,7 +352,7 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
         self.interface = interface
 
     def addcooker(self, cooker):
-        self.cooker = cooker
+        BaseImplServer.addcooker(self, cooker)
         self.commands.cooker = cooker
 
     def autoregister_all_functions(self, context, prefix):
@@ -356,10 +365,6 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
             if name.startswith(prefix):
                 self.register_function(method, name[len(prefix):])
 
-    def register_idle_function(self, function, data):
-        """Register a function to be called while the server is idle"""
-        assert hasattr(function, '__call__')
-        self._idlefuns[function] = data
 
     def serve_forever(self):
         # Create and run the event server controller in a separate thread
@@ -420,16 +425,11 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
     def set_connection_token(self, token):
         self.connection_token = token
 
-class BitbakeServerInfo():
-    def __init__(self, host, port):
-        self.host = host
-        self.port = port
-
-class BitBakeServerConnection():
-    def __init__(self, serverinfo, clientinfo=("localhost", 0)):
-        self.connection, self.transport = _create_server(serverinfo.host, serverinfo.port)
+class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
+    def __init__(self, serverImpl, clientinfo=("localhost", 0)):
+        self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port)
         self.clientinfo = clientinfo
-        self.serverinfo = serverinfo
+        self.serverImpl = serverImpl
 
     def connect(self):
         token = self.connection.addClient()
@@ -457,36 +457,22 @@ class BitBakeServerConnection():
         except:
             pass
 
-class BitBakeServer(object):
+class BitBakeServer(BitBakeBaseServer):
     def initServer(self, interface = ("localhost", 0)):
-        self.server = BitBakeXMLRPCServer(interface)
-
-    def addcooker(self, cooker):
-        self.cooker = cooker
-        self.server.addcooker(cooker)
-
-    def getServerIdleCB(self):
-        return self.server.register_idle_function
-
-    def saveConnectionDetails(self):
-        self.serverinfo = BitbakeServerInfo(self.server.host, self.server.port)
+        self.serverImpl = XMLRPCServer(interface)
 
     def detach(self):
-        daemonize.createDaemon(self.server.serve_forever, "bitbake-cookerdaemon.log")
+        daemonize.createDaemon(self.serverImpl.serve_forever, "bitbake-cookerdaemon.log")
         del self.cooker
-        del self.server
 
     def establishConnection(self):
-        self.connection = BitBakeServerConnection(self.serverinfo)
+        self.connection = BitBakeXMLRPCServerConnection(self.serverImpl)
         return self.connection.connect()
 
     def set_connection_token(self, token):
         self.connection.transport.set_connection_token(token)
 
-    def endSession(self):
-        self.connection.terminate()
-
-class BitBakeXMLRPCClient(object):
+class BitBakeXMLRPCClient(BitBakeBaseServer):
 
     def __init__(self):
         pass
@@ -510,8 +496,8 @@ class BitBakeXMLRPCClient(object):
             s.close()
         except:
             return None
-        self.serverinfo = BitbakeServerInfo(host, port)
-        self.connection = BitBakeServerConnection(self.serverinfo, (ip, 0))
+        self.serverImpl = XMLRPCProxyServer(host, port)
+        self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0))
         return self.connection.connect()
 
     def endSession(self):
-- 
1.8.1.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] xmlrpc: fixes for bitbake resident server
  2013-05-31 11:06 [PATCH 1/4] bitbake server: create common server infrastructure Alex DAMIAN
@ 2013-05-31 11:06 ` Alex DAMIAN
  2013-05-31 11:06 ` [PATCH 3/4] bitbake: fixes in executable Alex DAMIAN
  2013-05-31 11:06 ` [PATCH 4/4] xmlrpc: add support for event-observer-only connection Alex DAMIAN
  2 siblings, 0 replies; 7+ messages in thread
From: Alex DAMIAN @ 2013-05-31 11:06 UTC (permalink / raw)
  To: bitbake-devel, richard.purdie; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

This patch enables the XMLRPC server to remain
resident in memory after a task is run, and to accept
a new controlling client. To check the server after
task completion, do

lsof bitbake.lock

in the build directory. Kill the server with kill.

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 lib/bb/server/xmlrpc.py | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/lib/bb/server/xmlrpc.py b/lib/bb/server/xmlrpc.py
index 2747ed8..0b51ebd 100644
--- a/lib/bb/server/xmlrpc.py
+++ b/lib/bb/server/xmlrpc.py
@@ -227,7 +227,6 @@ class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
         self.end_headers()
         self.wfile.write(response)
 
-
 class BitBakeUIEventServer(threading.Thread):
     class EventAdapter():
         """
@@ -273,9 +272,10 @@ class BitBakeUIEventServer(threading.Thread):
             if evt:
                 self.connection.event.sendpickle(pickle.dumps(evt))
 
-class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
+class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer, threading.Thread):
     def __init__(self, interface):
         SimpleXMLRPCServer.__init__(self, interface, logRequests=False, allow_none=True)
+        threading.Thread.__init__(self)
         self.register_function(self.registerEventHandler, "registerEventHandler")
         self.register_function(self.unregisterEventHandler, "unregisterEventHandler")
         self.register_function(self.terminateServer, "terminateServer")
@@ -283,6 +283,7 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
         self.quit = False
         self.clients = {}
         self.client_ui_ids = {}
+        self.timeout = 1    # timeout for .handle_request()
 
     def registerEventHandler(self, host, port):
         """
@@ -317,13 +318,14 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
     def runCommand(self, cmd):
         return None
 
-    def serve_forever(self, main_server):
-        self.main_server = main_server
+    def run(self):
+        self.serve_forever()
+
+    def serve_forever(self):
         while not self.quit:
             self.handle_request()
         self.server_close()
 
-
 class XMLRPCProxyServer(BaseImplServer):
     """ not a real working server, but a stub for a proxy server connection
 
@@ -368,15 +370,11 @@ class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
 
     def serve_forever(self):
         # Create and run the event server controller in a separate thread
-        evt_server_ctrl = BitBakeXMLRPCEventServerController((self.host, self.port + 2))
-        self.event_controller_thread = threading.Thread(target = evt_server_ctrl.serve_forever, args = (self,))
+        self.event_controller_thread = BitBakeXMLRPCEventServerController((self.host, self.port + 2))
         self.event_controller_thread.start()
         # Start the actual XMLRPC server
         bb.cooker.server_main(self.cooker, self._serve_forever)
 
-    def removeClient(self):
-        self.commands.removeClient()
-
     def _serve_forever(self):
         """
         Serve Requests. Overloaded to honor a quit command
@@ -453,7 +451,7 @@ class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
         except:
             pass
         try:
-            self.connection.terminateServer()
+            self.connection.removeClient()
         except:
             pass
 
-- 
1.8.1.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] bitbake: fixes in executable
  2013-05-31 11:06 [PATCH 1/4] bitbake server: create common server infrastructure Alex DAMIAN
  2013-05-31 11:06 ` [PATCH 2/4] xmlrpc: fixes for bitbake resident server Alex DAMIAN
@ 2013-05-31 11:06 ` Alex DAMIAN
  2013-06-05 20:51   ` Bernhard Reutner-Fischer
  2013-05-31 11:06 ` [PATCH 4/4] xmlrpc: add support for event-observer-only connection Alex DAMIAN
  2 siblings, 1 reply; 7+ messages in thread
From: Alex DAMIAN @ 2013-05-31 11:06 UTC (permalink / raw)
  To: bitbake-devel, richard.purdie; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

Two fixes in bitbake related to running remote servers -
* can now specify correctly the bind port
* the information in print conforms to common server infrastructure

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 bin/bitbake | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/bin/bitbake b/bin/bitbake
index f3bbeb4..d263cbd 100755
--- a/bin/bitbake
+++ b/bin/bitbake
@@ -204,7 +204,8 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
 def start_server(servermodule, configParams, configuration):
     server = servermodule.BitBakeServer()
     if configParams.bind:
-        server.initServer((configParams.bind, 0))
+        (host, port) = configParams.bind.split(':')
+        server.initServer((host, int(port)))
     else:
         server.initServer()
 
@@ -313,7 +314,7 @@ def main():
             bb.event.ui_queue = []
             server_connection.terminate()
     else:
-        print("server address: %s, server port: %s" % (server.serverinfo.host, server.serverinfo.port))
+        print("server address: %s, server port: %s" % (server.serverImpl.host, server.serverImpl.port))
 
     return 1
 
-- 
1.8.1.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] xmlrpc: add support for event-observer-only connection
  2013-05-31 11:06 [PATCH 1/4] bitbake server: create common server infrastructure Alex DAMIAN
  2013-05-31 11:06 ` [PATCH 2/4] xmlrpc: fixes for bitbake resident server Alex DAMIAN
  2013-05-31 11:06 ` [PATCH 3/4] bitbake: fixes in executable Alex DAMIAN
@ 2013-05-31 11:06 ` Alex DAMIAN
  2013-06-06 12:58   ` Richard Purdie
  2 siblings, 1 reply; 7+ messages in thread
From: Alex DAMIAN @ 2013-05-31 11:06 UTC (permalink / raw)
  To: bitbake-devel, richard.purdie; +Cc: Alexandru DAMIAN

From: Alexandru DAMIAN <alexandru.damian@intel.com>

This patch adds support for multiple UI clients acting only as event syncs.
Summary of changes:

bitbake: adds support for --observe-only command line parameter

xmlrpc server: create a Observer-only connection type, and small changes
to accomodate new incoming parameters

event queue: add exclusive access to structures for multithreaded
operation; this is needed by accepting new UI handlers on a different thread

knotty: support for observer-only connections

Other minor cosmetic changes to support new parameters to functions were made

Based on original patch by Bogdan Marinescu <bogdan.a.marinescu@intel.com>

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
---
 bin/bitbake             |  8 ++++++-
 lib/bb/event.py         | 63 ++++++++++++++++++++++++++++++++++---------------
 lib/bb/server/xmlrpc.py | 57 +++++++++++++++++++++++++++++++++++++-------
 lib/bb/ui/knotty.py     | 29 +++++++++++++----------
 lib/bb/ui/uievent.py    |  4 ++--
 5 files changed, 119 insertions(+), 42 deletions(-)

diff --git a/bin/bitbake b/bin/bitbake
index d263cbd..ef0c5d8 100755
--- a/bin/bitbake
+++ b/bin/bitbake
@@ -197,6 +197,9 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
         parser.add_option("", "--remote-server", help = "Connect to the specified server",
                    action = "store", dest = "remote_server", default = False)
 
+        parser.add_option("", "--observe-only", help = "Connect to a server as an observing-only client",
+                   action = "store_true", dest = "observe_only", default = False)
+
         options, targets = parser.parse_args(sys.argv)
         return options, targets[1:]
 
@@ -269,6 +272,9 @@ def main():
     if configParams.remote_server and configParams.servertype != "xmlrpc":
         sys.exit("FATAL: If '--remote-server' is defined, we must set the servertype as 'xmlrpc'.\n")
 
+    if configParams.observe_only and (not configParams.remote_server or configParams.bind):
+        sys.exit("FATAL: '--observe-only' can only be used by UI clients connecting to a server.\n")
+
     if "BBDEBUG" in os.environ:
         level = int(os.environ["BBDEBUG"])
         if level > configuration.debug:
@@ -295,7 +301,7 @@ def main():
         server = start_server(servermodule, configParams, configuration)
     else:
         # we start a stub server that is actually a XMLRPClient to
-        server = servermodule.BitBakeXMLRPCClient()
+        server = servermodule.BitBakeXMLRPCClient(configParams.observe_only)
         server.saveConnectionDetails(configParams.remote_server)
 
     logger.removeHandler(handler)
diff --git a/lib/bb/event.py b/lib/bb/event.py
index 2826e35..726d074 100644
--- a/lib/bb/event.py
+++ b/lib/bb/event.py
@@ -33,12 +33,15 @@ import atexit
 import traceback
 import bb.utils
 import bb.compat
+import threading
 
 # This is the pid for which we should generate the event. This is set when
 # the runqueue forks off.
 worker_pid = 0
 worker_pipe = None
 
+_ui_handlers_lock = threading.Lock()
+
 logger = logging.getLogger('BitBake.Event')
 
 class Event(object):
@@ -93,6 +96,8 @@ def fire_class_handlers(event, d):
             continue
 
 ui_queue = []
+_ui_event_history = []
+_ui_event_history_lock = threading.Lock()
 @atexit.register
 def print_ui_queue():
     """If we're exiting before a UI has been spawned, display any queued
@@ -124,22 +129,34 @@ def fire_ui_handlers(event, d):
         # No UI handlers registered yet, queue up the messages
         ui_queue.append(event)
         return
-
+    _ui_event_history_lock.acquire()
+    _ui_event_history.append(event)
+    _ui_event_history_lock.release()
     errors = []
-    for h in _ui_handlers:
-        #print "Sending event %s" % event
-        try:
-             # We use pickle here since it better handles object instances
-             # which xmlrpc's marshaller does not. Events *must* be serializable
-             # by pickle.
-             if hasattr(_ui_handlers[h].event, "sendpickle"):
-                _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
-             else:
-                _ui_handlers[h].event.send(event)
-        except:
-            errors.append(h)
-    for h in errors:
-        del _ui_handlers[h]
+    _ui_handlers_lock.acquire()
+    try:
+        for h in _ui_handlers:
+            #print "Sending event %s" % event
+            try:
+                 # We use pickle here since it better handles object instances
+                 # which xmlrpc's marshaller does not. Events *must* be serializable
+                 # by pickle.
+                 if hasattr(_ui_handlers[h].event, "sendpickle"):
+                    _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
+                 else:
+                    _ui_handlers[h].event.send(event)
+            except:
+                errors.append(h)
+        for h in errors:
+            del _ui_handlers[h]
+    finally:
+        _ui_handlers_lock.release()
+
+def get_event_history():
+    _ui_event_history_lock.acquire()
+    evt_copy = _ui_event_history[:]
+    _ui_event_history_lock.release()
+    return evt_copy
 
 def fire(event, d):
     """Fire off an Event"""
@@ -199,13 +216,21 @@ def remove(name, handler):
     _handlers.pop(name)
 
 def register_UIHhandler(handler):
-    bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
-    _ui_handlers[_ui_handler_seq] = handler
+    _ui_handlers_lock.acquire()
+    try:
+        bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
+        _ui_handlers[_ui_handler_seq] = handler
+    finally:
+        _ui_handlers_lock.release()
     return _ui_handler_seq
 
 def unregister_UIHhandler(handlerNum):
-    if handlerNum in _ui_handlers:
-        del _ui_handlers[handlerNum]
+    _ui_handlers_lock.acquire()
+    try:
+        if handlerNum in _ui_handlers:
+            del _ui_handlers[handlerNum]
+    finally:
+        _ui_handlers_lock.release()
     return
 
 def getName(e):
diff --git a/lib/bb/server/xmlrpc.py b/lib/bb/server/xmlrpc.py
index 0b51ebd..0178bef 100644
--- a/lib/bb/server/xmlrpc.py
+++ b/lib/bb/server/xmlrpc.py
@@ -157,7 +157,7 @@ class BitBakeServerCommands():
         self.server = server
         self.has_client = False
 
-    def registerEventHandler(self, host, port):
+    def registerEventHandler(self, host, port, replay = False):
         """
         Register a remote UI Event Handler
         """
@@ -255,17 +255,25 @@ class BitBakeUIEventServer(threading.Thread):
             self.qlock.release()
             return e
 
-    def __init__(self, connection):
+    def __init__(self, connection, replay):
         self.connection = connection
         self.notify = threading.Event()
         self.event = BitBakeUIEventServer.EventAdapter(self.notify)
         self.quit = False
+        self.replay = replay
         threading.Thread.__init__(self)
 
     def terminateServer(self):
         self.quit = True
 
     def run(self):
+        # First send all events in the event history if requested
+        # by the client
+        if self.replay:
+           event_history = bb.event.get_event_history()
+           for evt in event_history:
+               self.connection.event.sendpickle(pickle.dumps(evt))
+           del event_history
         while not self.quit:
             self.notify.wait(0.1)
             evt = self.event.get()
@@ -278,14 +286,14 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer, threading.Thread):
         threading.Thread.__init__(self)
         self.register_function(self.registerEventHandler, "registerEventHandler")
         self.register_function(self.unregisterEventHandler, "unregisterEventHandler")
-        self.register_function(self.terminateServer, "terminateServer")
+        #self.register_function(self.terminateServer, "terminateServer")
         #self.register_function(self.runCommand, "runCommand")
         self.quit = False
         self.clients = {}
         self.client_ui_ids = {}
         self.timeout = 1    # timeout for .handle_request()
 
-    def registerEventHandler(self, host, port):
+    def registerEventHandler(self, host, port, replay = False):
         """
         Register a remote UI Event Handler
         """
@@ -293,7 +301,7 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer, threading.Thread):
         client_hash = "%s:%d" % (host, port)
         if self.clients.has_key(client_hash):
             return None
-        client_ui_server = BitBakeUIEventServer(connection)
+        client_ui_server = BitBakeUIEventServer(connection, replay)
         self.client_ui_ids[client_hash] = bb.event.register_UIHhandler(client_ui_server)
         client_ui_server.start()
         self.clients[client_hash] = client_ui_server
@@ -423,6 +431,33 @@ class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
     def set_connection_token(self, token):
         self.connection_token = token
 
+
+class BitBakeObserverConnection(BitBakeBaseServerConnection):
+    def __init__(self, serverImpl, clientinfo , replay):
+        self.connection = xmlrpclib.ServerProxy("http://%s:%d/" % (serverImpl.host, serverImpl.port + 2), allow_none=True)
+        self.clientinfo = clientinfo
+        self.replay = replay
+
+    def connect(self):
+        self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo, self.replay)
+        return self
+
+    def removeClient(self):
+        pass
+
+    def terminate(self):
+        # Don't wait for server indefinitely
+        import socket
+        socket.setdefaulttimeout(2)
+        try:
+            self.events.system_quit()
+        except:
+            pass
+        try:
+            self.connection.terminateServer()
+        except:
+            pass
+
 class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
     def __init__(self, serverImpl, clientinfo=("localhost", 0)):
         self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port)
@@ -471,9 +506,12 @@ class BitBakeServer(BitBakeBaseServer):
         self.connection.transport.set_connection_token(token)
 
 class BitBakeXMLRPCClient(BitBakeBaseServer):
+    """ a BitBakeServer controller that just connects to a remote server
 
-    def __init__(self):
-        pass
+    """
+    def __init__(self, observer_only = False, replay = False):
+        self.observer_only = observer_only
+        self.replay = replay
 
     def saveConnectionDetails(self, remote):
         self.remote = remote
@@ -495,7 +533,10 @@ class BitBakeXMLRPCClient(BitBakeBaseServer):
         except:
             return None
         self.serverImpl = XMLRPCProxyServer(host, port)
-        self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0))
+        if self.observer_only:
+            self.connection = BitBakeObserverConnection(self.serverImpl, (ip, 0), self.replay)
+        else:
+            self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0))
         return self.connection.connect()
 
     def endSession(self):
diff --git a/lib/bb/ui/knotty.py b/lib/bb/ui/knotty.py
index 389c3cc..465203f 100644
--- a/lib/bb/ui/knotty.py
+++ b/lib/bb/ui/knotty.py
@@ -216,21 +216,28 @@ class TerminalFilter(object):
             fd = sys.stdin.fileno()
             self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
 
-def main(server, eventHandler, params, tf = TerminalFilter):
-
+def _log_settings_from_server(server):
     # Get values of variables which control our output
     includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
     if error:
         logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
-        return 1
+        raise error
     loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
     if error:
         logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
-        return 1
+        raise error
     consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
     if error:
         logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
-        return 1
+        raise error
+    return includelogs, loglines, consolelogfile
+
+def main(server, eventHandler, params, tf = TerminalFilter):
+
+    if params.observe_only:
+        includelogs, loglines, consolelogfile = None, None, None
+    else:
+        includelogs, loglines, consolelogfile = _log_settings_from_server(server)
 
     if sys.stdin.isatty() and sys.stdout.isatty():
         log_exec_tty = True
@@ -254,7 +261,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
         consolelog.setFormatter(conlogformat)
         logger.addHandler(consolelog)
 
-    try:
+    if not params.observe_only:
         params.updateFromServer(server)
         cmdline = params.parseActions()
         if not cmdline:
@@ -271,9 +278,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
         elif ret != True:
             logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
             return 1
-    except xmlrpclib.Fault as x:
-        logger.error("XMLRPC Fault getting commandline:\n %s" % x)
-        return 1
+
 
     parseprogress = None
     cacheprogress = None
@@ -320,7 +325,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
                 elif event.levelno == format.WARNING:
                     warnings = warnings + 1
                 # For "normal" logging conditions, don't show note logs from tasks
-                # but do show them if the user has changed the default log level to 
+                # but do show them if the user has changed the default log level to
                 # include verbose/debug messages
                 if event.taskpid != 0 and event.levelno <= format.NOTE:
                     continue
@@ -469,12 +474,12 @@ def main(server, eventHandler, params, tf = TerminalFilter):
                 pass
         except KeyboardInterrupt:
             termfilter.clearFooter()
-            if main.shutdown == 1:
+            if not params.observe_only and main.shutdown == 1:
                 print("\nSecond Keyboard Interrupt, stopping...\n")
                 _, error = server.runCommand(["stateStop"])
                 if error:
                     logger.error("Unable to cleanly stop: %s" % error)
-            if main.shutdown == 0:
+            if not params.observe_only and main.shutdown == 0:
                 print("\nKeyboard Interrupt, closing down...\n")
                 interrupted = True
                 _, error = server.runCommand(["stateShutdown"])
diff --git a/lib/bb/ui/uievent.py b/lib/bb/ui/uievent.py
index 0b9a836..53a5f63 100644
--- a/lib/bb/ui/uievent.py
+++ b/lib/bb/ui/uievent.py
@@ -28,7 +28,7 @@ import socket, threading, pickle
 from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
 
 class BBUIEventQueue:
-    def __init__(self, BBServer, clientinfo=("localhost, 0")):
+    def __init__(self, BBServer, clientinfo=("localhost, 0"), replay = False):
 
         self.eventQueue = []
         self.eventQueueLock = threading.Lock()
@@ -44,7 +44,7 @@ class BBUIEventQueue:
         server.register_function( self.send_event, "event.sendpickle" )
         server.socket.settimeout(1)
 
-        self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port)
+        self.EventHandle = self.BBServer.registerEventHandler(self.host, self.port, replay)
 
         self.server = server
 
-- 
1.8.1.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/4] bitbake: fixes in executable
  2013-05-31 11:06 ` [PATCH 3/4] bitbake: fixes in executable Alex DAMIAN
@ 2013-06-05 20:51   ` Bernhard Reutner-Fischer
  2013-06-07 14:49     ` Damian, Alexandru
  0 siblings, 1 reply; 7+ messages in thread
From: Bernhard Reutner-Fischer @ 2013-06-05 20:51 UTC (permalink / raw)
  To: Alex DAMIAN; +Cc: bitbake-devel

On 31 May 2013 13:06, Alex DAMIAN <alexandru.damian@intel.com> wrote:
> From: Alexandru DAMIAN <alexandru.damian@intel.com>
>
> Two fixes in bitbake related to running remote servers -
> * can now specify correctly the bind port
> * the information in print conforms to common server infrastructure
>
> Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
> ---
>  bin/bitbake | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/bin/bitbake b/bin/bitbake
> index f3bbeb4..d263cbd 100755
> --- a/bin/bitbake
> +++ b/bin/bitbake
> @@ -204,7 +204,8 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
>  def start_server(servermodule, configParams, configuration):
>      server = servermodule.BitBakeServer()
>      if configParams.bind:
> -        server.initServer((configParams.bind, 0))
> +        (host, port) = configParams.bind.split(':')

[::]:1025

I.e. Does that work nicely on my v6-only box or did you mean .rsplit(':',2) ?
thanks,
> +        server.initServer((host, int(port)))
>      else:
>          server.initServer()
>
> @@ -313,7 +314,7 @@ def main():
>              bb.event.ui_queue = []
>              server_connection.terminate()
>      else:
> -        print("server address: %s, server port: %s" % (server.serverinfo.host, server.serverinfo.port))
> +        print("server address: %s, server port: %s" % (server.serverImpl.host, server.serverImpl.port))
>
>      return 1
>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 4/4] xmlrpc: add support for event-observer-only connection
  2013-05-31 11:06 ` [PATCH 4/4] xmlrpc: add support for event-observer-only connection Alex DAMIAN
@ 2013-06-06 12:58   ` Richard Purdie
  0 siblings, 0 replies; 7+ messages in thread
From: Richard Purdie @ 2013-06-06 12:58 UTC (permalink / raw)
  To: Alex DAMIAN; +Cc: bitbake-devel

On Fri, 2013-05-31 at 12:06 +0100, Alex DAMIAN wrote:
> From: Alexandru DAMIAN <alexandru.damian@intel.com>
> 
> This patch adds support for multiple UI clients acting only as event syncs.
> Summary of changes:
> 
> bitbake: adds support for --observe-only command line parameter
> 
> xmlrpc server: create a Observer-only connection type, and small changes
> to accomodate new incoming parameters
> 
> event queue: add exclusive access to structures for multithreaded
> operation; this is needed by accepting new UI handlers on a different thread
> 
> knotty: support for observer-only connections
> 
> Other minor cosmetic changes to support new parameters to functions were made
> 
> Based on original patch by Bogdan Marinescu <bogdan.a.marinescu@intel.com>
> 
> Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
> ---
>  bin/bitbake             |  8 ++++++-
>  lib/bb/event.py         | 63 ++++++++++++++++++++++++++++++++++---------------
>  lib/bb/server/xmlrpc.py | 57 +++++++++++++++++++++++++++++++++++++-------
>  lib/bb/ui/knotty.py     | 29 +++++++++++++----------
>  lib/bb/ui/uievent.py    |  4 ++--
>  5 files changed, 119 insertions(+), 42 deletions(-)

I merged the other three patches in the series. I was not happy with the
commit message summary as "XXX: fixes for XXX" tells me nothing. In this
case I rewrote them as examples of what looks better but please think
about those a bit more in future.

For this patch I have some concerns.

> diff --git a/bin/bitbake b/bin/bitbake
> index d263cbd..ef0c5d8 100755
> --- a/bin/bitbake
> +++ b/bin/bitbake
> @@ -197,6 +197,9 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
>          parser.add_option("", "--remote-server", help = "Connect to the specified server",
>                     action = "store", dest = "remote_server", default = False)
>  
> +        parser.add_option("", "--observe-only", help = "Connect to a server as an observing-only client",
> +                   action = "store_true", dest = "observe_only", default = False)
> +
>          options, targets = parser.parse_args(sys.argv)
>          return options, targets[1:]
>  
> @@ -269,6 +272,9 @@ def main():
>      if configParams.remote_server and configParams.servertype != "xmlrpc":
>          sys.exit("FATAL: If '--remote-server' is defined, we must set the servertype as 'xmlrpc'.\n")
>  
> +    if configParams.observe_only and (not configParams.remote_server or configParams.bind):
> +        sys.exit("FATAL: '--observe-only' can only be used by UI clients connecting to a server.\n")
> +
>      if "BBDEBUG" in os.environ:
>          level = int(os.environ["BBDEBUG"])
>          if level > configuration.debug:
> @@ -295,7 +301,7 @@ def main():
>          server = start_server(servermodule, configParams, configuration)
>      else:
>          # we start a stub server that is actually a XMLRPClient to
> -        server = servermodule.BitBakeXMLRPCClient()
> +        server = servermodule.BitBakeXMLRPCClient(configParams.observe_only)
>          server.saveConnectionDetails(configParams.remote_server)


Do we really need a commandline option for this or is this something the
UIs can figure out and do for themselves?

>      logger.removeHandler(handler)
> diff --git a/lib/bb/event.py b/lib/bb/event.py
> index 2826e35..726d074 100644
> --- a/lib/bb/event.py
> +++ b/lib/bb/event.py
> @@ -33,12 +33,15 @@ import atexit
>  import traceback
>  import bb.utils
>  import bb.compat
> +import threading

I've already mentioned that mixing mutliprocessing and threading in
bitbake has been known to cause problems. Did you investigate those
issues and do we know this is safe here?

I actually don't even understand why we're locking this. Only the server
process should be able to touching this queue.

>  # This is the pid for which we should generate the event. This is set when
>  # the runqueue forks off.
>  worker_pid = 0
>  worker_pipe = None
>  
> +_ui_handlers_lock = threading.Lock()
> +
>  logger = logging.getLogger('BitBake.Event')
>  
>  class Event(object):
> @@ -93,6 +96,8 @@ def fire_class_handlers(event, d):
>              continue
>  
>  ui_queue = []
> +_ui_event_history = []
> +_ui_event_history_lock = threading.Lock()
>  @atexit.register
>  def print_ui_queue():
>      """If we're exiting before a UI has been spawned, display any queued
> @@ -124,22 +129,34 @@ def fire_ui_handlers(event, d):
>          # No UI handlers registered yet, queue up the messages
>          ui_queue.append(event)
>          return
> -
> +    _ui_event_history_lock.acquire()
> +    _ui_event_history.append(event)
> +    _ui_event_history_lock.release()
>      errors = []
> -    for h in _ui_handlers:
> -        #print "Sending event %s" % event
> -        try:
> -             # We use pickle here since it better handles object instances
> -             # which xmlrpc's marshaller does not. Events *must* be serializable
> -             # by pickle.
> -             if hasattr(_ui_handlers[h].event, "sendpickle"):
> -                _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
> -             else:
> -                _ui_handlers[h].event.send(event)
> -        except:
> -            errors.append(h)
> -    for h in errors:
> -        del _ui_handlers[h]
> +    _ui_handlers_lock.acquire()
> +    try:
> +        for h in _ui_handlers:
> +            #print "Sending event %s" % event
> +            try:
> +                 # We use pickle here since it better handles object instances
> +                 # which xmlrpc's marshaller does not. Events *must* be serializable
> +                 # by pickle.
> +                 if hasattr(_ui_handlers[h].event, "sendpickle"):
> +                    _ui_handlers[h].event.sendpickle((pickle.dumps(event)))
> +                 else:
> +                    _ui_handlers[h].event.send(event)
> +            except:
> +                errors.append(h)
> +        for h in errors:
> +            del _ui_handlers[h]
> +    finally:
> +        _ui_handlers_lock.release()
> +
> +def get_event_history():
> +    _ui_event_history_lock.acquire()
> +    evt_copy = _ui_event_history[:]
> +    _ui_event_history_lock.release()
> +    return evt_copy


I'm afraid I don't like this at all. Why do we need to keep event
history? Surely the UIs are meant to query the server for current state,
not rely on a reply of existing events?

Reading the code I can figure out what you're doing and why and answer
my own questions. The commit message however sucks as it doesn't tell me
any of this. The locking and so on also looks inappropriate and
worrisome.

So this patch needs some further thought/work.

Cheers,

Richard



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/4] bitbake: fixes in executable
  2013-06-05 20:51   ` Bernhard Reutner-Fischer
@ 2013-06-07 14:49     ` Damian, Alexandru
  0 siblings, 0 replies; 7+ messages in thread
From: Damian, Alexandru @ 2013-06-07 14:49 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer; +Cc: bitbake-devel

[-- Attachment #1: Type: text/plain, Size: 1940 bytes --]

  Point taken. Unfortunately, this type of code if all over the place in
BB, so a subsequent patch will have to solve it, once we have testing
environment going on for this.

I'll add this to my list, but it is low priority. Patches welcome, though :)

Alex


On Wed, Jun 5, 2013 at 9:51 PM, Bernhard Reutner-Fischer <
rep.dot.nop@gmail.com> wrote:

> On 31 May 2013 13:06, Alex DAMIAN <alexandru.damian@intel.com> wrote:
> > From: Alexandru DAMIAN <alexandru.damian@intel.com>
> >
> > Two fixes in bitbake related to running remote servers -
> > * can now specify correctly the bind port
> > * the information in print conforms to common server infrastructure
> >
> > Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
> > ---
> >  bin/bitbake | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/bin/bitbake b/bin/bitbake
> > index f3bbeb4..d263cbd 100755
> > --- a/bin/bitbake
> > +++ b/bin/bitbake
> > @@ -204,7 +204,8 @@ class
> BitBakeConfigParameters(cookerdata.ConfigParameters):
> >  def start_server(servermodule, configParams, configuration):
> >      server = servermodule.BitBakeServer()
> >      if configParams.bind:
> > -        server.initServer((configParams.bind, 0))
> > +        (host, port) = configParams.bind.split(':')
>
> [::]:1025
>
> I.e. Does that work nicely on my v6-only box or did you mean
> .rsplit(':',2) ?
> thanks,
> > +        server.initServer((host, int(port)))
> >      else:
> >          server.initServer()
> >
> > @@ -313,7 +314,7 @@ def main():
> >              bb.event.ui_queue = []
> >              server_connection.terminate()
> >      else:
> > -        print("server address: %s, server port: %s" %
> (server.serverinfo.host, server.serverinfo.port))
> > +        print("server address: %s, server port: %s" %
> (server.serverImpl.host, server.serverImpl.port))
> >
> >      return 1
> >
>

[-- Attachment #2: Type: text/html, Size: 2906 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2013-06-07 14:49 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-31 11:06 [PATCH 1/4] bitbake server: create common server infrastructure Alex DAMIAN
2013-05-31 11:06 ` [PATCH 2/4] xmlrpc: fixes for bitbake resident server Alex DAMIAN
2013-05-31 11:06 ` [PATCH 3/4] bitbake: fixes in executable Alex DAMIAN
2013-06-05 20:51   ` Bernhard Reutner-Fischer
2013-06-07 14:49     ` Damian, Alexandru
2013-05-31 11:06 ` [PATCH 4/4] xmlrpc: add support for event-observer-only connection Alex DAMIAN
2013-06-06 12:58   ` Richard Purdie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.