IDZEBRA  2.2.7
flock.c
Go to the documentation of this file.
1 /* ThiĀ½ file is part of the Zebra server.
2  Copyright (C) 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 
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #ifdef WIN32
31 #include <io.h>
32 #include <sys/locking.h>
33 #endif
34 #if HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 
38 #include <idzebra/flock.h>
39 #include <zebra-lock.h>
40 #include <yaz/xmalloc.h>
41 #include <yaz/log.h>
42 
44 static int initialized = 0;
45 
47 static int posix_locks = 1;
48 
51 
53 static struct zebra_lock_info *lock_list = 0;
54 
57 #ifndef WIN32
60 #endif
61  struct zebra_lock_info *p;
62 };
63 
66  int fd;
68  char *fname;
70  int ref_count;
71 #ifndef WIN32
77 #endif
80 };
81 
82 static int log_level = 0;
83 
84 char *zebra_mk_fname(const char *dir, const char *name)
85 {
86  int dlen = dir ? strlen(dir) : 0;
87  char *fname = xmalloc(dlen + strlen(name) + 2);
88 
89  *fname = '\0';
90  if (dlen)
91  {
92  int last_one = dir[dlen-1];
93  strcat(fname, dir);
94 #ifdef WIN32
95  if (!strchr("/\\:", last_one))
96  strcat(fname, "\\");
97 #else
98  if (!strchr("/", last_one))
99  strcat(fname, "/");
100 #endif
101  }
102  strcat(fname, name);
103  return fname;
104 }
105 
106 ZebraLockHandle zebra_lock_create(const char *dir, const char *name)
107 {
108  char *fname = zebra_mk_fname(dir, name);
109  struct zebra_lock_info *p = 0;
110  ZebraLockHandle h = 0;
111 
112  assert(initialized);
113 
115  /* see if we have the same filename in a global list of "lock files" */
116 #ifndef WIN32
117  if (posix_locks)
118  {
119  for (p = lock_list; p ; p = p->next)
120  if (!strcmp(p->fname, fname))
121  break;
122  }
123 #endif
124  if (!p)
125  { /* didn't match (or we didn't want it to match! */
126  p = (struct zebra_lock_info *) xmalloc(sizeof(*p));
127 
128  p->ref_count = 0;
129 #ifdef WIN32
130  p->fd = open(name, O_BINARY|O_RDONLY);
131  if (p->fd == -1)
132  p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
133 #else
134  p->fd = open(fname, (O_BINARY|O_CREAT|O_RDWR), 0666);
135 #endif
136  if (p->fd == -1)
137  {
138  xfree(p);
139  yaz_log(YLOG_WARN | YLOG_ERRNO,
140  "zebra_lock_create fail fname=%s", fname);
141  p = 0;
142  }
143  else
144  {
145  p->fname = fname;
146  fname = 0; /* fname buffer now owned by p->fname */
147 #ifndef WIN32
148  if (posix_locks)
150 
152  p->no_file_write_lock = 0;
153  p->no_file_read_lock = 0;
154 #endif
155  p->next = lock_list;
156  lock_list = p;
157  }
158  }
159  if (p)
160  {
161  /* we have lock info so we can make a handle pointing to that */
162  p->ref_count++;
163  h = (ZebraLockHandle) xmalloc(sizeof(*h));
164  h->p = p;
165 #ifndef WIN32
166  h->write_flag = 0;
167 #endif
168  yaz_log(log_level, "zebra_lock_create fd=%d p=%p fname=%s",
169  h->p->fd, h, p->fname);
170  }
172  xfree(fname); /* free it - if it's still there */
173 
174  return h;
175 }
176 
178 {
179  if (!h)
180  return;
181  yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s",
182  h->p->fd, h, h->p->fname);
184  yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s refcount=%d",
185  h->p->fd, h, h->p->fname, h->p->ref_count);
186  assert(h->p->ref_count > 0);
187  --(h->p->ref_count);
188  if (h->p->ref_count == 0)
189  {
190  /* must remove shared info from lock_list */
191  struct zebra_lock_info **hp = &lock_list;
192  while (*hp)
193  {
194  if (*hp == h->p)
195  {
196  *hp = h->p->next;
197  break;
198  }
199  else
200  hp = &(*hp)->next;
201  }
202 
203  yaz_log(log_level, "zebra_lock_destroy fd=%d p=%p fname=%s remove",
204  h->p->fd, h, h->p->fname);
205 
206 #ifndef WIN32
207  if (posix_locks)
210 #endif
211  if (h->p->fd != -1)
212  close(h->p->fd);
213  xfree(h->p->fname);
214  xfree(h->p);
215  }
216  xfree(h);
218 }
219 
220 #ifndef WIN32
221 static int unixLock(int fd, int type, int cmd)
222 {
223  struct flock area;
224  int r;
225  area.l_type = type;
226  area.l_whence = SEEK_SET;
227  area.l_len = area.l_start = 0L;
228 
229  yaz_log(log_level, "fcntl begin type=%d fd=%d", type, fd);
230  r = fcntl(fd, cmd, &area);
231  if (r == -1)
232  yaz_log(YLOG_WARN|YLOG_ERRNO, "fcntl FAIL type=%d fd=%d", type, fd);
233  else
234  yaz_log(log_level, "fcntl type=%d OK fd=%d", type, fd);
235 
236  return r;
237 }
238 #endif
239 
241 {
242  int r = 0;
243  int do_lock = 0;
244  yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s begin",
245  h->p->fd, h, h->p->fname);
246 
247 #ifdef WIN32
248  while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
249  ;
250 #else
251  if (posix_locks)
253 
255  if (h->p->no_file_write_lock == 0)
256  do_lock = 1;
257  h->p->no_file_write_lock++;
258  if (do_lock)
259  {
260  /* if there is already a read lock.. upgrade to write lock */
261  r = unixLock(h->p->fd, F_WRLCK, F_SETLKW);
262  }
263  else
264  {
265  assert(posix_locks);
266  }
268 
269  h->write_flag = 1;
270 #endif
271  yaz_log(log_level, "zebra_lock_w fd=%d p=%p fname=%s end",
272  h->p->fd, h, h->p->fname);
273 
274  return r;
275 }
276 
278 {
279  int r = 0;
280  int do_lock = 0;
281 
282  yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s begin",
283  h->p->fd, h, h->p->fname);
284 #ifdef WIN32
285  while ((r = _locking(h->p->fd, _LK_LOCK, 1)))
286  ;
287 #else
288  if (posix_locks)
290 
292  if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
293  do_lock = 1;
294  h->p->no_file_read_lock++;
295  if (do_lock)
296  {
297  /* only read lock if no write locks already */
298  r = unixLock(h->p->fd, F_RDLCK, F_SETLKW);
299  }
300  else
301  {
302  assert(posix_locks);
303  }
305 
306  h->write_flag = 0;
307 #endif
308  yaz_log(log_level, "zebra_lock_r fd=%d p=%p fname=%s end",
309  h->p->fd, h, h->p->fname);
310  return r;
311 }
312 
314 {
315  int r = 0;
316  yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s begin",
317  h->p->fd, h, h->p->fname);
318 #ifdef WIN32
319  r = _locking(h->p->fd, _LK_UNLCK, 1);
320 #else
322  if (h->write_flag)
323  {
324  if (h->p->no_file_write_lock > 0)
325  h->p->no_file_write_lock--;
326  }
327  else
328  {
329  if (h->p->no_file_read_lock > 0)
330  h->p->no_file_read_lock--;
331  }
332  if (h->p->no_file_read_lock == 0 && h->p->no_file_write_lock == 0)
333  r = unixLock(h->p->fd, F_UNLCK, F_SETLKW);
334  else
335  {
336  r = 0;
337  assert(posix_locks);
338  }
339 
341 
342  if (posix_locks)
343  {
344  if (h->write_flag)
346  else
348  }
349 #endif
350  yaz_log(log_level, "zebra_unlock fd=%d p=%p fname=%s end",
351  h->p->fd, h, h->p->fname);
352  return r;
353 }
354 
360 static int check_for_linuxthreads(void)
361 {
362 #if __linux
363 #ifdef _CS_GNU_LIBPTHREAD_VERSION
364  char conf_buf[512];
365  size_t r = confstr(_CS_GNU_LIBPTHREAD_VERSION, conf_buf, sizeof(conf_buf));
366  if (r == 0)
367  {
368  yaz_log(YLOG_WARN|YLOG_ERRNO, "confstr failed");
369  return -1;
370  }
371  if (strncmp(conf_buf, "linuxthreads", 12) == 0)
372  posix_locks = 0; /* Using linuxthreads.. */
373 #else
374  posix_locks = 0; /* Old GLIBC on Linux. Assume linuxthreads */
375 #endif
376 #endif
377  return 0;
378 }
379 
381 {
382  if (!initialized)
383  {
384  initialized = 1;
385  log_level = yaz_log_module_level("flock");
386  yaz_log(log_level, "zebra_flock_init");
389  yaz_log(log_level, "posix_locks: %d", posix_locks);
390  }
391 }
392 
393 /*
394  * Local variables:
395  * c-basic-offset: 4
396  * c-file-style: "Stroustrup"
397  * indent-tabs-mode: nil
398  * End:
399  * vim: shiftwidth=4 tabstop=8 expandtab
400  */
401 
#define O_BINARY
Definition: agrep.c:46
static int unixLock(int fd, int type, int cmd)
Definition: flock.c:221
Zebra_mutex lock_list_mutex
Definition: flock.c:50
static struct zebra_lock_info * lock_list
Definition: flock.c:53
int zebra_lock_r(ZebraLockHandle h)
Definition: flock.c:277
int zebra_lock_w(ZebraLockHandle h)
Definition: flock.c:240
static int check_for_linuxthreads(void)
see if the fcntl locking is not POSIX
Definition: flock.c:360
void zebra_lock_destroy(ZebraLockHandle h)
Definition: flock.c:177
ZebraLockHandle zebra_lock_create(const char *dir, const char *name)
Definition: flock.c:106
void zebra_flock_init()
Definition: flock.c:380
static int log_level
Definition: flock.c:82
char * zebra_mk_fname(const char *dir, const char *name)
Definition: flock.c:84
static int initialized
Definition: flock.c:44
int zebra_unlock(ZebraLockHandle h)
Definition: flock.c:313
static int posix_locks
Definition: flock.c:47
struct zebra_lock_handle * ZebraLockHandle
Definition: flock.h:27
struct zebra_lock_info * p
Definition: flock.c:61
int write_flag
Definition: flock.c:59
char * fname
Definition: flock.c:68
int ref_count
Definition: flock.c:70
int no_file_read_lock
Definition: flock.c:74
Zebra_mutex file_mutex
Definition: flock.c:76
int no_file_write_lock
Definition: flock.c:73
Zebra_lock_rdwr rdwr_lock
Definition: flock.c:75
struct zebra_lock_info * next
Definition: flock.c:79
int fd
Definition: tstlockscope.c:38
int zebra_mutex_unlock(Zebra_mutex *p)
Definition: zebra-lock.c:74
int zebra_mutex_init(Zebra_mutex *p)
Definition: zebra-lock.c:31
int zebra_lock_rdwr_rlock(Zebra_lock_rdwr *p)
Definition: zebra-lock.c:111
int zebra_lock_rdwr_wlock(Zebra_lock_rdwr *p)
Definition: zebra-lock.c:123
int zebra_lock_rdwr_destroy(Zebra_lock_rdwr *p)
Definition: zebra-lock.c:100
int zebra_lock_rdwr_wunlock(Zebra_lock_rdwr *p)
Definition: zebra-lock.c:155
int zebra_lock_rdwr_runlock(Zebra_lock_rdwr *p)
Definition: zebra-lock.c:135
int zebra_mutex_lock(Zebra_mutex *p)
Definition: zebra-lock.c:59
int zebra_lock_rdwr_init(Zebra_lock_rdwr *p)
Definition: zebra-lock.c:89
int zebra_mutex_destroy(Zebra_mutex *p)
Definition: zebra-lock.c:43