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)
{
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);
}
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);