Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/background_worker.py : 100%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2013, 2014 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
8from threading import Thread, Lock
9from queue import Queue
11from xpra.log import Logger
12log = Logger("util")
15class Worker_Thread(Thread):
16 """
17 A background thread which calls the functions we post to it.
18 The functions are placed in a queue and only called once,
19 when this thread gets around to it.
20 """
22 def __init__(self):
23 super().__init__(name="Worker_Thread")
24 self.items = Queue()
25 self.exit = False
26 self.setDaemon(True)
28 def __repr__(self):
29 return "Worker_Thread(items=%s, exit=%s)" % (self.items.qsize(), self.exit)
31 def stop(self, force=False):
32 if self.exit:
33 return
34 items = tuple(x for x in self.items.queue if x is not None)
35 log("Worker_Thread.stop(%s) %i items still in work queue: %s", force, len(items), items)
36 if force:
37 if items:
38 log.warn("Worker stop: %s items in the queue will not be run!", len(items))
39 self.items.put(None)
40 self.items = Queue()
41 self.exit = True
42 else:
43 if items:
44 log.info("waiting for %s items in work queue to complete", len(items))
45 self.items.put(None)
47 def add(self, item, allow_duplicates=True):
48 if self.items.qsize()>10:
49 log.warn("Worker_Thread.items queue size is %s", self.items.qsize())
50 if not allow_duplicates:
51 if item in self.items.queue:
52 return
53 self.items.put(item)
55 def run(self):
56 log("Worker_Thread.run() starting")
57 while not self.exit:
58 item = self.items.get()
59 if item is None:
60 log("Worker_Thread.run() found end of queue marker")
61 self.exit = True
62 break
63 try:
64 log("Worker_Thread.run() calling %s (queue size=%s)", item, self.items.qsize())
65 item()
66 except Exception:
67 log.error("Error in worker thread processing item %s", item, exc_info=True)
68 log("Worker_Thread.run() ended (queue size=%s)", self.items.qsize())
70#only one worker thread for now:
71singleton = None
72#locking to ensure multi-threaded code doesn't create more than one
73lock = Lock()
75def get_worker(create=True):
76 global singleton
77 #fast path (no lock):
78 if singleton is not None or not create:
79 return singleton
80 with lock:
81 if not singleton:
82 singleton = Worker_Thread()
83 singleton.start()
84 return singleton
86def add_work_item(item, allow_duplicates=True):
87 w = get_worker(True)
88 log("add_work_item(%s, %s) worker=%s", item, allow_duplicates, w)
89 w.add(item, allow_duplicates)
91def stop_worker(force=False):
92 w = get_worker(False)
93 log("stop_worker(%s) worker=%s", force, w)
94 if w:
95 w.stop(force)