6f9625732a6c9de8e81decc6cdafcc62773f6b99
[idzebra-moved-to-github.git] / util / tstflock.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2010 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <yaz/test.h>
23 #include <yaz/log.h>
24 #if HAVE_SYS_TIME_H
25 #include <sys/time.h>
26 #endif
27 #include <time.h>
28
29 #if HAVE_SYS_STAT_H
30 #include <sys/stat.h>
31 #endif
32 #if HAVE_SYS_TYPES_H
33 #include <sys/types.h>
34 #endif
35 #if HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #if HAVE_SYS_WAIT_H
39 #include <sys/wait.h>
40 #endif
41
42 #include <fcntl.h>
43
44 #ifdef WIN32
45 #include <io.h>
46 #endif
47
48 #if YAZ_POSIX_THREADS
49 #include <pthread.h>
50 #endif
51 #ifdef WIN32
52 #include <windows.h>
53 #include <process.h>
54 #endif
55
56 #include <idzebra/flock.h>
57 #include <string.h>
58
59 static char seq[1000];
60 static char *seqp = 0;
61
62 #define NUM_THREADS 100
63
64 #if YAZ_POSIX_THREADS
65 pthread_cond_t sleep_cond = PTHREAD_COND_INITIALIZER;
66 pthread_mutex_t sleep_mutex = PTHREAD_MUTEX_INITIALIZER;
67 #endif
68
69 int test_fd = 0;
70
71 static void small_sleep(void)
72 {
73 #ifdef WIN32
74     Sleep(2);
75 #else
76 #if YAZ_POSIX_THREADS
77     struct timespec abstime;
78     struct timeval now;
79
80     gettimeofday(&now, 0);
81     abstime.tv_sec = now.tv_sec;
82     abstime.tv_nsec = 1000000 + now.tv_usec * 1000;
83     if (abstime.tv_nsec > 1000000000) /* 1s = 1e9 ns */
84     {
85         abstime.tv_nsec -= 1000000000;
86         abstime.tv_sec++;
87     }
88     pthread_mutex_lock(&sleep_mutex);
89     pthread_cond_timedwait(&sleep_cond, &sleep_mutex, &abstime);
90     pthread_mutex_unlock(&sleep_mutex);
91 #endif
92 #endif
93 }
94
95 void *run_func(void *arg)
96 {
97     int i;
98     int *pdata = (int*) arg;
99     int use_write_lock = *pdata;
100     ZebraLockHandle lh = zebra_lock_create(0, "my.LCK");
101     for (i = 0; i<2; i++)
102     {
103         int write_lock = use_write_lock;
104
105         if (use_write_lock == 2) /* random lock */
106             write_lock = (rand() & 3) == 3 ? 1 : 0;
107             
108         if (write_lock)
109         {
110             zebra_lock_w(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         else
121         {
122             zebra_lock_r(lh);
123             
124             write(test_fd, "l", 1);
125             *seqp++ = 'l';
126             small_sleep();
127             *seqp++ = 'u';
128             write(test_fd, "u", 1);
129             
130             zebra_unlock(lh);
131         }
132     }
133     zebra_lock_destroy(lh);
134     *pdata = 123;
135     return 0;
136 }
137
138 #ifdef WIN32
139 DWORD WINAPI ThreadProc(void *p)
140 {
141     run_func(p);
142     return 0;
143 }
144 #endif
145
146 static void tst_thread(int num, int write_flag)
147 {
148 #ifdef WIN32
149     HANDLE handles[NUM_THREADS];
150     DWORD dwThreadId[NUM_THREADS];
151 #endif
152 #if YAZ_POSIX_THREADS
153     pthread_t child_thread[NUM_THREADS];
154 #endif
155     int i, id[NUM_THREADS];
156
157     seqp = seq;
158     assert (num <= NUM_THREADS);
159     for (i = 0; i < num; i++)
160     {
161         id[i] = write_flag;
162 #if YAZ_POSIX_THREADS
163         pthread_create(&child_thread[i], 0 /* attr */, run_func, &id[i]);
164 #endif
165 #ifdef WIN32
166         if (1)
167         {
168             void *pData = &id[i];
169             handles[i] = CreateThread(
170                 NULL,              /* default security attributes */
171                 0,                 /* use default stack size */
172                 ThreadProc,        /* thread function */
173                 pData,             /* argument to thread function */
174                 0,                 /* use default creation flags */
175                 &dwThreadId[i]);   /* returns the thread identifier */
176         }
177
178 #endif
179     }
180 #if YAZ_POSIX_THREADS
181     for (i = 0; i<num; i++)
182         pthread_join(child_thread[i], 0);
183 #endif
184 #ifdef WIN32
185     WaitForMultipleObjects(num, handles, TRUE, INFINITE);
186 #endif
187     for (i = 0; i < num; i++)
188         YAZ_CHECK(id[i] == 123);
189     *seqp++ = '\0';
190     yaz_log(YLOG_LOG, "tst_thread(%d,%d) returns seq=%s", 
191             num, write_flag, seq);
192 }
193
194 static void tst(void)
195 {
196     tst_thread(4, 1); /* write locks */
197     if (1)
198     {
199         int i = 0;
200         while (seq[i])
201         {
202             YAZ_CHECK_EQ(seq[i], 'L');
203             YAZ_CHECK_EQ(seq[i+1], 'U');
204             i = i + 2;
205         }
206     }
207
208     tst_thread(6, 0);  /* read locks */
209
210     tst_thread(20, 2); /* random locks */
211 }
212
213 void fork_tst(void)
214 {
215 #if HAVE_SYS_WAIT_H
216     pid_t pid[2];
217     int i;
218
219     for (i = 0; i<2; i++)
220     {
221         pid[i] = fork();
222         if (!pid[i])
223         {
224             tst();
225             exit(0);
226         }
227     }
228     for (i = 0; i<2; i++)
229     {
230         int status;
231         waitpid(pid[i], &status, 0);
232         YAZ_CHECK(status == 0);
233     }
234 #else
235     tst();
236 #endif
237 }
238
239 int main(int argc, char **argv)
240 {
241     YAZ_CHECK_INIT(argc, argv);
242     YAZ_CHECK_LOG();
243
244     /* ensure the flock system logs in our test */
245     yaz_log_init_level(yaz_log_mask_str("flock"));
246
247     zebra_flock_init();
248
249     test_fd = open("tstflock.out", (O_BINARY|O_CREAT|O_RDWR), 0666);
250     YAZ_CHECK(test_fd != -1);
251     if (test_fd != -1)
252     {
253         fork_tst();
254     }
255     YAZ_CHECK_TERM;
256 }
257
258
259 /*
260  * Local variables:
261  * c-basic-offset: 4
262  * c-file-style: "Stroustrup"
263  * indent-tabs-mode: nil
264  * End:
265  * vim: shiftwidth=4 tabstop=8 expandtab
266  */
267