Last active
February 12, 2018 15:10
-
-
Save pingwin/42328c06507ce01554a72115b7b84570 to your computer and use it in GitHub Desktop.
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
/** | |
* This was something to play around with longjmp/setjmp and the stack that it would require. | |
* This code does not work as the direction this experiment was going would require context | |
* switching that I didn't want to happen. | |
*/ | |
#include <setjmp.h> | |
#include <ucontext.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <stdlib.h> | |
enum f_states { | |
STATE_ERROR = -1, | |
STATE_NULL = 0, | |
STATE_NEW, | |
STATE_RUNNING | |
}; | |
struct future_t { | |
jmp_buf *rip; // return to | |
struct future *msg_from; | |
}; | |
typedef struct future_t future; | |
struct message { | |
uint64_t msg_type; | |
jmp_buf *rip; // return to | |
ssize_t data_s; | |
void *data; | |
}; | |
#define MSG_ACK (struct message){ .rip = &self->private, .msg_type = 1 } | |
struct coroutine_t { | |
ucontext_t ctx; | |
jmp_buf private; // only cr can change | |
struct coroutine_t *parent; // only `root` can have parent == NULL | |
char name[100]; | |
char stack[4096 * 4]; // 4 pages | |
}; | |
typedef struct coroutine_t coroutine; | |
#define mkln(prefix, fmt) ({ \ | |
char __t [512]; \ | |
bzero(__t, sizeof(__t)); \ | |
snprintf(__t, sizeof(__t), "%s :: %s\n", prefix, fmt); \ | |
__t; \ | |
}) | |
#define pp(fmt, ...) printf(mkln(self->name, fmt), ##__VA_ARGS__); | |
intptr_t func_y(coroutine *self) { | |
enum f_states state = STATE_NULL; | |
struct message *msg = NULL; | |
intptr_t rc = 0; | |
do { | |
pp("do"); | |
if (STATE_RUNNING == state) { | |
rc = _setjmp(self->private); | |
pp("setjmp = %p", rc); | |
} | |
if (STATE_ERROR == rc) { | |
pp("error setjmp"); | |
state = STATE_ERROR; | |
} else if (STATE_RUNNING == state && STATE_NULL == rc) { | |
pp("block"); | |
if (self->parent == NULL) { | |
pp("ERR init w/o parent"); | |
state = STATE_ERROR; | |
rc = -1; | |
} else { | |
pp("setcontext to parent"); | |
_longjmp(self->parent->private, (intptr_t)&MSG_ACK); | |
} | |
} else if (STATE_NULL == rc) { | |
pp("first execution"); | |
state = STATE_RUNNING; | |
} else /* rc == future */ { | |
pp("sending reply"); | |
msg = (struct message*)&rc; | |
msg->data_s ++; | |
pp("data_t = %d", msg->data_s); | |
if (NULL != msg->rip) { | |
// save loc before jump | |
//rc = _setjmp(self->private); | |
pp("longjmp to %p", *msg->rip); | |
//if (rc == 0) | |
_longjmp(*msg->rip, (intptr_t)msg); | |
} else { | |
state = STATE_ERROR; | |
} | |
} | |
} while(state >= STATE_NEW); | |
pp("exiting"); | |
return rc; | |
} | |
coroutine * crinit(const char *name, intptr_t (*func)(coroutine*), coroutine *parent) { | |
coroutine *new = malloc(sizeof(coroutine)); | |
if (new == NULL) { | |
perror("coroutine new = malloc()"); | |
return NULL; | |
} | |
bzero(new, sizeof(coroutine)); | |
strncpy(new->name, name, sizeof(new->name)); | |
if (-1 == getcontext(&new->ctx)) { | |
perror("getcontext"); | |
return NULL; | |
} | |
new->ctx.uc_stack.ss_sp = new->stack; | |
new->ctx.uc_stack.ss_size = sizeof(new->stack); | |
new->parent = parent; | |
new->ctx.uc_link = &parent->ctx; | |
makecontext(&new->ctx, func, 1, new); | |
return new; | |
} | |
int main(int argc, char *argv[]) { | |
int32_t rc = 0; | |
struct message msg; | |
bzero(&msg, sizeof(msg)); | |
// setup root context | |
coroutine root; | |
bzero(&root, sizeof(root)); | |
coroutine *self = &root; | |
strncpy(self->name, "root", 4); | |
getcontext(&root.ctx); | |
/* | |
coroutine *self = crinit("root", func_y, NULL); | |
if (self == NULL) | |
return -1; | |
*/ | |
coroutine *A, *B = NULL; | |
rc = _setjmp(self->private); | |
if (0 == rc) { | |
A = crinit("fn_A", func_y, self); | |
setcontext(&A->ctx); | |
} | |
rc = _setjmp(self->private); | |
if (0 == rc) { | |
B = crinit("fn_B", func_y, self); | |
setcontext(&B->ctx); | |
} | |
// entering root loop | |
msg.rip = &self->private; | |
msg.data_s = 0; | |
intptr_t ptr = 0; | |
do { | |
ptr = _setjmp(self->private); | |
if (msg.data_s > 5) { | |
pp("all finished"); | |
break; | |
} | |
_longjmp(A->private, (intptr_t)&msg); | |
} while(1); | |
pp("Final value = %i", msg.data_s); | |
return rc; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment