setjmp longjmp with Stack
<p>I have to implement a user-level thread library as a homework using setjmp/longjmp. This is the code I wrote:</p>

<pre><code>#include &lt;signal.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/select.h&gt;
#include &lt;time.h&gt;
#include &lt;errno.h&gt;
#include &lt;signal.h&gt;
#include &lt;setjmp.h&gt;



#define STACKSIZE   128*1024    //approriate stack size

typedef void (*ult_func)();
struct tcb_str; //forward declaration

typedef struct tcb_str {
    //fill this struct with statusinformations
    stack_t stack;  //stack for local vars
    jmp_buf buf;
    int id;
    void (*threadfunc)();
    int waitingfor; //ID of Thread/ Filediscriptor the Thread is currently waiting for
    int waitingtype; //0 = Thread, 1 = fd
    int exitnumber; //Is set on exit
} tcb;

typedef struct queue queue;

struct queue *runqueue;
struct queue *blockedqueue;
struct queue *zombiequeue;

jmp_buf backtonormal;

int counter = 0;

struct queue {
    struct queue_node *start;
    struct queue_node *end;
};
struct queue_node {
    struct tcb_str *element;
    struct queue_node *next;
};

struct queue_node* pop(struct queue *qu) {

  if (qu == NULL || qu-&gt;start == NULL) {
    return NULL;
  }

  struct queue_node *node = qu-&gt;start;

  qu-&gt;start = node-&gt;next;
  if (qu-&gt;start == NULL) {
    qu-&gt;end = NULL;

  }
  node-&gt;next = NULL;
  return node;

}


int push(struct queue *qu, struct queue_node *node) {

  if (qu == NULL) {
    return -1;
  }
  node-&gt;next = NULL;
  if (qu-&gt;end == NULL) {
    qu-&gt;start = qu-&gt;end = node;
  } else {
    qu-&gt;end-&gt;next = node;
    qu-&gt;end = node;
  }
  return 1;
}


struct queue_node* removeByTid(struct queue *qu, int tid) {
    struct queue_node* tmp = qu-&gt;start;
    struct queue_node* previous = qu-&gt;start;
    if(tmp-&gt;element-&gt;id == tid) {
        pop(qu);
        return tmp;
    }

    do {
        if(tmp-&gt;element-&gt;id == tid) {
            //What if first and only
            previous-&gt;next = tmp-&gt;next;
            //What if only one left after
            tmp-&gt;next = NULL;
            if(qu-&gt;start-&gt;next == NULL) {
                qu-&gt;end = qu-&gt;start;
            }
            return tmp;
        }
        previous = tmp;
    }
    while((tmp = tmp-&gt;next));
    return NULL;
}

struct queue *initqueue() {
      queue *qu = malloc(sizeof(*qu));

      if (qu == NULL) {
        return NULL;
      }
      qu-&gt;start =  qu-&gt;end = NULL;
      return qu;
}
int checkfordata(int fd) {
    int data; //returns != 0 if data is available
    struct timeval tv_str;
    fd_set fds;
    FD_ZERO(&amp;fds);


    if (!FD_ISSET(fd, &amp;fds)) {
        FD_SET(fd, &amp;fds);       //Creating fd_set for select()
    }
    tv_str.tv_sec = 0;
    tv_str.tv_usec = 0;
    //is data available?
    data = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv_str);
    FD_CLR(fd, &amp;fds);
    return data;
}

void schedulerThread() {
    while(1) {
    //Check blocked Threads
    struct queue_node* tmp = blockedqueue-&gt;start;
    fd_set fds;
    FD_ZERO(&amp;fds);

    if(tmp != NULL) {

        //Go through blocked Threads
        do {
                int data = checkfordata(tmp-&gt;element-&gt;waitingfor);
                if(data &gt; 0) {
                    removeByTid(blockedqueue, tmp-&gt;element-&gt;id);
                    //Add to running queue (at start)
                    tmp-&gt;next = runqueue-&gt;start;
                    runqueue-&gt;start = tmp;
                    return;
                }
                else {

                    FD_SET(tmp-&gt;element-&gt;waitingfor, &amp;fds);
                }
        }
        while((tmp = tmp-&gt;next));
    }
    if(runqueue-&gt;start == NULL) {
        if(blockedqueue-&gt;start == NULL) {
            free(runqueue);
            free(blockedqueue);
            struct queue_node* qu;
            while((qu = pop(zombiequeue)) != NULL) {
                free(qu-&gt;element-&gt;stack.ss_sp);
                free(qu);
            }
            free(zombiequeue);
            return;
        }
        else {  
                    struct timeval tv_str;
                    tv_str.tv_sec = 0;
                    tv_str.tv_usec = 800 * 1000;
                    //We have to copy fds, as select will mess it up
                    fd_set fdset = fds;
                    select(FD_SETSIZE, &amp;fdset, NULL, NULL, &amp;tv_str);
        }
    }
    else {
        return;
    }
    }
}
/*
 This function only exists to tell the process to use an empty stack for the thread
 */
void signalHandlerSpawn( int arg ) {

    if ( setjmp( runqueue-&gt;start-&gt;element-&gt;buf ) ) {
        runqueue-&gt;start-&gt;element-&gt;threadfunc();
        longjmp(backtonormal, 1);
    }
    return;
}

int ult_spawn(ult_func f) {
    struct tcb_str* tcb = malloc(sizeof(struct tcb_str));
    tcb-&gt;threadfunc = f;
    tcb-&gt;waitingfor = -1;
    tcb-&gt;waitingtype = -1;
    tcb-&gt;id = ++counter;
    tcb-&gt;stack.ss_flags = 0;
    tcb-&gt;stack.ss_size = STACKSIZE;
    tcb-&gt;stack.ss_sp = malloc(STACKSIZE);
    if ( tcb-&gt;stack.ss_sp == 0 ) {
        perror( "Could not allocate stack." );
        exit( 1 );
    }
    stack_t oldStack;
    sigaltstack( &amp;(tcb-&gt;stack), 0 );
    struct sigaction sa;
    struct sigaction oldHandler;
    sa.sa_handler = &amp;signalHandlerSpawn;
    sa.sa_flags = SA_ONSTACK;
    sigemptyset( &amp;sa.sa_mask );
    sigaction( SIGUSR1, &amp;sa, &amp;oldHandler );

    struct queue_node* node = malloc(sizeof(struct queue_node));
    node-&gt;element = tcb;
    push(runqueue, node);
    struct queue_node* q = runqueue-&gt;start;
    runqueue-&gt;start = runqueue-&gt;end;
    raise( SIGUSR1 );

    /* Restore the original stack and handler */
    sigaltstack( &amp;oldStack, 0 );
    sigaction( SIGUSR1, &amp;oldHandler, 0 );

    runqueue-&gt;start = q;

    return tcb-&gt;id;
}

void ult_yield() {
    if(runqueue-&gt;start == NULL) {
        exit(1);
        //TODO clean up
    }
    //We're the only one, so no need to schedule
    if(runqueue-&gt;start == runqueue-&gt;end &amp;&amp; blockedqueue-&gt;start == NULL &amp;&amp; runqueue-&gt;start != NULL) {
        return;
    }
    else {
        if (setjmp(runqueue-&gt;start-&gt;element-&gt;buf))
                 return;
        else {
            struct queue_node* tmp = pop(runqueue);
            push(runqueue, tmp);
            longjmp(backtonormal, 1);
        }
    }
}

int ult_read(int fd, void *buf, int count) {
        if (setjmp(runqueue-&gt;start-&gt;element-&gt;buf)) {
            return read(fd, buf, count);
        }
        else {
            struct queue_node* tmp = pop(runqueue);
            tmp-&gt;element-&gt;waitingfor = fd;
            tmp-&gt;element-&gt;waitingtype = 1;
            push(blockedqueue, tmp);
            longjmp(backtonormal, 1);
        }
    return -1;
}
void ult_init(ult_func f) {
    runqueue = initqueue();
    blockedqueue = initqueue();
    zombiequeue = initqueue();
    ult_spawn(f);
    while(1) {
        if(setjmp(backtonormal))
            continue;
        else {
            schedulerThread();
            if(runqueue-&gt;start == NULL)
                return; //TODO clean up
            longjmp(runqueue-&gt;start-&gt;element-&gt;buf, 1);
        }
    }
}


void threadA()
{
    int fd;
    char *inpt = "/dev/random";
    char buf[8];
    fd = open(inpt, O_RDONLY, O_NONBLOCK);

    if (fd == -1)
    {
        perror("open()");
    }
    while(1)
    {
        memset(buf, 0, 8);
        ult_read(fd, &amp;buf, sizeof(buf));
    }
}

void threadB()
{
    char input[512] = {0};
    while(1)
    {
        memset(input, 0, 512);
        ult_read(STDIN_FILENO, &amp;input, 512);
        if(strcmp(input, "stats\n") == 0)
        {
           //print stats
            continue;
        }
    }
}

void myInit()
{
    int status;
    ult_spawn(&amp;threadA);
    ult_spawn(&amp;threadB);
    while(1) {
        ult_yield();
    }
}
int  main() {
    ult_init(&amp;myInit);
    return 0;
}
</code></pre>

<p>The problem occurs in ult_read. Once this function is called, it will jump back to the scheduler first. The scheduler checks whether data is available (to prevent the whole process from blocking) and jumps back to the function once there is data to read. Now when the function returns I get a segmentation fault. Valgrind is telling me:</p>

<pre><code>Jump to the invalid address stated on the next line
==20408==    at 0x0: ???
==20408==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
</code></pre>

<p>Ult_yield works just fine although it is using the same technique. I checked this question <a href="https://stackoverflow.com/questions/1381937/setjmp-longjmp-why-is-this-throwing-a-segfault">SetJmp/LongJmp: Why is this throwing a segfault?</a>, but I think that's a different problem, as I'm creating a separate stack for each "thread". 
Can anyone explain to me, what the problem is and how to fix it?</p>