All sleep calls via std::this_thread
[invirt/third/libt4.git] / lock_tester.cc
1 //
2 // Lock server tester
3 //
4
5 #include "lock_client.h"
6 #include <arpa/inet.h>
7 #include <unistd.h>
8
9 // must be >= 2
10 const int nt = 6; //XXX: lab1's rpc handlers are blocking. Since rpcs uses a thread pool of 10 threads, we cannot test more than 10 blocking rpc.
11 static lock_client *lc[nt];
12 static const char * a = "1";
13 static const char * b = "2";
14
15 // check_grant() and check_release() check that the lock server
16 // doesn't grant the same lock to both clients.
17 // it assumes that lock names are distinct in the first byte.
18 static int ct[256];
19 static std::mutex * count_mutex;
20
21 static void check_grant(lock_protocol::lockid_t lid) {
22     lock ml(*count_mutex);
23     int x = lid[0] & 0x0f;
24     if (ct[x] != 0) {
25         LOG_NONMEMBER << "error: server granted " << lid << " twice";
26         exit(1);
27     }
28     ct[x] += 1;
29 }
30
31 static void check_release(lock_protocol::lockid_t lid) {
32     lock ml(*count_mutex);
33     int x = lid[0] & 0x0f;
34     if (ct[x] != 1) {
35         LOG_NONMEMBER << "error: client released un-held lock " << lid;
36         exit(1);
37     }
38     ct[x] -= 1;
39 }
40
41 static void test1(void) {
42     LOG_NONMEMBER << "acquire a release a acquire a release a";
43     lc[0]->acquire(a);
44     check_grant(a);
45     lc[0]->release(a);
46     check_release(a);
47     lc[0]->acquire(a);
48     check_grant(a);
49     lc[0]->release(a);
50     check_release(a);
51
52     LOG_NONMEMBER << "acquire a acquire b release b release a";
53     lc[0]->acquire(a);
54     check_grant(a);
55     lc[0]->acquire(b);
56     check_grant(b);
57     lc[0]->release(b);
58     check_release(b);
59     lc[0]->release(a);
60     check_release(a);
61 }
62
63 static void test2(int i) {
64     LOG_NONMEMBER << "test2: client " << i << " acquire a release a";
65     lc[i]->acquire(a);
66     LOG_NONMEMBER << "test2: client " << i << " acquire done";
67     check_grant(a);
68     std::this_thread::sleep_for(milliseconds(100));
69     LOG_NONMEMBER << "test2: client " << i << " release";
70     check_release(a);
71     lc[i]->release(a);
72     LOG_NONMEMBER << "test2: client " << i << " release done";
73 }
74
75 static void test3(int i) {
76     LOG_NONMEMBER << "test3: client " << i << " acquire a release a concurrent";
77     for (int j = 0; j < 10; j++) {
78         lc[i]->acquire(a);
79         check_grant(a);
80         LOG_NONMEMBER << "test3: client " << i << " got lock";
81         check_release(a);
82         lc[i]->release(a);
83     }
84 }
85
86 static void test4(int i) {
87     LOG_NONMEMBER << "test4: thread " << i << " acquire a release a concurrent; same clnt";
88     for (int j = 0; j < 10; j++) {
89         lc[0]->acquire(a);
90         check_grant(a);
91         LOG_NONMEMBER << "test4: thread " << i << " on client 0 got lock";
92         check_release(a);
93         lc[0]->release(a);
94     }
95 }
96
97 static void test5(int i) {
98     LOG_NONMEMBER << "test5: client " << i << " acquire a release a concurrent; same and diff clnt";
99     for (int j = 0; j < 10; j++) {
100         if (i < 5)  lc[0]->acquire(a);
101         else  lc[1]->acquire(a);
102         check_grant(a);
103         LOG_NONMEMBER << "test5: client " << i << " got lock";
104         check_release(a);
105         if (i < 5) lc[0]->release(a);
106         else lc[1]->release(a);
107     }
108 }
109
110 int
111 main(int argc, char *argv[])
112 {
113     global = new t4_state('c');
114     count_mutex = new std::mutex();
115
116     thread th[nt];
117     int test = 0;
118
119     setvbuf(stdout, NULL, _IONBF, 0);
120     setvbuf(stderr, NULL, _IONBF, 0);
121
122     if (argc < 2) {
123         LOG_NONMEMBER << "Usage: " << argv[0] << " [host:]port [test]";
124         exit(1);
125     }
126
127     string dst = argv[1]; 
128
129     if (argc > 2) {
130         test = atoi(argv[2]);
131         if (test < 1 || test > 5) {
132             LOG_NONMEMBER << "Test number must be between 1 and 5";
133             exit(1);
134         }
135     }
136
137     LOG_NONMEMBER << "cache lock client";
138     for (int i = 0; i < nt; i++) lc[i] = new lock_client(dst);
139
140     if (!test || test == 1) {
141         test1();
142     }
143
144     if (!test || test == 2) {
145         // test2
146         for (int i = 0; i < nt; i++)
147             th[i] = thread(test2, i);
148         for (int i = 0; i < nt; i++)
149             th[i].join();
150     }
151
152     if (!test || test == 3) {
153         LOG_NONMEMBER << "test 3";
154
155         for (int i = 0; i < nt; i++)
156             th[i] = thread(test3, i);
157         for (int i = 0; i < nt; i++)
158             th[i].join();
159     }
160
161     if (!test || test == 4) {
162         LOG_NONMEMBER << "test 4";
163
164         for (int i = 0; i < 2; i++)
165             th[i] = thread(test4, i);
166         for (int i = 0; i < 2; i++)
167             th[i].join();
168     }
169
170     if (!test || test == 5) {
171         LOG_NONMEMBER << "test 5";
172
173         for (int i = 0; i < nt; i++)
174             th[i] = thread(test5, i);
175         for (int i = 0; i < nt; i++)
176             th[i].join();
177     }
178
179     LOG_NONMEMBER << argv[0] << ": passed all tests successfully";
180
181     for (int i = 0; i < nt; i++)
182         delete lc[i];
183 }