Skip to content

Commit

Permalink
tasks on setjmp / longjmp
Browse files Browse the repository at this point in the history
  • Loading branch information
majek committed Oct 18, 2012
1 parent bae1796 commit 2ee0d1e
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 0 deletions.
51 changes: 51 additions & 0 deletions setjmp/main.c
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;
}


77 changes: 77 additions & 0 deletions setjmp/tasklib.c
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;
}
14 changes: 14 additions & 0 deletions setjmp/tasklib.h
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);

0 comments on commit 2ee0d1e

Please sign in to comment.