-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include "../lock.h"
-#include "../thread.h"
+#include <util/threads/lock.h>
+#include <util/threads/thread.h>
#include <gtest/gtest.h>
}
// Destroying a locked mutex is a bad idea as well
-//
-// FIXME: The test is disabled, since it screws something up in the VM (other
-// tests fail then with rather cryptic messages, memory dumps and stuff).
-// Any idea how to make the test work and reasonably safe?
-TEST(MutexTest, DISABLED_destroyLocked) {
- // TODO: This probably won't work for non-debug mutexes. Disable on non-debug
- // compilation.
- Mutex* mutex = new Mutex;
- new Mutex::Locker(*mutex);
- EXPECT_THROW(delete mutex, isc::InvalidOperation);
- // Note: This leaks the locker. But this is a test for development aid
- // exception. The exception won't happen in normal build anyway and seeing
- // it means there's a bug. And we can't delete the locker now, since it
- // would access uninitialized memory.
+#ifdef EXPECT_DEATH
+TEST(MutexTest, destroyLocked) {
+ EXPECT_DEATH({
+ Mutex* mutex = new Mutex;
+ new Mutex::Locker(*mutex);
+ delete mutex;
+ // This'll leak the locker, but inside the slave process, it should
+ // not be an issue.
+ }, "");
}
+#endif
// This test tries if a mutex really locks. We could try that with a deadlock,
// but that's not practical (the test would not end).
// threads are started and the operation must be complicated enough so the
// compiler won't turn it into some kind of single atomic instruction.
//
+// FIXME: Any idea for a simpler but non-atomic operation that keeps an
+// invariant?
+//
// So, we'll have an array of numbers. Each thread will try to repeatedly
// find a number large at least as half of the average, take the number,
// distribute the value across the rest of the positions of the array and
// one will add something to the position another one have chosen and
// the other one will then zero it, not taking the new value into account.
// That'd lower the total value of the array.
+//
+// We run the threads in opposite directions (so we have no chance of them
+// keeping the same distance to each other and not meeting). Also, the indexing
+// is performed in a circular manner like with a ring buffer.
const unsigned long long length = 1000;
const unsigned long long iterations = 10000;
const unsigned long long value = 2000;
void
-performStrangeOperation(long long unsigned* array, int direction,
+performStrangeOperation(std::vector<long long unsigned> array, int direction,
Mutex* mutex)
{
unsigned long long position = 0;
for (size_t i = 0; i < iterations; i ++) {
Mutex::Locker lock(*mutex);
+ // Find a place with large enough value
while (array[position % length] < value) {
position += direction;
}
- unsigned long long value = array[position % length];
+ // Take the value
+ unsigned long long found_value = array[position % length];
+ // And distribute it to places following the found one, by
+ // adding 1 to each.
unsigned long long p2 = position;
- while (value > 0) {
+ while (found_value > 0) {
p2 += direction;
if (p2 % length == position % length) {
continue;
}
array[p2 % length] ++;
- value --;
+ found_value --;
}
+ // Zero the distributed value
array[position % length] = 0;
}
}
TEST(MutexTest, swarm) {
// This type has a low chance of being atomic itself, further raising
// the chance of problems appearing.
- long long unsigned array[length];
+ std::vector<long long unsigned> array(length);
for (size_t i = 0; i < length; ++ i) {
array[i] = value;
}
Mutex mutex;
+ // Run two parallel threads, each in one direction
Thread t1(boost::bind(&performStrangeOperation, array, 1, &mutex));
Thread t2(boost::bind(&performStrangeOperation, array, -1, &mutex));
t1.wait();
t2.wait();
+ // Check the sum didn't change.
long long unsigned sum = 0;
for (size_t i = 0; i < length; ++ i) {
sum += array[i];