Simple coroutine library / objects in plain C Snapshot
|
a coroutine thread. More...
Classes | |
struct | tagCTHREAD |
Typedefs | |
typedef void(* | CTHREAD_PROC )(VALUES *) |
typedef struct tagCTHREAD | CTHREAD |
Enumerations | |
enum | CTHREAD_STATE { CTHREAD_STATE_INIT, CTHREAD_STATE_RUNNING, CTHREAD_STATE_SUSPENDED, CTHREAD_STATE_EXIT } |
Functions | |
int | CTHREAD_libinit () |
library initialisation | |
CTHREAD * | CTHREAD_init (STACKS *stacks, CTHREAD_PROC proc) |
initialises a new co-routine thread. | |
int | CTHREAD_free (CTHREAD *thread) |
int | CTHREAD_start (CTHREAD *thread, VALUES **rvalue, const char *format,...) |
start a new thread - the thread procedure is invoked. | |
int | CTHREAD_resume (CTHREAD *thread, VALUES **rvalue, const char *format,...) |
resume a suspended thread | |
int | CTHREAD_yield (VALUES **rvalue, const char *format,...) |
a running thread temporarily suspends execution | |
int | CTHREAD_join (CTHREAD *thread, VALUES **rvalue) |
waits till the thread has finished Calls CTHREAD_resume repeatedly unntil the thread finishes. | |
int | CTHREAD_set_return_value (const char *format,...) |
a running thread sets it return values | |
uint32_t | CTHREAD_get_tid () |
get thread id | |
M_INLINE CTHREAD_STATE | CTHREAD_state (CTHREAD *thread) |
get thread state |
a coroutine thread.
A very limited user mode threading package that allows constructions of co-routines. Coroutine scheduling is done by mean of mkcontet/setcontext/getcontext functions (glibc)
User mode threads are best when used in a very limited scenario, complex usage scenarios often lead to intricate situations that are hard to debug. Areas where user mode threading shines
typedef struct tagCTHREAD CTHREAD |
typedef void(* CTHREAD_PROC)(VALUES *) |
enum CTHREAD_STATE |
int CTHREAD_free | ( | CTHREAD * | thread | ) |
deallocates a thread
Precondition: the thread must be in CTHREAD_STATE_EXIT state
Definition at line 296 of file cthread.c.
{ if (thread->state != CTHREAD_STATE_EXIT) { return -1; } free(thread); return 0; }
uint32_t CTHREAD_get_tid | ( | ) |
CTHREAD* CTHREAD_init | ( | STACKS * | stacks, |
CTHREAD_PROC | proc | ||
) |
initialises a new co-routine thread.
Postcondition: The new thread is initialised and enters CTHREAD_STATE_INIT state.
stacks | the thread is obtained from the pool of stacks (argument stack). |
proc | The thread procecdure is argument proc. |
Definition at line 48 of file cthread.c.
{ void *stack; CTHREAD *ret; int stage = 0; ret = (CTHREAD *) malloc( sizeof(CTHREAD) ); if (!ret) { return 0; } stage = 1; if (VALUES_init(&ret->thread_to_caller_value)) { goto err; } stage = 2; if (VALUES_init(&ret->caller_to_thread_value)) { goto err; } stage = 3; stack = STACKS_get( stacks, &ret->stack_entry ); if (!stack) { goto err; } stage = 4; ret->proc = proc; ret->prev_thread = 0; ret->thread_id = -1; ret->state = CTHREAD_STATE_INIT; ret->caller_to_thread_value_set = ret->thread_to_caller_value_set = 0; if (getcontext( &ret->context_coroutine )) { if (ret->state == CTHREAD_STATE_INIT) { goto err; } return 0; } //fprintf( stderr,"thread stack start %p\n",stack); ret->context_coroutine.uc_stack.ss_sp = stack; ret->context_coroutine.uc_stack.ss_size = STACKS_get_stack_size( stacks ); return ret; err: if (stage > 3) { STACKS_release(ret->stack_entry); } if (stage > 2) { VALUES_free(&ret->caller_to_thread_value); } if (stage > 1) { VALUES_free(&ret->thread_to_caller_value); } if (stage > 0) { free(ret); } return 0; }
waits till the thread has finished Calls CTHREAD_resume repeatedly unntil the thread finishes.
Definition at line 189 of file cthread.c.
{ if( thread->state == CTHREAD_STATE_INIT || thread->state == CTHREAD_STATE_RUNNING) { return -1; } while(thread->state != CTHREAD_STATE_EXIT) { CTHREAD_resume( thread, rvalue, 0 ); } return 0; }
int CTHREAD_libinit | ( | ) |
resume a suspended thread
Resumes a suspended thread, the function will return when the resumed thread calls CTHREAD_yield or when it exits.
Passing parameters to the thread; a variable length set of arguments can be sent to the thread, and the thread will be able to read them. Parameter format is the format specifier, subsequent variable length argument values are then sent to the thread.
Retrieving parameters from the thread: We can access values returned by the thread, once CTHREAD_resume returns. The values passed by the thread are stored in rvalue parameter.
Precondition: the thread is in CTHREAD_STATE_SUSPENDED state Postcondition: the thread is in CTHREAD_STATE_RUNNING state
Definition at line 201 of file cthread.c.
{ if (thread->state != CTHREAD_STATE_SUSPENDED) { return -1; } getcontext( &thread->context_caller ); if (thread->state == CTHREAD_STATE_RUNNING) { // got here when the running thread called yield for the first time, or exited without calling yield. thread->state = CTHREAD_STATE_SUSPENDED; if (rvalue) { if (thread->thread_to_caller_value_set) { *rvalue = &thread->thread_to_caller_value; } else { *rvalue = 0; } } return 0; } if (thread->state == CTHREAD_STATE_EXIT) { // got here from thread that has exited. if (rvalue) { if (thread->thread_to_caller_value_set) { *rvalue = &thread->thread_to_caller_value; } else { *rvalue = 0; } } return 0; } thread->caller_to_thread_value_set = 0; if (format) { va_list vlist; va_start( vlist, format ); if (VALUES_printv( &thread->caller_to_thread_value, format, vlist ) ) { return -1; } thread->caller_to_thread_value_set = 1; } SET_TLS( thread ); return setcontext( &thread->context_coroutine ); }
int CTHREAD_set_return_value | ( | const char * | format, |
... | |||
) |
a running thread sets it return values
Definition at line 316 of file cthread.c.
{ CTHREAD *thread; va_list vlist; thread = GET_TLS(); if (!thread) { return (uint32_t) -1; } va_start( vlist, format ); thread->thread_to_caller_value_set = 0; if (VALUES_printv( &thread->thread_to_caller_value, format, vlist )) { thread->thread_to_caller_value_set = 0; return -1; } thread->thread_to_caller_value_set = 1; return 0; }
start a new thread - the thread procedure is invoked.
The initialised thread is started; The function returns if the running thread either exited or entered suspended state (i.e. the thread called CTHREAD_yield)
Values passed from the thread to the caller are stored in rvalue parameter. If this parameter is 0 then the return values are ignored.
Values passed from the caller to the thread -
Precondition: the thread is in either CTHREAD_STATE_INIT or CTHREAD_STATE_EXIT state. Postcondition: the thread is in CTHREAD_STATE_RUNNING state.
Definition at line 139 of file cthread.c.
{ if (thread->state != CTHREAD_STATE_INIT) { return -1; } getcontext( &thread->context_caller ); if (thread->state == CTHREAD_STATE_RUNNING) { // got here when the running thread called yield for the first time, or exited without calling yield. thread->state = CTHREAD_STATE_SUSPENDED; if (rvalue) { if (thread->thread_to_caller_value_set) { *rvalue = &thread->thread_to_caller_value; } else { *rvalue = 0; } } return 0; } if (thread->state == CTHREAD_STATE_EXIT) { // got here from thread that has exited. if (rvalue) { if (thread->thread_to_caller_value_set) { *rvalue = &thread->thread_to_caller_value; } else { *rvalue = 0; } } return 0; } thread->caller_to_thread_value_set = 0; if (format) { va_list vlist; va_start( vlist, format ); if (VALUES_printv( &thread->caller_to_thread_value, format, vlist ) ) { return -1; } thread->caller_to_thread_value_set = 1; } return do_start( thread ); }
M_INLINE CTHREAD_STATE CTHREAD_state | ( | CTHREAD * | thread | ) |
int CTHREAD_yield | ( | VALUES ** | rvalue, |
const char * | format, | ||
... | |||
) |
a running thread temporarily suspends execution
Precondition: the thread is in CTHREAD_STATE_RUNNING state Postcondition: the thread is in CTHREAD_STATE_SUSPENDED state
Definition at line 250 of file cthread.c.
{ CTHREAD *thread; thread = GET_TLS(); if (!thread) { return -1; } if (thread->state != CTHREAD_STATE_RUNNING) { return -1; } getcontext( &thread->context_coroutine ); if (thread->state != CTHREAD_STATE_RUNNING) { // got here when this thread was resumed. thread->state = CTHREAD_STATE_RUNNING; if (rvalue) { if (thread->caller_to_thread_value_set) { *rvalue = &thread->caller_to_thread_value; } else { *rvalue = 0; } } return 0; } thread->thread_to_caller_value_set = 0; if (format) { va_list vlist; va_start( vlist, format ); if (VALUES_printv( &thread->thread_to_caller_value, format, vlist ) ) { return -1; } thread->thread_to_caller_value_set = 1; } SET_TLS( thread->prev_thread ); return setcontext( &thread->context_caller ); }