-
Notifications
You must be signed in to change notification settings - Fork 215
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
gcc -Wall -g main.c tasklib.c -D_FORTIFY_SOURCE=0 -O3 && gdb ./a.out -ex r | ||
*/ | ||
#include <stdio.h> | ||
#include <setjmp.h> | ||
#include "tasklib.h" | ||
|
||
|
||
int max_task = 0; | ||
struct context *mc; | ||
|
||
void task_entry() { | ||
/* Every task, when it starts - first return to scheduler */ | ||
if (mc->curr_task_no != 0) { | ||
printf("#%02i yielding to 0\n", mc->curr_task_no); | ||
yield(mc, 0, NULL); | ||
} | ||
int i; | ||
for(i=0; i < 2; i++){ | ||
int tn = mc->curr_task_no + 1; | ||
if (tn > max_task) tn = 0; | ||
printf("#%02i yielding to %i\n", mc->curr_task_no, tn); | ||
yield(mc, tn, NULL); | ||
} | ||
} | ||
|
||
|
||
int main() { | ||
mc = new_context(); | ||
/* We're in scheduler -> task 0 */ | ||
|
||
int i; | ||
for (i=1; i < 16; i++) { | ||
printf("#%02i spawning #%i\n", mc->curr_task_no, mc->last_task_no); | ||
max_task = spawn(mc, task_entry); | ||
} | ||
|
||
task_entry(); | ||
|
||
/* Allow task to die */ | ||
for (i=1; i < 16; i++) { | ||
yield(mc, i, NULL); | ||
} | ||
|
||
/* We're the last one left */ | ||
return 0; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <setjmp.h> | ||
#include "tasklib.h" | ||
|
||
|
||
#define DEBUG(_par...) do { \ | ||
fprintf(stderr, "%14s() %s:%u ", \ | ||
__FUNCTION__, __FILE__, __LINE__); \ | ||
fprintf(stderr, " " _par); \ | ||
fprintf(stderr, "\n"); \ | ||
} while (0) | ||
|
||
|
||
static void grow_stack(struct context *context, int task_no) { | ||
char _frame[4096]; | ||
/* We need to allocate few K of stack for every task. | ||
Prevent compiler from optiomizing this out. */ | ||
memset(_frame, 0, 4096); | ||
|
||
if (task_no >= 1024) { | ||
/* Return to task 0 */ | ||
longjmp(context->tasks[0], 1); | ||
} | ||
|
||
int r = setjmp(context->tasks[task_no]); | ||
if (r != 0) { | ||
context->curr_task_no = task_no; | ||
if (r == 1) { | ||
/* for task 0 just return to parent */ | ||
return; | ||
} | ||
|
||
fprintf(stderr, " [.] #%i starting\n", task_no); | ||
callback fun = (callback)r; | ||
fun(); | ||
fprintf(stderr, " [.] #%i exited\n", task_no); | ||
|
||
/* Return to task 0 after someone exited. */ | ||
longjmp(context->tasks[0], 1); | ||
} else { | ||
// DEBUG("task #%i, stack=%p\n", task_no, __builtin_frame_address(0)); | ||
grow_stack(context, task_no + 1); | ||
/* GCC does tail recursion nowadays. Prevent that. */ | ||
__asm__ __volatile__ ("" ::: "memory"); | ||
} | ||
} | ||
|
||
struct context *new_context() { | ||
struct context *context; | ||
context = malloc(sizeof(struct context)); | ||
memset(context, 0, sizeof(struct context)); | ||
context->last_task_no = 1; | ||
context->curr_task_no = 0; | ||
|
||
grow_stack(context, 0); | ||
return context; | ||
} | ||
|
||
|
||
void yield(struct context *context, int task_no, void *ud) { | ||
// DEBUG("context=%p", context); | ||
int curr_task_no = context->curr_task_no; | ||
int r = setjmp(context->tasks[curr_task_no]); | ||
if (!r) { | ||
longjmp(context->tasks[task_no], (int) ud); | ||
} | ||
context->curr_task_no = curr_task_no; | ||
return; | ||
} | ||
|
||
int spawn(struct context *context, callback fun) { | ||
int task_no = context->last_task_no++; | ||
yield(context, task_no, fun); | ||
return task_no; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
|
||
typedef void(*callback)(); | ||
|
||
struct context { | ||
jmp_buf tasks[1024]; | ||
|
||
int last_task_no; | ||
int curr_task_no; | ||
}; | ||
|
||
struct context *new_context(); | ||
void yield(struct context *context, int task_no, void *ud); | ||
int spawn(struct context *context, callback fun); |