Jump to content
The simFlight Network Forums

Lua crash.


Recommended Posts

Bonjour Pete,

 

Here is my problem.

I have a lua script which drives a Saitek FIP (Flight Instrument panel). 

In this lua several functions from the Event Library included a timer. There is also a callback function used when a button on the FIP is pressed or when a rotary dial is done.

Everything is working well except when the FIP Callback function is in competition with an event function. The Wideclient or fsx crash  with codes like 0xC0000029 (STATUS_LONJUMP) or 0x80000026 (STATUS_INVALIS_UNWIND_TARGET).

I also find in the log information such as Lua error 1.. Lua error 0... Lua error... on the line xx call to a nil function (on this line there is no call to a function)....

 

I have the feeling that the stack is corrupted when the FIP callback and the event want to run concurrently.

 

Do you have an idea ?

Cheers, 

Claude

 

Link to comment
Share on other sites

I have a lua script which drives a Saitek FIP (Flight Instrument panel). 

In this lua several functions from the Event Library included a timer. There is also a callback function used when a button on the FIP is pressed or when a rotary dial is done.
Everything is working well except when the FIP Callback function is in competition with an event function. The Wideclient or fsx crash  with codes like 0xC0000029 (STATUS_LONJUMP) or 0x80000026 (STATUS_INVALIS_UNWIND_TARGET).
I also find in the log information such as Lua error 1.. Lua error 0... Lua error... on the line xx call to a nil function (on this line there is no call to a function)....
 
I have the feeling that the stack is corrupted when the FIP callback and the event want to run concurrently.
 
Do you have an idea ?

 

No, not without more information! I can't even envisage what you are talking about with the little you say I'm afraid.

 

First please state version numbers -- FSUIPC and WideClient.

 

It would of course help to know where this "callback" function is, because my Lua libraries don't have anything like one -- events are the closest to callbacks. And why not show the actual Windows crash event data -- at least that shows also the module name and offset within it? That's always useful.

 

I am also confused by the mention of "WideClient or FSX". Where is this lua plugin running, and are you getting assorted errors on both PCs?  Finally, do the errors logged in Lua correspond to the time you get the crash and if so where?

 

Maybe you need to show the log too, along with the Lua program it corresponds with?

 

Pete

Link to comment
Share on other sites

Hi,

Merci Pete for your answer... and thank you for taking time to look in my problem.

 

FSUIPC 4.947c

WideClient 6.999n

 

The callback function is from the "Saitek Flight Panels for Lua " downloaded from this site.... http://www.super-hornet.com/ and is not from your library but is supposed to work with FSUIPC.
I join the documentation as an attached file.

I found this package from user contribution, and it works very well except the problem I described when the callback function compete with the event one.

 

I first discover the problem on the WideCleint, and to narrow the problem I run my script from FSX just to test..... with the same behavior.

 

1 some error log, which happens at the time of crash.

********* LUA: "FIP" Log [from WideClient] *********

Date (dmy): 13/02/16, Time 15:20:59.347: Client name is ASUS
     5569 LUA: beginning "C:\WideClient\FIP.lua"
    14602 *** LUA Error: attempt to call a number value
    14726 *** LUA Error: 1
 
********* LUA: "FIP" Log [from WideClient] *********
Date (dmy): 13/02/16, Time 15:30:12.011: Client name is ASUS
     5569 LUA: beginning "C:\WideClient\FIP.lua"
    22121 *** LUA Error: attempt to call a number value
    25506 *** LUA Error: attempt to call a number value
    27768 *** LUA Error: attempt to call a number value
    29390 *** LUA Error: attempt to call a number value
    29515 *** LUA Error: 1
 
 
2 Event manager (in french...)

 

Nom de l’application défaillante WideClient.exe, version : 6.9.9.9, horodatage : 0x53ba88bf
Nom du module défaillant : ntdll.dll, version : 6.1.7601.19110, horodatage : 0x5684255b
Code d’exception : 0xc0000029
Décalage d’erreur : 0x00090b0a
ID du processus défaillant : 0x23ec
Heure de début de l’application défaillante : 0x01d1666b0889e144
Chemin d’accès de l’application défaillante : C:\WideClient\WideClient.exe
Chemin d’accès du module défaillant: C:\Windows\SysWOW64\ntdll.dll
ID de rapport : 58344eae-d25e-11e5-957f-e0b9a5f8c339

 

or

 

Nom de l’application défaillante WideClient.exe, version : 6.9.9.9, horodatage : 0x53ba88bf
Nom du module défaillant : WideClient.exe, version : 6.9.9.9, horodatage : 0x53ba88bf
Code d’exception : 0xc0000005
Décalage d’erreur : 0x00031c69
ID du processus défaillant : 0x2f2c
Heure de début de l’application défaillante : 0x01d1666a8282399d
Chemin d’accès de l’application défaillante : C:\WideClient\WideClient.exe
Chemin d’accès du module défaillant: C:\WideClient\WideClient.exe
ID de rapport : cd8ef1b9-d25d-11e5-957f-e0b9a5f8c339
 
or
 
Nom de l’application défaillante WideClient.exe, version : 6.9.9.9, horodatage : 0x53ba88bf
Nom du module défaillant : unknown, version : 0.0.0.0, horodatage : 0x00000000
Code d’exception : 0x80000026
Décalage d’erreur : 0x7495cb49
ID du processus défaillant : 0x2d64
Heure de début de l’application défaillante : 0x01d1666a46d59ffe
Chemin d’accès de l’application défaillante : C:\WideClient\WideClient.exe
Chemin d’accès du module défaillant: unknown
ID de rapport : 97570f9d-d25d-11e5-957f-e0b9a5f8c339
 
3 my lua script.
require("saitek");
require("gd");
 
delta = 5
N1_min_display = "20"
N1_min = 20
N1 = 0
angle = 0
centre_x = 148
centre_y = 123
old_indice_throttle = 1
angle_throttle = 0
 
------------------------------------------------------------
function round(num, idp)
  local mult = 10^(idp or 0)
  return math.floor(num * mult + 0.5) / mult
end
 
-----------------------------------------------------------
function change_N1_min(model, index, state)
--print("state " .. state)
if state == 2 then N1_min = N1_min + 0.1 
elseif state == 4 then N1_min = N1_min - 0.1 
elseif state == 8 then N1_min = N1_min + 1 
elseif state == 16 then N1_min = N1_min - 1 
elseif state == 32 then 
N1_min_display = ""
saitek.SetLed('SFIP', 1, 1, 1, false)
saitek.SetLed('SFIP', 1, 1, 6, false)
return
elseif state == 1024 then 
N1_min_display = ""
saitek.SetLed('SFIP', 1, 1, 1, false)
saitek.SetLed('SFIP', 1, 1, 6, false)
return
 
end
---------------------------------------------------------------------
N1_min_display = N1_min
 
--print ("N1_min_display " .. N1_min_display)
redrawAll_N1()
saitek.SetLed('SFIP', 1, 1, 1, true)
saitek.SetLed('SFIP', 1, 1, 6, true)
end
saitek.RegisterSoftButtonDownCallback("SFIP", 1, "change_N1_min")
 
-- Creation image
N1_im = gd.createTrueColor(320, 240);
N1_ib = gd.createFromPng("Gauges//N1//N1T.png");
N1_id = gd.createTrueColor(2, 212); --angle N1
N1_is = gd.createTrueColor(1, 212);
 
black = N1_im:colorAllocate(0, 0, 0);
white = N1_im:colorAllocate(255, 255, 255);
grey = N1_im:colorAllocate(124, 124, 124); 
N1_im:filledRectangle(0, 0, 320, 240, black);
 
 
N1_id:colorTransparent(black)
N1_id:filledRectangle(0, 0, 2, 212, black);
N1_id:filledRectangle(0, 106, 2, 196, white);
N1_id:filledRectangle(1, 197, 2, 212, white);
 
N1_is:colorTransparent(black)
N1_is:filledRectangle(0, 0, 1, 212, black);
N1_is:filledRectangle(0, 197, 1, 212, white);
 
-------------------------------------------------------------------------------------------
function redrawAll_N1()
 
N1_im:filledRectangle(0, 0, 320, 240, black);
angle = round((90-((N1/102.8)*206)), 2) -- calcul angle N1
gd.copyRotated(N1_im, N1_id, centre_x, centre_y, 0, 0, 2, 212, (angle));
angle = -(angle - 90)
N1_im:filledArc(centre_x, centre_y, 190, 190, 0, angle, grey, gd.PIE)
 
gd.copyResized(N1_im, N1_ib, 20, 20, 0, 0, 286, 209, 286, 209);
N1_im:stringFT(white, "Arial", 30, 0, 180, 100, N1)
N1_im:stringFT(white, "Arial", 20, 0, 10, 30, N1_min_display)
-- envoi de l'image au FIP
saitek.SetImage("SFIP", 1, 1, 1, N1_im:gd2Str(320, gd.GD2_FMT_RAW));
 
end
 
------------------------------------------------------------------------------------------
-- N1 a changé
function N1_change(offset, value)
N1 = (100/16384) * value;
N1 = round(N1,1)
redrawAll_N1();
--print ("N1 " .. N1)
end
 
event.offset(0X0898, "UW", "N1_change");
 
-------------------------------------------------------------------------------------------------------------------------
 
Thank you Pete
Best regards
Claude
 
 

 

 

DOC.TXT

Link to comment
Share on other sites

FSUIPC 4.947c

WideClient 6.999n

 

The callback function is from the "Saitek Flight Panels for Lua " downloaded from this site.... http://www.super-hornet.com/ and is not from your library but is supposed to work with FSUIPC.

I join the documentation as an attached file.

I found this package from user contribution, and it works very well except the problem I described when the callback function compete with the event one.

 

I first discover the problem on the WideCleint, and to narrow the problem I run my script from FSX just to test..... with the same behavior.

 

I suspect that the problem is because the Lua interpreter is actually not running whilst an event is awaited.  The Lua plug-in is effectively "dead" until revived by the event occurring. The thread itself is still running however, checking for the event conditions. As soon as the event occurs, my code in the thread is attempting to call the event function.

 

I assume the code creating the callback itself must be running in a separate thread, otherwise effectively FSUIPC would not be able to check for its events -- that thread is running in the callback checker. So, when that separate thread then attempts to call the specified callback function, in my thread, then no matter which comes first, callback or event, things become very precarious. Who is now controlling the code flow? How is the Lua interpreter going to deal with re-entry when it is already executing?

 

I can see why the stack could get completely corrupted.

 

I don't see any way out of that. As far as I can see it's a design impossibility (or certainly a designer's nightmare!). It would have been better for that Saitek DLL to signal its intervention with your call supplying an offset to be changed so that you could have an event based on that (as well as the one you have). FSUIPC processes one event at a time, so they would be properly sequenced.

 

Unless that DLL can be changed I suggest your only recourse it to avoid using the event and instead use an infinite loop, checking your event offset each time. You'd probably need to include an ipc.sleep call for performance reasons, but at east the Lua interpreter is still active though the thread be suspended.

 

BTW please update your FSUIPC. I don't support old versions. Current is 4.949f.

 

Pete

Link to comment
Share on other sites

Actually, after having a long think after I posted the above reply, I realised that I don't really understand how callbacks, such as the one you have, actually work.

 

I must presume that the callback function is executed in the same thread as the rest of the plug-in, the one FSUIPC or WideClient specifically created for it. If so then since execution of a thread can only take place once -- i.e not in two places simultaneously -- the execution by FSUIPC of its scan for events and its ultimate call to the event function when one occurs -- must be suspended whilst the callback function is being executed. Therefore, if this logic is correct, you can't actually get both happening together. 

 

The "stack" we are talking about for Lua is not the normal CPU processor stack, of which there's one per thread, but its own data area storing all sorts of things including variables, functions, and so on. Where my mind rather boggles is trying to work out how all that is handled when the Saitek callback is called after FSUIPC has effectively exited the Lua program part altogether, pending the event.

 

I'm getting rather old for all this complexity. These things used to be easy, but I have fewer working little grey cells these days (blame the beer and wine! :cry: ).I think we might need assistance from the clever chap who wrote that Saitek DLL. Do you have contact with him? Have you asked for his help too, already?

 

Pete

Link to comment
Share on other sites

Bonsoir Pete,

Unfortunately the use of infinite loop instead of the event doesn't work...
 

I will try to contact the clever guy who wrote the saitek.dll, but I know he is very busy with other stuff.

I did not ask for his help on this particular problem, but I have his contact. 

 

Thanks again... I will let you know what is his thinking..

Cheers

Claude

Link to comment
Share on other sites

Unfortunately the use of infinite loop instead of the event doesn't work...

 

Hmm. Even with a sleep included? In what way didn't it work? I assume it doesn't crash. Does it just not get any of the callbacks?

 

Without understanding how it works I really can't explain that.

 

 

I will try to contact the clever guy who wrote the saitek.dll, but I know he is very busy with other stuff.

I did not ask for his help on this particular problem, but I have his contact. 

 

Thanks again... I will let you know what is his thinking..

 

Yes, please. I'd be most interested.

 

Pete

Link to comment
Share on other sites

After sleeping on it I awoke with a little more clarity of thought (though re-reading it I see it actually might be more cloudiness of thought!)

 

I think that it is likely that the saitek DLL is using the Windows callback mechanism to allow it to instigate its callback, in the same thread as the Lua plug-in. Windows will be seeing to the preservation of registers and stack whilst the callback is in operation, and resume that once the called-back function exits.

 

However, I think there must be some sort of clever mechanism programmed to prevent the said Lua plug-in being "called back" whist it is actually running. Because the Lua stack and so on is NOT the machine-aided stack maintained by the Windows mechanism, but its own data structure. The only safe time for the Lua callback function to be called is whilst an event is being awaited.

 

That is probably why it doesn't work if you do not use events.

 

However, since you find it crashing when the event occurs "at the same time" (really meaning, probably, just before, very close in time -- they cannot happen actually at the same time), I suspect this means it happens just AFTER the FSUIPC code has made the call into the Lua interpreter to execute the event function.

 

So the problem is likely a defect in the way the Saitek DLL is somehow detecting when it is safe to execute the callback. I've no idea how it would tell that the Lua thread is engaged inside the Lua interpreter, but it would seem that whatever method is used it is not foolproof.

 

This raises a question, though. It this is indeed what is happening, and the plug-in has to use events for it to work in the first place, then how would it ever work without danger of a crash for any plug-in using it? One must suppose that others are using it, and that it has been tested -- so what is different about the others? Or do they only use some more predictable event, like event.timer, which is somehow detected by the DLL?

 

To investigate that you could try one more alternative -- a timer event instead of an infinite loop, reading and testing the offset each time.

 

Pete

Link to comment
Share on other sites

Hi Pete,

 

That is probably why it doesn't work if you do not use events.

 

Yes it is worst.

Trying to narrow the problem I avoid using saitek.dll calls except the initialisation and the callback but it is the same.

 

If I stay longer in the callback by using an ipc.sleep the crash is immediate with the same error code as before. 

 

Saitek DLL is somehow detecting when it is safe to execute the callback

Isn't it the same problem for the event or timer, How could you know the callback is running.

 

a timer event instead of an infinite loop

 

Same crash. 

 

I will send a email to the saitek.dll developper tomorrow. He has an account on your forum, may be he will be able to intervene in this post to discuss with you.

You have already discuss with him in 2011...

 

http://forum.simflight.com/topic/68309-lua-capabilities/page-3#entry429053

 

Have a good day.

Cheers

Claude

Link to comment
Share on other sites

Just to add ...

In my previous post I said:

 

Isn't it the same problem for the event or timer, How could you know the callback is running.

the event is able to know that the callback is running... I do not how he knows, but I am sure of that.

By increasing the ipc.sleep in the callback, the event only fire when the sleep ended.

Claude

Link to comment
Share on other sites

If I stay longer in the callback by using an ipc.sleep the crash is immediate with the same error code as before. 

 

 

Because you are allowing longer for the Event to occur, so there's more chance of it occurring and FSUIPC trying to reenter the Lua interpreter whilst it is already running.

 

Isn't it the same problem for the event or timer, How could you know the callback is running.

 

 
No, because I never had any reason to suspect anything else would ever enter the Lua interpreter in the thread I created specifically for it. I don't have a clue how to tell if something has done. Maybe it is possible, maybe not. If the DLL author has a clue I could try protecting things my end, of course

 

 

You have already discuss with him in 2011...

 

 

 

Okay. Thanks. I'll take a look.
 

the event is able to know that the callback is running... I do not how he knows, but I am sure of that. 

.By increasing the ipc.sleep in the callback, the event only fire when the sleep ended.

 

That is only because the sleep applies to the whole thread. the thread is suspended till the end of the sleep. no events are checked by the thread until the sleep ends. I've no idea at present how my part of the thread code can check that something else hasn't already called the interpreter in the same thread. Maybe I can do something like check it's internal stack memory position, if I can find it. Or place some sort of unique value (a generated GUID) on the stack and see if it is still the top item. Sounds a bit dodgy though.

 

Pete

Link to comment
Share on other sites

Just to let you know that I received an answer from Chris Apers, who is the author of the saitek.dll. He will have a look to this post.

 

his dll is a must because whithout it it is very difficult to communicate with the FIP. The sdk provide by saitek if very complicate, the doc and the support are inexistant. 

Claude

Link to comment
Share on other sites

OK, finally remembered my password! :)

 

I put the Saitek DLL source code on GitHub: https://github.com/chrilith/Passerelle

 

I'll do some cleanup and doc (so that anyone can compile it easily), and start working on this specific crash problem.

 

Pete pointed the problem: this module is using classic Windows callbacks. So, I'll look at this event stuff and see if I can prevent race conditions.

Should not be too difficult (hopefully).

 

Claude, can you tell me what version of the Saitek FIP driver you are currently using?

 

Thanks!

Link to comment
Share on other sites

Pete pointed the problem: this module is using classic Windows callbacks. So, I'll look at this event stuff and see if I can prevent race conditions.

Should not be too difficult (hopefully).

 

An easy solution would be for the calling program to provide you with an offset number which you could change to signal the event. Then, if in a loop, the plug-in could simply test the offset value from time to time, and/or use event.offset.

 

If you need to feed back more information then I could instead allocate your DLL some offset memory space for fixed use. But I'm not sure if the DLL needs to be capable of multiple simultaneous use.

 

Pete

Link to comment
Share on other sites

An easy solution would be for the calling program to provide you with an offset number which you could change to signal the event. Then, if in a loop, the plug-in could simply test the offset value from time to time, and/or use event.offset.

 

If you need to feed back more information then I could instead allocate your DLL some offset memory space for fixed use. But I'm not sure if the DLL needs to be capable of multiple simultaneous use.

 

Pete

 

Thanks Pete, but yes, the DLL can be used simultaneously by multiple scripts. Your event.offset is still one of the solution, will check more deeply your documentation.

 

Reading posts here and there, even if I use coroutine, I'm not guaranteed to not corrupt something... but will try this anyway with lua_newthread() and locking.

 

Other solutions are:

 

- Add some kind of queueing: may lead to some synching problem in reg/unreg of callbacks

- Add socket-based communication

 

I'l study these 4 options!

 

Thanks

Link to comment
Share on other sites

I'l study these 4 options!

 

Another option would be for the plug-in to supply your function with the name of a variable it has previously defined which you could then change. Unfortunately that way doesn't allow events on changes so the variable would need testing n a loop or on a Timer event.

 

Pete

Link to comment
Share on other sites

Hum... unless I implement lua_lock/unlock, this will be the same problem since the callback is raised from an external thread, no?

 

I mean, changing the state of a variable in the global space need access synchonization on the Lua state to prevent corruption, without the lock, an external thread may corrupt the state (as it is currently using lua_pcall() from the callback).

 

Or I didn't get the point?

Link to comment
Share on other sites

Hum... unless I implement lua_lock/unlock, this will be the same problem since the callback is raised from an external thread, no?

 

I mean, changing the state of a variable in the global space need access synchonization on the Lua state to prevent corruption, without the lock, an external thread may corrupt the state (as it is currently using lua_pcall() from the callback).

 

Or I didn't get the point?

 

No, you are right. I was looking at it too simplistically.

 

Pete

Link to comment
Share on other sites

  • 2 weeks later...

Hi Pete,

 

So, we did some tests with Claude using lua_newthread() API function and even if it seems a bit more stable with FSUIPC it really seems that I cannot properly sync access to Lua with it. Also, event.offset() will, in most cases, take precedence over the DLL Lua calls.

 

So, as you proposed, an offset should do the trick as FSUIPC will be responsible for the synchronization and thread access.

Are you still OK to provide one specifically for my module?

In the meantime, can I use the 0x8001 used in your SDK sample code for testing purpose?

 

Thank you!

Link to comment
Share on other sites

So, as you proposed, an offset should do the trick as FSUIPC will be responsible for the synchronization and thread access.

Are you still OK to provide one specifically for my module?

In the meantime, can I use the 0x8001 used in your SDK sample code for testing purpose?

 

I'll reserve 736D. I think 8001 might be overwritten by other things internal to FSUIPC and WideFS. -- there are 0x300 bytes for them to talk about things.

 

So you'll change the offset to indicate a callback, right?

 

Suppose there's more than one plug-in all using your software - they'd all get the same callback?  Maybe some way of differentiating them will be necessary. Not sure how. And what about the parameters supplied to the callback function? Perhaps you'll need rather more than one offset, or even code assistance in FSUIPC?

 

Pete

Link to comment
Share on other sites

Thanks Pete.

 

Regarding your question, I have an internal script management based on the Lua state address.

 

I think I'll add some kind of internal event queuing and a function to process the message from Lua to be sure the callback is executed in the correct context.

Like this, the data is limited to an event index or address.

 

Will see if this can work.

 

I'll first add this queing system decoupling it from FSUIPC so that it can be used in any Lua script, then add the FSUIPC layer.

 

Thx

Link to comment
Share on other sites

Hi again,

 

It seems that I have a working version, without using FSUIPC offset for now.

 

I have a quick question regarding Lua execution in FSUIPC.

 

As my code is now polling for events, I'm using something like this in my test script:

 

event.offset(...Some offset to check...);
 
while true do
    passerelle.poll();   -- polling for events related to the callbacks and auto-execute them
    ipc.sleep(50);
end

 

Here, I receive all my events properly but the function used for offset() seems to never be called. Is this the intented behavior when an "event" loop is used?

 

I see in your Lua samples that you use this kind of loop but read each data directly from the offset, without using the event object. Is this because we cannot mix them?

 

Thanks, now, I'll do some BIG cleanup and implement the FSUIPC SDK :)

Link to comment
Share on other sites

I have a quick question regarding Lua execution in FSUIPC.

 

As my code is now polling for events, I'm using something like this in my test script:

event.offset(...Some offset to check...);
 
while true do
    passerelle.poll();   -- polling for events related to the callbacks and auto-execute them
    ipc.sleep(50);
end

Here, I receive all my events properly but the function used for offset() seems to never be called. Is this the intented behavior when an "event" loop is used?

 

The event system is used to enable a suspended Lua (one which exited, I.e stop processing) to run again with a call to the given function. It cannot interrupt one which is running in order to transfer control elsewhere in the same Lua.  I'm not sure what sort of mess would be created that way.

 

Many of the earlier Lua examples were created before the event system was implemented. Then, yes, the program had to stay in a loop looking for whatever it needed itself.

 

When the program terminates "naturally" (not by express termination), if there are any events being awaited, FSUIPC merely suspends the program and watches for those events. The thread itself continues to exist and in fact is running -- that is where the event checking is done. Really it's as if that part of FSUIPC is part of the Lua program. It is just coded in C and inside FSUIPC proper.

 

I'm not sure how any other way of implementing such facilities could be done. I do not know the innards of the Lua code very well, only enough to make it fit.

 

Anyway,I thought your callbacks couldn't occur unless the program exited awaiting an event? At least the use who had the problem said the callback function wouldn't get called without an event -- I asked him specifically to try it all with a loop and no events in case that solved the original problem.

 

Pete

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.