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