Skip to content

Instantly share code, notes, and snippets.

@cchandler
Created November 12, 2009 06:09
Show Gist options
  • Save cchandler/232643 to your computer and use it in GitHub Desktop.
Save cchandler/232643 to your computer and use it in GitHub Desktop.
//Play with context
#define _XOPEN_SOURCE
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<ucontext.h>
typedef struct{
int ctx_pos;
int cleanup;
ucontext_t *ctx;
char *stack_space;
} ChrisThread;
ChrisThread *current_thread;
ucontext_t *thread_start;
char *stack_space;
ChrisThread *ctx_list;
int current_pos = 0;
int current_ctx_pos = 0;
#define LIST_SIZE 50
void yield();
int _init_ctx_list()
{
if(!ctx_list)
{
printf("Initialize context list\n");
ctx_list = malloc(sizeof(ChrisThread)*LIST_SIZE);
}
return 0;
}
void _increment_current_ctx_pos()
{
// printf("Incrementing %d %d \n", current_ctx_pos, current_pos);
current_ctx_pos++;
if(current_ctx_pos >= current_pos)
{
current_ctx_pos = 0;
}
}
int _get_current_ctx_pos()
{
if(current_ctx_pos > current_pos)
{
current_ctx_pos = 0;
}
return current_ctx_pos;
}
void _remove_from_ctx_list()
{
// printf("Execution concluded, freeing thread %d current thread %d\n", (*thread_ref).ctx_pos, (*current_thread).ctx_pos);
(*current_thread).cleanup = 1;
// printf("Cleanup of ref %d current %d\n", (*thread_ref).cleanup, (*current_thread).cleanup);
// printf("Memory addresses %d %d \n", thread_ref, current_thread);
}
void _cleanup_thread(ChrisThread *thread_ref)
{
printf("Cleaning thread\n");
current_pos--;
free( (*thread_ref).stack_space );
free( (*thread_ref).ctx );
// free( thread_ref );
int pos = (*thread_ref).ctx_pos;
while(pos < current_pos)
{
ctx_list[pos] = ctx_list[pos+1];
pos++;
}
}
void _thread_life_cycle(void(*entry_point)(), ChrisThread *thread_ref )
{
// printf("Init thread lifecycle %d\n", (*thread_ref).ctx_pos);
(*entry_point)();
_remove_from_ctx_list();
yield();
}
int create_thread( void(*func_point)() )
{
_init_ctx_list();
ChrisThread *thread = (ChrisThread *) malloc(sizeof(ChrisThread));
ucontext_t *newctx = (ucontext_t *) malloc(sizeof(ucontext_t));
(*thread).ctx = newctx;
(*thread).ctx_pos = current_pos;
getcontext(newctx);
stack_space = (char *) malloc(sizeof(char)*SIGSTKSZ);
(*newctx).uc_stack.ss_sp = stack_space;
(*newctx).uc_stack.ss_size = sizeof(char)*SIGSTKSZ;
(*thread).stack_space = stack_space;
ctx_list[current_pos] = *thread;
int old_pos = current_pos++;
makecontext(newctx, &_thread_life_cycle, 2, func_point, &ctx_list[old_pos]);
return old_pos;
}
void run_threads()
{
thread_start = (ucontext_t *) malloc(sizeof(ucontext_t));
getcontext(thread_start);
char iterator_stack[SIGSTKSZ];
(*thread_start).uc_stack.ss_sp = iterator_stack;
(*thread_start).uc_stack.ss_size = sizeof(iterator_stack);
int _current_ctx_pos = current_ctx_pos;
_increment_current_ctx_pos();
current_thread = &ctx_list[_current_ctx_pos];
swapcontext(thread_start,((*current_thread).ctx));
}
void yield()
{
// printf("Current thread ID %d\n", (*current_thread).ctx_pos);
ChrisThread *old_thread = current_thread;
_increment_current_ctx_pos();
current_thread = &ctx_list[_get_current_ctx_pos()];
if((*old_thread).cleanup)
{
if((*old_thread).ctx_pos == (*current_thread).ctx_pos)
{
//The old thread that we're cleaning up is also
//the new thread. No more work :-).
printf("Exiting from threads\n");
return;
}
_cleanup_thread(old_thread);
setcontext((*current_thread).ctx);
}
else
{
swapcontext((*old_thread).ctx,(*current_thread).ctx);
}
}
void some_function(int a)
{
a = 25;
int i = 0;
while(a > 0)
{
printf("Hello %d\n", a);
i++;
if(i == 25)
{
break;
}
yield();
// a = 0;
}
}
void some_other_function()
{
// while(1)
// {
printf("The other function\n");
yield();
// }
}
void third_function()
{
int a = 25;
int i = 0;
while(a > 0)
{
printf("Third \n");
i++;
if(i == 15)
{
break;
}
yield();
// a = 0;
}
}
int main()
{
create_thread(&some_function);
create_thread(&some_other_function);
create_thread(&third_function);
run_threads();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment