Fix some typos.
[portage.git] / pym / _emerge / FifoIpcDaemon.py
1 # Copyright 2010-2013 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 import sys
5
6 try:
7         import fcntl
8 except ImportError:
9         #  http://bugs.jython.org/issue1074
10         fcntl = None
11
12 from portage import os
13 from _emerge.AbstractPollTask import AbstractPollTask
14 from portage.cache.mappings import slot_dict_class
15
16 class FifoIpcDaemon(AbstractPollTask):
17
18         __slots__ = ("input_fifo", "output_fifo",) + \
19                 ("_files", "_reg_id",)
20
21         _file_names = ("pipe_in",)
22         _files_dict = slot_dict_class(_file_names, prefix="")
23
24         def _start(self):
25                 self._files = self._files_dict()
26
27                 # File streams are in unbuffered mode since we do atomic
28                 # read and write of whole pickles.
29                 self._files.pipe_in = \
30                         os.open(self.input_fifo, os.O_RDONLY|os.O_NONBLOCK)
31
32                 # FD_CLOEXEC is enabled by default in Python >=3.4.
33                 if sys.hexversion < 0x3040000 and fcntl is not None:
34                         try:
35                                 fcntl.FD_CLOEXEC
36                         except AttributeError:
37                                 pass
38                         else:
39                                 fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFD,
40                                         fcntl.fcntl(self._files.pipe_in,
41                                                 fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
42
43                 self._reg_id = self.scheduler.io_add_watch(
44                         self._files.pipe_in,
45                         self._registered_events, self._input_handler)
46
47                 self._registered = True
48
49         def _reopen_input(self):
50                 """
51                 Re-open the input stream, in order to suppress
52                 POLLHUP events (bug #339976).
53                 """
54                 self.scheduler.source_remove(self._reg_id)
55                 os.close(self._files.pipe_in)
56                 self._files.pipe_in = \
57                         os.open(self.input_fifo, os.O_RDONLY|os.O_NONBLOCK)
58
59                 # FD_CLOEXEC is enabled by default in Python >=3.4.
60                 if sys.hexversion < 0x3040000 and fcntl is not None:
61                         try:
62                                 fcntl.FD_CLOEXEC
63                         except AttributeError:
64                                 pass
65                         else:
66                                 fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFD,
67                                         fcntl.fcntl(self._files.pipe_in,
68                                                 fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
69
70                 self._reg_id = self.scheduler.io_add_watch(
71                         self._files.pipe_in,
72                         self._registered_events, self._input_handler)
73
74         def isAlive(self):
75                 return self._registered
76
77         def _cancel(self):
78                 if self.returncode is None:
79                         self.returncode = 1
80                 self._unregister()
81                 # notify exit listeners
82                 self.wait()
83
84         def _wait(self):
85                 if self.returncode is not None:
86                         return self.returncode
87                 self._wait_loop()
88                 if self.returncode is None:
89                         self.returncode = os.EX_OK
90                 return self.returncode
91
92         def _input_handler(self, fd, event):
93                 raise NotImplementedError(self)
94
95         def _unregister(self):
96                 """
97                 Unregister from the scheduler and close open files.
98                 """
99
100                 self._registered = False
101
102                 if self._reg_id is not None:
103                         self.scheduler.source_remove(self._reg_id)
104                         self._reg_id = None
105
106                 if self._files is not None:
107                         for f in self._files.values():
108                                 os.close(f)
109                         self._files = None