Problem: die Methode Execute wird nie erreicht.
Wenn ich Init aufrufe wird wie erwartet taskmeth aufgerufen. Ich sehe
per Debugger dass "arg" die gleiche Adresse hatte wie vorher "this" in
Init, die Übergabe scheint also richtig zu funktionieren. Eine sehr
ähnliche Implementierung unter einem µC mit posixthreads funktioniert.
Was könnte verkehrt sein?
LG
Stefan
Stefan schrieb:> void Thread::taskmeth(void *arg)> {> Thread *obj = (Thread *) arg;>> obj->Execute();> }
ich schieße mal ins Blaue weil ich CoOS nicht kenne. Wenn das eine
C-Implementierung ist, dann sollte die thread-Function auch extern "C"
deklariert werden:
extern "C"
{
void taskmeth(void *arg)
{
Thread *obj = (Thread *) arg;
obj->Execute();
}
}
die statische Funktion aus der Thread-Klasse muss dann raus. Aber wie
gesagt, nur ein Verdacht.
Ja CoOs ist eine C Implementierung; aber die extern "C" Geschichte hat
leider auch nicht geholfen. taskmeth() wird ja angesprungen.
@Florian
arg ist ein Zeiger auf ein Objekt der Klasse Thread, genau wie this.
Dieser wird als Zeiger auf Thread gecastet und in obj gespeichert. Dann
wird von obj mit dem Dereferenzierungsoperator -> die Methode
aufgerufen... so meine Denke... Falsch?
Florian La schrieb:> Ist *arg bei der Übergabe sicher schon vom ein Thread-Objekt?> Wenn nicht, dann wandelst du ja ziemlich mist um...
Da er dort "this" übergibt ist das ok. Ich denke aber CoCreateTask
erwartet eine "C"- Funktion und keine (auch wenn static) C++
Klassenfunktion.
Stefan schrieb:> Dann> wird von obj mit dem Dereferenzierungsoperator -> die Methode> aufgerufen... so meine Denke... Falsch?
Hast du keinen Debugger? Was passiert den an der Stelle genau?
Stefan schrieb:> #define CoCreateTask(task,argv,prio,stk,stkSz) \> CreateTask(task,argv,(prio)|(((stkSz)<<8) &0x000FFF00 ),stk)> extern OS_TID CreateTask(FUNCPtr task,void *argv,U32> parameter,OS_STK *stk);
Interessant ist hier wir FUNCPtr definiert ist.
Stefan schrieb:> void Thread::Init()> {> CoCreateTask((FUNCPtr) taskmeth, this, 0, &task_stk[STACK_SIZE_TASK -> 1], STACK_SIZE_TASK);> }
Sicher des der in der Funktion das Ende vom Stack haben will? Wenn ja,
dann ticken die Chinesen eigenartig.
Ich hätte den Anfang übergeben, der Rest sollte CoCreateTask machen.
Ja, ist so in den Beispielen. Das mit dem Stackende übergeben habe ich
schon öfters auch in anderen Betriebssystemen gesehen, habe aber mal
ausprobiert den Anfang zu übergeben, dann schepperts gleich. Habe mal
zum Testen die while schleife direkt nach taskmeth kopiert, da drin
gehts, nur der obj->Execute() Aufruf spackt :-(
Stefan schrieb:> Bis zum blx r3 kann ich steppen, dann schepperts ins Nirvana
Und in r3 steht auch die Adresse von Thread::Execute?
Auch wenn es hier nichts hilft. Die Threadfunktion muss eine
"C"-Funktion sein. Wenn du das nicht beachtest wirst du noch so manches
Wunder bei gemischter C C++ Programmierung erleben. qsort und Konsorten
sind auch ein gutes Beispiel dafür.
Naja, zumindest muss es eine statische Methode sein, normale Methoden
werden wohl anders behandelt... Ich habe noch was beim
"Ursachenminimieren" herausgefunden:
1
voidThread::Init()
2
{
3
Thread*obj=this;
4
obj->Execute();
Selbst hier funktioniert der Aufruf schon nicht :-(
...und noch was: Selbst einfach nur "Execute();", ganz ohne
Objektzeiger, geht nicht! ...wenn ich das "virtual" entferne gehts! Das
virtual brauche ich später natürlich für die Polymorphie wenn ich
Klassen von Thread ableite...
Stefan schrieb:> Naja, zumindest muss es eine statische Methode sein, normale Methoden> werden wohl anders behandelt...
Das hat damit nichts zu tun. Selbst eine einfache Funktion in einer
cpp-Datei ist was anders als in einer c-Datei. Die Parameter werden
anders gehändelt.
Stefan schrieb:> void Thread::Init()> {> Thread *obj = this;> obj->Execute();
Wenn das geht:
void Thread::Init()
{
Execute();
...
dann suchen wir an der falschen Stelle. Gibt es denn von Thread eine
ordentliche Instanz?
Ich tippe mal das liegt an deinem Startup-Code. Wird da die Funktion:
__libc_init_array();
gerufen? Die ist eigentlich dafür da die Tabellen, die der Compiler eben
auch für virtuelle Funktionen braucht, zu initialisieren. Dafür müssen
auch Sektionen im Linker-Script angelegt werden. Macht das CooCox schon
automatisch? Als ich vor ca. 2 Jahren das letzte mal CooCox probiert
habe musste man das noch von Hand machen!
So etwa sieht das bei mir aus:
/* C++ constructors etc */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
KEEP(*(.fini));
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(0x4);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
/* End C++ */
} > Flash
/*
* for exception handling/unwind - some Newlib functions (in common
* with C++ and STDC++) use this.
* Use KEEP so not discarded with --gc-sections
*/
.ARM.extab : ALIGN(4)
{
KEEP(*(.ARM.extab* .gnu.linkonce.armextab.*))
} > Flash
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
KEEP(*(.ARM.exidx* .gnu.linkonce.armexidx.*))
} > Flash
__exidx_end = .;
_etext = .;
/* MAIN DATA SECTION */
So, das Linkerscript ist modifiziert, allerdings ist der startupcode bei
mir dummerweise in Assembler geschrieben, und die verlinkte Anleitung
einen Beitrag weiter oben geht von C aus. Ich weiß nicht wie ich das
__libc_init_array(); unterbringen kann, das sehe ich auch in der
Anleitung nicht :-( wie kommt die eigentlich her?
wenn du nicht weiter weißt, ruf sie doch in der main auf:
1
extern"C"
2
{
3
void__libc_init_array(void);
4
}
5
6
intmain(void)
7
{
8
__libc_init_array();
9
...
10
...
Die Funktion selbst sollte in einer der C++ Libs oder Objects vom
Compiler liegen. Die sind bei mir im Linkerscript so drin (bezieht sich
auf die gnu-arm-tools) :
GROUP
(
libgcc.a
libc.a
libm.a
crti.o
crtn.o
crtbegin.o
crtend.o
)
Ok, in main aufrufen hat geklappt, vielen Dank!
Habe dann noch etwas nach Startupcode gegoogelt, der sieht nun so aus:
/* Call the clock system intitialization function.*/
bl SystemInit
bl __libc_init_array
/* Call the application's entry point.*/
bl main
Klappt! Virtuelle Methoden funktionieren, alles gut.
Danke & Gruß
Stefan