Im trying to implement custom threads in C by creating a simple context switch function plus a FCFS scheduler.
The first step that i want to perform is to copy the entire function stack frame to heap to a saved frame and replace it by the first in queue.
The problem i have is that after finishing task one the stack of the second gets corrupted. I dont have any idea about why.
The code i have is the following:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define ITERATIONS 10
#define SSIZE 15
int * last;
void kwrite(const char*);
void kyield(int *);
void f1() {
int i = ITERATIONS;
while (i--) kwrite("A\n");
}
void f2() {
int i = ITERATIONS*2;
while (i--) {
printf("[%d]", i);
kwrite("B\n");
getchar();
}
}
void kwrite(const char* str) {
int a[10] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
write(1, str, strlen(str));
int *frame = malloc(sizeof(int)*SSIZE);
memcpy(frame, a, SSIZE*sizeof(int));
kyield(frame);
printf("ERROR\n");
}
void kyield(int * from) {
if (from == NULL) {
f1();
from = malloc(sizeof(int)*SSIZE);
memcpy(from, last, SSIZE*sizeof(int));
}
if (last == NULL) {
last = malloc(sizeof(int)*SSIZE);
memcpy(last, from, SSIZE*sizeof(int));
free(from);
f2();
exit(0);
}
int a[10] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
memcpy(a, last, SSIZE*sizeof(int));
memcpy(last, from, SSIZE*sizeof(int));
free(from);
}
int main(int argc, char** argv) {
kyield(NULL);
free(last);
}
It should call 10 times f1 and 20 f2 then exit. But when the var i of f2 is 8 it gets corrupted on the next iteration. Therefore entering an infinite loop.
Any help or suggestions would be appreciated! Have a nice day.
[edit] I suppose the code can be a bit tricky to understand so here it is a little clarification:
main calls kyield with null parameters.
kyield detects it and calls f1
f1 executes until kwrite is called
kwrite calls kyield passing its current stack frame
kyield detects the last stack frame is null so it copies the stack frame (sf from now on) given by kwrite, then calls f2 f2 does the same as f1
when kyield is executed next, both from and last wont be NULL so it will overwrite its current s f with the one in last, swap it with the one in from and lastly it will return, as the stack has been altered it will jump to the return address of the last kwrite, not the actual one, thus. Jumping from the f1 thread to f2.
Your memcpy(frame, a, SSIZE*sizeof(int)) looks wrong. Your SSIZE is defined to 15, but a has only a size of 10.
this is deliberate, as by copying 15 elements of 4 bytes we are copying the rax last value, the last ebp and the return address of the function.
https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/