12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337 |
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich; this module ported for the windows version, fof. *)
- MODULE Objects; (** AUTHOR "pjm, ejz, fof"; PURPOSE "Active object runtime support"; *)
- IMPORT SYSTEM, Trace, Kernel32, Machine, Modules, Heaps;
- CONST
- HandleExcp = TRUE; (* FALSE -> we asume that it is done correctly by Traps *)
- TraceVerbose = FALSE;
- StrongChecks = FALSE; defaultStackSize = 0;
- TraceOpenClose = FALSE;
- CONST
- (* Process flags *)
- Restart* = 0; (* Restart/Destroy process on exception *)
- PleaseHalt* = 10; (* Process requested to Halt itself soon *)
- Unbreakable* = 11;
- SelfTermination* = 12;
- Preempted* = 27; (* Has been preempted. *)
- Resistant* = 28; (* Can only be destroyed by itself *)
- PleaseStop* = 31; (* Process requested to Terminate or Halt itself soon *)
- InActive* = 26; (* needed to prevent processes to call finalizers while in await or lock or unlock, see Kernel.GC *)
- (** Process modes *)
- Unknown* = 0; Ready* = 1; (* for compatibility with native A2 *)
- Running* = 2; AwaitingLock* = 3; AwaitingCond* = 4; AwaitingEvent* = 5; Suspended* = 6; Terminated* = 7;
- (** Process priorities *)
- MinPriority = 0; (* only system idle processes run at this priority level *)
- Low* = 1; Normal* = 2; High* = 3; (* "user" priorities *)
- GCPriority* = 4; (* priority of garbage collector *)
- Realtime* = 5; (* reserved for interrupt handling and realtime apps, these processes are not allowed to allocate memory *)
- (* Process termination halt codes *)
- halt* = 2222;
- haltUnbreakable* = 2223;
- TYPE
- CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
- ProtectedObject = POINTER TO RECORD END; (* protected object (10000) *)
- ProcessQueue = Heaps.ProcessQueue;
- Body = PROCEDURE (self: ProtectedObject);
- Condition = PROCEDURE (slink: ADDRESS): BOOLEAN;
- EventHandler* = PROCEDURE {DELEGATE};
- RealtimeEventHandler* = PROCEDURE {DELEGATE, REALTIME};
- Timer* = POINTER TO RECORD
- next, prev : Timer;
- trigger: LONGINT;
- handler: EventHandler
- END;
- RealtimeTimer* = POINTER TO RECORD
- next, prev: RealtimeTimer;
- trigger: LONGINT;
- handler: RealtimeEventHandler
- END;
- Clock = OBJECT
- VAR h: Timer;
- ticks: LONGINT;
- hevent: Kernel32.HANDLE;
- res: Kernel32.BOOL;
- mode: LONGINT;
- process: Process;
- PROCEDURE Wakeup;
- VAR res: Kernel32.BOOL;
- BEGIN {EXCLUSIVE}
- res := Kernel32.SetEvent(hevent)
- END Wakeup;
- PROCEDURE Finalize(ptr: ANY);
- VAR res: Kernel32.BOOL;
- BEGIN
- IF hevent # 0 THEN res := Kernel32.CloseHandle(hevent); hevent := 0 END
- END Finalize;
- PROCEDURE &Init*;
- VAR fn: Heaps.FinalizerNode;
- BEGIN
- hevent := Kernel32.CreateEvent(NIL, 0, 0, NIL);
- ASSERT(hevent # 0);
- NEW(fn); fn.finalizer := SELF.Finalize; Heaps.AddFinalizer(SELF, fn)
- END Init;
- BEGIN {ACTIVE, SAFE, PRIORITY(High)}
- process := CurrentProcess();
- mode := process.mode;
- LOOP
- Machine.Acquire(Machine.Objects);
- process.mode := mode;
- LOOP
- h := event.next; (* event: head of timer event queue *)
- ticks := Kernel32.GetTickCount();
- IF (h = event) OR (h.trigger - ticks > 0) THEN EXIT END;
- event.next := h.next; event.next.prev := event; (* unlink *)
- h.next := NIL; h.prev := NIL;
- Machine.Release(Machine.Objects);
- h.handler(); (* assume handler will return promptly *)
- Machine.Acquire(Machine.Objects)
- END;
- mode := process.mode;
- process.mode := AwaitingEvent;
- Machine.Release(Machine.Objects);
- IF h = event THEN (* sentinel head of timer event queue: wait forever until a new event has been entered in queue *)
- res := Kernel32.WaitForSingleObject(hevent, MAX(LONGINT));
- ELSE
- res := Kernel32.WaitForSingleObject(hevent, h.trigger - ticks);
- END;
- END
- END Clock;
- TYPE
- Win32Event = Kernel32.HANDLE;
-
- GCContext = RECORD
- nextPos: SIZE; (* 0 to start with *)
- (*first,*) last: ARRAY 256 OF ADDRESS; (* first might be not required *)
- END;
- Process* = OBJECT(Heaps.ProcessLink)
- VAR
- rootedNext : Process; (* to prevent process to be GCed in WinAos *)
- obj-: ProtectedObject; (* associated active object *)
- state- {ALIGNED=16}: Kernel32.Context;
- condition-: Condition; (* awaited process' condition *)
- condFP-: ADDRESS; (* awaited process' condition's context *)
- mode-: LONGINT; (* process state *) (* only changed inside Objects lock ??? *)
- procID-: LONGINT; (* processor ID where running, exported for compatibilty , useless in WinAos *)
- waitingOn-: ProtectedObject; (* obj this process is waiting on (for lock or condition) *)
- id-: LONGINT; (* unique process ID for tracing *)
- flags*: SET; (* process flags *)
- priority-: LONGINT; (* process priority *)
- stackBottom: ADDRESS;
- handle-: Kernel32.HANDLE; (* handle to corresponding Windows thread *)
- body: Body;
- event: Win32Event;
- restartPC-: ADDRESS; (** entry point of body, for SAFE exception recovery *)
- restartSP-: ADDRESS; (** stack level at start of body, for SAFE exception recovery *)
- lastThreadTimes: HUGEINT; (*ALEX 2005.12.12*)
- gcContext: GCContext;
- context: ANY; (* commands contect *)
- PROCEDURE FindRoots; (* override, called while GC, replaces Threads.CheckStacks *)
- VAR sp: ADDRESS; res: Kernel32.BOOL; pc, bp: ADDRESS;
- n,adr: ADDRESS; desc {UNTRACED}: Modules.ProcedureDescPointer; p {UNTRACED}: ANY; i: SIZE;
- a0,a1, obp, osb, osbp, opc, gbp: ADDRESS;
- O: ANY; ID: LONGINT;
- mod {UNTRACED}: Modules.Module;
- proc {UNTRACED}: Modules.ProcedureDescPointer;
- modName: ARRAY 128 OF CHAR;
- contextPos: SIZE;
- BEGIN{UNCHECKED} (* avoid winapi call indirection *)
- O := obj; ID := id;
- IF (handle = 0) OR (mode = Terminated) OR (mode < Ready) (* procedure Wrapper not yet started *)
- OR (priority > High) (* stack of GC and realtime processes not traced *) THEN
- RETURN
- END;
-
- IF CurrentProcess() = SELF THEN
- sp := Machine.CurrentSP(); bp :=Machine.CurrentBP(); pc := Machine.CurrentPC();
- ELSE
- res := Kernel32.SuspendThread(handle); (* can suspend a suspended thread -- no problem at all *)
- state.ContextFlags := Kernel32.ContextControl + Kernel32.ContextInteger;
- res := Kernel32.GetThreadContext( handle, state );
- IF res = 0 THEN Trace.String("could not get thread context:"); Trace.Int(Kernel32.GetLastError(),1) END;
-
- sp := state.SP; bp := state.BP; pc := state.PC;
-
- mod := Modules.ThisModuleByAdr0(pc);
- IF mod # NIL THEN
- COPY(mod.name, modName);
- proc := Modules.FindProc(pc,mod.procTable);
- END;
-
- obp := bp; osb := stackBottom; opc := pc;
- osbp := state.BP;
- END;
-
- IF TraceProcessHook # NIL THEN
- TraceProcessHook(SELF,pc,bp,sp,stackBottom);
- END;
- contextPos := gcContext.nextPos;
-
- (* stack garbage collection *)
- IF Heaps.GCType= Heaps.HeuristicStackInspectionGC THEN
- #IF I386 THEN
- Heaps.Candidate( state.EDI ); Heaps.Candidate( state.ESI );
- Heaps.Candidate( state.EBX ); Heaps.Candidate( state.EDX );
- Heaps.Candidate( state.ECX ); Heaps.Candidate( state.EAX );
- #ELSIF AMD64 THEN
- Heaps.Candidate( state.RDI ); Heaps.Candidate( state.RSI );
- Heaps.Candidate( state.RBX ); Heaps.Candidate( state.RDX );
- Heaps.Candidate( state.RCX ); Heaps.Candidate( state.RAX );
- Heaps.Candidate( state.R9 ); Heaps.Candidate( state.R10 );
- Heaps.Candidate( state.R11 ); Heaps.Candidate( state.R12 );
- Heaps.Candidate( state.R13 ); Heaps.Candidate( state.R14 );
- Heaps.Candidate( state.R15 );
- #ELSE
- ASSERT(FALSE);
- #END
-
- IF (stackBottom # 0) & (sp # 0) THEN
- Heaps.RegisterCandidates( sp, stackBottom - sp );
- END;
- ELSIF Heaps.GCType = Heaps.MetaDataForStackGC THEN
- IF TraceVerbose THEN
- Trace.String("GC, process id = "); Trace.Int(id,1); Trace.Ln;
- END;
- LOOP
- IF (bp = NIL) OR (bp >= stackBottom) THEN EXIT END;
- IF Machine.ValidHeapAddress(pc) THEN
- (* ok, valid stack frame from A2, we can trace this *)
- ELSE
- (* no, cannot trace this Windows stack frame, we have to check if we recorded when we exited A2 previously *)
- DEC(contextPos);
- IF (contextPos >= 0) THEN
- bp := gcContext.last[contextPos];
- ELSE
- EXIT;
- END;
- END;
-
- SYSTEM.GET(bp, n);
- IF ODD(n) THEN (* procedure descriptor at bp *)
- desc := SYSTEM.VAL(Modules.ProcedureDescPointer, n-1);
- IF desc # NIL THEN
- IF TraceVerbose THEN
- WriteType(desc); Trace.Ln;
- END;
- a0 := ADDRESSOF(desc.offsets);
- a1 := SYSTEM.VAL(ADDRESS, desc.offsets);
- ASSERT(a0+SIZEOF(ADDRESS)=a1,54321);
- FOR i := 0 TO LEN(desc.offsets)-1 DO
- adr := bp + desc.offsets[i]; (* pointer at offset *)
- SYSTEM.GET(adr, p); (* load pointer *)
- IF p # NIL THEN
- Heaps.Mark(p);
- END;
- END;
- END;
- SYSTEM.GET(bp + 2*SIZEOF(ADDRESS), pc);
- SYSTEM.GET(bp + SIZEOF(ADDRESS), bp);
- ELSE (* classical stack frame without procedure descriptor *)
- SYSTEM.GET(bp + SIZEOF(ADDRESS), pc);
- bp := n;
- END;
- END;
- (* ASSERT((bp = stackBottom) OR (bp=0) ,12345); can be violated when coming from windows *)
- END;
-
- IF (CurrentProcess() # SELF) (* & (mode # Suspended) *) THEN
- res := Kernel32.ResumeThread(handle);
- ASSERT(res # -1);
- END;
- END FindRoots;
-
- END Process;
- TYPE
- ExceptionHandler* = PROCEDURE( VAR context: Kernel32.Context;
- VAR excpRec: Kernel32.ExceptionRecord;
- VAR handled: BOOLEAN);
- GCStatusExt = OBJECT(Heaps.GCStatus)
-
- (* called from Heaps.InvokeGC, i.e. this is a hidden upcall. However, it is necessary to take the Machine.Objects lock here since writing
- the set of variables here must not be interrupted, i.e. atomic writing of the set of variables is absolutely necessary. They system may hang
- if the lock is not taken. *)
- PROCEDURE SetgcOngoing(value: BOOLEAN);
- VAR p: Heaps.ProcessLink; cur, r: Process; res: Kernel32.BOOL; num: LONGINT; time: LONGINT;
- BEGIN (* serialize writers *)
- IF value THEN
- (* Low, Medium or High priority process calls this *)
- time := Kernel32.GetTickCount();
- Machine.Acquire(Machine.Objects);
- Machine.Acquire(Machine.Heaps); (* to protect agains concurrent LazySweep *)
- r := CurrentProcess();
- num := 0;
- p := ready.head;
- WHILE p # NIL DO
- cur := p(Process);
- IF ((cur.mode = Ready) OR (cur.mode = Running)) & (cur.priority <= High) & (cur # r) THEN
- res := Kernel32.SuspendThread(cur.handle);
- ASSERT(res >= 0);
- cur.mode := Suspended
- ELSE INC(num);
- END;
- p := p.next
- END;
- Heaps.CollectGarbage(Modules.root);
- p := ready.head;
- WHILE (p # NIL) DO
- cur := p(Process);
- (* only suspended and awaiting processes of ready queue are resumed *)
- IF cur.mode = Suspended THEN
- res := Kernel32.ResumeThread(cur.handle);
- ASSERT(res >= 0);
- cur.mode := Running
- END;
- p := p.next
- END;
- Machine.Release(Machine.Heaps);
- Machine.Release(Machine.Objects);
- time := Kernel32.GetTickCount()-time;
- IF Heaps.trace THEN Trace.String("GC Called -- duration "); Trace.Int(time,0); Trace.String(" ms."); Trace.Ln END;
- IF finalizerCaller # NIL THEN finalizerCaller.Activate() END;
- END;
- END SetgcOngoing;
- END GCStatusExt;
- FinalizedCollection* = OBJECT
- PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
- BEGIN HALT(301) END RemoveAll;
- END FinalizedCollection;
- FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
- c*: FinalizedCollection (* base type for collection containing object *)
- END;
- FinalizerCaller = OBJECT (* separate active object that calls finalizers *)
- VAR n: Heaps.FinalizerNode;
- event: Kernel32.HANDLE;
- process: Process;
- PROCEDURE &Init;
- BEGIN
- event := Kernel32.CreateEvent( NIL, Kernel32.False (* automatic *), Kernel32.False, NIL );
- ASSERT(event # 0);
- END Init;
- PROCEDURE Wait;
- VAR res: Kernel32.BOOL; mode: LONGINT;
- BEGIN
- mode := process.mode;
- process.mode := AwaitingEvent;
- res := Kernel32.WaitForSingleObject(event, Kernel32.Infinite);
- ASSERT(res = Kernel32.WaitObject0);
- process.mode := mode;
- END Wait;
- PROCEDURE Activate;
- VAR res: Kernel32.BOOL;
- BEGIN
- res := Kernel32.SetEvent(event);
- END Activate;
- BEGIN {ACTIVE, SAFE, PRIORITY(High)}
- process := CurrentProcess();
- LOOP
- Wait;
- LOOP
- n := Heaps.GetFinalizer();
- IF n = NIL THEN EXIT END;
- IF n IS FinalizerNode THEN
- n( FinalizerNode ).c.RemoveAll( n.objStrong ) (* remove it if it is not removed yet *)
- END;
- IF n.finalizer # NIL THEN
- n.finalizer( n.objStrong ) (* may acquire locks *)
- END
- END
- END;
- END FinalizerCaller;
- VAR
- awc-, awl-: LONGINT;
- oberonLoop*: ANY; (* Oberon Loop Process temporary workaround for Threads.oberonLoop *)
- break: ARRAY 16 OF CHAR;
- terminateProc: PROCEDURE;
- ready: ProcessQueue; (* contains running processes in this implementation *)
- numberOfProcessors: LONGINT; (* cached value of Machine.NumberOfProcessors() *)
- finalizerCaller: FinalizerCaller; (* active object for finalizer process, regarded as aprt of GC *)
- event: Timer; (* list of events *)
- clock: Clock;
- tlsIndex: LONGINT;
- nProcs: LONGINT;
- excplock: Kernel32.CriticalSection; exceptionhandler: ExceptionHandler;
- (* Set the current process' priority. *)
- PROCEDURE SetPriority*( priority: LONGINT );
- VAR r: Process; prio: LONGINT; res: Kernel32.BOOL;
- BEGIN
- ASSERT((priority >= Low) & (priority <= Realtime)); (* priority in bounds *)
- r := CurrentProcess(); r.priority := priority;
- CASE priority OF
- MinPriority:
- prio := Kernel32.ThreadPriorityIdle
- | Low:
- prio := Kernel32.ThreadPriorityBelowNormal
- | High:
- prio := Kernel32.ThreadPriorityAboveNormal
- | GCPriority, Realtime:
- prio := Kernel32.ThreadPriorityTimeCritical
- ELSE (* Normal *)
- prio := Kernel32.ThreadPriorityNormal
- END;
- res := Kernel32.SetThreadPriority( r.handle, prio );
- ASSERT(r.handle # 0);
- ASSERT(res # 0)
- END SetPriority;
- (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
- PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
- VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
- BEGIN
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
- ASSERT(hdr IS Heaps.ProtRecBlock);
- Machine.Acquire(Machine.Objects);
- res := (hdr.lockedBy = ActiveObject());
- Machine.Release(Machine.Objects);
- RETURN res
- END LockedByCurrent;
- PROCEDURE Yield*;
- BEGIN
- Kernel32.Sleep(0)
- END Yield;
- (** Return current process. (DEPRECATED, use ActiveObject) *)
- PROCEDURE CurrentProcess*( ): Process;
- BEGIN{UNCHECKED} (* makes sure that Enter and Leave are not emitted *)
- RETURN SYSTEM.VAL(Process, Kernel32.TlsGetValue(tlsIndex));
- END CurrentProcess;
- PROCEDURE CurrentContext*(): ANY;
- VAR p: Process;
- BEGIN
- p := CurrentProcess();
- IF p # NIL THEN RETURN p.context
- ELSE RETURN NIL
- END;
- END CurrentContext;
- PROCEDURE SetContext*(context: ANY);
- VAR p: Process;
- BEGIN
- p := CurrentProcess();
- IF p # NIL THEN p.context := context END;
- END SetContext;
- (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
- PROCEDURE GetStackBottom*(p: Process): ADDRESS;
- BEGIN
- RETURN p.stackBottom
- END GetStackBottom;
- (** Return the active object currently executing. *)
- PROCEDURE ActiveObject* (): ANY;
- VAR r: Process;
- BEGIN
- r := SYSTEM.VAL(Process, Kernel32.TlsGetValue(tlsIndex));
- RETURN r.obj
- END ActiveObject;
- (** Return the ID of the active currently executing process. *)
- PROCEDURE GetProcessID* (): LONGINT;
- VAR r: Process;
- BEGIN
- r := SYSTEM.VAL (Process, Kernel32.TlsGetValue( tlsIndex ));
- RETURN r.id
- END GetProcessID;
- (* Get a process from a queue (NIL if none). Caller must hold lock for specific queue. *)
- PROCEDURE Get(VAR queue: ProcessQueue; VAR new: Process);
- VAR t: Heaps.ProcessLink;
- BEGIN
- t := queue.head;
- IF t = NIL THEN (* zero elements in queue *)
- (* skip *)
- ELSIF t = queue.tail THEN (* one element in queue *)
- queue.head := NIL; queue.tail := NIL (* {(t.next = NIL) & (t.prev = NIL)} *)
- ELSE (* more than one element in queue *)
- queue.head := t.next; t.next := NIL; queue.head.prev := NIL
- END;
- ASSERT((t = NIL) OR (t.next = NIL ) & (t.prev = NIL)); (* temp strong check *)
- IF t = NIL THEN
- new := NIL
- ELSE
- ASSERT(t IS Process);
- new := t(Process)
- END
- END Get;
- (* Put a process in a queue. Caller must hold lock for specific queue. *)
- (* If t was running, be careful to protect Put and the subsequent SwitchTo with the ready lock. *)
- PROCEDURE Put(VAR queue: ProcessQueue; t: Process);
- BEGIN (* {t # NIL & t.next = NIL & t.prev = NIL} *)
- IF StrongChecks THEN
- ASSERT((t.next = NIL) & (t.prev = NIL))
- END;
- t.next := NIL; t.prev := NIL; (* ug *)
- IF queue.head = NIL THEN (* queue empty *)
- queue.head := t
- ELSE (* queue not empty *)
- queue.tail.next := t; t.prev := queue.tail
- END;
- queue.tail := t
- END Put;
- PROCEDURE {WINAPI} ExcpFrmHandler( CONST exceptionPointers: Kernel32.ExceptionPointers): Kernel32.DWORD ;
- VAR m: Modules.Module; eip, ebp, stack: ADDRESS; pc, handler, fp, sp: ADDRESS; handled: BOOLEAN; t: Process;
- BEGIN
- handled := FALSE;
- Kernel32.EnterCriticalSection( excplock );
- (*
- fof: commenting this resolved a problem with multiple traps that a are catched with FINALLY statements in Windows Vista
- in Windows XP not necessary if Kernel32.SetThreadContext is not used (better to return gracefully from this handler)
- SetCurrent(excpFrame);
- *)
- t := CurrentProcess();
- IF exceptionhandler = NIL THEN
- Trace.StringLn ( "Objects: No exception handler installed" );
- IF HandleExcp THEN
- Trace.String( "EXCEPTION " ); Trace.Address(exceptionPointers.exception.ExceptionCode);
- Trace.String( " at " ); Trace.Address(exceptionPointers.exception.ExceptionAddress);
- #IF I386 THEN
- Trace.Ln(); Trace.String( "EAX " ); Trace.Hex( exceptionPointers.context.EAX, 1 );
- Trace.String( " EBX " ); Trace.Hex( exceptionPointers.context.EBX, 1 ); Trace.Ln();
- Trace.String( "ECX " ); Trace.Hex( exceptionPointers.context.ECX, 1 ); Trace.String( " EDX " );
- Trace.Hex( exceptionPointers.context.EDX, 1 ); Trace.Ln(); Trace.String( "EDI " );
- Trace.Hex( exceptionPointers.context.EDI, 1 ); Trace.String( " ESI " );
- Trace.Hex( exceptionPointers.context.ESI, 1 ); Trace.Ln();
- #ELSIF AMD64 THEN
- Trace.Ln(); Trace.String( "RAX " ); Trace.Address(exceptionPointers.context.RAX);
- Trace.String( " RBX " ); Trace.Address(exceptionPointers.context.RBX); Trace.Ln();
- Trace.String( "RCX " ); Trace.Address(exceptionPointers.context.RCX); Trace.String( " RDX " );
- Trace.Address(exceptionPointers.context.RDX); Trace.Ln(); Trace.String( "RDI " );
- Trace.Address(exceptionPointers.context.RDI); Trace.String( " RSI " );
- Trace.Address(exceptionPointers.context.RSI); Trace.Ln();
-
- Trace.String( "R8 " ); Trace.Address(exceptionPointers.context.R8);
- Trace.String( " R9 " ); Trace.Address(exceptionPointers.context.R9); Trace.Ln();
- Trace.String( "R10 " ); Trace.Address(exceptionPointers.context.R10);
- Trace.String( " R11 " ); Trace.Address(exceptionPointers.context.R11); Trace.Ln();
- Trace.String( "R12 " ); Trace.Address(exceptionPointers.context.R12);
- Trace.String( " R13 " ); Trace.Address(exceptionPointers.context.R13); Trace.Ln();
- Trace.String( "R14 " ); Trace.Address(exceptionPointers.context.R14);
- Trace.String( " R15 " ); Trace.Address(exceptionPointers.context.R15); Trace.Ln();
- Trace.Ln;
- #ELSE
- -- UNIMPLEMENTED --
- #END
-
- Trace.String( "BP " );
- Trace.Address(exceptionPointers.context.BP); Trace.String( " SP " );
- Trace.Address(exceptionPointers.context.SP); Trace.Ln(); Trace.String( "PC " );
- Trace.Address(exceptionPointers.context.PC); Trace.Ln();
-
-
- Trace.Ln();
-
- eip := exceptionPointers.exception.ExceptionAddress; ebp := exceptionPointers.context.BP;
- IF eip = 0 THEN SYSTEM.GET( exceptionPointers.context.SP, eip ) END;
- stack := t.stackBottom;
- LOOP
- Trace.String( "at ebp= " ); Trace.Address(ebp); Trace.String( "H : " );
- m := Modules.ThisModuleByAdr( eip );
- IF m # NIL THEN
- Trace.String( m.name ); Trace.String( " " );
- Trace.Address(eip - SYSTEM.VAL( LONGINT, ADDRESSOF( m.code[0] ) ));
- ELSE Trace.String( "EIP " ); Trace.Address(eip)
- END;
- Trace.Ln();
- IF (ebp # 0) & (ebp < stack) THEN (* if ebp is 0 in first frame *)
- SYSTEM.GET( ebp + SIZEOF(ADDRESS), eip ); (* return addr from stack *)
- SYSTEM.GET( ebp, ebp ); (* follow dynamic link *)
- ELSE EXIT
- END
- END;
- Trace.Ln();
-
- handled := FALSE; fp := exceptionPointers.context.BP; sp := exceptionPointers.context.SP;
- pc := exceptionPointers.context.PC; handler := Modules.GetExceptionHandler( pc );
- IF handler # -1 THEN (* Handler in the current PAF *)
- exceptionPointers.context.PC := handler; handled := TRUE;
- (*SetTrapVariable(pc, fp); SetLastExceptionState(exc)*)
- ELSE
- WHILE (fp # 0) & (handler = -1) DO
- SYSTEM.GET( fp + SIZEOF(ADDRESS), pc );
- pc := pc - 1; (* CALL instruction, machine dependant!!! *)
- handler := Modules.GetExceptionHandler( pc );
- sp := fp; (* Save the old framepointer into the stack pointer *)
- SYSTEM.GET( fp, fp ) (* Unwind PAF *)
- END;
- IF handler = -1 THEN handled := FALSE;
- ELSE
- exceptionPointers.context.PC := handler; exceptionPointers.context.BP := fp; exceptionPointers.context.SP := sp;
- (* SetTrapVariable(pc, fp); SetLastExceptionState(exc);*)
- handled := TRUE
- END
- END;
- ELSE Trace.StringLn ( "Warning: FINALLY statement cannot be treated !" );
- END
- ELSE exceptionhandler(exceptionPointers.context^, exceptionPointers.exception^,handled );
- END;
- IF ~handled THEN
- exceptionPointers.context.PC := t.restartPC ;
- exceptionPointers.context.SP := t.restartSP;
- exceptionPointers.context.BP := t.stackBottom;
- ELSIF TraceVerbose THEN Trace.StringLn ( "trying to jump to FINALLY pc..." );
- END;
- Kernel32.LeaveCriticalSection( excplock );
- IF TraceVerbose THEN
- Machine.Acquire (Machine.TraceOutput);
- Trace.String( "recover process; pc=" ); Trace.Address( exceptionPointers.context.PC );
- Trace.String( "; sp= " ); Trace.Address( exceptionPointers.context.SP); Trace.String( "; bp= " );
- Trace.Address( exceptionPointers.context.BP); Trace.Ln;
- Machine.Release (Machine.TraceOutput);
- END;
- RETURN Kernel32.ExceptionContinueExecution; (* sets thread context and continues where specified in context *)
- END ExcpFrmHandler;
- PROCEDURE RemoveExcpFrm( VAR excpfrm: Kernel32.ExcpFrm );
- VAR this: Kernel32.ExcpFrmPtr;
- BEGIN
- Kernel32.RemoveVectoredContinueHandler(ExcpFrmHandler);
- END RemoveExcpFrm;
- PROCEDURE InstallExcpFrm( VAR excpfrm: Kernel32.ExcpFrm );
- BEGIN
- Kernel32.AddVectoredContinueHandler(1, ExcpFrmHandler);
- END InstallExcpFrm;
- PROCEDURE InQueue( queue: ProcessQueue; t: Process ): BOOLEAN;
- VAR p: Heaps.ProcessLink;
- BEGIN
- p := queue.head;
- WHILE (p # NIL ) & (p # t) DO p := p.next; END;
- RETURN (p = t);
- END InQueue;
- (* Remove a process from a queue that contains it. Caller must hold lock for specific queue. *)
- (* Not intended for frequent use. *)
- (* does not check if queue contained t ! *)
- PROCEDURE Remove( VAR queue: ProcessQueue; t: Process );
- BEGIN
- IF StrongChecks THEN
- ASSERT(InQueue(queue, t));
- ASSERT(t # NIL);
- END;
- IF t.prev # NIL THEN t.prev.next := t.next END;
- IF t.next # NIL THEN t.next.prev := t.prev END;
- IF t = queue.head THEN queue.head := t.next END;
- IF t = queue.tail THEN queue.tail := t.prev END;
- ASSERT((queue.head = NIL) OR (queue.head.prev = NIL) & (queue.tail.next = NIL));
- t.prev := NIL; t.next := NIL
- END Remove;
- PROCEDURE WriteType(obj: ANY);
- VAR type: LONGINT;
- BEGIN
- IF obj = NIL THEN Trace.String(" > NIL");
- ELSE
- Trace.String(" > "); SYSTEM.GET(SYSTEM.VAL(LONGINT, obj) + Heaps.TypeDescOffset, type);
- Heaps.WriteType(type);
- END;
- END WriteType;
- PROCEDURE terminate( t: Process );
- VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: Kernel32.BOOL; shutdown: BOOLEAN;
- BEGIN
- IF t = NIL THEN RETURN END;
- (* see Objects.TerminateThis *)
- Machine.Acquire( Machine.Objects );
- IF TraceVerbose OR TraceOpenClose THEN
- Machine.Acquire (Machine.TraceOutput);
- Trace.String( "Terminating process " ); Trace.Int( t.id, 1 ); WriteType( t.obj ); Trace.Ln;
- Machine.Release (Machine.TraceOutput);
- END;
- IF (t.mode = Ready) OR (t.mode = Running) THEN Remove( ready, t );
- ELSIF t.mode = AwaitingLock THEN
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, t.waitingOn) + Heaps.HeapBlockOffset, hdr);
- ASSERT(hdr IS Heaps.ProtRecBlock);
- Remove( hdr.awaitingLock, t ); Machine.Release( Machine.Objects );
- HALT( 97 )
- ELSIF t.mode = AwaitingCond THEN
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, t.waitingOn) + Heaps.HeapBlockOffset, hdr);
- ASSERT(hdr IS Heaps.ProtRecBlock);
- Remove( hdr.awaitingCond, t ); Machine.Release( Machine.Objects );
- HALT( 98 )
- ELSE Machine.Release( Machine.Objects );
- HALT( 99 )
- END;
- t.mode := Terminated; (* a process can also be "terminated" if the queue containing it is garbage collected *)
- t.stackBottom := 0; t.state.SP := 0;
- t.restartPC := 0;
- IF t.event # 0 THEN res := Kernel32.CloseHandle( t.event ); t.event := 0 END;
- DEC( nProcs ); shutdown := (nProcs = 0);
- Machine.Release( Machine.Objects );
- IF shutdown THEN
- Trace.StringLn ( " Objects: shutdown" ); Modules.Shutdown( -1 );
- Kernel32.ExitProcess( 0 )
- END
- END terminate;
- PROCEDURE {WINAPI} Wrapper( lpParameter: ANY ): LONGINT;
- VAR t: Process; obj: ProtectedObject; res: Kernel32.BOOL; bp,sp: ADDRESS;
- excpfrm: Kernel32.ExcpFrm;
- BEGIN
- (* it may happen that the garbage collector runs right here and ignores this procedure.
- This is not a problem since lpParameter (being a reference to a process) is protected by the process lists *)
- Machine.Acquire(Machine.Objects);
- res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(LONGINT, lpParameter));
- t := lpParameter(Process); obj := t.obj;
- ASSERT(res # 0);
- SetPriority(t.priority);
- bp := Machine.CurrentBP();
- sp := Machine.CurrentSP();
- t.restartSP := sp;
- t.stackBottom := bp;
- IF t.restartPC = SYSTEM.VAL(ADDRESS, terminateProc) THEN DEC(t.restartSP, SIZEOF(ADDRESS))
- ELSE DEC(t.restartSP, 2*SIZEOF(ADDRESS))
- END;
- IF TraceVerbose THEN
- Machine.Acquire(Machine.TraceOutput);
- Trace.String("New process; restartPC= "); Trace.Address(t.restartPC);
- Trace.String("; stackBottom= ");
- Trace.Address(t.stackBottom); Trace.Ln;
- Machine.Release(Machine.TraceOutput);
- END;
- t.mode := Running;
- (* now gc is enabled for this process stack *)
- Machine.Release(Machine.Objects);
- (* loop all processes that the GC did not see during process suspending because they were in the very moment being generated (just before the locked section) *)
- (*! should not be necessary any more as GC runs immediately and without scheduling decisions
- WHILE (gcActivity # NIL) & (gcActivity.process # NIL) & (gcActivity.process.mode = Running) DO END;
- *)
- t.body(obj);
- terminate(t);
- RemoveExcpFrm(excpfrm);
- RETURN 0
- END Wrapper;
- PROCEDURE FinalizeProcess(t: ANY);
- VAR p: Process; res: Kernel32.BOOL;
- BEGIN
- p := t(Process);
- IF TraceVerbose THEN
- Machine.Acquire (Machine.TraceOutput);
- Trace.String("Finalizing Process"); Trace.Int(p.id, 1);
- WriteType(p.obj); Trace.Ln;
- Machine.Release (Machine.TraceOutput);
- END;
- IF p.mode # Terminated THEN
- IF p.mode = AwaitingLock THEN DEC(awl);
- ELSIF p.mode = AwaitingCond THEN DEC(awc);
- END;
- (* no reference to the object any more *)
- Trace.String ("Closing unreferenced process"); (*Trace.Int(p.mode,20); Trace.Int( p.id, 20 ); *) Trace.Ln; (* Trace.Ln *)
- (* this usually happens, when an objects process waits on its own objtec and no reference exists any more. Then the object is discarded and
- consequently the process is unreferenced (except in the object). This cannot happen when there are still other references on the object.
- example:
- TYPE
- Object= OBJECT VAR active: BOOLEAN; BEGIN{ACTIVE} active := FALSE; AWAIT(active) END Object;
- VAR o: Object;
- BEGIN NEW(o);
- END;
- *)
- END;
- p.mode := Terminated; (* fof for GC problem *)
- IF p.handle # 0 THEN
- res := Kernel32.CloseHandle(p.handle); p.handle := 0
- END
- END FinalizeProcess;
- PROCEDURE TerminateProc;
- BEGIN
- terminate(CurrentProcess());
- Kernel32.ExitThread(0);
- Kernel32.Sleep(999999); (* wait until dependent threads terminated *)
- END TerminateProc;
- (* Allocate a new process associated with "obj". Must be outside lock region, because of potential GC. *)
- PROCEDURE NewProcess(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject; VAR new: Process);
- VAR t,r: Process; fn: Heaps.FinalizerNode;
- BEGIN
- NEW(t);
- t.gcContext.nextPos := 0;
- t.context := CurrentContext(); (* inherit context from parent process *)
- t.handle := 0;
- IF priority = 0 THEN (* no priority specified *)
- r := CurrentProcess();
- t.priority := r.priority (* inherit priority of creator *)
- ELSIF priority > 0 THEN (* positive priority specified *)
- t.priority := priority
- ELSE (* negative priority specified (only for Idle process) *)
- t.priority := MinPriority
- END;
- NEW(fn); (* implicit call Heaps.NewRec -> might invoke GC *)
- Machine.Acquire(Machine.Objects);
- t.next := NIL; t.prev := NIL; t.rootedNext := NIL;
- t.waitingOn := NIL; t.flags := flags; t.obj := obj; t.mode := Unknown;
- t.body := body; t.event := 0; fn.finalizer := FinalizeProcess;
- Heaps.AddFinalizer(t, fn);
- IF Restart IN flags THEN (* restart object body *)
- t.restartPC := SYSTEM.VAL(ADDRESS, body);
- ELSE (* terminate process *)
- t.restartPC := SYSTEM.VAL(ADDRESS, terminateProc);
- END;
-
- t.handle := Kernel32.CreateThread(0, defaultStackSize, Wrapper, t, {}, t.id);
- IF TraceVerbose OR TraceOpenClose THEN
- Machine.Acquire(Machine.TraceOutput);
- Trace.String("NewProcess: " ); Trace.Int(t.id, 1); WriteType(obj); Trace.Ln;
- Machine.Release(Machine.TraceOutput);
- END;
- ASSERT(t.handle # 0);
- new := t;
- END NewProcess;
- (* Create the process associated with an active object (kernel call). *)
- PROCEDURE CreateProcess*(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject);
- VAR t : Process; heapBlock {UNTRACED}: Heaps.HeapBlock;
- BEGIN
- ASSERT(priority >= 0, 1000); ASSERT(priority <=Realtime, 1001);
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, heapBlock);
-
- ASSERT(heapBlock IS Heaps.ProtRecBlock); (* protected object *)
- IF Restart IN flags THEN INCL(flags, Resistant) END; (* SAFE => Restart & Resistant *)
- NewProcess(body, priority, flags, obj, t); INC(nProcs); (* acquires Machine.Objects lock *)
- t.mode := Ready; Put(ready, t);
- Machine.Release(Machine.Objects);
- END CreateProcess;
- (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
- too early. *)
- PROCEDURE Lock*(obj: ProtectedObject; exclusive: BOOLEAN );
- VAR hdr {UNTRACED}: Heaps.ProtRecBlock; r: Process; res: WORD;
- BEGIN (* {called from user level} *)
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
- IF StrongChecks THEN
- ASSERT(hdr IS Heaps.ProtRecBlock); (* protected object *)
- ASSERT(exclusive) (* shared not implemented yet *)
- END;
- r := CurrentProcess();
- IF StrongChecks THEN
- ASSERT(hdr # NIL, 1001);
- ASSERT(r # NIL, 1002);
- END;
- Machine.Acquire(Machine.Objects);
- IF hdr.count = 0 THEN (* not locked *)
- hdr.count := -1; hdr.lockedBy := r;
- Machine.Release(Machine.Objects)
- ELSE (* already locked *)
- IF hdr.lockedBy = r THEN
- Machine.Release(Machine.Objects);
- HALT(2203) (* nested locks not allowed *)
- END;
- ASSERT(r.waitingOn = NIL); (* sanity check *)
- Remove(ready, r);
- IF r.event = 0 THEN
- r.event := Kernel32.CreateEvent( NIL, Kernel32.False (* auto *), Kernel32.False, NIL ); (* auto reset event with initial state = reset *)
- ASSERT ( r.event # 0, 1239 );
- END;
- r.waitingOn := obj; r.mode := AwaitingLock;
- Put(hdr.awaitingLock, r); INC(awl);
- Machine.Release(Machine.Objects);
- res := Kernel32.WaitForSingleObject(r.event, Kernel32.Infinite); (* block execution *)
- ASSERT(res = Kernel32.WaitObject0);
- IF StrongChecks THEN
- ASSERT(hdr.lockedBy = r); (* at this moment only this process can own the lock and only this process can release it*)
- END;
- END
- END Lock;
- (* Find the first true condition from the queue and remove it. Assume the object is currently locked. *)
- PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
- VAR first, cand: Process;
- BEGIN
- Get( q, first );
- IF first.condition( first.condFP ) THEN RETURN first END;
- Put( q, first );
- WHILE q.head # first DO
- Get( q, cand );
- IF cand.condition( cand.condFP ) THEN RETURN cand END;
- Put( q, cand )
- END;
- RETURN NIL
- END FindCondition;
- (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
- too early. *)
- PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
- VAR hdr {UNTRACED}: Heaps.ProtRecBlock; t, c: Process; res: WORD;
- BEGIN
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
- IF StrongChecks THEN
- ASSERT(hdr IS Heaps.ProtRecBlock) (* protected object *)
- END;
- ASSERT(hdr.count = -1); (* exclusive locked *)
- Machine.Acquire(Machine.Objects);
- IF hdr.awaitingCond.head # NIL THEN (* evaluate the waiting conditions *)
- (* we are holding the lock, so the queue can not change (to do: except in TerminateThis) *)
- c := FindCondition(hdr.awaitingCond); (* interrupts should be on during this call *)
- ELSE
- c := NIL
- END;
- IF c = NIL THEN (* no true condition found, check the lock queue *)
- Get(hdr.awaitingLock, t);
- IF t # NIL THEN
- hdr.lockedBy := t;
- t.waitingOn := NIL;
- ELSE
- hdr.lockedBy := NIL; hdr.count := 0
- END
- ELSE (* true condition found, transfer the lock *)
- c.waitingOn := NIL; hdr.lockedBy := c;
- t := NIL
- END;
- IF c # NIL THEN
- Put(ready, c); c.mode := Running; DEC(awc);
- res := Kernel32.SetEvent(c.event);
- ASSERT (res # 0, 1001);
- ELSIF t # NIL THEN
- Put(ready, t); t.mode := Running; DEC(awl);
- res := Kernel32.SetEvent(t.event);
- ASSERT (res # 0, 1002);
- END;
- Machine.Release( Machine.Objects )
- END Unlock;
- (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
- too early. *)
- PROCEDURE Await*( cond: Condition; slink: LONGINT; obj: ProtectedObject; flags: SET );
- VAR hdr {UNTRACED}: Heaps.ProtRecBlock; r, c, t: Process; res: WORD;
- BEGIN
- IF 1 IN flags THEN (* compiler did not generate IF *)
- IF cond(slink) THEN
- RETURN (* condition already true *)
- END
- END;
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
- IF StrongChecks THEN
- ASSERT(hdr IS Heaps.ProtRecBlock) (* protected object *)
- END;
- r := CurrentProcess();
- Machine.Acquire(Machine.Objects);
- IF hdr.lockedBy = r THEN (* current process holds exclusive lock *)
- IF StrongChecks THEN ASSERT(hdr.count = -1) END; (* exclusive locked *)
- IF hdr.awaitingCond.head # NIL THEN (* evaluate the waiting conditions *)
- (* we are holding the lock, so the queue can not change (to do: except in TerminateThis) *)
- c := FindCondition(hdr.awaitingCond) (* interrupts should be on during this call *)
- ELSE
- c := NIL
- END;
- IF c = NIL THEN
- Get(hdr.awaitingLock, t);
- IF t = NIL THEN (* none waiting - remove lock *)
- hdr.count := 0; hdr.lockedBy := NIL;
- ELSE (* transfer lock to first waiting process *)
- IF StrongChecks THEN ASSERT(t.mode = AwaitingLock) END;
- t.waitingOn := NIL;
- hdr.lockedBy := t;
- END;
- ELSE
- c.waitingOn := NIL; hdr.lockedBy := c;
- t := NIL;
- END;
- ELSE (* no lock, or some other process may hold the lock, but that's the user's indaba (may be monotonic condition) *)
- Machine.Release(Machine.Objects);
- HALT( 2204 ) (* await must be exclusive region *)
- END;
- r.condition := cond; r.condFP := slink;
- r.waitingOn := obj; r.mode := AwaitingCond;
- Remove(ready, r);
- IF r.event = 0 THEN
- r.event := Kernel32.CreateEvent( NIL, Kernel32.False (* auto *), Kernel32.False, NIL ); (* auto-reset event with initial state = reset *)
- ASSERT ( r.event # 0, 1239 );
- END;
- IF c # NIL THEN
- DEC(awc); Put(ready, c); c.mode := Running;
- res := Kernel32.SetEvent(c.event); (* restart execution *)
- ASSERT(res # 0, 1002);
- END;
- IF t # NIL THEN
- DEC(awl); Put(ready, t); t.mode := Running;
- res := Kernel32.SetEvent( t.event ); (* restart execution *)
- ASSERT(res # 0, 1003);
- END;
- Put(hdr.awaitingCond, r); INC(awc);
- Machine.Release(Machine.Objects);
- res := Kernel32.WaitForSingleObject(r.event, Kernel32.Infinite); (* block execution *)
- ASSERT(res = Kernel32.WaitObject0);
- IF StrongChecks THEN
- ASSERT(cond(slink));
- ASSERT(hdr.lockedBy = r) (* lock held again *)
- END
- END Await;
- PROCEDURE Break*( t: Process );
- CONST MaxTry = 50;
- VAR mod: Modules.Module; try: LONGINT; retBOOL: Kernel32.BOOL; (* Dan 09.11.05 *)
- PROCEDURE SafeForBreak( mod: Modules.Module ): BOOLEAN;
- BEGIN
- Trace.String( "Safe for break?: " );
- IF mod # NIL THEN
- Trace.StringLn ( mod.name );
- IF (mod.name = "Trace") OR (mod.name = "Machine") OR
- (mod.name = "Heaps") OR (mod.name = "Modules") OR
- (mod.name = "Objects") OR (mod.name = "Kernel") THEN
- Trace.StringLn ( " - no" ); RETURN FALSE
- ELSE Trace.StringLn ( " - yes" ); RETURN TRUE
- END
- ELSE Trace.StringLn ( "unknown module" ); RETURN FALSE
- END
- END SafeForBreak;
- BEGIN
- IF CurrentProcess() # t THEN
- Machine.Acquire( Machine.Objects );
- LOOP
- retBOOL := Kernel32.SuspendThread( t.handle );
- t.state.ContextFlags := Kernel32.ContextControl;
- retBOOL := Kernel32.GetThreadContext( t.handle, t.state );
- mod := Modules.ThisModuleByAdr( t.state.PC ); Trace.String( "Objects Break at adr: " );
- Trace.Int( t.state.PC, 5 ); Trace.Ln;
- IF mod # NIL THEN
- Trace.String( "In module: " ); Trace.StringLn ( mod.name );
- END;
- IF ~SafeForBreak( mod ) (* we do not break Kernel modules *) THEN
- retBOOL := Kernel32.ResumeThread( t.handle ); INC( try );
- IF try > MaxTry THEN
- Trace.StringLn ( "Threads.Break: failed " );
- Machine.Release( Machine.Objects );
- RETURN
- END
- ELSE EXIT
- END;
- END;
- (* push cont.Eip *) break[0] := 68X;
- SYSTEM.MOVE( ADDRESSOF( t.state.PC ), ADDRESSOF( break[1] ), 4 );
- (* push ebp *) break[5] := 055X;
- (* mov ebp, esp *) break[6] := 08BX; break[7] := 0ECX;
- (* push 13 *) break[8] := 06AX; break[9] := 0DX;
- (* int 3 *) break[10] := 0CCX;
- (* mov esp, ebp *) break[11] := 08BX; break[12] := 0E5X;
- (* pop ebp *) break[13] := 05DX;
- (* ret *) break[14] := 0C3X; t.state.PC := ADDRESSOF( break[0] );
- retBOOL := Kernel32.SetThreadContext( t.handle, t.state );
- retBOOL := Kernel32.ResumeThread( t.handle ); (* INC( Kernel.GClevel ); *)
- Machine.Release( Machine.Objects );
- ELSE HALT( 99 )
- END;
- END Break;
- (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
- PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
- BEGIN
- terminate(t);
- END TerminateThis;
- PROCEDURE Terminate*;
- BEGIN
- TerminateProc();
- END Terminate;
- PROCEDURE Init; (* can not use NEW *)
- VAR t: Process; fn: Heaps.FinalizerNode; proc: Kernel32.HANDLE;
- res: Kernel32.BOOL;
- lib: Kernel32.HMODULE;
- BEGIN
- Kernel32.AddVectoredExceptionHandler(1, ExcpFrmHandler);
- Kernel32.InitializeCriticalSection(excplock);
- numberOfProcessors := Machine.NumberOfProcessors();
- NEW(t); NEW(fn);
- Machine.Acquire(Machine.Objects);
- t.gcContext.nextPos := 0;
- nProcs := 1;
- t.next := NIL; t.prev := NIL;
- t.waitingOn := NIL; t.flags := {}; t.obj := NIL;
- t.mode := Unknown; t.body := NIL;
- t.priority := Normal;
- fn.finalizer := FinalizeProcess;
- Heaps.AddFinalizer(t, fn);
- t.handle := Kernel32.GetCurrentThread();
- t.id := Kernel32.GetCurrentThreadId();
- proc := Kernel32.GetCurrentProcess();
- res := Kernel32.DuplicateHandle(proc, t.handle, proc, t.handle, {}, 0, {Kernel32.DuplicateSameAccess});
- ASSERT(res # 0);
- res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(LONGINT, t));
- ASSERT(res # 0);
- t.stackBottom := Machine.stackBottom;
- t.mode := Running;
- Put( ready, t );
- ASSERT(t.handle # 0);
- Machine.Release(Machine.Objects);
- InitEventHandling; (* implicit call of NewProcess! *)
- InitGCHandling; (* do. *)
- Heaps.gcStatus := GCStatusFactory();
- END Init;
- (** Set (or reset) an event handler object's timeout value. *)
- PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
- VAR e: Timer; trigger: LONGINT;
- BEGIN
- ASSERT(Machine.Second= 1000); (* assume milliseconds for now *)
- ASSERT((t # NIL) & (h # NIL));
- ASSERT(ms >= 0);
- Machine.Acquire(Machine.Objects);
- trigger := Kernel32.GetTickCount() + ms; (* ignore overflow *)
- IF t.next # NIL THEN (* cancel previous timeout *)
- t.next.prev := t.prev; t.prev.next := t.next
- END;
- t.trigger := trigger; t.handler := h;
- e := event.next; (* performance: linear search! *)
- WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
- t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
- Machine.Release(Machine.Objects);
- clock.Wakeup()
- END SetTimeout;
- (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
- PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
- VAR e: Timer; trigger: LONGINT;
- BEGIN
- ASSERT(Machine.Second= 1000); (* assume milliseconds for now *)
- ASSERT((t # NIL) & (h # NIL));
- Machine.Acquire(Machine.Objects);
- trigger := ms; (* ignore overflow *)
- IF t.next # NIL THEN (* cancel previous timeout *)
- t.next.prev := t.prev; t.prev.next := t.next
- END;
- t.trigger := trigger; t.handler := h;
- e := event.next; (* performance: linear search! *)
- WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
- t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
- Machine.Release(Machine.Objects);
- clock.Wakeup()
- END SetTimeoutAt;
- (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
- PROCEDURE CancelTimeout*( t: Timer );
- BEGIN
- Machine.Acquire(Machine.Objects);
- ASSERT (t # event );
- IF t.next # NIL THEN
- t.next.prev := t.prev;
- IF t.prev#NIL THEN t.prev.next := t.next; END;
- t.next := NIL;
- t.prev := NIL
- END;
- Machine.Release(Machine.Objects);
- END CancelTimeout;
- PROCEDURE InitEventHandling;
- BEGIN
- NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
- NEW(clock);
- END InitEventHandling;
- PROCEDURE InitGCHandling;
- BEGIN
- NEW(finalizerCaller);
- END InitGCHandling;
- PROCEDURE GCStatusFactory(): Heaps.GCStatus;
- VAR gcStatusExt : GCStatusExt;
- BEGIN
- ASSERT(Heaps.gcStatus = NIL);
- NEW(gcStatusExt);
- RETURN gcStatusExt
- END GCStatusFactory;
- PROCEDURE InstallExceptionHandler*( e: ExceptionHandler );
- BEGIN
- exceptionhandler := e;
- END InstallExceptionHandler;
- PROCEDURE UpdateProcessState*( p: Process );
- VAR res: Kernel32.BOOL;
- BEGIN
- res := Kernel32.GetThreadContext( p.handle, p.state );
- ASSERT (p.handle # 0);
- END UpdateProcessState;
- (*ALEX 2005.12.12 added for WMPerfMon needs*)
- PROCEDURE NumReady*( ): LONGINT;
- VAR n: LONGINT; p: Heaps.ProcessLink;
- BEGIN
- n := 0;
- Machine.Acquire( Machine.Objects );
- p := ready.head;
- WHILE p # NIL DO INC( n ); p := p.next END;
- Machine.Release( Machine.Objects );
- RETURN n
- END NumReady;
- (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
- return the number of cycles since the process has been created. If FALSE, return the number of cycles
- consumed since the last time asked. *)
- PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
- VAR res : Kernel32.BOOL; temp : HUGEINT;
- BEGIN
- ASSERT(process # NIL);
- IF (Kernel32.QueryThreadCycleTime # NIL) THEN
- res := Kernel32.QueryThreadCycleTime(process.handle, cpuCycles[0]);
- ELSE
- cpuCycles[0] := Machine.GetTimer(); res := Kernel32.True;
- END;
- IF ~all & (res = Kernel32.True) THEN
- temp := process.lastThreadTimes;
- process.lastThreadTimes := cpuCycles[0];
- cpuCycles[0] := cpuCycles[0] - temp;
- END;
- END GetCpuCycles;
- PROCEDURE CurrentProcessTime*(): HUGEINT;
- VAR res: WORD; result: HUGEINT;
- BEGIN
- IF (Kernel32.QueryThreadCycleTime # NIL) THEN
- res := Kernel32.QueryThreadCycleTime(CurrentProcess().handle, result);
- ELSE (* fallback *)
- result := Machine.GetTimer();
- END;
- RETURN result;
- END CurrentProcessTime;
- PROCEDURE TimerFrequency*(): HUGEINT;
- BEGIN
- RETURN 1000000000;
- END TimerFrequency;
- VAR GetProcedureName*: PROCEDURE (pc: ADDRESS; VAR n: ARRAY OF CHAR; VAR spc: ADDRESS);
- PROCEDURE LeaveA2*;
- VAR cur: Process; ebp,n: ADDRESS;
- BEGIN
- #IF AMD64 THEN
- CODE
- PUSH RCX
- PUSH RDX
- PUSH R8
- PUSH R9
- END;
- #END
- IF clock = NIL THEN
- RETURN
- END;
- cur := CurrentProcess();
- IF cur # NIL THEN
- ebp := Machine.CurrentBP();
- SYSTEM.GET(ebp, n);
- IF ODD(n) THEN SYSTEM.GET(ebp + SIZEOF(ADDRESS), ebp) ELSE ebp := n END;
- cur.gcContext.last[cur.gcContext.nextPos] := ebp;
- INC(cur.gcContext.nextPos);
- ASSERT(cur.gcContext.nextPos < 255);
- IF cur.gcContext.nextPos > 255 THEN cur.gcContext.nextPos := 255 END;
- (* IF (cur.gcContext.nextPos > 4) THEN cur.gcContext.nextPos := 2 END;*)
- END;
- #IF AMD64 THEN
- CODE
- POP R9
- POP R8
- POP RDX
- POP RCX
- END;
- #END
- END LeaveA2;
- PROCEDURE ReenterA2*;
- VAR cur: Process;
- BEGIN
- IF clock = NIL THEN RETURN END;
- cur := CurrentProcess();
- IF cur # NIL THEN
- (* cur.gcContext.first[cur.gcContext.next] := NIL;*)
- DEC(cur.gcContext.nextPos);
- IF (cur.gcContext.nextPos <0 ) THEN cur.gcContext.nextPos := 0 END;
- cur.gcContext.last[cur.gcContext.nextPos] := NIL; (* returned *)
- END;
- END ReenterA2;
- VAR
- TraceProcessHook*: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
-
- BEGIN
- TraceProcessHook := NIL;
- exceptionhandler := NIL;
- terminateProc := TerminateProc;
- ready.head := NIL; ready.tail := NIL;
- tlsIndex := Kernel32.TlsAlloc();
- ASSERT ( tlsIndex # Kernel32.TLSOutOfIndexes );
- Kernel32.SendToDebugger("Modules.root", ADDRESSOF(Modules.root));
-
-
- Init;
- END Objects.
|