Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 #!/usr/bin/env python
3 import argparse
4 import collections
5 import ConfigParser
6 import multiprocessing
7 import time
9 ProcessNode = collections.namedtuple('ProcessNode', ['maxtime', 'children'])
11 class ProcessLauncher(object):
13 """ Create and Launch process trees specified by a '.ini' file
15 Typical .ini file accepted by this class :
17 [main]
18 children=c1, 1*c2, 4*c3
19 maxtime=10
21 [c1]
22 children= 2*c2, c3
23 maxtime=20
25 [c2]
26 children=3*c3
27 maxtime=5
29 [c3]
30 maxtime=3
32 This generates a process tree of the form:
33 [main]
34 |---[c1]
35 | |---[c2]
36 | | |---[c3]
37 | | |---[c3]
38 | | |---[c3]
39 | |
40 | |---[c2]
41 | | |---[c3]
42 | | |---[c3]
43 | | |---[c3]
44 | |
45 | |---[c3]
46 |
47 |---[c2]
48 | |---[c3]
49 | |---[c3]
50 | |---[c3]
51 |
52 |---[c3]
53 |---[c3]
54 |---[c3]
56 Caveat: The section names cannot contain a '*'(asterisk) or a ','(comma)
57 character as these are used as delimiters for parsing.
58 """
60 # Unit time for processes in seconds
61 UNIT_TIME = 1
63 def __init__(self, manifest, verbose=False):
64 """
65 Parses the manifest and stores the information about the process tree
66 in a format usable by the class.
68 Raises IOError if :
69 - The path does not exist
70 - The file cannot be read
71 Raises ConfigParser.*Error if:
72 - Files does not contain section headers
73 - File cannot be parsed because of incorrect specification
75 :param manifest: Path to the manifest file that contains the
76 configuration for the process tree to be launched
77 :verbose: Print the process start and end information.
78 Genrates a lot of output. Disabled by default.
79 """
81 self.verbose=verbose
83 # Children is a dictionary used to store information from the,
84 # Configuration file in a more usable format.
85 # Key : string contain the name of child process
86 # Value : A Named tuple of the form (max_time, (list of child processes of Key))
87 # Where each child process is a list of type: [count to run, name of child]
88 self.children = {}
91 cfgparser = ConfigParser.ConfigParser()
93 if not cfgparser.read(manifest):
94 raise IOError('The manifest %s could not be found/opened', manifest)
96 sections = cfgparser.sections()
97 for section in sections:
98 # Maxtime is a mandatory option
99 # ConfigParser.NoOptionError is raised if maxtime does not exist
100 if '*' in section or ',' in section:
101 raise ConfigParser.ParsingError('%s is not a valid section name. Section names cannot contain a \'*\' or \',\'.' % section)
102 m_time = cfgparser.get(section, 'maxtime')
103 try:
104 m_time = int(m_time)
105 except ValueError:
106 raise ValueError('Expected maxtime to be an integer, specified %s' % m_time)
108 # No children option implies there are no further children
109 # Leaving the children option blank is an error.
110 try:
111 c = cfgparser.get(section, 'children')
112 if not c:
113 # If children is an empty field, assume no children
114 children = None
116 else:
117 # Tokenize chilren field, ignore empty strings
118 children = [[y.strip() for y in x.strip().split('*', 1)]
119 for x in c.split(',') if x]
120 try:
121 for i, child in enumerate(children):
122 # No multiplicate factor infront of a process implies 1
123 if len(child) == 1:
124 children[i] = [1, child[0]]
125 else:
126 children[i][0] = int(child[0])
128 if children[i][1] not in sections:
129 raise ConfigParser.ParsingError('No section corresponding to child %s' % child[1])
130 except ValueError:
131 raise ValueError('Expected process count to be an integer, specified %s' % child[0])
133 except ConfigParser.NoOptionError:
134 children = None
135 pn = ProcessNode(maxtime=m_time,
136 children=children)
137 self.children[section] = pn
139 def run(self):
140 """
141 This function launches the process tree.
142 """
143 self._run('main', 0)
145 def _run(self, proc_name, level):
146 """
147 Runs the process specified by the section-name `proc_name` in the manifest file.
148 Then makes calls to launch the child processes of `proc_name`
150 :param proc_name: File name of the manifest as a string.
151 :param level: Depth of the current process in the tree.
152 """
153 if proc_name not in self.children.keys():
154 raise IOError("%s is not a valid process" % proc_name)
156 maxtime = self.children[proc_name].maxtime
157 if self.verbose:
158 print "%sLaunching %s for %d*%d seconds" % (" "*level, proc_name, maxtime, self.UNIT_TIME)
160 while self.children[proc_name].children:
161 child = self.children[proc_name].children.pop()
163 count, child_proc = child
164 for i in range(count):
165 p = multiprocessing.Process(target=self._run, args=(child[1], level+1))
166 p.start()
168 self._launch(maxtime)
169 if self.verbose:
170 print "%sFinished %s" % (" "*level, proc_name)
172 def _launch(self, running_time):
173 """
174 Create and launch a process and idles for the time specified by
175 `running_time`
177 :param running_time: Running time of the process in seconds.
178 """
179 elapsed_time = 0
181 while elapsed_time < running_time:
182 time.sleep(self.UNIT_TIME)
183 elapsed_time += self.UNIT_TIME
185 if __name__ == '__main__':
187 parser = argparse.ArgumentParser()
188 parser.add_argument("manifest", help="Specify the configuration .ini file")
189 args = parser.parse_args()
191 proclaunch = ProcessLauncher(args.manifest)
192 proclaunch.run()