]> Zhao Yanbai Git Server - minix.git/commitdiff
devman: allow multiple event read calls up to EOF 61/2861/1
authorDavid van Moolenbroek <david@minix3.org>
Tue, 28 Oct 2014 13:37:42 +0000 (13:37 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 28 Oct 2014 14:43:33 +0000 (14:43 +0000)
Read calls may be repeated by VFS if the user destination memory is
not mapped in.  Devman currently assumes that all reads are
successful, and uses this to track whether EOF has been reached for
a particular event, discarding it as soon as this happens.  Upon
repetition, this may result in lost events for devmand.

With this patch, devman discards events only once devmand reads the
EOF marker, which itself can never generate a user page fault.  The
result is that read calls for data can be repeated safely, without
the risk of losing events in the process.

Change-Id: I9dfdf7f8c8992a20a10302d79c3506e61f8564b0

minix/servers/devman/device.c

index 9075257e91817a7f015329ada80ce91955c252c7..9d5ed54c4f71e1eb6a65c1489fb791af8f02453e 100644 (file)
@@ -143,13 +143,7 @@ devman_event_read(char **ptr, size_t *len,off_t offset, void *data)
 {
        struct devman_event *ev = NULL;
        struct devman_event_inode *n;
-       static int eof = 0;     
        
-       if (eof) {
-               *len=0;
-               eof = 0;
-               return 0;
-       }
        n = (struct devman_event_inode *) data;
        
        if (!TAILQ_EMPTY(&n->event_queue)) {
@@ -157,18 +151,17 @@ devman_event_read(char **ptr, size_t *len,off_t offset, void *data)
        }
 
        buf_init(offset, *len);
-       if (ev != NULL) {
+       if (ev != NULL)
                buf_printf("%s", ev->data);
-               /* read all? */
-               if (*len + offset >= strlen(ev->data)) {
-                       TAILQ_REMOVE(&n->event_queue, ev, events);
-                       free(ev);
-                       eof = 1;
-               }
-       }
 
        *len = buf_get(ptr);
-       
+
+       /* read all (EOF)? */
+       if (ev != NULL && *len == 0) {
+               TAILQ_REMOVE(&n->event_queue, ev, events);
+               free(ev);
+       }
+
        return 0;
 }