critical_events
Differences
This shows you the differences between two versions of the page.
critical_events [2011/10/17 21:51] – external edit 127.0.0.1 | critical_events [2018/08/17 10:36] (current) – Document new insights gained over the course of twelve years (first cut) saturn | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Critical events and the pause problem | ||
+ | //Author// --- // | ||
+ | |||
+ | First of all, mIRC's scripting engine is **single-threaded**. There is only one thread that executes script code... ever.((Even identifiers like $comcall/ | ||
+ | |||
+ | The explanation as to why in some scenarios it //seems// that multiple scripts can be executed in " | ||
+ | |||
+ | mIRC is therefore also message queue based, and, as a result, every piece of script that gets executed is the result of receiving a message. In other words, mIRC's script engine is always called (directly or indirectly) from message processing code. Message queue processing is always single-threaded, | ||
+ | |||
+ | Now comes the important part. Identifiers like $input and $dialog, the WhileFix DLL, and any script-delaying COM-based snippets (/sleep, /xrun, $auth to name a few) all use a trick to process new messages while not returning from the current message-processing function: they call the message loop to process messages from within the code that is processing the current message. For this snippet we get a current execution stack that looks more or less like this: | ||
+ | |||
+ | [mirc' | ||
+ | [message processing code] -> | ||
+ | [script engine] -> | ||
+ | [wscript.shell COM handling DLL code] -> | ||
+ | [embedded message loop] -> | ||
+ | [message processing code] -> | ||
+ | [script engine] | ||
+ | |||
+ | Let's define " | ||
+ | |||
+ | Now, in general, mIRC makes a distinction between two different types of events, which I call critical and non-critical events. Critical events are events that are not allowed to be interrupted by non-critical events; " | ||
+ | |||
+ | The reason for the distinction is that in general, critical events simply cannot be interrupted. There are various reasons for this, one of them being that mIRC's internal data structures should not be touched from certain contexts. For example, consider the "on QUIT" event, and consider what could happen if mIRC were to process an "on JOIN" message for the same nickname before updating its own internal data structure (see also /updatenl). | ||
+ | |||
+ | On the other hand, non-critical events do not have this problem, and have no problem calling the message loop from within them. Hence, these are some (simplified) examples of allowed execution stacks: | ||
+ | |||
+ | [message loop] -> [critical event] | ||
+ | [message loop] -> [non-critical event] | ||
+ | [message loop] -> [non-critical event] -> [message loop] -> [critical event] | ||
+ | [message loop] -> [non-critical event] -> [message loop] -> [non-critical event] | ||
+ | [message loop] -> [non-critical event] -> [message loop] -> [non-critical event] -> [message loop] -> (etc) | ||
+ | |||
+ | In contrast, this execution stack must never occur: | ||
+ | |||
+ | [message loop] -> [critical event] -> [message loop] -> [critical event] | ||
+ | |||
+ | Fortunately, | ||
+ | |||
+ | That leaves this third category, for which it is less clear whether it should be allowed or not: | ||
+ | |||
+ | [message loop] -> [critical event] -> [message loop] -> [non-critical event] | ||
+ | |||
+ | That case would be technically possible. However, deferring the processing of incoming socket messages is never a good idea anyway. For example, if $input is used from an "on TEXT" event, and the user does not actually provide any input, then mIRC will not respond to any incoming " | ||
+ | |||
+ | Unlike $input, both the WhileFix DLL and COM-based script delaying snippets do not make the distinction between critical and non-critical events, so you can use them from critical events as well. Again, in that case no critical events will be processed from the nested message loop - so in the case of a COM-based script delaying snippet for example, no critical events will be processed until the snippet times out and returns. However, non-critical events may indeed be processed (the third category above). At that point it is entirely up to the scripter to prevent that the scripted delays cause problems for the IRC connections. | ||
+ | |||
+ | Again, all of this happens from a single thread: mIRC's main thread. If mIRC were multithreaded, | ||
critical_events.txt · Last modified: by saturn