LoaderImpl.mesa
Copyright Ó 1988, 1989, 1991 by Xerox Corporation. All rights reserved.
JKF December 13, 1988 1:52:18 pm PST
Eduardo Pelegri-Llopart October 28, 1988 11:17:46 am PDT
Bill Jackson (bj) January 6, 1989 8:48:59 pm PST
Willie-Sue Orr, March 16, 1989 8:51:13 pm PST
Willie-s, September 23, 1991 5:28 pm PDT
DIRECTORY
BasicTime USING [ GMT, latestGMT ],
CStrings USING [CString],
Loader USING [ LoadErrorType, LoadExceptionType ],
Rope USING [ Cat, Concat, Equal, Find, FindBackward, IsEmpty, Length, ROPE, Substr ],
SymTab USING [ Create, Delete, Fetch, Ref, Store ],
UXProcs USING [ CProc, ToCedarProc ],
UXStrings USING [ Create, ToRope ];
LoaderImpl:
CEDAR
PROGRAM
IMPORTS BasicTime, Rope, SymTab, UXStrings, UXProcs
EXPORTS Loader ~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
LoadException: PUBLIC SIGNAL [ type: Loader.LoadExceptionType, message: ROPE ] = CODE;
LoadError: PUBLIC ERROR [ type: Loader.LoadErrorType, message: ROPE ] = CODE;
XRLoadFile:
PROC [ fileName: CStrings.CString, funcName: CStrings.CString,
checkLoad:
INT32, nodebugger:
INT32 ]
RETURNS [ status:
INT32 ] =
TRUSTED MACHINE CODE { "+extern int load𡤏ile();.load𡤏ile" };
GetModuleName:
PROC
RETURNS [ moduleName:
ROPE ] = {
vStamp: CStrings.CString ~ UXStrings.Create["←versionStamp"];
addr: CStrings.CString ¬ LOOPHOLE[GetSymVal[vStamp]];
IF ( addr = NIL ) THEN ERROR LoadError[type: invalidObjectFile,
message: "Mimosa version stamp not found."];
moduleName ¬ UXStrings.ToRope[addr];
{
versionStampPrefix: ROPE = "@(#)mob←versio";
prefixLen: INT ~ versionStampPrefix.Length[];
front: ROPE ~ moduleName.Substr[len: prefixLen];
IF (
NOT versionStampPrefix.Equal[front] )
THEN {
ERROR LoadError[type: invalidObjectFile,
message: Rope.Concat["Mimosa version stamp not in proper format: ", front]];
};
};
{
p1: INT ~ moduleName.FindBackward[" "].SUCC;
r1: ROPE ¬ moduleName.Substr[start: p1];
p2: INT ~ r1.FindBackward["."];
moduleName ¬ IF ( p2 = -1 ) THEN r1 ELSE r1.Substr[len: p2];
};
RETURN[moduleName]
};
GetSymVal: PROC [ which: CStrings.CString ] RETURNS [ UXProcs.CProc ] = TRUSTED MACHINE CODE {"%<sys/types.h>\n+extern caddr←t get←sym←val();.get←sym←val" };
ModuleNameFromFileName:
PROC [ fileName:
ROPE ]
RETURNS [ moduleName:
ROPE ] ~ {
same as XR←strip();
lastSlashIndex: INT ~ fileName.FindBackward["/"];
basename: ROPE ~ IF ( lastSlashIndex = -1 )
THEN fileName ELSE fileName.Substr[lastSlashIndex.SUCC];
firstDot: INT ~ basename.Find["."];
moduleName ¬ IF ( firstDot = -1 ) THEN basename ELSE basename.Substr[len: firstDot];
};
InstallProc: TYPE = PROC;
RunProc: TYPE = PROC;
UnloadProc: TYPE = PROC;
Loadee: TYPE = REF LoadeeObject;
LoadeeObject:
TYPE =
RECORD [
fileName: ROPE,
moduleName: ROPE,
installProc: InstallProc,
runProc: RunProc,
unloadProc: UnloadProc,
installProcCalled: BOOL,
runProcCalled: BOOL,
unloadProcCalled: BOOL
];
table: SymTab.Ref ¬ NIL;
LookupLoadee:
PROC [ moduleName:
ROPE ]
RETURNS [ Loadee ] = {
WITH table.Fetch[moduleName].val
SELECT
FROM
loadee: Loadee => { RETURN [loadee] };
ENDCASE => {
message: ROPE ~ Rope.Cat["Couldn't locate loadee record for module ", moduleName, "."];
LoadError[type: loadeeNotFound, message: message];
};
};
LoadFile:
PUBLIC
PROC [ file:
ROPE ]
RETURNS [ moduleName:
ROPE ] = {
GetModuleLink:
PROC [ prefix:
ROPE, code: Loader.LoadErrorType ]
RETURNS [ proc:
PROC ¬
NIL ] ~ {
linkName: ROPE ¬ prefix.Concat[moduleName];
uxstring: CStrings.CString ¬ UXStrings.Create[linkName];
link: UXProcs.CProc ~ GetSymVal[uxstring];
proc ¬ LOOPHOLE[UXProcs.ToCedarProc[link]];
IF ( proc =
NIL )
THEN {
message: ROPE ~ Rope.Cat["Unable to locate proc [", linkName, "]\n"];
ERROR LoadError[type: code, message: message];
};
};
loadingFileString: CStrings.CString ¬ UXStrings.Create[file];
status: INT ¬ XRLoadFile[loadingFileString, NIL, 0, 0];
try to derive the module name
moduleName ¬ GetModuleName[];
IF ( moduleName.IsEmpty[] )
THEN moduleName ¬ ModuleNameFromFileName[file];
IF ( status = 0 )
THEN {
message: ROPE ~ Rope.Concat["PCR load fails - No action taken for file", file];
LoadError[unknown, message];
this should report invalidObjectFile, loadStateFull, insufficientVM etc.
};
{
file is loaded, now we need to find the install, run and unload procs
loadee: Loadee ~ NEW[LoadeeObject ¬ [fileName: file, moduleName: moduleName, installProc: NULL, runProc: NULL, unloadProc: NULL, installProcCalled: FALSE, runProcCalled: FALSE, unloadProcCalled: FALSE] ];
loadee.installProc ¬ GetModuleLink["←XR←install←", noInstallProc];
loadee.runProc ¬ GetModuleLink["←XR←run←", noRunProc];
loadee.unloadProc ¬ NIL; -- GetModuleLink["←XR←unload←", noUnloadProc];
IF ( table.Store[key: loadee.moduleName, val: loadee] =
FALSE )
THEN {
it's not necessarily an error to load another module which has a name which conflicts with the name of a previously loaded module, but you ought to notify clients that this has happend because in most cases it IS an error - the client probably wanted to unload it first.
message: ROPE ~ Rope.Cat["Reload of ", file, ": latest load completed, old loadee lost."];
SIGNAL LoadException[type: previouslyLoaded, message: message];
};
};
Install:
PUBLIC
PROC [ moduleName:
ROPE ] = {
loadee: Loadee ¬ LookupLoadee[moduleName];
IF ( loadee.installProcCalled )
THEN {
message: ROPE ~ Rope.Cat["The install proc for ", moduleName, " has already been called"];
SIGNAL LoadException[type: previouslyInstalled, message: message];
};
loadee.installProcCalled ¬ TRUE;
loadee.installProc[];
};
Run:
PUBLIC
PROC [ moduleName:
ROPE ] = {
loadee: Loadee ¬ LookupLoadee[moduleName];
IF ( loadee.runProcCalled )
THEN {
message: ROPE ~ Rope.Cat["The run proc for ", moduleName, " has already been called"];
SIGNAL LoadException[type: previouslyRun, message: message];
};
loadee.runProcCalled ¬ TRUE;
loadee.runProc[];
};
Unload:
PUBLIC
PROC [ moduleName:
ROPE ] = {
loadee: Loadee ¬ LookupLoadee[moduleName];
unloadProc: UnloadProc ¬ loadee.unloadProc;
IF ( loadee.unloadProcCalled )
THEN {
message: ROPE ~ Rope.Cat["The unload proc for ", moduleName, " has already been called"];
SIGNAL LoadException[type: previouslyUnloaded, message: message];
};
loadee.unloadProcCalled ¬ TRUE;
[] ¬ table.Delete[moduleName];
unloadProc[];
};
Zap:
PUBLIC
PROC [ moduleName:
ROPE ] = {
Unload[moduleName
! LoadError, LoadException => { [] ¬ table.Delete[moduleName]; CONTINUE } ];
};
BCDBuildTime: PUBLIC PROC --Loader-- [ proc: UNSAFE PROC ANY RETURNS ANY ¬ NIL ] RETURNS [ BasicTime.GMT ] = { RETURN[BasicTime.latestGMT] };
MakeProcedureResident: PUBLIC SAFE PROC [proc: PROC ANY RETURNS ANY] ~ { NULL };
MakeProcedureSwappable: PUBLIC PROC [proc: PROC ANY RETURNS ANY] ~ { NULL };
MakeGlobalFrameResident: PUBLIC SAFE PROC [proc: PROC ANY RETURNS ANY] ~ { NULL };
MakeGlobalFrameSwappable:
PUBLIC
PROC [proc:
PROC
ANY
RETURNS
ANY] ~ {
NULL };
InitLoader:
PROC = {
table ¬ SymTab.Create[];
};
Mainline code
InitLoader[];