<> <> <> <> <> <> <> 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_file();.load_file" }; 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 {"%\n+extern caddr_t get_sym_val();.get_sym_val" }; ModuleNameFromFileName: PROC [ fileName: ROPE ] RETURNS [ moduleName: ROPE ] ~ { <> 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]; <> 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]; <> }; { <> 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 { <> 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[]; }; <> InitLoader[]; END.