Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * 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;
- }
Add Comment
Please, Sign In to add comment