ndb/cs deadlock

Issue #320 new
Former user created an issue

Original issue 320 created by inferno-os on 2014-09-02T23:23:15.000Z:

cleanfid can kill request processes that are holding a lock on ndb. I don't see any harm in letting unneeded request processes linger, so instead of killing them I let them continue and discard their replies.

/appl/cmd/ndb/cs.b:37,46 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:37,51 connect: fn(): string; };

  • Reply: adt
  • Fid: adt { fid: int;
  • pid: int;
  • donec: chan of ref Reply;
  • reply: ref Reply;
  • };
  • Reply: adt
  • { addrs: list of string; err: string; }; /appl/cmd/ndb/cs.b:56,62 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:61,67 cache:= array[Ncache] of ref Cached; nextcache := 0;

  • rlist: list of ref Reply;

  • fidlist: list of ref Fid;

ndbfile := "/lib/ndb/local"; ndb: ref Db; /appl/cmd/ndb/cs.b:221,228 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:226,231

cs(file: ref Sys->FileIO) { - pidc := chan of int; - donec := chan of ref Reply; for (;;) { alt { (nil, buf, fid, wc) := <-file.write => /appl/cmd/ndb/cs.b:247,257 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:250,258 break; } now := time(); - r := ref Reply; - r.fid = fid; - spawn request(r, query, nbytes, now, wc, pidc, donec); - r.pid = <-pidc; - rlist = r :: rlist; + donec := chan[1] of ref Reply; + spawn request(query, nbytes, now, wc, donec); + fidlist = ref Fid(fid, donec, nil) :: fidlist; }

    (off, nbytes, fid, rc) := &lt;-file.read =&gt;

/appl/cmd/ndb/cs.b:263,271 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:264,269 rc <-= (nil, "unknown request"); } else ; # cleanfid(fid); # compensate for csendq in file2chan - - r := <-donec => - r.pid = 0; } } } /appl/cmd/ndb/cs.b:272,281 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:270,282

findfid(fid: int): ref Reply { - for(rl := rlist; rl != nil; rl = tl rl){ - r := hd rl; - if(r.fid == fid) - return r; + for(fl := fidlist; fl != nil; fl = tl fl){ + f := hd fl; + if(f.fid == fid){ + if(f.reply == nil) + f.reply = <-f.donec; + return f.reply; + } } return nil; } /appl/cmd/ndb/cs.b:282,310 - /usr/xmlset_roodkcableoj28840ybtide/cs.b:283,301

cleanfid(fid: int) { - rl := rlist; - rlist = nil; - for(; rl != nil; rl = tl rl){ - r := hd rl; - if(r.fid != fid) - rlist = r :: rlist; - else - killgrp(r.pid); + fl := fidlist; + fidlist = nil; + for(; fl != nil; fl = tl fl){ + f := hd fl; + if(f.fid != fid) + fidlist = f :: fidlist; } }

  • killgrp(pid: int)
  • request(query: string, nbytes: int, now: int, wc: chan of (int, string), donec: chan of ref Reply) {
  • if(pid != 0){
  • fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
  • if(fd == nil || sys->fprint(fd, "killgrp") < 0)
  • sys->fprint(stderr, "cs: can't killgrp %d: %r\n", pid);
  • }
  • }
  • request(r: ref Reply, query: string, nbytes: int, now: int, wc: chan of (int, string), pidc: chan of int, donec: chan of ref Reply)
  • {
  • pidc <-= sys->pctl(Sys->NEWPGRP, nil);
  • sys->pctl(Sys->NEWPGRP, nil);
  • r := ref Reply; if(query != nil && query[0] == '!'){ # general query (r.addrs, r.err) = genquery(query[1:]);

%%

implement Cs;

# Connection server translates net!machine!service into
# /net/tcp/clone 135.104.9.53!564
#

include &quot;sys.m&quot;;
    sys:    Sys;

include &quot;draw.m&quot;;

include &quot;srv.m&quot;;
    srv: Srv;

include &quot;bufio.m&quot;;
include &quot;attrdb.m&quot;;
    attrdb: Attrdb;
    Attr, Db, Dbentry, Tuples: import attrdb;

include &quot;ip.m&quot;;
    ip: IP;
include &quot;ipattr.m&quot;;
    ipattr: IPattr;

include &quot;arg.m&quot;;

Cs: module
{
    init:   fn(nil: ref Draw-&gt;Context, nil: list of string);
};

# signature of dial-on-demand module
CSdial: module
{
    init:   fn(nil: ref Draw-&gt;Context): string;
    connect:    fn(): string;
};

Fid: adt
{
    fid:    int;
    donec:  chan of ref Reply;
    reply:  ref Reply;
};

Reply: adt
{
    addrs:  list of string;
    err:    string;
};

Cached: adt
{
    expire: int;
    query:  string;
    addrs:  list of string;
};

Ncache: con 16;
cache:= array[Ncache] of ref Cached;
nextcache := 0;

fidlist: list of ref Fid;

ndbfile := &quot;/lib/ndb/local&quot;;
ndb: ref Db;
mntpt := &quot;/net&quot;;
myname: string;

stderr: ref Sys-&gt;FD;

verbose := 0;
dialmod: CSdial;

init(ctxt: ref Draw-&gt;Context, args: list of string)
{
    sys = load Sys Sys-&gt;PATH;
    stderr = sys-&gt;fildes(2);
    attrdb = load Attrdb Attrdb-&gt;PATH;
    if(attrdb == nil)
        cantload(Attrdb-&gt;PATH);
    attrdb-&gt;init();
    ip = load IP IP-&gt;PATH;
    if(ip == nil)
        cantload(IP-&gt;PATH);
    ip-&gt;init();
    ipattr = load IPattr IPattr-&gt;PATH;
    if(ipattr == nil)
        cantload(IPattr-&gt;PATH);
    ipattr-&gt;init(attrdb, ip);

    svcname := &quot;#scs&quot;;
    arg := load Arg Arg-&gt;PATH;
    if (arg == nil)
        cantload(Arg-&gt;PATH);
    arg-&gt;init(args);
    arg-&gt;setusage(&quot;cs [-v] [-x mntpt] [-f database] [-d dialmod]&quot;);
    while((c := arg-&gt;opt()) != 0)
        case c {
        'v' or 'D' =&gt;
            verbose++;
        'd' =&gt;   # undocumented hack to replace svc/cs/cs
            f := arg-&gt;arg();
            if(f != nil){
                dialmod = load CSdial f;
                if(dialmod == nil)
                    cantload(f);
            }
        'f' =&gt;
            ndbfile = arg-&gt;earg();
        'x' =&gt;
            mntpt = arg-&gt;earg();
            svcname = &quot;#scs&quot;+svcpt(mntpt);
        * =&gt;
            arg-&gt;usage();
        }

    if(arg-&gt;argv() != nil)
        arg-&gt;usage();
    arg = nil;

    srv = load Srv Srv-&gt;PATH;    # hosted Inferno only
    if(srv != nil)
        srv-&gt;init();

    sys-&gt;remove(svcname+&quot;/cs&quot;);
    sys-&gt;unmount(svcname, mntpt);
    publish(svcname);
    if(sys-&gt;bind(svcname, mntpt, Sys-&gt;MBEFORE) &lt; 0)
        error(sys-&gt;sprint(&quot;can't bind #s on %s: %r&quot;, mntpt));
    file := sys-&gt;file2chan(mntpt, &quot;cs&quot;);
    if(file == nil)
        error(sys-&gt;sprint(&quot;can't make %s/cs: %r&quot;, mntpt));
    sys-&gt;pctl(Sys-&gt;FORKFD|Sys-&gt;NEWPGRP, nil);
    refresh();
    if(dialmod != nil){
        e := dialmod-&gt;init(ctxt);
        if(e != nil)
            error(sys-&gt;sprint(&quot;can't initialise dial-on-demand: %s&quot;, e));
    }
    spawn cs(file);
}

svcpt(s: string): string
{
    for(i:=0; i&lt;len s; i++)
        if(s[i] == '/')
            s[i] = '_';
    return s;
}

publish(dir: string)
{
    d := Sys-&gt;nulldir;
    d.mode = 8r777;
    if(sys-&gt;wstat(dir, d) &lt; 0)
        sys-&gt;fprint(sys-&gt;fildes(2), &quot;cs: can't publish %s: %r\n&quot;, dir);
}

cantload(m: string)
{
    error(sys-&gt;sprint(&quot;cannot load %s: %r&quot;, m));
}

error(s: string)
{
    sys-&gt;fprint(sys-&gt;fildes(2), &quot;cs: %s\n&quot;, s);
    raise &quot;fail:error&quot;;
}

refresh()
{
    myname = sysname();
    if(ndb == nil){
        ndb2 := Db.open(ndbfile);
        if(ndb2 == nil){
            err := sys-&gt;sprint(&quot;%r&quot;);
            ndb2 = Db.open(&quot;/lib/ndb/inferno&quot;);   # try to get service map at least
            if(ndb2 == nil)
                sys-&gt;fprint(sys-&gt;fildes(2), &quot;cs: warning: can't open %s: %s\n&quot;, ndbfile, err);  # continue without it
        }
        ndb = Db.open(mntpt+&quot;/ndb&quot;);
        if(ndb != nil)
            ndb = ndb.append(ndb2);
        else
            ndb = ndb2;
    }else
        ndb.reopen();
}

sysname(): string
{
    t := rf(&quot;/dev/sysname&quot;);
    if(t != nil)
        return t;
    t = rf(&quot;#e/sysname&quot;);
    if(t == nil){
        s := rf(mntpt+&quot;/ndb&quot;);
        if(s != nil){
            db := Db.sopen(s);
            if(db != nil){
                (e, nil) := db.find(nil, &quot;sys&quot;);
                if(e != nil)
                    t = e.findfirst(&quot;sys&quot;);
            }
        }
    }
    if(t != nil){
        fd := sys-&gt;open(&quot;/dev/sysname&quot;, Sys-&gt;OWRITE);
        if(fd != nil)
            sys-&gt;fprint(fd, &quot;%s&quot;, t);
    }
    return t;
}

rf(name: string): string
{
    fd := sys-&gt;open(name, Sys-&gt;OREAD);
    buf := array[512] of byte;
    n := sys-&gt;read(fd, buf, len buf);
    if(n &lt;= 0)
        return nil;
    return string buf[0:n];
}

cs(file: ref Sys-&gt;FileIO)
{
    for (;;) {
        alt {
        (nil, buf, fid, wc) := &lt;-file.write =&gt;
            cleanfid(fid);  # each write cancels previous requests
            if(dialmod != nil){
                e := dialmod-&gt;connect();
                if(e != nil){
                    if(len e &gt; 5 &amp;&amp; e[0:5]==&quot;fail:&quot;)
                        e = e[5:];
                    if(e == &quot;&quot;)
                        e = &quot;unknown error&quot;;
                    wc &lt;-= (0, &quot;cs: dial on demand: &quot;+e);
                    break;
                }
            }
            if(wc != nil){
                nbytes := len buf;
                query := string buf;
                if(query == &quot;refresh&quot;){
                    refresh();
                    wc &lt;-= (nbytes, nil);
                    break;
                }
                now := time();
                donec := chan[1] of ref Reply;
                spawn request(query, nbytes, now, wc, donec);
                fidlist = ref Fid(fid, donec, nil) :: fidlist;
            }

        (off, nbytes, fid, rc) := &lt;-file.read =&gt;
            if(rc != nil){
                r := findfid(fid);
                if(r != nil)
                    reply(r, off, nbytes, rc);
                else
                    rc &lt;-= (nil, &quot;unknown request&quot;);
            } else
                ;   # cleanfid(fid);        # compensate for csendq in file2chan
        }
    }
}

findfid(fid: int): ref Reply
{
    for(fl := fidlist; fl != nil; fl = tl fl){
        f := hd fl;
        if(f.fid == fid){
            if(f.reply == nil)
                f.reply = &lt;-f.donec;
            return f.reply;
        }
    }
    return nil;
}

cleanfid(fid: int)
{
    fl := fidlist;
    fidlist = nil;
    for(; fl != nil; fl = tl fl){
        f := hd fl;
        if(f.fid != fid)
            fidlist = f :: fidlist;
    }
}

request(query: string, nbytes: int, now: int, wc: chan of (int, string), donec: chan of ref Reply)
{
    sys-&gt;pctl(Sys-&gt;NEWPGRP, nil);
    r := ref Reply;
    if(query != nil &amp;&amp; query[0] == '!'){
        # general query
        (r.addrs, r.err) = genquery(query[1:]);
    }else{
        (r.addrs, r.err) = xlate(query, now);
        if(r.addrs == nil &amp;&amp; r.err == nil)
            r.err = &quot;cs: can't translate address&quot;;
    }
    if(r.err != nil){
        if(verbose)
            sys-&gt;fprint(stderr, &quot;cs: %s: %s\n&quot;, query, r.err);
        wc &lt;-= (0, r.err);
    } else
        wc &lt;-= (nbytes, nil);
    donec &lt;-= r;
}

reply(r: ref Reply, off: int, nbytes: int, rc: chan of (array of byte, string))
{
    if(r.err != nil){
        rc &lt;-= (nil, r.err);
        return;
    }
    addr: string = nil;
    if(r.addrs != nil){
        addr = hd r.addrs;
        r.addrs = tl r.addrs;
    }
    off = 0;    # this version ignores offset
    rc &lt;-= reads(addr, off, nbytes);
}

#
# return the file2chan reply for a read of the given string
#
reads(str: string, off, nbytes: int): (array of byte, string)
{
    bstr := array of byte str;
    slen := len bstr;
    if(off &lt; 0 || off &gt;= slen)
        return (nil, nil);
    if(off + nbytes &gt; slen)
        nbytes = slen - off;
    if(nbytes &lt;= 0)
        return (nil, nil);
    return (bstr[off:off+nbytes], nil);
}

lookcache(query: string, now: int): ref Cached
{
    for(i:=0; i&lt;len cache; i++){
        c := cache[i];
        if(c != nil &amp;&amp; c.query == query &amp;&amp; now &lt; c.expire){
            if(verbose)
                sys-&gt;print(&quot;cache: %s -&gt; %s\n&quot;, query, hd c.addrs);
            return c;
        }
    }
    return nil;
}

putcache(query: string, addrs: list of string, now: int)
{
    ce := ref Cached;
    ce.expire = now+120;
    ce.query = query;
    ce.addrs = addrs;
    cache[nextcache] = ce;
    nextcache = (nextcache+1)%Ncache;
}

xlate(address: string, now: int): (list of string, string)
{
    n: int;
    l, rl, results: list of string;
    repl, netw, mach, service: string;

    ce := lookcache(address, now);
    if(ce != nil &amp;&amp; ce.addrs != nil)
        return (ce.addrs, nil);

    (n, l) = sys-&gt;tokenize(address, &quot;!\n&quot;);
    if(n &lt; 2)
        return (nil, &quot;bad format request&quot;);

    netw = hd l;
    if(netw == &quot;net&quot;)
        netw = &quot;tcp&quot;; # TO DO: better (needs lib/ndb)
    if(!isnetwork(netw))
        return (nil, &quot;network unavailable &quot;+netw);
    l = tl l;

    if(!isipnet(netw)) {
        repl = mntpt + &quot;/&quot; + netw + &quot;/clone &quot;;
        for(;;){
            repl += hd l;
            if((l = tl l) == nil)
                break;
            repl += &quot;!&quot;;
        }
        return (repl :: nil, nil);  # no need to cache
    }

    if(n != 3)
        return (nil, &quot;bad format request&quot;);
    mach = hd l;
    service = hd tl l;

    if(!isnumeric(service)) {
        s := xlatesvc(netw, service);
        if(s == nil){
            if(srv != nil)
                s = srv-&gt;ipn2p(netw, service);
            if(s == nil)
                return (nil, &quot;cs: can't translate service&quot;);
        }
        service = s;
    }

    attr := ipattr-&gt;dbattr(mach);
    if(mach == &quot;*&quot;)
        l = &quot;&quot; :: nil;
    else if(attr != &quot;ip&quot;) {
        # Symbolic server == &quot;$SVC&quot;
        if(mach[0] == '$' &amp;&amp; len mach &gt; 1 &amp;&amp; ndb != nil){
            (s, nil) := ipattr-&gt;findnetattr(ndb, &quot;sys&quot;, myname, mach[1:]);
            if(s == nil){
                names := dblook(&quot;infernosite&quot;, &quot;&quot;, mach[1:]);
                if(names == nil)
                    return (nil, &quot;cs: can't translate &quot;+mach);
                s = hd names;
            }
            mach = s;
            attr = ipattr-&gt;dbattr(mach);
        }
        if(attr == &quot;sys&quot;){
            results = dblook(&quot;sys&quot;, mach, &quot;ip&quot;);
            if(results != nil)
                attr = &quot;ip&quot;;
        }
        if(attr != &quot;ip&quot;){
            err: string;
            (results, err) = querydns(mach, &quot;ip&quot;);
            if(err != nil)
                return (nil, err);
        }else if(results == nil)
            results = mach :: nil;
        l = results;
        if(l == nil){
            if(srv != nil)
                l = srv-&gt;iph2a(mach);
            if(l == nil)
                return (nil, &quot;cs: unknown host&quot;);
        }
    } else
        l = mach :: nil;

    while(l != nil) {
        s := hd l;
        l = tl l;
        dnetw := netw;
        if(s != nil){
            (divert, err) := ipattr-&gt;findnetattr(ndb, &quot;ip&quot;, s, &quot;divert-&quot;+netw);
            if(err == nil &amp;&amp; divert != nil){
                dnetw = divert;
                if(!isnetwork(dnetw))
                    return (nil, &quot;network unavailable &quot;+dnetw);   # XXX should only give up if all addresses fail?
            }
        }

        if(s != &quot;&quot;)
            s[len s] = '!';
        s += service;

        repl = mntpt+&quot;/&quot;+dnetw+&quot;/clone &quot;+s;
        if(verbose)
            sys-&gt;fprint(stderr, &quot;cs: %s!%s!%s -&gt; %s\n&quot;, netw, mach, service, repl);

        rl = repl :: rl;
    }
    rl = reverse(rl);
    putcache(address, rl, now);
    return (rl, nil);
}

querydns(name: string, rtype: string): (list of string, string)
{
    fd := sys-&gt;open(mntpt+&quot;/dns&quot;, Sys-&gt;ORDWR);
    if(fd == nil)
        return (nil, nil);
    if(sys-&gt;fprint(fd, &quot;%s %s&quot;, name, rtype) &lt; 0)
        return (nil, sys-&gt;sprint(&quot;%r&quot;));
    rl: list of string;
    buf := array[256] of byte;
    sys-&gt;seek(fd, big 0, 0);
    while((n := sys-&gt;read(fd, buf, len buf)) &gt; 0){
        # name rtype value
        (nf, fld) := sys-&gt;tokenize(string buf[0:n], &quot; \t&quot;);
        if(nf != 3){
            sys-&gt;fprint(stderr, &quot;cs: odd result from dns: %s\n&quot;, string buf[0:n]);
            continue;
        }
        rl = hd tl tl fld :: rl;
    }
    return (reverse(rl), nil);
}

dblook(attr: string, val: string, rattr: string): list of string
{
    rl: list of string;
    ptr: ref Attrdb-&gt;Dbptr;
    for(;;){
        e: ref Dbentry;
        (e, ptr) = ndb.findbyattr(ptr, attr, val, rattr);
        if(e == nil)
            break;
        for(l := e.findbyattr(attr, val, rattr); l != nil; l = tl l){
            (nil, al) := hd l;
            for(; al != nil; al = tl al)
                if(!inlist((hd al).val, rl))
                    rl = (hd al).val :: rl;
        }
    }
    return reverse(rl);
}

inlist(s: string, l: list of string): int
{
    for(; l != nil; l = tl l)
        if(hd l == s)
            return 1;
    return 0;
}

reverse(l: list of string): list of string
{
    t: list of string;
    for(; l != nil; l = tl l)
        t = hd l :: t;
    return t;
}

isnumeric(a: string): int
{
    i, c: int;

    for(i = 0; i &lt; len a; i++) {
        c = a[i];
        if(c &lt; '0' || c &gt; '9')
            return 0;
    }
    return 1;
}

nets: list of string;

isnetwork(s: string) : int
{
    if(find(s, nets))
        return 1;
    (ok, nil) := sys-&gt;stat(mntpt+&quot;/&quot;+s+&quot;/clone&quot;);
    if(ok &gt;= 0) {
        nets = s :: nets;
        return 1;
    }
    return 0;
}

find(e: string, l: list of string) : int
{
    for(; l != nil; l = tl l)
        if (e == hd l)
            return 1;
    return 0;
}

isipnet(s: string) : int
{
    return s == &quot;net&quot; || s == &quot;tcp&quot; || s == &quot;udp&quot; || s == &quot;il&quot;;
}

xlatesvc(proto: string, s: string): string
{
    if(ndb == nil || s == nil || isnumeric(s))
        return s;
    (e, nil) := ndb.findbyattr(nil, proto, s, &quot;port&quot;);
    if(e == nil)
        return nil;
    matches := e.findbyattr(proto, s, &quot;port&quot;);
    if(matches == nil)
        return nil;
    (ts, al) := hd matches;
    restricted := &quot;&quot;;
    if(ts.hasattr(&quot;restricted&quot;))
        restricted = &quot;!r&quot;;
    if(verbose &gt; 1)
        sys-&gt;print(&quot;%s=%q port=%s%s\n&quot;, proto, s, (hd al).val, restricted);
    return (hd al).val+restricted;
}

time(): int
{
    timefd := sys-&gt;open(&quot;/dev/time&quot;, Sys-&gt;OREAD);
    if(timefd == nil)
        return 0;
    buf := array[128] of byte;
    sys-&gt;seek(timefd, big 0, 0);
    n := sys-&gt;read(timefd, buf, len buf);
    if(n &lt; 0)
        return 0;
    return int ((big string buf[0:n]) / big 1000000);
}

#
# general query: attr1=val1 attr2=val2 ... finds matching tuple(s)
#   where attr1 is the key and val1 can't be *
#
genquery(query: string): (list of string, string)
{
    (tups, err) := attrdb-&gt;parseline(query, 0);
    if(err != nil)
        return (nil, &quot;bad query: &quot;+err);
    if(tups == nil)
        return (nil, &quot;bad query&quot;);
    pairs := tups.pairs;
    a0 := (hd pairs).attr;
    if(a0 == &quot;ipinfo&quot;)
        return (nil, &quot;ipinfo not yet supported&quot;);
    v0 := (hd pairs).val;

    # if((a0 == &quot;dom&quot; || a0 == &quot;ip&quot;) &amp;&amp; v0 != nil){
    #   query dns ...
    # }

    ptr: ref Attrdb-&gt;Dbptr;
    e: ref Dbentry;
    for(;;){
        (e, ptr) = ndb.findpair(ptr, a0, v0);
        if(e == nil)
            break;
        for(l := e.lines; l != nil; l = tl l)
            if(qmatch(hd l, tl pairs)){
                ls: list of string;
                for(l = e.lines; l != nil; l = tl l)
                    ls = tuptext(hd l) :: ls;
                return (reverse(ls), nil);
            }
    }
    return  (nil, &quot;no match&quot;);
}

#
# see if set of tuples t contains every non-* attr/val pair
#
qmatch(t: ref Tuples, av: list of ref Attr): int
{
Match:
    for(; av != nil; av = tl av){
        a := hd av;
        for(pl := t.pairs; pl != nil; pl = tl pl)
            if((hd pl).attr == a.attr &amp;&amp;
                (a.val == &quot;*&quot; || a.val == (hd pl).val))
                continue Match;
        return 0;
    }
    return 1;
}

tuptext(t: ref Tuples): string
{
    s: string;
    for(pl := t.pairs; pl != nil; pl = tl pl){
        p := hd pl;
        if(s != nil)
            s[len s] = ' ';
        s += sys-&gt;sprint(&quot;%s=%q&quot;, p.attr, p.val);
    }
    return s;
}

%%

implement Cswedge;

include &quot;sys.m&quot;;
    sys: Sys;
include &quot;draw.m&quot;;

Cswedge: module {
    init:   fn(nil: ref Draw-&gt;Context, nil: list of string);
};

progname: string;

init(nil: ref Draw-&gt;Context, args: list of string)
{
    sys = load Sys Sys-&gt;PATH;

    progname = hd args;
    if(len args != 2) {
        sys-&gt;fprint(sys-&gt;fildes(2), &quot;usage: %s csfile\n&quot;, progname);
        raise &quot;fail:usage&quot;;
    }
    csfile := hd tl args;

    if((fd := sys-&gt;open(csfile, Sys-&gt;ORDWR)) == nil) {
        sys-&gt;fprint(sys-&gt;fildes(2), &quot;%s: open %s: %r\n&quot;, progname, csfile);
        raise &quot;fail:open&quot;;
    }

    sys-&gt;pctl(Sys-&gt;NEWPGRP, nil);

    N := 4;
    sync := chan of int;
    for(i := 0; i &lt; N; i++)
        spawn wedge(fd, i, sync);
    for(i = 0; i &lt; N; i++)
        &lt;-sync;

    sys-&gt;print(&quot;\n&quot;);
    sys-&gt;print(&quot;ok\n&quot;);
}

wedge(fd: ref Sys-&gt;FD, pid: int, sync: chan of int)
{
    q := array of byte &quot;tcp!::1!z39.50&quot;;
    for(i := 0; i &lt; 100 &amp;&amp; (n := sys-&gt;pwrite(fd, q, len q, big 0)) &gt; 0; i++)
        sys-&gt;print(&quot;%d&quot;, pid);
    if(n &lt; 0) {
        sys-&gt;fprint(sys-&gt;fildes(2), &quot;%s: write: %r\n&quot;, progname);
        raise &quot;fail:write&quot;;
    }
    sync &lt;-= 69105;
}

# bind '#I' /net.alt
# ndb/cs -x /net.alt
# cswedge /net.alt/cs

Comments (4)

  1. Former user Account Deleted

    Comment #1 originally posted by inferno-os on 2014-10-04T21:40:23.000Z:

    Charle why don´t reply, it´s not a normal comportament, i ask information for this deadlock

  2. Former user Account Deleted

    Comment #2 originally posted by inferno-os on 2014-10-08T21:07:42.000Z:

    Well, it was a thoughtful question.

    There's nothing really wrong about the proposed fix, but it side-steps the problem by letting the processes complete. That's fine, because the underlying problem is an ancient one, of how to make code (critical sections in this case) uninterruptible when they must be for correctness, without making the containing process impossible to kill, although there are approximations that would be fine.

    Here, the problem is that we hacked a lock in to Attrdb that suits a shared-memory environment without kills, when Inferno offers alternatives.

  3. Former user Account Deleted

    Comment #3 originally posted by inferno-os on 2014-10-09T04:58:53.000Z:

    So what would the be right way to fix Attrdb? The ways of removing the lock that I considered would have Attrdb spawn a process that won't necessarily get cleaned up by existing programs.

  4. Log in to comment