Adds some fairness to altsems and fixes a bug. Reference: /n/patches.lsub.org/patch/fairaltsems Date: Sun Jul 15 13:53:07 CES 2012 Signed-off-by: esoriano@lsub.org --- /sys/src/nix/port/syssem.c Thu Jul 5 11:00:28 2012 +++ /sys/src/nix/port/syssem.c Thu Jul 12 16:07:21 2012 @@ -280,10 +280,11 @@ semwakeup(s); } - +static int nextindex; /* * Alt makes its best efford to get a token from any sem in the array. * It ignores the dead sems and only crashes if all sems are dead. + * Nextstart is used to prevent starvation. */ static int semalt(Ksem *ss[], int n) @@ -292,10 +293,13 @@ Ksem *s; RWlock *rwl; int queued; + ulong from; if(n < 1) error(Ebadarg); + from = (ulong)semainc(&nextindex) % n; + /* * While searching an available sem, the proc * should not be awaken in a previously processed sem. @@ -306,11 +310,11 @@ up->waitsem = nil; up->semawaken = 0; queued = 0; - + for(i = 0; i < n; i++){ - s = ss[i]; + s = ss[(from+i)%n]; /* - * if the sem is dead, ignore it an keep searching + * if the sem is dead, ignore it and keep searching */ if(waserror()) continue; @@ -321,7 +325,6 @@ poperror(); up->waitsem = s; up->semawaken = 1; - i++; wunlock(rwl); goto Done; } @@ -352,11 +355,17 @@ /* * We are probably being killed. */ - for(i = 0; i < n; i++){ + for(i = 0; i < n; i++){ s = ss[i]; lock(s); - if(semdequeueme(s) != 0) - panic("semalt: the proc is not in the queue"); + /* + * up->waitsem was nil, but there can be dead sems, + * so semdequeueme could return -1. + */ + if(semdequeueme(s) < 0){ + unlock(s); + continue; + } unlock(s); if(! waserror()){ _userlock(s); @@ -372,7 +381,7 @@ Done: DBG("semalt up %#p awaken\n", up); r = -1; - for(j = 0; j < i; j++){ + for(j = 0; j < n; j++){ s = ss[j]; if(s == up->waitsem) r = j; @@ -380,7 +389,8 @@ /* * Cancel the reservation for the sem. * Note that the sem could be already - * dequeued by semwakeup. + * dequeued by semwakeup or never + * queued in this sem. */ lock(s); if(semdequeueme(s) == 0){ @@ -496,18 +506,23 @@ altsems(Ksem *ss[], int n) { int i, w; + ulong p; + + p = (ulong) ainc(&nextindex); + i = 0; /* busy wait */ for(w = 0; w < Semtrytimes; w++){ for(i = 0; i < n; i++) - if(ss[i]->sem->tickets > 0) + if(ss[(p+i)%n]->sem->tickets > 0) break; if(i < n) break; } + p = (p+i)%n; for(i = 0; i < n; i++) - if(downsem(ss[i], 0) == 1) - return i; + if(downsem(ss[(p+i)%n], 0) == 1) + return (p+i)%n; return semalt(ss, n); } --- /sys/src/libc/9sys/upsem.c Wed Jul 4 11:43:12 2012 +++ /sys/src/libc/9sys/upsem.c Thu Jul 12 11:04:09 2012 @@ -101,31 +101,37 @@ return 1; } -/* - * No optimistic for now. - */ +static int nextindex; + int altsems(Sem *ss[], int n) { - int w, i, j; + int w, i; + ulong p; - i = 0; if(ss == nil || n <= 0){ werrstr("altsems: bad args"); return -1; } + + i = 0; + p = (ulong) ainc(&nextindex); + /* busy wait */ for(w = 0; w < semtrytimes; w++){ for(i = 0; i < n; i++) - if(ss[i]->tickets > 0) + if(ss[(p+i)%n]->tickets > 0) break; if(i < n) break; } - for(j = 0; j < n; j++) - if(downsem(ss[(i+j)%n], 0) == 1){ + + p = (p+i)%n; + + for(i = 0; i < n; i++) + if(downsem(ss[(p+i)%n], 0) == 1){ ainc(&c.ualt); - return (i+j)%n; + return (p+i)%n; } ainc(&c.kalt); return semalt(ss, n);