2 FUSE fsel: FUSE select example
3 Copyright (C) 2008 SUSE Linux Products GmbH
4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
6 This program can be distributed under the terms of the GNU GPL.
9 gcc -Wall fsel.c `pkg-config fuse --cflags --libs` -o fsel
12 #define FUSE_USE_VERSION 29
26 * fsel_open_mask is used to limit the number of opens to 1 per file.
27 * This is to use file index (0-F) as fh as poll support requires
28 * unique fh per open file. Lifting this would require proper open
31 static unsigned fsel_open_mask;
32 static const char fsel_hex_map[] = "0123456789ABCDEF";
33 static struct fuse *fsel_fuse; /* needed for poll notification */
35 #define FSEL_CNT_MAX 10 /* each file can store upto 10 chars */
38 static pthread_mutex_t fsel_mutex; /* protects notify_mask and cnt array */
39 static unsigned fsel_poll_notify_mask; /* poll notification scheduled? */
40 static struct fuse_pollhandle *fsel_poll_handle[FSEL_FILES]; /* poll notify handles */
41 static unsigned fsel_cnt[FSEL_FILES]; /* nbytes stored in each file */
43 static int fsel_path_index(const char *path)
47 if (strlen(path) != 2 || path[0] != '/' || !isxdigit(ch) || islower(ch))
49 return ch <= '9' ? ch - '0' : ch - 'A' + 10;
52 static int fsel_getattr(const char *path, struct stat *stbuf)
56 memset(stbuf, 0, sizeof(struct stat));
58 if (strcmp(path, "/") == 0) {
59 stbuf->st_mode = S_IFDIR | 0555;
64 idx = fsel_path_index(path);
68 stbuf->st_mode = S_IFREG | 0444;
70 stbuf->st_size = fsel_cnt[idx];
74 static int fsel_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
75 off_t offset, struct fuse_file_info *fi)
83 if (strcmp(path, "/") != 0)
86 for (i = 0; i < FSEL_FILES; i++) {
87 name[0] = fsel_hex_map[i];
88 filler(buf, name, NULL, 0);
94 static int fsel_open(const char *path, struct fuse_file_info *fi)
96 int idx = fsel_path_index(path);
100 if ((fi->flags & 3) != O_RDONLY)
102 if (fsel_open_mask & (1 << idx))
104 fsel_open_mask |= (1 << idx);
107 * fsel files are nonseekable somewhat pipe-like files which
108 * gets filled up periodically by producer thread and consumed
109 * on read. Tell FUSE as such.
118 static int fsel_release(const char *path, struct fuse_file_info *fi)
124 fsel_open_mask &= ~(1 << idx);
128 static int fsel_read(const char *path, char *buf, size_t size, off_t offset,
129 struct fuse_file_info *fi)
136 pthread_mutex_lock(&fsel_mutex);
137 if (fsel_cnt[idx] < size)
138 size = fsel_cnt[idx];
139 printf("READ %X transferred=%zu cnt=%u\n", idx, size, fsel_cnt[idx]);
140 fsel_cnt[idx] -= size;
141 pthread_mutex_unlock(&fsel_mutex);
143 memset(buf, fsel_hex_map[idx], size);
147 static int fsel_poll(const char *path, struct fuse_file_info *fi,
148 struct fuse_pollhandle *ph, unsigned *reventsp)
150 static unsigned polled_zero;
156 * Poll notification requires pointer to struct fuse which
157 * can't be obtained when using fuse_main(). As notification
158 * happens only after poll is called, fill it here from
162 struct fuse_context *cxt = fuse_get_context();
164 fsel_fuse = cxt->fuse;
167 pthread_mutex_lock(&fsel_mutex);
170 struct fuse_pollhandle *oldph = fsel_poll_handle[idx];
173 fuse_pollhandle_destroy(oldph);
175 fsel_poll_notify_mask |= (1 << idx);
176 fsel_poll_handle[idx] = ph;
181 printf("POLL %X cnt=%u polled_zero=%u\n",
182 idx, fsel_cnt[idx], polled_zero);
187 pthread_mutex_unlock(&fsel_mutex);
191 static struct fuse_operations fsel_oper = {
192 .getattr = fsel_getattr,
193 .readdir = fsel_readdir,
195 .release = fsel_release,
200 static void *fsel_producer(void *data)
202 const struct timespec interval = { 0, 250000000 };
203 unsigned idx = 0, nr = 1;
210 pthread_mutex_lock(&fsel_mutex);
213 * This is the main producer loop which is executed
214 * ever 500ms. On each iteration, it fills one byte
215 * to 1, 2 or 4 files and sends poll notification if
218 for (i = 0, t = idx; i < nr;
219 i++, t = (t + FSEL_FILES / nr) % FSEL_FILES) {
220 if (fsel_cnt[t] == FSEL_CNT_MAX)
224 if (fsel_fuse && (fsel_poll_notify_mask & (1 << t))) {
225 struct fuse_pollhandle *ph;
227 printf("NOTIFY %X\n", t);
228 ph = fsel_poll_handle[t];
229 fuse_notify_poll(ph);
230 fuse_pollhandle_destroy(ph);
231 fsel_poll_notify_mask &= ~(1 << t);
232 fsel_poll_handle[t] = NULL;
236 idx = (idx + 1) % FSEL_FILES;
238 nr = (nr * 2) % 7; /* cycle through 1, 2 and 4 */
240 pthread_mutex_unlock(&fsel_mutex);
242 nanosleep(&interval, NULL);
248 int main(int argc, char *argv[])
254 errno = pthread_mutex_init(&fsel_mutex, NULL);
256 perror("pthread_mutex_init");
260 errno = pthread_attr_init(&attr);
262 perror("pthread_attr_init");
266 errno = pthread_create(&producer, &attr, fsel_producer, NULL);
268 perror("pthread_create");
272 ret = fuse_main(argc, argv, &fsel_oper, NULL);
274 pthread_cancel(producer);
275 pthread_join(producer, NULL);