Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 338 lines (259 sloc) 10.553 kb
bae9856 Yathin Krishnappa adding license information to sources
yathin authored
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
4 Redistribution and use of this software in source and binary forms, with or
5 without modification, are permitted provided that the following conditions are
6 met:
7
8 * Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10
11 * Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation and/or
13 other materials provided with the distribution.
14
15 * Neither the name of Yahoo! Inc. nor the names of its contributors may be used
16 to endorse or promote products derived from this software without specific prior
17 written permission of Yahoo! Inc.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
2bbc399 Mark Delany Many portability fixes and autoconf support
MarkDelany authored
31 #include "config.h"
32
f42d421 Yathin Krishnappa first commit. pluton framework
yathin authored
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/mman.h>
36 #include <sys/stat.h>
37 #include <sys/uio.h>
38
39 #include <errno.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "pluton/fault.h"
44
45 #include "global.h"
46 #include "processExitReason.h"
47 #include "shmService.h"
48 #include "util.h"
49
50
51 #ifndef MAP_NOSYNC
52 #define MAP_NOSYNC 0
53 #endif
54
55 pluton::shmServiceHandler::shmServiceHandler()
56 : _shmServicePtr(0), _shmProcessPtr(0), _shmThreadPtr(0),
57 _mapSize(0),
58 _maxProcesses(0), _maxThreads(0),
59 _myPid(0), _myTid(0)
60 {
61 _myLastStart.tv_sec = 0;
62 _myLastStart.tv_usec = 0;
63 }
64
65 pluton::shmServiceHandler::~shmServiceHandler()
66 {
67 if (_shmServicePtr) munmap(static_cast<void*>(_shmServicePtr), _mapSize);
68 }
69
70 //////////////////////////////////////////////////////////////////////
71 // Map the serviceMap for the service-side. This should be the first
72 // call to this class as the mapping is needed for most of the other
73 // methods to do something useful. A tid of -1 indicates a
74 // non-threaded service. In either case, the threadedness of the
75 // service must match the config.
76 //////////////////////////////////////////////////////////////////////
77
78 pluton::faultCode
79 pluton::shmServiceHandler::mapService(int fd, pid_t pid, bool threadedFlag)
80 {
81 // Need to know the size to map
82
83 struct stat sb;
84 if (fstat(fd, &sb) == -1) {
85 close(fd);
86 return pluton::shmFstatFailed;
87 }
88
89 _mapSize = sb.st_size;
90
91 void* p = mmap(0, _mapSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOSYNC, fd, 0);
92 if (p == MAP_FAILED) return pluton::shmMmapFailed;
93
94 shmService* tmpSP = static_cast<shmService*>(p);
95
96 if (tmpSP->_header._version != plutonGlobal::shmServiceVersion) return pluton::shmVersionMisMatch;
97
98 _shmServicePtr = static_cast<shmService*>(p);
99 _myConfig = _shmServicePtr->_config;
100
101 if (!threadedFlag) { // Non-threaded service but a threaded
102 if (_myConfig._maximumThreads > 1) return pluton::shmThreadConfigNotService; // config
103 }
104 else { // Threaded service but not a threaded
105 if (_myConfig._maximumThreads == 1) return pluton::shmThreadServiceNotConfig; // config
106 }
107
108 _myPid = pid;
109
110 return pluton::noFault;
111 }
112
113
114 bool
115 pluton::shmServiceHandler::setProcessReady(const struct timeval& now)
116 {
117 if (!_shmProcessPtr) if (!resolvePointers()) return false;
118
119 shmTimeVal tv;
120 tv.tv_sec = now.tv_sec;
121 tv.tv_usec = now.tv_usec;
122 _shmProcessPtr->_lastActive = _shmThreadPtr->_lastActive = tv;
123
124 return true;
125 }
126
127
128 //////////////////////////////////////////////////////////////////////
129 // Active transitions are recorded in shm so that the manager can
130 // understand the true state of the service. Whether it is stalled,
131 // idle or very busy. Concurrency of service is determined by the
132 // amount of active time vs idle time as measured by the service via
133 // this method.
134 //
135 // Because these counters are in shared memory that are not locked,
136 // they will *sometimes* be wrong due to update collisions, but that
137 // is likely to be very rare and the occassional collision doesn't
138 // really have much bearing as they are routinely reset to zero and
139 // re-sampled.
140 //////////////////////////////////////////////////////////////////////
141
142 void
143 pluton::shmServiceHandler::startResponseTimer(const struct timeval& now, bool affinity)
144 {
145 if (!_shmProcessPtr) if (!resolvePointers()) return;
146
147 _myLastStart = now;
148
149 shmTimeVal tv;
150 tv.tv_sec = now.tv_sec;
151 tv.tv_usec = now.tv_usec;
152 _shmProcessPtr->_lastActive = _shmThreadPtr->_lastActive = tv;
153 _shmThreadPtr->_affinityFlag = affinity;
154
155 //////////////////////////////////////////////////////////////////////
156 // Opportunistically count the current service occupancy for the
157 // manager since their sampling may never catch peaks.
158 //////////////////////////////////////////////////////////////////////
159
160 unsigned int maxActive = 0;
161 for (int pidx=0; pidx < _myConfig._maximumProcesses; ++pidx) {
162 if (_shmServicePtr->_process[pidx]._pid == 0) continue;
163 for (int tidx=0; tidx < _myConfig._maximumThreads; ++tidx) {
164 if (_shmServicePtr->_process[pidx]._thread[tidx]._activeFlag) ++maxActive;
165 }
166 }
167
168 if (maxActive > _shmServicePtr->_aggregateCounters._maximumActiveCount) {
169 _shmServicePtr->_aggregateCounters._maximumActiveCount = maxActive;
170 }
171 }
172
173
174 //////////////////////////////////////////////////////////////////////
175 // Calculate duration of request and transfer state to shm
176 //////////////////////////////////////////////////////////////////////
177
178 void
179 pluton::shmServiceHandler::stopResponseTimer(const struct timeval& now)
180 {
181 if (!_shmProcessPtr) if (!resolvePointers()) return;
182
183 // setProcessActive may not have resolvedPointers due to Manager
184 // tardiness, so only unwind the setProcessActive actions if it
185 // took any.
186
187 if (_myLastStart.tv_sec > 0) {
188 long uSecs = util::timevalDiffuS(now, _myLastStart);
189 _shmProcessPtr->_activeuSecs += uSecs;
190 _shmServicePtr->_aggregateCounters._activeuSecs += uSecs;
191 ++_shmServicePtr->_aggregateCounters._requestCount;
192 }
193 }
194
195
196 //////////////////////////////////////////////////////////////////////
197 // The true definition of an inactive service is when a service/thread
198 // is sitting on an accept() waiting for a request. This is the
199 // definition the manager need to distinguish between an idle and
200 // stalled service.
201 //////////////////////////////////////////////////////////////////////
202
203 void
204 pluton::shmServiceHandler::setProcessAcceptingRequests(bool tf)
205 {
206 if (!_shmProcessPtr) if (!resolvePointers()) return;
207
208 if (tf) {
209 _shmThreadPtr->_activeFlag = false;
210 --_shmProcessPtr->_activeThreadCount;
211 if (--_shmProcessPtr->_activeThreadCount < 0) _shmProcessPtr->_activeThreadCount = 0;
212 }
213 else {
214 _shmThreadPtr->_activeFlag = true;
215 ++_shmProcessPtr->_activeThreadCount;
216 }
217 }
218
219
220 //////////////////////////////////////////////////////////////////////
221 // Various counter transfer routines. All of these *set* their values
222 // rather than increment to minimize non-lock issues with shm.
223 //////////////////////////////////////////////////////////////////////
224
225 void
226 pluton::shmServiceHandler::setProcessRequestCount(int c)
227 {
228 if (!_shmProcessPtr) if (!resolvePointers()) return;
229
230 _shmProcessPtr->_requestCount = c;
231 }
232
233 void
234 pluton::shmServiceHandler::setProcessResponseCount(int c)
235 {
236 if (!_shmProcessPtr) if (!resolvePointers()) return;
237
238 _shmProcessPtr->_responseCount = c;
239 }
240
241 void
242 pluton::shmServiceHandler::setProcessFaultCount(int c)
243 {
244 if (!_shmProcessPtr) if (!resolvePointers()) return;
245
246 _shmProcessPtr->_faultCount = c;
247 }
248
249
250 //////////////////////////////////////////////////////////////////////
251 // Transfer details to shared memory so others can share the joy.
252 //////////////////////////////////////////////////////////////////////
253
254 void
255 pluton::shmServiceHandler::setProcessClientDetails(unsigned int requestID,
256 struct timeval startTime,
257 const char* cnamePtr, int cnameLength)
258 {
259 if (!_shmProcessPtr) if (!resolvePointers()) return;
260
261 _shmThreadPtr->_clientRequestID = requestID;
262
263 shmTimeVal tv;
264 tv.tv_sec = startTime.tv_sec;
265 tv.tv_usec = startTime.tv_usec;
266 _shmThreadPtr->_clientRequestStartTime = tv;
267
268 unsigned int cpLen = cnameLength;
269 if (cpLen >= sizeof(_shmThreadPtr->_clientRequestName)) {
270 cpLen = sizeof(_shmThreadPtr->_clientRequestName)-1;
271 }
272
273 strncpy(_shmThreadPtr->_clientRequestName, cnamePtr, cpLen);
274 _shmThreadPtr->_clientRequestName[cpLen] = '\0';
275 }
276
277
278 void
279 pluton::shmServiceHandler::setProcessExitReason(processExit::reason er)
280 {
281 if (!_shmProcessPtr) if (!resolvePointers()) return;
282
283 _shmProcessPtr->_exitReason = er;
284 }
285
286
287 void
288 pluton::shmServiceHandler::setProcessTerminated()
289 {
290 if (!_shmProcessPtr) if (!resolvePointers()) return;
291
292 _shmProcessPtr->_pid = 0;
293 }
294
295
296 processExit::reason
297 pluton::shmServiceHandler::getProcessShutdownRequest()
298 {
299 if (!_shmProcessPtr) if (!resolvePointers()) return processExit::noReason;
300
301 return _shmProcessPtr->_shutdownRequest;
302 }
303
304
305 time_t
306 pluton::shmServiceHandler::getManagerHeartbeat()
307 {
308 if (!_shmServicePtr) if (!resolvePointers()) return 0;
309
310 return _shmServicePtr->_managerHeartbeat;
311 }
312
313
314 //////////////////////////////////////////////////////////////////////
315 // Find the shmProcess and shmThread that matches this service
316 // handler. Since the pid in that structure is set independantly by
317 // the manager after the child is forked, there is a timing window
318 // whereby it's possible that it may not be set for the first few
319 // moments. Accordingly, not finding the entry is treated pretty
320 // passively by callers.
321 //////////////////////////////////////////////////////////////////////
322
323 bool
324 pluton::shmServiceHandler::resolvePointers()
325 {
326 if (!_shmServicePtr) return false; // If not mapped at all, can't search
327
328 for (int pidx=0; pidx < _myConfig._maximumProcesses; ++pidx) {
329 if (_shmServicePtr->_process[pidx]._pid == _myPid) {
330 _shmProcessPtr = &_shmServicePtr->_process[pidx];
331 _shmThreadPtr = &_shmProcessPtr->_thread[_myTid];
332 return true;
333 }
334 }
335
336 return false;
337 }
Something went wrong with that request. Please try again.