Reorg projects a bit, created new ODBC extension project.
[shibboleth/cpp-sp.git] / shib / shibthreadswin32test / shibthreadswin32test.cpp
1 // shibthreadswin32test.cpp : by Aaron Wohl xshib@awohl.com.
2 //
3
4 #ifdef RUBBISH
5 CondWait broadcast is not implemented on win32. The semantics are different for
6 broadcast like events on win32.  If waking multiple waiters is needed then
7 need to think about it.
8    
9 CondWait lock realease/wake up/lock get are not atomic on win32.  I dont think
10 that matters the way its used.  On wake up CondWait waits for the condition event or timeout.  After wake up it locks the mutex again.  Its not guarenteed that the one process that was signaled is the one that gets the lock next.
11 #endif
12
13 #include "stdafx.h"
14 #include "shib-threads.h"
15 #include "windows.h"
16 #include <list>
17 #include <iostream>
18
19 using namespace shibboleth;
20 using namespace std;
21
22 #define ASSERT(xxx) \
23 do { \
24 if(!(xxx)) { \
25         fprintf(stderr,"assert failed " #xxx); \
26         do_exit(1); \
27 } \
28 }while (0)
29
30 static volatile int basic_loop_count;
31 #define NUM_BASIC_LOOP (100)
32
33 static do_exit(int rc)
34 {
35   char ch;
36   cout << "press a key to exit" << endl;
37   cout << "exit code is " << rc << " (0 is good)" << endl;
38   cin >> ch;
39   exit(rc);
40 }
41
42 static void *basic_loop_thread(void *x)
43 {
44   for(int i=0;i<NUM_BASIC_LOOP;i++)
45     basic_loop_count++;
46   return 0;
47 }
48
49 static void test_basic_loop(void)
50 {
51   Thread *athr=Thread::create(&basic_loop_thread,0);
52   ASSERT(athr!=0);
53   void *return_val;
54   athr->join(&return_val);
55   ASSERT(basic_loop_count==NUM_BASIC_LOOP);
56 }
57
58 static RWLock *arwlock;
59
60 static int roll(int n)
61 {
62   return rand() % n;
63 }
64
65 static int shared_count;
66 #define NUM_READERS (3)
67 static volatile bool in_readern[NUM_READERS];
68
69 static void check_shared(void)
70 {
71   int share_count=0;
72   for(int i=0;i<NUM_READERS;i++)
73     if(in_readern[i])
74       share_count++;
75   ASSERT(share_count>0);
76   ASSERT(share_count<=NUM_READERS);
77   if(share_count>1)
78     shared_count++;
79 }
80
81 static int num_keys_disposed;
82
83 static void key_test_fcn(void *x)
84 {
85   num_keys_disposed++;
86 }
87
88 static void *lock_reader(void *x)
89 {
90   int locker_num=int(x);
91   ThreadKey *akey=ThreadKey::create(key_test_fcn);
92   ASSERT(akey!=0);
93   akey->setData(x);
94   for(int i=0;i<NUM_BASIC_LOOP;i++) {
95     ASSERT(arwlock->rdlock()==0);
96     in_readern[locker_num]=true;
97     Sleep(roll(500));
98     // make sure the thread local storage really is thread local
99     // if its not some other reader will trash it
100     ASSERT(akey->getData()==x);
101     check_shared();
102     in_readern[locker_num]=false;
103     ASSERT(arwlock->unlock()==0);
104     Sleep(roll(500));
105   }
106   delete akey;
107   return 0;
108 }
109
110 static void *lock_writer(void *y)
111 {
112  for(int i=0;i<NUM_BASIC_LOOP;i++) {
113   ASSERT(arwlock->wrlock()==0);
114   Sleep(roll(500));
115   ASSERT(arwlock->unlock()==0);
116   Sleep(roll(500));
117   }
118  return 0;
119 }
120
121 static void test_rwlock()
122 {
123  arwlock=RWLock::create();
124  {
125   bool cant_unlock_an_unlocked_lock=(arwlock->unlock()!=0);
126   ASSERT(cant_unlock_an_unlocked_lock);
127  }
128  list<Thread*> tl;
129  for(int i=0;i<NUM_READERS;i++) {
130    Thread *athr=Thread::create(&lock_reader,(void *)i);
131    tl.push_back(athr);
132    ASSERT(athr!=0);
133    Thread *athw=Thread::create(&lock_writer,0);
134    ASSERT(athw!=0);
135    tl.push_back(athw);
136  }
137  while(!tl.empty()) {
138     Thread *some_thread=tl.front();
139     void *return_val;
140     some_thread->join(&return_val);
141     tl.pop_front();
142  }
143  delete arwlock;
144  ASSERT(num_keys_disposed==NUM_READERS);
145 }
146
147 static void *empty_thread(void *x)
148 {
149   return 0;
150 }
151
152 static void test_detach(void)
153 {
154   Thread *ath=Thread::create(empty_thread,0);
155   ASSERT(ath->detach()==0);
156   // cant detch or join after already detach
157   ASSERT(ath->detach()!=0);
158   void *return_val;
159   ASSERT(ath->join(&return_val)!=0);
160   ASSERT(ath->detach()!=0);
161   delete ath;
162 }
163
164 static int in_kill_proc;
165
166 static void *kill_me(void *x)
167 {
168   while(1) {
169     in_kill_proc++;
170     Sleep(5);
171   }
172   return 0;
173 }
174
175 static void test_kill(void)
176 {
177   Thread *ath=Thread::create(kill_me,0);
178   while(in_kill_proc<3)
179     Sleep(5);
180
181   ASSERT(ath->kill(23)==0);
182   delete ath;
183 }
184
185 static void test_detach_kill(void)
186 {
187   test_detach();
188   test_kill();
189 }
190
191 static void test_cond_timeout(void)
192 {
193   Mutex *m=Mutex::create();
194   ASSERT(m!=0);
195   CondWait *cw=CondWait::create();  
196   ASSERT(cw!=0);
197   ASSERT(m->lock()==0);
198   time_t start_time=time(0L);
199 #define DELAY_TIME (7)
200   ASSERT(cw->timedwait(m,DELAY_TIME)==0);
201   int slept_for=time(0L)-start_time;
202   ASSERT(m->unlock()==0);
203   delete cw;
204   delete m;
205   int delta_time=abs(DELAY_TIME-slept_for);
206   if(delta_time>2)
207     do_exit(1);
208   cout << "CondWait: timed test ok" << endl;
209 }
210
211
212 static int cond_counter;
213 static CondWait *cond_wait;
214
215 static void *cond_incrementer(void *x)
216 {
217   Mutex *cm=(Mutex *)(x);
218   for(int i=0;i<NUM_BASIC_LOOP;i++) {
219     ASSERT(cm->lock()==0);
220     cond_counter++;
221     if(cond_counter==(NUM_BASIC_LOOP+NUM_BASIC_LOOP/2))
222       ASSERT(cond_wait->signal()==0);
223     ASSERT(cm->lock()==0);
224   }
225   return 0;
226 }
227
228 static void test_cond_signal(void)
229 {
230   Mutex *cm=Mutex::create();
231   ASSERT(cm!=0);
232   ASSERT(cm->lock()==0);
233   cond_wait=CondWait::create();
234   list<Thread*> tl;
235   for(int i=0;i<2;i++) {
236     Thread *athr=Thread::create(&cond_incrementer,(void *)cm);
237     tl.push_back(athr);
238     ASSERT(athr!=0);
239   }
240   ASSERT(cond_wait->wait(cm)==0);
241   ASSERT(cm->unlock()==0);
242   while(!tl.empty()) {
243     Thread *some_thread=tl.front();
244     void *return_val;
245     some_thread->join(&return_val);
246     tl.pop_front();
247   }
248   delete cond_wait;
249   delete cm;
250   cout << "CondWait: signal test ok" << endl;
251 }
252
253 static void test_cond_wait(void)
254 {
255   test_cond_timeout();
256   test_cond_signal();
257 }
258
259 static void protected_run_tests(void)
260 {
261   test_cond_wait();
262   test_detach_kill();
263   test_basic_loop();
264   test_rwlock();
265 }
266
267 static void run_tests(void)
268 {
269         try {
270                 protected_run_tests();
271         } catch (char *s) {
272                 cout << "caught error" << s << endl;
273                 do_exit(1);
274         } catch (...) {
275                 cout << "caught unknown error" << endl;
276                 do_exit(1);
277         }
278
279 }
280
281 int main(int argc, char* argv[])
282 {
283   cout << "testing shib-threads, will take like 5min, look for an ok at the end\n";
284   run_tests();
285   cout << "tests done\n";
286   cout << "readers shared " << shared_count << " times (0 shares is bad)" << endl;
287   if(shared_count<1)
288     do_exit(1);
289   do_exit(0);
290   return 0;
291 }
292