正在显示
1 个修改的文件
包含
321 行增加
和
0 行删除
src/server/spserver/spiocpdispatcher.cpp
0 → 100644
1 | +/* | |
2 | + * Copyright 2008 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 "spiocpdispatcher.hpp" | |
17 | + | |
18 | +#include "spwin32iocp.hpp" | |
19 | +#include "sphandler.hpp" | |
20 | +#include "spsession.hpp" | |
21 | +#include "spexecutor.hpp" | |
22 | +#include "sputils.hpp" | |
23 | +#include "spioutils.hpp" | |
24 | +#include "spiochannel.hpp" | |
25 | +#include "sprequest.hpp" | |
26 | + | |
27 | +#include "spiocpevent.hpp" | |
28 | + | |
29 | +SP_IocpDispatcher :: SP_IocpDispatcher( 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_IocpEventArg( 600 ); | |
40 | + SP_IocpMsgQueue * msgQueue = new SP_IocpMsgQueue( mEventArg->getCompletionPort(), | |
41 | + SP_IocpEventCallback::eKeyMsgQueue, SP_IocpEventCallback::onResponse, mEventArg ); | |
42 | + mEventArg->setResponseQueue( msgQueue ); | |
43 | + // load DisconnectEx | |
44 | + { | |
45 | + int fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED ); | |
46 | + mEventArg->loadDisconnectEx( fd ); | |
47 | + closesocket( fd ); | |
48 | + } | |
49 | + | |
50 | + mMaxThreads = maxThreads > 0 ? maxThreads : 4; | |
51 | + | |
52 | + mCompletionHandler = completionHandler; | |
53 | + | |
54 | + mPushQueue = new SP_IocpMsgQueue( mEventArg->getCompletionPort(), | |
55 | + SP_IocpEventCallback::eKeyMsgQueue, onPush, mEventArg ); | |
56 | +} | |
57 | + | |
58 | +SP_IocpDispatcher :: ~SP_IocpDispatcher() | |
59 | +{ | |
60 | + if( 0 == mIsRunning ) sleep( 1 ); | |
61 | + | |
62 | + shutdown(); | |
63 | + | |
64 | + for( ; mIsRunning; ) sleep( 1 ); | |
65 | + | |
66 | + delete mPushQueue; | |
67 | + mPushQueue = NULL; | |
68 | + | |
69 | + delete mEventArg; | |
70 | + mEventArg = NULL; | |
71 | +} | |
72 | + | |
73 | +void SP_IocpDispatcher :: setTimeout( int timeout ) | |
74 | +{ | |
75 | + mEventArg->setTimeout( timeout ); | |
76 | +} | |
77 | + | |
78 | +void SP_IocpDispatcher :: shutdown() | |
79 | +{ | |
80 | + mIsShutdown = 1; | |
81 | + | |
82 | + PostQueuedCompletionStatus( mEventArg->getCompletionPort(), 0, 0, 0 ); | |
83 | +} | |
84 | + | |
85 | +int SP_IocpDispatcher :: isRunning() | |
86 | +{ | |
87 | + return mIsRunning; | |
88 | +} | |
89 | + | |
90 | +int SP_IocpDispatcher :: getSessionCount() | |
91 | +{ | |
92 | + return mEventArg->getSessionManager()->getCount(); | |
93 | +} | |
94 | + | |
95 | +int SP_IocpDispatcher :: getReqQueueLength() | |
96 | +{ | |
97 | + return mEventArg->getInputResultQueue()->getLength(); | |
98 | +} | |
99 | + | |
100 | +int SP_IocpDispatcher :: dispatch() | |
101 | +{ | |
102 | + int ret = -1; | |
103 | + | |
104 | + sp_thread_attr_t attr; | |
105 | + sp_thread_attr_init( &attr ); | |
106 | + assert( sp_thread_attr_setstacksize( &attr, 1024 * 1024 ) == 0 ); | |
107 | + sp_thread_attr_setdetachstate( &attr, SP_THREAD_CREATE_DETACHED ); | |
108 | + | |
109 | + sp_thread_t thread; | |
110 | + ret = sp_thread_create( &thread, &attr, eventLoop, this ); | |
111 | + sp_thread_attr_destroy( &attr ); | |
112 | + if( 0 == ret ) { | |
113 | + sp_syslog( LOG_NOTICE, "Thread #%ld has been created for dispatcher", thread ); | |
114 | + } else { | |
115 | + mIsRunning = 0; | |
116 | + sp_syslog( LOG_WARNING, "Unable to create a thread for dispatcher, %s", | |
117 | + strerror( errno ) ) ; | |
118 | + } | |
119 | + | |
120 | + return ret; | |
121 | +} | |
122 | + | |
123 | +sp_thread_result_t SP_THREAD_CALL SP_IocpDispatcher :: eventLoop( void * arg ) | |
124 | +{ | |
125 | + SP_IocpDispatcher * dispatcher = (SP_IocpDispatcher*)arg; | |
126 | + | |
127 | + dispatcher->mIsRunning = 1; | |
128 | + | |
129 | + dispatcher->start(); | |
130 | + | |
131 | + dispatcher->mIsRunning = 0; | |
132 | + | |
133 | + return 0; | |
134 | +} | |
135 | + | |
136 | +void SP_IocpDispatcher :: outputCompleted( void * arg ) | |
137 | +{ | |
138 | + SP_CompletionHandler * handler = ( SP_CompletionHandler * ) ((void**)arg)[0]; | |
139 | + SP_Message * msg = ( SP_Message * ) ((void**)arg)[ 1 ]; | |
140 | + | |
141 | + handler->completionMessage( msg ); | |
142 | + | |
143 | + free( arg ); | |
144 | +} | |
145 | + | |
146 | +int SP_IocpDispatcher :: start() | |
147 | +{ | |
148 | + SP_Executor workerExecutor( mMaxThreads, "work" ); | |
149 | + SP_Executor actExecutor( 1, "act" ); | |
150 | + | |
151 | + /* Start the event loop. */ | |
152 | + while( 0 == mIsShutdown ) { | |
153 | + SP_IocpEventCallback::eventLoop( mEventArg, NULL ); | |
154 | + | |
155 | + for( ; NULL != mEventArg->getInputResultQueue()->top(); ) { | |
156 | + SP_Task * task = (SP_Task*)mEventArg->getInputResultQueue()->pop(); | |
157 | + workerExecutor.execute( task ); | |
158 | + } | |
159 | + | |
160 | + for( ; NULL != mEventArg->getOutputResultQueue()->top(); ) { | |
161 | + SP_Message * msg = (SP_Message*)mEventArg->getOutputResultQueue()->pop(); | |
162 | + | |
163 | + void ** arg = ( void** )malloc( sizeof( void * ) * 2 ); | |
164 | + arg[ 0 ] = (void*)mCompletionHandler; | |
165 | + arg[ 1 ] = (void*)msg; | |
166 | + | |
167 | + actExecutor.execute( outputCompleted, arg ); | |
168 | + } | |
169 | + } | |
170 | + | |
171 | + sp_syslog( LOG_NOTICE, "Dispatcher is shutdown." ); | |
172 | + | |
173 | + return 0; | |
174 | +} | |
175 | + | |
176 | +typedef struct tagSP_IocpPushArg { | |
177 | + int mType; // 0 : fd, 1 : timer | |
178 | + | |
179 | + // for push fd | |
180 | + int mFd; | |
181 | + SP_Handler * mHandler; | |
182 | + SP_IOChannel * mIOChannel; | |
183 | + int mNeedStart; | |
184 | + | |
185 | + // for push timer | |
186 | + struct timeval mTimeout; | |
187 | + SP_IocpEvent_t mTimerEvent; | |
188 | + SP_TimerHandler * mTimerHandler; | |
189 | + SP_IocpEventArg * mEventArg; | |
190 | + SP_IocpMsgQueue * mPushQueue; | |
191 | +} SP_IocpPushArg_t; | |
192 | + | |
193 | +void SP_IocpDispatcher :: onPush( void * queueData, void * arg ) | |
194 | +{ | |
195 | + SP_IocpPushArg_t * pushArg = (SP_IocpPushArg_t*)queueData; | |
196 | + SP_IocpEventArg * eventArg = (SP_IocpEventArg*)arg; | |
197 | + | |
198 | + if( 0 == pushArg->mType ) { | |
199 | + SP_Sid_t sid; | |
200 | + sid.mKey = eventArg->getSessionManager()->allocKey( &sid.mSeq ); | |
201 | + assert( sid.mKey > 0 ); | |
202 | + | |
203 | + SP_Session * session = new SP_Session( sid ); | |
204 | + | |
205 | + char clientIP[ 32 ] = { 0 }; | |
206 | + { | |
207 | + struct sockaddr_in clientAddr; | |
208 | + socklen_t clientLen = sizeof( clientAddr ); | |
209 | + getpeername( pushArg->mFd, (struct sockaddr *)&clientAddr, &clientLen ); | |
210 | + SP_IOUtils::inetNtoa( &( clientAddr.sin_addr ), clientIP, sizeof( clientIP ) ); | |
211 | + session->getRequest()->setClientPort( ntohs( clientAddr.sin_port ) ); | |
212 | + } | |
213 | + session->getRequest()->setClientIP( clientIP ); | |
214 | + | |
215 | + session->setHandler( pushArg->mHandler ); | |
216 | + session->setArg( eventArg ); | |
217 | + session->setIOChannel( pushArg->mIOChannel ); | |
218 | + | |
219 | + if( SP_IocpEventCallback::addSession( eventArg, (HANDLE)pushArg->mFd, session ) ) { | |
220 | + eventArg->getSessionManager()->put( sid.mKey, sid.mSeq, session ); | |
221 | + | |
222 | + if( pushArg->mNeedStart ) { | |
223 | + SP_IocpEventHelper::doStart( session ); | |
224 | + } else { | |
225 | + SP_IocpEventCallback::addRecv( session ); | |
226 | + } | |
227 | + } else { | |
228 | + delete session; | |
229 | + } | |
230 | + | |
231 | + free( pushArg ); | |
232 | + } else { | |
233 | + memset( &( pushArg->mTimerEvent ), 0, sizeof( SP_IocpEvent_t ) ); | |
234 | + pushArg->mTimerEvent.mType = SP_IocpEvent_t::eEventTimer; | |
235 | + | |
236 | + struct timeval curr; | |
237 | + sp_gettimeofday( &curr, NULL ); | |
238 | + struct timeval * dest = &( pushArg->mTimerEvent.mTimeout ); | |
239 | + struct timeval * src = &( pushArg->mTimeout ); | |
240 | + | |
241 | + dest->tv_sec = curr.tv_sec + src->tv_sec; | |
242 | + dest->tv_usec = curr.tv_usec + src->tv_usec; | |
243 | + if( dest->tv_usec >= 1000000 ) { | |
244 | + dest->tv_sec++; | |
245 | + dest->tv_usec -= 1000000; | |
246 | + } | |
247 | + | |
248 | + pushArg->mTimerEvent.mHeapIndex = -1; | |
249 | + pushArg->mTimerEvent.mOnTimer = onTimer; | |
250 | + | |
251 | + eventArg->getEventHeap()->push( &( pushArg->mTimerEvent ) ); | |
252 | + } | |
253 | +} | |
254 | + | |
255 | +int SP_IocpDispatcher :: push( int fd, SP_Handler * handler, int needStart ) | |
256 | +{ | |
257 | + SP_IOChannel * ioChannel = new SP_DefaultIOChannel(); | |
258 | + return push( fd, handler, ioChannel, needStart ); | |
259 | +} | |
260 | + | |
261 | +int SP_IocpDispatcher :: push( int fd, SP_Handler * handler, | |
262 | + SP_IOChannel * ioChannel, int needStart ) | |
263 | +{ | |
264 | + SP_IocpPushArg_t * arg = (SP_IocpPushArg_t*)malloc( sizeof( SP_IocpPushArg_t ) ); | |
265 | + arg->mType = 0; | |
266 | + arg->mFd = fd; | |
267 | + arg->mHandler = handler; | |
268 | + arg->mNeedStart = needStart; | |
269 | + arg->mIOChannel = ioChannel; | |
270 | + | |
271 | + SP_IOUtils::setNonblock( fd ); | |
272 | + | |
273 | + return mPushQueue->push( arg ); | |
274 | +} | |
275 | + | |
276 | +void SP_IocpDispatcher :: onTimer( void * arg ) | |
277 | +{ | |
278 | + SP_IocpEvent_t * event = (SP_IocpEvent_t*)arg; | |
279 | + SP_IocpPushArg_t * pushArg = CONTAINING_RECORD( event, SP_IocpPushArg_t, mTimerEvent ); | |
280 | + | |
281 | + pushArg->mEventArg->getInputResultQueue()->push( | |
282 | + new SP_SimpleTask( timer, pushArg, 1 ) ); | |
283 | +} | |
284 | + | |
285 | +void SP_IocpDispatcher :: timer( void * arg ) | |
286 | +{ | |
287 | + SP_IocpPushArg_t * pushArg = (SP_IocpPushArg_t*)arg; | |
288 | + SP_TimerHandler * handler = pushArg->mTimerHandler; | |
289 | + SP_IocpEventArg * eventArg = pushArg->mEventArg; | |
290 | + | |
291 | + SP_Sid_t sid; | |
292 | + sid.mKey = SP_Sid_t::eTimerKey; | |
293 | + sid.mSeq = SP_Sid_t::eTimerSeq; | |
294 | + SP_Response * response = new SP_Response( sid ); | |
295 | + if( 0 == handler->handle( response, &( pushArg->mTimeout ) ) ) { | |
296 | + pushArg->mPushQueue->push( arg ); | |
297 | + } else { | |
298 | + delete pushArg->mTimerHandler; | |
299 | + free( pushArg ); | |
300 | + } | |
301 | + | |
302 | + eventArg->getResponseQueue()->push( response ); | |
303 | +} | |
304 | + | |
305 | +int SP_IocpDispatcher :: push( const struct timeval * timeout, SP_TimerHandler * handler ) | |
306 | +{ | |
307 | + SP_IocpPushArg_t * arg = (SP_IocpPushArg_t*)malloc( sizeof( SP_IocpPushArg_t ) ); | |
308 | + | |
309 | + arg->mType = 1; | |
310 | + arg->mTimeout = *timeout; | |
311 | + arg->mTimerHandler = handler; | |
312 | + arg->mEventArg = mEventArg; | |
313 | + arg->mPushQueue = mPushQueue; | |
314 | + | |
315 | + return mPushQueue->push( arg ); | |
316 | +} | |
317 | + | |
318 | +int SP_IocpDispatcher :: push( SP_Response * response ) | |
319 | +{ | |
320 | + return mEventArg->getResponseQueue()->push( response ); | |
321 | +} | ... | ... |
请
注册
或
登录
后发表评论