ae4861c09c5fd309f3d079f023b5f974370294f7
[idzebra-moved-to-github.git] / util / tstflock.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: tstflock.c,v 1.15 2006-07-05 12:33:38 adam Exp $
6  */
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <yaz/test.h>
11 #include <yaz/log.h>
12 #if HAVE_SYS_TIME_H
13 #include <sys/time.h>
14 #endif
15 #include <time.h>
16
17 #if HAVE_SYS_STAT_H
18 #include <sys/stat.h>
19 #endif
20 #if HAVE_SYS_TYPES_H
21 #include <sys/types.h>
22 #endif
23 #if HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #if HAVE_SYS_WAIT_H
27 #include <sys/wait.h>
28 #endif
29
30 #include <fcntl.h>
31
32 #ifdef WIN32
33 #include <io.h>
34 #endif
35
36 #if YAZ_POSIX_THREADS
37 #include <pthread.h>
38 #endif
39 #ifdef WIN32
40 #include <windows.h>
41 #include <process.h>
42 #endif
43
44 #include <idzebra/flock.h>
45 #include <string.h>
46
47 static char seq[1000];
48 static char *seqp = 0;
49
50 #define NUM_THREADS 100
51
52 #if YAZ_POSIX_THREADS
53 pthread_cond_t sleep_cond = PTHREAD_COND_INITIALIZER;
54 pthread_mutex_t sleep_mutex = PTHREAD_MUTEX_INITIALIZER;
55 #endif
56
57 int test_fd = 0;
58
59 static void small_sleep()
60 {
61 #ifdef WIN32
62     Sleep(2);
63 #else
64 #if YAZ_POSIX_THREADS
65     struct timespec abstime;
66     struct timeval now;
67
68     gettimeofday(&now, 0);
69     abstime.tv_sec = now.tv_sec;
70     abstime.tv_nsec = 1000000 + now.tv_usec * 1000;
71     if (abstime.tv_nsec > 1000000000) /* 1s = 1e9 ns */
72     {
73         abstime.tv_nsec -= 1000000000;
74         abstime.tv_sec++;
75     }
76     pthread_mutex_lock(&sleep_mutex);
77     pthread_cond_timedwait(&sleep_cond, &sleep_mutex, &abstime);
78     pthread_mutex_unlock(&sleep_mutex);
79 #endif
80 #endif
81 }
82
83 void *run_func(void *arg)
84 {
85     int i;
86     int *pdata = (int*) arg;
87     int use_write_lock = *pdata;
88     ZebraLockHandle lh = zebra_lock_create(0, "my.LCK");
89     for (i = 0; i<2; i++)
90     {
91         int write_lock = use_write_lock;
92
93         if (use_write_lock == 2) /* random lock */
94             write_lock = (rand() & 3) == 3 ? 1 : 0;
95             
96         if (write_lock)
97         {
98             zebra_lock_w(lh);
99
100             write(test_fd, "L", 1);
101             *seqp++ = 'L';
102             small_sleep();
103             *seqp++ = 'U';  
104             write(test_fd, "U", 1);
105           
106             zebra_unlock(lh);
107         }
108         else
109         {
110             zebra_lock_r(lh);
111             
112             write(test_fd, "l", 1);
113             *seqp++ = 'l';
114             small_sleep();
115             *seqp++ = 'u';
116             write(test_fd, "u", 1);
117             
118             zebra_unlock(lh);
119         }
120     }
121     zebra_lock_destroy(lh);
122     *pdata = 123;
123     return 0;
124 }
125
126 #ifdef WIN32
127 DWORD WINAPI ThreadProc(void *p)
128 {
129     run_func(p);
130     return 0;
131 }
132 #endif
133
134 static void tst_thread(int num, int write_flag)
135 {
136 #ifdef WIN32
137     HANDLE handles[NUM_THREADS];
138     DWORD dwThreadId[NUM_THREADS];
139 #endif
140 #if YAZ_POSIX_THREADS
141     pthread_t child_thread[NUM_THREADS];
142 #endif
143     int i, id[NUM_THREADS];
144
145     seqp = seq;
146     assert (num <= NUM_THREADS);
147     for (i = 0; i < num; i++)
148     {
149         id[i] = write_flag;
150 #if YAZ_POSIX_THREADS
151         pthread_create(&child_thread[i], 0 /* attr */, run_func, &id[i]);
152 #endif
153 #ifdef WIN32
154         if (1)
155         {
156             void *pData = &id[i];
157             handles[i] = CreateThread(
158                 NULL,              /* default security attributes */
159                 0,                 /* use default stack size */
160                 ThreadProc,        /* thread function */
161                 pData,             /* argument to thread function */
162                 0,                 /* use default creation flags */
163                 &dwThreadId[i]);   /* returns the thread identifier */
164         }
165
166 #endif
167     }
168 #if YAZ_POSIX_THREADS
169     for (i = 0; i<num; i++)
170         pthread_join(child_thread[i], 0);
171 #endif
172 #ifdef WIN32
173     WaitForMultipleObjects(num, handles, TRUE, INFINITE);
174 #endif
175     for (i = 0; i < num; i++)
176         YAZ_CHECK(id[i] == 123);
177     *seqp++ = '\0';
178     yaz_log(YLOG_LOG, "tst_thread(%d,%d) returns seq=%s", 
179             num, write_flag, seq);
180 }
181
182 static void tst()
183 {
184     tst_thread(4, 1); /* write locks */
185     if (1)
186     {
187         int i = 0;
188         while (seq[i])
189         {
190             YAZ_CHECK_EQ(seq[i], 'L');
191             YAZ_CHECK_EQ(seq[i+1], 'U');
192             i = i + 2;
193         }
194     }
195
196     tst_thread(6, 0);  /* read locks */
197
198     tst_thread(20, 2); /* random locks */
199 }
200
201 void fork_tst()
202 {
203 #if HAVE_SYS_WAIT_H
204     pid_t pid[2];
205     int i;
206
207     for (i = 0; i<2; i++)
208     {
209         pid[i] = fork();
210         if (!pid[i])
211         {
212             tst();
213             exit(0);
214         }
215     }
216     for (i = 0; i<2; i++)
217     {
218         int status;
219         waitpid(pid[i], &status, 0);
220         YAZ_CHECK(status == 0);
221     }
222 #else
223     tst();
224 #endif
225 }
226
227 int main(int argc, char **argv)
228 {
229     char logname[220];
230     YAZ_CHECK_INIT(argc, argv);
231
232     sprintf(logname, "%.200s.log", argv[0]);
233     yaz_log_init_file(logname);
234
235     /* log time + thread id (%!) */
236     yaz_log_time_format("%c:%!");
237
238     /* ensure the flock system logs in our test */
239     yaz_log_init_level(yaz_log_mask_str("flock"));
240
241     zebra_flock_init();
242
243     test_fd = open("tstflock.out", (O_BINARY|O_CREAT|O_RDWR), 0666);
244     YAZ_CHECK(test_fd != -1);
245     if (test_fd != -1)
246     {
247         fork_tst();
248     }
249     YAZ_CHECK_TERM;
250 }
251
252
253 /*
254  * Local variables:
255  * c-basic-offset: 4
256  * indent-tabs-mode: nil
257  * End:
258  * vim: shiftwidth=4 tabstop=8 expandtab
259  */
260