1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
#include "stdafx.h"
#include "OS/Thread.h"
#include "OS/ThreadGroup.h"
#include "OS/Condition.h"
#include "Tracker.h"
using namespace os;
static int var = 0;
static THREAD int local = 0;
static Semaphore stopSema(0);
static void otherThread() {
var++;
local++;
Sleep(10);
var++;
local++;
assert(local == 2);
stopSema.up();
}
BEGIN_TEST(ThreadTest, OS) {
ThreadGroup g;
var = 0;
local = 1;
{
os::Thread t = os::Thread::spawn(util::simpleVoidFn(otherThread), g);
CHECK_NEQ(t, os::Thread::current());
}
Sleep(30);
stopSema.down();
CHECK_EQ(var, 2);
{
os::Thread t = os::Thread::spawn(util::simpleVoidFn(otherThread), g);
CHECK_NEQ(t, os::Thread::current());
}
stopSema.down();
CHECK_EQ(var, 4);
CHECK_EQ(local, 1);
} END_TEST
static void setVar() {
var = 1;
stopSema.up();
}
static void uthreadInterop() {
UThread::spawn(util::simpleVoidFn(&setVar));
// Note: we're not running leave here!
}
static void setVar2() {
// Keep a reference, to confuse the runtime a bit.
os::Thread t = os::Thread::current();
UThread::leave();
var = 2;
stopSema.up();
}
static void uthreadInterop2() {
UThread::spawn(util::simpleVoidFn(&setVar2));
UThread::leave();
}
struct TInterop {
os::Future<int> result;
void run() {
result.post(42);
}
};
BEGIN_TEST(UThreadInterop, OS) {
ThreadGroup g;
var = 0;
os::Thread::spawn(util::simpleVoidFn(uthreadInterop), g);
stopSema.down();
CHECK_EQ(var, 1);
var = 0;
os::Thread::spawn(util::simpleVoidFn(uthreadInterop2), g);
stopSema.down();
CHECK_EQ(var, 2);
var = 0;
os::Thread t = os::Thread::spawn(util::Fn<void, void>(), g);
Sleep(20); // Make sure 't' enters the condition waiting.
UThread::spawn(util::simpleVoidFn(setVar), &t);
stopSema.down();
CHECK_EQ(var, 1);
// Check so that futures work with regular semaphores as well.
{
TInterop i;
os::Thread::spawn(util::memberVoidFn(&i, &TInterop::run), g);
CHECK_EQ(i.result.result(), 42);
// Multiple times should also work.
CHECK_EQ(i.result.result(), 42);
}
} END_TEST
struct Cond {
// Condition variable to use for testing.
Condition c;
// Semaphore to start the other thread.
Semaphore start;
// Semaphore to indicate an iteration is done.
Semaphore done;
// Shared variable to use for results.
nat count;
Cond() : start(0), done(0), count(0) {}
// Run the other thread.
void run() {
for (nat i = 0; i < 10; i++) {
start.down();
c.wait();
count++;
done.up();
}
}
};
BEGIN_TEST(ConditionTest, OS) {
Cond z;
ThreadGroup g;
os::Thread::spawn(util::memberVoidFn(&z, &Cond::run), g);
z.start.up();
Sleep(10); // Let the other thread run into c.wait()
z.c.signal();
z.done.down();
CHECK_EQ(z.count, 1);
z.c.signal();
z.start.up();
z.done.down();
CHECK_EQ(z.count, 2);
z.c.signal();
z.c.signal();
z.start.up();
z.done.down();
Sleep(10); // If it runs multiple times, make sure it is complete.
CHECK_EQ(z.count, 3);
// Stress test the rest of the times...
for (nat i = 4; i <= 10; i++) {
z.start.up();
z.c.signal();
z.done.down();
CHECK_EQ(z.count, i);
}
// Now z.count is 10, and the other thread will terminate eventually.
} END_TEST;
|