"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.1/example/poll.c" (14 Nov 2017, 6447 Bytes) of package /linux/misc/fuse-3.2.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "poll.c": 3.0.2_vs_3.1.0.

    1 /*
    2   FUSE fsel: FUSE select example
    3   Copyright (C) 2008       SUSE Linux Products GmbH
    4   Copyright (C) 2008       Tejun Heo <teheo@suse.de>
    5 
    6   This program can be distributed under the terms of the GNU GPL.
    7   See the file COPYING.
    8 */
    9 
   10 /** @file
   11  *
   12  * This example illustrates how to write a FUSE file system that
   13  * supports polling for changes that don't come through the kernel. It
   14  * can be tested with the poll_client.c program.
   15  *
   16  * Compile with:
   17  *
   18  *     gcc -Wall poll.c `pkg-config fuse3 --cflags --libs` -o poll
   19  *
   20  * ## Source code ##
   21  * \include poll.c
   22  */
   23 
   24 #define FUSE_USE_VERSION 31
   25 
   26 #include <config.h>
   27 
   28 #include <fuse.h>
   29 #include <unistd.h>
   30 #include <ctype.h>
   31 #include <string.h>
   32 #include <stdio.h>
   33 #include <stdlib.h>
   34 #include <errno.h>
   35 #include <time.h>
   36 #include <pthread.h>
   37 #include <poll.h>
   38 
   39 /*
   40  * fsel_open_mask is used to limit the number of opens to 1 per file.
   41  * This is to use file index (0-F) as fh as poll support requires
   42  * unique fh per open file.  Lifting this would require proper open
   43  * file management.
   44  */
   45 static unsigned fsel_open_mask;
   46 static const char fsel_hex_map[] = "0123456789ABCDEF";
   47 static struct fuse *fsel_fuse;  /* needed for poll notification */
   48 
   49 #define FSEL_CNT_MAX    10  /* each file can store upto 10 chars */
   50 #define FSEL_FILES  16
   51 
   52 static pthread_mutex_t fsel_mutex;  /* protects notify_mask and cnt array */
   53 static unsigned fsel_poll_notify_mask;  /* poll notification scheduled? */
   54 static struct fuse_pollhandle *fsel_poll_handle[FSEL_FILES]; /* poll notify handles */
   55 static unsigned fsel_cnt[FSEL_FILES];   /* nbytes stored in each file */
   56 
   57 static int fsel_path_index(const char *path)
   58 {
   59     char ch = path[1];
   60 
   61     if (strlen(path) != 2 || path[0] != '/' || !isxdigit(ch) || islower(ch))
   62         return -1;
   63     return ch <= '9' ? ch - '0' : ch - 'A' + 10;
   64 }
   65 
   66 static int fsel_getattr(const char *path, struct stat *stbuf,
   67             struct fuse_file_info *fi)
   68 {
   69     (void) fi;
   70     int idx;
   71 
   72     memset(stbuf, 0, sizeof(struct stat));
   73 
   74     if (strcmp(path, "/") == 0) {
   75         stbuf->st_mode = S_IFDIR | 0555;
   76         stbuf->st_nlink = 2;
   77         return 0;
   78     }
   79 
   80     idx = fsel_path_index(path);
   81     if (idx < 0)
   82         return -ENOENT;
   83 
   84     stbuf->st_mode = S_IFREG | 0444;
   85     stbuf->st_nlink = 1;
   86     stbuf->st_size = fsel_cnt[idx];
   87     return 0;
   88 }
   89 
   90 static int fsel_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
   91             off_t offset, struct fuse_file_info *fi,
   92             enum fuse_readdir_flags flags)
   93 {
   94     char name[2] = { };
   95     int i;
   96 
   97     (void) offset;
   98     (void) fi;
   99     (void) flags;
  100 
  101     if (strcmp(path, "/") != 0)
  102         return -ENOENT;
  103 
  104     for (i = 0; i < FSEL_FILES; i++) {
  105         name[0] = fsel_hex_map[i];
  106         filler(buf, name, NULL, 0, 0);
  107     }
  108 
  109     return 0;
  110 }
  111 
  112 static int fsel_open(const char *path, struct fuse_file_info *fi)
  113 {
  114     int idx = fsel_path_index(path);
  115 
  116     if (idx < 0)
  117         return -ENOENT;
  118     if ((fi->flags & 3) != O_RDONLY)
  119         return -EACCES;
  120     if (fsel_open_mask & (1 << idx))
  121         return -EBUSY;
  122     fsel_open_mask |= (1 << idx);
  123 
  124     /*
  125      * fsel files are nonseekable somewhat pipe-like files which
  126      * gets filled up periodically by producer thread and consumed
  127      * on read.  Tell FUSE as such.
  128      */
  129     fi->fh = idx;
  130     fi->direct_io = 1;
  131     fi->nonseekable = 1;
  132 
  133     return 0;
  134 }
  135 
  136 static int fsel_release(const char *path, struct fuse_file_info *fi)
  137 {
  138     int idx = fi->fh;
  139 
  140     (void) path;
  141 
  142     fsel_open_mask &= ~(1 << idx);
  143     return 0;
  144 }
  145 
  146 static int fsel_read(const char *path, char *buf, size_t size, off_t offset,
  147              struct fuse_file_info *fi)
  148 {
  149     int idx = fi->fh;
  150 
  151     (void) path;
  152     (void) offset;
  153 
  154     pthread_mutex_lock(&fsel_mutex);
  155     if (fsel_cnt[idx] < size)
  156         size = fsel_cnt[idx];
  157     printf("READ   %X transferred=%zu cnt=%u\n", idx, size, fsel_cnt[idx]);
  158     fsel_cnt[idx] -= size;
  159     pthread_mutex_unlock(&fsel_mutex);
  160 
  161     memset(buf, fsel_hex_map[idx], size);
  162     return size;
  163 }
  164 
  165 static int fsel_poll(const char *path, struct fuse_file_info *fi,
  166              struct fuse_pollhandle *ph, unsigned *reventsp)
  167 {
  168     static unsigned polled_zero;
  169     int idx = fi->fh;
  170 
  171     (void) path;
  172 
  173     /*
  174      * Poll notification requires pointer to struct fuse which
  175      * can't be obtained when using fuse_main().  As notification
  176      * happens only after poll is called, fill it here from
  177      * fuse_context.
  178      */
  179     if (!fsel_fuse) {
  180         struct fuse_context *cxt = fuse_get_context();
  181         if (cxt)
  182             fsel_fuse = cxt->fuse;
  183     }
  184 
  185     pthread_mutex_lock(&fsel_mutex);
  186 
  187     if (ph != NULL) {
  188         struct fuse_pollhandle *oldph = fsel_poll_handle[idx];
  189 
  190         if (oldph)
  191             fuse_pollhandle_destroy(oldph);
  192 
  193         fsel_poll_notify_mask |= (1 << idx);
  194         fsel_poll_handle[idx] = ph;
  195     }
  196 
  197     if (fsel_cnt[idx]) {
  198         *reventsp |= POLLIN;
  199         printf("POLL   %X cnt=%u polled_zero=%u\n",
  200                idx, fsel_cnt[idx], polled_zero);
  201         polled_zero = 0;
  202     } else
  203         polled_zero++;
  204 
  205     pthread_mutex_unlock(&fsel_mutex);
  206     return 0;
  207 }
  208 
  209 static struct fuse_operations fsel_oper = {
  210     .getattr    = fsel_getattr,
  211     .readdir    = fsel_readdir,
  212     .open       = fsel_open,
  213     .release    = fsel_release,
  214     .read       = fsel_read,
  215     .poll       = fsel_poll,
  216 };
  217 
  218 static void *fsel_producer(void *data)
  219 {
  220     const struct timespec interval = { 0, 250000000 };
  221     unsigned idx = 0, nr = 1;
  222 
  223     (void) data;
  224 
  225     while (1) {
  226         int i, t;
  227 
  228         pthread_mutex_lock(&fsel_mutex);
  229 
  230         /*
  231          * This is the main producer loop which is executed
  232          * ever 500ms.  On each iteration, it fills one byte
  233          * to 1, 2 or 4 files and sends poll notification if
  234          * requested.
  235          */
  236         for (i = 0, t = idx; i < nr;
  237              i++, t = (t + FSEL_FILES / nr) % FSEL_FILES) {
  238             if (fsel_cnt[t] == FSEL_CNT_MAX)
  239                 continue;
  240 
  241             fsel_cnt[t]++;
  242             if (fsel_fuse && (fsel_poll_notify_mask & (1 << t))) {
  243                 struct fuse_pollhandle *ph;
  244 
  245                 printf("NOTIFY %X\n", t);
  246                 ph = fsel_poll_handle[t];
  247                 fuse_notify_poll(ph);
  248                 fuse_pollhandle_destroy(ph);
  249                 fsel_poll_notify_mask &= ~(1 << t);
  250                 fsel_poll_handle[t] = NULL;
  251             }
  252         }
  253 
  254         idx = (idx + 1) % FSEL_FILES;
  255         if (idx == 0)
  256             nr = (nr * 2) % 7;  /* cycle through 1, 2 and 4 */
  257 
  258         pthread_mutex_unlock(&fsel_mutex);
  259 
  260         nanosleep(&interval, NULL);
  261     }
  262 
  263     return NULL;
  264 }
  265 
  266 int main(int argc, char *argv[])
  267 {
  268     pthread_t producer;
  269     pthread_attr_t attr;
  270     int ret;
  271 
  272     errno = pthread_mutex_init(&fsel_mutex, NULL);
  273     if (errno) {
  274         perror("pthread_mutex_init");
  275         return 1;
  276     }
  277 
  278     errno = pthread_attr_init(&attr);
  279     if (errno) {
  280         perror("pthread_attr_init");
  281         return 1;
  282     }
  283 
  284     errno = pthread_create(&producer, &attr, fsel_producer, NULL);
  285     if (errno) {
  286         perror("pthread_create");
  287         return 1;
  288     }
  289 
  290     ret = fuse_main(argc, argv, &fsel_oper, NULL);
  291 
  292     pthread_cancel(producer);
  293     pthread_join(producer, NULL);
  294 
  295     return ret;
  296 }