Hide keyboard shortcuts

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. 

6 

7 

8from threading import Thread, Lock 

9from queue import Queue 

10 

11from xpra.log import Logger 

12log = Logger("util") 

13 

14 

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 """ 

21 

22 def __init__(self): 

23 super().__init__(name="Worker_Thread") 

24 self.items = Queue() 

25 self.exit = False 

26 self.setDaemon(True) 

27 

28 def __repr__(self): 

29 return "Worker_Thread(items=%s, exit=%s)" % (self.items.qsize(), self.exit) 

30 

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) 

46 

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) 

54 

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()) 

69 

70#only one worker thread for now: 

71singleton = None 

72#locking to ensure multi-threaded code doesn't create more than one 

73lock = Lock() 

74 

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 

85 

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) 

90 

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)