Claude Troncy Posted February 13, 2016 Report Posted February 13, 2016 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
Pete Dowson Posted February 13, 2016 Report Posted February 13, 2016 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
Claude Troncy Posted February 13, 2016 Author Report Posted February 13, 2016 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
Pete Dowson Posted February 13, 2016 Report Posted February 13, 2016 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
Pete Dowson Posted February 13, 2016 Report Posted February 13, 2016 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
Claude Troncy Posted February 13, 2016 Author Report Posted February 13, 2016 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
Pete Dowson Posted February 14, 2016 Report Posted February 14, 2016 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
Pete Dowson Posted February 14, 2016 Report Posted February 14, 2016 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
Claude Troncy Posted February 14, 2016 Author Report Posted February 14, 2016 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
Claude Troncy Posted February 14, 2016 Author Report Posted February 14, 2016 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
Pete Dowson Posted February 14, 2016 Report Posted February 14, 2016 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... http://forum.simflight.com/topic/68309-lua-capabilities/page-3#entry429053 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
Claude Troncy Posted February 16, 2016 Author Report Posted February 16, 2016 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
Chrilith Posted February 22, 2016 Report Posted February 22, 2016 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!
Pete Dowson Posted February 22, 2016 Report Posted February 22, 2016 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
Claude Troncy Posted February 22, 2016 Author Report Posted February 22, 2016 Hi Chris, I am using the last drivers provided by Saitek for W7 64 bits 7-0-47-1-X64 Claude
Chrilith Posted February 24, 2016 Report Posted February 24, 2016 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
Pete Dowson Posted February 24, 2016 Report Posted February 24, 2016 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
Chrilith Posted February 24, 2016 Report Posted February 24, 2016 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?
Pete Dowson Posted February 24, 2016 Report Posted February 24, 2016 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
Chrilith Posted March 10, 2016 Report Posted March 10, 2016 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!
Pete Dowson Posted March 10, 2016 Report Posted March 10, 2016 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
Chrilith Posted March 10, 2016 Report Posted March 10, 2016 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
Chrilith Posted March 10, 2016 Report Posted March 10, 2016 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 :)
Pete Dowson Posted March 10, 2016 Report Posted March 10, 2016 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
Chrilith Posted March 10, 2016 Report Posted March 10, 2016 Makes sense, thank you for your answer. :) I'll implement different modes for different use cases. Thank you again!
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now