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