PageRenderTime 20ms CodeModel.GetById 11ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llheartbeat.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 165 lines | 97 code | 20 blank | 48 comment | 22 complexity | 8f0aa8d37e1b2bbbffd03fa18363dcaf MD5 | raw file
  1/**
  2 * @file llheartbeat.cpp
  3 * @brief Class encapsulating logic for telling a watchdog that we live.
  4 *
  5 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include <errno.h>
 28#include <signal.h>
 29
 30#include "linden_common.h"
 31#include "llapp.h"
 32
 33#include "llheartbeat.h"
 34
 35LLHeartbeat::LLHeartbeat(F32 secs_between_heartbeat,
 36			 F32 aggressive_heartbeat_panic_secs,
 37			 F32 aggressive_heartbeat_max_blocking_secs)
 38	: mSecsBetweenHeartbeat(secs_between_heartbeat),
 39	  mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs),
 40	  mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs),
 41	  mSuppressed(false)
 42{
 43	mBeatTimer.reset();
 44	mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat);
 45	mPanicTimer.reset();
 46	mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
 47}
 48
 49LLHeartbeat::~LLHeartbeat()
 50{
 51	// do nothing.
 52}
 53
 54void
 55LLHeartbeat::setSuppressed(bool is_suppressed)
 56{
 57	mSuppressed = is_suppressed;
 58}
 59
 60// returns 0 on success, -1 on permanent failure, 1 on temporary failure
 61int
 62LLHeartbeat::rawSend()
 63{
 64#if LL_WINDOWS
 65	return 0; // Pretend we succeeded.
 66#else
 67	if (mSuppressed)
 68		return 0; // Pretend we succeeded.
 69
 70	int result;
 71#ifndef LL_DARWIN
 72	union sigval dummy;
 73	result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy);
 74#else
 75	result = kill(getppid(), LL_HEARTBEAT_SIGNAL);
 76#endif
 77	if (result == 0)
 78		return 0; // success
 79
 80	int err = errno;
 81	if (err == EAGAIN)
 82		return 1; // failed to queue, try again
 83
 84	return -1; // other failure.
 85#endif
 86}
 87
 88int
 89LLHeartbeat::rawSendWithTimeout(F32 timeout_sec)
 90{
 91	int result = 0;
 92
 93	// Spin tightly until our heartbeat is digested by the watchdog
 94	// or we time-out.  We don't really want to sleep because our
 95	// wake-up time might be undesirably synchronised to a hidden
 96	// clock by the system's scheduler.
 97	mTimeoutTimer.reset();
 98	mTimeoutTimer.setTimerExpirySec(timeout_sec);
 99	do {
100		result = rawSend();
101		//llinfos << " HEARTSENDc=" << result << llendl;
102	} while (result==1 && !mTimeoutTimer.hasExpired());
103
104	return result;
105}
106
107bool
108LLHeartbeat::send(F32 timeout_sec)
109{
110	bool total_success = false;
111	int result = 1;
112
113	if (timeout_sec > 0.f) {
114		// force a spin until success or timeout
115		result = rawSendWithTimeout(timeout_sec);
116	} else {
117		if (mBeatTimer.hasExpired()) {
118			// zero-timeout; we don't care too much whether our
119			// heartbeat was digested.
120			result = rawSend();
121			//llinfos << " HEARTSENDb=" << result << llendl;
122		}
123	}
124
125	if (result == -1) {
126		// big failure.
127	} else if (result == 0) {
128		total_success = true;
129	} else {
130		// need to retry at some point
131	}
132
133	if (total_success) {
134		mBeatTimer.reset();
135		mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat);
136		// reset the time until we start panicking about lost
137		// heartbeats again.
138		mPanicTimer.reset();
139		mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
140	} else {
141		// leave mBeatTimer as expired so we'll lazily poke the
142		// watchdog again next time through.
143	}
144
145	if (mPanicTimer.hasExpired()) {
146		// It's been ages since we successfully had a heartbeat
147		// digested by the watchdog.  Sit here and spin a while
148		// in the hope that we can force it through.
149		llwarns << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds.  Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl;
150		result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs);
151		if (result == 0) {
152			total_success = true;
153		} else {
154			// we couldn't even force it through.  That's bad,
155			// but we'll try again in a while.
156			llwarns << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl;
157		}
158		
159		// in any case, reset the panic timer.
160		mPanicTimer.reset();
161		mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs);
162	}
163
164	return total_success;
165}