cooperate2.c

DownloadView Raw

/**
 * cooperate2.c
 *
 * Demonstrates two "threads" employing an extremely basic cooperative
 * multitasking approach. Each thread does a bit of its overall work and then
 * yields control of the CPU over to the other thread. This interleaves thread
 * progress (rather than executing sequentially as in cooperate1.c)
 *
 * Compile:
 *     gcc -Wall -o cooperate2 cooperate2.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");
    swapcontext(&context[1], &context[2]);

    for (i = 0; i <= 1000000000; i++);
    printf("Thread 1: Finished second loop\n");
    swapcontext(&context[1], &context[2]);

    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");
    swapcontext(&context[2], &context[1]);

    for (i = 0; i <= 1000000000; i++);
    printf("Thread 2: Finished second loop\n");
    swapcontext(&context[2], &context[1]);

    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;
}