// STATE.BCPL Save/Restore state of program // E. R. Fiala -- last edited January 20, 1977 11:37 AM // Programs using this package should not call GetFixed until after // StorageInit is called, else it will be impossible to add initialization // code at the end of the program to the free storage pool. StorageInit // should be called immediately after the Junta (if any). // The program must pass the address of the first static and last static // to StorageInit. These are obtained from the layout vector which is an // argument to the entry procedure of the program (FirstStatic = Layout!26 // and LastStatic = Layout!27). It seems wasteful to save all the // procedure statics, but this is necessary if the Overlay package is // used, and it is easier to save them all than worry about it. // All storage to be saved is acquired by the GetStorage routine, so the // state of the program consists of its statics (all of which are saved), // its page zero items (explicitly saved by calls on SaveStatics), and the // core between EndStorage at the time BeginSave is called and EndStorage // at the time SaveState is called. // Consecutive calls to GetStorage allocate blocks with decreasing // addresses. There is no header word associated with a block, so it // is impossible to selectively deallocate blocks acquired by GetStorage. // The current position at which blocks are being obtained is contained // in the static EndStorage. Hence, if you want to subsequently free // all the blocks back to some point, you have to save the value of // EndStorage at that point and restore later. If you want to manage // a region selectively, build a zone from a block acquired by // GetStorage and use the standard Alloc package. // After executing an initialization procedure, its code can be added to // the free storage pool by doing Storage = InitProc. // The static StateBlockSize must be defined elsewhere in the program // BeginSave is called to mark the current position in free storage. // All storage acquired after that time and before SaveState is called // will be saved by SaveState, in addition to StateBlock, all of the // program's statics, and all page-zero statics enumerated by calls // to SaveStatics. There is no provision for enumerating individual // blocks of storage outside the region delimited by BeginSave and // SaveState. // The first call to SaveState passes a stream argument and a program // label argument. The caller's frame and this label are remembered // for subsequent RestoreState calls. Later on the program can call // SaveState again without the label argument. This will preserve // the same items as were preserved in the original call to SaveState, // allowing the program to fire up with different initial information. // RestoreState accepts a stream argument for the file containing // information saved by SaveState. Its second argument is a flag // which should be true when RestoreState is called during program // initialization. The program can reinitialize itself during // operation by calling RestoreState with the second argument false. get "state.d" external [ // OS CallSwat; Closes; ReadBlock; WriteBlock CallersFrame; GotoLabel; Usc // Program StateBlockSize // Defined here BeginSave; SaveState; RestoreState GetStorage; GetEvenStorage; StorageLeft EndStorage; Storage // Defined here for init only NoStore; StateBlock; StatePtr ] static [ StateBlock; StatePtr; EndStorage; Storage; NoStore ] let GetStorage(Size) = valof [ EndStorage = EndStorage-Size if Usc(Storage,EndStorage) < 0 then resultis EndStorage resultis NoStore("Out of storage") ] and GetEvenStorage(Size) = (GetStorage(Size+1)+1) & 177776B and StorageLeft() = EndStorage-Storage //Mark the first location to be saved and BeginSave() be StateBlock>>State.End = EndStorage and SaveState(S,Label; numargs NA) be [ if S eq 0 then CallSwat("No stream for SaveState") if NA ge 2 do //Delimit region saved & where to resume [ StateBlock>>State.Ptr = StatePtr StateBlock>>State.CF = CallersFrame() StateBlock>>State.CL = Label StateBlock>>State.Storage = Storage StateBlock>>State.First = EndStorage ] for I = (size State/16) to StatePtr-2 by 2 do //Get static values [ StateBlock!(I+1) = rv StateBlock!I ] WriteBlock(S,StateBlock,StateBlockSize) WriteBlock(S,StateBlock>>State.FirstS,StateBlock>>State.NStats) WriteBlock(S,StateBlock>>State.First, StateBlock>>State.End - StateBlock>>State.First) Closes(S) ] and RestoreState(S,reinitFlag)be [ if S eq 0 then CallSwat("No stream for RestoreState") ReadBlock(S,StateBlock,StateBlockSize) if not reinitFlag then if EndStorage ne StateBlock>>State.End then CallSwat("Program or OS incompatible") ReadBlock(S,StateBlock>>State.FirstS,StateBlock>>State.NStats) for I = (size State/16) to StatePtr-2 by 2 do [ rv (StateBlock!I) = StateBlock!(I+1) ] EndStorage = StateBlock>>State.First Storage = StateBlock>>State.Storage StatePtr = StateBlock>>State.Ptr let WC = StateBlock>>State.End - EndStorage let N = ReadBlock(S,EndStorage,WC) if N ne WC then CallSwat("State file clobbered") Closes(S); GotoLabel(StateBlock>>State.CF,StateBlock>>State.CL,0) ]