exceptIntf.CrashedThreadId content for EFrozen

delphi package - automated exception handling
Post Reply
wprins
Posts: 7
Joined: Mon Mar 21, 2011 9:51 am

exceptIntf.CrashedThreadId content for EFrozen

Post by wprins »

Hi,

Today I tried to modify the bug report email subject to include the thread/client name, within the registered madExcept Exception handler with code as follows:

Code: Select all

  if exceptIntf.ExceptClass = 'EFrozen' then
  begin
    exceptIntf.MailSubject := exceptIntf.MailSubject + ' ('+GetThreadName(exceptIntf.CrashedThreadId)+')';
  end;
However it seems that CrashedThreadId contains not the hanging/frozen thread but instead contains the AntiFreezeThread id instead. (The text the above appended when I tested was "(madExcept - AntiFreezeThread ($42cc))".)

Is this a bug? Or is there some other way to determine what the threadid of the hanging thread for which EFrozen was raised is?

Thanks so much in advance,

Walter
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: exceptIntf.CrashedThreadId content for EFrozen

Post by madshi »

The frozen state is always detected by the "anti freeze" thread, which then raises an EFrozen exception. That's the whole purpose of that thread. So "GetThreadName(exceptIntf.CrashedThreadId)" works correctly. The freeze detection practically just means that your main thread has stopped responding to messages. So if you will, you could hard code the main thread to be the "responsible" thread for the freeze exception.
wprins
Posts: 7
Joined: Mon Mar 21, 2011 9:51 am

Re: exceptIntf.CrashedThreadId content for EFrozen

Post by wprins »

OK, can you please clarify what the use of exceptIntf.CrashedThreadID is if it just always returns the same threadID as GetCurrentThreadId(), which is what I understand you answer to imply? (The fact that "CrashedThreadID" is the id of the freezechecking thread seemingly suggests that the FreezeThread itself is hung? Or do I completely misunderstand the intent of CrashedThreadID?)

That being the case then, I guess what I really want to know is, how then in the context of a madexcept exception handler handling/being told about a frozen thread, can you know the threadid of that thread that is frozen?

On a related note I'm still "having an argument" with some datasnap server code trying to plumb in freeze/hung checking for client threads. The trouble I'm having boils down to the fact that the threads are created inside the guts of datasnap and clients can be terminated in various ways/places, resulting in difficulties ensuring that CloseAntiFreeze is called for every thread being monitored on the client thread itself (in order to stop the freezethread from thinking the thread is hung), as in some cases the only event/hook notification of a client disconnecting or having gone etc actually happens on a different datasnap thread (it seems sometimes after the actual client thread has already terminated).

In the latter case this leaves me with madExcept's freezechecking thread still triggering (albeit on behalf of a dead thread), and given the above behaviour I don't know what the threadid is (as CrashedThreadID won't tell me, and I don't know of any other place to get this?), and indeed no way to stop the freezethread from checking such a terminated thread even if I did know the thread ID, because I can't pass a threadID to CloseAntiFreeze()).

It may well be that I'm being entirely stupid about this, so any general observations/suggestions are gratefully received.

(I may go dig around in the datasnap code today to try and track down the actual thread creation and destruction points and see if it's feasible to plumb in some kind of subclass to allow me to hook in to the actual client thread lifetime in order to ensure InitAntiFreeze and CloseAntiFreeze is called excactly in parallel to the lifetime of the client threads, but ideally I really don't want to be modifying Emba owned datasnap code...)
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: exceptIntf.CrashedThreadId content for EFrozen

Post by madshi »

"CrashedThreadID" is meant to be used for crashes, not for freezes.

As I already explained in my previous comment, the whole extent of madExcept's freeze checking/reporting is that it checks if the main thread is still reacting to messages. There seems to be a misunderstanding on your part: madExcept is *NOT* able to detect freezes in any arbitrary thread. It's not technically possible because there's no definition of being frozen for any threads other than the main thread. Secondary threads might be intended to be "stuck" in e.g. a WaitForSingleObject() call, or in some other call. Secondary threads are not required to handle messages. So there's no way for madExcept to properly detect if a secondary thread is frozen, simply because madExcept doesn't know in which situation you would consider a secondary thread to be frozen or not.

So once more: The one and only thing madExcept's freeze check does is to check if the main thread responds to window messages (like e.g. WM_PAINT or whatever). If the main thread doesn't respond to messages for a specific amount of time, madExcept's freeze checking thread raises an EFrozen message. And since freeze detection is *ALWAYS* limited to only detect freezes in the main thread, "CrashedThreadID" is not needed nor useful. EFrozen always means the *main* thread is frozen.

That of course also means that there's no reason for you to call InitAntiFreeze or CloseAntiFreeze in the context of a specific thread you want to be analyzed for freezing, because AntiFreeze doesn't do that, anway. It only ever checks your main thread, nothing else.
wprins
Posts: 7
Joined: Mon Mar 21, 2011 9:51 am

Re: exceptIntf.CrashedThreadId content for EFrozen

Post by wprins »

madshi wrote:The frozen state is always detected by the "anti freeze" thread, which then raises an EFrozen exception. That's the whole purpose of that thread. So "GetThreadName(exceptIntf.CrashedThreadId)" works correctly. The freeze detection practically just means that your main thread has stopped responding to messages. So if you will, you could hard code the main thread to be the "responsible" thread for the freeze exception.
Just to be clear and by way of background/context: I am working on a datasnap server which is also a service. This means there isn't really any "main thread" (although there are several listening threads and a "container" thread that acts as the first port of call to handle authentication requests from what I understand about datasnap's thread architecture.) New client threads then get created to service clients more or less (if using datasnap session mode). I call "InitAntiFreeze" from the context of every thread I want monitoring, which is a) the "container thread", I guess you could think of this as the "main thread", and b) in the "UserAuthenticate" event method, which is approximately the first thing that happens on a new client thread created by datasnap. I then correspondingly call CloseAntiFreeze in the Disconnect event (which is approximately the last event that happens normally for client threads) and when the container datamodule is destroyed. The trouble is that the Disconnect event may not happen if for example the client drops off or otherwise disappears and I then don't get a call on the client thread that I can use to disable the anti-freeze checking, and then am stuck with repeatedly being notified about the client thread being hung without this being the case as far as I can tell (since presumably the client thread's terminated.)

Perhaps I can't use madExcept's anti-freeze checking to check for hung threads in a datasnap server? :sorry:
Last edited by wprins on Thu Feb 15, 2018 10:32 am, edited 1 time in total.
wprins
Posts: 7
Joined: Mon Mar 21, 2011 9:51 am

Re: exceptIntf.CrashedThreadId content for EFrozen

Post by wprins »

madshi wrote:"CrashedThreadID" is meant to be used for crashes, not for freezes.
That of course also means that there's no reason for you to call InitAntiFreeze or CloseAntiFreeze in the context of a specific thread you want to be analyzed for freezing, because AntiFreeze doesn't do that, anway. It only ever checks your main thread, nothing else.
Thank you so much for your response. OK, I understand, I think.

Basically I thought I could use the anti-freeze checking as a simple "per thread" timer (effectively) to notify me if any thread takes longer than a specified amount of time before it finishes its job (which could indicate a hang). You're saying that's not the case/how things work so I'll stop trying to put a square peg in a round hole! :crazy:

Thanks again!

Walter
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: exceptIntf.CrashedThreadId content for EFrozen

Post by madshi »

Ok, I have to retract some of what I just wrote, sorry about that. I did add an extra trick to the anti freeze checking for services, because services don't have a conventional main thread:

For normal applications, you would activate freeze checking in the madExcept settings. If you do that, you don't have to call InitAntiFreeze yourself, it gets automatically called by the main thread during madExcept initialization.

However, for services, you can disable freeze checking in the madExcept settings. In that case, in the moment when you manually call InitAntiFreeze, the thread in whose context you call it, will be considered the "main thread" by the anti freeze checking. So in a sense, you *can* actually (in contrast to what I wrote earlier) check one specific thread for freezes. However, please understand that this whole freeze checking is based just on checking whether the "main thread" (real or chosen by you) is responding to messages. I'm not sure if your server's thread which you want to check is really expected to handle messages all the time? Only you can answer that.

Furthermore, InitAntiFreeze will do nothing if you call it twice - unless you call CloseAntiFreeze first. So you can't check multiple threads for freezes at the same time.

Maybe it would be a good idea for you to brainstorm how you define the state of a frozen thread exactly? And do you want multiple threads to be "watched" for freezes at the same time? If you can perfectly define when a thread is frozen and when it's not, then it should be relatively easy for you to implement your own solution, which might be more custom tailored to your specific needs. All you'd need to do is to create your own secondary freeze checking thread, have to watch your worker threads and if your freeze checking thread detects a freeze, raise an EFrozen exception. The tricky part would be to make the EFrozen detection point to the detected frozen thread, though, but if you want to go this way, we can discuss how to do that.
Post Reply