[core] fix concurrency issues

* initialize first line of output earlier (before modules are
  initialized, so that module/thread output cannot interfere)
* make sure that update and draw are protected against concurrent access
This commit is contained in:
tobi-wan-kenobi 2022-09-09 20:58:59 +02:00
parent 28601cf2b7
commit f4bd0fba0b
2 changed files with 19 additions and 9 deletions

View file

@ -75,6 +75,8 @@ def handle_events(config, update_lock):
def main(): def main():
global started
config = core.config.Config(sys.argv[1:]) config = core.config.Config(sys.argv[1:])
level = logging.DEBUG if config.debug() else logging.ERROR level = logging.DEBUG if config.debug() else logging.ERROR
if config.logfile(): if config.logfile():
@ -97,6 +99,8 @@ def main():
core.input.register(None, core.input.WHEEL_UP, "i3-msg workspace prev_on_output") core.input.register(None, core.input.WHEEL_UP, "i3-msg workspace prev_on_output")
core.input.register(None, core.input.WHEEL_DOWN, "i3-msg workspace next_on_output") core.input.register(None, core.input.WHEEL_DOWN, "i3-msg workspace next_on_output")
core.event.trigger("start")
update_lock = threading.Lock() update_lock = threading.Lock()
event_thread = threading.Thread(target=handle_events, args=(config, update_lock, )) event_thread = threading.Thread(target=handle_events, args=(config, update_lock, ))
event_thread.daemon = True event_thread.daemon = True
@ -127,7 +131,6 @@ def main():
if util.format.asbool(config.get("engine.collapsible", True)) == True: if util.format.asbool(config.get("engine.collapsible", True)) == True:
core.input.register(None, core.input.MIDDLE_MOUSE, output.toggle_minimize) core.input.register(None, core.input.MIDDLE_MOUSE, output.toggle_minimize)
core.event.trigger("start")
started = True started = True
signal.signal(10, sig_USR1_handler) signal.signal(10, sig_USR1_handler)
while True: while True:

View file

@ -1,6 +1,7 @@
import sys import sys
import json import json
import time import time
import threading
import core.theme import core.theme
import core.event import core.event
@ -145,6 +146,7 @@ class i3(object):
self.__content = {} self.__content = {}
self.__theme = theme self.__theme = theme
self.__config = config self.__config = config
self.__lock = threading.Lock()
core.event.register("update", self.update) core.event.register("update", self.update)
core.event.register("start", self.draw, "start") core.event.register("start", self.draw, "start")
core.event.register("draw", self.draw, "statusline") core.event.register("draw", self.draw, "statusline")
@ -176,14 +178,15 @@ class i3(object):
self.__content[widget_id]["minimized"] = not self.__content[widget_id]["minimized"] self.__content[widget_id]["minimized"] = not self.__content[widget_id]["minimized"]
def draw(self, what, args=None): def draw(self, what, args=None):
cb = getattr(self, what) with self.__lock:
data = cb(args) if args else cb() cb = getattr(self, what)
if "blocks" in data: data = cb(args) if args else cb()
sys.stdout.write(json.dumps(data["blocks"], default=dump_json)) if "blocks" in data:
if "suffix" in data: sys.stdout.write(json.dumps(data["blocks"], default=dump_json))
sys.stdout.write(data["suffix"]) if "suffix" in data:
sys.stdout.write("\n") sys.stdout.write(data["suffix"])
sys.stdout.flush() sys.stdout.write("\n")
sys.stdout.flush()
def start(self): def start(self):
return { return {
@ -244,6 +247,10 @@ class i3(object):
return blocks return blocks
def update(self, affected_modules=None, redraw_only=False, force=False): def update(self, affected_modules=None, redraw_only=False, force=False):
with self.__lock:
self.update2(affected_modules, redraw_only, force)
def update2(self, affected_modules=None, redraw_only=False, force=False):
now = time.time() now = time.time()
for module in self.__modules: for module in self.__modules:
if affected_modules and not module.id in affected_modules: if affected_modules and not module.id in affected_modules: