END/STOP and destructors

General discussion for topics related to the FreeBASIC project or its community.
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

END/STOP and destructors

Post by speedfixer »

END:
Usage of this statement does not cleanly close scope. Local variables will not have their destructors called automatically, because FreeBASIC does not do stack unwinding. Only the destructors of global variables will be called in this case.

For this reason, it is discouraged to use End simply to mark the end of a program; the program will come to an end automatically, and in a cleaner fashion, when the last line of module-level code has executed.
STOP:
Note: STOP is not implemented properly yet; currently it is the same as SYSTEM.
For each library I write, I write an exit function that could be called a destructor. Each would clean up mutexes, CONDs, special allocations, terminate threads, etc. I use Linux, only. Frequently, the console state (local or remote) doesn't get cleanly cleared. I have a function set that clears this, also. I even have a few debug routines that give me good data on fail situations.

I have one general destructor that tests if a library is present (at compile time) and will call each appropriate exit function at program close.
Perfect.

END does what it says: it does not call any destructors.

STOP does.
STOP from anywhere will call my general destructor and then all my exit code is executed. Program traps can correctly dump info and close everything down nicely without me having to unwind everything. I can kill a program from anywhere and everything is happy.

Should anyone choose to work on this function (STOP) ---

PLEASE DON'T CHANGE THIS 'FEATURE'

This 'incomplete' function helps SO MUCH as it is.
I just wanted to record somewhere that it works this way for me.

david
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: END/STOP and destructors

Post by fxm »

With Windows:
- Neither END, neither STOP, neither SYSTEM calls the destructors of the local variables defined in the implicit main scope.
- By cons, the module destructor is always called even with END or STOP or SYSTEM.

Question: Why put a END/STOP/SYSTEM at the end of the code ?
It is best not to put anything at all !
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: END/STOP and destructors

Post by jj2007 »

Just for curiosity: What would a "destructor" of local variables typically do...?
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: END/STOP and destructors

Post by fxm »

- For the predefined-type variables, only the var-len strings have a destructor. Its goal is to free the dynamic memory reserved for the string character data (at address 'Strp(string_name)') if they exist (not empty string).
- For a user-defined-type variables, in addition to an eventual implicit destructor (due to the contained fields or inherited types), the user may add its own actions by defining an explicit destructor.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: END/STOP and destructors

Post by jj2007 »

Thanks, that makes sense. In fact, except for exotic cases, only a dynamically allocated string needs a destructor. Numerical variables on the stack, for example, don't require any action on exit.
adele
Posts: 47
Joined: Jun 13, 2015 19:33

Re: END/STOP and destructors

Post by adele »

Hi,
fxm wrote:With Windows:
Question: Why put a END/STOP/SYSTEM at the end of the code ?
It is best not to put anything at all !
Maybe to explicitly pass the returncode / errorcode to the OS? :)
BTW:
System, Stop and End produce all the same code (FBCx64 /WIN):

Code: Select all

mov	 ecx, 0 ' the "0" can be set by (retvalue)
call	fb_End
mov	eax, DWORD PTR -12[rbp]
leave
ret
Adi
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: END/STOP and destructors

Post by fxm »

In that case, one workaround is to include all main part execution code (except any procedure declaration/definition and obviously END/SCOPE/SYSTEM) inside a scope block:

Code: Select all

Type UDT
  Dim As Integer I = 1234
  Declare Destructor ()
End Type
Destructor UDT ()
  Print "Destructor called"
End Destructor  

Dim As Integer returnCode

Scope
  '.....
  Dim As UDT u
  Print u.I
  '.....
  returnCode = 5678
End Scope
Sleep

End returnCode
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

Re: END/STOP and destructors

Post by speedfixer »

I DON'T put an END/STOP/SYSTEM at the end of my code.

My library management/compile system will automatically put a call to a sub marked as a destructor in my code. THAT will pull in any exit code for any library I use. As a destructor, it runs last.

Specifically, if a library has conditionals or mutexes, memory allocations, even threads left running - for each library I make a specific exit sub that will clean up its own leftovers. Simple local variables in the main or functions are not included. Not needed.

Every library I make is static compiled. Most functions have their own source file. This cuts down on the un-needed includes at link time. If the library is stable, it is compiled without error checking, optimized, and rarely touched again. I have over 40 of these libraries. EACH has its own exit sub. This cuts WAY down on the compile time and size for large programs. Did I mention? I precompile both a single thread and a multithread version of each lib. At this time, it takes less than two minutes to recompile every lib I have after a large linux update, and I expect to get this down under a minute soon.

The destructor sub is not pre-compiled. In that destructor, I simply include a #define that is tested for each library.

Ever close a program and discover later that a thread is still running? Doesn't happen to me.
I don't ever have to explicitely kill or clean up anything in my main code. I DON'T build large class/UDTs that will pull along a lot of RTTI or other overhead that gets really hard to debug later. There is a reason bugs hide in c++ for decades, and why every efficient OS is usually written in c, not c++.

If you are layers deep in your code and hit what eventually would be a terminal error for your program, you can STOP out and your destructors will be called. This is why I want STOP to not change. END will not do this, at least in Linux. Or, mybe it will and I just haven't tested the final main destructor with it yet. I don't remember.

I can't speak for Windows - gave that up a long time ago (except for games: I like shooters.)
In Linux, a STOP anywhere will call my destructor - until someone 'fixes' it.
Very nice when, in Linux, the console/terminal does not always get cleared correctly by the FB graphics thread. I have a lot of systems here at home.

A hard crash is still a hard crash, though. No way around that. Then you debug in something like gdb.

For me, the main stays the same. The program logic is clear in the main without extra clutter or digging into the functions to see what is going on. Each library has its own dim, declare, init, include, exit files that my system includes as needed. Define one flag (or many) and console routines or IPC or thread management or box management or AI libs AND any dependency libs are included - in the right place, and only the functions I actually use are linked. I never have an executable over 350k.


david
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: END/STOP and destructors

Post by fxm »

If in Linux an END disables the execution of the module destructor, I think the bug is rather here.
The STOP (which allows the execution of the module destructor) is already working normally (no reason to change it).
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

Re: END/STOP and destructors

Post by speedfixer »

I agree.
The notes in the wiki suggest that someone believes STOP is not complete or broken.
sancho3
Posts: 358
Joined: Sep 30, 2017 3:22

Re: END/STOP and destructors

Post by sancho3 »

Even if it were to be 'fixed', couldn't you just use System?
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

Re: END/STOP and destructors

Post by speedfixer »

OK.

I have a few cases where END has been a really poor choice. If END should never be used, I guess it is just a legacy compatibility function and it should be noted as such in the documents. Otherwise, every newbie will wonder why it exists.

SYSTEM may indeed work, though one should choose and use a function for its intent, not its side effect.

I will rigourously explore the operations of END - STOP - and SYSTEM (in Ubuntu Linux) to see how each behaves.

david
speedfixer
Posts: 606
Joined: Nov 28, 2012 1:27
Location: CA, USA moving to WA, USA
Contact:

Re: END/STOP and destructors

Post by speedfixer »

Started testing - things got more complex.

FreeBASIC Compiler - Version 1.06.0 (04-09-2017), built for linux-x86_64 (64bit)
Copyright (C) 2004-2016 The FreeBASIC development team.

64 bit Lubuntu 16.04.4
AMD FX 6100 8 GB

Code: Select all

' destructor.bas

' Show *when/if* code calls global destructor
' uncomment/comment each case in turn to see results

' echo ' ' && echo ' no exx ' && fbc test.bas && echo ' '
' echo ' ' && echo ' with exx ' && fbc -exx test.bas && echo ' '

declare sub dest1
screen 21
dim as integer eee

''----------  case 1  -------------
'print "AAA"
'print a(9); "XXX"

' will not compile

''----------  case 2  -------------

'dim as string a(5)
'print "AAA"
'print a(4); "XXX"

' compile
'   AAA, XXX, ZZZ, DDD

''----------  case 3  -------------

'dim as string a(5)
'print a(9)

' compile with no -exx:
'   screen crash, seg fault

''----------  case 4 -------------

'dim as string a(5)
'print "AAA"
'print a(9); "XXX"

' compile with no -exx:
'   AAA, XXX, ZZZ, DDD, no message

''---------------------------------
''----------  case 5  -------------

'dim as string a(5)
'dim as integer x
'x = 99
'print a(x);

' compile with no -exx:
'   ZZZ - DDD - no error message
' compile with -exx:
'   screen crash - destructor called - then error message to console
''----------  case 6  -------------

'dim as string a(5)
'dim as integer x
'x = 99
'print a(x);
'eee = err
'if eee <> 0 then
    'while inkey <> "": sleep 10,1: wend
    'print "YYY: error! "; eee : sleep
'end if

' compile with no -exx:
'   screen crash - DDD - no error message - console not reset correctly
' compile with -exx:
'   screen crash - DDD - console error message - console reset correctly

''===================================================
' stopped testing - other things to do today
''===================================================

''===================================================

while inkey <> "": sleep 10,1: wend: print "ZZZ: sleep " : sleep

sub dest1 destructor

    print "DDD  You just got destructed!"

    while inkey <> "": sleep 10, 1: wend
    while inkey = "": sleep 300, 1: print ".";: wend
end sub
Both PRINT and error processing changes things a lot.
I am guessing I would have about 12+ more changed code sets to just map the effects of each.

No time for this right now. At least I have a better clue when/where to look to fix a failed console/terminal reset on exit.
Also, I suspect that the host environment gets 'muddied' by some cases of these fails. NOT calling destructors must have consequences.
Crashing the screen thread yet not terminating FB must have consequences.

david
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: END/STOP and destructors

Post by coderJeff »

END/STOP/SYSTEM had different outcomes on QB. In FB, all do the same thing. Documentation is misleading. Read the docs closely and you will see STOP currently is like SYSTEM, and SYSTEM is same as END.

Not sure where to add this to the docs (it could be expanded a lot), but here is the simplified life cycle of an FB program (exact names may vary):

1) mainCRTStartup --> __main --> __do_global_ctors
2) libfbrt defines a global ctor that gets executed before all other global ctors to intialize fbrt & console
3) any module level code not in main module is implicitly added as global ctor
3) __do_global_dtors is added to the list of exit handlers -- atexit() C function
4) call fbc MAIN() - this is YOUR (implicit) main function in the main module
5) call to fb_Init() to finish init of the program
6) YOUR PROGRAM HERE
7) if you have no END statement, fbc compiler adds one implicitly to the end of the implicit main function
8) Any End/Stop/System calls fb_End
9) fb_End Calls exit()
10) exit() calls all the exit handlers, including __do_global_dtors
11) fbrt defines a global dtor to clean-up library - prints an error message if one is saved
12) if for some reason main actually returned instead, (RET instruction), mainCRTStartup calls the exit handlers.
13) calling the exit handlers is not expected to return, the process ends

There's actually, many more details depending on platform, shared libraries etc, -exx enabled, etc. You can get different results depending on how the program fails. If fb can catch the error, like a NULL pointer check, you get a nice exit message. If it's a hard crash, like an unhandled segfault, program just halts.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: END/STOP and destructors

Post by fxm »

In your example, case 3 and case 4 never compile.
(the value limits of numeric literals used as static array indexes are always checked at compilation phase)
Post Reply