Windows.Objects.Mod 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697
  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. (*#IF SHAREDLIB THEN*)
  19. External = 13; (* external (non A2) process attached in case of a DLL *)
  20. (*#END;*)
  21. InActive* = 26; (* needed to prevent processes to call finalizers while in await or lock or unlock, see Kernel.GC *)
  22. (** Process modes *)
  23. Unknown* = 0; Ready* = 1; (* for compatibility with native A2 *)
  24. Running* = 2; AwaitingLock* = 3; AwaitingCond* = 4; AwaitingEvent* = 5; Suspended* = 6; Terminated* = 7;
  25. (** Process priorities *)
  26. MinPriority = 0; (* only system idle processes run at this priority level *)
  27. Low* = 1; Normal* = 2; High* = 3; (* "user" priorities *)
  28. GCPriority* = 4; (* priority of garbage collector *)
  29. Realtime* = 5; (* reserved for interrupt handling and realtime apps, these processes are not allowed to allocate memory *)
  30. (* Process termination halt codes *)
  31. halt* = 2222;
  32. haltUnbreakable* = 2223;
  33. TYPE
  34. CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
  35. ProtectedObject = POINTER TO RECORD END; (* protected object (10000) *)
  36. ProcessQueue = Heaps.ProcessQueue;
  37. Body = PROCEDURE (self: ProtectedObject);
  38. Condition = PROCEDURE (slink: ADDRESS): BOOLEAN;
  39. EventHandler* = PROCEDURE {DELEGATE};
  40. RealtimeEventHandler* = PROCEDURE {DELEGATE, REALTIME};
  41. Timer* = POINTER TO RECORD
  42. next, prev : Timer;
  43. trigger: LONGINT;
  44. handler: EventHandler
  45. END;
  46. RealtimeTimer* = POINTER TO RECORD
  47. next, prev: RealtimeTimer;
  48. trigger: LONGINT;
  49. handler: RealtimeEventHandler
  50. END;
  51. Clock = OBJECT
  52. VAR h: Timer;
  53. ticks: LONGINT;
  54. hevent: Kernel32.HANDLE;
  55. res: Kernel32.BOOL;
  56. mode: LONGINT;
  57. process: Process;
  58. exiting: BOOLEAN;
  59. PROCEDURE Wakeup;
  60. VAR res: Kernel32.BOOL;
  61. BEGIN {EXCLUSIVE}
  62. res := Kernel32.SetEvent(hevent)
  63. END Wakeup;
  64. PROCEDURE Exit;
  65. BEGIN
  66. exiting := TRUE;
  67. Wakeup;
  68. END Exit;
  69. PROCEDURE Finalize(ptr: ANY);
  70. BEGIN
  71. Exit;
  72. END Finalize;
  73. PROCEDURE &Init*;
  74. VAR fn: Heaps.FinalizerNode;
  75. BEGIN
  76. hevent := Kernel32.CreateEvent(NIL, 0, 0, NIL);
  77. ASSERT(hevent # 0);
  78. NEW(fn); fn.finalizer := SELF.Finalize; Heaps.AddFinalizer(SELF, fn)
  79. END Init;
  80. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  81. process := CurrentProcess();
  82. mode := process.mode;
  83. LOOP
  84. Machine.Acquire(Machine.Objects);
  85. process.mode := mode;
  86. LOOP
  87. h := event.next; (* event: head of timer event queue *)
  88. ticks := Kernel32.GetTickCount();
  89. IF (h = event) OR (h.trigger - ticks > 0) THEN EXIT END;
  90. event.next := h.next; event.next.prev := event; (* unlink *)
  91. h.next := NIL; h.prev := NIL;
  92. Machine.Release(Machine.Objects);
  93. h.handler(); (* assume handler will return promptly *)
  94. Machine.Acquire(Machine.Objects)
  95. END;
  96. mode := process.mode;
  97. process.mode := AwaitingEvent;
  98. Machine.Release(Machine.Objects);
  99. IF h = event THEN (* sentinel head of timer event queue: wait forever until a new event has been entered in queue *)
  100. res := Kernel32.WaitForSingleObject(hevent, MAX(LONGINT));
  101. ELSE
  102. res := Kernel32.WaitForSingleObject(hevent, h.trigger - ticks);
  103. END;
  104. IF exiting THEN EXIT; END;
  105. END;
  106. process.mode := Running; (*! avoid a trap in terminate *)
  107. IF hevent # 0 THEN res := Kernel32.CloseHandle(hevent); END;
  108. END Clock;
  109. TYPE
  110. Win32Event = Kernel32.HANDLE;
  111. GCContext = RECORD
  112. nextPos: SIZE; (* 0 to start with *)
  113. (*first,*) last: ARRAY 256 OF ADDRESS; (* first might be not required *)
  114. END;
  115. Process* = OBJECT(Heaps.ProcessLink)
  116. VAR
  117. rootedNext : Process; (* to prevent process to be GCed in WinAos *)
  118. obj-: ProtectedObject; (* associated active object *)
  119. state- {ALIGNED=16}: Kernel32.Context;
  120. condition-: Condition; (* awaited process' condition *)
  121. condFP-: ADDRESS; (* awaited process' condition's context *)
  122. mode-: LONGINT; (* process state *) (* only changed inside Objects lock ??? *)
  123. procID-: LONGINT; (* processor ID where running, exported for compatibilty , useless in WinAos *)
  124. waitingOn-: ProtectedObject; (* obj this process is waiting on (for lock or condition) *)
  125. id-: LONGINT; (* unique process ID for tracing *)
  126. flags*: SET; (* process flags *)
  127. priority-: LONGINT; (* process priority *)
  128. stackBottom: ADDRESS;
  129. handle-: Kernel32.HANDLE; (* handle to corresponding Windows thread *)
  130. body: Body;
  131. event: Win32Event;
  132. restartPC-: ADDRESS; (** entry point of body, for SAFE exception recovery *)
  133. restartSP-: ADDRESS; (** stack level at start of body, for SAFE exception recovery *)
  134. lastThreadTimes: HUGEINT; (*ALEX 2005.12.12*)
  135. gcContext: GCContext;
  136. context: ANY; (* commands contect *)
  137. PROCEDURE FindRoots; (* override, called while GC, replaces Threads.CheckStacks *)
  138. VAR sp: ADDRESS; res: Kernel32.BOOL; pc, bp: ADDRESS;
  139. n,adr: ADDRESS; desc {UNTRACED}: Modules.ProcedureDescPointer; p {UNTRACED}: ANY; i: SIZE;
  140. a0,a1, obp, osb, osbp, opc, gbp: ADDRESS;
  141. O: ANY; ID: LONGINT;
  142. mod {UNTRACED}: Modules.Module;
  143. proc {UNTRACED}: Modules.ProcedureDescPointer;
  144. modName: ARRAY 128 OF CHAR;
  145. contextPos: SIZE;
  146. BEGIN{UNCHECKED} (* avoid winapi call indirection *)
  147. O := obj; ID := id;
  148. IF (handle = 0) OR (mode = Terminated) OR (mode < Ready) (* procedure Wrapper not yet started *)
  149. OR (priority > High) (* stack of GC and realtime processes not traced *) THEN
  150. RETURN
  151. END;
  152. IF CurrentProcess() = SELF THEN
  153. sp := SYSTEM.GetStackPointer(); bp :=SYSTEM.GetFramePointer(); pc := Machine.CurrentPC();
  154. ELSE
  155. res := Kernel32.SuspendThread(handle); (* can suspend a suspended thread -- no problem at all *)
  156. state.ContextFlags := Kernel32.ContextControl + Kernel32.ContextInteger;
  157. res := Kernel32.GetThreadContext( handle, state );
  158. IF res = 0 THEN Trace.String("could not get thread context:"); Trace.Int(Kernel32.GetLastError(),1) END;
  159. sp := state.SP; bp := state.BP; pc := state.PC;
  160. mod := Modules.ThisModuleByAdr0(pc);
  161. IF mod # NIL THEN
  162. COPY(mod.name, modName);
  163. proc := Modules.FindProc(pc,mod.procTable);
  164. END;
  165. obp := bp; osb := stackBottom; opc := pc;
  166. osbp := state.BP;
  167. END;
  168. IF TraceProcessHook # NIL THEN
  169. TraceProcessHook(SELF,pc,bp,sp,stackBottom);
  170. END;
  171. contextPos := gcContext.nextPos;
  172. IF contextPos < 0 THEN RETURN END; (* this thread is currently not active in A2 *)
  173. (* stack garbage collection *)
  174. IF Heaps.GCType= Heaps.HeuristicStackInspectionGC THEN
  175. #IF I386 THEN
  176. Heaps.Candidate( state.RDI ); Heaps.Candidate( state.RSI );
  177. Heaps.Candidate( state.RB ); Heaps.Candidate( state.RD );
  178. Heaps.Candidate( state.RC ); Heaps.Candidate( state.RA );
  179. #ELSIF AMD64 THEN
  180. Heaps.Candidate( state.RDI ); Heaps.Candidate( state.RSI );
  181. Heaps.Candidate( state.RB ); Heaps.Candidate( state.RD );
  182. Heaps.Candidate( state.RC ); Heaps.Candidate( state.RA );
  183. Heaps.Candidate( state.R9 ); Heaps.Candidate( state.R10 );
  184. Heaps.Candidate( state.R11 ); Heaps.Candidate( state.R12 );
  185. Heaps.Candidate( state.R13 ); Heaps.Candidate( state.R14 );
  186. Heaps.Candidate( state.R15 );
  187. #ELSE
  188. ASSERT(FALSE);
  189. #END
  190. IF (stackBottom # 0) & (sp # 0) THEN
  191. Heaps.RegisterCandidates( sp, stackBottom - sp );
  192. END;
  193. ELSIF Heaps.GCType = Heaps.MetaDataForStackGC THEN
  194. IF TraceVerbose THEN
  195. Trace.String("GC, process id = "); Trace.Int(id,1); Trace.Ln;
  196. END;
  197. LOOP
  198. IF (bp = NIL) OR (bp >= stackBottom) THEN EXIT END;
  199. IF Machine.ValidHeapAddress(pc) THEN
  200. (* ok, valid stack frame from A2, we can trace this *)
  201. ELSE
  202. (* no, cannot trace this Windows stack frame, we have to check if we recorded when we exited A2 previously *)
  203. bp := NIL;
  204. WHILE (contextPos > 0) & (bp = NIL) DO
  205. DEC(contextPos);
  206. bp := gcContext.last[contextPos];
  207. END;
  208. IF bp = NIL THEN
  209. EXIT;
  210. END;
  211. END;
  212. SYSTEM.GET(bp, n);
  213. IF ODD(n) THEN (* procedure descriptor at bp *)
  214. desc := SYSTEM.VAL(Modules.ProcedureDescPointer, n-1);
  215. IF desc # NIL THEN
  216. IF TraceVerbose THEN
  217. WriteType(desc); Trace.Ln;
  218. END;
  219. a0 := ADDRESSOF(desc.offsets);
  220. a1 := SYSTEM.VAL(ADDRESS, desc.offsets);
  221. ASSERT(a0+SIZEOF(ADDRESS)=a1,54321);
  222. FOR i := 0 TO LEN(desc.offsets)-1 DO
  223. adr := bp + desc.offsets[i]; (* pointer at offset *)
  224. SYSTEM.GET(adr, p); (* load pointer *)
  225. IF p # NIL THEN
  226. Heaps.Mark(p);
  227. END;
  228. END;
  229. END;
  230. SYSTEM.GET(bp + 2*SIZEOF(ADDRESS), pc);
  231. SYSTEM.GET(bp + SIZEOF(ADDRESS), bp);
  232. ELSE (* classical stack frame without procedure descriptor *)
  233. SYSTEM.GET(bp + SIZEOF(ADDRESS), pc);
  234. bp := n;
  235. END;
  236. END;
  237. (* ASSERT((bp = stackBottom) OR (bp=0) ,12345); can be violated when coming from windows *)
  238. END;
  239. IF (CurrentProcess() # SELF) (* & (mode # Suspended) *) THEN
  240. res := Kernel32.ResumeThread(handle);
  241. ASSERT(res # -1);
  242. END;
  243. END FindRoots;
  244. END Process;
  245. TYPE
  246. ExceptionHandler* = PROCEDURE( VAR context: Kernel32.Context;
  247. VAR excpRec: Kernel32.ExceptionRecord;
  248. VAR handled: BOOLEAN);
  249. GCStatusExt = OBJECT(Heaps.GCStatus)
  250. (* called from Heaps.InvokeGC, i.e. this is a hidden upcall. However, it is necessary to take the Machine.Objects lock here since writing
  251. 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
  252. if the lock is not taken. *)
  253. PROCEDURE SetgcOngoing(value: BOOLEAN);
  254. VAR p: Heaps.ProcessLink; cur, r: Process; res: Kernel32.BOOL; num: LONGINT; time: LONGINT;
  255. BEGIN (* serialize writers *)
  256. IF value THEN
  257. (* Low, Medium or High priority process calls this *)
  258. time := Kernel32.GetTickCount();
  259. Machine.Acquire(Machine.Objects);
  260. Machine.Acquire(Machine.Heaps); (* to protect agains concurrent LazySweep *)
  261. r := CurrentProcess();
  262. num := 0;
  263. p := ready.head;
  264. WHILE p # NIL DO
  265. cur := p(Process);
  266. IF ((cur.mode = Ready) OR (cur.mode = Running)) & (cur.priority <= High) & (cur # r) & (cur.gcContext.nextPos >= 0) THEN
  267. res := Kernel32.SuspendThread(cur.handle);
  268. ASSERT(res >= 0);
  269. cur.mode := Suspended
  270. ELSE INC(num);
  271. END;
  272. p := p.next
  273. END;
  274. Heaps.CollectGarbage(Modules.root);
  275. p := ready.head;
  276. WHILE (p # NIL) DO
  277. cur := p(Process);
  278. (* only suspended and awaiting processes of ready queue are resumed *)
  279. IF cur.mode = Suspended THEN
  280. res := Kernel32.ResumeThread(cur.handle);
  281. ASSERT(res >= 0);
  282. cur.mode := Running
  283. END;
  284. p := p.next
  285. END;
  286. Machine.Release(Machine.Heaps);
  287. Machine.Release(Machine.Objects);
  288. time := Kernel32.GetTickCount()-time;
  289. IF Heaps.trace THEN Trace.String("GC Called -- duration "); Trace.Int(time,0); Trace.String(" ms."); Trace.Ln END;
  290. IF finalizerCaller # NIL THEN finalizerCaller.Activate() END;
  291. END;
  292. END SetgcOngoing;
  293. END GCStatusExt;
  294. FinalizedCollection* = OBJECT
  295. PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
  296. BEGIN HALT(301) END RemoveAll;
  297. END FinalizedCollection;
  298. FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
  299. c*: FinalizedCollection (* base type for collection containing object *)
  300. END;
  301. FinalizerCaller = OBJECT (* separate active object that calls finalizers *)
  302. VAR n: Heaps.FinalizerNode;
  303. event: Kernel32.HANDLE;
  304. process: Process;
  305. exiting: BOOLEAN;
  306. PROCEDURE &Init;
  307. BEGIN
  308. event := Kernel32.CreateEvent( NIL, Kernel32.False (* automatic *), Kernel32.False, NIL );
  309. ASSERT(event # 0);
  310. END Init;
  311. PROCEDURE Wait(): BOOLEAN;
  312. VAR res: Kernel32.BOOL; mode: LONGINT;
  313. BEGIN
  314. mode := process.mode;
  315. process.mode := AwaitingEvent;
  316. res := Kernel32.WaitForSingleObject(event, Kernel32.Infinite);
  317. process.mode := mode;
  318. ASSERT(res = Kernel32.WaitObject0);
  319. IF ~exiting THEN
  320. RETURN TRUE;
  321. ELSE
  322. RETURN FALSE;
  323. END;
  324. END Wait;
  325. PROCEDURE Activate;
  326. VAR res: Kernel32.BOOL;
  327. BEGIN
  328. res := Kernel32.SetEvent(event);
  329. END Activate;
  330. PROCEDURE Exit;
  331. BEGIN
  332. exiting := TRUE;
  333. Activate;
  334. END Exit;
  335. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  336. process := CurrentProcess();
  337. WHILE Wait() DO
  338. LOOP
  339. n := Heaps.GetFinalizer();
  340. IF n = NIL THEN EXIT END;
  341. IF n IS FinalizerNode THEN
  342. n( FinalizerNode ).c.RemoveAll( n.objStrong ) (* remove it if it is not removed yet *)
  343. END;
  344. IF n.finalizer # NIL THEN
  345. n.finalizer( n.objStrong ) (* may acquire locks *)
  346. END
  347. END;
  348. END;
  349. IF event # 0 THEN IGNORE Kernel32.CloseHandle(event); END;
  350. END FinalizerCaller;
  351. VAR
  352. awc-, awl-: LONGINT;
  353. oberonLoop*: ANY; (* Oberon Loop Process temporary workaround for Threads.oberonLoop *)
  354. break: ARRAY 16 OF CHAR;
  355. terminateProc: PROCEDURE;
  356. ready: ProcessQueue; (* contains running processes in this implementation *)
  357. numberOfProcessors: LONGINT; (* cached value of Machine.NumberOfProcessors() *)
  358. finalizerCaller: FinalizerCaller; (* active object for finalizer process, regarded as aprt of GC *)
  359. event: Timer; (* list of events *)
  360. clock: Clock;
  361. tlsIndex: LONGINT;
  362. nProcs: LONGINT;
  363. excplock: Kernel32.CriticalSection; exceptionhandler: ExceptionHandler;
  364. (* Set the current process' priority. *)
  365. PROCEDURE SetPriority*( priority: LONGINT );
  366. VAR r: Process; prio: LONGINT; res: Kernel32.BOOL;
  367. BEGIN
  368. ASSERT((priority >= Low) & (priority <= Realtime)); (* priority in bounds *)
  369. r := CurrentProcess(); r.priority := priority;
  370. CASE priority OF
  371. MinPriority:
  372. prio := Kernel32.ThreadPriorityIdle
  373. | Low:
  374. prio := Kernel32.ThreadPriorityBelowNormal
  375. | High:
  376. prio := Kernel32.ThreadPriorityAboveNormal
  377. | GCPriority, Realtime:
  378. prio := Kernel32.ThreadPriorityTimeCritical
  379. ELSE (* Normal *)
  380. prio := Kernel32.ThreadPriorityNormal
  381. END;
  382. res := Kernel32.SetThreadPriority( r.handle, prio );
  383. ASSERT(r.handle # 0);
  384. ASSERT(res # 0)
  385. END SetPriority;
  386. (** Return TRUE iff the specified protected object is locked exclusive to the current process. *)
  387. PROCEDURE LockedByCurrent*( obj: ANY ): BOOLEAN;
  388. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: BOOLEAN;
  389. BEGIN
  390. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  391. ASSERT(hdr IS Heaps.ProtRecBlock);
  392. Machine.Acquire(Machine.Objects);
  393. res := (hdr.lockedBy = ActiveObject());
  394. Machine.Release(Machine.Objects);
  395. RETURN res
  396. END LockedByCurrent;
  397. PROCEDURE Yield*;
  398. BEGIN
  399. Kernel32.Sleep(0)
  400. END Yield;
  401. (** Return current process. (DEPRECATED, use ActiveObject) *)
  402. PROCEDURE CurrentProcess*( ): Process;
  403. BEGIN{UNCHECKED} (* makes sure that Enter and Leave are not emitted *)
  404. RETURN SYSTEM.VAL(Process, Kernel32.TlsGetValue(tlsIndex));
  405. END CurrentProcess;
  406. PROCEDURE CurrentContext*(): ANY;
  407. VAR p: Process;
  408. BEGIN
  409. p := CurrentProcess();
  410. IF p # NIL THEN RETURN p.context
  411. ELSE RETURN NIL
  412. END;
  413. END CurrentContext;
  414. PROCEDURE SetContext*(context: ANY);
  415. VAR p: Process;
  416. BEGIN
  417. p := CurrentProcess();
  418. IF p # NIL THEN p.context := context END;
  419. END SetContext;
  420. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  421. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  422. BEGIN
  423. RETURN p.stackBottom
  424. END GetStackBottom;
  425. (** Return the active object currently executing. *)
  426. PROCEDURE ActiveObject* (): ANY;
  427. VAR r: Process;
  428. BEGIN
  429. r := SYSTEM.VAL(Process, Kernel32.TlsGetValue(tlsIndex));
  430. RETURN r.obj
  431. END ActiveObject;
  432. (** Return the ID of the active currently executing process. *)
  433. PROCEDURE GetProcessID* (): LONGINT;
  434. VAR r: Process;
  435. BEGIN
  436. r := SYSTEM.VAL (Process, Kernel32.TlsGetValue( tlsIndex ));
  437. RETURN r.id
  438. END GetProcessID;
  439. (* Get a process from a queue (NIL if none). Caller must hold lock for specific queue. *)
  440. PROCEDURE Get(VAR queue: ProcessQueue; VAR new: Process);
  441. VAR t: Heaps.ProcessLink;
  442. BEGIN
  443. t := queue.head;
  444. IF t = NIL THEN (* zero elements in queue *)
  445. (* skip *)
  446. ELSIF t = queue.tail THEN (* one element in queue *)
  447. queue.head := NIL; queue.tail := NIL (* {(t.next = NIL) & (t.prev = NIL)} *)
  448. ELSE (* more than one element in queue *)
  449. queue.head := t.next; t.next := NIL; queue.head.prev := NIL
  450. END;
  451. ASSERT((t = NIL) OR (t.next = NIL ) & (t.prev = NIL)); (* temp strong check *)
  452. IF t = NIL THEN
  453. new := NIL
  454. ELSE
  455. ASSERT(t IS Process);
  456. new := t(Process)
  457. END
  458. END Get;
  459. (* Put a process in a queue. Caller must hold lock for specific queue. *)
  460. (* If t was running, be careful to protect Put and the subsequent SwitchTo with the ready lock. *)
  461. PROCEDURE Put(VAR queue: ProcessQueue; t: Process);
  462. BEGIN (* {t # NIL & t.next = NIL & t.prev = NIL} *)
  463. IF StrongChecks THEN
  464. ASSERT((t.next = NIL) & (t.prev = NIL))
  465. END;
  466. t.next := NIL; t.prev := NIL; (* ug *)
  467. IF queue.head = NIL THEN (* queue empty *)
  468. queue.head := t
  469. ELSE (* queue not empty *)
  470. queue.tail.next := t; t.prev := queue.tail
  471. END;
  472. queue.tail := t
  473. END Put;
  474. PROCEDURE {WINAPI} ExcpFrmHandler( CONST exceptionPointers: Kernel32.ExceptionPointers): Kernel32.DWORD ;
  475. VAR m: Modules.Module; eip, ebp, stack: ADDRESS; pc, handler, fp, sp: ADDRESS; handled: BOOLEAN; t: Process;
  476. BEGIN
  477. handled := FALSE;
  478. Kernel32.EnterCriticalSection( excplock );
  479. (*
  480. fof: commenting this resolved a problem with multiple traps that a are catched with FINALLY statements in Windows Vista
  481. in Windows XP not necessary if Kernel32.SetThreadContext is not used (better to return gracefully from this handler)
  482. SetCurrent(excpFrame);
  483. *)
  484. t := CurrentProcess();
  485. IF exceptionhandler = NIL THEN
  486. Trace.StringLn ( "Objects: No exception handler installed" );
  487. IF HandleExcp THEN
  488. Trace.String( "EXCEPTION " ); Trace.Address(exceptionPointers.exception.ExceptionCode);
  489. Trace.String( " at " ); Trace.Address(exceptionPointers.exception.ExceptionAddress);
  490. #IF I386 THEN
  491. Trace.Ln(); Trace.String( "EAX " ); Trace.Hex( exceptionPointers.context.RA, 1 );
  492. Trace.String( " EBX " ); Trace.Hex( exceptionPointers.context.RB, 1 ); Trace.Ln();
  493. Trace.String( "ECX " ); Trace.Hex( exceptionPointers.context.RC, 1 ); Trace.String( " EDX " );
  494. Trace.Hex( exceptionPointers.context.RD, 1 ); Trace.Ln(); Trace.String( "EDI " );
  495. Trace.Hex( exceptionPointers.context.RDI, 1 ); Trace.String( " ESI " );
  496. Trace.Hex( exceptionPointers.context.RSI, 1 ); Trace.Ln();
  497. #ELSIF AMD64 THEN
  498. Trace.Ln(); Trace.String( "RAX " ); Trace.Address(exceptionPointers.context.RA);
  499. Trace.String( " RBX " ); Trace.Address(exceptionPointers.context.RB); Trace.Ln();
  500. Trace.String( "RCX " ); Trace.Address(exceptionPointers.context.RC); Trace.String( " RDX " );
  501. Trace.Address(exceptionPointers.context.RD); Trace.Ln(); Trace.String( "RDI " );
  502. Trace.Address(exceptionPointers.context.RDI); Trace.String( " RSI " );
  503. Trace.Address(exceptionPointers.context.RSI); Trace.Ln();
  504. Trace.String( "R8 " ); Trace.Address(exceptionPointers.context.R8);
  505. Trace.String( " R9 " ); Trace.Address(exceptionPointers.context.R9); Trace.Ln();
  506. Trace.String( "R10 " ); Trace.Address(exceptionPointers.context.R10);
  507. Trace.String( " R11 " ); Trace.Address(exceptionPointers.context.R11); Trace.Ln();
  508. Trace.String( "R12 " ); Trace.Address(exceptionPointers.context.R12);
  509. Trace.String( " R13 " ); Trace.Address(exceptionPointers.context.R13); Trace.Ln();
  510. Trace.String( "R14 " ); Trace.Address(exceptionPointers.context.R14);
  511. Trace.String( " R15 " ); Trace.Address(exceptionPointers.context.R15); Trace.Ln();
  512. Trace.Ln;
  513. #ELSE
  514. -- UNIMPLEMENTED --
  515. #END
  516. Trace.String( "BP " );
  517. Trace.Address(exceptionPointers.context.BP); Trace.String( " SP " );
  518. Trace.Address(exceptionPointers.context.SP); Trace.Ln(); Trace.String( "PC " );
  519. Trace.Address(exceptionPointers.context.PC); Trace.Ln();
  520. Trace.Ln();
  521. eip := exceptionPointers.exception.ExceptionAddress; ebp := exceptionPointers.context.BP;
  522. IF eip = 0 THEN SYSTEM.GET( exceptionPointers.context.SP, eip ) END;
  523. stack := t.stackBottom;
  524. LOOP
  525. Trace.String( "at ebp= " ); Trace.Address(ebp); Trace.String( "H : " );
  526. m := Modules.ThisModuleByAdr( eip );
  527. IF m # NIL THEN
  528. Trace.String( m.name ); Trace.String( " " );
  529. Trace.Address(eip - SYSTEM.VAL( LONGINT, ADDRESSOF( m.code[0] ) ));
  530. ELSE Trace.String( "EIP " ); Trace.Address(eip)
  531. END;
  532. Trace.Ln();
  533. IF (ebp # 0) & (ebp < stack) THEN (* if ebp is 0 in first frame *)
  534. SYSTEM.GET( ebp + SIZEOF(ADDRESS), eip ); (* return addr from stack *)
  535. SYSTEM.GET( ebp, ebp ); (* follow dynamic link *)
  536. ELSE EXIT
  537. END
  538. END;
  539. Trace.Ln();
  540. handled := FALSE; fp := exceptionPointers.context.BP; sp := exceptionPointers.context.SP;
  541. pc := exceptionPointers.context.PC; handler := Modules.GetExceptionHandler( pc );
  542. IF handler # -1 THEN (* Handler in the current PAF *)
  543. exceptionPointers.context.PC := handler; handled := TRUE;
  544. (*SetTrapVariable(pc, fp); SetLastExceptionState(exc)*)
  545. ELSE
  546. WHILE (fp # 0) & (handler = -1) DO
  547. SYSTEM.GET( fp + SIZEOF(ADDRESS), pc );
  548. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  549. handler := Modules.GetExceptionHandler( pc );
  550. sp := fp; (* Save the old framepointer into the stack pointer *)
  551. SYSTEM.GET( fp, fp ) (* Unwind PAF *)
  552. END;
  553. IF handler = -1 THEN handled := FALSE;
  554. ELSE
  555. exceptionPointers.context.PC := handler; exceptionPointers.context.BP := fp; exceptionPointers.context.SP := sp;
  556. (* SetTrapVariable(pc, fp); SetLastExceptionState(exc);*)
  557. handled := TRUE
  558. END
  559. END;
  560. ELSE Trace.StringLn ( "Warning: FINALLY statement cannot be treated !" );
  561. END
  562. ELSE exceptionhandler(exceptionPointers.context^, exceptionPointers.exception^,handled );
  563. END;
  564. IF ~handled THEN
  565. exceptionPointers.context.PC := t.restartPC ;
  566. exceptionPointers.context.SP := t.restartSP;
  567. exceptionPointers.context.BP := t.stackBottom;
  568. ELSIF TraceVerbose THEN Trace.StringLn ( "trying to jump to FINALLY pc..." );
  569. END;
  570. Kernel32.LeaveCriticalSection( excplock );
  571. IF TraceVerbose THEN
  572. Machine.Acquire (Machine.TraceOutput);
  573. Trace.String( "recover process; pc=" ); Trace.Address( exceptionPointers.context.PC );
  574. Trace.String( "; sp= " ); Trace.Address( exceptionPointers.context.SP); Trace.String( "; bp= " );
  575. Trace.Address( exceptionPointers.context.BP); Trace.Ln;
  576. Machine.Release (Machine.TraceOutput);
  577. END;
  578. RETURN Kernel32.ExceptionContinueExecution; (* sets thread context and continues where specified in context *)
  579. END ExcpFrmHandler;
  580. PROCEDURE RemoveExcpFrm( VAR excpfrm: Kernel32.ExcpFrm );
  581. VAR this: Kernel32.ExcpFrmPtr;
  582. BEGIN
  583. IGNORE Kernel32.RemoveVectoredContinueHandler(ExcpFrmHandler);
  584. END RemoveExcpFrm;
  585. PROCEDURE InstallExcpFrm( VAR excpfrm: Kernel32.ExcpFrm );
  586. BEGIN
  587. Kernel32.AddVectoredContinueHandler(1, ExcpFrmHandler);
  588. END InstallExcpFrm;
  589. PROCEDURE InQueue( queue: ProcessQueue; t: Process ): BOOLEAN;
  590. VAR p: Heaps.ProcessLink;
  591. BEGIN
  592. p := queue.head;
  593. WHILE (p # NIL ) & (p # t) DO p := p.next; END;
  594. RETURN (p = t);
  595. END InQueue;
  596. (* Remove a process from a queue that contains it. Caller must hold lock for specific queue. *)
  597. (* Not intended for frequent use. *)
  598. (* does not check if queue contained t ! *)
  599. PROCEDURE Remove( VAR queue: ProcessQueue; t: Process );
  600. BEGIN
  601. IF StrongChecks THEN
  602. ASSERT(InQueue(queue, t));
  603. ASSERT(t # NIL);
  604. END;
  605. IF t.prev # NIL THEN t.prev.next := t.next END;
  606. IF t.next # NIL THEN t.next.prev := t.prev END;
  607. IF t = queue.head THEN queue.head := t.next END;
  608. IF t = queue.tail THEN queue.tail := t.prev END;
  609. ASSERT((queue.head = NIL) OR (queue.head.prev = NIL) & (queue.tail.next = NIL));
  610. t.prev := NIL; t.next := NIL
  611. END Remove;
  612. PROCEDURE WriteType(obj: ANY);
  613. VAR type: LONGINT;
  614. BEGIN
  615. IF obj = NIL THEN Trace.String(" > NIL");
  616. ELSE
  617. Trace.String(" > "); SYSTEM.GET(SYSTEM.VAL(LONGINT, obj) + Heaps.TypeDescOffset, type);
  618. Heaps.WriteType(type);
  619. END;
  620. END WriteType;
  621. PROCEDURE terminate( t: Process );
  622. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; res: Kernel32.BOOL; shutdown: BOOLEAN;
  623. BEGIN
  624. IF t = NIL THEN RETURN END;
  625. (* see Objects.TerminateThis *)
  626. Machine.Acquire( Machine.Objects );
  627. IF TraceVerbose OR TraceOpenClose THEN
  628. Machine.Acquire (Machine.TraceOutput);
  629. Trace.String( "Terminating process " ); Trace.Int( t.id, 1 ); WriteType( t.obj ); Trace.Ln;
  630. Machine.Release (Machine.TraceOutput);
  631. END;
  632. IF (t.mode = Ready) OR (t.mode = Running) THEN Remove( ready, t );
  633. ELSIF t.mode = AwaitingLock THEN
  634. SYSTEM.GET(SYSTEM.VAL(ADDRESS, t.waitingOn) + Heaps.HeapBlockOffset, hdr);
  635. ASSERT(hdr IS Heaps.ProtRecBlock);
  636. Remove( hdr.awaitingLock, t ); Machine.Release( Machine.Objects );
  637. HALT( 97 )
  638. ELSIF t.mode = AwaitingCond THEN
  639. SYSTEM.GET(SYSTEM.VAL(ADDRESS, t.waitingOn) + Heaps.HeapBlockOffset, hdr);
  640. ASSERT(hdr IS Heaps.ProtRecBlock);
  641. Remove( hdr.awaitingCond, t ); Machine.Release( Machine.Objects );
  642. HALT( 98 )
  643. ELSE Machine.Release( Machine.Objects );
  644. HALT( 99 )
  645. END;
  646. t.mode := Terminated; (* a process can also be "terminated" if the queue containing it is garbage collected *)
  647. t.stackBottom := 0; t.state.SP := 0;
  648. t.restartPC := 0;
  649. IF t.event # 0 THEN res := Kernel32.CloseHandle( t.event ); t.event := 0 END;
  650. DEC( nProcs ); shutdown := (nProcs = 0);
  651. Machine.Release( Machine.Objects );
  652. IF shutdown THEN
  653. Trace.StringLn ( " Objects: shutdown" ); Modules.Shutdown( -1 );
  654. Kernel32.ExitProcess( 0 )
  655. END
  656. END terminate;
  657. PROCEDURE {WINAPI} Wrapper( lpParameter: ANY ): LONGINT;
  658. VAR t: Process; obj: ProtectedObject; res: Kernel32.BOOL; bp,sp: ADDRESS;
  659. excpfrm: Kernel32.ExcpFrm;
  660. BEGIN
  661. (* it may happen that the garbage collector runs right here and ignores this procedure.
  662. This is not a problem since lpParameter (being a reference to a process) is protected by the process lists *)
  663. Machine.Acquire(Machine.Objects);
  664. res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(ADDRESS, lpParameter));
  665. t := lpParameter(Process); obj := t.obj;
  666. ASSERT(res # 0);
  667. SetPriority(t.priority);
  668. bp := SYSTEM.GetFramePointer();
  669. sp := SYSTEM.GetStackPointer();
  670. t.restartSP := sp;
  671. t.stackBottom := bp;
  672. IF t.restartPC = SYSTEM.VAL(ADDRESS, terminateProc) THEN DEC(t.restartSP, SIZEOF(ADDRESS))
  673. ELSE DEC(t.restartSP, 2*SIZEOF(ADDRESS))
  674. END;
  675. IF TraceVerbose THEN
  676. Machine.Acquire(Machine.TraceOutput);
  677. Trace.String("New process; restartPC= "); Trace.Address(t.restartPC);
  678. Trace.String("; stackBottom= ");
  679. Trace.Address(t.stackBottom);
  680. Trace.String("; id= ");
  681. Trace.Int(t.id,0); Trace.Ln;
  682. Machine.Release(Machine.TraceOutput);
  683. END;
  684. t.mode := Running;
  685. (* now gc is enabled for this process stack *)
  686. Machine.Release(Machine.Objects);
  687. (* 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) *)
  688. (*! should not be necessary any more as GC runs immediately and without scheduling decisions
  689. WHILE (gcActivity # NIL) & (gcActivity.process # NIL) & (gcActivity.process.mode = Running) DO END;
  690. *)
  691. t.body(obj);
  692. terminate(t);
  693. RemoveExcpFrm(excpfrm);
  694. RETURN 0
  695. END Wrapper;
  696. PROCEDURE FinalizeProcess(t: ANY);
  697. VAR p: Process; res: Kernel32.BOOL;
  698. BEGIN
  699. p := t(Process);
  700. IF TraceVerbose THEN
  701. Machine.Acquire (Machine.TraceOutput);
  702. Trace.String("Finalizing Process"); Trace.Int(p.id, 1);
  703. WriteType(p.obj); Trace.Ln;
  704. Machine.Release (Machine.TraceOutput);
  705. END;
  706. IF p.mode # Terminated THEN
  707. IF p.mode = AwaitingLock THEN DEC(awl);
  708. ELSIF p.mode = AwaitingCond THEN DEC(awc);
  709. END;
  710. (* no reference to the object any more *)
  711. Trace.String ("Closing unreferenced process"); (*Trace.Int(p.mode,20); Trace.Int( p.id, 20 ); *) Trace.Ln; (* Trace.Ln *)
  712. (* this usually happens, when an objects process waits on its own objtec and no reference exists any more. Then the object is discarded and
  713. consequently the process is unreferenced (except in the object). This cannot happen when there are still other references on the object.
  714. example:
  715. TYPE
  716. Object= OBJECT VAR active: BOOLEAN; BEGIN{ACTIVE} active := FALSE; AWAIT(active) END Object;
  717. VAR o: Object;
  718. BEGIN NEW(o);
  719. END;
  720. *)
  721. END;
  722. p.mode := Terminated; (* fof for GC problem *)
  723. IF p.handle # 0 THEN
  724. res := Kernel32.CloseHandle(p.handle); p.handle := 0
  725. END
  726. END FinalizeProcess;
  727. PROCEDURE TerminateProc;
  728. BEGIN
  729. terminate(CurrentProcess());
  730. Kernel32.ExitThread(0);
  731. Kernel32.Sleep(999999); (* wait until dependent threads terminated *)
  732. END TerminateProc;
  733. (* Allocate a new process associated with "obj". Must be outside lock region, because of potential GC. *)
  734. PROCEDURE NewProcess(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject; VAR new: Process);
  735. VAR t,r: Process; fn: Heaps.FinalizerNode;
  736. BEGIN
  737. NEW(t);
  738. t.gcContext.nextPos := 0;
  739. t.context := CurrentContext(); (* inherit context from parent process *)
  740. t.handle := 0;
  741. IF priority = 0 THEN (* no priority specified *)
  742. r := CurrentProcess();
  743. t.priority := r.priority (* inherit priority of creator *)
  744. ELSIF priority > 0 THEN (* positive priority specified *)
  745. t.priority := priority
  746. ELSE (* negative priority specified (only for Idle process) *)
  747. t.priority := MinPriority
  748. END;
  749. NEW(fn); (* implicit call Heaps.NewRec -> might invoke GC *)
  750. Machine.Acquire(Machine.Objects);
  751. t.next := NIL; t.prev := NIL; t.rootedNext := NIL;
  752. t.waitingOn := NIL; t.flags := flags; t.obj := obj; t.mode := Unknown;
  753. t.body := body; t.event := 0; fn.finalizer := FinalizeProcess;
  754. Heaps.AddFinalizer(t, fn);
  755. IF Restart IN flags THEN (* restart object body *)
  756. t.restartPC := SYSTEM.VAL(ADDRESS, body);
  757. ELSE (* terminate process *)
  758. t.restartPC := SYSTEM.VAL(ADDRESS, terminateProc);
  759. END;
  760. (*! Put the process into the process queue before the thread is created.
  761. this is highly important in case of a DLL, where Objects.AttachThread
  762. will be called by Kernel32.EntryPoint (DllMain)
  763. *)
  764. Put(ready, t);
  765. t.handle := Kernel32.CreateThread(0, defaultStackSize, Wrapper, t, {}, t.id);
  766. IF TraceVerbose OR TraceOpenClose THEN
  767. Machine.Acquire(Machine.TraceOutput);
  768. Trace.String("NewProcess: " ); Trace.Int(t.id, 1); WriteType(obj); Trace.Ln;
  769. Machine.Release(Machine.TraceOutput);
  770. END;
  771. ASSERT(t.handle # 0);
  772. new := t;
  773. END NewProcess;
  774. (* Create the process associated with an active object (kernel call). *)
  775. PROCEDURE CreateProcess*(body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject);
  776. VAR t : Process; heapBlock {UNTRACED}: Heaps.HeapBlock;
  777. BEGIN
  778. ASSERT(priority >= 0, 1000); ASSERT(priority <=Realtime, 1001);
  779. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, heapBlock);
  780. ASSERT(heapBlock IS Heaps.ProtRecBlock); (* protected object *)
  781. IF Restart IN flags THEN INCL(flags, Resistant) END; (* SAFE => Restart & Resistant *)
  782. NewProcess(body, priority, flags, obj, t); INC(nProcs); (* acquires Machine.Objects lock *)
  783. t.mode := Ready;
  784. Machine.Release(Machine.Objects);
  785. END CreateProcess;
  786. (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
  787. too early. *)
  788. PROCEDURE Lock*(obj: ProtectedObject; exclusive: BOOLEAN );
  789. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; r: Process; res: WORD;
  790. BEGIN (* {called from user level} *)
  791. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  792. IF StrongChecks THEN
  793. ASSERT(hdr IS Heaps.ProtRecBlock); (* protected object *)
  794. ASSERT(exclusive) (* shared not implemented yet *)
  795. END;
  796. r := CurrentProcess();
  797. IF StrongChecks THEN
  798. ASSERT(hdr # NIL, 1001);
  799. ASSERT(r # NIL, 1002);
  800. END;
  801. Machine.Acquire(Machine.Objects);
  802. IF hdr.count = 0 THEN (* not locked *)
  803. hdr.count := -1; hdr.lockedBy := r;
  804. Machine.Release(Machine.Objects)
  805. ELSE (* already locked *)
  806. IF hdr.lockedBy = r THEN
  807. Machine.Release(Machine.Objects);
  808. HALT(2203) (* nested locks not allowed *)
  809. END;
  810. ASSERT(r.waitingOn = NIL); (* sanity check *)
  811. Remove(ready, r);
  812. IF r.event = 0 THEN
  813. r.event := Kernel32.CreateEvent( NIL, Kernel32.False (* auto *), Kernel32.False, NIL ); (* auto reset event with initial state = reset *)
  814. ASSERT ( r.event # 0, 1239 );
  815. END;
  816. r.waitingOn := obj; r.mode := AwaitingLock;
  817. Put(hdr.awaitingLock, r); INC(awl);
  818. Machine.Release(Machine.Objects);
  819. res := Kernel32.WaitForSingleObject(r.event, Kernel32.Infinite); (* block execution *)
  820. ASSERT(res = Kernel32.WaitObject0);
  821. IF StrongChecks THEN
  822. ASSERT(hdr.lockedBy = r); (* at this moment only this process can own the lock and only this process can release it*)
  823. END;
  824. END
  825. END Lock;
  826. (* Find the first true condition from the queue and remove it. Assume the object is currently locked. *)
  827. PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
  828. VAR first, cand: Process;
  829. BEGIN
  830. Get( q, first );
  831. IF first.condition( first.condFP ) THEN RETURN first END;
  832. Put( q, first );
  833. WHILE q.head # first DO
  834. Get( q, cand );
  835. IF cand.condition( cand.condFP ) THEN RETURN cand END;
  836. Put( q, cand )
  837. END;
  838. RETURN NIL
  839. END FindCondition;
  840. (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
  841. too early. *)
  842. PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
  843. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; t, c: Process; res: WORD;
  844. BEGIN
  845. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  846. IF StrongChecks THEN
  847. ASSERT(hdr IS Heaps.ProtRecBlock) (* protected object *)
  848. END;
  849. ASSERT(hdr.count = -1); (* exclusive locked *)
  850. Machine.Acquire(Machine.Objects);
  851. IF hdr.awaitingCond.head # NIL THEN (* evaluate the waiting conditions *)
  852. (* we are holding the lock, so the queue can not change (to do: except in TerminateThis) *)
  853. c := FindCondition(hdr.awaitingCond); (* interrupts should be on during this call *)
  854. ELSE
  855. c := NIL
  856. END;
  857. IF c = NIL THEN (* no true condition found, check the lock queue *)
  858. Get(hdr.awaitingLock, t);
  859. IF t # NIL THEN
  860. hdr.lockedBy := t;
  861. t.waitingOn := NIL;
  862. ELSE
  863. hdr.lockedBy := NIL; hdr.count := 0
  864. END
  865. ELSE (* true condition found, transfer the lock *)
  866. c.waitingOn := NIL; hdr.lockedBy := c;
  867. t := NIL
  868. END;
  869. IF c # NIL THEN
  870. Put(ready, c); c.mode := Running; DEC(awc);
  871. res := Kernel32.SetEvent(c.event);
  872. ASSERT (res # 0, 1001);
  873. ELSIF t # NIL THEN
  874. Put(ready, t); t.mode := Running; DEC(awl);
  875. res := Kernel32.SetEvent(t.event);
  876. ASSERT (res # 0, 1002);
  877. END;
  878. Machine.Release( Machine.Objects )
  879. END Unlock;
  880. (* The procedure Lock, Unlock and Await do not use header locks since it turned out that the header locks sometimes were finalized
  881. too early. *)
  882. PROCEDURE Await*( cond: Condition; slink: LONGINT; obj: ProtectedObject; flags: SET );
  883. VAR hdr {UNTRACED}: Heaps.ProtRecBlock; r, c, t: Process; res: WORD;
  884. BEGIN
  885. IF 1 IN flags THEN (* compiler did not generate IF *)
  886. IF cond(slink) THEN
  887. RETURN (* condition already true *)
  888. END
  889. END;
  890. SYSTEM.GET(SYSTEM.VAL(ADDRESS, obj) + Heaps.HeapBlockOffset, hdr);
  891. IF StrongChecks THEN
  892. ASSERT(hdr IS Heaps.ProtRecBlock) (* protected object *)
  893. END;
  894. r := CurrentProcess();
  895. Machine.Acquire(Machine.Objects);
  896. IF hdr.lockedBy = r THEN (* current process holds exclusive lock *)
  897. IF StrongChecks THEN ASSERT(hdr.count = -1) END; (* exclusive locked *)
  898. IF hdr.awaitingCond.head # NIL THEN (* evaluate the waiting conditions *)
  899. (* we are holding the lock, so the queue can not change (to do: except in TerminateThis) *)
  900. c := FindCondition(hdr.awaitingCond) (* interrupts should be on during this call *)
  901. ELSE
  902. c := NIL
  903. END;
  904. IF c = NIL THEN
  905. Get(hdr.awaitingLock, t);
  906. IF t = NIL THEN (* none waiting - remove lock *)
  907. hdr.count := 0; hdr.lockedBy := NIL;
  908. ELSE (* transfer lock to first waiting process *)
  909. IF StrongChecks THEN ASSERT(t.mode = AwaitingLock) END;
  910. t.waitingOn := NIL;
  911. hdr.lockedBy := t;
  912. END;
  913. ELSE
  914. c.waitingOn := NIL; hdr.lockedBy := c;
  915. t := NIL;
  916. END;
  917. ELSE (* no lock, or some other process may hold the lock, but that's the user's indaba (may be monotonic condition) *)
  918. Machine.Release(Machine.Objects);
  919. HALT( 2204 ) (* await must be exclusive region *)
  920. END;
  921. r.condition := cond; r.condFP := slink;
  922. r.waitingOn := obj; r.mode := AwaitingCond;
  923. Remove(ready, r);
  924. IF r.event = 0 THEN
  925. r.event := Kernel32.CreateEvent( NIL, Kernel32.False (* auto *), Kernel32.False, NIL ); (* auto-reset event with initial state = reset *)
  926. ASSERT ( r.event # 0, 1239 );
  927. END;
  928. IF c # NIL THEN
  929. DEC(awc); Put(ready, c); c.mode := Running;
  930. res := Kernel32.SetEvent(c.event); (* restart execution *)
  931. ASSERT(res # 0, 1002);
  932. END;
  933. IF t # NIL THEN
  934. DEC(awl); Put(ready, t); t.mode := Running;
  935. res := Kernel32.SetEvent( t.event ); (* restart execution *)
  936. ASSERT(res # 0, 1003);
  937. END;
  938. Put(hdr.awaitingCond, r); INC(awc);
  939. Machine.Release(Machine.Objects);
  940. res := Kernel32.WaitForSingleObject(r.event, Kernel32.Infinite); (* block execution *)
  941. ASSERT(res = Kernel32.WaitObject0);
  942. IF StrongChecks THEN
  943. ASSERT(cond(slink));
  944. ASSERT(hdr.lockedBy = r) (* lock held again *)
  945. END
  946. END Await;
  947. PROCEDURE Break*( t: Process );
  948. CONST MaxTry = 50;
  949. VAR mod: Modules.Module; try: LONGINT; retBOOL: Kernel32.BOOL; (* Dan 09.11.05 *)
  950. PROCEDURE SafeForBreak( mod: Modules.Module ): BOOLEAN;
  951. BEGIN
  952. Trace.String( "Safe for break?: " );
  953. IF mod # NIL THEN
  954. Trace.StringLn ( mod.name );
  955. IF (mod.name = "Trace") OR (mod.name = "Machine") OR
  956. (mod.name = "Heaps") OR (mod.name = "Modules") OR
  957. (mod.name = "Objects") OR (mod.name = "Kernel") THEN
  958. Trace.StringLn ( " - no" ); RETURN FALSE
  959. ELSE Trace.StringLn ( " - yes" ); RETURN TRUE
  960. END
  961. ELSE Trace.StringLn ( "unknown module" ); RETURN FALSE
  962. END
  963. END SafeForBreak;
  964. BEGIN
  965. IF CurrentProcess() # t THEN
  966. Machine.Acquire( Machine.Objects );
  967. LOOP
  968. retBOOL := Kernel32.SuspendThread( t.handle );
  969. t.state.ContextFlags := Kernel32.ContextControl;
  970. retBOOL := Kernel32.GetThreadContext( t.handle, t.state );
  971. mod := Modules.ThisModuleByAdr( t.state.PC ); Trace.String( "Objects Break at adr: " );
  972. Trace.Int( t.state.PC, 5 ); Trace.Ln;
  973. IF mod # NIL THEN
  974. Trace.String( "In module: " ); Trace.StringLn ( mod.name );
  975. END;
  976. IF ~SafeForBreak( mod ) (* we do not break Kernel modules *) THEN
  977. retBOOL := Kernel32.ResumeThread( t.handle ); INC( try );
  978. IF try > MaxTry THEN
  979. Trace.StringLn ( "Threads.Break: failed " );
  980. Machine.Release( Machine.Objects );
  981. RETURN
  982. END
  983. ELSE EXIT
  984. END;
  985. END;
  986. (* push cont.Eip *) break[0] := 68X;
  987. SYSTEM.MOVE( ADDRESSOF( t.state.PC ), ADDRESSOF( break[1] ), 4 );
  988. (* push ebp *) break[5] := 055X;
  989. (* mov ebp, esp *) break[6] := 08BX; break[7] := 0ECX;
  990. (* push 13 *) break[8] := 06AX; break[9] := 0DX;
  991. (* int 3 *) break[10] := 0CCX;
  992. (* mov esp, ebp *) break[11] := 08BX; break[12] := 0E5X;
  993. (* pop ebp *) break[13] := 05DX;
  994. (* ret *) break[14] := 0C3X; t.state.PC := ADDRESSOF( break[0] );
  995. retBOOL := Kernel32.SetThreadContext( t.handle, t.state );
  996. retBOOL := Kernel32.ResumeThread( t.handle ); (* INC( Kernel.GClevel ); *)
  997. Machine.Release( Machine.Objects );
  998. ELSE HALT( 99 )
  999. END;
  1000. END Break;
  1001. (* Attempt to terminate a specific process (mostly ignoring its locks). DEPRECATED *)
  1002. PROCEDURE TerminateThis*( t: Process; halt: BOOLEAN );
  1003. BEGIN
  1004. terminate(t);
  1005. END TerminateThis;
  1006. PROCEDURE Terminate*;
  1007. BEGIN
  1008. TerminateProc();
  1009. END Terminate;
  1010. PROCEDURE Init; (* can not use NEW *)
  1011. VAR t: Process; fn: Heaps.FinalizerNode; proc: Kernel32.HANDLE;
  1012. res: Kernel32.BOOL;
  1013. lib: Kernel32.HMODULE;
  1014. low, high: SIZE;
  1015. BEGIN
  1016. Kernel32.AddVectoredExceptionHandler(1, ExcpFrmHandler);
  1017. Kernel32.InitializeCriticalSection(excplock);
  1018. numberOfProcessors := Machine.NumberOfProcessors();
  1019. NEW(t);
  1020. #IF ~SHAREDLIB THEN
  1021. NEW(fn);
  1022. #END;
  1023. Machine.Acquire(Machine.Objects);
  1024. t.gcContext.nextPos := 0;
  1025. nProcs := 1;
  1026. t.next := NIL; t.prev := NIL;
  1027. t.waitingOn := NIL;
  1028. #IF ~SHAREDLIB THEN
  1029. t.flags := {};
  1030. t.obj := NIL;
  1031. #ELSE
  1032. t.flags := {External}; (*! mark the process as external (non A2) *)
  1033. NEW(t.obj); (*! required for ActiveObject() to return non-NIL *)
  1034. #END;
  1035. t.mode := Unknown; t.body := NIL;
  1036. t.priority := Normal;
  1037. #IF ~SHAREDLIB THEN (*! do not allow to finalize the dll loading thread *)
  1038. fn.finalizer := FinalizeProcess;
  1039. Heaps.AddFinalizer(t, fn);
  1040. #END;
  1041. t.handle := Kernel32.GetCurrentThread();
  1042. t.id := Kernel32.GetCurrentThreadId();
  1043. proc := Kernel32.GetCurrentProcess();
  1044. res := Kernel32.DuplicateHandle(proc, t.handle, proc, t.handle, {}, 0, {Kernel32.DuplicateSameAccess});
  1045. ASSERT(res # 0);
  1046. res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(ADDRESS, t));
  1047. ASSERT(res # 0);
  1048. #IF ~SHAREDLIB THEN
  1049. t.stackBottom := Machine.stackBottom;
  1050. #ELSE
  1051. Kernel32.GetCurrentThreadStackLimits(low,high);
  1052. t.stackBottom := high;
  1053. #END;
  1054. t.mode := Running;
  1055. Put( ready, t );
  1056. ASSERT(t.handle # 0);
  1057. Machine.Release(Machine.Objects);
  1058. InitEventHandling; (* implicit call of NewProcess! *)
  1059. InitGCHandling; (* do. *)
  1060. Heaps.gcStatus := GCStatusFactory();
  1061. END Init;
  1062. (** Set (or reset) an event handler object's timeout value. *)
  1063. PROCEDURE SetTimeout*(t: Timer; h: EventHandler; ms: LONGINT );
  1064. VAR e: Timer; trigger: LONGINT;
  1065. BEGIN
  1066. ASSERT(Machine.Second= 1000); (* assume milliseconds for now *)
  1067. ASSERT((t # NIL) & (h # NIL));
  1068. ASSERT(ms >= 0);
  1069. Machine.Acquire(Machine.Objects);
  1070. trigger := Kernel32.GetTickCount() + ms; (* ignore overflow *)
  1071. IF t.next # NIL THEN (* cancel previous timeout *)
  1072. t.next.prev := t.prev; t.prev.next := t.next
  1073. END;
  1074. t.trigger := trigger; t.handler := h;
  1075. e := event.next; (* performance: linear search! *)
  1076. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  1077. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  1078. Machine.Release(Machine.Objects);
  1079. clock.Wakeup()
  1080. END SetTimeout;
  1081. (** Set (or reset) an event handler object's timeout value. Here ms is absolute *)
  1082. PROCEDURE SetTimeoutAt*(t: Timer; h: EventHandler; ms: LONGINT);
  1083. VAR e: Timer; trigger: LONGINT;
  1084. BEGIN
  1085. ASSERT(Machine.Second= 1000); (* assume milliseconds for now *)
  1086. ASSERT((t # NIL) & (h # NIL));
  1087. Machine.Acquire(Machine.Objects);
  1088. trigger := ms; (* ignore overflow *)
  1089. IF t.next # NIL THEN (* cancel previous timeout *)
  1090. t.next.prev := t.prev; t.prev.next := t.next
  1091. END;
  1092. t.trigger := trigger; t.handler := h;
  1093. e := event.next; (* performance: linear search! *)
  1094. WHILE (e # event) & (e.trigger - trigger <= 0) DO e := e.next END;
  1095. t.prev := e.prev; e.prev := t; t.next := e; t.prev.next := t;
  1096. Machine.Release(Machine.Objects);
  1097. clock.Wakeup()
  1098. END SetTimeoutAt;
  1099. (** Cancel an event handler object's timeout, if any. It is possible that the timer has expired, but not yet been scheduled to run. *)
  1100. PROCEDURE CancelTimeout*( t: Timer );
  1101. BEGIN
  1102. Machine.Acquire(Machine.Objects);
  1103. ASSERT (t # event );
  1104. IF t.next # NIL THEN
  1105. t.next.prev := t.prev;
  1106. IF t.prev#NIL THEN t.prev.next := t.next; END;
  1107. t.next := NIL;
  1108. t.prev := NIL
  1109. END;
  1110. Machine.Release(Machine.Objects);
  1111. END CancelTimeout;
  1112. PROCEDURE InitEventHandling;
  1113. BEGIN
  1114. NEW(event); event.next := event; event.prev := event; (* event: head of timer event queue, only a sentinel *)
  1115. NEW(clock);
  1116. END InitEventHandling;
  1117. PROCEDURE InitGCHandling;
  1118. BEGIN
  1119. NEW(finalizerCaller);
  1120. END InitGCHandling;
  1121. PROCEDURE GCStatusFactory(): Heaps.GCStatus;
  1122. VAR gcStatusExt : GCStatusExt;
  1123. BEGIN
  1124. ASSERT(Heaps.gcStatus = NIL);
  1125. NEW(gcStatusExt);
  1126. RETURN gcStatusExt
  1127. END GCStatusFactory;
  1128. PROCEDURE InstallExceptionHandler*( e: ExceptionHandler );
  1129. BEGIN
  1130. exceptionhandler := e;
  1131. END InstallExceptionHandler;
  1132. PROCEDURE UpdateProcessState*( p: Process );
  1133. VAR res: Kernel32.BOOL;
  1134. BEGIN
  1135. res := Kernel32.GetThreadContext( p.handle, p.state );
  1136. ASSERT (p.handle # 0);
  1137. END UpdateProcessState;
  1138. (*ALEX 2005.12.12 added for WMPerfMon needs*)
  1139. PROCEDURE NumReady*( ): LONGINT;
  1140. VAR n: LONGINT; p: Heaps.ProcessLink;
  1141. BEGIN
  1142. n := 0;
  1143. Machine.Acquire( Machine.Objects );
  1144. p := ready.head;
  1145. WHILE p # NIL DO INC( n ); p := p.next END;
  1146. Machine.Release( Machine.Objects );
  1147. RETURN n
  1148. END NumReady;
  1149. (** Return number of CPU cycles consumed by the specified process. If all is TRUE,
  1150. return the number of cycles since the process has been created. If FALSE, return the number of cycles
  1151. consumed since the last time asked. *)
  1152. PROCEDURE GetCpuCycles*(process : Process; VAR cpuCycles : CpuCyclesArray; all : BOOLEAN);
  1153. VAR res : Kernel32.BOOL; temp : HUGEINT;
  1154. BEGIN
  1155. ASSERT(process # NIL);
  1156. IF (Kernel32.QueryThreadCycleTime # NIL) THEN
  1157. res := Kernel32.QueryThreadCycleTime(process.handle, cpuCycles[0]);
  1158. ELSE
  1159. cpuCycles[0] := Machine.GetTimer(); res := Kernel32.True;
  1160. END;
  1161. IF ~all & (res = Kernel32.True) THEN
  1162. temp := process.lastThreadTimes;
  1163. process.lastThreadTimes := cpuCycles[0];
  1164. cpuCycles[0] := cpuCycles[0] - temp;
  1165. END;
  1166. END GetCpuCycles;
  1167. PROCEDURE CurrentProcessTime*(): HUGEINT;
  1168. VAR res: WORD; result: HUGEINT;
  1169. BEGIN
  1170. IF (Kernel32.QueryThreadCycleTime # NIL) THEN
  1171. res := Kernel32.QueryThreadCycleTime(CurrentProcess().handle, result);
  1172. ELSE (* fallback *)
  1173. result := Machine.GetTimer();
  1174. END;
  1175. RETURN result;
  1176. END CurrentProcessTime;
  1177. PROCEDURE TimerFrequency*(): HUGEINT;
  1178. BEGIN
  1179. RETURN 1000000000;
  1180. END TimerFrequency;
  1181. VAR GetProcedureName*: PROCEDURE (pc: ADDRESS; VAR n: ARRAY OF CHAR; VAR spc: ADDRESS);
  1182. (* Leave A2 is called when a process leaves A2 by a call to the windows API *)
  1183. PROCEDURE LeaveA2*;
  1184. VAR cur: Process; ebp,n: ADDRESS;
  1185. BEGIN
  1186. #IF AMD64 THEN
  1187. CODE
  1188. PUSH RCX
  1189. PUSH RDX
  1190. PUSH R8
  1191. PUSH R9
  1192. END;
  1193. #END
  1194. IF clock = NIL THEN
  1195. RETURN
  1196. END;
  1197. cur := CurrentProcess();
  1198. IF cur # NIL THEN
  1199. ebp := SYSTEM.GetFramePointer();
  1200. SYSTEM.GET(ebp, n);
  1201. IF ODD(n) THEN SYSTEM.GET(ebp + SIZEOF(ADDRESS), ebp) ELSE ebp := n END;
  1202. cur.gcContext.last[cur.gcContext.nextPos] := ebp;
  1203. INC(cur.gcContext.nextPos);
  1204. ASSERT(cur.gcContext.nextPos < 255);
  1205. END;
  1206. #IF AMD64 THEN
  1207. CODE
  1208. POP R9
  1209. POP R8
  1210. POP RDX
  1211. POP RCX
  1212. END;
  1213. #END
  1214. END LeaveA2;
  1215. (* reenter is called when a process returns from a call to the windows API *)
  1216. PROCEDURE ReenterA2*;
  1217. VAR cur: Process;
  1218. BEGIN
  1219. IF clock = NIL THEN RETURN END;
  1220. cur := CurrentProcess();
  1221. IF cur # NIL THEN
  1222. IF (cur.gcContext.nextPos > 0) THEN
  1223. DEC(cur.gcContext.nextPos);
  1224. END;
  1225. cur.gcContext.last[cur.gcContext.nextPos] := NIL; (* returned *)
  1226. (*cur.gcContext.first[cur.gcContext.nextPos] := NIL; (* returned *)*)
  1227. END;
  1228. END ReenterA2;
  1229. PROCEDURE RegisterExternalThread*;
  1230. CONST THREAD_PRIORITY_ERROR_RETURN = 0x7fffffff;
  1231. VAR
  1232. t: Process;
  1233. proc: Kernel32.HANDLE;
  1234. res: Kernel32.BOOL;
  1235. low, high: SIZE;
  1236. BEGIN
  1237. (*!TODO: the allocation below can potentially invoke the GC and can cause a crash
  1238. since the current thread is not yet registered.
  1239. Consider to use a preallocated array of Process descriptors *)
  1240. NEW(t);
  1241. NEW(t.obj); (*! required for ActiveObject() to return non-NIL *)
  1242. t.gcContext.nextPos := 0;
  1243. t.next := NIL; t.prev := NIL;
  1244. t.waitingOn := NIL;
  1245. t.flags := {External}; (*! mark the process as external (non A2) *)
  1246. t.mode := Unknown; t.body := NIL;
  1247. t.handle := Kernel32.GetCurrentThread();
  1248. t.priority := Kernel32.GetThreadPriority(t.handle);
  1249. ASSERT(t.priority # THREAD_PRIORITY_ERROR_RETURN);
  1250. CASE t.priority OF
  1251. |Kernel32.ThreadPriorityIdle: t.priority := MinPriority;
  1252. |Kernel32.ThreadPriorityBelowNormal: t.priority := Low;
  1253. |Kernel32.ThreadPriorityAboveNormal: t.priority := High;
  1254. |Kernel32.ThreadPriorityTimeCritical: t.priority := Realtime;
  1255. ELSE
  1256. ASSERT(t.priority = Kernel32.ThreadPriorityNormal);
  1257. t.priority := Normal;
  1258. END;
  1259. t.id := Kernel32.GetCurrentThreadId();
  1260. proc := Kernel32.GetCurrentProcess();
  1261. res := Kernel32.DuplicateHandle(proc, t.handle, proc, t.handle, {}, 0, {Kernel32.DuplicateSameAccess});
  1262. ASSERT(res # 0);
  1263. Kernel32.GetCurrentThreadStackLimits(low,high);
  1264. t.stackBottom := high;
  1265. t.mode := Running;
  1266. res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(ADDRESS, t));
  1267. ASSERT(res # 0);
  1268. Machine.Acquire(Machine.Objects);
  1269. Put(ready, t);
  1270. Machine.Release(Machine.Objects);
  1271. Machine.Acquire(Machine.TraceOutput);
  1272. Trace.String("registered an external thread: id=");
  1273. Trace.Int(t.id,0);
  1274. Trace.String(", handle=");
  1275. Trace.Int(t.handle,0);
  1276. Trace.String(", stackBottom=");
  1277. Trace.Hex(t.stackBottom,-8);
  1278. Trace.Ln;
  1279. Machine.Release(Machine.TraceOutput);
  1280. END RegisterExternalThread;
  1281. (* enter A2 should be called when a process enters A2 from windows or from A2 via a call to a WINAPI A2 function *)
  1282. PROCEDURE EnterA2*;
  1283. VAR cur: Process; ebp, n: ADDRESS;
  1284. BEGIN
  1285. cur := CurrentProcess();
  1286. IF cur = NIL THEN (* create a process descriptor *)
  1287. RegisterExternalThread();
  1288. cur := CurrentProcess();
  1289. Trace.String("First Enter: "); Trace.Address(cur); Trace.Ln;
  1290. ELSE
  1291. ebp := SYSTEM.GetFramePointer();
  1292. SYSTEM.GET(ebp, n);
  1293. IF ODD(n) THEN SYSTEM.GET(ebp + SIZEOF(ADDRESS), ebp) ELSE ebp := n END;
  1294. IF cur.gcContext.nextPos = -1 THEN (* re-entry *)
  1295. cur.gcContext.nextPos := 0;
  1296. cur.stackBottom := ebp;
  1297. Trace.String("Reenter: "); Trace.Address(cur); Trace.Ln;
  1298. ELSE
  1299. INC(cur.gcContext.nextPos);
  1300. cur.gcContext.last[cur.gcContext.nextPos] := NIL;
  1301. END;
  1302. END;
  1303. (*
  1304. cur.gcContext.first[cur.gcContext.nextPos] := ebp; (* here our responsibility starts -- currently this field is not strictly required to be set valid *)
  1305. cur.gcContext.last[cur.gcContext.nextPos] := NIL; (* we do not know where it ends yet *)
  1306. *)
  1307. END EnterA2;
  1308. (* exit A2 should be called when a process exits a WINAPI procedure *)
  1309. PROCEDURE ExitA2*();
  1310. VAR cur: Process;
  1311. BEGIN
  1312. cur := CurrentProcess();
  1313. ASSERT(cur # NIL);
  1314. DEC(cur.gcContext.nextPos);
  1315. cur.gcContext.last[cur.gcContext.nextPos] := NIL;
  1316. IF cur.gcContext.nextPos < 0 THEN (* process exits A2 *)
  1317. Trace.String("Exit: "); Trace.Address(cur); Trace.Ln;
  1318. END;
  1319. END ExitA2;
  1320. #IF SHAREDLIB THEN
  1321. PROCEDURE InQueueById( queue: ProcessQueue; id: LONGINT ): BOOLEAN;
  1322. VAR p: Heaps.ProcessLink;
  1323. BEGIN
  1324. p := queue.head;
  1325. WHILE (p # NIL ) & (p(Process).id # id) DO p := p.next; END;
  1326. RETURN (p # NIL);
  1327. END InQueueById;
  1328. PROCEDURE AttachThread*();
  1329. CONST THREAD_PRIORITY_ERROR_RETURN = 0x7fffffff;
  1330. VAR
  1331. t: Process;
  1332. proc: Kernel32.HANDLE;
  1333. res: Kernel32.BOOL;
  1334. low, high: SIZE;
  1335. BEGIN
  1336. (*! this thread attach event could be invoked by Kernel32.CreateThread called within Objects.NewProcess.
  1337. In such cases the created process will be already in the process queue and we must skip it.
  1338. All other cases correspond to external threads. *)
  1339. Machine.Acquire(Machine.Objects);
  1340. IF InQueueById(ready,Kernel32.GetCurrentThreadId()) THEN
  1341. Machine.Release(Machine.Objects);
  1342. RETURN;
  1343. END;
  1344. Machine.Release(Machine.Objects);
  1345. (*!TODO: this can potentially invoke the GC and can cause a crash
  1346. since the current thread is not yet registered.
  1347. Consider to use a preallocated array of Process descriptors *)
  1348. NEW(t);
  1349. Machine.Acquire(Machine.Objects);
  1350. t.gcContext.nextPos := 0;
  1351. t.next := NIL; t.prev := NIL;
  1352. t.waitingOn := NIL;
  1353. t.flags := {External}; (*! mark the process as external (non A2) *)
  1354. NEW(t.obj); (*! required for ActiveObject() to return non-NIL *)
  1355. t.mode := Unknown; t.body := NIL;
  1356. t.handle := Kernel32.GetCurrentThread();
  1357. t.priority := Kernel32.GetThreadPriority(t.handle);
  1358. ASSERT(t.priority # THREAD_PRIORITY_ERROR_RETURN);
  1359. CASE t.priority OF
  1360. |Kernel32.ThreadPriorityIdle: t.priority := MinPriority;
  1361. |Kernel32.ThreadPriorityBelowNormal: t.priority := Low;
  1362. |Kernel32.ThreadPriorityAboveNormal: t.priority := High;
  1363. |Kernel32.ThreadPriorityTimeCritical: t.priority := Realtime;
  1364. ELSE
  1365. ASSERT(t.priority = Kernel32.ThreadPriorityNormal);
  1366. t.priority := Normal;
  1367. END;
  1368. t.id := Kernel32.GetCurrentThreadId();
  1369. proc := Kernel32.GetCurrentProcess();
  1370. res := Kernel32.DuplicateHandle(proc, t.handle, proc, t.handle, {}, 0, {Kernel32.DuplicateSameAccess});
  1371. ASSERT(res # 0);
  1372. res := Kernel32.TlsSetValue(tlsIndex, SYSTEM.VAL(ADDRESS, t));
  1373. ASSERT(res # 0);
  1374. Kernel32.GetCurrentThreadStackLimits(low,high);
  1375. t.stackBottom := high;
  1376. t.mode := Running;
  1377. Put(ready, t);
  1378. Machine.Acquire(Machine.TraceOutput);
  1379. Trace.String("attached thread: id=");
  1380. Trace.Int(t.id,0);
  1381. Trace.String(", handle=");
  1382. Trace.Int(t.handle,0);
  1383. Trace.String(", stackBottom=");
  1384. Trace.Hex(t.stackBottom,-8);
  1385. Trace.Ln;
  1386. Machine.Release(Machine.TraceOutput);
  1387. Machine.Release(Machine.Objects);
  1388. END AttachThread;
  1389. PROCEDURE CleanupExternalProcess(t: Process);
  1390. BEGIN
  1391. ASSERT(External IN t.flags);
  1392. IF InQueue(ready,t) THEN Remove(ready,t); END;
  1393. IF t.event # 0 THEN Kernel32.CloseHandle(t.event); END;
  1394. DEC(nProcs);
  1395. END CleanupExternalProcess;
  1396. PROCEDURE DetachThread*();
  1397. VAR t: Process;
  1398. BEGIN
  1399. t := CurrentProcess();
  1400. IF ~(External IN t.flags) THEN RETURN; END;
  1401. Machine.Acquire(Machine.Objects);
  1402. CleanupExternalProcess(t);
  1403. Machine.Release(Machine.Objects);
  1404. Machine.Acquire (Machine.TraceOutput);
  1405. Trace.String("detached a thread: id="); Trace.Int(t.id,0); Trace.Ln;
  1406. Machine.Release (Machine.TraceOutput);
  1407. END DetachThread;
  1408. PROCEDURE CleanupProcesses;
  1409. VAR
  1410. t: Process;
  1411. res: Kernel32.BOOL;
  1412. BEGIN
  1413. Machine.Acquire(Machine.Objects);
  1414. Get(ready, t);
  1415. WHILE t # NIL DO
  1416. IF t.mode # Terminated THEN
  1417. IF External IN t.flags THEN
  1418. Machine.Acquire (Machine.TraceOutput);
  1419. Trace.String("cleaning up an external process: id="); Trace.Int(t.id,0); Trace.String(", mode="); Trace.Int(t.mode,0); Trace.Ln;
  1420. Machine.Release (Machine.TraceOutput);
  1421. CleanupExternalProcess(t);
  1422. ELSE
  1423. Machine.Acquire (Machine.TraceOutput);
  1424. Trace.String("killing a process: id="); Trace.Int(t.id,0); Trace.String(", mode="); Trace.Int(t.mode,0); Trace.Ln;
  1425. Machine.Release (Machine.TraceOutput);
  1426. res := Kernel32.TerminateThread(t.handle,-1);
  1427. IF res = 0 THEN
  1428. Machine.Acquire (Machine.TraceOutput);
  1429. Trace.String("failed to kill a process: id="); Trace.Int(t.id,0); Trace.String(", error="); Trace.Int(Kernel32.GetLastError(),0); Trace.Ln;
  1430. Machine.Release (Machine.TraceOutput);
  1431. END;
  1432. END;
  1433. END;
  1434. Get(ready, t);
  1435. END;
  1436. Machine.Release(Machine.Objects);
  1437. END CleanupProcesses;
  1438. PROCEDURE DetachProcess*();
  1439. CONST
  1440. TerminationTimeout = 1000;
  1441. VAR
  1442. p: Heaps.ProcessLink;
  1443. t: Process;
  1444. res: Kernel32.BOOL;
  1445. tick: LONGINT;
  1446. numNonTerminated, numExternals: SIZE;
  1447. BEGIN
  1448. Modules.Shutdown(-1);
  1449. finalizerCaller.Exit;
  1450. clock.Exit;
  1451. Machine.Acquire(Machine.TraceOutput);
  1452. Trace.StringLn("wait until all A2 processes terminate");
  1453. Machine.Release(Machine.TraceOutput);
  1454. tick := Kernel32.GetTickCount();
  1455. REPEAT
  1456. numNonTerminated := 0;
  1457. numExternals := 0;
  1458. Machine.Acquire(Machine.Objects);
  1459. p := ready.head;
  1460. WHILE p # NIL DO
  1461. t := p(Process);
  1462. IF External IN t.flags THEN
  1463. INC(numExternals);
  1464. ELSIF t.mode # Terminated THEN
  1465. INC(numNonTerminated);
  1466. END;
  1467. p := p.next;
  1468. END;
  1469. Machine.Release(Machine.Objects);
  1470. UNTIL (numNonTerminated = 0) OR (Kernel32.GetTickCount() - tick >= TerminationTimeout);
  1471. IF numNonTerminated # 0 THEN
  1472. Machine.Acquire(Machine.TraceOutput);
  1473. Trace.String("there are "); Trace.Int(numNonTerminated,0); Trace.StringLn(" A2 processes to terminate forcedly");
  1474. Machine.Release(Machine.TraceOutput);
  1475. CleanupProcesses;
  1476. ELSE
  1477. Machine.Acquire(Machine.TraceOutput);
  1478. Trace.StringLn("all A2 processes terminated");
  1479. Machine.Release(Machine.TraceOutput);
  1480. IF numExternals # 0 THEN
  1481. CleanupProcesses;
  1482. END;
  1483. END;
  1484. res := Kernel32.TlsFree(tlsIndex);
  1485. IF res = 0 THEN
  1486. Machine.Acquire (Machine.TraceOutput);
  1487. Trace.String("failed free TLS: error="); Trace.Int(Kernel32.GetLastError(),0); Trace.Ln;
  1488. Machine.Release (Machine.TraceOutput);
  1489. END;
  1490. (*!TODO: free resources allocated in Machine (e.g. critical section objects) *)
  1491. END DetachProcess;
  1492. #END;
  1493. VAR
  1494. TraceProcessHook*: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
  1495. BEGIN
  1496. TraceProcessHook := NIL;
  1497. exceptionhandler := NIL;
  1498. terminateProc := TerminateProc;
  1499. ready.head := NIL; ready.tail := NIL;
  1500. tlsIndex := Kernel32.TlsAlloc();
  1501. ASSERT ( tlsIndex # Kernel32.TLSOutOfIndexes );
  1502. Kernel32.SendToDebugger("Modules.root", ADDRESSOF(Modules.root));
  1503. Init;
  1504. END Objects.
  1505. Linker.Link --fileFormat=PE32CUI --fileName=oberonn.exe --extension=GofW --displacement=401000H
  1506. Builtins Trace Kernel32 Heaps Modules Objects Kernel KernelLog Streams Commands Files WinFS Clock Dates Reals Strings Diagnostics BitSets
  1507. StringPool ObjectFile GenericLinker Reflection Loader Shell StdIOShell Traps System ~