
    <<OSMiscOpsImpl.Mesa>>
        <<Satterthwaite, June 18, 1986 9:51:31 am PDT>>
        <<Maxwell, August 11, 1983 8:23 am>>
        <<Paul Rovner, November 19, 1983 5:03 pm>>
        <<Russ Atkinson (RRA) March 6, 1985 10:05:58 pm PST>>
    <<>>
    DIRECTORY
        Basics: TYPE USING [LongNumber],
        BasicTime: TYPE USING [GMT, Now, nullGMT],
        BcdDefs: TYPE USING [VersionStamp],
        OSMiscOps: TYPE USING [Address],
        PrincOpsUtils: TYPE USING [BITXOR],
        ProcessorFace: TYPE USING [processorID],
        VM: TYPE USING [AddressForPageNumber, Allocate, Free, Interval, PageNumber, PageNumberForAddress];

    OSMiscOpsImpl: PROGRAM
        IMPORTS BasicTime, PrincOpsUtils, ProcessorFace, VM
        EXPORTS OSMiscOps = { 

    <<bulk free storage management>>
        <<>>
        intervals: LIST OF VM.Interval _ NIL;

        Pages: PUBLIC PROC[n: CARDINAL] RETURNS[base: OSMiscOps.Address] = {
            IF n = 0 THEN base _ NIL
            ELSE {
                interval: VM.Interval = VM.Allocate[count: n];
                intervals _ CONS[interval, intervals];
                base _ VM.AddressForPageNumber[interval.page]};
            RETURN};

        FreePages: PUBLIC PROC[base: OSMiscOps.Address] = {
            page: VM.PageNumber;
            last: LIST OF VM.Interval _ NIL;
            IF base = NIL THEN RETURN;
            page _ VM.PageNumberForAddress[base];
            FOR list: LIST OF VM.Interval _ intervals, list.rest UNTIL list = NIL DO
                IF list.first.page = page THEN {
                    VM.Free[list.first];
                    IF last = NIL THEN intervals _ list.rest ELSE last.rest _ list.rest;
                    EXIT};
                last _ list;
                ENDLOOP;
            };


    <<version stamp management>>

        GetNetAndHost: PROC RETURNS[net, host: CARDINAL] = {
            pId: ARRAY [0..3) OF WORD = LOOPHOLE[ProcessorFace.processorID]; 
            sum: WORD = PrincOpsUtils.BITXOR[pId[0], PrincOpsUtils.BITXOR[pId[1], pId[2]]];
            net _ sum/256;  host _ sum MOD 256};


        lastTime: BasicTime.GMT _ BasicTime.nullGMT;

        GenerateUniqueId: PUBLIC PROC RETURNS[BcdDefs.VersionStamp] = {
            net, host: CARDINAL;
            time: BasicTime.GMT;
            [net, host] _ GetNetAndHost[];
            DO
                time _ BasicTime.Now[];
                IF lastTime = BasicTime.nullGMT OR time # lastTime THEN EXIT;
                ENDLOOP;
            lastTime _ time;
            RETURN[[net: net, host: host, time: LOOPHOLE[time, CARD]]]};

    <<new version stamp operations>>

        StampSize: NAT = 3;
        Stamp: PUBLIC TYPE = RECORD[word: ARRAY [0..StampSize) OF CARDINAL];

        AddStamps: PROC[s1, s2: Stamp] RETURNS[sum: Stamp] = {
            carry: [0..1] _ 0;
            i: NAT;
            FOR i DECREASING IN [0..StampSize) DO
                t: Basics.LongNumber _ [lc[s1.word[i].LONG + s2.word[i].LONG + carry.LONG]];
                sum.word[i] _ t.lowbits;  carry _ t.highbits;
                ENDLOOP;
            FOR i DECREASING IN [0..StampSize) WHILE carry # 0 DO
                t: Basics.LongNumber _ [lc[sum.word[i].LONG + carry.LONG]];
                sum.word[i] _ t.lowbits;  carry _ t.highbits;
                ENDLOOP};

        RotateStamp: PROC[s: Stamp] RETURNS[Stamp] = INLINE {RETURN [AddStamps[s, s]]};

        MergeStamps: PUBLIC PROC [sum, item: Stamp] RETURNS [Stamp] = {
            RETURN[AddStamps[RotateStamp[sum], item]]};

        }.
