From: TX on
I have a problem with blocking of main thread:

My application contains an interpreter and I need to write a debugger
for it.

The mainframe creates a thread that is interpreting instructions. When I
need to break execution of instruction thread, I use
WaitForSingleObject(m_WaitEventHandle, INFINITE);
in the interpreter thread.

Everything works fine until the window is opened from the interpreter.
Then the mainframe freezes.

When I break execution in VC the call stack for interpreter thread shows:

ý NTDLL!
ý KERNEL32!
ý CDebugManager::CheckBreakpoints()
ý CInterpreterThread::Run()
ý _AfxThreadEntry()
ý _threadstartex()
ý KERNEL32!

call stack for the mainframe:
ý CWinThread::Run()
ý CWinApp::Run()
ý AfxWinMain()
ý WinMain()
ý WinMainCRTStartup()
ý KERNEL32!


The window opened from interpreter is descendant of CDialog and is
created by calling CDialog::Create(IDD_DIALOG_BASE)

What can be wrong?
Is it a way to find out why the main thread is blocking?

Thanks for any help.
From: Scott McPhillips [MVP] on
TX wrote:
> I have a problem with blocking of main thread:
>
> My application contains an interpreter and I need to write a debugger
> for it.
>
> The mainframe creates a thread that is interpreting instructions. When I
> need to break execution of instruction thread, I use
> WaitForSingleObject(m_WaitEventHandle, INFINITE);
> in the interpreter thread.
>
> Everything works fine until the window is opened from the interpreter.
> Then the mainframe freezes.
>
> When I break execution in VC the call stack for interpreter thread shows:
>
> ý NTDLL!
> ý KERNEL32!
> ý CDebugManager::CheckBreakpoints()
> ý CInterpreterThread::Run()
> ý _AfxThreadEntry()
> ý _threadstartex()
> ý KERNEL32!
>
> call stack for the mainframe:
> ý CWinThread::Run()
> ý CWinApp::Run()
> ý AfxWinMain()
> ý WinMain()
> ý WinMainCRTStartup()
> ý KERNEL32!
>
>
> The window opened from interpreter is descendant of CDialog and is
> created by calling CDialog::Create(IDD_DIALOG_BASE)
>
> What can be wrong?
> Is it a way to find out why the main thread is blocking?
>
> Thanks for any help.

The main call stack does not look frozen: CWinThread::Run is the main
message pump. Assuming that you have installed the MFC source files, a
double-click on the top line of the stack will show you where the main
thread is executing.

Does your main thread attempt to access the dialog or dialog controls
created in the second thread? That would cause a deadlock if the second
thread is in WaitForSingleObject. The second thread cannot maintain a
window while it is in WaitForSingleObject. It is best to put all
windows in the main thread.

--
Scott McPhillips [VC++ MVP]

From: Joseph M. Newcomer on
I've written many interpreters. Blocking the main thread is ALWAYS a mistake.

You have not said what the child thread is doing. The key phrase here is "until the window
is opened". Who "opens" "the window"? You have not said who opens it, or what window it
is. I can imagine any number of cases where you have created a canoncical deadlock
situation.

One question is "how fast does your interpreter have to be?" A low-speed interpreter can
use a lot of really simple tricks to handle interpreter sequencing at the byte-code level.
For a high-speed interpreter (need to execute hundreds of thousands of byte codes per
second), even putting a WaitForSingleObject on a debug event is going to seriously impact
performance.

It doesn't matter what the stack looks like; key to all of this is to remove ANY
WaitFor... from the main GUI thread, period; and preferrably, remove the WaitFor... from
the interpreter thread.

First trick: you PostThreadMessage a user-defined message to a UI thread. The PostMessage
says "execute". When the message is dequeued (I used a UI thread to handle this). When in
Run mode, the interpreter forces a PostThreadMessage to execute the next byte code. In
single-step mode, or when you hit the "break" button on your control panel, you set a
Boolean that stops this message from being posted. So it simply executes one step of the
interpreter and stops. I had an interpreter that allowed single-byte-code debug and
statement-at-a-time debug (in fact, it was the first Windows program I wrote).

Now this does have a limitation on performance. For the code I was interpreting (a simple
language akin to BASIC in its semantics but bearing a strong resemblance to C in its
syntax), the average program was a couple hundred lines, had very few loops (just
enumerating database items), and usually completed execution by the time the user realized
the mouse had clicked.

More than a decade later, I used the same technique in my HP16C emulator. Same
low-performance issues made it feasible.

Now, if I needed performance, I'd probably do something like


while(TRUE)
{ /* thread loop */
::WaitForSingleObject(runEvent, INFINITE);
while(interpreting)
{ /* interpreter loop */
interpretOneOp();
if(breakflag)
break; // leave interpreter loop
} /* interpreter loop */
gui->PostMessage(UWM_INTERPRETER_STOPPED);
} /* thread loop */
gui->Postmessage(UWM_SHUTDOWN);

Note that this runs the interpreter at "full speed" unless the breakflag is set. The
"break" button on your control panel/menu will ResetEvent() and set this flag (in that
order!); the "run/resume" item (think F5 key) will clear this flag and SetEvent().
Single-step will set the brekflag and then do a SetEvent(). Note that if the interpreter
is stopped, it is impossible to kill the thread; see my essay on worker threads and how to
use a ShutdownEvent and WaitForMultipleObjects to terminate the main thread loop. Note
that this algorithm removes the WaitFor[Single/Multiple] object from the main interpreter
loop.

Now, the way the main GUI thread determines the interpreter has stopped interpreting is
because it receives the UWM_INTERPRETER_STOPPED message.

Note this now shows you a general mechanism. For example, you can have the generic
breakflag, which says "stop the interpreter loop" but you can also have a "reason" which
encodes why it stopped, and you could pass this back in the wParam. For example, "array
index out of bounds" would implicitly set the break flag, and set the reason.

Another mechanism is to put the interpreter loop inside a try/catch construct (we did
this back in 1967 when we built an interactive interpreted language at CMU called "LCC")

while(TRUE)
{ /* thread loop */
WaitForSingleObject(runEvent, INFINITE);
try
{
while(TRUE)
{ /* interpreter loop */
interpretOneOp();
if(breakflag)
throw new CInterpreterBreakException( );
} /* interpreter loop */
}
catch(CInterpreterException * e)
{
ResetEvent(runEvent);
gui->PostMessage(UWM_INTERPRETER_EXCEPTION, (WPARAM)e);
}
} /* thread loop */

The recipient then can interpret the CInterpreterException and call the Delete method on
the exception when it is done.

Now CInterpreterException is a subclass of CException, and it in turn has subclasses such
as CInterpreterArrayBoundsException, CInterpreterDivideByZeroException,
CInterpreterIsReallyConfusedException, and the one I show abouve,
CInterpreterBreakException.

The try block is outside the interpreter loop, so it only has to be called once, because
exception handler setup/teardown is realtively slow. Expect that the interpreter loop is
going to be screamingly fast under this model (limited only by the computations
themselves).

By the way, the way I implemented the interpreter was that I just had the parse tree of my
language, enhanced in some minor ways (alas, the advantages of multiple inheritance would
show up well here, but it has a lot of other problems), and each node, which was a
subclass of the abstract superclass TreeNode, had an Interpret method. So

class OpAdd : public BinaryNode {
public:
void Execute() { int R = stack.pop(); int L = stack.pop(); stack.push(R + L);
};

class BinaryNode : public TreeNode {
public:
TreeNode * left;
TreeNode * right;
void Execute() PURE;
};

class TreeNode {
public:
void Execute() PURE;
};

class LeafNode : public:TreeNode {
public:
void Execute() PURE;
};

class intval : public LeafNode {
public:
int value; // literal integer value
void Execute() { stack.push(value); }
};

class variable : public LeafNode {
public:
CString name;
void Execute() { var * v = Lookup(name);
if(!v->initialized)
throw new CInterpreterUsedUninitializedVariable;
stack.push(v->value);
}

This should give you a number of ideas.
joe


On Sun, 10 Jul 2005 02:26:16 +0200, TX <tx(a)tx> wrote:

>I have a problem with blocking of main thread:
>
>My application contains an interpreter and I need to write a debugger
>for it.
>
>The mainframe creates a thread that is interpreting instructions. When I
>need to break execution of instruction thread, I use
>WaitForSingleObject(m_WaitEventHandle, INFINITE);
>in the interpreter thread.
>
>Everything works fine until the window is opened from the interpreter.
>Then the mainframe freezes.
>
>When I break execution in VC the call stack for interpreter thread shows:
>
>ý NTDLL!
>ý KERNEL32!
>ý CDebugManager::CheckBreakpoints()
>ý CInterpreterThread::Run()
>ý _AfxThreadEntry()
>ý _threadstartex()
>ý KERNEL32!
>
>call stack for the mainframe:
>ý CWinThread::Run()
>ý CWinApp::Run()
>ý AfxWinMain()
>ý WinMain()
>ý WinMainCRTStartup()
>ý KERNEL32!
>
>
>The window opened from interpreter is descendant of CDialog and is
>created by calling CDialog::Create(IDD_DIALOG_BASE)
>
>What can be wrong?
>Is it a way to find out why the main thread is blocking?
>
>Thanks for any help.

Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: TX on
Scott McPhillips [MVP] wrote:
> TX wrote:
>
>> I have a problem with blocking of main thread:
>>
>> My application contains an interpreter and I need to write a debugger
>> for it.
>>
>> The mainframe creates a thread that is interpreting instructions. When
>> I need to break execution of instruction thread, I use
>> WaitForSingleObject(m_WaitEventHandle, INFINITE);
>> in the interpreter thread.
>>
>> Everything works fine until the window is opened from the interpreter.
>> Then the mainframe freezes.
>>
>> When I break execution in VC the call stack for interpreter thread shows:
>>
>> ý NTDLL!
>> ý KERNEL32!
>> ý CDebugManager::CheckBreakpoints()
>> ý CInterpreterThread::Run()
>> ý _AfxThreadEntry()
>> ý _threadstartex()
>> ý KERNEL32!
>>
>> call stack for the mainframe:
>> ý CWinThread::Run()
>> ý CWinApp::Run()
>> ý AfxWinMain()
>> ý WinMain()
>> ý WinMainCRTStartup()
>> ý KERNEL32!
>>
>>
>> The window opened from interpreter is descendant of CDialog and is
>> created by calling CDialog::Create(IDD_DIALOG_BASE)
>>
>> What can be wrong?
>> Is it a way to find out why the main thread is blocking?
>>
>> Thanks for any help.
>
>
> The main call stack does not look frozen: CWinThread::Run is the main
> message pump. Assuming that you have installed the MFC source files, a
> double-click on the top line of the stack will show you where the main
> thread is executing.
>
> Does your main thread attempt to access the dialog or dialog controls
> created in the second thread? That would cause a deadlock if the second
> thread is in WaitForSingleObject. The second thread cannot maintain a
> window while it is in WaitForSingleObject. It is best to put all
> windows in the main thread.
>

Now I break execution again and the call stack for main thread shows this:

------------------------
ý USER32! 77e1392f()
ý USER32! 77e15709()
ý CFrameWnd::NotifyFloatingWindows()
ý CFrameWnd::OnActivate()
ý CWnd::OnWndMsg()
ý CWnd::WindowProc()
ý AfxCallWndProc()
ý AfxWndProc()
ý AfxWndProcBase()
ý USER32! 77e12e98()
ý USER32! 77e139a3()
ý USER32! 77e1395f()
ý NTDLL! 77fa032f()
ý CWinThread::PumpMessage()
ý CWinThread::Run()
ý CWinApp::Run()
ý AfxWinMain()
ý WinMain()
ý WinMainCRTStartup()
ý KERNEL32! 77e97d08()
------------------------

When I double-click on CFrameWnd::NotifyFloatingWindows(), the source of
WinFrm.cpp shows the line marked with =====>


------------------------
void CFrameWnd::NotifyFloatingWindows(DWORD dwFlags)
{
ASSERT_VALID(this);
ASSERT(m_hWnd != NULL);

// get top level parent frame window first unless this is a child window
CFrameWnd* pParent = (GetStyle() & WS_CHILD) ? this : GetTopLevelFrame();
ASSERT(pParent != NULL);
if (dwFlags & (FS_DEACTIVATE|FS_ACTIVATE))
{
// update parent window activation state
BOOL bActivate = !(dwFlags & FS_DEACTIVATE);
BOOL bEnabled = pParent->IsWindowEnabled();

if (bActivate && bEnabled && pParent != this)
{
// Excel will try to Activate itself when it receives a
// WM_NCACTIVATE so we need to keep it from doing that here.
m_nFlags |= WF_KEEPMINIACTIVE;
pParent->SendMessage(WM_NCACTIVATE, TRUE);
m_nFlags &= ~WF_KEEPMINIACTIVE;
}
else
{
pParent->SendMessage(WM_NCACTIVATE, FALSE);
}
}

// then update the state of all floating windows owned by the parent
HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while (hWnd != NULL)
{
if (AfxIsDescendant(pParent->m_hWnd, hWnd))
::SendMessage(hWnd, WM_FLOATSTATUS, dwFlags, 0);
=====> hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
}
------------------------

In hWnd is the handle of the window that was opened from the interpreter...
From: Scott McPhillips [MVP] on
TX wrote:
> When I double-click on CFrameWnd::NotifyFloatingWindows(), the source of
> WinFrm.cpp shows the line marked with =====>
> // then update the state of all floating windows owned by the parent
> HWND hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
> while (hWnd != NULL)
> {
> if (AfxIsDescendant(pParent->m_hWnd, hWnd))
> ::SendMessage(hWnd, WM_FLOATSTATUS, dwFlags, 0);
> =====> hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
> }
> }
> ------------------------
>
> In hWnd is the handle of the window that was opened from the interpreter...

Bingo. That seems to be the problem I described earlier. Accessing a
window that was created in another thread requires the other thread to
execute. But your other thread is blocked in WaitForSingleObject so it
will not execute. You have apparently compounded the problem by
creating a parent-child relationship between windows in multiple
threads, which MFC is not desgigned to handle.

* Do not create windows in a thread that will be suspended.
* Do not access windows from a thread that did not create them.

The recommended practice is to put all windows in the main GUI thread.
If another thread needs to update a window it must request the GUI
thread to do it, typically via PostMessage to a window. An example of
this lock-free technique can be found in
http://www.mvps.org/vcfaq/mfc/index.htm

--
Scott McPhillips [VC++ MVP]