5 from gi.repository import GObject
7 from .common import ST_ACTIVE, ST_TRANSITION, OnoffDevice
9 logger = logging.getLogger("onoff.process")
11 class OnoffProcess(OnoffDevice):
12 def __init__(self, command, start_wait=0, termsig=signal.SIGTERM):
13 OnoffDevice.__init__(self)
14 self.command = command
15 self.start_wait = start_wait
16 self.termsig = termsig
19 self.starting = None # timeout event during start
20 self.watch = None # watch event
22 def start_process(self):
23 assert self.state == 0
24 assert self.pid is None
25 assert self.starting is None
26 logger.info("starting command %s", " ".join(self.command))
27 self.state = ST_ACTIVE|ST_TRANSITION
28 ret = GObject.spawn_async(self.command, flags=GObject.SPAWN_SEARCH_PATH | GObject.SPAWN_DO_NOT_REAP_CHILD)
31 logger.debug("started as pid %d", self.pid)
32 self.watch = GObject.child_watch_add(self.pid, self.process_died)
33 self.starting = GObject.timeout_add(1000 * self.start_wait,
35 self.changestate(self.state)
37 def process_died(self, pid, condition):
38 assert self.state != 0
39 assert self.pid == pid
40 assert self.watch is not None
44 logger.info("process %d died", pid)
45 self.changestate(self.state)
47 def process_started(self):
48 assert self.state == ST_ACTIVE|ST_TRANSITION
49 assert self.starting is not None
50 self.state = ST_ACTIVE
52 logger.debug("process started")
53 self.changestate(self.state)
55 def stop_process(self):
56 assert self.state & ST_ACTIVE
57 assert self.pid is not None
58 if self.state & ST_TRANSITION:
59 logger.debug("cancelling start notification")
60 assert self.starting is not None
61 ret = GObject.source_remove(self.starting)
64 self.state = ST_TRANSITION
65 logger.info("killing process %d", self.pid)
66 os.kill(self.pid, self.termsig)
67 self.changestate(self.state)
73 logger.debug("not activating from state %d", self.state)
76 if self.state & ST_ACTIVE:
79 logger.debug("not deactivating from state %d", self.state)