Hello, I reported this race condition on itch.io but got no replies so I am posting it again here, in case somebody stumbles on it.
This problem happens when the cart data is in use and the cartridge is quickly restarted.
Consider the following code:
value = 0 frame = 0 function _init() cartdata("race_condition") value = dget(0) dset(0,0) -- set value to 0 for next reload with ctrl+r end function _update() if btnp(5) then dset(0, (value+1)%10) -- increase value by 1 run() -- reset cartridge end frame += 1 end function _draw() cls() print("current value: "..value, value+1) print("frame: "..frame) end |
If you look at it, the expected behavior would be that:
- If you press X, the stored value should increase by 1 (modulus 10) and then the cartridge should restart and load that value.
- If you reset with Ctrl+R, no value is set so it should be reset to 0 because of the dset(0, 0) at the end of the init.
Notice however, that if you run the cartridge and press X, there are 3 possible outcomes:
- Value gets reset to 0.
- Value stays the same.
- Value increases by 1 as intended, but this only seems to happen if the cartridge ran for more than 60 frames.
So my belief is that there is a race condition between the dset() calls of the different times the cartridge is reset, and they fight to write in the cart data.
This behavior seems independent of the target platform, you can try it here:
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/27691/dinnerwashingatsunset.gif)
running this cart through the embedded web player (0.2.6b / firefox 126.0 / linux), I notice the same behavior you describe. But additionally, I can sometimes press X around 40-60 frames, and it will reload with "current value: 1". I got it to work once when I pressed X at 31 frames, although it took many tries (they normally reloaded with value 0).
I think the issue might be that dset()
isn't fully flushing to "disk" (whatever that means in this web context) before run()
resets the cart. I remember @SmellyFishstiks talking about this behavior somewhere else on the BBS (although I may be remembering the wrong person). I thought that was in the context of long-running carts tho, not within the first 60 frames?
It's very interesting that the behavior depends on how long the cart has been running -- I haven't heard of anything like this before
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/42184/spezkit icon4.png)
Ya that was me (https://www.lexaloffle.com/bbs/?tid=52956)
In the end for my problem at least I realized that jumping cdata hoops was way more effort than just storing to memory somewhere.
I think it makes sense that writing to savedata is unpredictable since it's outside of pico but it's odd...
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/82211/7_realshadowcaster.png)
This is wild. I tried to see if the return value of carddata could be of any use... It's not.
More interestingly, I tried to loop in _init while dget(0) is zero. Despite not doing anything aside from looking at dget(0), the value changes, so the calls to dset(0,0) and dset(0,5) that happened before calling run are both taken into account, but both occur with a huge delay. This delay is invisible when you don't use run because dset immediately writes to memory before queuing its demand to "disk" write, and dget is just a memory read that gets the last value.
I suspect all the writes to "disk" happen in the order asked by the program, but the incoherent behavior is due to the program missing some of the change, acting on old values and never looking at the new ones.
Safest "fix" at the moment is to wait a second between the last dset and run, as @SmellyFishstiks had already found out.
[Please log in to post a comment]