PDA

View Full Version : Executing C++ before and after main()



fullmetalcoder
9th May 2007, 15:44
I'm writing a C++ component that brings some requirements and after intense web browsing I did no find any clue...


How to make some pieces of code called before main() and also static constructors?
How to make some pieces of code called after main() and also static destructors?
How to ensure that this hack is portable?
Thanks in advance for your help.

jpujolf
9th May 2007, 16:25
I'm writing a C++ component that brings some requirements and after intense web browsing I did no find any clue...



How to make some pieces of code called before main() and also static constructors?
How to make some pieces of code called after main() and also static destructors?


I've made this trick :


// GlobalClass.h

class GlobalClass
{
static GlobalClass * m_Instance;
public :
GlobalClass();
~GlobalClass();

// here stuff, if needed...
};



// GlobalClass.cpp

GlobalClass * GlobalClass::m_Instances = 0;

GlobalClass::GlobalClass ()
{
// To avoid dlouble execution...
assert ( m_Instance );
m_Instance = this;
// Before main stuff
...
}

GlobalClass::GlobalClass ()
{
m_Instance = 0;
// After main stuff
...
}




GlobalClass GLOBALSTUFF;

int main ( int argc, char *argv[] )
{
// Here your code...
}

How to ensure that this hack is portable?[/LIST]

I think that's portable...


Thanks in advance for your help.

Not at all, if I hope this was useful for you...

moowy
9th May 2007, 17:22
This technique is called singleton. U can read more about it here: http://en.wikipedia.org/wiki/Singleton_pattern

fullmetalcoder
9th May 2007, 17:45
I've made this trick :


// GlobalClass.h

class GlobalClass
{
static GlobalClass * m_Instance;
public :
GlobalClass();
~GlobalClass();

// here stuff, if needed...
};

This is very similar to singleton pattern and something used by Qt (apart from the fact that it's probably not thread safe) : Q_GLOBAL_STATIC(TYPE, NAME) macro defined in qtglobal.h

However it does not solve my problem because it won't be called BEFORE ALL STATIC CONSTRUCTORS of the program and attached libraries...

marcel
9th May 2007, 18:05
I'm afraid the answer is simple: You can't do that!
You have no control over main() - how or when it is executed.
The point is that you don't call main(), it is the other way around.

I actually am curious to hear a solution for this.

What should your component do? Maybe there is another solution.

Regards

fullmetalcoder
9th May 2007, 18:35
I think there should be a solution because Qt someway does it (or are static object used?) to manage object cleanup and things like that... Anyway my component is an application wide memory pool : http://www.qtcentre.org/forum/f-qt-programming-2/t-fast-serializationdeserialization-page2-6838.html

My problem, as described in this thread, is that I get unexpected crash when using my custom alloc()/dealloc() functions whereas replacing them by qMalloc()/qFree() works well. One could think that my functions are directly responsible for these segfaults but actually it looks trickier than this because my allocator seems to work quite well and segfaults occur in two precise location only : QMutex::lock() (http://doc.trolltech.com/latest/qmutex.html#lock) and QMutex::unlock() (http://doc.trolltech.com/latest/qmutex.html#unlock) called on wrong pointers from QReadWriteLock::lock() (http://doc.trolltech.com/latest/qreadwritelock.html#lock) or QreadWriteLock::unlock() (http://doc.trolltech.com/latest/qreadwritelock.html#unlock)...

I thus thought that forcing EVERY SINGLE object to be allocated through the pool would solve this but....

marcel
9th May 2007, 18:55
Regarding the segfaults:
Are you allocating from more than one thread.

The global memory pool should be locked for exclusive access by the current allocating thread ( mem allocation is not atomic ). It is possible, if you use more than one thread, that two threads may try to allocate the same block in the mem pool, resulting in a mem violation -> therefore the segfault.


Qt most likely uses static objects that are destroyed in the same time (or after ) the QApplication.


The main function is the application entry point - it is called by the OS when you run a program. You can force something to be called before main, or after main exits.

marcel
9th May 2007, 18:56
Could we see your custom allocator/deallocator and how you use it? Maybe you can show us where exactly you get the segfaults...

Regards

vermarajeev
10th May 2007, 07:03
Well, I dont if I'm correct. I was asked the same question by my friend, How to call display a string before main() and another string after main()...

Something like

int main()
{
cout<<"Love";
}

Now without touching main() I need to display "I Love You"
So the solution is something like this


class A
{
public:
A(){ cout<< "I"; }
~A() { cout<<"You"; }
};
A a;
int main()
{
cout<<"Love";
}

Here 'I' is displayed before main and 'You' after main.. Do you want something like this???

//I have not tested above code so might be incorrect....

fullmetalcoder
10th May 2007, 20:21
Regarding the segfaults:
Are you allocating from more than one thread.
AFAIK there shouldn't be ANY thread apart from the main/GUI one in the test case...


The global memory pool should be locked for exclusive access by the current allocating thread ( mem allocation is not atomic ). It is possible, if you use more than one thread, that two threads may try to allocate the same block in the mem pool, resulting in a mem violation -> therefore the segfault.I'm afraid it's trickier than that... When I serialize access to the pool (for both alloc and dealloc) through QMutex I get a deadlock message and the application hangs...


The main function is the application entry point - it is called by the OS when you run a program. You can force something to be called before main, or after main exits.
That's not exactly true... For example, under Linux some other functions are called before main and after (mainly things related to global objects and added internally by the compiler but still...). I found an example on the web showing how to do that but it worked only with recent versions of MSVC so I just dropped it. Anyway singleton may help me here because it would ensure that the pool is created as soon as program asks for memory allocation.


Could we see your custom allocator/deallocator and how you use it? Maybe you can show us where exactly you get the segfaults...
Sure! But it probably won't help... As far as I investigated, everything is allocated and initialized properly but for some reason the pointer to one of the allocated QReadWriteLock is somewhere decremented by one byte causing the segfault... I don't know where this decrement is done and I've no idea why it occurs when my allocator is used...

@vermarajeev :
Your trick will work but there is no way to ensure that A::A() gets called BEFORE ALL OTHER STATIC CTORs and A::~A() AFTER ALL OTHER STATIC DTORs....

marcel
10th May 2007, 20:36
Understood.
Can you give a link to that example you were talking about?

About the allocator/deallocator: if you don't manage to solve it, you may as well post it, maybe we can find some solution.

Why don't you use a QMutex instead of a QReadWriteLock?


In many cases, QReadWriteLock is a direct competitor to QMutex (http://www.qtcentre.org/forum/qmutex.html). QReadWriteLock is a good choice if there are many concurrent reads and writing occurs infrequently.

I believe a QMutex( actually you need two ) is more trustworthy :). You could trace the errors easier than with a rw lock.

Regards

wysota
10th May 2007, 22:30
Obviously the trick from the beginning of the thread is neither working or portable (the compiler may change the order of calls if it finds it useful).

A general answer is that you need your own startup code for that. One that doesn't call main() but first executes your code and only then jumps to the starting address of the application (not "main"!). On Linux you could probably use a preload object with a small assembly code that does what I explained, but this certainly won't be portable. A portable solution is hardly doable for an already built application (when you can't substitute the startup code directly yourself).

fullmetalcoder
11th May 2007, 11:37
About the allocator/deallocator: if you don't manage to solve it, you may as well post it, maybe we can find some solution.
I've posted a link to an older version in another thread : http://www.qtcentre.org/forum/f-qt-programming-2/t-fast-serializationdeserialization-6838.html


Understood.
Can you give a link to that example you were talking about?
Sure!, It's packed with the allocator code


Why don't you use a QMutex instead of a QReadWriteLock?
I don't use QReadWriteLock, Qt does...


I believe a QMutex( actually you need two ) is more trustworthy :). You could trace the errors easier than with a rw lock.
One appears to be enough and is safer because otherwise parallel alloc/dealloc would be allowed which would be quite bad...



Obviously the trick from the beginning of the thread is neither working or portable (the compiler may change the order of calls if it finds it useful).

A general answer is that you need your own startup code for that. One that doesn't call main() but first executes your code and only then jumps to the starting address of the application (not "main"!). On Linux you could probably use a preload object with a small assembly code that does what I explained, but this certainly won't be portable. A portable solution is hardly doable for an already built application (when you can't substitute the startup code directly yourself).
That's what I was thinking about but there does not seem to be a standard and portable way to achieve that...

OK, that was for the answers! The nice thing is that, after some hard work I've been able to fix it all :

There must have been a problem in the allocator but rewriting its internal functions seems to have fully fixed it
A tricky singleton alternative pattern fixes the problem of prior initialization of the pool before any new call. The only downside is that the size of the pool becomes fixed on compile time... Will do for my purpose so it's not so embarassing after all...Only one problem left : QLibrary now refuses to load my plugin... I'll see if it comes from an error of mine or a broken internal...

Thank you all for your advices. :)

fullmetalcoder
11th May 2007, 19:49
Only one problem left : QLibrary now refuses to load my plugin... I'll see if it comes from an error of mine or a broken internal...
It was actually a LD_LIBRARY_PATH quirk so everything is fine! :)

But (yeah, there MUST always be a but...), there is one trouble left :( I'm now able to use a memory pool all along the execution with thread safety, pretty good performances and no leak but I get screwed on program end... Due to the way Qt works (many underlying static components and auto object cleanup) I just can't destroy my pool at the end of the main loop or I get a segfault... I tried using a static wrapper object to do it after but it doesn't help. Actually my big problem is that I need to make sure that Qt libs get unloaded/uninitialized before destroying the pool. So we're back to the thread topic : how do I hook some code at a post-main() entry point?

Just to help you understanding what's going on, here comes a gdb backtrace :

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1208957232 (LWP 4905)]
QMutex::lock (this=0xb7e170e4) at thread/qmutex.cpp:177
177 thread/qmutex.cpp: No such file or directory.
in thread/qmutex.cpp
(gdb) bt
#0 QMutex::lock (this=0xb7e170e4) at thread/qmutex.cpp:177
#1 0x0026c7ec in qUnregisterResourceData (version=1, tree=0xbc6620 "", name=0xbc6b20 "", data=0xbc7a60 "")
at ../../include/QtCore/../../src/corelib/thread/qmutex.h:93
#2 0x00b86dec in qCleanupResources_qstyle () at .rcc/release-shared/qrc_qstyle.cpp:15616
#3 0x00b86e0b in __tcf_0 () at .rcc/release-shared/qrc_qstyle.cpp:15619
#4 0x01022c0c in __cxa_finalize () from /lib/libc.so.6
#5 0x00706393 in __do_global_dtors_aux () from /usr/local/Trolltech/Qt-4.2.2/lib/libQtGui.so.4
#6 0x00b86f1c in _fini () from /usr/local/Trolltech/Qt-4.2.2/lib/libQtGui.so.4
#7 0x0060f0fd in _dl_fini () from /lib/ld-linux.so.2
#8 0x0102298e in exit () from /lib/libc.so.6
#9 0x0100d72c in __libc_start_main () from /lib/libc.so.6
#10 0x080493d1 in _start ()
(gdb)

fullmetalcoder
11th May 2007, 20:13
I've found a very interesting link after some more investigations and web research : http://www-128.ibm.com/developerworks/eserver/library/es-MigratingWin32toLinux.html#N10083

There are unfortunately some issues left :

For some reasons (possibly to allow it to make use of shared components), this custom destructor is called before libraries unloading so segfaults still occurs unless I call abort() which is IMHO quite bad, even though harmless...
Using the "standard" _fini() entry point seems to work better since the segfault disappears but any debug output placed in it (via printf, qDebug, whatever...) does not show up and I suppose that in this case libraries are not unloaded at all because this entry point is AFAIK, just like new/delete operators, a substitution to existing symbols available in C/C++ runtime...
How portable is this solution???

ct
12th May 2007, 19:19
Did you guys find the answer ? ok this may not be useful for you but I think sometimes ago I was trying to achieve "Reflection" in C++. I noticed something strange through some of the examples, it was the way a particular line of code has to be written for it to run before the main...




#include<iostream>

using namespace std;

int myfunc()
{
cout<<"hello world"<<endl;
return 1;
}
class myClass{

public:
static int func(){ cout << "Inside static function"<<endl;
return 1;
}
myClass(){ cout<<"inside my class constructor"<<endl; }
~myClass();

};

static int s = myClass::func();
static int n = myfunc();


int main(int argc,char** argv)
{
cout << "inside main"<<endl;
return 0;
}
static int g = myfunc();


if you don't use static then the code won't compile..btw how do you call a function right after main..becuase main is the point your program will be starting and after main ends the program ends..so guess..I don't have a answer to that..it does appear to be calling after main but it calls myfunc() twice before entering main...We can call static functions or global functions but it *has* to return something and we need to put it in a static variable....if anyone can explain why we need to do this..that would be great...i just know it works this way..

However, I actually don't have much idea about the seg faults that you guys are talking about....

wysota
12th May 2007, 20:03
If you want to call something after main, you may use atexit().

fullmetalcoder
13th May 2007, 08:06
If you want to call something after main, you may use atexit().
That's how gcc registers function declared with __attribute__((destructor)) and it's actually not what I want because my tests showed that such a function will be called before shared libs unloading, resulting in segfaults when Qt tries to do its cleanup...

wysota
13th May 2007, 08:28
I was referring to what my preposter said, not to your situation, I know it's different.