Login Register Actian.com  

Actian Community Wiki

Navigation
Learn About
Developing With
Ingres Talk
Information
Toolbox

Ingres OpenROAD Projects/Breaking out of tightloops

From Ingres Community Wiki

Jump to: navigation, search

Contents

Overview

Developers at times code infinite loops during the application development process. If these loops are not caught while developing code they can become painfully apparent while testing under Workbench. Especially without a breakpoint set in the offending code. After a few choice words about the OpenROAD development team, where the intensity of the tirade often depends on how much work you are going to lose after you terminate the w4gldev process. At the moment, the only choice you have is to terminate the process, start the development code again, sprinkle the source with breakpoints, and start the process to narrow down where the problem lies. At times it is easy to find the offending code but with large complex applications it possible to get into situations where the loops are difficult to detect. The solution to this development problem takes one of two paths. The first path is to never make these mistakes while the second is to provide the developer with the ability to press a key that will cause the program to stop executing 4GL. Control will be given back to the developer. With the debugger waiting to execute the next statement that would have normally executed if the developer hadn't pressed the key to gain control over the running program.

External Interface

While the Ctrl + C keystroke combination has been suggested as the hot key that should be pressed to break into an application. There are conventions that suggest that this is not the best key to use here. For example in Microsoft Windows GUI applications, this is the shortcut key that you press to copy text to the clipboard but it is still commonly used in command windows to stop execution of applications. It still seems as if the better choice might be the Pause/Break key on the keyboard which is the VK_PAUSE virtual key.

When this key is pressed, if an OpenROAD application is being run from Workbench the program will stop executing and return control to the debugger window. This Window will display the source file being executed at the line right after the previously executed line. If the debugger window is not open at the point the VK_PAUSE key is pressed. The debugger will start and place you at the next line after the previously executed line.

Pressing this VK_PAUSE key will not stop an OpenROAD application that is executing from an image file. If the application depends on this key for some functionality an alternate key must be used during testing. Perhaps a future feature will allow a developer to configure the debugger to ignore or override the current break key.

Application Developer Interface

We need will eventually need a way to allow the developer to override the default key used to break execution functionality could be designed. This aspect of the project is not being defined at this time. We will make the basic break functionality work with pressing the Pause/Break key.

New Attributes

None

Mentors

Joe Kronk Brigitte Duplenee Bodo Bergmann

Developers

Attendees’ at the June 2011 OpenROAD code sprint.

Development Strategy/Notes

Note 1. While prototyping in 2008, Don Criley wrote a routine IIOMxxxHandleInterrupt() that lives in butils.c called in IITranslateAccelerator(). The source code for these functions is as follows:

i4
IIOMxxxHandleInterrupt( IIOBJECT *self, LPMSG lpmsg, i4 eventtype, i4 runmode )
{

    MSG msg;
    IIWINDOW *mainwin;


    if ( !self || self->class != IIOCWINDOW )
    {
	return 0;
    }
    else
    {
	mainwin = self;
    }

    if ( lpmsg == NULL )
    {
	if ( !PeekMessage( &msg, /* mainwin->framewdg */ NULL, WM_KEYDOWN, WM_KEYDOWN, PM_NOREMOVE ) )
	{
	    return 0;
	}

	if ( GetMessage (&msg, NULL, WM_KEYDOWN, WM_KEYDOWN ) )
	{
	    lpmsg = &msg;
	}
	else
	{
	    return 0;
	}
    }

    if( lpmsg->message == WM_KEYDOWN &&
    	(GetKeyState(VK_CONTROL) & 0x8000) &&
	 lpmsg->wParam == 'C')
    {
	if ( self->class == IIOCWINDOW )
	{
	    IISESBLK *session = IIwexec->session;
	    IIITSTACK *itstack = ((IIWINDOW *)self)->command;

    	    SEND8( mainwin, enqueue,
        	   (bool)TRUE, eventtype, (i4)0, (i4)0,
        	    (i4)0, (i4)0, (i4)0, (i4)0);

	    itstack->runmode = runmode;
	    return 1;
	}
    }
}

nat
IITranslateAccelerator(HWND hwnd, HACCEL haccl, LPMSG lpmsg)
{
	IIWINDOW *	self = NULL;
	WPARAM		wParam;

	if ((lpmsg->message == WM_SYSCHAR) && (IILookupAccel(lpmsg) == TRUE))
		return (nat)TRUE;
	else if ((lpmsg->message == WM_KEYDOWN) 
		  || (lpmsg->message == WM_SYSKEYUP)  
		  || ((lpmsg->message == WM_SYSKEYDOWN) && (GetFocus() == NULL)) 
		  || ((lpmsg->message == WM_CHAR || lpmsg->message == WM_SYSCHAR)
				&& (lpmsg->lParam & 0x20000000)))
	{
		if (IIUGhfHtabFind(IIwexec->windowhash, hwnd, &self) == OK
		 && self->AcceleratorKeyTargetWindow 
		 && self->AcceleratorKeyTargetWindow->framewdg)
		{
			/* Check if possible menu speedkey & not editing trim */
			wParam = lpmsg->wParam;
			if (lpmsg->message == WM_KEYDOWN
				|| lpmsg->message == WM_SYSKEYDOWN)
			{
				if ((GetKeyState(VK_CONTROL) & 0x8000)
				 || ((wParam >= VK_F1) && (wParam <= VK_F24))
				 || ((wParam == VK_DELETE) && (self->mode != FM_TRIM))
				 || ((wParam == VK_INSERT) && (self->mode != FM_TRIM))
				 || ((wParam == VK_BACK  ) && (self->mode != FM_TRIM)))
				{
					postMenuMsg(self->AcceleratorKeyTargetWindow->framewdg,lpmsg);
					dont_requeue = TRUE;	/* Bug 94018 */
					return(TRUE);
				}
			}
			else if (((wParam != VK_F4) 
				   && (wParam != VK_MENU)
				   && (wParam != VK_SPACE))
				  || ((wParam == VK_MENU)
				   && (lpmsg->message == WM_SYSKEYUP)))
			{
			       /* Check if numpadkeys & not editing trim */
			        if (((wParam == VK_NUMPAD0) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD1) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD2) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD3) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD4) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD5) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD6) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD7) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD8) && (self->mode != FM_TRIM))
				|| ((wParam == VK_NUMPAD9) && (self->mode != FM_TRIM)))
                                {
				  if (GetFocus() == lpmsg->hwnd)
				   {
					postMenuMsg(self->AcceleratorKeyTargetWindow->framewdg,lpmsg);
					dont_requeue = TRUE;	/* Bug 94018 */
                                   }
				}
				return(TRUE);
			}
		}
	}
	if ( self )
	{
	    /*
	    ** Get the WOOF object from the hash table based on 
	    ** the window handle.
	    */
		
	    HRESULT hr;
	    HWND parent;
	    IIEXTOBJFIELD *eventobj; 
	    BOOL bTranslateControl = FALSE;

	    if (IIUGhfHtabFind( IIwexec->windowhash, lpmsg->hwnd, &eventobj) != OK)
		bTranslateControl = TRUE;
	    eventobj = NULL;
	    parent = lpmsg->hwnd;
	    while( parent != NULL )
	    {
		parent = GetParent( parent );
		if ( parent && 
		        (IIUGhfHtabFind( IIwexec->windowhash, parent, &eventobj) == OK))
		{
		    if ( eventobj->class == IIOCEXTOBJFIELD )
		    {
			if( lpmsg->message == WM_KEYDOWN && 
			    (lpmsg->wParam == VK_TAB ||
			    lpmsg->wParam == VK_DELETE ||
			    lpmsg->wParam == VK_INSERT) ||
			    ((bTranslateControl == TRUE) &&
			    (GetKeyState(VK_CONTROL) & 0x8000) &&
				(lpmsg->wParam == 'X' ||
				 lpmsg->wParam == 'V' ||
				 lpmsg->wParam == 'C')))
			{
			    LPDISPATCH idisp = NULL;
			    
			    if ( eventobj->extobject && 
				 eventobj->extobject->idispatch )
			    {
			    	idisp = eventobj->extobject->idispatch;
			    	hr = IIOleTranslateAccelerator( idisp, lpmsg );
			    	return hr;
			    }	
			}
		    }			
		}
		if ( self )
		{
		    return IIOMxxxHandleInterrupt( self, lpmsg, WindowClose, ITTERMINATE );
		}
	    }
	}	
	return TranslateAccelerator(hwnd, haccl, lpmsg);
}

Note 2. Piccolo change 495468 backed out the only call to this function that examined every key stroke in IITranslateAccelerator().

C:\bcdev\w4fpclr\ingres\w4gl\woof\wcbnt>p describe 495468

Change 495468 in ingres on 05-jan-2009 by crido01 on w4fpclr_int_w32_CRIDO01-755


- description -

Remove call to IIOMxxxHandleInterrupt in the translate accelerator.
It was mistakenly prematurely added.

- reviewers notified -

tonda02, mcgem01, hanch04 and dupbr01

- bugs fixed -

121440 118716 117030

- release notes -

121440
        Updating the FP_CLEAR fields on a tabpage, where the tabpage
        is FP_CLEAR and the tabfolder is FP_CLEAR.  The tabfolder itself
        being nested in an FP_CLEAR compositefield, causes the
        FP_CLEAR compositefield to be refreshed in its entirety, rather  then
        just updating the area beneath  the tabpage's fields.  This causes
        unnecessary flashing.

118716
        When clicking on some tabbar buttons the background of buttonfields
        on the new tabpage are sometimes drawn first before the tabpage
        is painted in full.

117030
        An entryfield with BgPattern = FP_CLEAR in a tablefield will
        have its contents garbled when the tablefield is scrolled.

- affected files -

ingres!w4fpclr!generic!w4gl!woof!wcbnt butils.c change -> 266

- differences -

ingres!w4fpclr!generic!w4gl!woof!wcbnt butils.c -> 266

1279a1280,1282
> **  05-jan-2009 (crido01) Bugs 117030 and 121440
> **    Remove call to IIOMxxxHandleInterrupt in the translate accelerator.
> **    It was mistakenly prematurely added.
7029,7032d7031
<               }
<               if ( self )
<               {
<                   return IIOMxxxHandleInterrupt( self, lpmsg, WindowClose, ITTERMINATE );

Note 3. The OpenROAD interpreter has two main loops that execute 4GL statement blocks. The first loop executes code without the debugger being active while the second loop executes code with the debugger being active. We need to figure out where in the debug interpreter loop to insert logic that makes a call to IIOMxxxHandleInterrupt() routine to check for our special key press after every 4GL statement. We will also need to modify the IIIOMxxxHandleInterrupt() routine to take the correct arguments to check for the right key. The final thing to do is to set the appropriate variables. So that the debugger is primed to execute a breakpoint before executing the next statement if the VK_PAUSE key down is detected..

Tests

1. Introduce a tight loop in the initalize block of a frame:

/*
** Introduce a infinite loop
*/
initialize()=
declare
	i = integer not null;
enddeclare
{

	for i=1 to 10000 do
		i = 5;
	endfor;
}

2. Run this code under the debugger so the program will loop indefinitely. You will have to terminate the OpenROAD process (w4gldev.exe on windows) and restart the Workbench to gain control before the implementation of this feature. When this feature is implemented you should be able to break into it by pressing the Pause/Break key on the keyboard.3. Run this from the debugger and verifiy that it breaks and allows execution to continue from the debugger.

3. Run this application from workbench directly without starting the debugger. Verify that the debugger starts up to allow execution to continue from the debugger.

4. Test on a keyboard other than a US keyboard and verify the Pause/Break key interrupts a running application under Workbench.

5. Code a loop that takes 15 seconds or longer to complete and make an image of the application. Run the new image and try to break in to the application. It should ignore attempts to break in by pressing the Pause/Break Key and complete normally.

Comments

Joe Kronk 23 May 2011

Proposal introduced.

Brigitte Duplenne 25 January 2012

SIR 126183 (OPENROAD) We must be able to choose the key or combination of keys used for breaking in the 4GL debugger.

SIR 126182 (OPENROAD) When debugging 4GL code we must be able to break the running of the code when it is in an infinite loop.

Implementation: Don had passed the code to Joe. In the code Don had passed to Joe, the key that will break in the debugger was hardcoded. When I tested for the Sprint I used my laptop but unfortunately I didn't have that key on my keyboard. So I looked for a way to customized it.

In the way Don has implemented the fix we cannot use IITranslateAccelerator (as this associates a function to a speedkey) so I added a new virtual key SK_BREAK and I created a new function that will test if the keys entered are the key that have been assigned to SK_BREAK.

I was getting a crash with the original code sent by Don. That was on : if ( ifc && (!ifc->if_ismethod) && ifc->if_obj && ifc->if_obj->form ) in itilloop.c

I first added an additional test on "session->current_ifc" but I was not that satisfied with that test. I tried to find a solution where we could test instead if "ifc->if_obj" is valid. So I modified the code and reset the if_obj to NULL when we release a frame. But then I was getting other crashes. I removed the code and did some new tests yesterday with only the additionnal test on "session->current_ifc" and that seems to do the job. May be there will be some cases where we will not break but in that case that could be review as a bug fix.

The key for breaking will be by default VK_PAUSE, but this could be modified in the keyboard file. However at the moment a combination of key using ALT will not work. In IIOMxxxHandleInterrupt I added the case and test for SYSKEYDONW but somehow that didn't work so at the moment we will not be able to use ALT. But I have done successful test with a key, a shift key, a ctrl+key ... The line to change in the keyboard file is the first one ex: -24 Ctrl+F2 Ctrl-VK_F2 SK_BREAK

Brigitte Duplenne 27 January 2012

Change 514650 submitted. - affected files -

ingres!w4er!generic!w4gl!fleas!symtab i4built.roc change -> 95 ingres!w4er!generic!w4gl!fleas!w4interp itilloop.c change -> 43 ingres!w4er!generic!w4gl!hdr!hdr woof.h change -> 170 ingres!w4er!generic!w4gl!w4glcl!files default.kbd change -> 2 ingres!w4er!generic!w4gl!w4glcl!spec_wnt w4gl32.rc change -> 33 ingres!w4er!generic!w4gl!woof!hdr wacctbl.nph change -> 7 ingres!w4er!generic!w4gl!woof!wcbnt bexcutor.c change -> 86 ingres!w4er!generic!w4gl!woof!wcbnt butils.c change -> 368

Personal tools
© 2011 Actian Corporation. All Rights Reserved