Windows.Objects.Mod 45 KB

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