diff options
Diffstat (limited to 'scripts/runqemu')
-rwxr-xr-x | scripts/runqemu | 128 |
1 files changed, 91 insertions, 37 deletions
diff --git a/scripts/runqemu b/scripts/runqemu index f83e05728b..b0509672d5 100755 --- a/scripts/runqemu +++ b/scripts/runqemu | |||
@@ -157,19 +157,6 @@ def get_first_file(cmds): | |||
157 | return f | 157 | return f |
158 | return '' | 158 | return '' |
159 | 159 | ||
160 | def check_free_port(host, port): | ||
161 | """ Check whether the port is free or not """ | ||
162 | import socket | ||
163 | from contextlib import closing | ||
164 | |||
165 | with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: | ||
166 | if sock.connect_ex((host, port)) == 0: | ||
167 | # Port is open, so not free | ||
168 | return False | ||
169 | else: | ||
170 | # Port is not open, so free | ||
171 | return True | ||
172 | |||
173 | class BaseConfig(object): | 160 | class BaseConfig(object): |
174 | def __init__(self): | 161 | def __init__(self): |
175 | # The self.d saved vars from self.set(), part of them are from qemuboot.conf | 162 | # The self.d saved vars from self.set(), part of them are from qemuboot.conf |
@@ -218,8 +205,9 @@ class BaseConfig(object): | |||
218 | self.audio_enabled = False | 205 | self.audio_enabled = False |
219 | self.tcpserial_portnum = '' | 206 | self.tcpserial_portnum = '' |
220 | self.custombiosdir = '' | 207 | self.custombiosdir = '' |
221 | self.lock = '' | 208 | self.taplock = '' |
222 | self.lock_descriptor = None | 209 | self.taplock_descriptor = None |
210 | self.portlocks = {} | ||
223 | self.bitbake_e = '' | 211 | self.bitbake_e = '' |
224 | self.snapshot = False | 212 | self.snapshot = False |
225 | self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs', | 213 | self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs', |
@@ -240,30 +228,81 @@ class BaseConfig(object): | |||
240 | # avoid cleanup twice | 228 | # avoid cleanup twice |
241 | self.cleaned = False | 229 | self.cleaned = False |
242 | 230 | ||
243 | def acquire_lock(self, error=True): | 231 | def acquire_taplock(self, error=True): |
244 | logger.debug("Acquiring lockfile %s..." % self.lock) | 232 | logger.debug("Acquiring lockfile %s..." % self.taplock) |
245 | try: | 233 | try: |
246 | self.lock_descriptor = open(self.lock, 'w') | 234 | self.taplock_descriptor = open(self.taplock, 'w') |
247 | fcntl.flock(self.lock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB) | 235 | fcntl.flock(self.taplock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB) |
248 | except Exception as e: | 236 | except Exception as e: |
249 | msg = "Acquiring lockfile %s failed: %s" % (self.lock, e) | 237 | msg = "Acquiring lockfile %s failed: %s" % (self.taplock, e) |
250 | if error: | 238 | if error: |
251 | logger.error(msg) | 239 | logger.error(msg) |
252 | else: | 240 | else: |
253 | logger.info(msg) | 241 | logger.info(msg) |
254 | if self.lock_descriptor: | 242 | if self.taplock_descriptor: |
255 | self.lock_descriptor.close() | 243 | self.taplock_descriptor.close() |
256 | self.lock_descriptor = None | 244 | self.taplock_descriptor = None |
257 | return False | 245 | return False |
258 | return True | 246 | return True |
259 | 247 | ||
260 | def release_lock(self): | 248 | def release_taplock(self): |
261 | if self.lock_descriptor: | 249 | if self.taplock_descriptor: |
262 | logger.debug("Releasing lockfile for tap device '%s'" % self.tap) | 250 | logger.debug("Releasing lockfile for tap device '%s'" % self.tap) |
263 | fcntl.flock(self.lock_descriptor, fcntl.LOCK_UN) | 251 | fcntl.flock(self.taplock_descriptor, fcntl.LOCK_UN) |
264 | self.lock_descriptor.close() | 252 | self.taplock_descriptor.close() |
265 | os.remove(self.lock) | 253 | os.remove(self.taplock) |
266 | self.lock_descriptor = None | 254 | self.taplock_descriptor = None |
255 | |||
256 | def check_free_port(self, host, port, lockdir): | ||
257 | """ Check whether the port is free or not """ | ||
258 | import socket | ||
259 | from contextlib import closing | ||
260 | |||
261 | lockfile = os.path.join(lockdir, str(port) + '.lock') | ||
262 | if self.acquire_portlock(lockfile): | ||
263 | with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: | ||
264 | if sock.connect_ex((host, port)) == 0: | ||
265 | # Port is open, so not free | ||
266 | self.release_portlock(lockfile) | ||
267 | return False | ||
268 | else: | ||
269 | # Port is not open, so free | ||
270 | return True | ||
271 | else: | ||
272 | return False | ||
273 | |||
274 | def acquire_portlock(self, lockfile, error=True): | ||
275 | logger.debug("Acquiring lockfile %s..." % lockfile) | ||
276 | try: | ||
277 | portlock_descriptor = open(lockfile, 'w') | ||
278 | self.portlocks.update({lockfile: portlock_descriptor}) | ||
279 | fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_EX|fcntl.LOCK_NB) | ||
280 | except Exception as e: | ||
281 | msg = "Acquiring lockfile %s failed: %s" % (lockfile, e) | ||
282 | if error: | ||
283 | logger.error(msg) | ||
284 | else: | ||
285 | logger.info(msg) | ||
286 | if self.portlocks[lockfile]: | ||
287 | self.portlocks[lockfile].close() | ||
288 | del self.portlocks[lockfile] | ||
289 | return False | ||
290 | return True | ||
291 | |||
292 | def release_portlock(self, lockfile=None): | ||
293 | if lockfile != None: | ||
294 | logger.debug("Releasing lockfile '%s'" % lockfile) | ||
295 | fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_UN) | ||
296 | self.portlocks[lockfile].close() | ||
297 | os.remove(lockfile) | ||
298 | del self.portlocks[lockfile] | ||
299 | elif len(self.portlocks): | ||
300 | for lockfile, descriptor in self.portlocks.items(): | ||
301 | logger.debug("Releasing lockfile '%s'" % lockfile) | ||
302 | fcntl.flock(descriptor, fcntl.LOCK_UN) | ||
303 | descriptor.close() | ||
304 | os.remove(lockfile) | ||
305 | self.portlocks = {} | ||
267 | 306 | ||
268 | def get(self, key): | 307 | def get(self, key): |
269 | if key in self.d: | 308 | if key in self.d: |
@@ -923,10 +962,21 @@ class BaseConfig(object): | |||
923 | ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt) | 962 | ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt) |
924 | ports = [int(i) for i in ports] | 963 | ports = [int(i) for i in ports] |
925 | mac = 2 | 964 | mac = 2 |
965 | |||
966 | lockdir = "/tmp/qemu-port-locks" | ||
967 | if not os.path.exists(lockdir): | ||
968 | # There might be a race issue when multi runqemu processess are | ||
969 | # running at the same time. | ||
970 | try: | ||
971 | os.mkdir(lockdir) | ||
972 | os.chmod(lockdir, 0o777) | ||
973 | except FileExistsError: | ||
974 | pass | ||
975 | |||
926 | # Find a free port to avoid conflicts | 976 | # Find a free port to avoid conflicts |
927 | for p in ports[:]: | 977 | for p in ports[:]: |
928 | p_new = p | 978 | p_new = p |
929 | while not check_free_port('localhost', p_new): | 979 | while not self.check_free_port('localhost', p_new, lockdir): |
930 | p_new += 1 | 980 | p_new += 1 |
931 | mac += 1 | 981 | mac += 1 |
932 | while p_new in ports: | 982 | while p_new in ports: |
@@ -981,8 +1031,8 @@ class BaseConfig(object): | |||
981 | if os.path.exists('%s.skip' % lockfile): | 1031 | if os.path.exists('%s.skip' % lockfile): |
982 | logger.info('Found %s.skip, skipping %s' % (lockfile, p)) | 1032 | logger.info('Found %s.skip, skipping %s' % (lockfile, p)) |
983 | continue | 1033 | continue |
984 | self.lock = lockfile + '.lock' | 1034 | self.taplock = lockfile + '.lock' |
985 | if self.acquire_lock(error=False): | 1035 | if self.acquire_taplock(error=False): |
986 | tap = p | 1036 | tap = p |
987 | logger.info("Using preconfigured tap device %s" % tap) | 1037 | logger.info("Using preconfigured tap device %s" % tap) |
988 | logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap)) | 1038 | logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap)) |
@@ -1000,8 +1050,8 @@ class BaseConfig(object): | |||
1000 | cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native) | 1050 | cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native) |
1001 | tap = subprocess.check_output(cmd).decode('utf-8').strip() | 1051 | tap = subprocess.check_output(cmd).decode('utf-8').strip() |
1002 | lockfile = os.path.join(lockdir, tap) | 1052 | lockfile = os.path.join(lockdir, tap) |
1003 | self.lock = lockfile + '.lock' | 1053 | self.taplock = lockfile + '.lock' |
1004 | self.acquire_lock() | 1054 | self.acquire_taplock() |
1005 | self.cleantap = True | 1055 | self.cleantap = True |
1006 | logger.debug('Created tap: %s' % tap) | 1056 | logger.debug('Created tap: %s' % tap) |
1007 | 1057 | ||
@@ -1233,8 +1283,11 @@ class BaseConfig(object): | |||
1233 | cmds = shlex.split(cmd) | 1283 | cmds = shlex.split(cmd) |
1234 | logger.info('Running %s\n' % cmd) | 1284 | logger.info('Running %s\n' % cmd) |
1235 | pass_fds = [] | 1285 | pass_fds = [] |
1236 | if self.lock_descriptor: | 1286 | if self.taplock_descriptor: |
1237 | pass_fds = [self.lock_descriptor.fileno()] | 1287 | pass_fds = [self.taplock_descriptor.fileno()] |
1288 | if len(self.portlocks): | ||
1289 | for descriptor in self.portlocks.values(): | ||
1290 | pass_fds.append(descriptor.fileno()) | ||
1238 | process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds) | 1291 | process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds) |
1239 | self.qemupid = process.pid | 1292 | self.qemupid = process.pid |
1240 | retcode = process.wait() | 1293 | retcode = process.wait() |
@@ -1256,7 +1309,8 @@ class BaseConfig(object): | |||
1256 | cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native) | 1309 | cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native) |
1257 | logger.debug('Running %s' % str(cmd)) | 1310 | logger.debug('Running %s' % str(cmd)) |
1258 | subprocess.check_call(cmd) | 1311 | subprocess.check_call(cmd) |
1259 | self.release_lock() | 1312 | self.release_taplock() |
1313 | self.release_portlock() | ||
1260 | 1314 | ||
1261 | if self.nfs_running: | 1315 | if self.nfs_running: |
1262 | logger.info("Shutting down the userspace NFS server...") | 1316 | logger.info("Shutting down the userspace NFS server...") |