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