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