monolified's approach has the advantages of being cross-platform, atomic and standard, and doesn't give false positives in case of a crash, over any other solution presented so far.
local instance_detector -- keep it live until the application finishes
do
local tcp = require 'socket'.tcp
instance_detector = tcp()
if not instance_detector:bind('127.0.0.1', 16219) then
print("An instance is already running, closing")
return love.event.quit()
end
end
Some great ideas. I was wondering if Love2D can check for all instance/apps/programs running and then if one of those matches my program then I can quit?
I don't want to troll through every service but when I open task manager I can see there are five apps running now (for example) so I'd just step through that looking for a text value. Possible?
Current project: https://togfox.itch.io/hwarang
A card game that brings sword fighting to life. Simple to learn, hard to master. Learn when to advance, dodge, strike and counter. Learn how to strike without being struck. https://discord.gg/HeHgwE5nsZ
I think you can probably do that via C FFI, but you'd have to do it on a per-platform basis. Additionally, I don't think reading the application window or process name is a good idea, as that can, depending on circumstances, create false-positives. Sure, games' titles often can be a bit more unique and less generic, but you'd still have to make sure that your process' name doesn't interfere with anything else. This approach also doesn't necessarily solve the problem in the event the application hangs, but still remains in the active processes list for some time before exiting. Furthermore, there may be some circumstances where your application doesn't have the rights to read other processes' titles, but this is probably a platform and environment specific thing.
The code pgimeno posted basically already does all you need - just make the port number configurable and you're good to go.
function other_instance_running()
if exists(lockfile) then
port = read_port_from(lockfile)
socket = bind_local_socket(port)
if not succeeded(socket) then
return true
end
delete(lockfile)
end
return false
end
function start_instance_guard()
repeat
port = love.math.random(49152, 65535) -- or loop over the whole range
socket = bind_local_socket(port)
until succeeded(socket)
write_port_to(lockfile, port)
end
function love.quit()
delete(lockfile)
return false
end
edit: fixed some ambiguity
Last edited by grump on Wed Mar 31, 2021 11:37 am, edited 1 time in total.
My only concern is which method uses less (CPU) resources. I don't know if using a listening socket to behave like a global mutex in this way involves any redundant polling from the OS or not.
My concern with grump's approach is the lack of atomicity (a time-of-check to time-of-use race; if two instances are launched at the same time, it's possible that neither detects the other), but I guess that's too strict for practical situations.
The socket solution is clever but it's hacky.
We need to open an issue request to include love.filesystem.lock in the next version of love2d.
lfs.lock seems to available in similar libraries
ivan wrote: ↑Wed Mar 31, 2021 12:42 pm
We need to open an issue request to include love.filesystem.lock in the next version of love2d.
If you want this to happen, you have to submit a pull request yourself, and PhysFS does not seem to support file locking, so it's not going to integrate super well with the filesystem API.
And even then... LÖVE is moving at a glacier's pace with its weird release cycle. Not enough manpower I guess.