@Bruno
Not sure if I got the problem you are describing exactly but what about doing the opposite direction? Make a very simple socket program for Windows that is launched and this program connects to your python application instead. When python notices the connection it is sure that wineserver is running because it just received the connection from an app running inside Wine. Also as long as this small utility is up wineserver won't close too.
Thanks, yes, I have considered this approach (and will likely follow it if everything else does not work). I'd prefer a "pythonic" solution without adding dependencies like a cross-compiler (for compiling the utility) to my module. I am already doing this for tests, but I'd really like to keep the module itself "clean" and easy to install. Just as a theoretical question, could such a utility be implemented as a batch file which wine (cmd) could handle "out of the box"?
@Sebastian
thanks again, this is really helpful.
If you disconnect before the real command is started the wineserver will assume it is no longer needed and terminate automatically. I would say this is a bug, because the user definitely does not expect that when passing "-p".
Is this worth opening a ticket?
Nevertheless, when you keep the connection open, it should actually work (and also does work for me, according to a quick test).
Once my wineserver is up, I try to do a number of path conversion using "winepath -w /some/path" etc. first before I fire up any exe-files. Am I correct in assuming that winepath should also use my wineserver (if run with the same prefix)? Can you check whether your quick test also works with winepath (eliminating a potential source of error)? I managed to turn winepath directly into a zombie a number of times by running winepath (too early) while wineserver was still starting. It does not produce any error messages whatsoever.
A slightly better solution which does not trigger this problem would be to wait for the wineserver lock (which will also appear in the server dir).
I used your code and implemented a routine which waits for the lock-file to be locked - see below this email. Usually, it requires two attempts / about 0.01 seconds until it succeeds. The PID returned by your code matches the PID of my wineserver. The problem is, just after I have confirmed the lock, winepath becomes a zombie again and again and ... occasionally, it works. Is this a bug or a lack of understanding on my part?
There is still a small race-condition (the lock is acquired but the socket has not been created yet), but Wine will be able to deal with that. It will retry a couple of times until it finally succeeds.
Could a failure in this mechanism be the reason for my zombies? (Happens with Wine 2.5, 2.6 and 2.10.)
BTW: As I saw, you replaced the "/tmp" with tempfile.gettempdir(), but this is actually not correct. Wineserver sockets will always be created in /tmp (hardcoded in the source) to ensure the correct socket is found, no matter which environment variables are set.
I did not expect that ... thanks.
Best regards, Sebastian
# Get full path of socket lock_path = os.path.join(self.server_path, 'lock')
# Status log self.log.out('[wine session] Expecting wineserver lock at %s ...' % lock_path)
# Status variable got_lock_pid = False # Time-step wait_for_seconds = 0.01 # Timeout timeout_after_seconds = 30.0 # Already waited for ... started_waiting_at = time.time() # Connection trys tried_this_many_times = 0
# Run loop until socket appears while True:
# Does socket file exist? if os.path.exists(lock_path):
# Count attempts tried_this_many_times += 1
# Open lock file lock_file = open(lock_path, 'rb') # Can I retrieve a PID? lock_pid = self.__get_lock_pid__(lock_file) # Close lock file lock_file.close()
# Check result if lock_pid is not None: got_lock_pid = True break
# Break the loop after timeout if time.time() >= (started_waiting_at + timeout_after_seconds): break
# Wait before trying again time.sleep(wait_for_seconds)
# Evaluate the result if not got_lock_pid:
self.log.out( '[wine session] ... was not locked %d (after %0.2f seconds & %d attempts)! Quit.' % ( timeout_after_seconds, tried_this_many_times ) ) sys.exit()
else:
# Log status self.log.out( '[wine session] ... is locked by PID %d (after %0.2f seconds & %d attempts)!' % ( lock_pid, time.time() - started_waiting_at, tried_this_many_times ) )