attempt to fix for python3
[~helmut/onoff.git] / onoff / process.py
1 import logging
2 import os
3 import signal
4
5 from gi.repository import GObject
6
7 from .common import ST_ACTIVE, ST_TRANSITION, OnoffDevice
8
9 logger = logging.getLogger("onoff.process")
10
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
17         self.state = 0
18         self.pid = None
19         self.starting = None # timeout event during start
20         self.watch = None # watch event
21
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)
29         self.pid = ret[0]
30         assert self.pid
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,
34                                             self.process_started)
35         self.changestate(self.state)
36
37     def process_died(self, pid, condition):
38         assert self.state != 0
39         assert self.pid == pid
40         assert self.watch is not None
41         self.state = 0
42         self.watch = None
43         self.pid = None
44         logger.info("process %d died", pid)
45         self.changestate(self.state)
46
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
51         self.starting = None
52         logger.debug("process started")
53         self.changestate(self.state)
54
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)
62             assert ret
63             self.starting = None
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)
68
69     def activate(self):
70         if self.state == 0:
71             self.start_process()
72         else:
73             logger.debug("not activating from state %d", self.state)
74
75     def deactivate(self):
76         if self.state & ST_ACTIVE:
77             self.stop_process()
78         else:
79             logger.debug("not deactivating from state %d", self.state)
80
81     def close(self):
82         self.deactivate()