Merge branch 'expression-parser'
[fio.git] / filelock.c
1 /*
2  * Really simple exclusive file locking based on filename.
3  * No hash indexing, just a list, so only works well for < 100 files or
4  * so. But that's more than what fio needs, so should be fine.
5  */
6 #include <inttypes.h>
7 #include <string.h>
8 #include <assert.h>
9
10 #include "flist.h"
11 #include "filelock.h"
12 #include "smalloc.h"
13 #include "mutex.h"
14 #include "hash.h"
15 #include "log.h"
16
17 struct fio_filelock {
18         uint32_t hash;
19         struct fio_mutex lock;
20         struct flist_head list;
21         unsigned int references;
22 };
23         
24 static struct flist_head *filelock_list;
25 static struct fio_mutex *filelock_lock;
26
27 int fio_filelock_init(void)
28 {
29         filelock_list = smalloc(sizeof(*filelock_list));
30         if (!filelock_list)
31                 return 1;
32
33         INIT_FLIST_HEAD(filelock_list);
34         filelock_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
35         if (!filelock_lock) {
36                 sfree(filelock_list);
37                 return 1;
38         }
39
40         return 0;
41 }
42
43 void fio_filelock_exit(void)
44 {
45         if (!filelock_list)
46                 return;
47
48         assert(flist_empty(filelock_list));
49         sfree(filelock_list);
50         filelock_list = NULL;
51         fio_mutex_remove(filelock_lock);
52         filelock_lock = NULL;
53 }
54
55 static struct fio_filelock *fio_hash_find(uint32_t hash)
56 {
57         struct flist_head *entry;
58         struct fio_filelock *ff;
59
60         flist_for_each(entry, filelock_list) {
61                 ff = flist_entry(entry, struct fio_filelock, list);
62                 if (ff->hash == hash)
63                         return ff;
64         }
65
66         return NULL;
67 }
68
69 static struct fio_filelock *fio_hash_get(uint32_t hash)
70 {
71         struct fio_filelock *ff;
72
73         ff = fio_hash_find(hash);
74         if (!ff) {
75                 ff = smalloc(sizeof(*ff));
76                 ff->hash = hash;
77                 __fio_mutex_init(&ff->lock, FIO_MUTEX_UNLOCKED);
78                 ff->references = 0;
79                 flist_add(&ff->list, filelock_list);
80         }
81
82         return ff;
83 }
84
85 int fio_trylock_file(const char *fname)
86 {
87         struct fio_filelock *ff;
88         uint32_t hash;
89
90         hash = jhash(fname, strlen(fname), 0);
91
92         fio_mutex_down(filelock_lock);
93         ff = fio_hash_get(hash);
94         ff->references++;
95         fio_mutex_up(filelock_lock);
96
97         if (!fio_mutex_down_trylock(&ff->lock))
98                 return 0;
99
100         fio_mutex_down(filelock_lock);
101
102         /*
103          * If we raced and the only reference to the lock is us, we can
104          * grab it
105          */
106         if (ff->references != 1) {
107                 ff->references--;
108                 ff = NULL;
109         }
110
111         fio_mutex_up(filelock_lock);
112
113         if (ff) {
114                 fio_mutex_down(&ff->lock);
115                 return 0;
116         }
117
118         return 1;
119 }
120
121 void fio_lock_file(const char *fname)
122 {
123         struct fio_filelock *ff;
124         uint32_t hash;
125
126         hash = jhash(fname, strlen(fname), 0);
127
128         fio_mutex_down(filelock_lock);
129         ff = fio_hash_get(hash);
130         ff->references++;
131         fio_mutex_up(filelock_lock);
132
133         fio_mutex_down(&ff->lock);
134 }
135
136 void fio_unlock_file(const char *fname)
137 {
138         struct fio_filelock *ff;
139         uint32_t hash;
140
141         hash = jhash(fname, strlen(fname), 0);
142
143         fio_mutex_down(filelock_lock);
144
145         ff = fio_hash_find(hash);
146         if (ff) {
147                 ff->references--;
148                 fio_mutex_up(&ff->lock);
149                 if (!ff->references) {
150                         flist_del(&ff->list);
151                         sfree(ff);
152                 }
153         } else
154                 log_err("fio: file not found for unlocking\n");
155
156         fio_mutex_up(filelock_lock);
157 }