1
1
#include " precomp.h"
2
2
3
3
CNodeProcessManager::CNodeProcessManager (CNodeApplication* application, IHttpContext* context)
4
- : application(application), processes(NULL ), processCount( 0 ), currentProcess(0 ), isClosing(FALSE ),
4
+ : application(application), processes(NULL ), currentProcess(0 ), isClosing(FALSE ),
5
5
refCount(1 )
6
6
{
7
7
if (this ->GetApplication ()->IsDebugMode ())
8
8
{
9
- this ->maxProcessCount = 1 ;
9
+ this ->processCount = 1 ;
10
10
}
11
11
else
12
12
{
13
- this ->maxProcessCount = CModuleConfiguration::GetMaxProcessCountPerApplication (context);
13
+ this ->processCount = CModuleConfiguration::GetNodeProcessCountPerApplication (context);
14
14
}
15
15
16
16
// cache event provider since the application can be disposed prior to CNodeProcessManager
@@ -22,11 +22,19 @@ CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpCon
22
22
23
23
CNodeProcessManager::~CNodeProcessManager ()
24
24
{
25
- if (NULL != processes)
25
+ this ->Cleanup ();
26
+ }
27
+
28
+ void CNodeProcessManager::Cleanup ()
29
+ {
30
+ if (NULL != this ->processes )
26
31
{
27
32
for (int i = 0 ; i < this ->processCount ; i++)
28
33
{
29
- delete this ->processes [i];
34
+ if (this ->processes [i])
35
+ {
36
+ delete this ->processes [i];
37
+ }
30
38
}
31
39
32
40
delete[] this ->processes ;
@@ -43,74 +51,45 @@ HRESULT CNodeProcessManager::Initialize(IHttpContext* context)
43
51
{
44
52
HRESULT hr;
45
53
46
- ErrorIf (NULL == (this ->processes = new CNodeProcess* [this ->maxProcessCount ]), ERROR_NOT_ENOUGH_MEMORY);
47
- RtlZeroMemory (this ->processes , this ->maxProcessCount * sizeof (CNodeProcess*));
48
- if ( this ->GetApplication ()-> IsDebuggee () )
54
+ ErrorIf (NULL == (this ->processes = new CNodeProcess* [this ->processCount ]), ERROR_NOT_ENOUGH_MEMORY);
55
+ RtlZeroMemory (this ->processes , this ->processCount * sizeof (CNodeProcess*));
56
+ for ( int i = 0 ; i < this ->processCount ; i++ )
49
57
{
50
- // ensure the debugee process is started without activating message
51
- // this is to make sure it is available for the debugger to connect to
52
-
53
- CheckError (this ->AddOneProcess (NULL , context));
58
+ CheckError (this ->AddProcess (i, context));
54
59
}
55
60
56
61
return S_OK;
57
62
Error:
58
63
59
- if (NULL != this ->processes )
60
- {
61
- delete [] this ->processes ;
62
- this ->processes = NULL ;
63
- }
64
+ this ->Cleanup ();
64
65
65
66
return hr;
66
67
}
67
68
68
- HRESULT CNodeProcessManager::AddOneProcessCore (CNodeProcess** process , IHttpContext* context)
69
+ HRESULT CNodeProcessManager::AddProcess ( int ordinal , IHttpContext* context)
69
70
{
70
71
HRESULT hr;
71
72
72
- ErrorIf (this ->processCount == this ->maxProcessCount , ERROR_NOT_ENOUGH_QUOTA);
73
- ErrorIf (NULL == (this ->processes [this ->processCount ] = new CNodeProcess (this , context, this ->processCount )), ERROR_NOT_ENOUGH_MEMORY);
74
- CheckError (this ->processes [this ->processCount ]->Initialize (context));
75
- if (NULL != process)
76
- {
77
- *process = this ->processes [this ->processCount ];
78
- }
79
- this ->processCount ++;
73
+ ErrorIf (NULL != this ->processes [ordinal], ERROR_INVALID_PARAMETER);
74
+ ErrorIf (NULL == (this ->processes [ordinal] = new CNodeProcess (this , context, ordinal)), ERROR_NOT_ENOUGH_MEMORY);
75
+ CheckError (this ->processes [ordinal]->Initialize (context));
80
76
81
77
return S_OK;
82
78
Error:
83
79
84
- if (NULL != this ->processes [this -> processCount ])
80
+ if (NULL != this ->processes [ordinal ])
85
81
{
86
- delete this ->processes [this -> processCount ];
87
- this ->processes [this -> processCount ] = NULL ;
82
+ delete this ->processes [ordinal ];
83
+ this ->processes [ordinal ] = NULL ;
88
84
}
89
85
90
86
return hr;
91
87
}
92
88
93
- HRESULT CNodeProcessManager::AddOneProcess (CNodeProcess** process, IHttpContext* context)
94
- {
95
- HRESULT hr;
96
-
97
- if (NULL != process)
98
- {
99
- *process = NULL ;
100
- }
101
-
102
- ErrorIf (this ->processCount == this ->maxProcessCount , ERROR_NOT_ENOUGH_QUOTA);
103
- CheckError (this ->AddOneProcessCore (process, context));
104
-
105
- return S_OK;
106
- Error:
107
-
108
- return hr;
109
- }
110
-
111
89
HRESULT CNodeProcessManager::Dispatch (CNodeHttpStoredContext* request)
112
90
{
113
91
HRESULT hr;
92
+ unsigned int tmpProcess, processToUse;
114
93
115
94
CheckNull (request);
116
95
@@ -120,24 +99,48 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request)
120
99
{
121
100
ENTER_SRW_SHARED (this ->srwlock )
122
101
123
- if (!this ->isClosing && this -> TryRouteRequestToExistingProcess (request) )
102
+ if (!this ->isClosing )
124
103
{
125
- request = NULL ;
104
+ // employ a round robin routing logic to get a "ticket" to use a process with a specific ordinal number
105
+
106
+ if (1 == this ->processCount )
107
+ {
108
+ processToUse = 0 ;
109
+ }
110
+ else
111
+ {
112
+ do
113
+ {
114
+ tmpProcess = this ->currentProcess ;
115
+ processToUse = (tmpProcess + 1 ) % this ->processCount ;
116
+ } while (tmpProcess != InterlockedCompareExchange (&this ->currentProcess , processToUse, tmpProcess));
117
+ }
118
+
119
+ // try dispatch to that process
120
+
121
+ if (NULL != this ->processes [processToUse])
122
+ {
123
+ CheckError (this ->processes [processToUse]->AcceptRequest (request));
124
+ request = NULL ;
125
+ }
126
126
}
127
127
128
128
LEAVE_SRW_SHARED (this ->srwlock )
129
129
130
- if (request && ! this -> isClosing )
130
+ if (NULL != request )
131
131
{
132
- // existing processes were unable to accept this request; create a new process to handle it
132
+ // the process to dispatch to does not exist and must be recreated
133
133
134
134
ENTER_SRW_EXCLUSIVE (this ->srwlock )
135
135
136
- if (!this ->isClosing && ! this -> TryRouteRequestToExistingProcess (request) )
136
+ if (!this ->isClosing )
137
137
{
138
- CNodeProcess* newProcess = NULL ;
139
- CheckError (this ->AddOneProcess (&newProcess, request->GetHttpContext ()));
140
- CheckError (newProcess->AcceptRequest (request));
138
+ if (NULL == this ->processes [processToUse])
139
+ {
140
+ CheckError (this ->AddProcess (processToUse, request->GetHttpContext ()));
141
+ }
142
+
143
+ CheckError (this ->processes [processToUse]->AcceptRequest (request));
141
144
}
142
145
143
146
LEAVE_SRW_EXCLUSIVE (this ->srwlock )
@@ -162,29 +165,6 @@ HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request)
162
165
return hr;
163
166
}
164
167
165
- BOOL CNodeProcessManager::TryRouteRequestToExistingProcess (CNodeHttpStoredContext* context)
166
- {
167
- if (this ->processCount == 0 )
168
- {
169
- return false ;
170
- }
171
-
172
- DWORD i = this ->currentProcess ;
173
-
174
- do {
175
-
176
- if (S_OK == this ->processes [i]->AcceptRequest (context))
177
- {
178
- return true ;
179
- }
180
-
181
- i = (i + 1 ) % this ->processCount ;
182
-
183
- } while (i != this ->currentProcess );
184
-
185
- return false ;
186
- }
187
-
188
168
HRESULT CNodeProcessManager::RecycleProcess (CNodeProcess* process)
189
169
{
190
170
HRESULT hr;
@@ -221,13 +201,7 @@ HRESULT CNodeProcessManager::RecycleProcess(CNodeProcess* process)
221
201
return S_OK;
222
202
}
223
203
224
- if (i < (this ->processCount - 1 ))
225
- {
226
- memcpy (this ->processes + i, this ->processes + i + 1 , sizeof (CNodeProcess*) * (this ->processCount - i - 1 ));
227
- }
228
-
229
- this ->processCount --;
230
- this ->currentProcess = 0 ;
204
+ this ->processes [i] = NULL ;
231
205
232
206
gracefulRecycle = TRUE ;
233
207
}
@@ -277,7 +251,17 @@ HRESULT CNodeProcessManager::Recycle()
277
251
278
252
this ->isClosing = TRUE ;
279
253
280
- if (0 < this ->processCount )
254
+ BOOL hasActiveProcess = FALSE ;
255
+ for (int i = 0 ; i < this ->processCount ; i++)
256
+ {
257
+ if (this ->processes [i])
258
+ {
259
+ hasActiveProcess = TRUE ;
260
+ break ;
261
+ }
262
+ }
263
+
264
+ if (hasActiveProcess)
281
265
{
282
266
// perform actual recycling on a diffrent thread to free up the file watcher thread
283
267
@@ -321,23 +305,28 @@ unsigned int CNodeProcessManager::GracefulShutdown(void* arg)
321
305
ProcessRecycleArgs* args = (ProcessRecycleArgs*)arg;
322
306
HRESULT hr;
323
307
HANDLE* drainHandles = NULL ;
308
+ DWORD drainHandleCount = 0 ;
324
309
325
310
// drain active requests
326
311
327
312
ErrorIf (NULL == (drainHandles = new HANDLE[args->count ]), ERROR_NOT_ENOUGH_MEMORY);
328
313
RtlZeroMemory (drainHandles, args->count * sizeof HANDLE);
329
314
for (int i = 0 ; i < args->count ; i++)
330
315
{
331
- drainHandles[i] = CreateEvent (NULL , TRUE , FALSE , NULL );
332
- args->processes [i]->SignalWhenDrained (drainHandles[i]);
316
+ if (args->processes [i])
317
+ {
318
+ drainHandles[drainHandleCount] = CreateEvent (NULL , TRUE , FALSE , NULL );
319
+ args->processes [i]->SignalWhenDrained (drainHandles[drainHandleCount]);
320
+ drainHandleCount++;
321
+ }
333
322
}
334
323
335
324
if (args->processManager ->gracefulShutdownTimeout > 0 )
336
325
{
337
- WaitForMultipleObjects (args-> count , drainHandles, TRUE , args->processManager ->gracefulShutdownTimeout );
326
+ WaitForMultipleObjects (drainHandleCount , drainHandles, TRUE , args->processManager ->gracefulShutdownTimeout );
338
327
}
339
328
340
- for (int i = 0 ; i < args-> count ; i++)
329
+ for (int i = 0 ; i < drainHandleCount ; i++)
341
330
{
342
331
CloseHandle (drainHandles[i]);
343
332
}
0 commit comments