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