Win64.Objects.Mod 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich; this module ported for the windows version, fof. *)
  2. MODULE Objects; (** AUTHOR "pjm, ejz, fof"; PURPOSE "Active object runtime support"; *)
  3. IMPORT SYSTEM, Trace, Kernel32, Machine, Modules, Heaps;
  4. CONST
  5. HandleExcp = TRUE; (* FALSE -> we asume that it is done correctly by Traps *)
  6. TraceVerbose = TRUE;
  7. StrongChecks = FALSE; defaultStackSize = 0;
  8. TraceOpenClose = FALSE;
  9. CONST
  10. (* Process flags *)
  11. Restart* = 0; (* Restart/Destroy process on exception *)
  12. PleaseHalt* = 10; (* Process requested to Halt itself soon *)
  13. Unbreakable* = 11;
  14. SelfTermination* = 12;
  15. Preempted* = 27; (* Has been preempted. *)
  16. Resistant* = 28; (* Can only be destroyed by itself *)
  17. PleaseStop* = 31; (* Process requested to Terminate or Halt itself soon *)
  18. InActive* = 26; (* needed to prevent processes to call finalizers while in await or lock or unlock, see Kernel.GC *)
  19. (** Process modes *)
  20. Unknown* = 0; Ready* = 1; (* for compatibility with native A2 *)
  21. Running* = 2; AwaitingLock* = 3; AwaitingCond* = 4; AwaitingEvent* = 5; Suspended* = 6; Terminated* = 7;
  22. (** Process priorities *)
  23. MinPriority = 0; (* only system idle processes run at this priority level *)
  24. Low* = 1; Normal* = 2; High* = 3; (* "user" priorities *)
  25. GCPriority* = 4; (* priority of garbage collector *)
  26. Realtime* = 5; (* reserved for interrupt handling and realtime apps, these processes are not allowed to allocate memory *)
  27. (* Process termination halt codes *)
  28. halt* = 2222;
  29. haltUnbreakable* = 2223;
  30. TYPE
  31. CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
  32. ProtectedObject = POINTER TO RECORD END; (* protected object (10000) *)
  33. ProcessQueue = Heaps.ProcessQueue;
  34. Body = PROCEDURE (self: ProtectedObject);
  35. Condition = PROCEDURE (slink: ADDRESS): BOOLEAN;
  36. EventHandler* = PROCEDURE {DELEGATE};
  37. RealtimeEventHandler* = PROCEDURE {DELEGATE, REALTIME};
  38. Timer* = POINTER TO RECORD
  39. next, prev : Timer;
  40. trigger: LONGINT;
  41. handler: EventHandler
  42. END;
  43. RealtimeTimer* = POINTER TO RECORD
  44. next, prev: RealtimeTimer;
  45. trigger: LONGINT;
  46. handler: RealtimeEventHandler
  47. END;
  48. Clock = OBJECT
  49. VAR h: Timer;
  50. ticks: LONGINT;
  51. hevent: Kernel32.HANDLE;
  52. res: Kernel32.BOOL;
  53. mode: LONGINT;
  54. process: Process;
  55. PROCEDURE Wakeup;
  56. VAR res: Kernel32.BOOL;
  57. BEGIN {EXCLUSIVE}
  58. res := Kernel32.SetEvent(hevent)
  59. END Wakeup;
  60. PROCEDURE Finalize(ptr: ANY);
  61. VAR res: Kernel32.BOOL;
  62. BEGIN
  63. IF hevent # 0 THEN res := Kernel32.CloseHandle(hevent); hevent := 0 END
  64. END Finalize;
  65. PROCEDURE &Init*;
  66. VAR fn: Heaps.FinalizerNode;
  67. BEGIN
  68. hevent := Kernel32.CreateEvent(NIL, 0, 0, NIL);
  69. ASSERT(hevent # 0);
  70. NEW(fn); fn.finalizer := SELF.Finalize; Heaps.AddFinalizer(SELF, fn)
  71. END Init;
  72. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  73. process := CurrentProcess();
  74. mode := process.mode;
  75. LOOP
  76. Machine.Acquire(Machine.Objects);
  77. process.mode := mode;
  78. LOOP
  79. h := event.next; (* event: head of timer event queue *)
  80. ticks := Kernel32.GetTickCount();
  81. IF (h = event) OR (h.trigger - ticks > 0) THEN EXIT END;
  82. event.next := h.next; event.next.prev := event; (* unlink *)
  83. h.next := NIL; h.prev := NIL;
  84. Machine.Release(Machine.Objects);
  85. h.handler(); (* assume handler will return promptly *)
  86. Machine.Acquire(Machine.Objects)
  87. END;
  88. mode := process.mode;
  89. process.mode := AwaitingEvent;
  90. Machine.Release(Machine.Objects);
  91. IF h = event THEN (* sentinel head of timer event queue: wait forever until a new event has been entered in queue *)
  92. res := Kernel32.WaitForSingleObject(hevent, MAX(LONGINT));
  93. ELSE
  94. res := Kernel32.WaitForSingleObject(hevent, h.trigger - ticks);
  95. END;
  96. END
  97. END Clock;
  98. TYPE
  99. Win32Event = Kernel32.HANDLE;
  100. GCContext = RECORD
  101. ebp: ADDRESS;
  102. END;
  103. Process* = OBJECT(Heaps.ProcessLink)
  104. VAR
  105. rootedNext : Process; (* to prevent process to be GCed in WinAos *)
  106. obj-: ProtectedObject; (* associated active object *)
  107. state-: Kernel32.Context;
  108. (*
  109. sse: SSEState; (* fpu and sse state of preempted process (only valid if Preempted IN flag) *)
  110. sseAdr: LONGINT;
  111. *)
  112. condition-: Condition; (* awaited process' condition *)
  113. condFP-: LONGINT; (* awaited process' condition's context *)
  114. mode-: LONGINT; (* process state *) (* only changed inside Objects lock ??? *)
  115. procID-: LONGINT; (* processor ID where running, exported for compatibilty , useless in WinAos *)
  116. waitingOn-: ProtectedObject; (* obj this process is waiting on (for lock or condition) *)
  117. id-: LONGINT; (* unique process ID for tracing *)
  118. flags*: SET; (* process flags *)
  119. priority-: LONGINT; (* process priority *)
  120. (*
  121. currPri: LONGINT;
  122. stack*: Machine.Stack; (** user-level stack of process *)
  123. *)
  124. stackBottom: ADDRESS;
  125. handle-: Kernel32.HANDLE; (* handle to corresponding Windows thread *)
  126. body: Body;
  127. event: Win32Event;
  128. restartPC-: ADDRESS; (** entry point of body, for SAFE exception recovery *)
  129. restartSP-: ADDRESS; (** stack level at start of body, for SAFE exception recovery *)
  130. (*
  131. perfCyc*: ARRAY Machine.MaxCPU OF HUGEINT;
  132. priInvCnt: LONGINT; (* counts the nummber of object locks hold that increased currPri of the process *)
  133. exp*: Machine.ExceptionState;
  134. oldReturnPC: LONGINT;
  135. *)
  136. lastThreadTimes: HUGEINT; (*ALEX 2005.12.12*)
  137. gcContext: GCContext;
  138. PROCEDURE FindRoots; (* override, called while GC, replaces Threads.CheckStacks *)
  139. VAR sp: ADDRESS; res: Kernel32.BOOL; pc, bp: ADDRESS;
  140. n,adr: ADDRESS; desc {UNTRACED}: Modules.ProcedureDescPointer; i: LONGINT; p {UNTRACED}: ANY;
  141. context: Kernel32.Wow64Context;
  142. a0,a1, obp, osb, osbp, opc, gbp: ADDRESS;
  143. O: ANY; ID: LONGINT;
  144. mod {UNTRACED}: Modules.Module;
  145. proc {UNTRACED}: Modules.ProcedureDescPointer;
  146. modName: ARRAY 128 OF CHAR;
  147. BEGIN
  148. O := obj; ID := id;
  149. IF (handle = 0) OR (mode = Terminated) OR (mode < Ready) (* procedure Wrapper not yet started *)
  150. OR (priority > High) (* stack of GC and realtime processes not traced *) THEN
  151. RETURN
  152. END;
  153. IF CurrentProcess() = SELF THEN
  154. sp := Machine.CurrentSP(); bp :=Machine.CurrentBP(); pc := Machine.CurrentPC();
  155. ELSE
  156. IF mode # Suspended THEN
  157. IF isWow64 THEN
  158. res := Kernel32.Wow64SuspendThread(handle);
  159. ELSE
  160. res := Kernel32.SuspendThread(handle);
  161. END;
  162. ASSERT(res # -1);
  163. END;
  164. state.ContextFlags := SYSTEM.VAL(LONGINT, Kernel32.ContextControl + Kernel32.ContextInteger);
  165. res := Kernel32.GetThreadContext( handle, state );
  166. context.ContextFlags := SYSTEM.VAL(LONGINT, Kernel32.ContextControl + Kernel32.ContextInteger);
  167. IF isWow64 THEN
  168. res := Kernel32.Wow64GetThreadContext( handle, context );
  169. ELSE
  170. res := Kernel32.GetThreadContext( handle, context );
  171. END;
  172. ASSERT(res # 0);
  173. sp := context.SP; bp := context.BP; pc := context.PC;
  174. mod := Modules.ThisModuleByAdr0(pc);
  175. IF mod # NIL THEN
  176. COPY(mod.name, modName);
  177. proc := Modules.FindProc(pc,mod.procTable);
  178. END;
  179. obp := bp; osb := stackBottom; opc := pc;
  180. osbp := state.BP;
  181. END;
  182. gbp := gcContext.ebp;
  183. IF gbp # NIL THEN bp := gbp END;
  184. IF TraceProcessHook # NIL THEN
  185. TraceProcessHook(SELF,pc,bp,sp,stackBottom);
  186. END;
  187. (* stack garbage collection *)
  188. IF Heaps.GCType= Heaps.HeuristicStackInspectionGC THEN
  189. Heaps.Candidate( context.RDI ); Heaps.Candidate( context.RSI );
  190. Heaps.Candidate( context.RBX ); Heaps.Candidate( context.RDX );
  191. Heaps.Candidate( context.RCX ); Heaps.Candidate( context.RAX );
  192. IF (stackBottom # 0) & (sp # 0) THEN
  193. Heaps.RegisterCandidates( sp, stackBottom - sp );
  194. END;
  195. ELSIF Heaps.GCType = Heaps.MetaDataForStackGC THEN
  196. IF bp < stackBottom THEN
  197. WHILE (bp # Heaps.NilVal) & (bp < stackBottom) DO (* do not test for bp >= sp: could be wrong temporarily! *)
  198. SYSTEM.GET(bp, n);
  199. IF ODD(n) THEN (* procedure descriptor at bp *)
  200. desc := SYSTEM.VAL(Modules.ProcedureDescPointer, n-1);
  201. IF desc # NIL THEN
  202. a0 := ADDRESSOF(desc.offsets);
  203. a1 := SYSTEM.VAL(ADDRESS, desc.offsets);
  204. ASSERT(a0+SIZEOF(ADDRESS)=a1,54321);
  205. FOR i := 0 TO LEN(desc.offsets)-1 DO
  206. adr := bp + desc.offsets[i]; (* pointer at offset *)
  207. SYSTEM.GET(adr, p); (* load pointer *)
  208. IF p # NIL THEN
  209. Heaps.Mark(p);
  210. END;
  211. END;
  212. END;
  213. SYSTEM.GET(bp + SIZEOF(ADDRESS), bp);
  214. ELSE (* classical stack frame *)
  215. bp := n;
  216. END;
  217. END;
  218. ASSERT((bp = stackBottom) OR (bp=0) ,12345);
  219. END;
  220. END;
  221. IF (CurrentProcess() # SELF) & (mode # Suspended) THEN
  222. res := Kernel32.ResumeThread(handle);
  223. ASSERT(res # -1);
  224. END;
  225. END FindRoots;
  226. END Process;
  227. TYPE
  228. (* ExceptionHandler* = PROCEDURE( CONST exceptionPointers: Kernel32.ExceptionPointers): Kernel32.DWORD; *)
  229. ExceptionHandler* = PROCEDURE( VAR context: Kernel32.Context;
  230. VAR excpRec: Kernel32.ExceptionRecord;
  231. VAR handled: BOOLEAN);
  232. GCStatusExt = OBJECT(Heaps.GCStatus)
  233. (* called from Heaps.InvokeGC, i.e. this is a hidden upcall. However, it is necessary to take the Machine.Objects lock here since writing
  234. 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
  235. if the lock is not taken. *)
  236. PROCEDURE SetgcOngoing(value: BOOLEAN);
  237. VAR p: Heaps.ProcessLink; cur, r: Process; res: Kernel32.BOOL; num: LONGINT; time: LONGINT;
  238. BEGIN (* serialize writers *)
  239. IF value THEN
  240. (* Low, Medium or High priority process calls this *)
  241. time := Kernel32.GetTickCount();
  242. Machine.Acquire(Machine.Objects);
  243. Machine.Acquire(Machine.Heaps); (* to protect agains concurrent LazySweep *)
  244. r := CurrentProcess();
  245. num := 0;
  246. p := ready.head;
  247. WHILE p # NIL DO
  248. cur := p(Process);
  249. IF ((cur.mode = Ready) OR (cur.mode = Running)) & (cur.priority <= High) & (cur # r) THEN
  250. IF isWow64 THEN
  251. res := Kernel32.Wow64SuspendThread(cur.handle);
  252. ELSE
  253. res := Kernel32.SuspendThread(cur.handle);
  254. END;
  255. ASSERT(res >= 0);
  256. cur.mode := Suspended
  257. ELSE INC(num);
  258. END;
  259. p := p.next
  260. END;
  261. Heaps.CollectGarbage(Modules.root);
  262. p := ready.head;
  263. WHILE (p # NIL) DO
  264. cur := p(Process);
  265. (* only suspended and awaiting processes of ready queue are resumed *)
  266. IF cur.mode = Suspended THEN
  267. res := Kernel32.ResumeThread(cur.handle);
  268. ASSERT(res >= 0);
  269. cur.mode := Running
  270. END;
  271. p := p.next
  272. END;
  273. Machine.Release(Machine.Heaps);
  274. Machine.Release(Machine.Objects);
  275. time := Kernel32.GetTickCount()-time;
  276. IF Heaps.trace THEN Trace.String("GC Called -- duration "); Trace.Int(time,0); Trace.String(" ms."); Trace.Ln END;
  277. IF finalizerCaller # NIL THEN finalizerCaller.Activate() END;
  278. END;
  279. END SetgcOngoing;
  280. END GCStatusExt;
  281. FinalizedCollection* = OBJECT
  282. PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
  283. BEGIN HALT(301) END RemoveAll;
  284. END FinalizedCollection;
  285. FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
  286. c*: FinalizedCollection (* base type for collection containing object *)
  287. END;
  288. FinalizerCaller = OBJECT (* separate active object that calls finalizers *)
  289. VAR n: Heaps.FinalizerNode;
  290. event: Kernel32.HANDLE;
  291. process: Process;
  292. PROCEDURE &Init;
  293. BEGIN
  294. event := Kernel32.CreateEvent( NIL, Kernel32.False (* automatic *), Kernel32.False, NIL );
  295. ASSERT(event # 0);
  296. END Init;
  297. PROCEDURE Wait;
  298. VAR res: Kernel32.BOOL; mode: LONGINT;
  299. BEGIN
  300. mode := process.mode;
  301. process.mode := AwaitingEvent;
  302. res := Kernel32.WaitForSingleObject(event, Kernel32.Infinite);
  303. ASSERT(res = Kernel32.WaitObject0);
  304. process.mode := mode;
  305. END Wait;
  306. PROCEDURE Activate;
  307. VAR res: Kernel32.BOOL;
  308. BEGIN
  309. res := Kernel32.SetEvent(event);
  310. END Activate;
  311. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  312. process := CurrentProcess();
  313. LOOP
  314. Wait;
  315. LOOP
  316. n := Heaps.GetFinalizer();
  317. IF n = NIL THEN EXIT END;
  318. IF n IS FinalizerNode THEN
  319. n( FinalizerNode ).c.RemoveAll( n.objStrong ) (* remove it if it is not removed yet *)
  320. END;
  321. IF n.finalizer # NIL THEN
  322. n.finalizer( n.objStrong ) (* may acquire locks *)
  323. END
  324. END
  325. END;
  326. END FinalizerCaller;
  327. VAR
  328. awc-, awl-: LONGINT;
  329. oberonLoop*: ANY; (* Oberon Loop Process temporary workaround for Threads.oberonLoop *)
  330. break: ARRAY 16 OF CHAR;
  331. terminateProc: PROCEDURE;
  332. ready: ProcessQueue; (* contains running processes in this implementation *)
  333. numberOfProcessors: LONGINT; (* cached value of Machine.NumberOfProcessors() *)
  334. finalizerCaller: FinalizerCaller; (* active object for finalizer process, regarded as aprt of GC *)
  335. event: Timer; (* list of events *)
  336. clock: Clock;
  337. tlsIndex: LONGINT;
  338. nProcs: LONGINT;
  339. excplock: Kernel32.CriticalSection; exceptionhandler: ExceptionHandler;
  340. isWow64: BOOLEAN; (* TRUE for WOW64 environment *)
  341. (* Set the current process' priority. *)
  342. PROCEDURE SetPriority*( priority: LONGINT );
  343. VAR r: Process; prio: LONGINT; res: Kernel32.BOOL;
  344. BEGIN
  345. ASSERT((priority >= Low) & (priority <= Realtime)); (* priority in bounds *)
  346. r := CurrentProcess(); r.priority := priority;
  347. CASE priority OF
  348. MinPriority:
  349. prio := Kernel32.ThreadPriorityIdle
  350. | Low:
  351. prio := Kernel32.ThreadPriorityBelowNormal
  352. | High:
  353. prio := Kernel32.ThreadPriorityAboveNormal
  354. | GCPriority, Realtime:
  355. prio := Kernel32.ThreadPriorityTimeCritical
  356. ELSE (* Normal *)
  357. prio := Kernel32.ThreadPriorityNormal
  358. END;
  359. res := Kernel32.SetThreadPriority( r.handle, prio );
  360. ASSERT(r.handle # 0);
  361. ASSERT(res # 0)
  362. END SetPriority;
  363. (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
  364. PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
  365. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
  366. BEGIN
  367. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  368. ASSERT(hdr IS Heaps.ProtRecBlock);
  369. Machine.Acquire(Machine.Objects);
  370. res := (hdr.lockedBy = ActiveObject());
  371. Machine.Release(Machine.Objects);
  372. RETURN res
  373. END LockedByCurrent;
  374. PROCEDURE Yield*;
  375. BEGIN
  376. Kernel32.Sleep(0)
  377. END Yield;
  378. (** Return current process. (DEPRECATED, use ActiveObject) *)
  379. PROCEDURE CurrentProcess*( ): Process;
  380. BEGIN{UNCHECKED} (* makes sure that Enter and Leave are not emitted *)
  381. RETURN SYSTEM.VAL(Process, Kernel32.TlsGetValue(tlsIndex));
  382. END CurrentProcess;
  383. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  384. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  385. BEGIN
  386. RETURN p.stackBottom
  387. END GetStackBottom;
  388. (** Return the active object currently executing. *)
  389. PROCEDURE ActiveObject* (): ANY;
  390. VAR r: Process;
  391. BEGIN
  392. r := SYSTEM.VAL(Process, Kernel32.TlsGetValue(tlsIndex));
  393. RETURN r.obj
  394. END ActiveObject;
  395. (** Return the ID of the active currently executing process. *)
  396. PROCEDURE GetProcessID* (): LONGINT;
  397. VAR r: Process;
  398. BEGIN
  399. r := SYSTEM.VAL (Process, Kernel32.TlsGetValue( tlsIndex ));
  400. RETURN r.id
  401. END GetProcessID;
  402. (* Get a process from a queue (NIL if none). Caller must hold lock for specific queue. *)
  403. PROCEDURE Get(VAR queue: ProcessQueue; VAR new: Process);
  404. VAR t: Heaps.ProcessLink;
  405. BEGIN
  406. t := queue.head;
  407. IF t = NIL THEN (* zero elements in queue *)
  408. (* skip *)
  409. ELSIF t = queue.tail THEN (* one element in queue *)
  410. queue.head := NIL; queue.tail := NIL (* {(t.next = NIL) & (t.prev = NIL)} *)
  411. ELSE (* more than one element in queue *)
  412. queue.head := t.next; t.next := NIL; queue.head.prev := NIL
  413. END;
  414. ASSERT((t = NIL) OR (t.next = NIL ) & (t.prev = NIL)); (* temp strong check *)
  415. IF t = NIL THEN
  416. new := NIL
  417. ELSE
  418. ASSERT(t IS Process);
  419. new := t(Process)
  420. END
  421. END Get;
  422. (* Put a process in a queue. Caller must hold lock for specific queue. *)
  423. (* If t was running, be careful to protect Put and the subsequent SwitchTo with the ready lock. *)
  424. PROCEDURE Put(VAR queue: ProcessQueue; t: Process);
  425. BEGIN (* {t # NIL & t.next = NIL & t.prev = NIL} *)
  426. IF StrongChecks THEN
  427. ASSERT((t.next = NIL) & (t.prev = NIL))
  428. END;
  429. t.next := NIL; t.prev := NIL; (* ug *)
  430. IF queue.head = NIL THEN (* queue empty *)
  431. queue.head := t
  432. ELSE (* queue not empty *)
  433. queue.tail.next := t; t.prev := queue.tail
  434. END;
  435. queue.tail := t
  436. END Put;
  437. (* starting address of user stack for current thread, called stack top in TIB.H *)
  438. PROCEDURE -StackBottom*( ): LONGINT;
  439. CODE {SYSTEM.i386}
  440. DB 064H
  441. DB 08BH
  442. DB 005H
  443. DB 004H
  444. DB 000H
  445. DB 000H
  446. DB 000H
  447. END StackBottom;
  448. PROCEDURE {WINAPI} ExcpFrmHandler( CONST exceptionPointers: Kernel32.ExceptionPointers): Kernel32.DWORD ;
  449. VAR m: Modules.Module; eip, ebp, stack: ADDRESS; pc, handler, fp, sp: ADDRESS; handled: BOOLEAN; t: Process;
  450. BEGIN
  451. TRACE("TRAP");
  452. handled := FALSE;
  453. Kernel32.EnterCriticalSection( excplock );
  454. (*
  455. fof: commenting this resolved a problem with multiple traps that a are catched with FINALLY statements in Windows Vista
  456. in Windows XP not necessary if Kernel32.SetThreadContext is not used (better to return gracefully from this handler)
  457. SetCurrent(excpFrame);
  458. *)
  459. t := CurrentProcess();
  460. IF exceptionhandler = NIL THEN
  461. Trace.StringLn ( "Objects: No exception handler installed" );
  462. IF HandleExcp THEN
  463. Trace.String( "EXCEPTION " ); Trace.Address(exceptionPointers.exception.ExceptionCode);
  464. Trace.String( " at " ); Trace.Address(exceptionPointers.exception.ExceptionAddress);
  465. Trace.Ln(); Trace.String( "RAX " ); Trace.Address(exceptionPointers.context.RAX);
  466. Trace.String( " RBX " ); Trace.Address(exceptionPointers.context.RBX); Trace.Ln();
  467. Trace.String( "RCX " ); Trace.Address(exceptionPointers.context.RCX); Trace.String( " RDX " );
  468. Trace.Address(exceptionPointers.context.RDX); Trace.Ln(); Trace.String( "RDI " );
  469. Trace.Address(exceptionPointers.context.RDI); Trace.String( " RSI " );
  470. Trace.Address(exceptionPointers.context.RSI); Trace.Ln();
  471. Trace.String( "R8 " ); Trace.Address(exceptionPointers.context.R8);
  472. Trace.String( " R9 " ); Trace.Address(exceptionPointers.context.R9); Trace.Ln();
  473. Trace.String( "R10 " ); Trace.Address(exceptionPointers.context.R10);
  474. Trace.String( " R11 " ); Trace.Address(exceptionPointers.context.R11); Trace.Ln();
  475. Trace.String( "R12 " ); Trace.Address(exceptionPointers.context.R12);
  476. Trace.String( " R13 " ); Trace.Address(exceptionPointers.context.R13); Trace.Ln();
  477. Trace.String( "R14 " ); Trace.Address(exceptionPointers.context.R14);
  478. Trace.String( " R15 " ); Trace.Address(exceptionPointers.context.R15); Trace.Ln();
  479. Trace.Ln;
  480. Trace.String( "RBP " );
  481. Trace.Address(exceptionPointers.context.BP); Trace.String( " RSP " );
  482. Trace.Address(exceptionPointers.context.SP); Trace.Ln(); Trace.String( "PC " );
  483. Trace.Address(exceptionPointers.context.PC); Trace.Ln();
  484. Trace.Ln();
  485. eip := exceptionPointers.exception.ExceptionAddress; ebp := exceptionPointers.context.BP;
  486. IF eip = 0 THEN SYSTEM.GET( exceptionPointers.context.SP, eip ) END;
  487. stack := StackBottom();
  488. LOOP
  489. Trace.String( "at ebp= " ); Trace.Address(ebp); Trace.String( "H : " );
  490. m := Modules.ThisModuleByAdr( eip );
  491. IF m # NIL THEN
  492. Trace.String( m.name ); Trace.String( " " );
  493. Trace.Address(eip - SYSTEM.VAL( LONGINT, ADDRESSOF( m.code[0] ) ));
  494. ELSE Trace.String( "EIP " ); Trace.Address(eip)
  495. END;
  496. Trace.Ln();
  497. IF (ebp # 0) & (ebp < stack) THEN (* if ebp is 0 in first frame *)
  498. SYSTEM.GET( ebp + SIZEOF(ADDRESS), eip ); (* return addr from stack *)
  499. SYSTEM.GET( ebp, ebp ); (* follow dynamic link *)
  500. ELSE EXIT
  501. END
  502. END;
  503. Trace.Ln();
  504. (* finally and all that ...
  505. handled := FALSE; fp := exceptionPointers.context.BP; sp := exceptionPointers.context.SP;
  506. pc := exceptionPointers.context.PC; handler := Modules.GetExceptionHandler( pc );
  507. IF handler # -1 THEN (* Handler in the current PAF *)
  508. exceptionPointers.context.PC := handler; handled := TRUE;
  509. (*SetTrapVariable(pc, fp); SetLastExceptionState(exc)*)
  510. ELSE
  511. WHILE (fp # 0) & (handler = -1) DO
  512. SYSTEM.GET( fp + SIZEOF(ADDRESS), pc );
  513. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  514. handler := Modules.GetExceptionHandler( pc );
  515. sp := fp; (* Save the old framepointer into the stack pointer *)
  516. SYSTEM.GET( fp, fp ) (* Unwind PAF *)
  517. END;
  518. IF handler = -1 THEN handled := FALSE;
  519. ELSE
  520. TRACE("CHANGED HANDLER ADR ");
  521. exceptionPointers.context.PC := handler; exceptionPointers.context.BP := fp; exceptionPointers.context.SP := sp;
  522. (* SetTrapVariable(pc, fp); SetLastExceptionState(exc);*)
  523. handled := TRUE
  524. END
  525. END;
  526. *)
  527. ELSE Trace.StringLn ( "Warning: FINALLY statement cannot be treated !" );
  528. END
  529. ELSE exceptionhandler(exceptionPointers.context^, exceptionPointers.exception^,handled );
  530. END;
  531. TRACE(handled);
  532. IF ~handled THEN
  533. exceptionPointers.context.PC := (*TerminateProc*) t.restartPC ;
  534. exceptionPointers.context.SP := t.restartSP;
  535. exceptionPointers.context.BP := t.stackBottom;
  536. ELSIF TraceVerbose THEN Trace.StringLn ( "trying to jump to FINALLY pc..." );
  537. END;
  538. Kernel32.LeaveCriticalSection( excplock );
  539. IF TraceVerbose THEN
  540. Machine.Acquire (Machine.TraceOutput);
  541. Trace.String( "recover process; pc=" ); Trace.Address( exceptionPointers.context.PC );
  542. Trace.String( "; sp= " ); Trace.Address( exceptionPointers.context.SP); Trace.String( "; bp= " );
  543. Trace.Address( exceptionPointers.context.BP); Trace.Ln;
  544. Machine.Release (Machine.TraceOutput);
  545. END;
  546. RETURN Kernel32.ExceptionContinueExecution; (* sets thread context and continues where specified in context *)
  547. END ExcpFrmHandler;
  548. (*
  549. (* get the currently installed execption frame *)
  550. (* PROCEDURE -GetCur 64H, 8BH, 0DH, 0, 0, 0, 0; (* MOV ECX, FS:[0] *) *)
  551. (* Better *)
  552. PROCEDURE -GetCur;
  553. CODE {SYSTEM.AMD64}
  554. MOV RCX, [GS:0]
  555. ; DB 064H, 08BH, 00DH, 000H, 000H, 000H, 000H
  556. END GetCur;
  557. PROCEDURE GetCurrent( ): Kernel32.ExcpFrmPtr;
  558. VAR cur: Kernel32.ExcpFrmPtr;
  559. BEGIN
  560. GetCur;
  561. cur := SYSTEM.VAL(Kernel32.ExcpFrmPtr,Machine.GetRCX());
  562. TRACE(cur);
  563. (* RETURN ECX *)
  564. RETURN cur
  565. END GetCurrent;
  566. *)
  567. (*
  568. (* install a new exception frame *)
  569. (* PROCEDURE -SetCur 64H, 0A3H, 0, 0, 0, 0; (* MOV FS:[0], EAX *)*)
  570. (* Better *)
  571. PROCEDURE -SetCur;
  572. CODE {SYSTEM.AMD64}
  573. ; DB 064H, 0A3H, 000H, 000H, 000H, 000H
  574. MOV [GS:0], RAX
  575. END SetCur;
  576. PROCEDURE SetCurrent( cur: Kernel32.ExcpFrmPtr );
  577. BEGIN
  578. TRACE(cur);
  579. Machine.SetRAX(cur);
  580. (* EAX := cur *)
  581. CODE{SYSTEM.AMD64}
  582. MOV [GS:0], RAX
  583. END;
  584. TRACE(GetCurrent());
  585. (*SetCur*)
  586. END SetCurrent;
  587. *)
  588. PROCEDURE RemoveExcpFrm( VAR excpfrm: Kernel32.ExcpFrm );
  589. VAR this: Kernel32.ExcpFrmPtr;
  590. BEGIN
  591. (*
  592. this := GetCurrent();
  593. (* ASSERT ( this = ADDRESSOF( excpfrm ) ); *)
  594. IF this # ADDRESSOF( excpfrm ) THEN Trace.StringLn ( "RemoveExcpFrm: Problem with excpfrm pointer" );
  595. ELSE SetCurrent( excpfrm.link )
  596. END;
  597. *)
  598. (*
  599. Kernel32.RemoveVectoredExceptionHandler(ExcpFrmHandler);
  600. *)
  601. END RemoveExcpFrm;
  602. PROCEDURE InstallExcpFrm( VAR excpfrm: Kernel32.ExcpFrm );
  603. BEGIN
  604. Kernel32.AddVectoredContinueHandler(1, ExcpFrmHandler);
  605. (*
  606. excpfrm.link := GetCurrent(); excpfrm.handler := ExcpFrmHandler;
  607. SetCurrent( ADDRESSOF( excpfrm ) )
  608. *)
  609. END InstallExcpFrm;
  610. PROCEDURE InQueue( queue: ProcessQueue; t: Process ): BOOLEAN;
  611. VAR p: Heaps.ProcessLink;
  612. BEGIN
  613. p := queue.head;
  614. WHILE (p # NIL ) & (p # t) DO p := p.next; END;
  615. RETURN (p = t);
  616. END InQueue;
  617. (* Remove a process from a queue that contains it. Caller must hold lock for specific queue. *)
  618. (* Not intended for frequent use. *)
  619. (* does not check if queue contained t ! *)
  620. PROCEDURE Remove( VAR queue: ProcessQueue; t: Process );
  621. BEGIN
  622. IF StrongChecks THEN
  623. ASSERT(InQueue(queue, t));
  624. ASSERT(t # NIL);
  625. END;
  626. IF t.prev # NIL THEN t.prev.next := t.next END;
  627. IF t.next # NIL THEN t.next.prev := t.prev END;
  628. IF t = queue.head THEN queue.head := t.next END;
  629. IF t = queue.tail THEN queue.tail := t.prev END;
  630. ASSERT((queue.head = NIL) OR (queue.head.prev = NIL) & (queue.tail.next = NIL));
  631. t.prev := NIL; t.next := NIL
  632. END Remove;
  633. PROCEDURE WriteType(obj: ANY);
  634. VAR type: LONGINT;
  635. BEGIN
  636. IF obj = NIL THEN Trace.String(" > NIL");
  637. ELSE
  638. Trace.String(" > "); SYSTEM.GET(SYSTEM.VAL(LONGINT, obj) + Heaps.TypeDescOffset, type);
  639. Heaps.WriteType(type);
  640. END;
  641. END WriteType;
  642. PROCEDURE terminate( t: Process );
  643. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: Kernel32.BOOL; shutdown: BOOLEAN;
  644. BEGIN
  645. TRACE("terminate");
  646. IF t = NIL THEN RETURN END;
  647. (* see Objects.TerminateThis *)
  648. Machine.Acquire( Machine.Objects );
  649. IF TraceVerbose OR TraceOpenClose THEN
  650. Machine.Acquire (Machine.TraceOutput);
  651. Trace.String( "Terminating process " ); Trace.Int( t.id, 1 ); WriteType( t.obj ); Trace.Ln;
  652. Machine.Release (Machine.TraceOutput);
  653. END;
  654. IF (t.mode = Ready) OR (t.mode = Running) THEN Remove( ready, t );
  655. ELSIF t.mode = AwaitingLock THEN
  656. SYSTEM.GET(SYSTEM.VAL(ADDRESS, t.waitingOn) + Heaps.HeapBlockOffset, hdr);
  657. ASSERT(hdr IS Heaps.ProtRecBlock);
  658. Remove( hdr.awaitingLock, t ); Machine.Release( Machine.Objects );
  659. HALT( 97 )
  660. ELSIF t.mode = AwaitingCond THEN
  661. SYSTEM.GET(SYSTEM.VAL(ADDRESS, t.waitingOn) + Heaps.HeapBlockOffset, hdr);
  662. ASSERT(hdr IS Heaps.ProtRecBlock);
  663. Remove( hdr.awaitingCond, t ); Machine.Release( Machine.Objects );
  664. HALT( 98 )
  665. ELSE Machine.Release( Machine.Objects );
  666. HALT( 99 )
  667. END;
  668. t.mode := Terminated; (* a process can also be "terminated" if the queue containing it is garbage collected *)
  669. t.stackBottom := 0; t.state.SP := 0;
  670. t.restartPC := 0;
  671. IF t.event # 0 THEN res := Kernel32.CloseHandle( t.event ); t.event := 0 END;
  672. DEC( nProcs ); shutdown := (nProcs = 0);
  673. Machine.Release( Machine.Objects );
  674. IF shutdown THEN
  675. Trace.StringLn ( " Objects: shutdown" ); Modules.Shutdown( -1 );
  676. Kernel32.ExitProcess( 0 )
  677. END
  678. END terminate;
  679. PROCEDURE {WINAPI} Wrapper( lpParameter: ANY ): LONGINT;
  680. VAR t: Process; obj: ProtectedObject; res: Kernel32.BOOL; bp,sp: ADDRESS;
  681. excpfrm: Kernel32.ExcpFrm;
  682. BEGIN
  683. (* it may happen that the garbage collector runs right here and ignores this procedure.
  684. This is not a problem since lpParameter (being a reference to a process) is protected by the process lists *)
  685. Machine.Acquire(Machine.Objects);
  686. res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(LONGINT, lpParameter));
  687. t := lpParameter(Process); obj := t.obj;
  688. ASSERT(res # 0);
  689. SetPriority(t.priority);
  690. bp := Machine.CurrentBP();
  691. sp := Machine.CurrentSP();
  692. t.restartSP := sp;
  693. t.stackBottom := bp;
  694. IF t.restartPC = SYSTEM.VAL(ADDRESS, terminateProc) THEN DEC(t.restartSP, SIZEOF(ADDRESS))
  695. ELSE DEC(t.restartSP, 2*SIZEOF(ADDRESS))
  696. END;
  697. IF TraceVerbose THEN
  698. Machine.Acquire(Machine.TraceOutput);
  699. Trace.String("New process; restartPC= "); Trace.Address(t.restartPC);
  700. Trace.String("; stackBottom= ");
  701. Trace.Address(t.stackBottom); Trace.Ln;
  702. Machine.Release(Machine.TraceOutput);
  703. END;
  704. t.mode := Running;
  705. (* now gc is enabled for this process stack *)
  706. Machine.Release(Machine.Objects);
  707. (* 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) *)
  708. (*! should not be necessary any more as GC runs immediately and without scheduling decisions
  709. WHILE (gcActivity # NIL) & (gcActivity.process # NIL) & (gcActivity.process.mode = Running) DO END;
  710. *)
  711. t.body(obj);
  712. terminate(t);
  713. RemoveExcpFrm(excpfrm);
  714. RETURN 0
  715. END Wrapper;
  716. PROCEDURE FinalizeProcess(t: ANY);
  717. VAR p: Process; res: Kernel32.BOOL;
  718. BEGIN
  719. p := t(Process);
  720. IF TraceVerbose THEN
  721. Machine.Acquire (Machine.TraceOutput);
  722. Trace.String("Finalizing Process"); Trace.Int(p.id, 1);
  723. WriteType(p.obj); Trace.Ln;
  724. Machine.Release (Machine.TraceOutput);
  725. END;
  726. IF p.mode # Terminated THEN
  727. IF p.mode = AwaitingLock THEN DEC(awl);
  728. ELSIF p.mode = AwaitingCond THEN DEC(awc);
  729. END;
  730. (* no reference to the object any more *)
  731. Trace.String ("Closing unreferenced process"); (*Trace.Int(p.mode,20); Trace.Int( p.id, 20 ); *) Trace.Ln; (* Trace.Ln *)
  732. (* this usually happens, when an objects process waits on its own objtec and no reference exists any more. Then the object is discarded and
  733. consequently the process is unreferenced (except in the object). This cannot happen when there are still other references on the object.
  734. example:
  735. TYPE
  736. Object= OBJECT VAR active: BOOLEAN; BEGIN{ACTIVE} active := FALSE; AWAIT(active) END Object;
  737. VAR o: Object;
  738. BEGIN NEW(o);
  739. END;
  740. *)
  741. END;
  742. p.mode := Terminated; (* fof for GC problem *)
  743. IF p.handle # 0 THEN
  744. res := Kernel32.CloseHandle(p.handle); p.handle := 0
  745. END
  746. END FinalizeProcess;
  747. PROCEDURE TerminateProc;
  748. BEGIN
  749. TRACE("TerminateProc");
  750. terminate(CurrentProcess());
  751. Kernel32.ExitThread(0);
  752. Kernel32.Sleep(999999); (* wait until dependent threads terminated *)
  753. END TerminateProc;
  754. (* Allocate a new process associated with "obj". Must be outside lock region, because of potential GC. *)
  755. PROCEDURE NewProcess(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject; VAR new: Process);
  756. VAR t,r: Process; fn: Heaps.FinalizerNode;
  757. BEGIN
  758. NEW(t);
  759. t.handle := 0;
  760. IF priority = 0 THEN (* no priority specified *)
  761. r := CurrentProcess();
  762. t.priority := r.priority (* inherit priority of creator *)
  763. ELSIF priority > 0 THEN (* positive priority specified *)
  764. t.priority := priority
  765. ELSE (* negative priority specified (only for Idle process) *)
  766. t.priority := MinPriority
  767. END;
  768. NEW(fn); (* implicit call Heaps.NewRec -> might invoke GC *)
  769. Machine.Acquire(Machine.Objects);
  770. t.next := NIL; t.prev := NIL; t.rootedNext := NIL;
  771. t.waitingOn := NIL; t.flags := flags; t.obj := obj; t.mode := Unknown;
  772. t.body := body; t.event := 0; fn.finalizer := FinalizeProcess;
  773. Heaps.AddFinalizer(t, fn);
  774. IF Restart IN flags THEN (* restart object body *)
  775. t.restartPC := SYSTEM.VAL(ADDRESS, body);
  776. ELSE (* terminate process *)
  777. t.restartPC := SYSTEM.VAL(ADDRESS, terminateProc);
  778. END;
  779. (* t.restartPC := SYSTEM.VAL(ADDRESS, terminateProc);*)
  780. t.handle := Kernel32.CreateThread(0, defaultStackSize, Wrapper, t, {}, t.id);
  781. IF TraceVerbose OR TraceOpenClose THEN
  782. Machine.Acquire(Machine.TraceOutput);
  783. Trace.String("NewProcess: " ); Trace.Int(t.id, 1); WriteType(obj); Trace.Ln;
  784. Machine.Release(Machine.TraceOutput);
  785. END;
  786. ASSERT(t.handle # 0);
  787. new := t;
  788. END NewProcess;
  789. (* Create the process associated with an active object (kernel call). *)
  790. PROCEDURE CreateProcess*(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject);
  791. VAR t : Process; heapBlock {UNTRACED}: Heaps.HeapBlock;
  792. BEGIN
  793. ASSERT(priority >= 0, 1000); ASSERT(priority <=Realtime, 1001);
  794. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, heapBlock);
  795. ASSERT(heapBlock IS Heaps.ProtRecBlock); (* protected object *)
  796. IF Restart IN flags THEN INCL(flags, Resistant) END; (* SAFE => Restart & Resistant *)
  797. NewProcess(body, priority, flags, obj, t); INC(nProcs); (* acquires Machine.Objects lock *)
  798. t.mode := Ready; Put(ready, t);
  799. Machine.Release(Machine.Objects);
  800. END CreateProcess;
  801. (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
  802. too early. *)
  803. PROCEDURE Lock*(obj: ProtectedObject; exclusive: BOOLEAN );
  804. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; r: Process; res: LONGINT;
  805. BEGIN (* {called from user level} *)
  806. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  807. IF StrongChecks THEN
  808. ASSERT(hdr IS Heaps.ProtRecBlock); (* protected object *)
  809. ASSERT(exclusive) (* shared not implemented yet *)
  810. END;
  811. r := CurrentProcess();
  812. IF StrongChecks THEN
  813. ASSERT(hdr # NIL, 1001);
  814. ASSERT(r # NIL, 1002);
  815. END;
  816. Machine.Acquire(Machine.Objects);
  817. IF hdr.count = 0 THEN (* not locked *)
  818. hdr.count := -1; hdr.lockedBy := r;
  819. Machine.Release(Machine.Objects)
  820. ELSE (* already locked *)
  821. IF hdr.lockedBy = r THEN
  822. Machine.Release(Machine.Objects);
  823. HALT(2203) (* nested locks not allowed *)
  824. END;
  825. ASSERT(r.waitingOn = NIL); (* sanity check *)
  826. Remove(ready, r);
  827. IF r.event = 0 THEN
  828. r.event := Kernel32.CreateEvent( NIL, Kernel32.False (* auto *), Kernel32.False, NIL ); (* auto reset event with initial state = reset *)
  829. ASSERT ( r.event # 0, 1239 );
  830. END;
  831. r.waitingOn := obj; r.mode := AwaitingLock;
  832. Put(hdr.awaitingLock, r); INC(awl);
  833. Machine.Release(Machine.Objects);
  834. res := Kernel32.WaitForSingleObject(r.event, Kernel32.Infinite); (* block execution *)
  835. ASSERT(res = Kernel32.WaitObject0);
  836. IF StrongChecks THEN
  837. ASSERT(hdr.lockedBy = r); (* at this moment only this process can own the lock and only this process can release it*)
  838. END;
  839. END
  840. END Lock;
  841. (* Find the first true condition from the queue and remove it. Assume the object is currently locked. *)
  842. PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
  843. VAR first, cand: Process;
  844. BEGIN
  845. Get( q, first );
  846. IF first.condition( first.condFP ) THEN RETURN first END;
  847. Put( q, first );
  848. WHILE q.head # first DO
  849. Get( q, cand );
  850. IF cand.condition( cand.condFP ) THEN RETURN cand END;
  851. Put( q, cand )
  852. END;
  853. RETURN NIL
  854. END FindCondition;
  855. (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
  856. too early. *)
  857. PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
  858. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; t, c: Process; res: LONGINT;
  859. BEGIN
  860. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  861. IF StrongChecks THEN
  862. ASSERT(hdr IS Heaps.ProtRecBlock) (* protected object *)
  863. END;
  864. ASSERT(hdr.count = -1); (* exclusive locked *)
  865. Machine.Acquire(Machine.Objects);
  866. IF hdr.awaitingCond.head # NIL THEN (* evaluate the waiting conditions *)
  867. (* we are holding the lock, so the queue can not change (to do: except in TerminateThis) *)
  868. c := FindCondition(hdr.awaitingCond); (* interrupts should be on during this call *)
  869. ELSE
  870. c := NIL
  871. END;
  872. IF c = NIL THEN (* no true condition found, check the lock queue *)
  873. Get(hdr.awaitingLock, t);
  874. IF t # NIL THEN
  875. hdr.lockedBy := t;
  876. t.waitingOn := NIL;
  877. ELSE
  878. hdr.lockedBy := NIL; hdr.count := 0
  879. END
  880. ELSE (* true condition found, transfer the lock *)
  881. c.waitingOn := NIL; hdr.lockedBy := c;
  882. t := NIL
  883. END;
  884. IF c # NIL THEN
  885. Put(ready, c); c.mode := Running; DEC(awc);
  886. res := Kernel32.SetEvent(c.event);
  887. ASSERT (res # 0, 1001);
  888. ELSIF t # NIL THEN
  889. Put(ready, t); t.mode := Running; DEC(awl);
  890. res := Kernel32.SetEvent(t.event);
  891. ASSERT (res # 0, 1002);
  892. END;
  893. Machine.Release( Machine.Objects )
  894. END Unlock;
  895. (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
  896. too early. *)
  897. PROCEDURE Await*( cond: Condition; slink: LONGINT; obj: ProtectedObject; flags: SET );
  898. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; r, c, t: Process; res: LONGINT;
  899. BEGIN
  900. IF 1 IN flags THEN (* compiler did not generate IF *)
  901. IF cond(slink) THEN
  902. RETURN (* condition already true *)
  903. END
  904. END;
  905. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  906. IF StrongChecks THEN
  907. ASSERT(hdr IS Heaps.ProtRecBlock) (* protected object *)
  908. END;
  909. r := CurrentProcess();
  910. Machine.Acquire(Machine.Objects);
  911. IF hdr.lockedBy = r THEN (* current process holds exclusive lock *)
  912. IF StrongChecks THEN ASSERT(hdr.count = -1) END; (* exclusive locked *)
  913. IF hdr.awaitingCond.head # NIL THEN (* evaluate the waiting conditions *)
  914. (* we are holding the lock, so the queue can not change (to do: except in TerminateThis) *)
  915. c := FindCondition(hdr.awaitingCond) (* interrupts should be on during this call *)
  916. ELSE
  917. c := NIL
  918. END;
  919. IF c = NIL THEN
  920. Get(hdr.awaitingLock, t);
  921. IF t = NIL THEN (* none waiting - remove lock *)
  922. hdr.count := 0; hdr.lockedBy := NIL;
  923. ELSE (* transfer lock to first waiting process *)
  924. IF StrongChecks THEN ASSERT(t.mode = AwaitingLock) END;
  925. t.waitingOn := NIL;
  926. hdr.lockedBy := t;
  927. END;
  928. ELSE
  929. c.waitingOn := NIL; hdr.lockedBy := c;
  930. t := NIL;
  931. END;
  932. ELSE (* no lock, or some other process may hold the lock, but that's the user's indaba (may be monotonic condition) *)
  933. Machine.Release(Machine.Objects);
  934. HALT( 2204 ) (* await must be exclusive region *)
  935. END;
  936. r.condition := cond; r.condFP := slink;
  937. r.waitingOn := obj; r.mode := AwaitingCond;
  938. Remove(ready, r);
  939. IF r.event = 0 THEN
  940. r.event := Kernel32.CreateEvent( NIL, Kernel32.False (* auto *), Kernel32.False, NIL ); (* auto-reset event with initial state = reset *)
  941. ASSERT ( r.event # 0, 1239 );
  942. END;
  943. IF c # NIL THEN
  944. DEC(awc); Put(ready, c); c.mode := Running;
  945. res := Kernel32.SetEvent(c.event); (* restart execution *)
  946. ASSERT(res # 0, 1002);
  947. END;
  948. IF t # NIL THEN
  949. DEC(awl); Put(ready, t); t.mode := Running;
  950. res := Kernel32.SetEvent( t.event ); (* restart execution *)
  951. ASSERT(res # 0, 1003);
  952. END;
  953. Put(hdr.awaitingCond, r); INC(awc);
  954. Machine.Release(Machine.Objects);
  955. res := Kernel32.WaitForSingleObject(r.event, Kernel32.Infinite); (* block execution *)
  956. ASSERT(res = Kernel32.WaitObject0);
  957. IF StrongChecks THEN
  958. ASSERT(cond(slink));
  959. ASSERT(hdr.lockedBy = r) (* lock held again *)
  960. END
  961. END Await;
  962. PROCEDURE Break*( t: Process );
  963. CONST MaxTry = 50;
  964. VAR mod: Modules.Module; try: LONGINT; retBOOL: Kernel32.BOOL; (* Dan 09.11.05 *)
  965. PROCEDURE SafeForBreak( mod: Modules.Module ): BOOLEAN;
  966. BEGIN
  967. Trace.String( "Safe for break?: " );
  968. IF mod # NIL THEN
  969. Trace.StringLn ( mod.name );
  970. IF (mod.name = "Trace") OR (mod.name = "Machine") OR
  971. (mod.name = "Heaps") OR (mod.name = "Modules") OR
  972. (mod.name = "Objects") OR (mod.name = "Kernel") THEN
  973. Trace.StringLn ( " - no" ); RETURN FALSE
  974. ELSE Trace.StringLn ( " - yes" ); RETURN TRUE
  975. END
  976. ELSE Trace.StringLn ( "unknown module" ); RETURN FALSE
  977. END
  978. END SafeForBreak;
  979. BEGIN
  980. IF CurrentProcess() # t THEN
  981. Machine.Acquire( Machine.Objects );
  982. LOOP
  983. IF isWow64 THEN
  984. retBOOL := Kernel32.Wow64SuspendThread(t.handle);
  985. ELSE
  986. retBOOL := Kernel32.SuspendThread( t.handle );
  987. END;
  988. t.state.ContextFlags := SYSTEM.VAL(LONGINT, Kernel32.ContextControl);
  989. retBOOL := Kernel32.GetThreadContext( t.handle, t.state );
  990. mod := Modules.ThisModuleByAdr( t.state.PC ); Trace.String( "Objects Break at adr: " );
  991. Trace.Int( t.state.PC, 5 ); Trace.Ln;
  992. IF mod # NIL THEN
  993. Trace.String( "In module: " ); Trace.StringLn ( mod.name );
  994. END;
  995. IF ~SafeForBreak( mod ) (* we do not break Kernel modules *) THEN
  996. retBOOL := Kernel32.ResumeThread( t.handle ); INC( try );
  997. IF try > MaxTry THEN
  998. Trace.StringLn ( "Threads.Break: failed " );
  999. Machine.Release( Machine.Objects );
  1000. RETURN
  1001. END
  1002. ELSE EXIT
  1003. END;
  1004. END;
  1005. (* push cont.Eip *) break[0] := 68X;
  1006. SYSTEM.MOVE( ADDRESSOF( t.state.PC ), ADDRESSOF( break[1] ), 4 );
  1007. (* push ebp *) break[5] := 055X;
  1008. (* mov ebp, esp *) break[6] := 08BX; break[7] := 0ECX;
  1009. (* push 13 *) break[8] := 06AX; break[9] := 0DX;
  1010. (* int 3 *) break[10] := 0CCX;
  1011. (* mov esp, ebp *) break[11] := 08BX; break[12] := 0E5X;
  1012. (* pop ebp *) break[13] := 05DX;
  1013. (* ret *) break[14] := 0C3X; t.state.PC := ADDRESSOF( break[0] );
  1014. retBOOL := Kernel32.SetThreadContext( t.handle, t.state );
  1015. retBOOL := Kernel32.ResumeThread( t.handle ); (* INC( Kernel.GClevel ); *)
  1016. Machine.Release( Machine.Objects );
  1017. ELSE HALT( 99 )
  1018. END;
  1019. END Break;
  1020. (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
  1021. PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
  1022. BEGIN
  1023. terminate(t);
  1024. END TerminateThis;
  1025. PROCEDURE Terminate*;
  1026. BEGIN
  1027. TerminateProc();
  1028. END Terminate;
  1029. PROCEDURE Init; (* can not use NEW *)
  1030. (*VAR lock: PROCEDURE(obj: ProtectedObject; exclusive: BOOLEAN);
  1031. unlock: PROCEDURE(obj: ProtectedObject; dummy: BOOLEAN);
  1032. await: PROCEDURE(cond: Condition; slink: LONGINT; obj: ProtectedObject; flags: SET);
  1033. create: PROCEDURE(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject);
  1034. *)
  1035. VAR t: Process; fn: Heaps.FinalizerNode; proc: Kernel32.HANDLE;
  1036. res: Kernel32.BOOL;
  1037. BEGIN
  1038. Kernel32.AddVectoredExceptionHandler(1, ExcpFrmHandler);
  1039. Kernel32.InitializeCriticalSection(excplock);
  1040. numberOfProcessors := Machine.NumberOfProcessors();
  1041. (* lock := Lock; unlock := Unlock; await := Await; create := CreateProcess;*)
  1042. NEW(t); NEW(fn);
  1043. Machine.Acquire(Machine.Objects);
  1044. nProcs := 1;
  1045. t.next := NIL; t.prev := NIL;
  1046. t.waitingOn := NIL; t.flags := {}; t.obj := NIL;
  1047. t.mode := Unknown; t.body := NIL;
  1048. t.priority := Normal;
  1049. fn.finalizer := FinalizeProcess;
  1050. Heaps.AddFinalizer(t, fn);
  1051. t.handle := Kernel32.GetCurrentThread();
  1052. t.id := Kernel32.GetCurrentThreadId();
  1053. proc := Kernel32.GetCurrentProcess();
  1054. res := Kernel32.DuplicateHandle(proc, t.handle, proc, t.handle, {}, 0, {Kernel32.DuplicateSameAccess});
  1055. ASSERT(res # 0);
  1056. res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(LONGINT, t));
  1057. ASSERT(res # 0);
  1058. t.stackBottom := StackBottom(); t.mode := Running;
  1059. Put( ready, t );
  1060. ASSERT(t.handle # 0);
  1061. Machine.Release(Machine.Objects);
  1062. InitEventHandling; (* implicit call of NewProcess! *)
  1063. InitGCHandling; (* do. *)
  1064. Heaps.gcStatus := GCStatusFactory();
  1065. END Init;
  1066. (** Set (or reset) an event handler object's timeout value. *)
  1067. PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
  1068. VAR e: Timer; trigger: LONGINT;
  1069. BEGIN
  1070. ASSERT(Machine.Second= 1000); (* assume milliseconds for now *)
  1071. ASSERT((t # NIL) & (h # NIL));
  1072. ASSERT(ms >= 0);
  1073. Machine.Acquire(Machine.Objects);
  1074. trigger := Kernel32.GetTickCount() + ms; (* ignore overflow *)
  1075. IF t.next # NIL THEN (* cancel previous timeout *)
  1076. t.next.prev := t.prev; t.prev.next := t.next
  1077. END;
  1078. t.trigger := trigger; t.handler := h;
  1079. e := event.next; (* performance: linear search! *)
  1080. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  1081. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  1082. Machine.Release(Machine.Objects);
  1083. clock.Wakeup()
  1084. END SetTimeout;
  1085. (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
  1086. PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
  1087. VAR e: Timer; trigger: LONGINT;
  1088. BEGIN
  1089. ASSERT(Machine.Second= 1000); (* assume milliseconds for now *)
  1090. ASSERT((t # NIL) & (h # NIL));
  1091. Machine.Acquire(Machine.Objects);
  1092. trigger := ms; (* ignore overflow *)
  1093. IF t.next # NIL THEN (* cancel previous timeout *)
  1094. t.next.prev := t.prev; t.prev.next := t.next
  1095. END;
  1096. t.trigger := trigger; t.handler := h;
  1097. e := event.next; (* performance: linear search! *)
  1098. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  1099. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  1100. Machine.Release(Machine.Objects);
  1101. clock.Wakeup()
  1102. END SetTimeoutAt;
  1103. (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
  1104. PROCEDURE CancelTimeout*( t: Timer );
  1105. BEGIN
  1106. Machine.Acquire(Machine.Objects);
  1107. ASSERT (t # event );
  1108. IF t.next # NIL THEN
  1109. t.next.prev := t.prev;
  1110. IF t.prev#NIL THEN t.prev.next := t.next; END;
  1111. t.next := NIL;
  1112. t.prev := NIL
  1113. END;
  1114. Machine.Release(Machine.Objects);
  1115. END CancelTimeout;
  1116. PROCEDURE InitEventHandling;
  1117. BEGIN
  1118. NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
  1119. NEW(clock);
  1120. END InitEventHandling;
  1121. PROCEDURE InitGCHandling;
  1122. BEGIN
  1123. NEW(finalizerCaller);
  1124. END InitGCHandling;
  1125. PROCEDURE GCStatusFactory(): Heaps.GCStatus;
  1126. VAR gcStatusExt : GCStatusExt;
  1127. BEGIN
  1128. ASSERT(Heaps.gcStatus = NIL);
  1129. NEW(gcStatusExt);
  1130. RETURN gcStatusExt
  1131. END GCStatusFactory;
  1132. PROCEDURE InstallExceptionHandler*( e: ExceptionHandler );
  1133. BEGIN
  1134. exceptionhandler := e;
  1135. END InstallExceptionHandler;
  1136. PROCEDURE UpdateProcessState*( p: Process );
  1137. VAR res: Kernel32.BOOL;
  1138. BEGIN
  1139. res := Kernel32.GetThreadContext( p.handle, p.state );
  1140. ASSERT (p.handle # 0);
  1141. END UpdateProcessState;
  1142. (*ALEX 2005.12.12 added for WMPerfMon needs*)
  1143. PROCEDURE NumReady*( ): LONGINT;
  1144. VAR n: LONGINT; p: Heaps.ProcessLink;
  1145. BEGIN
  1146. n := 0;
  1147. Machine.Acquire( Machine.Objects );
  1148. p := ready.head;
  1149. WHILE p # NIL DO INC( n ); p := p.next END;
  1150. Machine.Release( Machine.Objects );
  1151. RETURN n
  1152. END NumReady;
  1153. (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
  1154. return the number of cycles since the process has been created. If FALSE, return the number of cycles
  1155. consumed since the last time asked. *)
  1156. PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
  1157. VAR res : Kernel32.BOOL; temp : HUGEINT;
  1158. BEGIN
  1159. ASSERT(process # NIL);
  1160. IF (Kernel32.QueryThreadCycleTime # NIL) THEN
  1161. res := Kernel32.QueryThreadCycleTime(process.handle, cpuCycles[0]);
  1162. ELSE
  1163. cpuCycles[0] := Machine.GetTimer(); res := Kernel32.True;
  1164. END;
  1165. IF ~all & (res = Kernel32.True) THEN
  1166. temp := process.lastThreadTimes;
  1167. process.lastThreadTimes := cpuCycles[0];
  1168. cpuCycles[0] := cpuCycles[0] - temp;
  1169. END;
  1170. END GetCpuCycles;
  1171. PROCEDURE CurrentProcessTime*(): HUGEINT;
  1172. VAR res: LONGINT; result: HUGEINT;
  1173. BEGIN
  1174. IF (Kernel32.QueryThreadCycleTime # NIL) THEN
  1175. res := Kernel32.QueryThreadCycleTime(CurrentProcess().handle, result);
  1176. ELSE (* fallback *)
  1177. result := Machine.GetTimer();
  1178. END;
  1179. RETURN result;
  1180. END CurrentProcessTime;
  1181. PROCEDURE TimerFrequency*(): HUGEINT;
  1182. BEGIN
  1183. RETURN 1000000000;
  1184. END TimerFrequency;
  1185. VAR GetProcedureName*: PROCEDURE (pc: ADDRESS; VAR n: ARRAY OF CHAR; VAR spc: ADDRESS);
  1186. PROCEDURE LeaveA2;
  1187. VAR cur: Process; ebp,n: ADDRESS;
  1188. BEGIN
  1189. IF clock = NIL THEN RETURN END;
  1190. cur := CurrentProcess();
  1191. IF cur # NIL THEN
  1192. ebp := Machine.CurrentBP();
  1193. SYSTEM.GET(ebp, n);
  1194. IF ODD(n) THEN SYSTEM.GET(ebp + SIZEOF(ADDRESS), ebp) ELSE ebp := n END;
  1195. cur.gcContext.ebp := ebp;
  1196. END;
  1197. END LeaveA2;
  1198. PROCEDURE ReenterA2;
  1199. VAR cur: Process;
  1200. BEGIN
  1201. IF clock = NIL THEN RETURN END;
  1202. cur := CurrentProcess();
  1203. IF cur # NIL THEN
  1204. cur.gcContext.ebp := NIL;
  1205. END;
  1206. END ReenterA2;
  1207. VAR
  1208. lpContext: Kernel32.Wow64Context;
  1209. TraceProcessHook*: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
  1210. BEGIN
  1211. TraceProcessHook := NIL;
  1212. exceptionhandler := NIL;
  1213. terminateProc := TerminateProc;
  1214. ready.head := NIL; ready.tail := NIL;
  1215. tlsIndex := Kernel32.TlsAlloc();
  1216. ASSERT ( tlsIndex # Kernel32.TLSOutOfIndexes );
  1217. Kernel32.SendToDebugger("Modules.root", ADDRESSOF(Modules.root));
  1218. (* determine whether it is WOW64 environment *)
  1219. TRACE(Kernel32.Wow64GetThreadContext);
  1220. (*
  1221. isWow64 := (Kernel32.Wow64GetThreadContext # NIL) & (Kernel32.Wow64GetThreadContext(Kernel32.GetCurrentThread(),lpContext) # 0);
  1222. TRACE("Objects 5");
  1223. IF isWow64 THEN
  1224. Trace.String("Use Wow64"); Trace.Ln;
  1225. END;
  1226. *)
  1227. Init;
  1228. END Objects.
  1229. (*
  1230. 24.03.1998 pjm Started
  1231. 06.05.1998 pjm CreateProcess init process, page fault handler
  1232. 06.08.1998 pjm Moved exception interrupt handling here for current process
  1233. 17.08.1998 pjm FindRoots method
  1234. 02.10.1998 pjm Idle process
  1235. 06.11.1998 pjm snapshot
  1236. 25.03.1999 pjm Scope removed
  1237. 28.05.1999 pjm EventHandler object
  1238. 01.06.1999 pjm Fixed InterruptProcess lock error
  1239. 16.06.1999 pjm Flat IRQ priority model to avoid GC deadlock
  1240. 23.06.1999 pjm Flat IRQ priority experiment failed, rather do STI in FieldIRQ to avoid GC deadlock
  1241. 29.06.1999 pjm Timeout in EventHandler object
  1242. 13.01.2000 pjm Overed (Interrupt Objects, Event Handlers, Process ID, Process state, Process mode, Process stack, Await)
  1243. 17.10.2000 pjm Priorities
  1244. 22.10.2003 mib SSE2 extension
  1245. 24.10.2003 phk Priority inversion / cycle counters
  1246. Stack invariant for GC:
  1247. o if process is running, the processor registers contain its state
  1248. o if process is not running, at least state.ESP is valid, and between stack.adr and stack.high (for GC)
  1249. o when releasing the Ready lock, make sure the process state is up to date
  1250. *)
  1251. SystemTools.ShowStacks ~
  1252. Heaps.SetMetaData
  1253. StaticLinker.Link --fileFormat=PE32 --fileName=A2GC.exe --extension=GofW --displacement=401000H Runtime Trace Kernel32 Machine Heaps Modules Objects Kernel KernelLog Streams Commands FIles WinFS Clock Dates Reals Strings Diagnostics BitSets StringPool ObjectFile GenericLinker Reflection GenericLoader BootConsole ~