Win32.Objects.Mod 47 KB

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