XlServiceImpl.mesa
Copyright Ó 1988, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, April 27, 1988 4:10:20 pm PDT
Christian Jacobi, May 8, 1992 3:35 pm PDT
Willie-s, November 25, 1991 4:47 pm PST
DIRECTORY
IO, PropList, Random, Rope, SymTab, SystemNames, Xl, XlPrivate, XlPrivateSplit, XlService;
XlServiceImpl: CEDAR MONITOR
IMPORTS IO, PropList, Random, Rope, SymTab, SystemNames, Xl
EXPORTS Xl, XlPrivateSplit, XlService
~ BEGIN OPEN Xl, XlPrivate;
ROPE: TYPE = Rope.ROPE;
badService: ERROR = CODE;
trustedServiceProp: REF ATOM = NEW[ATOM ¬ $trustedServiceProp];
--the service is put on a property of the connection so we are sure about decreasing the connection count only once
serviceVersion: ROPE ~ "�r←ServiceVersion"; --name of X atom to distinguish services
serviceTab: SymTab.Ref ~ SymTab.Create[3];
--Problem: the removal of dead dead services is not completely guaranteed depending on how connections die. This is a minor problem since we don't intend to use big timesharing and use many many servers yet.
--Possible solution: we might have list of connections anyway; service maintenance could be bound to that list.
Service: TYPE = REF ServiceImplRep;
ServiceImplRep: TYPE ~ RECORD [
connectionCount: INT ¬ 0, --maybe alive connections only
propList: PropList.List ¬ NIL, --the real properties for clients
serviceKey: ROPE ¬ NIL
];
ServiceRep: PUBLIC TYPE = ServiceImplRep;
debuggingAssumeServicePerModuleInstance: BOOL ~ FALSE;
--then everything is same service !!!
--usefull for debugging the port of Xl to new machine
debuggingHackKey: ROPE ¬ IO.PutFR1["hack serviceKey %g", IO.time[]];
InitServiceStuff: PUBLIC PROC [c: Connection] = {
serviceKey: ROPE;
atom: XAtom ¬ MakeAtom[c, serviceVersion];
rootWindow: Window ¬ FirstRoot[c];
ret: PropertyReturnRec;
IF debuggingAssumeServicePerModuleInstance
THEN serviceKey ¬ debuggingHackKey
ELSE {
--normal case
ret ¬ GetProperty[c: c, w: rootWindow, property: atom, supposedFormat: 8];
IF ret.format#8 OR ret.type#atom OR ret.value=NIL THEN {
<<rarely: once per server boot>>
tentativeKey: ROPE ¬ IO.PutFLR["%g %g %g", LIST[IO.time[], IO.rope[SystemNames.MachineName[]], IO.int[Random.NextInt[]]] ];
BEGIN --prevent X server bug [XlR2 of MIT]
WHILE Rope.Length[tentativeKey] MOD 4 # 0 DO
tentativeKey ¬ Rope.Concat[tentativeKey, " "];
ENDLOOP;
END;
GrabServer[c];
ret ¬ GetProperty[c: c, w: rootWindow, property: atom, supposedFormat: 8];
IF ret.format#8 OR ret.type#atom OR ret.value=NIL THEN {
ChangeProperty[c, rootWindow, atom, atom, replace, serviceKey ¬ tentativeKey];
};
UngrabServer[c];
};
serviceKey ¬ NARROW[ret.value];
};
[] ¬ EntryDefineService[c, serviceKey];
};
EntryDefineService: ENTRY PROC [c: Connection, serviceKey: ROPE] RETURNS [service: Service] = {
ENABLE UNWIND => NULL;
service ¬ NEW[ServiceImplRep ¬ [connectionCount: 0, serviceKey: serviceKey, propList: PropList.NewPropList[]]];
IF ~SymTab.Insert[serviceTab, serviceKey, service] THEN
service ¬ NARROW[SymTab.Fetch[serviceTab, serviceKey].val];
service.connectionCount ¬ service.connectionCount + 1;
c.service ¬ service;
c.serviceProperties ¬ service.propList;
PutConnectionProp[c, trustedServiceProp, service];
};
ReleaseService: PUBLIC ENTRY PROC [c: Connection] = {
ENABLE UNWIND => NULL;
IF c#NIL THEN {
service: Service ¬ c.service;
IF service#NIL AND GetConnectionProp[c, trustedServiceProp]=service THEN {
PutConnectionProp[c, trustedServiceProp, NIL]; --make sure service released once only
service.connectionCount ¬ MAX[service.connectionCount - 1, 0];
IF service.connectionCount=0 THEN [] ¬ SymTab.Delete[serviceTab, service.serviceKey];
};
};
};
GetService: PUBLIC PROC [c: Connection] RETURNS [service: REF] = {
service ¬ c.service
};
PutProp: PUBLIC ENTRY PROC [service: REF, key: REF, val: REF ¬ NIL] = {
WITH service SELECT FROM
sr: REF ServiceImplRep => [] ¬ PropList.PutProp[sr.propList, key, val];
ENDCASE => RETURN WITH ERROR badService
};
GetProp: PUBLIC ENTRY PROC [service: REF, key: REF] RETURNS [val: REF ¬ NIL] = {
WITH service SELECT FROM
sr: REF ServiceImplRep => RETURN [ PropList.GetProp[sr.propList, key] ];
ENDCASE => RETURN WITH ERROR badService
};
PutServiceProp: PUBLIC PROC [c: Connection, key: REF, val: REF ¬ NIL] = {
[] ¬ PropList.PutProp[c.serviceProperties, key, val]
};
GetServiceProp: PUBLIC PROC [c: Connection, key: REF] RETURNS [val: REF] = {
val ¬ PropList.GetProp[c.serviceProperties, key]
};
GetServicePropAndInit: PUBLIC PROC [c: Connection, key: REF, init: InitializeProcType] RETURNS [val: REF] = {
WrapInit: PropList.InitializeProcType = {val ¬ init[NARROW[data], key]};
val ¬ PropList.GetPropOrInit[c.serviceProperties, key, WrapInit, c].val
};
END.