Race condition on closing/reopening formspec

For people working on the C++ code.
Post Reply
zeuner
Member
Posts: 43
Joined: Fri Dec 01, 2017 20:09
GitHub: zeuner

Race condition on closing/reopening formspec

by zeuner » Post

I'm running into an issue where sometimes, a formspec triggered by the server won't become visible on the client because of a race condition when another form is closed about at the same time:

Normally, GUIFormSpecMenu::~GUIFormSpecMenu gets called right after GUIModalMenu::quitMenu, and afterwards, opening a formspec through handleCommand_ShowFormSpec works by creating a new object.

Rarely, handleCommand_ShowFormSpec gets processed after GUIModalMenu::quitMenu but before GUIFormSpecMenu::~GUIFormSpecMenu gets called. In these cases, GUIFormSpecMenu::setFormspecPrepend et al are called on the formspec object which is about to close, and are never seen by the client.

Any ideas? Maybe this processing could be (partially) serialized so a formspec object where the client already knows it will close will not be used to provide new dialogs.

User avatar
sorcerykid
Member
Posts: 1502
Joined: Fri Aug 26, 2016 15:36
GitHub: sorcerykid
In-game: Nemo
Location: Illinois, USA

Re: Race condition on closing/reopening formspec

by sorcerykid » Post

Try doing `minetest.after`with 0s delay, as that will make the new form show one tick after the other one closed.

karamel
Member
Posts: 42
Joined: Wed Jul 19, 2017 21:51

Re: Race condition on closing/reopening formspec

by karamel » Post

From what I understand handleCommand_* are executed on packet receive. And Minetest uses UDP, which has no constraint on the order in which the packets are received (to be faster than TCP). If you call minetest.close_formspec("player_name", "my_formspec", formspec) and minetest.open_formspec("player_name", "my_formspec", [other_]formspec) almost at the same time, 2 packets are sent and there is no guaranty that close is executed before open on the client side.

If you are lucky both packets are treated during the same loop and you may check for concurrent packet. If you are not lucky close may be treated during the next loop and there will be no way to know if there was a concurrent packet.

Could you give an example showing when this happens sometime? I suppose it is for updating the currently displayed formspec. There may be other way to do it, like not closing it or using a variable formname according to the content. I don't know, I haven't tested it outside player inventory formspec which has a `set` method.

`doc` from Wuzzy's minetest_doc_modpack updates the currently viewed formspec by never closing it.

Using a timer or after can do the trick almost at all time and virtually solve the issue, but there is logically no guaranty that it works 100% of the time if it is really an UDP packet order issue. If it is not, well, you may discard this post :)

User avatar
v-rob
Developer
Posts: 816
Joined: Thu Mar 24, 2016 03:19
GitHub: v-rob
IRC: v-rob
Location: Right behind you.

Re: Race condition on closing/reopening formspec

by v-rob » Post

If this is a problem caused by using minetest.close_formspec followed by minetest.show_formspec to update a form, don't close the formspec at all. minetest.close_formspec should only be used for just that -- closing the formspec. minetest.show_formspec both shows and reshows (updates) a formspec without minetest.close_formspec even necessary.
GUI Core Developer | My Best Mods: Bridger - Slats - Stained Glass | To contact me, send a PM

micheal65536
Member
Posts: 167
Joined: Mon May 22, 2017 20:27

Re: Race condition on closing/reopening formspec

by micheal65536 » Post

sorcerykid wrote:Try doing `minetest.after`with 0s delay, as that will make the new form show one tick after the other one closed.
As far as I can understand from his description of the problem, I think his issue is either that the client is ignoring a new form from the server if the user happens to close an existing from on the client at the exact same time/within the same client tick, or that the server isn't sending out a new form to the client if the server receives a close event for an existing form from the client at the exact same time/within the same server tick. In either case, using minetest.after won't fix it as there could equally be a race condition in the following tick (if it is indeed a race condition between an action on the server and an independent action on the client/user that the server has no control over).

micheal65536
Member
Posts: 167
Joined: Mon May 22, 2017 20:27

Re: Race condition on closing/reopening formspec

by micheal65536 » Post

karamel wrote:From what I understand handleCommand_* are executed on packet receive. And Minetest uses UDP, which has no constraint on the order in which the packets are received (to be faster than TCP). If you call minetest.close_formspec("player_name", "my_formspec", formspec) and minetest.open_formspec("player_name", "my_formspec", [other_]formspec) almost at the same time, 2 packets are sent and there is no guaranty that close is executed before open on the client side.

If you are lucky both packets are treated during the same loop and you may check for concurrent packet. If you are not lucky close may be treated during the next loop and there will be no way to know if there was a concurrent packet.
From a quick look at the source code (network/connection.cpp and network/connection.h) combined with my (limited) knowledge of Minetest's networking behavior, I'm fairly certain that Minetest implements its own packet ordering. Otherwise other "glitches" resulting from out-of-order packets (nodes vanishing after being placed, chat messages especially automated ones appearing out of order, etc.) would be common enough that you would hear about it, and even over very laggy and unreliable network connections I have never experienced anything like this myself.

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests