Charles.Forsyth20060303a828770d19 years agoHistory
190 lines · 3.7 KB · Brainfuck
RawDownload
implement Srvmgr; include "sys.m";	sys: Sys; include "srvmgr.m";include "service.m";include "cfg.m"; Srvinfo: adt {	name: string;	path: string;	args: list of string;}; services: list of ref Srvinfo; init(srvdir: string): (string, chan of ref Srvreq){	sys = load Sys Sys->PATH;	cfg := load Cfg Cfg->PATH;	cfgpath := srvdir + "/services.cfg";	if (cfg == nil)		return (sys->sprint("cannot load %s: %r", Cfg->PATH), nil);	err := cfg->init(cfgpath);	if (err != nil)		return (err, nil); 	(err, services) = parsecfg(cfgpath, srvdir, cfg);	if (err != nil)		return (err, nil); 	rc := chan of ref Srvreq;	spawn srv(rc);	return (nil, rc);} parsecfg(p, srvdir: string, cfg: Cfg): (string, list of ref Srvinfo){	srvlist: list of ref Srvinfo;	Record, Tuple: import cfg; 	for (slist := cfg->getkeys(); slist != nil; slist = tl slist) {		name := hd slist;		matches := cfg->lookup(name);		if (len matches > 1) {			(nil, duplicate) := hd tl matches;			primary := hd duplicate.tuples;			lnum := primary.lnum;			err := sys->sprint("%s:%d: duplicate service name %s", p, lnum, name);			return (err, nil);		}		(nil, r) := hd matches;		lnum := (hd r.tuples).lnum; 		(path, tuple) := r.lookup("path");		if (path == nil) {			err := sys->sprint("%s:%d: missing path for service %s", p, lnum, name);			return (err, nil);		}		if (path[0] != '/')			path = srvdir + "/" + path; 		args: list of string = nil;		for (tuples := tl r.tuples; tuples != nil; tuples = tl tuples) {			t := hd tuples;			arg := t.lookup("arg");			if (arg != nil)				args = arg :: args;		}		nargs: list of string = nil;		for (; args != nil; args = tl args)			nargs = hd args :: nargs;		srvlist = ref Srvinfo(name, path, args) ::srvlist;	}	if (srvlist == nil) {		err := sys->sprint("%s: no services", p);		return (err, nil);	}	return (nil, srvlist);}	srv(rc: chan of ref Srvreq){	for (;;) {		req := <- rc;		id := req.sname + " " + req.id;		pick r := req {		Acquire =>			# r.user not used, but could control access			service := acquire(id);			err := "";			if (service.fd == nil) {				(err, service.root, service.fd) = startservice(req.sname);				if (err != nil)					release(id);			}			r.reply <-= (err, service.root, service.fd);		Release =>			release(id);		}	}} ## returns (error, service root, service FD)#startservice(name: string): (string, string, ref Sys->FD){sys->print("startservice [%s]\n", name);	srv: ref Srvinfo;	for (sl := services; sl != nil; sl = tl sl) {		s := hd sl;		if (s.name == name) {			srv = s;			break;		}	}	if (srv == nil)		return ("unknown service", nil, nil); 	service := load Service srv.path;	if (service == nil) {		err := sys->sprint("cannot load %s: %r", srv.path);		return (err, nil, nil);	} 	return service->init(srv.args);} Srvmap: adt {	id: string;	root: string;	fd: ref Sys->FD;	nref: int;	next: cyclic ref Srvmap;}; PRIME: con 211;buckets := array[PRIME] of ref Srvmap; hash(id: string): int{	# HashPJW	h := 0;	for (i := 0; i < len id; i++) {		h = (h << 4) + id[i];		g := h & int 16rf0000000;		if (g != 0) {			h = h ^ ((g >> 24) & 16rff);			h = h ^ g;		}	}	if (h < 0)		h &= ~(1<<31);	return int (h % PRIME);} acquire(id: string): ref Srvmap{	h := hash(id);	for (p := buckets[h]; p != nil; p = p.next)		if (p.id == id) {			p.nref++;			return p;		}	p = ref Srvmap(id, nil, nil, 1, buckets[h]);	buckets[h] = p;	return p;} release(id: string){	h :=hash(id);	prev: ref Srvmap;	for (p := buckets[h]; p != nil; p = p.next) {		if (p.id == id){			p.nref--;			if (p.nref == 0) {				sys->print("release [%s]\n", p.id);				if (prev == nil)					buckets[h] = p.next;				else					prev.next = p.next;			}			return;		}		prev = p;	}}