Monitor wine processes

This commit is contained in:
Mathieu Comandon 2015-03-05 03:58:40 +01:00
parent 5d3b1f3666
commit dabd331d8f
6 changed files with 41 additions and 14 deletions

View file

@ -198,7 +198,7 @@ class Game(object):
self.killswitch = None
self.game_thread = LutrisThread(launch_arguments,
path=self.runner.working_dir, env=env,
runner=self.runner, env=env,
rootpid=gameplay_info.get('rootpid'))
self.state = self.STATE_RUNNING
if hasattr(self.runner, 'stop'):

View file

@ -199,5 +199,5 @@ class steam(Runner):
appid = self.game_config.get('appid')
logger.debug("Launching Wine Steam uninstall of game %s" % appid)
command = '"%s" steam://uninstall/%s' % (self.steam_exe, appid)
thread = LutrisThread(command, path=self.working_dir)
thread = LutrisThread(command, runner=self)
thread.start()

View file

@ -203,7 +203,6 @@ def is_version_installed(version, arch=None):
class wine(Runner):
"""Run Windows games with Wine."""
human_name = "Wine"
executable = 'wine'
platform = 'Windows'
game_options = [
{
@ -262,6 +261,14 @@ class wine(Runner):
"Desktop": r"%s\Explorer" % reg_prefix
}
core_processes = (
'services.exe',
'winedevice.exe',
'plugplay.exe',
'explorer.exe',
'rpcss.exe',
)
def __init__(self, config=None):
super(wine, self).__init__(config)
wine_versions = \
@ -510,6 +517,13 @@ class wine(Runner):
env['WINEPREFIX'] = self.prefix_path
return env
def get_pids(self):
"""Return a list of pids of processes using the current wine exe"""
exe = self.get_executable()
if not exe.startswith('/'):
exe = system.find_executable(exe)
return system.get_pids_using_file(exe)
def play(self):
game_exe = self.game_exe
arguments = self.game_config.get('args') or ''

View file

@ -336,5 +336,5 @@ class winesteam(wine.wine):
env = self.get_env()
command = self.launch_args + ['steam://uninstall/%s' % appid]
self.prepare_launch()
thread = LutrisThread(' '.join(command), path=self.working_dir, env=env)
thread = LutrisThread(' '.join(command), runner=self, env=env)
thread.start()

View file

@ -16,12 +16,14 @@ HEARTBEAT_DELAY = 5000 # Number of milliseconds between each heartbeat
class LutrisThread(threading.Thread):
"""Runs the game in a separate thread"""
def __init__(self, command, path="/tmp", env={}, rootpid=None):
debug_output = False
def __init__(self, command, runner=None, env={}, rootpid=None):
"""Thread init"""
threading.Thread.__init__(self)
self.env = env
self.command = command
self.path = path
self.runner = runner
self.game_process = None
self.return_code = None
self.rootpid = rootpid or os.getpid()
@ -29,7 +31,11 @@ class LutrisThread(threading.Thread):
self.stdout = ''
self.attached_threads = []
self.cycles_without_children = 0
logger.debug('Running thread from %s', self.path)
if self.runner:
self.path = runner.working_dir
else:
self.path = '/tmp/'
def attach_thread(self, thread):
"""Attach child process that need to be killed on game exit"""
@ -45,15 +51,22 @@ class LutrisThread(threading.Thread):
cwd=self.path, env=self.env)
for line in iter(self.game_process.stdout.readline, ''):
self.stdout += line
sys.stdout.write(line)
if self.debug_output:
sys.stdout.write(line)
def iter_children(self, process, topdown=True):
def iter_children(self, process, topdown=True, first=True):
if self.runner.name.startswith('wine') and first:
pids = self.runner.get_pids()
for pid in pids:
wineprocess = Process(pid)
if wineprocess.name not in self.runner.core_processes:
process.children.append(wineprocess)
for child in process.children:
if topdown:
yield child
gen = self.iter_children(child)
for c in gen:
yield c
subs = self.iter_children(child, topdown=topdown, first=False)
for sub in subs:
yield sub
if not topdown:
yield child

View file

@ -174,8 +174,8 @@ def get_pids_using_file(path):
"""Return a list of pids using file `path`"""
if not os.path.exists(path):
logger.error("No file %s", path)
return
lsof_output = execute("lsof -t \"{}\"".format(path))
return []
lsof_output = execute(["lsof", "-t", path])
if lsof_output:
return lsof_output.split('\n')
else: