cooperate1.c

DownloadView Raw

/**
 * cooperate1.c
 *
 * Demonstrates two "threads" (or rather, execution contexts), one running
 * before another. This example is probably not that exciting: it looks like it
 * just runs two functions in succession. However, imagine that the functions
 * were loaded dynamically (like regular programs such as ls, pwd, etc.), and
 * note that we are not directly calling them.
 *
 * Compile:
 *     gcc -Wall -o cooperate1 cooperate1.c
 */

#include <stdio.h>
#include <ucontext.h>

ucontext_t context[3];

void thread1(void)
{
    int i;
    for (i = 0; i <= 1000000000; i++) {
        /* Spin! Spin! Spin! */
    }
    printf("Thread 1: Finished first loop\n");

    for (i = 0; i <= 1000000000; i++);
    printf("Thread 1: Finished second loop\n");

    for (i = 0; i <= 1000000000; i++);
    printf("Thread 1: Finished third loop\n");
}

void thread2(void)
{
    int i;
    for (i = 0; i <= 1000000000; i++);
    printf("Thread 2: Finished first loop\n");

    for (i = 0; i <= 1000000000; i++);
    printf("Thread 2: Finished second loop\n");

    for (i = 0; i <= 1000000000; i++);
    printf("Thread 2: Finished third loop\n");
}

int main(void)
{
    char stack1[SIGSTKSZ];
    char stack2[SIGSTKSZ];

    getcontext(&context[0]);

    getcontext(&context[1]);
    context[1].uc_stack.ss_sp = stack1;
    context[1].uc_stack.ss_size = sizeof(stack1);
    /* uc_link determines where the execution context returns to when it
     * completes: */
    context[1].uc_link = &context[2];
    makecontext(&context[1], thread1, 0);

    getcontext(&context[2]);
    context[2].uc_stack.ss_sp = stack2;
    context[2].uc_stack.ss_size = sizeof(stack2);
    /* Note that the 2nd thread will return back to main(): */
    context[2].uc_link = &context[0];
    makecontext(&context[2], thread2, 0);

    swapcontext(&context[0], &context[1]);
    return 0;
}