正在显示
1 个修改的文件
包含
295 行增加
和
0 行删除
src/server/spserver/spdispatcher.cpp
0 → 100644
1 | +/* | ||
2 | + * Copyright 2007 Stephen Liu | ||
3 | + * For license terms, see the file COPYING along with this library. | ||
4 | + */ | ||
5 | + | ||
6 | +#include <stdlib.h> | ||
7 | +#include <stdio.h> | ||
8 | +#include <string.h> | ||
9 | +#include <assert.h> | ||
10 | +#include <errno.h> | ||
11 | +#include <signal.h> | ||
12 | + | ||
13 | +#include "spporting.hpp" | ||
14 | +#include "spthread.hpp" | ||
15 | + | ||
16 | +#include "spdispatcher.hpp" | ||
17 | + | ||
18 | +#include "speventcb.hpp" | ||
19 | +#include "sphandler.hpp" | ||
20 | +#include "spsession.hpp" | ||
21 | +#include "spexecutor.hpp" | ||
22 | +#include "sputils.hpp" | ||
23 | +#include "spiochannel.hpp" | ||
24 | +#include "spioutils.hpp" | ||
25 | +#include "sprequest.hpp" | ||
26 | + | ||
27 | +#include "event_msgqueue.h" | ||
28 | + | ||
29 | +SP_Dispatcher :: SP_Dispatcher( SP_CompletionHandler * completionHandler, int maxThreads ) | ||
30 | +{ | ||
31 | +#ifdef SIGPIPE | ||
32 | + /* Don't die with SIGPIPE on remote read shutdown. That's dumb. */ | ||
33 | + signal( SIGPIPE, SIG_IGN ); | ||
34 | +#endif | ||
35 | + | ||
36 | + mIsShutdown = 0; | ||
37 | + mIsRunning = 0; | ||
38 | + | ||
39 | + mEventArg = new SP_EventArg( 600 ); | ||
40 | + | ||
41 | + mMaxThreads = maxThreads > 0 ? maxThreads : 4; | ||
42 | + | ||
43 | + mCompletionHandler = completionHandler; | ||
44 | + | ||
45 | + mPushQueue = msgqueue_new( mEventArg->getEventBase(), 0, onPush, mEventArg ); | ||
46 | +} | ||
47 | + | ||
48 | +SP_Dispatcher :: ~SP_Dispatcher() | ||
49 | +{ | ||
50 | + if( 0 == mIsRunning ) sleep( 1 ); | ||
51 | + | ||
52 | + shutdown(); | ||
53 | + | ||
54 | + for( ; mIsRunning; ) sleep( 1 ); | ||
55 | + | ||
56 | + //msgqueue_destroy( (struct event_msgqueue*)mPushQueue ); | ||
57 | + | ||
58 | + delete mEventArg; | ||
59 | + mEventArg = NULL; | ||
60 | +} | ||
61 | + | ||
62 | +void SP_Dispatcher :: setTimeout( int timeout ) | ||
63 | +{ | ||
64 | + mEventArg->setTimeout( timeout ); | ||
65 | +} | ||
66 | + | ||
67 | +void SP_Dispatcher :: shutdown() | ||
68 | +{ | ||
69 | + mIsShutdown = 1; | ||
70 | +} | ||
71 | + | ||
72 | +int SP_Dispatcher :: isRunning() | ||
73 | +{ | ||
74 | + return mIsRunning; | ||
75 | +} | ||
76 | + | ||
77 | +int SP_Dispatcher :: getSessionCount() | ||
78 | +{ | ||
79 | + return mEventArg->getSessionManager()->getCount(); | ||
80 | +} | ||
81 | + | ||
82 | +int SP_Dispatcher :: getReqQueueLength() | ||
83 | +{ | ||
84 | + return mEventArg->getInputResultQueue()->getLength(); | ||
85 | +} | ||
86 | + | ||
87 | +int SP_Dispatcher :: dispatch() | ||
88 | +{ | ||
89 | + int ret = -1; | ||
90 | + | ||
91 | + sp_thread_attr_t attr; | ||
92 | + sp_thread_attr_init( &attr ); | ||
93 | + assert( sp_thread_attr_setstacksize( &attr, 1024 * 1024 ) == 0 ); | ||
94 | + sp_thread_attr_setdetachstate( &attr, SP_THREAD_CREATE_DETACHED ); | ||
95 | + | ||
96 | + sp_thread_t thread; | ||
97 | + ret = sp_thread_create( &thread, &attr, eventLoop, this ); | ||
98 | + sp_thread_attr_destroy( &attr ); | ||
99 | + if( 0 == ret ) { | ||
100 | + sp_syslog( LOG_NOTICE, "Thread #%ld has been created for dispatcher", thread ); | ||
101 | + } else { | ||
102 | + mIsRunning = 0; | ||
103 | + sp_syslog( LOG_WARNING, "Unable to create a thread for dispatcher, %s", | ||
104 | + strerror( errno ) ) ; | ||
105 | + } | ||
106 | + | ||
107 | + return ret; | ||
108 | +} | ||
109 | + | ||
110 | +sp_thread_result_t SP_THREAD_CALL SP_Dispatcher :: eventLoop( void * arg ) | ||
111 | +{ | ||
112 | + SP_Dispatcher * dispatcher = (SP_Dispatcher*)arg; | ||
113 | + | ||
114 | + dispatcher->mIsRunning = 1; | ||
115 | + | ||
116 | + dispatcher->start(); | ||
117 | + | ||
118 | + dispatcher->mIsRunning = 0; | ||
119 | + | ||
120 | + return 0; | ||
121 | +} | ||
122 | + | ||
123 | +void SP_Dispatcher :: outputCompleted( void * arg ) | ||
124 | +{ | ||
125 | + SP_CompletionHandler * handler = ( SP_CompletionHandler * ) ((void**)arg)[0]; | ||
126 | + SP_Message * msg = ( SP_Message * ) ((void**)arg)[ 1 ]; | ||
127 | + | ||
128 | + handler->completionMessage( msg ); | ||
129 | + | ||
130 | + free( arg ); | ||
131 | +} | ||
132 | + | ||
133 | +int SP_Dispatcher :: start() | ||
134 | +{ | ||
135 | + SP_Executor workerExecutor( mMaxThreads, "work" ); | ||
136 | + SP_Executor actExecutor( 1, "act" ); | ||
137 | + | ||
138 | + /* Start the event loop. */ | ||
139 | + while( 0 == mIsShutdown ) { | ||
140 | + event_base_loop( mEventArg->getEventBase(), EVLOOP_ONCE ); | ||
141 | + | ||
142 | + for( ; NULL != mEventArg->getInputResultQueue()->top(); ) { | ||
143 | + SP_Task * task = (SP_Task*)mEventArg->getInputResultQueue()->pop(); | ||
144 | + workerExecutor.execute( task ); | ||
145 | + } | ||
146 | + | ||
147 | + for( ; NULL != mEventArg->getOutputResultQueue()->top(); ) { | ||
148 | + SP_Message * msg = (SP_Message*)mEventArg->getOutputResultQueue()->pop(); | ||
149 | + | ||
150 | + void ** arg = ( void** )malloc( sizeof( void * ) * 2 ); | ||
151 | + arg[ 0 ] = (void*)mCompletionHandler; | ||
152 | + arg[ 1 ] = (void*)msg; | ||
153 | + | ||
154 | + actExecutor.execute( outputCompleted, arg ); | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + sp_syslog( LOG_NOTICE, "Dispatcher is shutdown." ); | ||
159 | + | ||
160 | + return 0; | ||
161 | +} | ||
162 | + | ||
163 | +typedef struct tagSP_PushArg { | ||
164 | + int mType; // 0 : fd, 1 : timer | ||
165 | + | ||
166 | + // for push fd | ||
167 | + int mFd; | ||
168 | + SP_Handler * mHandler; | ||
169 | + SP_IOChannel * mIOChannel; | ||
170 | + int mNeedStart; | ||
171 | + | ||
172 | + // for push timer | ||
173 | + struct timeval mTimeout; | ||
174 | + struct event mTimerEvent; | ||
175 | + SP_TimerHandler * mTimerHandler; | ||
176 | + SP_EventArg * mEventArg; | ||
177 | + void * mPushQueue; | ||
178 | +} SP_PushArg_t; | ||
179 | + | ||
180 | +void SP_Dispatcher :: onPush( void * queueData, void * arg ) | ||
181 | +{ | ||
182 | + SP_PushArg_t * pushArg = (SP_PushArg_t*)queueData; | ||
183 | + SP_EventArg * eventArg = (SP_EventArg*)arg; | ||
184 | + | ||
185 | + if( 0 == pushArg->mType ) { | ||
186 | + SP_Sid_t sid; | ||
187 | + sid.mKey = eventArg->getSessionManager()->allocKey( &sid.mSeq ); | ||
188 | + assert( sid.mKey > 0 ); | ||
189 | + | ||
190 | + SP_Session * session = new SP_Session( sid ); | ||
191 | + | ||
192 | + char clientIP[ 32 ] = { 0 }; | ||
193 | + { | ||
194 | + struct sockaddr_in clientAddr; | ||
195 | + socklen_t clientLen = sizeof( clientAddr ); | ||
196 | + getpeername( pushArg->mFd, (struct sockaddr *)&clientAddr, &clientLen ); | ||
197 | + SP_IOUtils::inetNtoa( &( clientAddr.sin_addr ), clientIP, sizeof( clientIP ) ); | ||
198 | + session->getRequest()->setClientPort( ntohs( clientAddr.sin_port ) ); | ||
199 | + } | ||
200 | + session->getRequest()->setClientIP( clientIP ); | ||
201 | + | ||
202 | + | ||
203 | + eventArg->getSessionManager()->put( sid.mKey, sid.mSeq, session ); | ||
204 | + | ||
205 | + session->setHandler( pushArg->mHandler ); | ||
206 | + session->setIOChannel( pushArg->mIOChannel ); | ||
207 | + session->setArg( eventArg ); | ||
208 | + | ||
209 | + event_set( session->getReadEvent(), pushArg->mFd, EV_READ, | ||
210 | + SP_EventCallback::onRead, session ); | ||
211 | + event_set( session->getWriteEvent(), pushArg->mFd, EV_WRITE, | ||
212 | + SP_EventCallback::onWrite, session ); | ||
213 | + | ||
214 | + if( pushArg->mNeedStart ) { | ||
215 | + SP_EventHelper::doStart( session ); | ||
216 | + } else { | ||
217 | + SP_EventCallback::addEvent( session, EV_WRITE, pushArg->mFd ); | ||
218 | + SP_EventCallback::addEvent( session, EV_READ, pushArg->mFd ); | ||
219 | + } | ||
220 | + | ||
221 | + free( pushArg ); | ||
222 | + } else { | ||
223 | + event_set( &( pushArg->mTimerEvent ), -1, 0, onTimer, pushArg ); | ||
224 | + event_base_set( eventArg->getEventBase(), &( pushArg->mTimerEvent ) ); | ||
225 | + event_add( &( pushArg->mTimerEvent ), &( pushArg->mTimeout ) ); | ||
226 | + } | ||
227 | +} | ||
228 | + | ||
229 | +int SP_Dispatcher :: push( int fd, SP_Handler * handler, int needStart ) | ||
230 | +{ | ||
231 | + SP_IOChannel * ioChannel = new SP_DefaultIOChannel(); | ||
232 | + return push( fd, handler, ioChannel, needStart ); | ||
233 | +} | ||
234 | + | ||
235 | +int SP_Dispatcher :: push( int fd, SP_Handler * handler, | ||
236 | + SP_IOChannel * ioChannel, int needStart ) | ||
237 | +{ | ||
238 | + SP_PushArg_t * arg = (SP_PushArg_t*)malloc( sizeof( SP_PushArg_t ) ); | ||
239 | + arg->mType = 0; | ||
240 | + arg->mFd = fd; | ||
241 | + arg->mHandler = handler; | ||
242 | + arg->mIOChannel = ioChannel; | ||
243 | + arg->mNeedStart = needStart; | ||
244 | + | ||
245 | + SP_IOUtils::setNonblock( fd ); | ||
246 | + | ||
247 | + return msgqueue_push( (struct event_msgqueue*)mPushQueue, arg ); | ||
248 | +} | ||
249 | + | ||
250 | +void SP_Dispatcher :: onTimer( int, short, void * arg ) | ||
251 | +{ | ||
252 | + SP_PushArg_t * pushArg = (SP_PushArg_t*)arg; | ||
253 | + | ||
254 | + pushArg->mEventArg->getInputResultQueue()->push( | ||
255 | + new SP_SimpleTask( timer, pushArg, 1 ) ); | ||
256 | +} | ||
257 | + | ||
258 | +void SP_Dispatcher :: timer( void * arg ) | ||
259 | +{ | ||
260 | + SP_PushArg_t * pushArg = (SP_PushArg_t*)arg; | ||
261 | + SP_TimerHandler * handler = pushArg->mTimerHandler; | ||
262 | + SP_EventArg * eventArg = pushArg->mEventArg; | ||
263 | + | ||
264 | + SP_Sid_t sid; | ||
265 | + sid.mKey = SP_Sid_t::eTimerKey; | ||
266 | + sid.mSeq = SP_Sid_t::eTimerSeq; | ||
267 | + SP_Response * response = new SP_Response( sid ); | ||
268 | + if( 0 == handler->handle( response, &( pushArg->mTimeout ) ) ) { | ||
269 | + msgqueue_push( (struct event_msgqueue*)pushArg->mPushQueue, arg ); | ||
270 | + } else { | ||
271 | + delete pushArg->mTimerHandler; | ||
272 | + free( pushArg ); | ||
273 | + } | ||
274 | + | ||
275 | + msgqueue_push( (struct event_msgqueue*)eventArg->getResponseQueue(), response ); | ||
276 | +} | ||
277 | + | ||
278 | +int SP_Dispatcher :: push( const struct timeval * timeout, SP_TimerHandler * handler ) | ||
279 | +{ | ||
280 | + SP_PushArg_t * arg = (SP_PushArg_t*)malloc( sizeof( SP_PushArg_t ) ); | ||
281 | + | ||
282 | + arg->mType = 1; | ||
283 | + arg->mTimeout = *timeout; | ||
284 | + arg->mTimerHandler = handler; | ||
285 | + arg->mEventArg = mEventArg; | ||
286 | + arg->mPushQueue = mPushQueue; | ||
287 | + | ||
288 | + return msgqueue_push( (struct event_msgqueue*)mPushQueue, arg ); | ||
289 | +} | ||
290 | + | ||
291 | +int SP_Dispatcher :: push( SP_Response * response ) | ||
292 | +{ | ||
293 | + return msgqueue_push( (struct event_msgqueue*)mEventArg->getResponseQueue(), response ); | ||
294 | +} | ||
295 | + |
请
注册
或
登录
后发表评论