Merge branch 'master' into timeheap
authorFredrik Tolf <fredrik@dolda2000.com>
Sat, 31 Dec 2016 17:53:33 +0000 (18:53 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Sat, 31 Dec 2016 18:24:30 +0000 (19:24 +0100)
Conflicts:
lib/mtio-epoll.c

1  2 
lib/mtio-epoll.c

diff --combined lib/mtio-epoll.c
@@@ -37,21 -37,14 +37,21 @@@ static struct blocker *blockers
  struct blocker {
      struct blocker *n, *p, *n2, *p2;
      int fd, reg;
-     int ev;
+     int ev, rev, id;
 +    int thpos;
      time_t to;
      struct muth *th;
  };
  
 +struct timeentry {
 +    time_t to;
 +    struct blocker *bl;
 +};
 +
  static int epfd = -1, fdln = 0;
  static int exitstatus;
  static struct blocker **fdlist;
 +static typedbuf(struct timeentry) timeheap;
  
  static int regfd(struct blocker *bl)
  {
@@@ -136,95 -129,72 +136,135 @@@ static void remfd(struct blocker *bl
      bl->reg = 0;
  }
  
- int block(int fd, int ev, time_t to)
 +static void thraise(struct timeentry ent, int n)
 +{
 +    int p;
 +    
 +    while(n > 0) {
 +      p = (n - 1) >> 1;
 +      if(timeheap.b[p].to <= ent.to)
 +          break;
 +      timeheap.b[n] = timeheap.b[p];
 +      timeheap.b[n].bl->thpos = n;
 +      n = p;
 +    }
 +    timeheap.b[n] = ent;
 +    ent.bl->thpos = n;
 +}
 +
 +static void thlower(struct timeentry ent, int n)
 +{
 +    int c;
 +    
 +    while(1) {
 +      c = (n << 1) + 1;
 +      if(c >= timeheap.d)
 +          break;
 +      if((c + 1 < timeheap.d) && (timeheap.b[c + 1].to < timeheap.b[c].to))
 +          c = c + 1;
 +      if(timeheap.b[c].to > ent.to)
 +          break;
 +      timeheap.b[n] = timeheap.b[c];
 +      timeheap.b[n].bl->thpos = n;
 +      n = c;
 +    }
 +    timeheap.b[n] = ent;
 +    ent.bl->thpos = n;
 +}
 +
 +static void addtimeout(struct blocker *bl, time_t to)
 +{
 +    sizebuf(timeheap, ++timeheap.d);
 +    thraise((struct timeentry){.to = to, .bl = bl}, timeheap.d - 1);
 +}
 +
 +static void deltimeout(struct blocker *bl)
 +{
 +    struct timeentry ent;
 +    int n;
 +    
 +    if(bl->thpos == timeheap.d - 1) {
 +      timeheap.d--;
 +      return;
 +    }
 +    n = bl->thpos;
 +    ent = timeheap.b[--timeheap.d];
 +    if((n > 0) && (timeheap.b[(n - 1) >> 1].to > ent.to))
 +      thraise(ent, n);
 +    else
 +      thlower(ent, n);
 +}
 +
+ static int addblock(struct blocker *bl)
  {
-     struct blocker *bl;
-     int rv;
-     
-     omalloc(bl);
-     bl->fd = fd;
-     bl->ev = ev;
-     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;
-     if(to > 0)
-       addtimeout(bl, bl->to = (time(NULL) + to));
-     rv = yield();
++    if(bl->to > 0)
++      addtimeout(bl, bl->to);
+     return(0);
+ }
+ static void remblock(struct blocker *bl)
+ {
 +    if(bl->to > 0)
 +      deltimeout(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);
  }
  
@@@ -233,23 -203,27 +273,23 @@@ int ioloop(void
      struct blocker *bl, *nbl;
      struct epoll_event evr[16];
      int i, fd, nev, ev, toval;
 -    time_t now, timeout;
 +    time_t now;
      
      exitstatus = 0;
      epfd = epoll_create(128);
      fcntl(epfd, F_SETFD, FD_CLOEXEC);
 +    bufinit(timeheap);
      for(bl = blockers; bl; bl = nbl) {
        nbl = bl->n;
        if(regfd(bl))
            resume(bl->th, -1);
      }
      while(blockers != NULL) {
 -      timeout = 0;
 -      for(bl = blockers; bl; bl = bl->n) {
 -          if((bl->to != 0) && ((timeout == 0) || (timeout > bl->to)))
 -              timeout = bl->to;
 -      }
        now = time(NULL);
 -      if(timeout == 0)
 +      if(timeheap.d == 0)
            toval = -1;
 -      else if(timeout > now)
 -          toval = (timeout - now) * 1000;
 +      else if(timeheap.b[0].to > now)
 +          toval = (timeheap.b[0].to - now) * 1000;
        else
            toval = 1000;
        if(exitstatus)
                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);
-       while((timeheap.d > 0) && (timeheap.b[0].to <= now))
-           resume(timeheap.b[0].bl->th, 0);
 -      for(bl = blockers; bl; bl = nbl) {
 -          nbl = bl->n;
 -          if((bl->to != 0) && (bl->to <= now)) {
 -              if(bl->id < 0) {
 -                  resume(bl->th, 0);
 -              } else {
 -                  bl->rev = 0;
 -                  resume(bl->th, bl->id);
 -              }
++      while((timeheap.d > 0) && (timeheap.b[0].to <= now)) {
++          if(bl->id < 0) {
++              resume(timeheap.b[0].bl->th, 0);
++          } else {
++              bl->rev = 0;
++              resume(bl->th, bl->id);
+           }
+       }
      }
      for(bl = blockers; bl; bl = bl->n)
        remfd(bl);
 +    buffree(timeheap);
      close(epfd);
      epfd = -1;
      return(exitstatus);