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.