Coroutinen - Status speichern
Verfasst: 26.03.2011, 12:20
Hallo,
ich beschäftige mich gerade ein wenig mit Coroutinen (via setjmp(), longjmp() und manueller Stack-Speicherung). Das funktioniert auch alles ganz gut, jetzt möchte ich jedoch gerne dei Ausführung des Programms unterbrechen (irgendwann bei einem Kontextwechsel) und den Status speichern (Stack, Registerinhalte). Das ganze soll später wieder geladen werden können und die Coroutinen sollen an der Stelle fortgesetzt werden, an denen die Unterbrechnung stattgefunden hat.
Leider funktioniert das nicht so ganz, bzw. bin ich mir nicht sicher, was alles gemacht werden muss, damit das klappt. Ich benutze (als Beispiel) folgenden Code. Wenn das Argument "write" übergeben wird, werden zwei Coroutinen (ind & fib) ausgeführt (eine Weile lang) und schließlich deren Attribute in eine Datei geschrieben. Beim Laden werden diese Datein gelesen - jedoch knallts beim ersten Aufruf von longjmp().
Ich führe das ganze mit dem gdb aus, d.h. die Position des Stack im Speicher ist in beiden Fällen die gleiche (im write und anschließenden read fall), d.h. ich kann die Stackpointer (low und high) weiterhin benutzen (denke ich mir so zumindest). Ich bekomme dennoch folgende Ausgabe:
Klappt also nicht. Warum nicht?
Wäre super wenn mir jemand weiterhelfen könnte. Es ist für mich (zumindest erstmal) vollkommen in Ordnung, irgendwelche platformspezifischen Dinge zu machen oder sonstige Einschränkungen vorzunehmen. Wäre halt toll, wenns erstmal prinzipiell halbwegs funktioniert.
Ich hoffe mal ihr könnt mir weiterhelfen. Schönes Wochenende euch allen,
Thomas
ich beschäftige mich gerade ein wenig mit Coroutinen (via setjmp(), longjmp() und manueller Stack-Speicherung). Das funktioniert auch alles ganz gut, jetzt möchte ich jedoch gerne dei Ausführung des Programms unterbrechen (irgendwann bei einem Kontextwechsel) und den Status speichern (Stack, Registerinhalte). Das ganze soll später wieder geladen werden können und die Coroutinen sollen an der Stelle fortgesetzt werden, an denen die Unterbrechnung stattgefunden hat.
Leider funktioniert das nicht so ganz, bzw. bin ich mir nicht sicher, was alles gemacht werden muss, damit das klappt. Ich benutze (als Beispiel) folgenden Code. Wenn das Argument "write" übergeben wird, werden zwei Coroutinen (ind & fib) ausgeführt (eine Weile lang) und schließlich deren Attribute in eine Datei geschrieben. Beim Laden werden diese Datein gelesen - jedoch knallts beim ersten Aufruf von longjmp().
Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
typedef unsigned int uint;
typedef unsigned short word;
typedef unsigned char byte;
#ifdef __GNUC__
#define NOINLINE __attribute__((noinline))
#else
#define NOINLINE __declspec(noinline)
#endif
#include <setjmp.h>
#include <fstream>
#include <string>
using namespace std;
enum {
STKPAD = 1 << 16, STKSAV = 1 << 10
};
template<typename T>
struct coroutine {
volatile uint state;
volatile char* stkptrH;
volatile char* stkptrL;
jmp_buf PointA, PointB;
char stack[STKSAV];
coroutine() {
state = 0;
}
NOINLINE // necessary for IntelC + my_setjmp.h
void yield(int value) {
char curtmp;
stkptrL = (&curtmp) - 16; // -16 is necessary for MSC
if (setjmp(PointB) == 0) {
state = value;
memcpy(stack, (char*) stkptrL, stkptrH - stkptrL);
longjmp(PointA, 1);
}
}
NOINLINE // necessary for MSC, to avoid allocation of stktmp before setjmp()
void call_do_process() {
char stktmp[STKPAD];
stkptrH = stktmp;
((T*) this)->do_process();
}
uint call(void) {
if (setjmp(PointA) == 0) {
if (state) {
memcpy((char*) stkptrL, stack, stkptrH - stkptrL);
longjmp(PointB, 1);
}
call_do_process();
}
return state;
}
void save(string pFileName) {
ofstream f;
f.open(pFileName.c_str(), ios::out | ios::binary | ios::trunc);
f.write((char*) &state, sizeof(state));
f.write((char*) &stkptrH, sizeof(stkptrH));
f.write((char*) &stkptrL, sizeof(stkptrH));
f.write((char*) &PointA[0], sizeof(__jmp_buf_tag ));
f.write((char*) &PointB[0], sizeof(__jmp_buf_tag ));
f.write(stack, STKSAV);
f.close();
}
void read(string pFileName) {
ifstream f;
f.open(pFileName.c_str(), ios::in | ios::binary);
f.read((char*) &state, sizeof(state));
f.read((char*) &stkptrH, sizeof(stkptrH));
f.read((char*) &stkptrL, sizeof(stkptrH));
f.read((char*) &PointA[0], sizeof(__jmp_buf_tag ));
f.read((char*) &PointB[0], sizeof(__jmp_buf_tag ));
f.read(stack, STKSAV);
f.close();
memcpy((char*) stkptrL, stack, stkptrH - stkptrL);
}
};
struct indexX: coroutine<indexX> {
void do_process(void) {
uint a = 1;
while (1) {
yield(a);
a++;
}
}
};
struct fibonacci: coroutine<fibonacci> {
void do_process(void) {
uint a = 0, b = 1;
while (1) {
yield(b);
b = b + a;
a = b - a;
}
}
};
int main(int argc, char** argv) {
indexX ind;
fibonacci fib;
printf("%p\n", &ind);
char indFn[] = "ind";
char fibFn[] = "fib";
if (argc < 2) {
printf("too few args.\n");
return 0;
}
if (strcmp("write", argv[1]) == 0) {
printf("write.\n");
for (int i = 0; i < 20; i++) {
printf("%i:%i ", ind.call(), fib.call());
ind.call();
fib.call();
}
ind.save(indFn);
fib.save(fibFn);
printf("\n");
} else {
printf("read.\n");
ind.read(indFn);
fib.read(fibFn);
for (int i = 0; i < 20; i++) {
printf("%i:%i ", ind.call(), fib.call());
printf("\n");
}
}
printf("done.\n");
return 0;
}
Code: Alles auswählen
(gdb) run write
Starting program: /home/thomas/workspaces/Studienarbeit/SetJump/Debug/SetJump write
0x7fffffffdc40
write.
1:1 3:2 5:5 7:13 9:34 11:89 13:233 15:610 17:1597 19:4181 21:10946 23:28657 25:75025 27:196418 29:514229 31:1346269 33:3524578 35:9227465 37:24157817 39:63245986
done.
Program exited normally.
(gdb) run read
Starting program: /home/thomas/workspaces/Studienarbeit/SetJump/Debug/SetJump read
0x7fffffffdc40
read.
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff72eda7e in ?? () from /lib/libc.so.6
(gdb)
Wäre super wenn mir jemand weiterhelfen könnte. Es ist für mich (zumindest erstmal) vollkommen in Ordnung, irgendwelche platformspezifischen Dinge zu machen oder sonstige Einschränkungen vorzunehmen. Wäre halt toll, wenns erstmal prinzipiell halbwegs funktioniert.
Ich hoffe mal ihr könnt mir weiterhelfen. Schönes Wochenende euch allen,
Thomas