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.
14 * fsel.c - FUSE fsel: FUSE select example
16 * \section section_compile compiling this example
18 * gcc -Wall fsel.c `pkg-config fuse3 --cflags --libs` -o fsel
20 * \section section_source the complete source
25 #define FUSE_USE_VERSION 30
41 * fsel_open_mask is used to limit the number of opens to 1 per file.
42 * This is to use file index (0-F) as fh as poll support requires
43 * unique fh per open file. Lifting this would require proper open
46 static unsigned fsel_open_mask
;
47 static const char fsel_hex_map
[] = "0123456789ABCDEF";
48 static struct fuse
*fsel_fuse
; /* needed for poll notification */
50 #define FSEL_CNT_MAX 10 /* each file can store upto 10 chars */
53 static pthread_mutex_t fsel_mutex
; /* protects notify_mask and cnt array */
54 static unsigned fsel_poll_notify_mask
; /* poll notification scheduled? */
55 static struct fuse_pollhandle
*fsel_poll_handle
[FSEL_FILES
]; /* poll notify handles */
56 static unsigned fsel_cnt
[FSEL_FILES
]; /* nbytes stored in each file */
58 static int fsel_path_index(const char *path
)
62 if (strlen(path
) != 2 || path
[0] != '/' || !isxdigit(ch
) || islower(ch
))
64 return ch
<= '9' ? ch
- '0' : ch
- 'A' + 10;
67 static int fsel_getattr(const char *path
, struct stat
*stbuf
)
71 memset(stbuf
, 0, sizeof(struct stat
));
73 if (strcmp(path
, "/") == 0) {
74 stbuf
->st_mode
= S_IFDIR
| 0555;
79 idx
= fsel_path_index(path
);
83 stbuf
->st_mode
= S_IFREG
| 0444;
85 stbuf
->st_size
= fsel_cnt
[idx
];
89 static int fsel_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
90 off_t offset
, struct fuse_file_info
*fi
)
98 if (strcmp(path
, "/") != 0)
101 for (i
= 0; i
< FSEL_FILES
; i
++) {
102 name
[0] = fsel_hex_map
[i
];
103 filler(buf
, name
, NULL
, 0);
109 static int fsel_open(const char *path
, struct fuse_file_info
*fi
)
111 int idx
= fsel_path_index(path
);
115 if ((fi
->flags
& 3) != O_RDONLY
)
117 if (fsel_open_mask
& (1 << idx
))
119 fsel_open_mask
|= (1 << idx
);
122 * fsel files are nonseekable somewhat pipe-like files which
123 * gets filled up periodically by producer thread and consumed
124 * on read. Tell FUSE as such.
133 static int fsel_release(const char *path
, struct fuse_file_info
*fi
)
139 fsel_open_mask
&= ~(1 << idx
);
143 static int fsel_read(const char *path
, char *buf
, size_t size
, off_t offset
,
144 struct fuse_file_info
*fi
)
151 pthread_mutex_lock(&fsel_mutex
);
152 if (fsel_cnt
[idx
] < size
)
153 size
= fsel_cnt
[idx
];
154 printf("READ %X transferred=%zu cnt=%u\n", idx
, size
, fsel_cnt
[idx
]);
155 fsel_cnt
[idx
] -= size
;
156 pthread_mutex_unlock(&fsel_mutex
);
158 memset(buf
, fsel_hex_map
[idx
], size
);
162 static int fsel_poll(const char *path
, struct fuse_file_info
*fi
,
163 struct fuse_pollhandle
*ph
, unsigned *reventsp
)
165 static unsigned polled_zero
;
171 * Poll notification requires pointer to struct fuse which
172 * can't be obtained when using fuse_main(). As notification
173 * happens only after poll is called, fill it here from
177 struct fuse_context
*cxt
= fuse_get_context();
179 fsel_fuse
= cxt
->fuse
;
182 pthread_mutex_lock(&fsel_mutex
);
185 struct fuse_pollhandle
*oldph
= fsel_poll_handle
[idx
];
188 fuse_pollhandle_destroy(oldph
);
190 fsel_poll_notify_mask
|= (1 << idx
);
191 fsel_poll_handle
[idx
] = ph
;
196 printf("POLL %X cnt=%u polled_zero=%u\n",
197 idx
, fsel_cnt
[idx
], polled_zero
);
202 pthread_mutex_unlock(&fsel_mutex
);
206 static struct fuse_operations fsel_oper
= {
207 .getattr
= fsel_getattr
,
208 .readdir
= fsel_readdir
,
210 .release
= fsel_release
,
215 static void *fsel_producer(void *data
)
217 const struct timespec interval
= { 0, 250000000 };
218 unsigned idx
= 0, nr
= 1;
225 pthread_mutex_lock(&fsel_mutex
);
228 * This is the main producer loop which is executed
229 * ever 500ms. On each iteration, it fills one byte
230 * to 1, 2 or 4 files and sends poll notification if
233 for (i
= 0, t
= idx
; i
< nr
;
234 i
++, t
= (t
+ FSEL_FILES
/ nr
) % FSEL_FILES
) {
235 if (fsel_cnt
[t
] == FSEL_CNT_MAX
)
239 if (fsel_fuse
&& (fsel_poll_notify_mask
& (1 << t
))) {
240 struct fuse_pollhandle
*ph
;
242 printf("NOTIFY %X\n", t
);
243 ph
= fsel_poll_handle
[t
];
244 fuse_notify_poll(ph
);
245 fuse_pollhandle_destroy(ph
);
246 fsel_poll_notify_mask
&= ~(1 << t
);
247 fsel_poll_handle
[t
] = NULL
;
251 idx
= (idx
+ 1) % FSEL_FILES
;
253 nr
= (nr
* 2) % 7; /* cycle through 1, 2 and 4 */
255 pthread_mutex_unlock(&fsel_mutex
);
257 nanosleep(&interval
, NULL
);
263 int main(int argc
, char *argv
[])
269 errno
= pthread_mutex_init(&fsel_mutex
, NULL
);
271 perror("pthread_mutex_init");
275 errno
= pthread_attr_init(&attr
);
277 perror("pthread_attr_init");
281 errno
= pthread_create(&producer
, &attr
, fsel_producer
, NULL
);
283 perror("pthread_create");
287 ret
= fuse_main(argc
, argv
, &fsel_oper
, NULL
);
289 pthread_cancel(producer
);
290 pthread_join(producer
, NULL
);