Simple coroutine library / objects in plain C Snapshot
|
00001 #ifndef __CTHREAD_H__ 00002 #define __CTHREAD_H__ 00003 00004 00005 #include <ucontext.h> 00006 #include <stdint.h> 00007 #include <corothread/stacks.h> 00008 #include <corothread/val.h> 00009 00010 /** 00011 * @defgroup CTHREAD 00012 * @brief a coroutine thread. 00013 * 00014 * A very limited user mode threading package that allows constructions of co-routines. 00015 * Coroutine scheduling is done by mean of mkcontet/setcontext/getcontext functions (glibc) 00016 * 00017 * User mode threads are best when used in a very limited scenario, complex usage scenarios often 00018 * lead to intricate situations that are hard to debug. 00019 * Areas where user mode threading shines 00020 * - coroutines / continuations 00021 * - generator funcions (like python/ruby/perl). 00022 * 00023 * 00024 * @{ 00025 */ 00026 00027 typedef void (*CTHREAD_PROC) (VALUES *); 00028 00029 typedef enum { 00030 CTHREAD_STATE_INIT, 00031 CTHREAD_STATE_RUNNING, 00032 CTHREAD_STATE_SUSPENDED, 00033 CTHREAD_STATE_EXIT, 00034 } CTHREAD_STATE; 00035 00036 00037 00038 typedef struct tagCTHREAD { 00039 ucontext_t context_coroutine; 00040 ucontext_t context_caller; 00041 CTHREAD_STATE state; 00042 uint32_t thread_id; 00043 00044 int thread_to_caller_value_set; 00045 VALUES thread_to_caller_value; 00046 int caller_to_thread_value_set; 00047 VALUES caller_to_thread_value; 00048 00049 CTHREAD_PROC proc; 00050 struct tagCTHREAD *prev_thread; 00051 STACK_ENTRY *stack_entry; 00052 } CTHREAD; 00053 00054 00055 00056 /** 00057 * @brief library initialisation 00058 */ 00059 int CTHREAD_libinit(); 00060 00061 /** 00062 * @brief initialises a new co-routine thread. 00063 00064 * Postcondition: The new thread is initialised and enters CTHREAD_STATE_INIT state. 00065 00066 * @param stacks the thread is obtained from the pool of stacks (argument stack). 00067 * @param proc The thread procecdure is argument proc. 00068 */ 00069 CTHREAD * CTHREAD_init( STACKS *stacks, CTHREAD_PROC proc ); 00070 00071 /** 00072 * deallocates a thread 00073 * 00074 * Precondition: the thread must be in CTHREAD_STATE_EXIT state 00075 */ 00076 int CTHREAD_free( CTHREAD *thread ); 00077 00078 /** 00079 * @brief start a new thread - the thread procedure is invoked. 00080 * 00081 * 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) 00082 * 00083 * Values passed from the thread to the caller are stored in rvalue parameter. 00084 * If this parameter is 0 then the return values are ignored. 00085 * 00086 * Values passed from the caller to the thread - 00087 * 00088 * Precondition: the thread is in either CTHREAD_STATE_INIT or CTHREAD_STATE_EXIT state. 00089 * Postcondition: the thread is in CTHREAD_STATE_RUNNING state. 00090 * 00091 */ 00092 int CTHREAD_start( CTHREAD *thread, VALUES **rvalue, const char *format , ... ); 00093 00094 00095 /** 00096 * @brief resume a suspended thread 00097 * 00098 * Resumes a suspended thread, the function will return when the resumed thread calls CTHREAD_yield or when it exits. 00099 * 00100 * 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. 00101 * Parameter format is the format specifier, subsequent variable length argument values are then sent to the thread. 00102 * 00103 * Retrieving parameters from the thread: 00104 * We can access values returned by the thread, once CTHREAD_resume returns. The values passed by the thread are stored in rvalue parameter. 00105 * 00106 * Precondition: the thread is in CTHREAD_STATE_SUSPENDED state 00107 * Postcondition: the thread is in CTHREAD_STATE_RUNNING state 00108 */ 00109 int CTHREAD_resume( CTHREAD *thread, VALUES **rvalue, const char *format, ... ); 00110 00111 00112 00113 00114 /** 00115 * @brief a running thread temporarily suspends execution 00116 * 00117 * Precondition: the thread is in CTHREAD_STATE_RUNNING state 00118 * Postcondition: the thread is in CTHREAD_STATE_SUSPENDED state 00119 00120 00121 */ 00122 int CTHREAD_yield(VALUES **rvalue, const char *format, ... ); 00123 00124 /** 00125 * @brief waits till the thread has finished 00126 * Calls CTHREAD_resume repeatedly unntil the thread finishes. 00127 */ 00128 int CTHREAD_join( CTHREAD *thread, VALUES **rvalue ); 00129 00130 00131 /** 00132 * @brief a running thread sets it return values 00133 * 00134 */ 00135 int CTHREAD_set_return_value( const char *format, ... ); 00136 00137 /** 00138 * @brief get thread id 00139 * 00140 * Precondition: the thread is in any state other than CTHREAD_STATE_INIT 00141 */ 00142 uint32_t CTHREAD_get_tid(); 00143 00144 /** 00145 * @brief get thread state 00146 */ 00147 M_INLINE CTHREAD_STATE CTHREAD_state(CTHREAD *thread) 00148 { 00149 return thread->state; 00150 } 00151 00152 /** 00153 * @} 00154 */ 00155 00156 #endif 00157 00158