WIP: Prevent Mu from opening more than one instance
It's quite common for Mu to be slow enough to start that users grow impatient and start a second instance. This will then cause problems as both will try to, eg, create the same virtual environment.
This PR -- as a prototype -- uses the Qt Shared Memory wrapper to effect a Mutex which will prevent any further instance from opening while one is already running
This pull request introduces 2 alerts when merging 45f330f2b55980ad7a5155a3b670492afd9684fe into b9d08e39490eb3f5d8a57b929a24158bba383753 - view on LGTM.com
new alerts:
- 2 for Unused import
This pull request introduces 2 alerts when merging 96a85346dbc0c6961c807888818d7a0994d50721 into 9fe47acf97096649d94cd26b379247f73e74d6ee - view on LGTM.com
new alerts:
- 2 for Unused import
Current state of play: Mu will detect that another instance is blocking it and will report the PID of the blocking instance. Also, all instance now log their PID with the logging header block to assist this (and other) debugging.
If a running instance is detected, the starting instance logs the fact and exits with error code 2
Still to do: the shared memory approach we're using to act as an interprocess Mutex operates slightly differently on *nix vs Windows. We need to add some cleanup code on *nix; on WIndows by contrast the OS owns the shared memory and will clean up after itself.
In macOS I get this exception
2022-07-20 10:54:39,781 - root:174(excepthook) ERROR: Unrecoverable error
Traceback (most recent call last):
File "run.py", line 6, in <module>
run()
File "/Users/microbit-carlos/workspace/carlos/mu/mu/app.py", line 310, in run
_shared_memory.acquire()
File "/Users/microbit-carlos/workspace/carlos/mu/mu/app.py", line 285, in acquire
self._shared_memory.data()[:4] = struct.pack("l", os.getpid())
ValueError: cannot modify the size of a sip.voidptr object
And then the next run this:
Traceback (most recent call last):
File "run.py", line 6, in <module>
run()
File "/Users/microbit-carlos/workspace/carlos/mu/mu/app.py", line 311, in run
_shared_memory.acquire()
File "/Users/microbit-carlos/workspace/carlos/mu/mu/app.py", line 281, in acquire
pid = struct.unpack("l", self._shared_memory.data()[:4])
struct.error: unpack requires a buffer of 8 bytes
Looks like on my Python (64 bit build) long is 8 bytes:
Python 3.7.12 (default, Feb 16 2022, 19:03:18)
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.architecture()
('64bit', '')
>>> import struct
>>> struct.calcsize("h") # short
2
>>> struct.calcsize("i") # int
4
>>> struct.calcsize("I") # unsigned int
4
>>> struct.calcsize("l") # long
8
>>> struct.calcsize("q") # long long
8
>>>
Thanks for the comments, @carlosperate. I realise that I have unpushed changes on my local branch, several of which will address some of the points you raise. I'll try to do a housekeeping push later.
Any movement on this..?
I gave this a quick run in macOS and worked as expected 👍