lib: Fixed mblock bug for epoll.
[ashd.git] / lib / mtio-epoll.c
index 511af81..af7cd27 100644 (file)
@@ -37,12 +37,13 @@ static struct blocker *blockers;
 struct blocker {
     struct blocker *n, *p, *n2, *p2;
     int fd, reg;
-    int ev;
+    int ev, rev, id;
     time_t to;
     struct muth *th;
 };
 
 static int epfd = -1, fdln = 0;
+static int exitstatus;
 static struct blocker **fdlist;
 
 static int regfd(struct blocker *bl)
@@ -125,46 +126,86 @@ static void remfd(struct blocker *bl)
            flog(LOG_ERR, "epoll_mod on fd %i: %s", bl->fd, strerror(errno));
        }
     }
+    bl->reg = 0;
 }
 
-int block(int fd, int ev, time_t to)
+static int addblock(struct blocker *bl)
 {
-    struct blocker *bl;
-    int rv;
-    
-    omalloc(bl);
-    bl->fd = fd;
-    bl->ev = ev;
-    if(to > 0)
-       bl->to = time(NULL) + to;
-    bl->th = current;
-    if((epfd >= 0) && regfd(bl)) {
-       free(bl);
+    if((epfd >= 0) && regfd(bl))
        return(-1);
-    }
     bl->n = blockers;
     if(blockers)
        blockers->p = bl;
     blockers = bl;
-    rv = yield();
+    return(0);
+}
+
+static void remblock(struct blocker *bl)
+{
     if(bl->n)
        bl->n->p = bl->p;
     if(bl->p)
        bl->p->n = bl->n;
-    if(bl == blockers)
+    if(blockers == bl)
        blockers = bl->n;
     remfd(bl);
-    free(bl);
+}
+
+struct selected mblock(time_t to, int n, struct selected *spec)
+{
+    int i, id;
+    struct blocker bls[n];
+    
+    to = (to > 0)?(time(NULL) + to):0;
+    for(i = 0; i < n; i++) {
+       bls[i] = (struct blocker) {
+           .fd = spec[i].fd,
+           .ev = spec[i].ev,
+           .id = i,
+           .to = to,
+           .th = current,
+       };
+       if(addblock(&bls[i])) {
+           for(i--; i >= 0; i--)
+               remblock(&bls[i]);
+           return((struct selected){.fd = -1, .ev = -1});
+       }
+    }
+    id = yield();
+    for(i = 0; i < n; i++)
+       remblock(&bls[i]);
+    if(id < 0)
+       return((struct selected){.fd = -1, .ev = -1});
+    return((struct selected){.fd = bls[id].fd, .ev = bls[id].rev});
+}
+
+int block(int fd, int ev, time_t to)
+{
+    struct blocker bl;
+    int rv;
+    
+    bl = (struct blocker) {
+       .fd = fd,
+       .ev = ev,
+       .id = -1,
+       .to = (to > 0)?(time(NULL) + to):0,
+       .th = current,
+    };
+    if(addblock(&bl))
+       return(-1);
+    rv = yield();
+    remblock(&bl);
     return(rv);
 }
 
-void ioloop(void)
+int ioloop(void)
 {
     struct blocker *bl, *nbl;
     struct epoll_event evr[16];
     int i, fd, nev, ev, toval;
     time_t now, timeout;
     
+    exitstatus = 0;
     epfd = epoll_create(128);
     fcntl(epfd, F_SETFD, FD_CLOEXEC);
     for(bl = blockers; bl; bl = nbl) {
@@ -185,10 +226,12 @@ void ioloop(void)
            toval = (timeout - now) * 1000;
        else
            toval = 1000;
+       if(exitstatus)
+           break;
        nev = epoll_wait(epfd, evr, sizeof(evr) / sizeof(*evr), toval);
        if(nev < 0) {
            if(errno != EINTR) {
-               flog(LOG_CRIT, "ioloop: select errored out: %s", strerror(errno));
+               flog(LOG_CRIT, "ioloop: epoll_wait errored out: %s", strerror(errno));
                /* To avoid CPU hogging in case it's bad, which it
                 * probably is. */
                sleep(1);
@@ -206,17 +249,37 @@ void ioloop(void)
                ev = -1;
            for(bl = fdlist[fd]; bl; bl = nbl) {
                nbl = bl->n2;
-               if((ev < 0) || (ev & bl->ev))
-                   resume(bl->th, ev);
+               if((ev < 0) || (ev & bl->ev)) {
+                   if(bl->id < 0) {
+                       resume(bl->th, ev);
+                   } else {
+                       bl->rev = ev;
+                       resume(bl->th, bl->id);
+                   }
+               }
            }
        }
        now = time(NULL);
        for(bl = blockers; bl; bl = nbl) {
            nbl = bl->n;
-           if((bl->to != 0) && (bl->to <= now))
-               resume(bl->th, 0);
+           if((bl->to != 0) && (bl->to <= now)) {
+               if(bl->id < 0) {
+                   resume(bl->th, 0);
+               } else {
+                   bl->rev = 0;
+                   resume(bl->th, bl->id);
+               }
+           }
        }
     }
+    for(bl = blockers; bl; bl = bl->n)
+       remfd(bl);
     close(epfd);
     epfd = -1;
+    return(exitstatus);
+}
+
+void exitioloop(int status)
+{
+    exitstatus = status;
 }