Bail out from parent procedure

Just starting out? Need help? Post your questions and find answers here.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

That's what I do as well, and I find it leads to 3 lines of error checking for every 1 line of program logic. Which is sort of boring.
Yes, mine tend to proceed along the following lines so that when an error is flagged, an error report is given automatcally and the main procedure terminates.

Code: Select all

Procedure Main()
  If ReportError(Proc1()) = 0
    If ReportError(Proc2()) = 0
      If ReportError(Proc3()) = 0
        If ReportError(Proc4()) = 0

        ...blah blah

        EndIf
      EndIf
    EndIf
  EndIf
ProcedureReturn
I may look like a mule, but I'm not a complete ass.
okasvi
Enthusiast
Enthusiast
Posts: 150
Joined: Wed Apr 27, 2005 9:41 pm
Location: Finland

Post by okasvi »

Trond wrote:
the complete processing can be within a thread that will be terminated if an error occurs,
so the level of nesting is no longer a problem and the main-thread isn't touched at all....
I will have to allocate a lot of memory, which will be flushed down the toilet when I use KillThread().
1. OnErrorGosub(@FreeAllocatedMemory())
2. SetErrorNumber($DEADC0DE) or !int3 (?)
3. ExitThread_(0)

:)
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

okasvi wrote:
Trond wrote:
the complete processing can be within a thread that will be terminated if an error occurs,
so the level of nesting is no longer a problem and the main-thread isn't touched at all....
I will have to allocate a lot of memory, which will be flushed down the toilet when I use KillThread().
1. OnErrorGosub(@FreeAllocatedMemory())
2. SetErrorNumber($DEADC0DE) or !int3 (?)
3. ExitThread_(0)

:)
Then I'll have to keep track of all allocated memory.
okasvi
Enthusiast
Enthusiast
Posts: 150
Joined: Wed Apr 27, 2005 9:41 pm
Location: Finland

Post by okasvi »

Well, you can't ask for miracles :P
Code simple wrappers for memory functions to do it, so you don't have to change existing code that much...
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

I will have to allocate a lot of memory, which will be flushed down the toilet when I use KillThread().
ermn...
I think the MEM you allocate within the thread will be freed by the OS when you kill the thread.
if you need to keep the MEM, allocate it outside the thread...

besides, I thought you meant "an error" in that way,
that your processing reveals an incoherence or such,
not a real error that should be handled via OnError...
did I mistake you in that point?
oh... and have a nice day.
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Killing a thread frees NO memory, not even the stack area of the thread! Thats why using KillThread() is highly discouraged.
(should only be used in extreme cases)
quidquid Latine dictum sit altum videtur
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

I think what you are looking for is something like setjump() and longjump() in C.

Here is an example:

Code: Select all

; =======================================================================

Structure JumpData
  EAX.l
  ECX.l
  EDX.l
  EBX.l
  ESP.l
  EBP.l
  ESI.l
  EDI.l
  ReturnAddr.l
EndStructure

DisableDebugger

; Stores the current program state in *mark, making it a possible target for a jump
; The procedure returns normally when the jump is set up, and when LongJump() is called,
; the program execution will again return from this procedure and continue there.
;
; Returnvalue:
;   - 0 when called to setup a jump target
;   - 'ReturnValue' from LongJump() after a jump was made back to this location
;
Procedure SetJump(*mark.JumpData)
  !mov eax, [p.p_mark]
  !pop dword [eax+32]
  !add esp, 4
  
  !mov [eax], dword 0
  !mov [eax+4], ecx
  !mov [eax+8], edx
  !mov [eax+12], ebx
  !mov [eax+16], esp
  !mov [eax+20], ebp
  !mov [eax+24], esi
  !mov [eax+28], edi

LongJump_Target:
  !mov edi, [eax+28]
  !mov esi, [eax+24]
  !mov ebp, [eax+20]
  !mov esp, [eax+16]
  !mov ebx, [eax+12]
  !mov edx, [eax+8]
  !mov ecx, [eax+4]
  
  !push dword [eax+32]
  !mov eax, [eax]
  !ret
EndProcedure

; Jumps back to the given *mark. SetJump() will return on the old location with
; the specified 'ReturnValue'.
; The LongJump() procedure never returns to where it was called from.
;
; Note: You can only jump out of procedures, not into them. So when SetJump()
; is called inside a procedure, you can only jump back to it while the execution
; has not yet left that procedure (as its stack frame is then destroyed, making it invalid to jump to)
;
Procedure LongJump(*mark.JumpData, ReturnValue.l)
  *mark\EAX = ReturnValue
  !mov eax, [p.p_mark]
  !jmp l_longjump_target
EndProcedure

EnableDebugger

; =======================================================================
; Example:
; =======================================================================


Global jump.JumpData


Procedure Processing(value)
  Debug "entering procedure: "  + Str(value)
  
  If value = 10
    LongJump(@jump, 1)
  ElseIf Value = 20
    LongJump(@jump, 2)
  Else
    Processing(value+1)
  EndIf    

  Debug "leaving procedure: " + Str(value)
EndProcedure

; Set up the jump position. In this example, the execution will return
; 3 times from this position. First normally, and then each time the LongJump()
; is called
;
Select SetJump(@jump)
  Case 0: Debug "jump mark set"
          Processing(0) ; start our procedure
  
  Case 1: Debug "error 1"
          Debug "trying again from 11"
          Processing(11) ; start the processing again

  Case 2: Debug "error 2"
  ; ...
EndSelect

Debug "program end"
End
Notes:
  • The CallStack display of the Debugger will be wrong when you call this, as the debugger does not notice
    that the procedures returned. (because technically they didn't)
  • This of course does not take care of any allocated memory. (also not local String variables, LinkedLists and Arrays)
    So when using this, you have to handle these things in a different way, or you will get a memory leak.
    (Use global/static variables, or allocate memory blocks for them that you register somewhere so you
    can correctly free them all after a LongJump)
It is not a perfect solution, as it requires extra work to get right, but it works.
quidquid Latine dictum sit altum videtur
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Thanks, it's what I'm looking for, except for the string problem.
Post Reply