Simple coroutine library integrated with IO event loop (libevent) / objects in plain C Snapshot
|
00001 #ifndef __EVTHREAD_H_ 00002 #define __EVTHREAD_H_ 00003 00004 #include <corothread/cthread.h> 00005 #include <corothread/stacks.h> 00006 00007 #include <sys/socket.h> 00008 #include <sys/types.h> 00009 #include <cutils/dlist.h> 00010 #include <nutils/addrutil.h> 00011 00012 #include <event.h> 00013 00014 // --------------------------------------------------------------------------- 00015 00016 /** 00017 * @defgroup EVLOOP 00018 * @brief event loop object. 00019 * The event loop wraps a small user mode threading library where a user mode thread is created per connection. 00020 * 00021 * When a new connection is received via accept(2), then an EVSOCKET object is created that encapsulates this socket, 00022 * and the socket is set to non blocking mode, and a user mode thread EVTHREAD is created that owns the new EVSOCKET object. 00023 * TCPACCEPTOR is the class that does all that. 00024 * 00025 * A user mode thread can own one or more EVSOCKET objects, it can read or write to an EVSOCKET object which has the API of a blocking socket. 00026 * when the socket blocks, (i.e. recv or send returns -1 and errno == EWOULDBLOCK) then the attached user mode thread is suspended, and control 00027 * returns to the event loop, the event loop schedules a different user mode thread, when an IO event occurs on a socket owned by that thread. 00028 * 00029 * A user mode thread (EVTHREAD) can create other sockets (EVSOCKET) that are then attached to the current thread. 00030 * 00031 * A use mode thread also owns a set of timer objects (EVTIMER), when the thread exits, all the timer objects are cleaned up. 00032 * 00033 * The event loop is implemented by libevent. 00034 * 00035 * Unlike other packages, where one can create several user mode thread and then has to cope with the problem of their synchronization, we keep things simple here. 00036 * There is one thread per connection, that is supposed to do protocol handling and processing, all on condition that processing does not involve heavy CPU intensive tasks. 00037 * If your problem does have such task, then there is also support for the Half-sync/Half-async pattern. 00038 * 00039 * @{ 00040 */ 00041 typedef struct tagEVLOOP { 00042 struct event_base *ev_base; 00043 STACKS *stacks; 00044 } EVLOOP; 00045 00046 EVLOOP * EVLOOP_init(STACKS *stacks ); 00047 00048 int EVLOOP_run( EVLOOP *loop ); 00049 00050 int EVLOOP_break( EVLOOP *loop ); 00051 00052 /** 00053 * @} 00054 */ 00055 00056 // --------------------------------------------------------------------------- 00057 struct tagEVSOCKET; 00058 struct tagEVTHREAD; 00059 00060 /** 00061 * @defgroup EVTHREAD 00062 * @brief user mode thread attached to an event loop 00063 * The thread owns one or more EVSOCKETS, it initially activated when the thread is created, and is futher activated when an IO event occurs on a EVSOCKET object 00064 * owned by this thread. 00065 * 00066 * @{ 00067 */ 00068 00069 typedef void (*EVTHREAD_PROC) ( struct tagEVTHREAD *thread, struct tagEVSOCKET *socket, void *user_ctx); 00070 00071 typedef struct tagEVTHREAD { 00072 EVLOOP *loop; 00073 EVTHREAD_PROC thread_proc; 00074 void *user_context; 00075 CTHREAD *cthread; 00076 struct tagEVSOCKET *socket; 00077 struct event timer_event; 00078 DLIST object_list; 00079 } EVTHREAD; 00080 00081 EVTHREAD *EVTHREAD_init(EVLOOP *loop, EVTHREAD_PROC thread_proc, void *user_ctx); 00082 00083 00084 int EVTHREAD_start( EVTHREAD *thread, struct tagEVSOCKET *socket ); 00085 00086 int EVTHREAD_delay( EVTHREAD *thread, struct timeval delay ); 00087 00088 #if 0 00089 int EVTHREAD_dns_lookup ( EVTHREAD *thread, int addr_family, const char *dns_name ); 00090 00091 int EVTHREAD_dns_lookup ( EVTHREAD *thread, int addr_family, const char *dns_name ) 00092 { 00093 CTHREAD *thread; 00094 00095 switch( addr_family ) { 00096 case AF_INET: 00097 evdns_resolve_ipv6( dns_name, 0, evdns_callback_type callback, void *ptr); 00098 break; 00099 case AF_INET6: 00100 evdns_resolve_ipv6( dns_name, 0, evdns_callback_type callback, void *ptr); 00101 break; 00102 } 00103 00104 CHREAD_yield(); 00105 } 00106 #endif 00107 00108 00109 /** 00110 * @} 00111 */ 00112 00113 // --------------------------------------------------------------------------- 00114 00115 typedef enum { 00116 EVTHREAD_OBJECT_SOCKET, 00117 EVTHREAD_OBJECT_TIMER, 00118 } EVTHREAD_OBJECT_TYPE; 00119 00120 /** 00121 * @brief base class of sockets and timers. API of this class is not not called directly by the user of this library. 00122 */ 00123 typedef struct tagEVTHREAD_OBJECT { 00124 DLIST_entry entry; 00125 int object_type; 00126 EVTHREAD *owner; 00127 } EVTHREAD_OBJECT; 00128 00129 // --------------------------------------------------------------------------- 00130 00131 /** 00132 * @defgroup EVTIMER 00133 * @brief timer object atached to event loop, when the timer fires, the timer id is sent to the thread that has set the timer 00134 * @{ 00135 */ 00136 struct tagEVTIMER; 00137 00138 typedef enum { 00139 EVTIMER_STATE_INIT, 00140 EVTIMER_STATE_SCHEDULED, 00141 } EVTIMERSTATE; 00142 00143 typedef struct tagEVTIMER { 00144 EVTHREAD_OBJECT object_base; 00145 00146 EVLOOP *loop; 00147 int timer_id; 00148 struct timeval tm; 00149 struct event timer_event; 00150 00151 EVTIMERSTATE state; 00152 } EVTIMER; 00153 00154 00155 EVTIMER *EVTIMER_init(EVTHREAD *thread, int timer_id, struct timeval tm ); 00156 00157 int EVTIMER_start( EVTIMER *ret); 00158 00159 int EVTIMER_cancel( EVTIMER *timer ); 00160 00161 int EVTIMER_free( EVTIMER *timer ); 00162 00163 /** 00164 * @} 00165 */ 00166 00167 // --------------------------------------------------------------------------- 00168 /** 00169 * @defgroup EVSOCKET 00170 * @brief a socket attached to user mode thread. 00171 * 00172 * - a thread can either read from or write to a socket, not both at the same time. 00173 * - a thread can read or write from one socket at a time. 00174 * 00175 * @{ 00176 */ 00177 00178 typedef enum { 00179 EVSOCKET_STATE_INIT, 00180 EVSOCKET_STATE_CONNECTING, 00181 EVSOCKET_STATE_CONNECTED, 00182 EVSOCKET_STATE_READING, 00183 EVSOCKET_STATE_WRITING, 00184 EVSOCKET_STATE_CLOSED, 00185 EVSOCKET_STATE_ERROR, 00186 } EVSOCKET_STATE; 00187 00188 00189 typedef struct tagEVSOCKET { 00190 EVTHREAD_OBJECT object_base; 00191 00192 int fd; 00193 struct event read_event; 00194 struct event write_event; 00195 00196 EVSOCKET_STATE state; 00197 EVTIMER *timer_idle_timeout; // idle timeout. 00198 EVTIMER *timer_io_timeout; // timeout of current operation (read or write). 00199 struct timeval idle_timeout; 00200 00201 EVLOOP *loop; 00202 EVTHREAD *thread; 00203 } 00204 EVSOCKET; 00205 00206 EVSOCKET *EVSOCKET_init(EVTHREAD *thread, int fd, int is_connected); 00207 00208 int EVSOCKET_close(EVSOCKET *socket); 00209 00210 int EVSOCKET_connect( EVSOCKET *socket, struct sockaddr *address, socklen_t socklen, struct timeval timeout); 00211 00212 void EVSOCKET_set_idle_timeout(EVSOCKET *socket, struct timeval timeout ); 00213 00214 int EVSOCKET_recv( EVSOCKET *socket, void *buf, size_t buf_size, int flags, struct timeval timeout ); 00215 00216 int EVSOCKET_recv_all( EVSOCKET *socket, void *buf, size_t buf_size, int flags, struct timeval timeout ); 00217 00218 int EVSOCKET_send( EVSOCKET *socket, void *buf, size_t buf_size, int flags, struct timeval timeout ); 00219 00220 /** 00221 * @} 00222 */ 00223 00224 // --------------------------------------------------------------------------- 00225 00226 /** 00227 * @defgroup TCPACCEPTOR 00228 * @brief listener for tcp connections, a usermode thread is created for each new connection. 00229 * 00230 * @{ 00231 */ 00232 00233 typedef int (*EVTHREAD_FACTORY) (int fd, EVTHREAD_PROC *proc, void **ctx, void *factory_ctx ); 00234 00235 00236 typedef struct tagTCPACCEPTOR { 00237 EVLOOP *loop; 00238 int fd; 00239 struct event read_event; 00240 int read_buffer_size,send_buffer_size; 00241 EVTHREAD_FACTORY factory; 00242 void *ctx; 00243 00244 } EVTCPACCEPTOR; 00245 00246 EVTCPACCEPTOR * EVTCPACCEPTOR_init_ex( EVLOOP *loop, SOCKADDR *addr, int listener_backlog, EVTHREAD_FACTORY factory, int read_buffer_size, int write_buffer_size, void *ctx ); 00247 00248 EVTCPACCEPTOR * EVTCPACCEPTOR_init( EVLOOP *loop, int listener_fd, EVTHREAD_FACTORY factory, int read_buffer_size, int write_buffer_size, void *ctx ); 00249 00250 void EVTCPACCEPTOR_close(EVTCPACCEPTOR *); 00251 00252 00253 /** 00254 * @} 00255 */ 00256 00257 #endif 00258 00259