Googlefoo failed me.
Need to check if another instance of my app is already running then
- show message
- close this instance or switch to that instance.
Running the app twice is causing database locking issues. Any tips? Thanks.
Enforce just one instance?
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Enforce just one instance?
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
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
Re: Enforce just one instance?
Maybe create, open, check for access to some file.
- zorg
- Party member
- Posts: 3446
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Enforce just one instance?
A simple way would be to have your project create a file when opened, and delete it before it quits (there's a callback for the latter)
The project should check before creating the file if it exists already or not, if it does, it's already running, and it could just shut itself down.
Switching in the sense of closing the other process and having this one be the one running is a bit harder because of the first part, closing another process... not sure how that could be accomplished to be honest. (it's not impossible, but imo it's way more complicated than what it's worth thinking about)
The project should check before creating the file if it exists already or not, if it does, it's already running, and it could just shut itself down.
Switching in the sense of closing the other process and having this one be the one running is a bit harder because of the first part, closing another process... not sure how that could be accomplished to be honest. (it's not impossible, but imo it's way more complicated than what it's worth thinking about)
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Re: Enforce just one instance?
well, in Clickteam Fusion, there exist extension which allow to detect if game opened in other instance or notzorg wrote: ↑Sun Mar 21, 2021 5:28 am A simple way would be to have your project create a file when opened, and delete it before it quits (there's a callback for the latter)
The project should check before creating the file if it exists already or not, if it does, it's already running, and it could just shut itself down.
Switching in the sense of closing the other process and having this one be the one running is a bit harder because of the first part, closing another process... not sure how that could be accomplished to be honest. (it's not impossible, but imo it's way more complicated than what it's worth thinking about)
And if it detect, it will callback "it's another extension"
which can be used to close game, for example:
if copyInstance == true then
love.event.quit()
end
also there exist function which allow to check if this instance original or copy, soo, i guess it's not that hard as it seems
Re: Enforce just one instance?
Write random (time) number to the file, if it changes then there is another process.
Re: Enforce just one instance?
You can also run a local server with a fixed port. Then the other instance can't use the same port.
(The code is just proof of concept)
(The code is just proof of concept)
Code: Select all
local socket = require"socket"
local s, err = socket.bind("0.0.0.0", "8329")
local role = err == "address already in use" and "EXTRA" or "PRIMARY"
local text = ""
if role == "PRIMARY" then
s:settimeout(0)
local servers, clients = {s}, {}
local timer = 0
local default_run = love.run
love.run = function()
runf = default_run()
return function()
ret = runf()
local rlist = socket.select(servers, clients, 0)
for _, client in ipairs(rlist) do
if not clients[client] then
table.insert(clients, client)
clients[client] = #clients
text = "Another instance opened"
timer = 5
else
client:close()
table.remove(clients, clients[client])
clients[client] = nil
end
end
return ret
end
end
love.update = function(dt)
if text == "" then return end
if timer > 0 then timer = timer - dt end
if timer <= 0 then text = "" end
end
else -- if "extra"
local client = socket.tcp()
client:connect("0.0.0.0", "8329")
client:send("PING")
text = "Another instance is running\nPress any key to quit"
love.keypressed = function()
love.event.quit()
end
end
love.draw = function()
love.graphics.print(role, 50, 25)
love.graphics.print(text, 50, 50)
end
Last edited by monolifed on Sat Mar 27, 2021 8:01 pm, edited 1 time in total.
Re: Enforce just one instance?
Yes, I use this method too, although you have to check if that file is locked or not. If the file is there but it's not locked then the previous instance has either crashed or was terminated.A simple way would be to have your project create a file when opened, and delete it before it quits (there's a callback for the latter)
PS. On further examination it appears that Love2d doesn't lock the file when opened in write mode (the io module doesn't support this either).
Any tips on how to lock temporary files would be greatly appreciated!
Re: Enforce just one instance?
What the Qt libraries use for this is a 'shared memory object', something used with IPC ("interprocess communication").
It's a named block of memory that different processes can access and read/write to like a file that exists in system memory. It's got a unique name, that's how different processes can all use this same name to access it.
So when you start your LÖVE game, you first try to open the named memory block. If it fails to open then it doesn't exist yet (as this is the only living instance of your program in the OS session), so you create the named memory block yourself.
If it DOES open it, then you know that the named memory block already exists and there's probably another instance running. I say "probably" because that initial program instance might have crashed and didn't get to destroy the named memory block, so it lingers there (this happens on Linux/Mac systems; on Windows it's destroyed when the program that created it ends).
So provided your program is able to always destroy this shared memory block when it ends (be it from a crash or a successful run), this is a way to have a single app instance.
-----
Now to implement in Lua. This seems to be a (Win/Mac/Linux) cross-platform LuaJIT-FFI-based implementation of this:
https://github.com/luapower/mmap/blob/master/mmap.lua
...but it's got a lot of stuff that maybe you don't need. So for simpler reference there's this C++ library which should be easier to port:
https://github.com/itchio/shoom/tree/master/src
You would port that 'shoom' library, or at least the parts from it you want, by using the code from that Lua library above as reference for how to wrap the OS functions, the constants etc.
It's a named block of memory that different processes can access and read/write to like a file that exists in system memory. It's got a unique name, that's how different processes can all use this same name to access it.
So when you start your LÖVE game, you first try to open the named memory block. If it fails to open then it doesn't exist yet (as this is the only living instance of your program in the OS session), so you create the named memory block yourself.
If it DOES open it, then you know that the named memory block already exists and there's probably another instance running. I say "probably" because that initial program instance might have crashed and didn't get to destroy the named memory block, so it lingers there (this happens on Linux/Mac systems; on Windows it's destroyed when the program that created it ends).
So provided your program is able to always destroy this shared memory block when it ends (be it from a crash or a successful run), this is a way to have a single app instance.
-----
Now to implement in Lua. This seems to be a (Win/Mac/Linux) cross-platform LuaJIT-FFI-based implementation of this:
https://github.com/luapower/mmap/blob/master/mmap.lua
...but it's got a lot of stuff that maybe you don't need. So for simpler reference there's this C++ library which should be easier to port:
https://github.com/itchio/shoom/tree/master/src
You would port that 'shoom' library, or at least the parts from it you want, by using the code from that Lua library above as reference for how to wrap the OS functions, the constants etc.
- zorg
- Party member
- Posts: 3446
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Enforce just one instance?
As another post said, one could check the last modified date, and if the first/main instance hasn't updated that for long enough (on a separate thread perhaps, so visual hangs won't cause any issues), then it's safe to assume that that instance crashed/was terminated and didn't clean up after itself.ivan wrote: ↑Sun Mar 21, 2021 1:20 pmYes, I use this method too, although you have to check if that file is locked or not. If the file is there but it's not locked then the previous instance has either crashed or was terminated.A simple way would be to have your project create a file when opened, and delete it before it quits (there's a callback for the latter)
PS. On further examination it appears that Love2d doesn't lock the file when opened in write mode (the io module doesn't support this either).
Any tips on how to lock temporary files would be greatly appreciated!
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Re: Enforce just one instance?
After some more research, instead of using shared memory objects like I suggested before, there's a safer solution based on this library:
https://github.com/oblique/named-lock/tree/master/src
It uses a named mutex on Windows (so your program can lock that mutex, which is a memory object, and if any other instances try to lock it as well, they'll fail and know that they're not the only instance), and on Linux and Mac it uses a file lock like it's being suggested in this thread, using the "flock" function.
Anyone trying to port this can still use that mmap Lua FFI library as reference for how to wrap the OS functions for use in your Lua code.
This would work for desktop platforms only though -- I don't know how it'd be done using FFI on Android -- and it also assumes that you need it to work on all OSes. The OP hasn't said if this is a requirement. If you only need if for a specific OS then you only need the functions for that OS alone obviously.
On Linux and Mac, the benefit of doing it with file locking instead of writing a timestamp in a file is that the OS becomes a gatekeeper into the file, so you don't have to keep polling it for changes which uses hard disk reads, something that I like to avoid if possible.
https://github.com/oblique/named-lock/tree/master/src
It uses a named mutex on Windows (so your program can lock that mutex, which is a memory object, and if any other instances try to lock it as well, they'll fail and know that they're not the only instance), and on Linux and Mac it uses a file lock like it's being suggested in this thread, using the "flock" function.
Anyone trying to port this can still use that mmap Lua FFI library as reference for how to wrap the OS functions for use in your Lua code.
This would work for desktop platforms only though -- I don't know how it'd be done using FFI on Android -- and it also assumes that you need it to work on all OSes. The OP hasn't said if this is a requirement. If you only need if for a specific OS then you only need the functions for that OS alone obviously.
On Linux and Mac, the benefit of doing it with file locking instead of writing a timestamp in a file is that the OS becomes a gatekeeper into the file, so you don't have to keep polling it for changes which uses hard disk reads, something that I like to avoid if possible.
Who is online
Users browsing this forum: Google [Bot] and 5 guests