diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp
index 2f48d13c2d1dcff8dc30592441d08e7ffc2f19df..3d3f738c060dd0ad845abc4ee09c47566e81d89d 100644
--- a/indra/llcommon/lldeadmantimer.cpp
+++ b/indra/llcommon/lldeadmantimer.cpp
@@ -29,8 +29,21 @@
 #include "lldeadmantimer.h"
 
 
+// *TODO:  Currently, this uses lltimer functions for its time
+// aspects and this leaks into the apis in the U64s/F64s.  Would
+// like to perhaps switch this over to TSC register-based timers
+// sometime and drop the overhead some more.
+
+
+//  Flag states and their meaning:
+//  mActive  mDone   Meaning
+//   false   false   Nothing running, no result available
+//    true   false   Timer running, no result available
+//   false    true   Timer finished, result can be read once
+//    true    true   Not allowed
+//
 LLDeadmanTimer::LLDeadmanTimer(F64 horizon)
-	: mHorizon(U64(horizon * gClockFrequency)),
+	: mHorizon(U64(llmax(horizon, F64(0.0)) * gClockFrequency)),
 	  mActive(false),			// If true, a timer is running.
 	  mDone(false),				// If true, timer has completed and can be read (once)
 	  mStarted(U64L(0)),
@@ -78,19 +91,14 @@ void LLDeadmanTimer::stop(U64 now)
 
 bool LLDeadmanTimer::isExpired(F64 & started, F64 & stopped, U64 & count, U64 now)
 {
-	if (! mActive)
-	{
-		return false;
-	}
-	
-	if (! mDone)
+	if (mActive && ! mDone)
 	{
 		if (! now)
 		{
 			now = LLTimer::getCurrentClockCount();
 		}
 
-		if (now > mExpires)
+		if (now >= mExpires)
 		{
 			// mStopped from ringBell() is the value we want
 			mActive = false;
@@ -124,7 +132,7 @@ void LLDeadmanTimer::ringBell(U64 now)
 		now = LLTimer::getCurrentClockCount();
 	}
 
-	if (now > mExpires)
+	if (now >= mExpires)
 	{
 		mActive = false;
 		mDone = true;
diff --git a/indra/llcommon/tests/lldeadmantimer_test.cpp b/indra/llcommon/tests/lldeadmantimer_test.cpp
index 52a27b9c0a1f487b25b5b5f212fbe55ce8e11f84..571d43825fd1896b97f0d653b5597f266bd3ae23 100644
--- a/indra/llcommon/tests/lldeadmantimer_test.cpp
+++ b/indra/llcommon/tests/lldeadmantimer_test.cpp
@@ -31,6 +31,20 @@
 
 #include "../test/lltut.h"
 
+// Convert between floating point time deltas and U64 time deltas.
+// Reflects an implementation detail inside lldeadmantimer.cpp
+
+static U64 float_time_to_u64(F64 delta)
+{
+	return U64(delta * gClockFrequency);
+}
+
+static F64 u64_time_to_float(U64 delta)
+{
+	return delta * gClockFrequencyInv;
+}
+
+
 namespace tut
 {
 
@@ -47,17 +61,254 @@ typedef test_group<deadmantimer_test> deadmantimer_group_t;
 typedef deadmantimer_group_t::object deadmantimer_object_t;
 tut::deadmantimer_group_t deadmantimer_instance("LLDeadmanTimer");
 
+// Basic construction test and isExpired() call
 template<> template<>
 void deadmantimer_object_t::test<1>()
 {
 	F64 started(42.0), stopped(97.0);
 	U64 count(U64L(8));
-	LLDeadmanTimer timer(1.0);
+	LLDeadmanTimer timer(10.0);
 
 	ensure_equals("isExpired() returns false after ctor()", timer.isExpired(started, stopped, count), false);
-	ensure_approximately_equals("isExpired() does not modify started", started, F64(42.0), 2);
-	ensure_approximately_equals("isExpired() does not modify stopped", stopped, F64(97.0), 2);
-	ensure_equals("isExpired() does not modified count", count, U64L(8));
+	ensure_approximately_equals("t1 - isExpired() does not modify started", started, F64(42.0), 2);
+	ensure_approximately_equals("t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+	ensure_equals("t1 - isExpired() does not modify count", count, U64L(8));
+}
+
+
+// Construct with negative horizon - not useful generally but will be useful in testing
+template<> template<>
+void deadmantimer_object_t::test<2>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(0.0);			// Zero is pre-expired
+
+	ensure_equals("isExpired() still returns false with 0.0 time ctor()", timer.isExpired(started, stopped, count), false);
+}
+
+
+// "pre-expired" timer - starting a timer with a 0.0 horizon will result in
+// expiration on first test.
+template<> template<>
+void deadmantimer_object_t::test<3>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(0.0);
+
+	timer.start();
+	ensure_equals("isExpired() returns true with 0.0 horizon time", timer.isExpired(started, stopped, count), true);
+	ensure_approximately_equals("expired timer with no bell ringing has stopped == started", started, stopped, 8);
+}
+
+
+// "pre-expired" timer - bell rings are ignored as we're already expired.
+template<> template<>
+void deadmantimer_object_t::test<4>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(0.0);
+	
+	timer.start();
+	timer.ringBell(LLTimer::getCurrentClockCount() + float_time_to_u64(1000.0));
+	ensure_equals("isExpired() returns true with 0.0 horizon time after bell ring", timer.isExpired(started, stopped, count), true);
+	ensure_approximately_equals("ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8);
+}
+
+
+// start() test - unexpired timer reports unexpired
+template<> template<>
+void deadmantimer_object_t::test<5>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(10.0);
+	
+	timer.start();
+	ensure_equals("isExpired() returns false after starting with 10.0 horizon time", timer.isExpired(started, stopped, count), false);
+	ensure_approximately_equals("t5 - isExpired() does not modify started", started, F64(42.0), 2);
+	ensure_approximately_equals("t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+	ensure_equals("t5 - isExpired() does not modify count", count, U64L(8));
 }
 
+
+// start() test - start in the past but not beyond 1 horizon
+template<> template<>
+void deadmantimer_object_t::test<6>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(10.0);
+
+	U64 the_past(LLTimer::getCurrentClockCount() - float_time_to_u64(5.0));
+	timer.start(the_past);
+	ensure_equals("isExpired() returns false with 10.0 horizon time starting 5.0 in past", timer.isExpired(started, stopped, count), false);
+	ensure_approximately_equals("t6 - isExpired() does not modify started", started, F64(42.0), 2);
+	ensure_approximately_equals("t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2);
+	ensure_equals("t6 - isExpired() does not modify count", count, U64L(8));
+}
+
+
+// start() test - start in the past but well beyond 1 horizon
+template<> template<>
+void deadmantimer_object_t::test<7>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(10.0);
+
+	U64 the_past(LLTimer::getCurrentClockCount() - float_time_to_u64(20.0));
+	timer.start(the_past);
+	ensure_equals("isExpired() returns true with 10.0 horizon time starting 20.0 in past", timer.isExpired(started, stopped, count), true);
+	ensure_approximately_equals("starting before horizon still gives equal started / stopped", started, stopped, 8);
+}
+
+
+// isExpired() test - results are read-once.  Probes after first true are false.
+template<> template<>
+void deadmantimer_object_t::test<8>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(10.0);
+
+	U64 the_past(LLTimer::getCurrentClockCount() - float_time_to_u64(20.0));
+	timer.start(the_past);
+	ensure_equals("t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", timer.isExpired(started, stopped, count), true);
+
+	started = 42.0;
+	stopped = 97.0;
+	count = U64L(8);
+	ensure_equals("t8 - second isExpired() returns false after true", timer.isExpired(started, stopped, count), false);
+	ensure_approximately_equals("t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2);
+	ensure_approximately_equals("t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2);
+	ensure_equals("t8 - 2nd isExpired() does not modify count", count, U64L(8));
+}
+
+
+// ringBell() test - see that we can keep a timer from expiring
+template<> template<>
+void deadmantimer_object_t::test<9>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(5.0);
+
+	U64 now(LLTimer::getCurrentClockCount());
+	F64 real_start(u64_time_to_float(now));
+	timer.start();
+
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	ensure_equals("t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", timer.isExpired(started, stopped, count, now), false);
+	F64 last_good_ring(u64_time_to_float(now));
+
+	// Jump forward and expire
+	now += float_time_to_u64(10.0);
+	ensure_equals("t9 - 5.0 horizon timer expires on 10-second jump", timer.isExpired(started, stopped, count, now), true);
+	ensure_approximately_equals("t9 - started matches start() time", started, real_start, 4);
+	ensure_approximately_equals("t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4);
+	ensure_equals("t9 - 10 good ringBell()s", count, U64L(10));
+	ensure_equals("t9 - single read only", timer.isExpired(started, stopped, count, now), false);
+}
+
+
+// restart after expiration test - verify that restarts behave well
+template<> template<>
+void deadmantimer_object_t::test<10>()
+{
+	F64 started(42.0), stopped(97.0);
+	U64 count(U64L(8));
+	LLDeadmanTimer timer(5.0);
+
+	U64 now(LLTimer::getCurrentClockCount());
+	F64 real_start(u64_time_to_float(now));
+	timer.start();
+
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	ensure_equals("t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", timer.isExpired(started, stopped, count, now), false);
+	F64 last_good_ring(u64_time_to_float(now));
+
+	// Jump forward and expire
+	now += float_time_to_u64(10.0);
+	ensure_equals("t10 - 5.0 horizon timer expires on 10-second jump", timer.isExpired(started, stopped, count, now), true);
+	ensure_approximately_equals("t10 - started matches start() time", started, real_start, 4);
+	ensure_approximately_equals("t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4);
+	ensure_equals("t10 - 10 good ringBell()s", count, U64L(10));
+	ensure_equals("t10 - single read only", timer.isExpired(started, stopped, count, now), false);
+
+	// Jump forward and restart
+	now += float_time_to_u64(1.0);
+	real_start = u64_time_to_float(now);
+	timer.start(now);
+
+	// Run a modified bell ring sequence
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	now += float_time_to_u64(1.0);
+	timer.ringBell(now);
+	ensure_equals("t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", timer.isExpired(started, stopped, count, now), false);
+	last_good_ring = u64_time_to_float(now);
+
+	// Jump forward and expire
+	now += float_time_to_u64(10.0);
+	ensure_equals("t10 - 5.0 horizon timer expires on 8-second jump", timer.isExpired(started, stopped, count, now), true);
+	ensure_approximately_equals("t10 - 2nd started matches start() time", started, real_start, 4);
+	ensure_approximately_equals("t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4);
+	ensure_equals("t10 - 8 good ringBell()s", count, U64L(8));
+	ensure_equals("t10 - single read only - 2nd start", timer.isExpired(started, stopped, count, now), false);
+}
+
+
 } // end namespace tut