All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/10] build/msg: Cleanup verbose option handling
@ 2020-08-24 16:53 Richard Purdie
  2020-08-24 16:53 ` [PATCH 02/10] cooker/cookerdata/main: Improve loglevel handling Richard Purdie
                   ` (8 more replies)
  0 siblings, 9 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

The levels of indirection to set these verbose logging options is rather
crazy. This attempts to turn things into two specific options with
much more specific meanings. For now its all still controlled by the
commandline verbose option and should funciton as previously, with
the addition that the BB_VERBOSE_LOGS option can now be task specific.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 bin/bitbake-worker   | 4 ++--
 lib/bb/build.py      | 7 +++++--
 lib/bb/cooker.py     | 5 -----
 lib/bb/cookerdata.py | 7 ++++++-
 lib/bb/msg.py        | 6 ------
 lib/bb/runqueue.py   | 4 ++--
 6 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/bin/bitbake-worker b/bin/bitbake-worker
index 97cc0fd60f..9334f11fb8 100755
--- a/bin/bitbake-worker
+++ b/bin/bitbake-worker
@@ -413,9 +413,9 @@ class BitbakeWorker(object):
 
     def handle_workerdata(self, data):
         self.workerdata = pickle.loads(data)
+        bb.build.verboseShellLogging = self.workerdata["build_verbose_shell"]
+        bb.build.verboseStdoutLogging = self.workerdata["build_verbose_stdout"]
         bb.msg.loggerDefaultLogLevel = self.workerdata["logdefaultlevel"]
-        bb.msg.loggerDefaultVerbose = self.workerdata["logdefaultverbose"]
-        bb.msg.loggerVerboseLogs = self.workerdata["logdefaultverboselogs"]
         bb.msg.loggerDefaultDomains = self.workerdata["logdefaultdomain"]
         for mc in self.databuilder.mcdata:
             self.databuilder.mcdata[mc].setVar("PRSERV_HOST", self.workerdata["prhost"])
diff --git a/lib/bb/build.py b/lib/bb/build.py
index 94f9cb371c..974d2ff065 100644
--- a/lib/bb/build.py
+++ b/lib/bb/build.py
@@ -29,6 +29,9 @@ from bb import data, event, utils
 bblogger = logging.getLogger('BitBake')
 logger = logging.getLogger('BitBake.Build')
 
+verboseShellLogging = False
+verboseStdoutLogging = False
+
 __mtime_cache = {}
 
 def cached_mtime_noerror(f):
@@ -413,7 +416,7 @@ def exec_func_shell(func, d, runfile, cwd=None):
 
         bb.data.emit_func(func, script, d)
 
-        if bb.msg.loggerVerboseLogs:
+        if verboseShellLogging or bb.utils.to_boolean(d.getVar("BB_VERBOSE_LOGS", False)):
             script.write("set -x\n")
         if cwd:
             script.write("cd '%s'\n" % cwd)
@@ -433,7 +436,7 @@ exit $ret
         if fakerootcmd:
             cmd = [fakerootcmd, runfile]
 
-    if bb.msg.loggerDefaultVerbose:
+    if verboseStdoutLogging:
         logfile = LogTee(logger, StdoutNoopContextManager())
     else:
         logfile = StdoutNoopContextManager()
diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py
index 33452e7b93..57caf38c2a 100644
--- a/lib/bb/cooker.py
+++ b/lib/bb/cooker.py
@@ -413,11 +413,6 @@ class BBCooker:
             self.data.disableTracking()
 
     def parseConfiguration(self):
-        # Set log file verbosity
-        verboselogs = bb.utils.to_boolean(self.data.getVar("BB_VERBOSE_LOGS", False))
-        if verboselogs:
-            bb.msg.loggerVerboseLogs = True
-
         # Change nice level if we're asked to
         nice = self.data.getVar("BB_NICE_LEVEL")
         if nice:
diff --git a/lib/bb/cookerdata.py b/lib/bb/cookerdata.py
index b86e7d446b..6bf411bcd2 100644
--- a/lib/bb/cookerdata.py
+++ b/lib/bb/cookerdata.py
@@ -58,11 +58,14 @@ class ConfigParameters(object):
     def updateToServer(self, server, environment):
         options = {}
         for o in ["abort", "force", "invalidate_stamp",
-                  "verbose", "debug", "dry_run", "dump_signatures",
+                  "debug", "dry_run", "dump_signatures",
                   "debug_domains", "extra_assume_provided", "profile",
                   "prefile", "postfile", "server_timeout"]:
             options[o] = getattr(self.options, o)
 
+        options['build_verbose_shell'] = self.options.verbose
+        options['build_verbose_stdout'] = self.options.verbose
+
         ret, error = server.runCommand(["updateConfig", options, environment, sys.argv])
         if error:
             raise Exception("Unable to update the server configuration with local parameters: %s" % error)
@@ -125,6 +128,8 @@ class CookerConfiguration(object):
         self.skipsetscene = False
         self.invalidate_stamp = False
         self.dump_signatures = []
+        self.build_verbose_shell = False
+        self.build_verbose_stdout = False
         self.dry_run = False
         self.tracking = False
         self.xmlrpcinterface = []
diff --git a/lib/bb/msg.py b/lib/bb/msg.py
index 2d88c4e72d..1b1a23bb50 100644
--- a/lib/bb/msg.py
+++ b/lib/bb/msg.py
@@ -146,18 +146,12 @@ class LogFilterLTLevel(logging.Filter):
 #
 
 loggerDefaultLogLevel = BBLogFormatter.NOTE
-loggerDefaultVerbose = False
-loggerVerboseLogs = False
 loggerDefaultDomains = {}
 
 def init_msgconfig(verbose, debug, debug_domains=None):
     """
     Set default verbosity and debug levels config the logger
     """
-    bb.msg.loggerDefaultVerbose = verbose
-    if verbose:
-        bb.msg.loggerVerboseLogs = True
-
     if debug:
         bb.msg.loggerDefaultLogLevel = BBLogFormatter.DEBUG - debug + 1
     elif verbose:
diff --git a/lib/bb/runqueue.py b/lib/bb/runqueue.py
index 02a261e30c..6370ce50a1 100644
--- a/lib/bb/runqueue.py
+++ b/lib/bb/runqueue.py
@@ -1263,8 +1263,8 @@ class RunQueue:
             "fakerootnoenv" : self.rqdata.dataCaches[mc].fakerootnoenv,
             "sigdata" : bb.parse.siggen.get_taskdata(),
             "logdefaultlevel" : bb.msg.loggerDefaultLogLevel,
-            "logdefaultverbose" : bb.msg.loggerDefaultVerbose,
-            "logdefaultverboselogs" : bb.msg.loggerVerboseLogs,
+            "build_verbose_shell" : self.cooker.configuration.build_verbose_shell,
+            "build_verbose_stdout" : self.cooker.configuration.build_verbose_stdout,
             "logdefaultdomain" : bb.msg.loggerDefaultDomains,
             "prhost" : self.cooker.prhost,
             "buildname" : self.cfgData.getVar("BUILDNAME"),
-- 
2.25.1


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

* [PATCH 02/10] cooker/cookerdata/main: Improve loglevel handling
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 03/10] cookerdata: Ensure UI options are updated to the server Richard Purdie
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

Rather than passing debug/verbose/debug_domains around, pass the
computed output of these. Ensure that the cooker sets the levels
to match the levels currently set in the UI and generally try and
make it easier to understand what the code is doing.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/cooker.py     |  7 ++++++-
 lib/bb/cookerdata.py | 10 ++++++----
 lib/bb/main.py       |  8 ++++----
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py
index 57caf38c2a..c34de303fb 100644
--- a/lib/bb/cooker.py
+++ b/lib/bb/cooker.py
@@ -446,7 +446,12 @@ class BBCooker:
                 logger.debug(1, "Marking as dirty due to '%s' option change to '%s'" % (o, options[o]))
                 print("Marking as dirty due to '%s' option change to '%s'" % (o, options[o]))
                 clean = False
-            setattr(self.configuration, o, options[o])
+            if hasattr(self.configuration, o):
+                setattr(self.configuration, o, options[o])
+
+        bb.msg.loggerDefaultLogLevel = self.configuration.default_loglevel
+        bb.msg.loggerDefaultDomains = self.configuration.debug_domains
+
         for k in bb.utils.approved_variables():
             if k in environment and k not in self.configuration.env:
                 logger.debug(1, "Updating new environment variable %s to %s" % (k, environment[k]))
diff --git a/lib/bb/cookerdata.py b/lib/bb/cookerdata.py
index 6bf411bcd2..f43610e7f8 100644
--- a/lib/bb/cookerdata.py
+++ b/lib/bb/cookerdata.py
@@ -58,13 +58,15 @@ class ConfigParameters(object):
     def updateToServer(self, server, environment):
         options = {}
         for o in ["abort", "force", "invalidate_stamp",
-                  "debug", "dry_run", "dump_signatures",
-                  "debug_domains", "extra_assume_provided", "profile",
+                  "dry_run", "dump_signatures",
+                  "extra_assume_provided", "profile",
                   "prefile", "postfile", "server_timeout"]:
             options[o] = getattr(self.options, o)
 
         options['build_verbose_shell'] = self.options.verbose
         options['build_verbose_stdout'] = self.options.verbose
+        options['default_loglevel'] = bb.msg.loggerDefaultLogLevel
+        options['debug_domains'] = bb.msg.loggerDefaultDomains
 
         ret, error = server.runCommand(["updateConfig", options, environment, sys.argv])
         if error:
@@ -114,11 +116,11 @@ class CookerConfiguration(object):
     """
 
     def __init__(self):
-        self.debug_domains = []
+        self.debug_domains = bb.msg.loggerDefaultDomains
+        self.default_loglevel = bb.msg.loggerDefaultLogLevel
         self.extra_assume_provided = []
         self.prefile = []
         self.postfile = []
-        self.debug = 0
         self.cmd = None
         self.abort = True
         self.force = False
diff --git a/lib/bb/main.py b/lib/bb/main.py
index af2880f8d5..e483cce1ae 100755
--- a/lib/bb/main.py
+++ b/lib/bb/main.py
@@ -357,11 +357,11 @@ def bitbake_main(configParams, configuration):
 
     if "BBDEBUG" in os.environ:
         level = int(os.environ["BBDEBUG"])
-        if level > configuration.debug:
-            configuration.debug = level
+        if level > configParams.debug:
+            configParams.debug = level
 
-    bb.msg.init_msgconfig(configParams.verbose, configuration.debug,
-                          configuration.debug_domains)
+    bb.msg.init_msgconfig(configParams.verbose, configParams.debug,
+                          configParams.debug_domains)
 
     server_connection, ui_module = setup_bitbake(configParams, configuration)
     # No server connection
-- 
2.25.1


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

* [PATCH 03/10] cookerdata: Ensure UI options are updated to the server
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
  2020-08-24 16:53 ` [PATCH 02/10] cooker/cookerdata/main: Improve loglevel handling Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 04/10] cooker/cookerdata: Ensure UI event log is updated from commandline Richard Purdie
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

There were some options which were not being passed to the server. This
was breaking, particularly in memory resident bitbake mode.

Add the missing options to the correct place to ensure the server is
updated correctly.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/cookerdata.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/bb/cookerdata.py b/lib/bb/cookerdata.py
index f43610e7f8..9eddf7cf6a 100644
--- a/lib/bb/cookerdata.py
+++ b/lib/bb/cookerdata.py
@@ -60,7 +60,9 @@ class ConfigParameters(object):
         for o in ["abort", "force", "invalidate_stamp",
                   "dry_run", "dump_signatures",
                   "extra_assume_provided", "profile",
-                  "prefile", "postfile", "server_timeout"]:
+                  "prefile", "postfile", "server_timeout",
+                  "nosetscene", "setsceneonly", "skipsetscene",
+                  "runall", "runonly"]:
             options[o] = getattr(self.options, o)
 
         options['build_verbose_shell'] = self.options.verbose
-- 
2.25.1


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

* [PATCH 04/10] cooker/cookerdata: Ensure UI event log is updated from commandline
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
  2020-08-24 16:53 ` [PATCH 02/10] cooker/cookerdata/main: Improve loglevel handling Richard Purdie
  2020-08-24 16:53 ` [PATCH 03/10] cookerdata: Ensure UI options are updated to the server Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 05/10] cooker: Defer configuration init to after UI connection Richard Purdie
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

Currently the eventlog is not handled correctly for memory resident
bitbake. Fix this by allowing adpations to configuration changes.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/cooker.py     | 18 +++++++++++-------
 lib/bb/cookerdata.py |  2 +-
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py
index c34de303fb..3f351cbea6 100644
--- a/lib/bb/cooker.py
+++ b/lib/bb/cooker.py
@@ -150,6 +150,7 @@ class BBCooker:
 
     def __init__(self, configuration, featureSet=None, idleCallBackRegister=None):
         self.recipecaches = None
+        self.eventlog = None
         self.skiplist = {}
         self.featureset = CookerFeatures()
         if featureSet:
@@ -199,13 +200,6 @@ class BBCooker:
         bb.debug(1, "BBCooker parsed base configuration %s" % time.time())
         sys.stdout.flush()
 
-        # we log all events to a file if so directed
-        if self.configuration.writeeventlog:
-            # register the log file writer as UI Handler
-            writer = EventWriter(self, self.configuration.writeeventlog)
-            EventLogWriteHandler = namedtuple('EventLogWriteHandler', ['event'])
-            bb.event.register_UIHhandler(EventLogWriteHandler(writer))
-
         self.inotify_modified_files = []
 
         def _process_inotify_updates(server, cooker, abort):
@@ -449,6 +443,16 @@ class BBCooker:
             if hasattr(self.configuration, o):
                 setattr(self.configuration, o, options[o])
 
+        if self.configuration.writeeventlog:
+            if self.eventlog and self.eventlog[0] != self.configuration.writeeventlog:
+                bb.event.unregister_UIHhandler(self.eventlog[1])
+            if not self.eventlog or self.eventlog[0] != self.configuration.writeeventlog:
+                # we log all events to a file if so directed
+                # register the log file writer as UI Handler
+                writer = EventWriter(self, self.configuration.writeeventlog)
+                EventLogWriteHandler = namedtuple('EventLogWriteHandler', ['event'])
+                self.eventlog = (self.configuration.writeeventlog, bb.event.register_UIHhandler(EventLogWriteHandler(writer)))
+
         bb.msg.loggerDefaultLogLevel = self.configuration.default_loglevel
         bb.msg.loggerDefaultDomains = self.configuration.debug_domains
 
diff --git a/lib/bb/cookerdata.py b/lib/bb/cookerdata.py
index 9eddf7cf6a..3baa9ade1b 100644
--- a/lib/bb/cookerdata.py
+++ b/lib/bb/cookerdata.py
@@ -62,7 +62,7 @@ class ConfigParameters(object):
                   "extra_assume_provided", "profile",
                   "prefile", "postfile", "server_timeout",
                   "nosetscene", "setsceneonly", "skipsetscene",
-                  "runall", "runonly"]:
+                  "runall", "runonly", "writeeventlog"]:
             options[o] = getattr(self.options, o)
 
         options['build_verbose_shell'] = self.options.verbose
-- 
2.25.1


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

* [PATCH 05/10] cooker: Defer configuration init to after UI connection
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
                   ` (2 preceding siblings ...)
  2020-08-24 16:53 ` [PATCH 04/10] cooker/cookerdata: Ensure UI event log is updated from commandline Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 06/10] server/process: Move the socket code to server process only Richard Purdie
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

Currently we end up parsing the base configuration multiple times as
initially, the right settings haven't come from the UI. We can defer
this until later in startup using runCommand as a trigger.

The advantage to doing this is improved startup times and ultimately
we should be able to avoid the double parse of the base configuration.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/command.py        |  9 ++++++++-
 lib/bb/cooker.py         | 17 ++++++++---------
 lib/bb/server/process.py | 38 +++++++++++++++++++++-----------------
 3 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/lib/bb/command.py b/lib/bb/command.py
index 4d152ff4c0..d4dcc653a0 100644
--- a/lib/bb/command.py
+++ b/lib/bb/command.py
@@ -54,13 +54,20 @@ class Command:
         self.cooker = cooker
         self.cmds_sync = CommandsSync()
         self.cmds_async = CommandsAsync()
-        self.remotedatastores = bb.remotedata.RemoteDatastores(cooker)
+        self.remotedatastores = None
 
         # FIXME Add lock for this
         self.currentAsyncCommand = None
 
     def runCommand(self, commandline, ro_only = False):
         command = commandline.pop(0)
+
+        # Ensure cooker is ready for commands
+        if command != "updateConfig" and command != "setFeatures":
+            self.cooker.init_configdata()
+            if not self.remotedatastores:
+                self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
+
         if hasattr(CommandsSync, command):
             # Can run synchronous commands straight away
             command_method = getattr(self.cmds_sync, command)
diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py
index 3f351cbea6..3f9cb75434 100644
--- a/lib/bb/cooker.py
+++ b/lib/bb/cooker.py
@@ -195,11 +195,6 @@ class BBCooker:
         self.hashserv = None
         self.hashservaddr = None
 
-        self.initConfigurationData()
-
-        bb.debug(1, "BBCooker parsed base configuration %s" % time.time())
-        sys.stdout.flush()
-
         self.inotify_modified_files = []
 
         def _process_inotify_updates(server, cooker, abort):
@@ -233,6 +228,13 @@ class BBCooker:
         bb.debug(1, "BBCooker startup complete %s" % time.time())
         sys.stdout.flush()
 
+    def init_configdata(self):
+        if not hasattr(self, "data"):
+            self.initConfigurationData()
+            bb.debug(1, "BBCooker parsed base configuration %s" % time.time())
+            sys.stdout.flush()
+            self.handlePRServ()
+
     def process_inotify_updates(self):
         for n in [self.confignotifier, self.notifier]:
             if n.check_events(timeout=0):
@@ -318,7 +320,7 @@ class BBCooker:
         for feature in features:
             self.featureset.setFeature(feature)
         bb.debug(1, "Features set %s (was %s)" % (original_featureset, list(self.featureset)))
-        if (original_featureset != list(self.featureset)) and self.state != state.error:
+        if (original_featureset != list(self.featureset)) and self.state != state.error and hasattr(self, "data"):
             self.reset()
 
     def initConfigurationData(self):
@@ -1658,9 +1660,6 @@ class BBCooker:
         return pkgs_to_build
 
     def pre_serve(self):
-        # We now are in our own process so we can call this here.
-        # PRServ exits if its parent process exits
-        self.handlePRServ()
         return
 
     def post_serve(self):
diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
index 65e1eab527..b037e0fb6c 100644
--- a/lib/bb/server/process.py
+++ b/lib/bb/server/process.py
@@ -58,6 +58,7 @@ class ProcessServer():
         self.sockname = sockname
 
         self.server_timeout = server_timeout
+        self.timeout = self.server_timeout
         self.xmlrpcinterface = xmlrpcinterface
 
     def register_idle_function(self, function, data):
@@ -72,21 +73,6 @@ class ProcessServer():
 
             print("Bitbake XMLRPC server address: %s, server port: %s" % (self.xmlrpc.host, self.xmlrpc.port))
 
-        heartbeat_event = self.cooker.data.getVar('BB_HEARTBEAT_EVENT')
-        if heartbeat_event:
-            try:
-                self.heartbeat_seconds = float(heartbeat_event)
-            except:
-                bb.warn('Ignoring invalid BB_HEARTBEAT_EVENT=%s, must be a float specifying seconds.' % heartbeat_event)
-
-        self.timeout = self.server_timeout or self.cooker.data.getVar('BB_SERVER_TIMEOUT')
-        try:
-            if self.timeout:
-                self.timeout = float(self.timeout)
-        except:
-            bb.warn('Ignoring invalid BB_SERVER_TIMEOUT=%s, must be a float specifying seconds.' % self.timeout)
-
-
         try:
             self.bitbake_lock.seek(0)
             self.bitbake_lock.truncate()
@@ -129,6 +115,7 @@ class ProcessServer():
         fds = [self.sock]
         if self.xmlrpc:
             fds.append(self.xmlrpc)
+        seendata = False
         print("Entering server connection loop")
 
         def disconnect_client(self, fds):
@@ -228,6 +215,22 @@ class ProcessServer():
             if self.xmlrpc in ready:
                 self.xmlrpc.handle_requests()
 
+            if not seendata and hasattr(self.cooker, "data"):
+                heartbeat_event = self.cooker.data.getVar('BB_HEARTBEAT_EVENT')
+                if heartbeat_event:
+                    try:
+                        self.heartbeat_seconds = float(heartbeat_event)
+                    except:
+                        bb.warn('Ignoring invalid BB_HEARTBEAT_EVENT=%s, must be a float specifying seconds.' % heartbeat_event)
+
+                self.timeout = self.server_timeout or self.cooker.data.getVar('BB_SERVER_TIMEOUT')
+                try:
+                    if self.timeout:
+                        self.timeout = float(self.timeout)
+                except:
+                    bb.warn('Ignoring invalid BB_SERVER_TIMEOUT=%s, must be a float specifying seconds.' % self.timeout)
+                seendata = True
+
             ready = self.idle_commands(.1, fds)
 
         print("Exiting")
@@ -323,8 +326,9 @@ class ProcessServer():
             self.next_heartbeat += self.heartbeat_seconds
             if self.next_heartbeat <= now:
                 self.next_heartbeat = now + self.heartbeat_seconds
-            heartbeat = bb.event.HeartbeatEvent(now)
-            bb.event.fire(heartbeat, self.cooker.data)
+            if hasattr(self.cooker, "data"):
+                heartbeat = bb.event.HeartbeatEvent(now)
+                bb.event.fire(heartbeat, self.cooker.data)
         if nextsleep and now + nextsleep > self.next_heartbeat:
             # Shorten timeout so that we we wake up in time for
             # the heartbeat.
-- 
2.25.1


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

* [PATCH 06/10] server/process: Move the socket code to server process only
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
                   ` (3 preceding siblings ...)
  2020-08-24 16:53 ` [PATCH 05/10] cooker: Defer configuration init to after UI connection Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 07/10] main/server/process: Drop configuration object passing Richard Purdie
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

The sock object isn't used client side so we can just created it in
the server process and save passing around the fd/object.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/server/process.py | 32 +++++++++++++++-----------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
index b037e0fb6c..8f5abb32bf 100644
--- a/lib/bb/server/process.py
+++ b/lib/bb/server/process.py
@@ -402,27 +402,11 @@ class BitBakeServer(object):
         self.bitbake_lock = lock
         self.readypipe, self.readypipein = os.pipe()
 
-        # Create server control socket
-        if os.path.exists(sockname):
-            os.unlink(sockname)
-
         # Place the log in the builddirectory alongside the lock file
         logfile = os.path.join(os.path.dirname(self.bitbake_lock.name), "bitbake-cookerdaemon.log")
 
-        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        # AF_UNIX has path length issues so chdir here to workaround
-        cwd = os.getcwd()
-        try:
-            os.chdir(os.path.dirname(sockname))
-            self.sock.bind(os.path.basename(sockname))
-        finally:
-            os.chdir(cwd)
-        self.sock.listen(1)
-
-        os.set_inheritable(self.sock.fileno(), True)
         startdatetime = datetime.datetime.now()
         bb.daemonize.createDaemon(self._startServer, logfile)
-        self.sock.close()
         self.bitbake_lock.close()
         os.close(self.readypipein)
 
@@ -478,7 +462,21 @@ class BitBakeServer(object):
         sys.stdout.flush()
 
         try:
-            server = ProcessServer(self.bitbake_lock, self.sock, self.sockname, self.configuration.server_timeout, self.configuration.xmlrpcinterface)
+            # Create server control socket
+            if os.path.exists(self.sockname):
+                os.unlink(self.sockname)
+
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            # AF_UNIX has path length issues so chdir here to workaround
+            cwd = os.getcwd()
+            try:
+                os.chdir(os.path.dirname(self.sockname))
+                sock.bind(os.path.basename(self.sockname))
+            finally:
+                os.chdir(cwd)
+            sock.listen(1)
+
+            server = ProcessServer(self.bitbake_lock, sock, self.sockname, self.configuration.server_timeout, self.configuration.xmlrpcinterface)
             os.close(self.readypipe)
             writer = ConnectionWriter(self.readypipein)
             try:
-- 
2.25.1


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

* [PATCH 07/10] main/server/process: Drop configuration object passing
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
                   ` (4 preceding siblings ...)
  2020-08-24 16:53 ` [PATCH 06/10] server/process: Move the socket code to server process only Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 08/10] cooker: Ensure BB_ORIGENV is updated by changes to configuration.env Richard Purdie
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

The first thing the UIs do is update the server config from the UI. We
can just rely upon that and start the server with a standard config,
removing the need to pass the confusing configuration object around
as well as configParams, which contains a similar copy of some of the
data.

This makes memory resident bitbake work the same way as the normal
mode, removing the opportunity for some class of bugs.

The xmlrpcinterface and server_timeout values are passed in at server
startup time now and there no longer a second option in the
configuration which is effective ignored once the server starts.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/cooker.py         |  4 ++--
 lib/bb/cookerdata.py     |  9 ---------
 lib/bb/main.py           | 10 ++++------
 lib/bb/server/process.py |  9 +++++----
 lib/bb/tinfoil.py        |  8 +-------
 5 files changed, 12 insertions(+), 28 deletions(-)

diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py
index 3f9cb75434..99605e5844 100644
--- a/lib/bb/cooker.py
+++ b/lib/bb/cooker.py
@@ -148,7 +148,7 @@ class BBCooker:
     Manages one bitbake build run
     """
 
-    def __init__(self, configuration, featureSet=None, idleCallBackRegister=None):
+    def __init__(self, featureSet=None, idleCallBackRegister=None):
         self.recipecaches = None
         self.eventlog = None
         self.skiplist = {}
@@ -157,7 +157,7 @@ class BBCooker:
             for f in featureSet:
                 self.featureset.setFeature(f)
 
-        self.configuration = configuration
+        self.configuration = bb.cookerdata.CookerConfiguration()
 
         self.idleCallBackRegister = idleCallBackRegister
 
diff --git a/lib/bb/cookerdata.py b/lib/bb/cookerdata.py
index 3baa9ade1b..190ff3ab82 100644
--- a/lib/bb/cookerdata.py
+++ b/lib/bb/cookerdata.py
@@ -136,22 +136,13 @@ class CookerConfiguration(object):
         self.build_verbose_stdout = False
         self.dry_run = False
         self.tracking = False
-        self.xmlrpcinterface = []
-        self.server_timeout = None
         self.writeeventlog = False
-        self.server_only = False
         self.limited_deps = False
         self.runall = []
         self.runonly = []
 
         self.env = {}
 
-    def setConfigParameters(self, parameters):
-        for key in self.__dict__.keys():
-            if key in parameters.options.__dict__:
-                setattr(self, key, parameters.options.__dict__[key])
-        self.env = parameters.environment.copy()
-
     def __getstate__(self):
         state = {}
         for key in self.__dict__.keys():
diff --git a/lib/bb/main.py b/lib/bb/main.py
index e483cce1ae..7990195eac 100755
--- a/lib/bb/main.py
+++ b/lib/bb/main.py
@@ -344,8 +344,6 @@ def bitbake_main(configParams, configuration):
     except:
         pass
 
-    configuration.setConfigParameters(configParams)
-
     if configParams.server_only and configParams.remote_server:
             raise BBMainException("FATAL: The '--server-only' option conflicts with %s.\n" %
                                   ("the BBSERVER environment variable" if "BBSERVER" in os.environ \
@@ -363,7 +361,7 @@ def bitbake_main(configParams, configuration):
     bb.msg.init_msgconfig(configParams.verbose, configParams.debug,
                           configParams.debug_domains)
 
-    server_connection, ui_module = setup_bitbake(configParams, configuration)
+    server_connection, ui_module = setup_bitbake(configParams)
     # No server connection
     if server_connection is None:
         if configParams.status_only:
@@ -390,7 +388,7 @@ def bitbake_main(configParams, configuration):
 
     return 1
 
-def setup_bitbake(configParams, configuration, extrafeatures=None):
+def setup_bitbake(configParams, extrafeatures=None):
     # Ensure logging messages get sent to the UI as events
     handler = bb.event.LogHandler()
     if not configParams.status_only:
@@ -431,11 +429,11 @@ def setup_bitbake(configParams, configuration, extrafeatures=None):
                         logger.info("bitbake server is not running.")
                         lock.close()
                         return None, None
-                    # we start a server with a given configuration
+                    # we start a server with a given featureset
                     logger.info("Starting bitbake server...")
                     # Clear the event queue since we already displayed messages
                     bb.event.ui_queue = []
-                    server = bb.server.process.BitBakeServer(lock, sockname, configuration, featureset)
+                    server = bb.server.process.BitBakeServer(lock, sockname, featureset, configParams.server_timeout, configParams.xmlrpcinterface)
 
                 else:
                     logger.info("Reconnecting to bitbake server...")
diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
index 8f5abb32bf..03cdde04ee 100644
--- a/lib/bb/server/process.py
+++ b/lib/bb/server/process.py
@@ -394,9 +394,10 @@ class BitBakeServer(object):
     start_log_format = '--- Starting bitbake server pid %s at %s ---'
     start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
 
-    def __init__(self, lock, sockname, configuration, featureset):
+    def __init__(self, lock, sockname, featureset, server_timeout, xmlrpcinterface):
 
-        self.configuration = configuration
+        self.server_timeout = server_timeout
+        self.xmlrpcinterface = xmlrpcinterface
         self.featureset = featureset
         self.sockname = sockname
         self.bitbake_lock = lock
@@ -476,11 +477,11 @@ class BitBakeServer(object):
                 os.chdir(cwd)
             sock.listen(1)
 
-            server = ProcessServer(self.bitbake_lock, sock, self.sockname, self.configuration.server_timeout, self.configuration.xmlrpcinterface)
+            server = ProcessServer(self.bitbake_lock, sock, self.sockname, self.server_timeout, self.xmlrpcinterface)
             os.close(self.readypipe)
             writer = ConnectionWriter(self.readypipein)
             try:
-                self.cooker = bb.cooker.BBCooker(self.configuration, self.featureset, server.register_idle_function)
+                self.cooker = bb.cooker.BBCooker(self.featureset, server.register_idle_function)
             except bb.BBHandledException:
                 return None
             writer.send("r")
diff --git a/lib/bb/tinfoil.py b/lib/bb/tinfoil.py
index dccbe0ebb5..e19d9cff04 100644
--- a/lib/bb/tinfoil.py
+++ b/lib/bb/tinfoil.py
@@ -22,7 +22,6 @@ import bb.taskdata
 import bb.utils
 import bb.command
 import bb.remotedata
-from bb.cookerdata import CookerConfiguration
 from bb.main import setup_bitbake, BitBakeConfigParameters
 import bb.fetch2
 
@@ -381,18 +380,13 @@ class Tinfoil:
         if not config_params:
             config_params = TinfoilConfigParameters(config_only=config_only, quiet=quiet)
 
-        cookerconfig = CookerConfiguration()
-        cookerconfig.setConfigParameters(config_params)
-
         if not config_only:
             # Disable local loggers because the UI module is going to set up its own
             for handler in self.localhandlers:
                 self.logger.handlers.remove(handler)
             self.localhandlers = []
 
-        self.server_connection, ui_module = setup_bitbake(config_params,
-                            cookerconfig,
-                            extrafeatures)
+        self.server_connection, ui_module = setup_bitbake(config_params, extrafeatures)
 
         self.ui_module = ui_module
 
-- 
2.25.1


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

* [PATCH 08/10] cooker: Ensure BB_ORIGENV is updated by changes to configuration.env
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
                   ` (5 preceding siblings ...)
  2020-08-24 16:53 ` [PATCH 07/10] main/server/process: Drop configuration object passing Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 09/10] server/process: Log extra threads at exit Richard Purdie
  2020-08-24 16:53 ` [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process Richard Purdie
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

Changes to configuration.env were not updating BB_ORIGENV, fix this.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/cooker.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/bb/cooker.py b/lib/bb/cooker.py
index 99605e5844..754303813b 100644
--- a/lib/bb/cooker.py
+++ b/lib/bb/cooker.py
@@ -458,6 +458,12 @@ class BBCooker:
         bb.msg.loggerDefaultLogLevel = self.configuration.default_loglevel
         bb.msg.loggerDefaultDomains = self.configuration.debug_domains
 
+        if hasattr(self, "data"):
+            origenv = bb.data.init()
+            for k in environment:
+                origenv.setVar(k, environment[k])
+            self.data.setVar("BB_ORIGENV", origenv)
+
         for k in bb.utils.approved_variables():
             if k in environment and k not in self.configuration.env:
                 logger.debug(1, "Updating new environment variable %s to %s" % (k, environment[k]))
-- 
2.25.1


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

* [PATCH 09/10] server/process: Log extra threads at exit
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
                   ` (6 preceding siblings ...)
  2020-08-24 16:53 ` [PATCH 08/10] cooker: Ensure BB_ORIGENV is updated by changes to configuration.env Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-24 16:53 ` [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process Richard Purdie
  8 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

Dump info into the logs if there are extra threads left at process exit
time.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/server/process.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
index 03cdde04ee..915651084e 100644
--- a/lib/bb/server/process.py
+++ b/lib/bb/server/process.py
@@ -233,6 +233,9 @@ class ProcessServer():
 
             ready = self.idle_commands(.1, fds)
 
+        if len(threading.enumerate()) != 1:
+            print("More than one thread left?: " + str(threading.enumerate()))
+
         print("Exiting")
         # Remove the socket file so we don't get any more connections to avoid races
         try:
-- 
2.25.1


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

* [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process
  2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
                   ` (7 preceding siblings ...)
  2020-08-24 16:53 ` [PATCH 09/10] server/process: Log extra threads at exit Richard Purdie
@ 2020-08-24 16:53 ` Richard Purdie
  2020-08-25 16:06   ` [bitbake-devel] " Joshua Watt
  8 siblings, 1 reply; 14+ messages in thread
From: Richard Purdie @ 2020-08-24 16:53 UTC (permalink / raw)
  To: bitbake-devel

Trying to have a new python process forked off an original doesn't work
out well and ends up having race issues. To avoid this, exec() a new
bitbake server process. This starts with a fresh python interpreter
and resolves various atexit and other multiprocessing issues once
and for all.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/server/process.py | 92 +++++++++++++++++++++++-----------------
 1 file changed, 53 insertions(+), 39 deletions(-)

diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
index 915651084e..d248570cd2 100644
--- a/lib/bb/server/process.py
+++ b/lib/bb/server/process.py
@@ -38,7 +38,7 @@ class ProcessServer():
     profile_filename = "profile.log"
     profile_processed_filename = "profile.log.processed"
 
-    def __init__(self, lock, sock, sockname, server_timeout, xmlrpcinterface):
+    def __init__(self, lock, lockname, sock, sockname, server_timeout, xmlrpcinterface):
         self.command_channel = False
         self.command_channel_reply = False
         self.quit = False
@@ -54,6 +54,7 @@ class ProcessServer():
         self._idlefuns = {}
 
         self.bitbake_lock = lock
+        self.bitbake_lock_name = lockname
         self.sock = sock
         self.sockname = sockname
 
@@ -259,7 +260,7 @@ class ProcessServer():
 
         # Finally release the lockfile but warn about other processes holding it open
         lock = self.bitbake_lock
-        lockfile = lock.name
+        lockfile = self.bitbake_lock_name
         lock.close()
         lock = None
 
@@ -393,9 +394,10 @@ class BitBakeProcessServerConnection(object):
         self.connection.recv.close()
         return
 
+start_log_format = '--- Starting bitbake server pid %s at %s ---'
+start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
+
 class BitBakeServer(object):
-    start_log_format = '--- Starting bitbake server pid %s at %s ---'
-    start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
 
     def __init__(self, lock, sockname, featureset, server_timeout, xmlrpcinterface):
 
@@ -429,7 +431,7 @@ class BitBakeServer(object):
             ready.close()
             bb.error("Unable to start bitbake server (%s)" % str(r))
             if os.path.exists(logfile):
-                logstart_re = re.compile(self.start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
+                logstart_re = re.compile(start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
                 started = False
                 lines = []
                 lastlines = []
@@ -441,7 +443,7 @@ class BitBakeServer(object):
                             lastlines.append(line)
                             res = logstart_re.match(line.rstrip())
                             if res:
-                                ldatetime = datetime.datetime.strptime(res.group(2), self.start_log_datetime_format)
+                                ldatetime = datetime.datetime.strptime(res.group(2), start_log_datetime_format)
                                 if ldatetime >= startdatetime:
                                     started = True
                                     lines.append(line)
@@ -462,42 +464,54 @@ class BitBakeServer(object):
         ready.close()
 
     def _startServer(self):
-        print(self.start_log_format % (os.getpid(), datetime.datetime.now().strftime(self.start_log_datetime_format)))
-        sys.stdout.flush()
+        os.close(self.readypipe)
+        os.set_inheritable(self.bitbake_lock.fileno(), True)
+        os.set_inheritable(self.readypipein, True)
+        os.execlp("bitbake-server", "bitbake-server", "decafbad", str(self.bitbake_lock.fileno()), str(self.readypipein), self.bitbake_lock.name, self.sockname,  str(self.server_timeout), str(self.xmlrpcinterface[0]), str(self.xmlrpcinterface[1]))
 
-        try:
-            # Create server control socket
-            if os.path.exists(self.sockname):
-                os.unlink(self.sockname)
+def execServer(lockfd, readypipeinfd, lockname, sockname, server_timeout, xmlrpcinterface):
 
-            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-            # AF_UNIX has path length issues so chdir here to workaround
-            cwd = os.getcwd()
-            try:
-                os.chdir(os.path.dirname(self.sockname))
-                sock.bind(os.path.basename(self.sockname))
-            finally:
-                os.chdir(cwd)
-            sock.listen(1)
-
-            server = ProcessServer(self.bitbake_lock, sock, self.sockname, self.server_timeout, self.xmlrpcinterface)
-            os.close(self.readypipe)
-            writer = ConnectionWriter(self.readypipein)
-            try:
-                self.cooker = bb.cooker.BBCooker(self.featureset, server.register_idle_function)
-            except bb.BBHandledException:
-                return None
-            writer.send("r")
-            writer.close()
-            server.cooker = self.cooker
-            print("Started bitbake server pid %d" % os.getpid())
-            sys.stdout.flush()
-
-            server.run()
+    import bb.cookerdata
+    import bb.cooker
+
+    print(start_log_format % (os.getpid(), datetime.datetime.now().strftime(start_log_datetime_format)))
+    sys.stdout.flush()
+
+    try:
+        bitbake_lock = os.fdopen(lockfd, "w")
+
+        # Create server control socket
+        if os.path.exists(sockname):
+            os.unlink(sockname)
+
+        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        # AF_UNIX has path length issues so chdir here to workaround
+        cwd = os.getcwd()
+        try:
+            os.chdir(os.path.dirname(sockname))
+            sock.bind(os.path.basename(sockname))
         finally:
-            # Flush any ,essages/errors to the logfile before exit
-            sys.stdout.flush()
-            sys.stderr.flush()
+            os.chdir(cwd)
+        sock.listen(1)
+
+        server = ProcessServer(bitbake_lock, lockname, sock, sockname, server_timeout, xmlrpcinterface)
+        writer = ConnectionWriter(readypipeinfd)
+        try:
+            featureset = []
+            cooker = bb.cooker.BBCooker(featureset, server.register_idle_function)
+        except bb.BBHandledException:
+            return None
+        writer.send("r")
+        writer.close()
+        server.cooker = cooker
+        print("Started bitbake server pid %d" % os.getpid())
+        sys.stdout.flush()
+
+        server.run()
+    finally:
+        # Flush any ,essages/errors to the logfile before exit
+        sys.stdout.flush()
+        sys.stderr.flush()
 
 def connectProcessServer(sockname, featureset):
     # Connect to socket
-- 
2.25.1


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

* Re: [bitbake-devel] [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process
  2020-08-24 16:53 ` [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process Richard Purdie
@ 2020-08-25 16:06   ` Joshua Watt
  2020-08-25 17:06     ` Richard Purdie
  0 siblings, 1 reply; 14+ messages in thread
From: Joshua Watt @ 2020-08-25 16:06 UTC (permalink / raw)
  To: Richard Purdie; +Cc: bitbake-devel

On Mon, Aug 24, 2020 at 11:53 AM Richard Purdie
<richard.purdie@linuxfoundation.org> wrote:
>
> Trying to have a new python process forked off an original doesn't work
> out well and ends up having race issues. To avoid this, exec() a new
> bitbake server process. This starts with a fresh python interpreter
> and resolves various atexit and other multiprocessing issues once
> and for all.
>
> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> ---
>  lib/bb/server/process.py | 92 +++++++++++++++++++++++-----------------
>  1 file changed, 53 insertions(+), 39 deletions(-)
>
> diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
> index 915651084e..d248570cd2 100644
> --- a/lib/bb/server/process.py
> +++ b/lib/bb/server/process.py
> @@ -38,7 +38,7 @@ class ProcessServer():
>      profile_filename = "profile.log"
>      profile_processed_filename = "profile.log.processed"
>
> -    def __init__(self, lock, sock, sockname, server_timeout, xmlrpcinterface):
> +    def __init__(self, lock, lockname, sock, sockname, server_timeout, xmlrpcinterface):
>          self.command_channel = False
>          self.command_channel_reply = False
>          self.quit = False
> @@ -54,6 +54,7 @@ class ProcessServer():
>          self._idlefuns = {}
>
>          self.bitbake_lock = lock
> +        self.bitbake_lock_name = lockname
>          self.sock = sock
>          self.sockname = sockname
>
> @@ -259,7 +260,7 @@ class ProcessServer():
>
>          # Finally release the lockfile but warn about other processes holding it open
>          lock = self.bitbake_lock
> -        lockfile = lock.name
> +        lockfile = self.bitbake_lock_name
>          lock.close()
>          lock = None
>
> @@ -393,9 +394,10 @@ class BitBakeProcessServerConnection(object):
>          self.connection.recv.close()
>          return
>
> +start_log_format = '--- Starting bitbake server pid %s at %s ---'
> +start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
> +
>  class BitBakeServer(object):
> -    start_log_format = '--- Starting bitbake server pid %s at %s ---'
> -    start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
>
>      def __init__(self, lock, sockname, featureset, server_timeout, xmlrpcinterface):
>
> @@ -429,7 +431,7 @@ class BitBakeServer(object):
>              ready.close()
>              bb.error("Unable to start bitbake server (%s)" % str(r))
>              if os.path.exists(logfile):
> -                logstart_re = re.compile(self.start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
> +                logstart_re = re.compile(start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
>                  started = False
>                  lines = []
>                  lastlines = []
> @@ -441,7 +443,7 @@ class BitBakeServer(object):
>                              lastlines.append(line)
>                              res = logstart_re.match(line.rstrip())
>                              if res:
> -                                ldatetime = datetime.datetime.strptime(res.group(2), self.start_log_datetime_format)
> +                                ldatetime = datetime.datetime.strptime(res.group(2), start_log_datetime_format)
>                                  if ldatetime >= startdatetime:
>                                      started = True
>                                      lines.append(line)
> @@ -462,42 +464,54 @@ class BitBakeServer(object):
>          ready.close()
>
>      def _startServer(self):
> -        print(self.start_log_format % (os.getpid(), datetime.datetime.now().strftime(self.start_log_datetime_format)))
> -        sys.stdout.flush()
> +        os.close(self.readypipe)
> +        os.set_inheritable(self.bitbake_lock.fileno(), True)
> +        os.set_inheritable(self.readypipein, True)
> +        os.execlp("bitbake-server", "bitbake-server", "decafbad", str(self.bitbake_lock.fileno()), str(self.readypipein), self.bitbake_lock.name, self.sockname,  str(self.server_timeout), str(self.xmlrpcinterface[0]), str(self.xmlrpcinterface[1]))

You may want to do:

 os.execl(sys.executable, sys.executable, "bitbake-server", ....)

This ensures that the same python interpreter is used for the server
and UI front end.

>
> -        try:
> -            # Create server control socket
> -            if os.path.exists(self.sockname):
> -                os.unlink(self.sockname)
> +def execServer(lockfd, readypipeinfd, lockname, sockname, server_timeout, xmlrpcinterface):
>
> -            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
> -            # AF_UNIX has path length issues so chdir here to workaround
> -            cwd = os.getcwd()
> -            try:
> -                os.chdir(os.path.dirname(self.sockname))
> -                sock.bind(os.path.basename(self.sockname))
> -            finally:
> -                os.chdir(cwd)
> -            sock.listen(1)
> -
> -            server = ProcessServer(self.bitbake_lock, sock, self.sockname, self.server_timeout, self.xmlrpcinterface)
> -            os.close(self.readypipe)
> -            writer = ConnectionWriter(self.readypipein)
> -            try:
> -                self.cooker = bb.cooker.BBCooker(self.featureset, server.register_idle_function)
> -            except bb.BBHandledException:
> -                return None
> -            writer.send("r")
> -            writer.close()
> -            server.cooker = self.cooker
> -            print("Started bitbake server pid %d" % os.getpid())
> -            sys.stdout.flush()
> -
> -            server.run()
> +    import bb.cookerdata
> +    import bb.cooker
> +
> +    print(start_log_format % (os.getpid(), datetime.datetime.now().strftime(start_log_datetime_format)))
> +    sys.stdout.flush()
> +
> +    try:
> +        bitbake_lock = os.fdopen(lockfd, "w")
> +
> +        # Create server control socket
> +        if os.path.exists(sockname):
> +            os.unlink(sockname)
> +
> +        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
> +        # AF_UNIX has path length issues so chdir here to workaround
> +        cwd = os.getcwd()
> +        try:
> +            os.chdir(os.path.dirname(sockname))
> +            sock.bind(os.path.basename(sockname))
>          finally:
> -            # Flush any ,essages/errors to the logfile before exit
> -            sys.stdout.flush()
> -            sys.stderr.flush()
> +            os.chdir(cwd)
> +        sock.listen(1)
> +
> +        server = ProcessServer(bitbake_lock, lockname, sock, sockname, server_timeout, xmlrpcinterface)
> +        writer = ConnectionWriter(readypipeinfd)
> +        try:
> +            featureset = []
> +            cooker = bb.cooker.BBCooker(featureset, server.register_idle_function)
> +        except bb.BBHandledException:
> +            return None
> +        writer.send("r")
> +        writer.close()
> +        server.cooker = cooker
> +        print("Started bitbake server pid %d" % os.getpid())
> +        sys.stdout.flush()
> +
> +        server.run()
> +    finally:
> +        # Flush any ,essages/errors to the logfile before exit
> +        sys.stdout.flush()
> +        sys.stderr.flush()
>
>  def connectProcessServer(sockname, featureset):
>      # Connect to socket
> --
> 2.25.1
>
> 

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

* Re: [bitbake-devel] [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process
  2020-08-25 16:06   ` [bitbake-devel] " Joshua Watt
@ 2020-08-25 17:06     ` Richard Purdie
  2020-08-25 17:19       ` Joshua Watt
  0 siblings, 1 reply; 14+ messages in thread
From: Richard Purdie @ 2020-08-25 17:06 UTC (permalink / raw)
  To: Joshua Watt; +Cc: bitbake-devel

On Tue, 2020-08-25 at 11:06 -0500, Joshua Watt wrote:
> On Mon, Aug 24, 2020 at 11:53 AM Richard Purdie
> <richard.purdie@linuxfoundation.org> wrote:
> > Trying to have a new python process forked off an original doesn't work
> > out well and ends up having race issues. To avoid this, exec() a new
> > bitbake server process. This starts with a fresh python interpreter
> > and resolves various atexit and other multiprocessing issues once
> > and for all.
> > 
> > Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> > ---
> >  lib/bb/server/process.py | 92 +++++++++++++++++++++++-----------------
> >  1 file changed, 53 insertions(+), 39 deletions(-)
> > 
> > diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
> > index 915651084e..d248570cd2 100644
> > --- a/lib/bb/server/process.py
> > +++ b/lib/bb/server/process.py
> > @@ -38,7 +38,7 @@ class ProcessServer():
> >      profile_filename = "profile.log"
> >      profile_processed_filename = "profile.log.processed"
> > 
> > -    def __init__(self, lock, sock, sockname, server_timeout, xmlrpcinterface):
> > +    def __init__(self, lock, lockname, sock, sockname, server_timeout, xmlrpcinterface):
> >          self.command_channel = False
> >          self.command_channel_reply = False
> >          self.quit = False
> > @@ -54,6 +54,7 @@ class ProcessServer():
> >          self._idlefuns = {}
> > 
> >          self.bitbake_lock = lock
> > +        self.bitbake_lock_name = lockname
> >          self.sock = sock
> >          self.sockname = sockname
> > 
> > @@ -259,7 +260,7 @@ class ProcessServer():
> > 
> >          # Finally release the lockfile but warn about other processes holding it open
> >          lock = self.bitbake_lock
> > -        lockfile = lock.name
> > +        lockfile = self.bitbake_lock_name
> >          lock.close()
> >          lock = None
> > 
> > @@ -393,9 +394,10 @@ class BitBakeProcessServerConnection(object):
> >          self.connection.recv.close()
> >          return
> > 
> > +start_log_format = '--- Starting bitbake server pid %s at %s ---'
> > +start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
> > +
> >  class BitBakeServer(object):
> > -    start_log_format = '--- Starting bitbake server pid %s at %s ---'
> > -    start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
> > 
> >      def __init__(self, lock, sockname, featureset, server_timeout, xmlrpcinterface):
> > 
> > @@ -429,7 +431,7 @@ class BitBakeServer(object):
> >              ready.close()
> >              bb.error("Unable to start bitbake server (%s)" % str(r))
> >              if os.path.exists(logfile):
> > -                logstart_re = re.compile(self.start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
> > +                logstart_re = re.compile(start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
> >                  started = False
> >                  lines = []
> >                  lastlines = []
> > @@ -441,7 +443,7 @@ class BitBakeServer(object):
> >                              lastlines.append(line)
> >                              res = logstart_re.match(line.rstrip())
> >                              if res:
> > -                                ldatetime = datetime.datetime.strptime(res.group(2), self.start_log_datetime_format)
> > +                                ldatetime = datetime.datetime.strptime(res.group(2), start_log_datetime_format)
> >                                  if ldatetime >= startdatetime:
> >                                      started = True
> >                                      lines.append(line)
> > @@ -462,42 +464,54 @@ class BitBakeServer(object):
> >          ready.close()
> > 
> >      def _startServer(self):
> > -        print(self.start_log_format % (os.getpid(), datetime.datetime.now().strftime(self.start_log_datetime_format)))
> > -        sys.stdout.flush()
> > +        os.close(self.readypipe)
> > +        os.set_inheritable(self.bitbake_lock.fileno(), True)
> > +        os.set_inheritable(self.readypipein, True)
> > +        os.execlp("bitbake-server", "bitbake-server", "decafbad", str(self.bitbake_lock.fileno()), str(self.readypipein), self.bitbake_lock.name, self.sockname,  str(self.server_timeout), str(self.xmlrpcinterface[0]), str(self.xmlrpcinterface[1]))
> 
> You may want to do:
> 
>  os.execl(sys.executable, sys.executable, "bitbake-server", ....)
> 
> This ensures that the same python interpreter is used for the server
> and UI front end.

Yes, good point, although leaving arg0 as bitbake-server is probably
helpful for debugging so you can see the server process in a process
listing?

I had to change the code slightly in master-next to use execl() with
"../../../bitbake-server" based upon __file__ as it would break in
cases where we've messed around with PATH.

Cheers,

Richard



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

* Re: [bitbake-devel] [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process
  2020-08-25 17:06     ` Richard Purdie
@ 2020-08-25 17:19       ` Joshua Watt
  2020-08-25 17:23         ` Richard Purdie
  0 siblings, 1 reply; 14+ messages in thread
From: Joshua Watt @ 2020-08-25 17:19 UTC (permalink / raw)
  To: Richard Purdie; +Cc: bitbake-devel


On 8/25/20 12:06 PM, Richard Purdie wrote:
> On Tue, 2020-08-25 at 11:06 -0500, Joshua Watt wrote:
>> On Mon, Aug 24, 2020 at 11:53 AM Richard Purdie
>> <richard.purdie@linuxfoundation.org> wrote:
>>> Trying to have a new python process forked off an original doesn't work
>>> out well and ends up having race issues. To avoid this, exec() a new
>>> bitbake server process. This starts with a fresh python interpreter
>>> and resolves various atexit and other multiprocessing issues once
>>> and for all.
>>>
>>> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
>>> ---
>>>   lib/bb/server/process.py | 92 +++++++++++++++++++++++-----------------
>>>   1 file changed, 53 insertions(+), 39 deletions(-)
>>>
>>> diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
>>> index 915651084e..d248570cd2 100644
>>> --- a/lib/bb/server/process.py
>>> +++ b/lib/bb/server/process.py
>>> @@ -38,7 +38,7 @@ class ProcessServer():
>>>       profile_filename = "profile.log"
>>>       profile_processed_filename = "profile.log.processed"
>>>
>>> -    def __init__(self, lock, sock, sockname, server_timeout, xmlrpcinterface):
>>> +    def __init__(self, lock, lockname, sock, sockname, server_timeout, xmlrpcinterface):
>>>           self.command_channel = False
>>>           self.command_channel_reply = False
>>>           self.quit = False
>>> @@ -54,6 +54,7 @@ class ProcessServer():
>>>           self._idlefuns = {}
>>>
>>>           self.bitbake_lock = lock
>>> +        self.bitbake_lock_name = lockname
>>>           self.sock = sock
>>>           self.sockname = sockname
>>>
>>> @@ -259,7 +260,7 @@ class ProcessServer():
>>>
>>>           # Finally release the lockfile but warn about other processes holding it open
>>>           lock = self.bitbake_lock
>>> -        lockfile = lock.name
>>> +        lockfile = self.bitbake_lock_name
>>>           lock.close()
>>>           lock = None
>>>
>>> @@ -393,9 +394,10 @@ class BitBakeProcessServerConnection(object):
>>>           self.connection.recv.close()
>>>           return
>>>
>>> +start_log_format = '--- Starting bitbake server pid %s at %s ---'
>>> +start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
>>> +
>>>   class BitBakeServer(object):
>>> -    start_log_format = '--- Starting bitbake server pid %s at %s ---'
>>> -    start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
>>>
>>>       def __init__(self, lock, sockname, featureset, server_timeout, xmlrpcinterface):
>>>
>>> @@ -429,7 +431,7 @@ class BitBakeServer(object):
>>>               ready.close()
>>>               bb.error("Unable to start bitbake server (%s)" % str(r))
>>>               if os.path.exists(logfile):
>>> -                logstart_re = re.compile(self.start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
>>> +                logstart_re = re.compile(start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
>>>                   started = False
>>>                   lines = []
>>>                   lastlines = []
>>> @@ -441,7 +443,7 @@ class BitBakeServer(object):
>>>                               lastlines.append(line)
>>>                               res = logstart_re.match(line.rstrip())
>>>                               if res:
>>> -                                ldatetime = datetime.datetime.strptime(res.group(2), self.start_log_datetime_format)
>>> +                                ldatetime = datetime.datetime.strptime(res.group(2), start_log_datetime_format)
>>>                                   if ldatetime >= startdatetime:
>>>                                       started = True
>>>                                       lines.append(line)
>>> @@ -462,42 +464,54 @@ class BitBakeServer(object):
>>>           ready.close()
>>>
>>>       def _startServer(self):
>>> -        print(self.start_log_format % (os.getpid(), datetime.datetime.now().strftime(self.start_log_datetime_format)))
>>> -        sys.stdout.flush()
>>> +        os.close(self.readypipe)
>>> +        os.set_inheritable(self.bitbake_lock.fileno(), True)
>>> +        os.set_inheritable(self.readypipein, True)
>>> +        os.execlp("bitbake-server", "bitbake-server", "decafbad", str(self.bitbake_lock.fileno()), str(self.readypipein), self.bitbake_lock.name, self.sockname,  str(self.server_timeout), str(self.xmlrpcinterface[0]), str(self.xmlrpcinterface[1]))
>> You may want to do:
>>
>>   os.execl(sys.executable, sys.executable, "bitbake-server", ....)
>>
>> This ensures that the same python interpreter is used for the server
>> and UI front end.
> Yes, good point, although leaving arg0 as bitbake-server is probably
> helpful for debugging so you can see the server process in a process
> listing?

Ya, that's seems fine:

  os.execl(sys.executable, "bitbake-server", bitbake_server_path, ....)

looks like it would work

>
> I had to change the code slightly in master-next to use execl() with
> "../../../bitbake-server" based upon __file__ as it would break in
> cases where we've messed around with PATH.
>
> Cheers,
>
> Richard
>
>

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

* Re: [bitbake-devel] [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process
  2020-08-25 17:19       ` Joshua Watt
@ 2020-08-25 17:23         ` Richard Purdie
  0 siblings, 0 replies; 14+ messages in thread
From: Richard Purdie @ 2020-08-25 17:23 UTC (permalink / raw)
  To: Joshua Watt; +Cc: bitbake-devel

On Tue, 2020-08-25 at 12:19 -0500, Joshua Watt wrote:
> On 8/25/20 12:06 PM, Richard Purdie wrote:
> > On Tue, 2020-08-25 at 11:06 -0500, Joshua Watt wrote:
> > > On Mon, Aug 24, 2020 at 11:53 AM Richard Purdie
> > > <richard.purdie@linuxfoundation.org> wrote:
> > > > Trying to have a new python process forked off an original doesn't work
> > > > out well and ends up having race issues. To avoid this, exec() a new
> > > > bitbake server process. This starts with a fresh python interpreter
> > > > and resolves various atexit and other multiprocessing issues once
> > > > and for all.
> > > > 
> > > > Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> > > > ---
> > > >   lib/bb/server/process.py | 92 +++++++++++++++++++++++-----------------
> > > >   1 file changed, 53 insertions(+), 39 deletions(-)
> > > > 
> > > > diff --git a/lib/bb/server/process.py b/lib/bb/server/process.py
> > > > index 915651084e..d248570cd2 100644
> > > > --- a/lib/bb/server/process.py
> > > > +++ b/lib/bb/server/process.py
> > > > @@ -38,7 +38,7 @@ class ProcessServer():
> > > >       profile_filename = "profile.log"
> > > >       profile_processed_filename = "profile.log.processed"
> > > > 
> > > > -    def __init__(self, lock, sock, sockname, server_timeout, xmlrpcinterface):
> > > > +    def __init__(self, lock, lockname, sock, sockname, server_timeout, xmlrpcinterface):
> > > >           self.command_channel = False
> > > >           self.command_channel_reply = False
> > > >           self.quit = False
> > > > @@ -54,6 +54,7 @@ class ProcessServer():
> > > >           self._idlefuns = {}
> > > > 
> > > >           self.bitbake_lock = lock
> > > > +        self.bitbake_lock_name = lockname
> > > >           self.sock = sock
> > > >           self.sockname = sockname
> > > > 
> > > > @@ -259,7 +260,7 @@ class ProcessServer():
> > > > 
> > > >           # Finally release the lockfile but warn about other processes holding it open
> > > >           lock = self.bitbake_lock
> > > > -        lockfile = lock.name
> > > > +        lockfile = self.bitbake_lock_name
> > > >           lock.close()
> > > >           lock = None
> > > > 
> > > > @@ -393,9 +394,10 @@ class BitBakeProcessServerConnection(object):
> > > >           self.connection.recv.close()
> > > >           return
> > > > 
> > > > +start_log_format = '--- Starting bitbake server pid %s at %s ---'
> > > > +start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
> > > > +
> > > >   class BitBakeServer(object):
> > > > -    start_log_format = '--- Starting bitbake server pid %s at %s ---'
> > > > -    start_log_datetime_format = '%Y-%m-%d %H:%M:%S.%f'
> > > > 
> > > >       def __init__(self, lock, sockname, featureset, server_timeout, xmlrpcinterface):
> > > > 
> > > > @@ -429,7 +431,7 @@ class BitBakeServer(object):
> > > >               ready.close()
> > > >               bb.error("Unable to start bitbake server (%s)" % str(r))
> > > >               if os.path.exists(logfile):
> > > > -                logstart_re = re.compile(self.start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
> > > > +                logstart_re = re.compile(start_log_format % ('([0-9]+)', '([0-9-]+ [0-9:.]+)'))
> > > >                   started = False
> > > >                   lines = []
> > > >                   lastlines = []
> > > > @@ -441,7 +443,7 @@ class BitBakeServer(object):
> > > >                               lastlines.append(line)
> > > >                               res = logstart_re.match(line.rstrip())
> > > >                               if res:
> > > > -                                ldatetime = datetime.datetime.strptime(res.group(2), self.start_log_datetime_format)
> > > > +                                ldatetime = datetime.datetime.strptime(res.group(2), start_log_datetime_format)
> > > >                                   if ldatetime >= startdatetime:
> > > >                                       started = True
> > > >                                       lines.append(line)
> > > > @@ -462,42 +464,54 @@ class BitBakeServer(object):
> > > >           ready.close()
> > > > 
> > > >       def _startServer(self):
> > > > -        print(self.start_log_format % (os.getpid(), datetime.datetime.now().strftime(self.start_log_datetime_format)))
> > > > -        sys.stdout.flush()
> > > > +        os.close(self.readypipe)
> > > > +        os.set_inheritable(self.bitbake_lock.fileno(), True)
> > > > +        os.set_inheritable(self.readypipein, True)
> > > > +        os.execlp("bitbake-server", "bitbake-server", "decafbad", str(self.bitbake_lock.fileno()), str(self.readypipein), self.bitbake_lock.name, self.sockname,  str(self.server_timeout), str(self.xmlrpcinterface[0]), str(self.xmlrpcinterface[1]))
> > > You may want to do:
> > > 
> > >   os.execl(sys.executable, sys.executable, "bitbake-server", ....)
> > > 
> > > This ensures that the same python interpreter is used for the server
> > > and UI front end.
> > Yes, good point, although leaving arg0 as bitbake-server is probably
> > helpful for debugging so you can see the server process in a process
> > listing?
> 
> Ya, that's seems fine:
> 
>   os.execl(sys.executable, "bitbake-server", bitbake_server_path, ....)
> 
> looks like it would work

It does. I'm handling this as a followup patch since the original set
was tested and ready to merge (now merged).

This one will test and then merge if all the corner cases work out ok.

Cheers,

Richard


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

end of thread, other threads:[~2020-08-25 17:23 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-24 16:53 [PATCH 01/10] build/msg: Cleanup verbose option handling Richard Purdie
2020-08-24 16:53 ` [PATCH 02/10] cooker/cookerdata/main: Improve loglevel handling Richard Purdie
2020-08-24 16:53 ` [PATCH 03/10] cookerdata: Ensure UI options are updated to the server Richard Purdie
2020-08-24 16:53 ` [PATCH 04/10] cooker/cookerdata: Ensure UI event log is updated from commandline Richard Purdie
2020-08-24 16:53 ` [PATCH 05/10] cooker: Defer configuration init to after UI connection Richard Purdie
2020-08-24 16:53 ` [PATCH 06/10] server/process: Move the socket code to server process only Richard Purdie
2020-08-24 16:53 ` [PATCH 07/10] main/server/process: Drop configuration object passing Richard Purdie
2020-08-24 16:53 ` [PATCH 08/10] cooker: Ensure BB_ORIGENV is updated by changes to configuration.env Richard Purdie
2020-08-24 16:53 ` [PATCH 09/10] server/process: Log extra threads at exit Richard Purdie
2020-08-24 16:53 ` [PATCH 10/10] server/process: Add bitbake-server and exec() a new server process Richard Purdie
2020-08-25 16:06   ` [bitbake-devel] " Joshua Watt
2020-08-25 17:06     ` Richard Purdie
2020-08-25 17:19       ` Joshua Watt
2020-08-25 17:23         ` 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.