FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister   ProfileProfile   Log inLog in 


closing the program after an unknown exception?

Post new topic   Reply to topic    discuss.visual-prolog.com Forum Index -> Visual Prolog
View previous topic :: View next topic  
Author Message
B.Hooijenga



The Netherlands
Joined: 11 Jul 2002
Posts: 174

PostPosted: 23 Aug 2016 13:51    Post subject: closing the program after an unknown exception? Reply with quote

Thomas,

Between my robot and laptop I use a bluetooth connection. In general it is working very nicely.
Sometimes during test-drives I get an unknown exception.
Mostly because my program can not deal with a real world situation..

My problem is that VIP always closes the application. I can not see the sensorreadings the robot has made so far .
I would very much have the (extra) possibilty like the exceptionhandling for internal exceptions.
There the program does not end. And then I can properly investigate the problem.

Can something be done?

Kind regards

Ben



unknown exception.PNG
 Description:
 Filesize:  97.73 KB
 Viewed:  2348 Time(s)

unknown exception.PNG


Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 23 Aug 2016 18:57    Post subject: Reply with quote

I am not sure I fully understand what happens. When does the program end?

Also, can you press "Copy" and then paste the exception so that I can see the entire text?

By the way, there is nothing "strange" about this exception. The exception is raised in Action here (in window):

class predicates
    timerProc_tick : gui_native::timerProc.
clauses
    timerProc_tick(Window, _Message, Timer, _Time) :-
        timerAction(Action) = uncheckedConvert(timerAction, Timer),
        try
            Action()
        catch TraceId do
            _ = gui_native::killTimer(Window, Timer),
            % The timer action is not retracted from the window
            exception::continue_unknown(TraceId, "Exception in tickAction/delayCall")
        end try.

The "difficult" thing about this exception is that it takes place in a timer actions, which mean that it runs "asynchronous" compared to your normal code. But timer actions don't happen by themselves someone/something starts them. It will be a delayCall or a tickAction as stated in the exception. Do you use any such calls yourself?

Otherwise they must have been stated indirectly by something else, you could put break points on timerAction and delayCall to see where they are called from.

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
B.Hooijenga



The Netherlands
Joined: 11 Jul 2002
Posts: 174

PostPosted: 24 Aug 2016 15:15    Post subject: Reply with quote

Thomas,

I will try to be more specific.

Let us suppose that there is an exception and VIP can handle it.
Then I get an exception dialog.
After I have pressed the copy-button I get a copy.
Then the exception dialog is closed but not the application.
That is important because I keep in control of the program.
I can for instance ask for sensorreadings, give a command, close a log-file and so on.
Such things are often possible because the wireless connection keeps mostly intact in spite of the exception.

Now for the case of an unknown exception.
I get also an exception dialog.
After I have pressed the copy-button I get a copy.
Then the exception dialog is closed but also the application.
I lose control and can take no actions anymore like described above. (apart from reading the copy).
That is a pity because I am pretty sure that the wireless connection is still there.

VIP will have good reasons for always closing the application after the handling of an unknown exception.
But I would be very pleased when I have a choice in this matter. As in the first situation.


As for your other questions:
I am using a timer event. At the moment with a tickduration of 700 millisconds. But that may change.
During this time laptop and robot are exchanging information. The time they need depends on the time
the Vipprogram uses to solve some questions and the time the robot needs for his actions. And there are
other factors. The tickduration is not so easy to predict, so I am experimenting.

And there are the real world problems: empty batteries, bumping to the wall, misreadings of a sensor.
Such things are unknown errors for VIP.

Kind regards

Ben
Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 24 Aug 2016 20:14    Post subject: Reply with quote

There is absolutely nothing special about "unknown exception".

The "unknown" comes from exception::continue_unknown in these lines of code:

class predicates
    timerProc_tick : gui_native::timerProc.
clauses
    timerProc_tick(Window, _Message, Timer, _Time) :-
        timerAction(Action) = uncheckedConvert(timerAction, Timer),
        try
            Action()
        catch TraceId do
            _ = gui_native::killTimer(Window, Timer),
            % The timer action is not retracted from the window
            exception::continue_unknown(TraceId, "Exception in tickAction/delayCall")
        end try.

If you create a new GUI project and update it like this:

predicates
    onShow : window::showListener.
clauses
    onShow(_, _CreationData) :-
        _MessageForm = messageForm::display(This),
        _ = tickAction(500, {  :- _ = inverse(0) }).

class predicates
    inverse : (integer) -> integer.
clauses
    inverse(X) = 1 div X.

Then you will have a program that 500ms after it starts will perform a division by zero. It will give an exception dump similar to this:

----------------------------------------

An unknown exception has been trapped and continued

Arguments = Exception in tickAction/delayCall
unknown (exception) in window::timerProc_tick

----------------------------------------
System exception

error code = 1
ExtraInfo = Exception C0000094: Integral divide by zero
systemException (runtime_exception) in runtime_exception::runtimeExceptionRaiser

----------------------------------------
taskwindow\taskwindow.pro(24)
C:\v\user\Thomas_Linder_Puls\_vip\timerException\Exe\vipKernel.dll (0x140085D6)
C:\v\user\Thomas_Linder_Puls\_vip\timerException\Exe\vipKernel.dll (0x14006244)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x776EB652)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x776EB624)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x776D8E7F)
taskwindow\taskwindow.pro(19)
c:\v\_vp\_vip6\prodir\pfc\gui\window.pro(1016)
...


You will notice that the first entry is an "unknown exception" coming from the mentioned line, but the next entry is a "division by zero".

If you run the program you will also notice that it does not terminate after you press copy.

So there must be another reason why your program terminates.

From what I can see in your image both the first and the second entry comes from the mentioned exception::continue_unknown (which is quite strange), but the "root" of the exception is in the other end of the dump. That is where I would start the examination.

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
B.Hooijenga



The Netherlands
Joined: 11 Jul 2002
Posts: 174

PostPosted: 25 Aug 2016 15:25    Post subject: Reply with quote

Thomas,

Thank you.
Quote:
If you run the program you will also notice that it does not terminate after you press copy.

I regret to say, but I do not follow you here.
Your suggestion terminates as well.

I made the program and included the zip-file.
If you would be so kind and have a look at it

In taskwindow.pro you find a fact readings which is just a string containing data the laptop and robot has send to eachother during a testdrive.
I put it there just for demonstration it has no further importance here. Do not waste your time with it.

clauses
    onShow(_, _CreationData) :-
        _MessageForm = messageForm::display(This),
          _ = tickAction(500, {  :- _ = inverse(0) }),
%       _ = binary::getIndexed_unsigned8($[],0),
        stdio::write(readings).

After an unknown exception you can only see a part of this data.
The buttons for hide details, close application, copy and ok are are all closing the application and one can not reach the data the testdrive has left behind.

Now have a look at this, please.

clauses
    onShow(_, _CreationData) :-
        _MessageForm = messageForm::display(This),
%          _ = tickAction(500, {  :- _ = inverse(0) }),
       _ = binary::getIndexed_unsigned8($[],0),
        stdio::write(readings).

Now the buttons for hide details, copy and ok perform there action and then we return to the taskwindow.
If you do menu/file/open you get all the data the testdrive has left behind.

It is this behaviour I would like see in the case of an unexpected exception.

Kind regards

Ben



testUnknownException.zip
 Description:

Download
 Filename:  testUnknownException.zip
 Filesize:  18.48 KB
 Downloaded:  125 Time(s)

Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 25 Aug 2016 21:50    Post subject: Reply with quote

I am sorry, that I actually didn't run my test it Vip 7.5, but in our current version. You are right it does close in Vip 7.5.

Still it doesn't have any thing to do with the unknown exception, the problem is that it happens on a timer event. I am afraid that timer events works in that way in Vip 7.5.

However the problem is that your timed predicate terminates with an exception. You still haven't shown the exception dump you get, so it is difficult to assist with that part.

You can of course make sure that you timed predicate does not terminates with an exception by wrapping it with a try-catch construction.

Have you read the Exception Handling tutorial?

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
B.Hooijenga



The Netherlands
Joined: 11 Jul 2002
Posts: 174

PostPosted: 26 Aug 2016 15:50    Post subject: Reply with quote

Thomas,
Quote:
....but in our current version

May I conclude that in the next VIP-version, the closing problem does not exist anymore?
Quote:
Still it doesn't have any thing to do with the unknown exception, the problem is that it happens on a timer event

You are absolutely right, but it was the closing problem that makes things difficult in the first place.

Anyway, I started two months ago with using the timer, after reading your tutorials on delaycall and exceptions.
I was fully aware of the problems I could expect with tickaction/delaycall in the timer event.
For the simple reason that there are a lot of uncertainties.

The interaction between two bluetooth devices is a mystery
There are RS232 timing events in windows,
There is the general eventhandling in windows which has influence on timing
The solutions/algortihms I use in my program are using time.
There are events in the c-code on the robot
There is the length of the messages laptop and robot are sending to each other.
There are sensorproperties on the robot.

Well, I am experimenting with the timer, gathering results to see if it is workable. If not, I have to look for another approach.

Here is the code I use for starting up and using the timer.

predicates
    onTimeronButton_ctl : button::clickResponder.
clauses
    onTimeronButton_ctl(_Source) = button::defaultAction :-
    %    projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),
        projectptr:to_commands(edit_ctl,message_ctl,toterm("10000"),toterm(wait_ctl:getText())),
        not (timer1:isRunning()), % zet timer aan
        edit_ctl:setText("adcl\nadc\nadcr"), % geef opdracht(en)

        timer1:setTickDuration(700), % tijdsduur
        timer1:start, % beginnen
        !.
    onTimeronButton_ctl(_Source) = button::defaultAction.


predicates
    onTimer : window::timerListener.
% lees sensorwaarden in
% haal actie op
%
clauses
    onTimer(_Source, _Timer) :-
      if driving = false()
        then
            edit_ctl:setText("adcl\nadc\nadcr") ,
            projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),
            Command = projectptr:action(),
            _ = vpi::processEvents(),
            edit_ctl:setText(Command), % geef opdracht(en)
            driving := true()
        else
            projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),
            driving := false()
     end if,
  %    projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),
   %   edit_ctl:setText("adcl\nadc\nadcr"). % geef opdracht(en)
      !.
    onTimer(_Source, _Timer).

By changing the tickduration to 400 milliseconds I could force the program to give an unknown exception.

The robot is reading three sensors and sends information back.
We are lucky and can just read some output.
On the screendump we see an empty tail. (left under).
I also can see (OE) in the header that this happens during the last command (adcr).
Apparently the RS232 buffer is empty: nothing to read. 400 millisecond is not enough.

Here is the full text:


========================================
Dump: 2016-08-26 12:51:56
----------------------------------------
Exception: unknown (exception)

An unknown exception has been trapped and continued

Predicate name = timerProc_tick
Arguments = Exception in tickAction/delayCall

continued 2016-08-26 12:39:45
ThreadId: 7028
Class name: window
Predicate name: timerProc_tick



----------------------------------------
Exception: indexOutOfRange (binary_exception)

Index out of binary limits

Predicate name = checkOffsetForSetGetValue
SourceCursor = pfc\binary\binary.pro(606,13)
Index = 0
binary size = 4
element size = 1

raised 2016-08-26 12:39:45
ThreadId: 7028
Class name: binary
Predicate name: checkOffsetForSetGetValue


c:\program files (x86)\visual prolog 7.5\pfc\exception\exception.pro(198)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipKernel.dll (0x140083A5)
c:\program files (x86)\visual prolog 7.5\pfc\exception\exception.pro(198)
c:\program files (x86)\visual prolog 7.5\pfc\exception\exception.pro(182)
c:\program files (x86)\visual prolog 7.5\pfc\binary\binary_exception.pro(18)
c:\program files (x86)\visual prolog 7.5\pfc\binary\binary.pro(607)
c:\program files (x86)\visual prolog 7.5\pfc\binary\binary.pro(237)
boards\boardsupport.pro(394)
boards\boardsupport.pro(332)
boards\boardsupport.pro(253)
boards\boardsupport.pro(221)
boards\boardsupport.pro(92)
testing\userinterfacers232.pro(509)
c:\program files (x86)\visual prolog 7.5\pfc\gui\window.pro(1062)
c:\program files (x86)\visual prolog 7.5\pfc\gui\window.pro(1000)
C:\WINDOWS\System32\USER32.dll (0x7795D273)
C:\WINDOWS\System32\USER32.dll (0x7793EF95)
C:\WINDOWS\System32\USER32.dll (0x7793E283)
C:\WINDOWS\System32\USER32.dll (0x7794C521)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipVpi.dll (0x1531A4EF)
c:\program files (x86)\visual prolog 7.5\pfc\vpi\vpi.pro(21)
c:\program files (x86)\visual prolog 7.5\pfc\windowsapi\exe_api\exe_api.pro(63)
c:\program files (x86)\visual prolog 7.5\pfc\application\exe\mainexe.pro(21)
main.pro(26)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipKernel.dll (0x1400884B)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipKernel.dll (0x14008B0B)
C:\Users\Ben\Documents\RS232_Messages\Exe\RS232_Messages.exe (0x00548F67)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x77B50609)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x77B505D4)

----------------------------------------
OS information:

Windows 8 64-bit (Build 9200)
Number Of Processors: 4 PageSize: 4096 Processor: 8664 level: 6 revision: 17665
ProcessorNameString: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
VendorIdentifier: GenuineIntel
Identifier: Intel64 Family 6 Model 69 Stepping 1
~MHz: 2295

The code where the predicate gets an empty binary is here.

predicates
    tailCheck:(binary) -> boolean.
clauses
    tailCheck(Tail) = true() :-
        Length = binary::getSize(Tail),
        etx = binary::getIndexed_unsigned8(Tail,uncheckedConvert(core::positive,Length-1)), % Index starts at 0
        message:write("EndOfText = Ok\n"),
        !.
   tailCheck(Tail) = false() :-
        Length = binary::getSize(Tail),
        message:write("EndOfText must be ",etx," instead of ",binary::getIndexed_unsigned8(Tail,uncheckedConvert(core::positive,Length)),"\n"),
        !.

Thanks for all your suggestions
Kind regards

Ben



unknown_exception_400millisec.PNG
 Description:
 Filesize:  237.37 KB
 Viewed:  2294 Time(s)

unknown_exception_400millisec.PNG


Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 28 Aug 2016 17:06    Post subject: Reply with quote

Yes, the mentioned problem does not exist in the next version.

You can easily make it disappear in your version also; simply by catching all exceptions in your times predicate:

predicates
    onTimer_safe : window::timerListener.
clauses
    onTimer_safe(Source, Timer) :-
        try
            onTimer(Source, Timer)
        catch TraceId do
            errorPresentationDialog::present(TraceId)
        end try.


_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
B.Hooijenga



The Netherlands
Joined: 11 Jul 2002
Posts: 174

PostPosted: 29 Aug 2016 13:19    Post subject: Reply with quote

Thomas,

I tried your suggestion, again with forcing an unknown exception with 400 milliseconds time duration instead of 700.
But no result: it does not work: my program hangs, the robot goes wild and bluetooth is not happy either.
No harm done.

Then I tried this:

predicates
    onShow : window::showListener.
clauses
    onShow(_, _CreationData) :-
        _MessageForm = messageForm::display(This),
         try
         _ = tickAction(500, {  :- _ = inverse(0) })
        catch TraceId do
            errorPresentationDialog::present(TraceId)
        end try.
 
class predicates
    inverse : (integer) -> integer.
clauses
    inverse(X) = 1 div X.

No effect. The program just closes on all buttons.

So, I am afraid I have to wait until the new VIP version arrives.
In the meantime I try to investigate my program further. There is always room for improvement!

Kind regards

Ben
Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 30 Aug 2016 10:04    Post subject: Reply with quote

That is the wrong place you catch the exception.

It is the code that is exceuted in the timer call that must catch the exception:

predicates
    onShow : window::showListener.
clauses
    onShow(_, _CreationData) :-
        _MessageForm = messageForm::display(This),
        delayCall(500, {  :- _ = inverse_safe(0) }).

class predicates
    inverse_safe : (integer) -> integer.
clauses
    inverse_safe(X) = R :-
         try
            R = inverse(X)
        catch TraceId do
            errorPresentationDialog::present(TraceId),
            R = 0
        end try.

class predicates
    inverse : (integer) -> integer.
clauses
    inverse(X) = 1 div X.

I have changed the tickAction to a delayCall because otherwise you will get an exception each 500 ms and that will give quite a lot of dialogs. But the principle is the same: the timer action should never exit with an exception.

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
B.Hooijenga



The Netherlands
Joined: 11 Jul 2002
Posts: 174

PostPosted: 5 Sep 2016 11:55    Post subject: Reply with quote

Thomas

Because I am using a timerevent in my robotprogram I was a little bit confused about the delaycall.
This is the solution I eventually use.
The trick is to stop the timer in case of an systemerror.
It seems to work well.
I did not see the term unknownexception anymore by driving the robot.


facts
    timer1 : timerControl := erroneous.

predicates
    onShow : window::showListener.
clauses
    onShow(_Source, _Data) :-
        timer1:= timerControl::new(This),
        stdio::write("tickduration = ",timer1 :getTickDuration(),"\n"),
        timer1:start.

predicates
    onTimer : window::timerListener.
clauses
    onTimer(_Source, _Timer) :-
    %    delayCall(1, {  :- _ = inverse_safe(4) }).
        _ = inverse_safe(0).


predicates
    inverse_safe : (integer) -> integer.
clauses
    inverse_safe(X) = R :-
         try
            R = inverse(X),
            stdio::write(R,"\n")
        catch TraceId do
            timer1:stop,
            errorPresentationDialog::present(TraceId),
            R = 0
        end try.

class predicates
    inverse : (integer) -> integer.
clauses
    inverse(X) = 1 div X.

Thanks very much for your help.

Kind regards

Ben
Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 6 Sep 2016 20:08    Post subject: Reply with quote

I think you should drop using the timerControl it is an "outdated" thing. Instead you should either use:
  • delayCall for one "shots"
  • tickAction for repeated "shots"
Basically the tickAction does the same as the timerControl just without an extra control.

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    discuss.visual-prolog.com Forum Index -> Visual Prolog All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum