Generic.Unix.Objects.Mod 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Objects; (** AUTHOR "pjm, G.F."; PURPOSE "Active object runtime support"; *)
  3. IMPORT S := SYSTEM, Trace, Glue, Unix, Machine, Heaps, Modules;
  4. CONST
  5. (*! Process flags, meaningless in Unix ports !!! *)
  6. PleaseHalt* = 10; (* Process requested to Halt itself soon *)
  7. Unbreakable*= 11; (* FINALLY shall not catch HALT exception (PleaseHalt is also set) *)
  8. SelfTermination*=12; (* Indicates the process has requested to terminate ifself (PleaseHalt is also set) *)
  9. Preempted* = 27; (* Has been preempted. *)
  10. Resistant* = 28; (* Can only be destroyed by itself *)
  11. MinPriority* = Unix.ThreadLow;
  12. Low* = Unix.ThreadLow + 1;
  13. Normal* = Unix.ThreadNormal;
  14. High* = Unix.ThreadHigh - 2;
  15. GCPriority* = Unix.ThreadHigh - 1;
  16. Realtime* = Unix.ThreadHigh;
  17. (* Process flag defined by compiler in OPC.CallRecBody *)
  18. Restart* = 0; (* Restart/Destroy process on exception *)
  19. (* Process modes (in UnixAos Running means Running or Ready!) *)
  20. Unknown* = 0; Ready* = 1; Running* = 2; AwaitingLock* = 3;
  21. AwaitingCond* = 4; AwaitingEvent* = 5; Terminated* = 6;
  22. Second* = 1000; (* frequency of ticks increments in Hz *)
  23. DefaultStacksize = 128*1024;
  24. VAR
  25. (* timer *)
  26. timerActivity : TimerActivity;
  27. clock : Clock;
  28. timers : Timer;
  29. timerListMutex : Unix.Mutex_t;
  30. timerStopped: BOOLEAN;
  31. (* processes *)
  32. SystemA2Up- : BOOLEAN;
  33. root- : Process; (*! Anchor of all instantiated threads in system *)
  34. stacksize: LONGINT; (* stack size of active objects, adjustable via boot parameter *)
  35. processList : Unix.Mutex_t;
  36. createProcess : Unix.Mutex_t;
  37. startProcess : Unix.Mutex_t;
  38. lockMutex : Unix.Mutex_t;
  39. childrunning : Unix.Condition_t;
  40. processPointer : Unix.Key_t;
  41. newProcess: Process;
  42. nextPID: LONGINT;
  43. finalizerCaller : FinalizerCaller;
  44. mainthread: Unix.Thread_t;
  45. TYPE
  46. LockT= POINTER TO RECORD
  47. mtx, enter: ADDRESS;
  48. END;
  49. CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
  50. ProtectedObject = POINTER TO RECORD END;
  51. ObjectHeader = Heaps.ProtRecBlock;
  52. ProcessQueue = Heaps.ProcessQueue;
  53. EventHandler* = PROCEDURE {DELEGATE};
  54. Timer* = OBJECT
  55. VAR
  56. next: Timer;
  57. trigger: LONGINT;
  58. handler: EventHandler
  59. END Timer;
  60. TimerActivity = OBJECT
  61. VAR
  62. t, r: Timer; h: EventHandler; restart: BOOLEAN;
  63. PROCEDURE UpdateTicks;
  64. BEGIN {EXCLUSIVE}
  65. Machine.UpdateTicks
  66. END UpdateTicks;
  67. PROCEDURE Restart;
  68. BEGIN {EXCLUSIVE}
  69. restart := TRUE
  70. END Restart;
  71. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  72. restart := FALSE;
  73. LOOP
  74. t := timers;
  75. IF t # NIL THEN
  76. h := NIL; r := NIL;
  77. BEGIN {EXCLUSIVE}
  78. AWAIT( (Machine.ticks >= t.trigger) OR restart ); restart := FALSE;
  79. IF Machine.ticks >= t.trigger THEN
  80. h := t.handler; r := t
  81. END
  82. END;
  83. IF r # NIL THEN Remove( r ) END;
  84. IF h # NIL THEN (* not canceled *) h END
  85. ELSE
  86. BEGIN{EXCLUSIVE}
  87. AWAIT( restart ); restart := FALSE;
  88. END
  89. END
  90. END
  91. END TimerActivity;
  92. Clock* = OBJECT
  93. BEGIN {ACTIVE}
  94. LOOP
  95. Unix.ThrSleep( 10 );
  96. IF ~timerStopped THEN timerActivity.UpdateTicks END
  97. END;
  98. END Clock;
  99. FinalizedCollection* = OBJECT (* base type for collection, extended in Kernel.Mod *)
  100. PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
  101. BEGIN HALT(301) END RemoveAll;
  102. END FinalizedCollection;
  103. FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
  104. c*: FinalizedCollection (* base type for collection containing object *)
  105. END;
  106. FinalizerCaller = OBJECT (* separate active object that calls finalizers *)
  107. VAR
  108. n: Heaps.FinalizerNode; start: BOOLEAN;
  109. PROCEDURE Activate;
  110. BEGIN {EXCLUSIVE}
  111. start := TRUE
  112. END Activate;
  113. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  114. start := FALSE;
  115. LOOP
  116. BEGIN {EXCLUSIVE} AWAIT( start ) END;
  117. start := FALSE;
  118. LOOP
  119. n := Heaps.GetFinalizer();
  120. IF n = NIL THEN EXIT END;
  121. IF n IS FinalizerNode THEN
  122. n(FinalizerNode).c.RemoveAll(n.objStrong) (* remove it if it is not removed yet *)
  123. END;
  124. IF n.finalizer # NIL THEN
  125. n.finalizer(n.objStrong) (* may acquire locks *)
  126. END;
  127. END;
  128. END
  129. END FinalizerCaller;
  130. Body = PROCEDURE ( self: ProtectedObject );
  131. Condition = PROCEDURE ( slink: ADDRESS ): BOOLEAN;
  132. Process* = OBJECT (Heaps.ProcessLink)
  133. VAR
  134. threadId- : Unix.Thread_t;
  135. nextProcess- : Process; (* next in list of all processes *)
  136. stackBottom - : ADDRESS;
  137. id- : LONGINT;
  138. body : Body;
  139. mode- : LONGINT;
  140. flags- : SET;
  141. priority- : LONGINT; (* only effective if Aos is running SUID root *)
  142. succ : Process; (* in ProcessQueue *)
  143. obj- : ProtectedObject; (* associated active object *)
  144. condition- : Condition; (* awaited process' condition *)
  145. condFP- : ADDRESS; (* awaited process' condition's context *)
  146. continue : Unix.Condition_t; (* gets signaled when condition yields true *)
  147. waitingOn- : ProtectedObject;
  148. procID- : LONGINT; (*! processor ID where running, not used in UnixAos *)
  149. state- : Machine.State;
  150. state0 : ARRAY 2048 OF CHAR; (* thread state at body start, used for restart after trap *)
  151. context: ANY; (* commands context *)
  152. PROCEDURE FindRoots*;
  153. VAR sp, bp, n, a0, a1, adr: ADDRESS; desc: Modules.ProcedureDescPointer; i: LONGINT; p {UNTRACED}: ANY;
  154. BEGIN
  155. IF mode # Terminated THEN
  156. IF SELF = CurrentProcess() THEN
  157. state.SP := Machine.CurrentSP( );
  158. state.BP := Machine.CurrentBP( );
  159. END;
  160. sp := state.SP; bp := state.BP;
  161. IF Heaps.GCType = Heaps.HeuristicStackInspectionGC THEN
  162. IF (stackBottom # 0) & (sp # 0) & (sp <= stackBottom) THEN
  163. Heaps.RegisterCandidates( sp, stackBottom - sp );
  164. END;
  165. ELSIF Heaps.GCType = Heaps.MetaDataForStackGC THEN
  166. IF bp < stackBottom THEN
  167. WHILE (bp # Heaps.NilVal) & (bp > 1024) & (bp < stackBottom) DO (* do not test for bp >= sp: could be wrong temporarily! *)
  168. S.GET( bp, n );
  169. IF ODD( n ) THEN (* procedure descriptor at bp *)
  170. IF n > 1024 THEN
  171. desc := S.VAL( Modules.ProcedureDescPointer, n-1 );
  172. IF desc # NIL THEN
  173. a0 := ADDRESSOF( desc.offsets );
  174. a1 := S.VAL( ADDRESS, desc.offsets );
  175. ASSERT( a0+SIZEOF( ADDRESS ) = a1, 54321 );
  176. FOR i := 0 TO LEN( desc.offsets ) - 1 DO
  177. adr := bp + desc.offsets[i]; (* pointer at offset *)
  178. S.GET( adr, p ); (* load pointer *)
  179. IF p # NIL THEN
  180. Heaps.Mark( p );
  181. END
  182. END
  183. END
  184. END;
  185. S.GET( bp + SIZEOF( ADDRESS ), bp );
  186. ELSE (* classical stack frame *)
  187. bp := n;
  188. END;
  189. END;
  190. ASSERT( (bp = stackBottom) OR (bp < 1024) , 12345 );
  191. END;
  192. END
  193. END;
  194. Heaps.Mark( nextProcess )
  195. END FindRoots;
  196. PROCEDURE Cancel;
  197. VAR pt, t: Process; kt: Unix.Thread_t;
  198. BEGIN
  199. IF SELF = CurrentProcess() THEN Exit
  200. ELSE
  201. Machine.Acquire( Machine.X11 ); (* let the thread to be killed first finish its last I/O, if any *)
  202. Unix.MtxLock( processList );
  203. pt := NIL; t := root; kt := 0;
  204. WHILE (t # NIL ) & (t # SELF) DO pt := t; t := t.nextProcess END;
  205. IF t = SELF THEN
  206. kt := threadId;
  207. IF pt = NIL THEN root := t.nextProcess ELSE pt.nextProcess := t.nextProcess END;
  208. END;
  209. Unix.MtxUnlock( processList );
  210. IF kt # 0 THEN Unix.ThrKill( kt ) END;
  211. Machine.Release( Machine.X11 );
  212. END
  213. END Cancel;
  214. PROCEDURE GetPriority( ): LONGINT;
  215. BEGIN
  216. RETURN Unix.ThrGetPriority( threadId )
  217. END GetPriority;
  218. PROCEDURE SetPriority( prio: LONGINT );
  219. VAR pr: LONGINT;
  220. BEGIN
  221. pr := max( Machine.prioLow, min( prio, Machine.prioHigh ) );
  222. Unix.ThrSetPriority( threadId, pr ); (* works only if SUID root *)
  223. priority := GetPriority( )
  224. END SetPriority;
  225. PROCEDURE & Initialize( obj: ProtectedObject; bodyProc: Body; prio: LONGINT; fl: SET; stacksize: LONGINT);
  226. BEGIN
  227. SELF.obj := obj; condition := NIL; continue := Unix.NewCond( );
  228. flags := fl;
  229. priority := prio;
  230. nextProcess := NIL;
  231. context := CurrentContext();
  232. IF root # NIL THEN
  233. newProcess := SELF;
  234. ASSERT( bodyProc # NIL );
  235. body := bodyProc;
  236. Unix.MtxLock( startProcess );
  237. threadId := Unix.ThrStart( BodyStarter, stacksize );
  238. Unix.CondWait( childrunning, startProcess );
  239. Unix.MtxUnlock( startProcess );
  240. RegisterFinalizer( SELF, FinalizeProcess );
  241. ELSE
  242. (* first process *)
  243. stackBottom := Glue.stackBottom;
  244. threadId := Unix.ThrThis( );
  245. id := 0; nextPID := 1;
  246. root := SELF;
  247. mode := Running;
  248. Unix.WriteKey( processPointer, SELF );
  249. END;
  250. END Initialize;
  251. END Process;
  252. GCStatusExt = OBJECT (Heaps.GCStatus)
  253. (* called from Heaps.InvokeGC, i.e. this is a hidden upcall. However, it is necessary to take the Machine.Objects
  254. lock here since writing the set of variables here must not be interrupted, i.e. atomic writing of the set of variables
  255. is absolutely necessary. They system may hang if the lock is not taken. *)
  256. PROCEDURE SetgcOngoing( value: BOOLEAN );
  257. VAR cur: Process;
  258. BEGIN (* serialize writers *)
  259. cur := CurrentProcess();
  260. IF value THEN
  261. Machine.Acquire( Machine.Objects );
  262. Machine.Acquire( Machine.Heaps );
  263. cur.state.SP := Machine.CurrentSP();
  264. cur.state.BP := Machine.CurrentBP();
  265. cur.state.PC := ADDRESSOF( GCLoop );
  266. SuspendActivities;
  267. Heaps.CollectGarbage( Modules.root );
  268. Machine.Release( Machine.Heaps );
  269. Machine.Release( Machine.Objects );
  270. ResumeActivities;
  271. finalizerCaller.Activate;
  272. END;
  273. END SetgcOngoing;
  274. END GCStatusExt;
  275. PROCEDURE BodyStarter;
  276. VAR p{UNTRACED}: Process; res: LONGINT; prevBP: ADDRESS;
  277. BEGIN
  278. Unix.MtxLock( startProcess );
  279. p := newProcess; newProcess := NIL;
  280. Unix.WriteKey( processPointer, p );
  281. p.id := nextPID; INC( nextPID );
  282. p.stackBottom := Machine.CurrentBP( );
  283. S.GET( p.stackBottom, prevBP );
  284. S.PUT( prevBP, S.VAL( ADDRESS, 0 ) ); (* for terminating Reflection.StackTraceBack *)
  285. Unix.MtxLock( processList );
  286. p.nextProcess := root; root := p;
  287. Unix.MtxUnlock( processList );
  288. Unix.CondSignal( childrunning );
  289. Unix.MtxUnlock( startProcess );
  290. p.SetPriority( p.priority );
  291. IF Restart IN p.flags THEN
  292. res := Unix.sigsetjmp( ADDRESSOF( p.state0[0] ), 1 );
  293. END;
  294. p.mode := Running;
  295. p.body( p.obj );
  296. p.mode := Terminated;
  297. Exit
  298. END BodyStarter;
  299. (*--------------------- create, lock, await, unlock -------------------------*)
  300. (* initialize the ObjectHeader, requires lockMutex temporarily *)
  301. PROCEDURE InitProtHeader( hdr: ObjectHeader);
  302. VAR lock: LockT;
  303. BEGIN
  304. (* we cannot hold the lockMute here because allocation can trigger the GC that requires the lock when activating the finalizers *)
  305. NEW(lock);
  306. Unix.MtxLock(lockMutex);
  307. IF hdr.lock = NIL THEN
  308. lock.mtx := Unix.NewMtx( ); lock.enter := Unix.NewCond( ); hdr.lockedBy := NIL;
  309. hdr.lock := lock;
  310. END;
  311. Unix.MtxUnlock(lockMutex);
  312. END InitProtHeader;
  313. PROCEDURE CreateProcess*( body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject );
  314. VAR p: Process; hdr: ObjectHeader;
  315. BEGIN
  316. Unix.MtxLock( createProcess );
  317. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  318. InitProtHeader( hdr );
  319. IF priority = 0 THEN priority := Normal END;
  320. NEW( p, obj, body, priority, flags, stacksize ) ; (* execute BodyStarter as new (posix or solaris) thread *)
  321. Unix.MtxUnlock( createProcess );
  322. RegisterFinalizer( obj, FinalizeActiveObj )
  323. END CreateProcess;
  324. PROCEDURE Lock*( obj: ProtectedObject; exclusive: BOOLEAN );
  325. VAR hdr: ObjectHeader; p: Process; lock: LockT;
  326. BEGIN
  327. ASSERT( exclusive ); (* shared not implemented yet *)
  328. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  329. p := CurrentProcess();
  330. p.state.SP := Machine.CurrentSP( );
  331. p.state.BP := Machine.CurrentBP( );
  332. p.state.PC := Machine.CurrentPC( );
  333. p.mode := AwaitingLock;
  334. (*! we might want to replace the lock mutex by a lock free construct *)
  335. IF hdr.lock = NIL THEN InitProtHeader( hdr ) END;
  336. lock := S.VAL(LockT, hdr.lock);
  337. p.mode := AwaitingLock;
  338. Unix.MtxLock( lock.mtx );
  339. WHILE hdr.lockedBy # NIL DO
  340. (* wait until threads with complied AWAIT conditions have left the monitor *)
  341. Unix.CondWait( lock.enter, lock.mtx );
  342. END;
  343. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  344. END Lock;
  345. PROCEDURE Await*( cond: Condition; slink: ADDRESS; obj: ProtectedObject; flags: SET );
  346. VAR hdr: ObjectHeader; p, c: Process; lock: LockT;
  347. BEGIN
  348. IF 1 IN flags THEN (* compiler did not generate IF *)
  349. IF cond( slink ) THEN (* condition already true *) RETURN END
  350. END;
  351. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  352. lock := S.VAL(LockT, hdr.lock);
  353. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  354. p := CurrentProcess();
  355. ASSERT( hdr.lockedBy = p, 2204 );
  356. p.succ := NIL; p.condition := cond; p.condFP := slink;
  357. p.waitingOn := obj; p.mode := AwaitingCond;
  358. Put( hdr.awaitingCond, p );
  359. hdr.lockedBy := c;
  360. IF c # NIL THEN Unix.CondSignal( c.continue ) ELSE Unix.CondSignal( lock.enter ) END;
  361. p.state.SP := Machine.CurrentSP( );
  362. p.state.BP := Machine.CurrentBP( );
  363. p.state.PC := Machine.CurrentPC( );
  364. Unix.CondWait( p.continue, lock.mtx );
  365. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  366. END Await;
  367. PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
  368. VAR hdr: ObjectHeader; c: Process; lock: LockT;
  369. BEGIN
  370. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  371. lock := S.VAL(LockT,hdr.lock);
  372. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  373. hdr.lockedBy := c;
  374. IF c # NIL THEN Unix.CondSignal( c.continue ) ELSE Unix.CondSignal( lock.enter ) END;
  375. Unix.MtxUnlock( lock.mtx );
  376. END Unlock;
  377. PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
  378. VAR first, cand: Process;
  379. BEGIN
  380. Get( q, first );
  381. IF first.condition( first.condFP ) THEN RETURN first ELSE Put( q, first ) END;
  382. WHILE q.head # first DO
  383. Get( q, cand );
  384. IF cand.condition( cand.condFP ) THEN RETURN cand ELSE Put( q, cand ) END;
  385. END;
  386. RETURN NIL
  387. END FindCondition;
  388. PROCEDURE Get( VAR queue: ProcessQueue; VAR new: Process );
  389. VAR t: Process;
  390. BEGIN
  391. t := queue.head(Process);
  392. IF t # NIL THEN
  393. IF t = queue.tail THEN queue.head := NIL; queue.tail := NIL
  394. ELSE queue.head := t.succ; t.succ := NIL
  395. END
  396. END;
  397. new := t
  398. END Get;
  399. PROCEDURE Put( VAR queue: ProcessQueue; t: Process );
  400. BEGIN
  401. IF queue.head = NIL THEN queue.head := t ELSE queue.tail(Process).succ := t END;
  402. queue.tail := t
  403. END Put;
  404. (*-------------------------------------------------------------------------*)
  405. PROCEDURE Terminate*;
  406. BEGIN
  407. Exit
  408. END Terminate;
  409. PROCEDURE TerminateThis*( p: Process; unbreakable: BOOLEAN );
  410. BEGIN
  411. p.mode := Terminated;
  412. p.Cancel
  413. END TerminateThis;
  414. PROCEDURE SetPriority*( pri: LONGINT ); (* Set the current process' priority. *)
  415. VAR me: Process;
  416. BEGIN
  417. me := CurrentProcess();
  418. me.SetPriority( pri )
  419. END SetPriority;
  420. PROCEDURE Sleep*( ms: LONGINT );
  421. BEGIN
  422. Unix.ThrSleep( ms );
  423. END Sleep;
  424. PROCEDURE Yield*; (* Relinquish control. *)
  425. BEGIN
  426. Unix.ThrYield( );
  427. END Yield;
  428. (* Return current process. (DEPRECATED, use ActiveObject) *)
  429. PROCEDURE CurrentProcess*( ): Process;
  430. BEGIN
  431. RETURN S.VAL( Process, Unix.ReadKey( processPointer ) )
  432. END CurrentProcess;
  433. PROCEDURE CurrentContext*(): ANY;
  434. VAR p: Process;
  435. BEGIN
  436. p := CurrentProcess();
  437. IF p # NIL THEN RETURN p.context
  438. ELSE RETURN NIL
  439. END;
  440. END CurrentContext;
  441. PROCEDURE SetContext*(context: ANY);
  442. VAR p: Process;
  443. BEGIN
  444. p := CurrentProcess();
  445. IF p # NIL THEN p.context := context END;
  446. END SetContext;
  447. (* Return the active object currently executing. *)
  448. PROCEDURE ActiveObject*( ): ANY;
  449. VAR p: Process;
  450. BEGIN
  451. p := CurrentProcess();
  452. RETURN p.obj
  453. END ActiveObject;
  454. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  455. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  456. BEGIN
  457. RETURN p.stackBottom
  458. END GetStackBottom;
  459. PROCEDURE GetProcessID*( ): LONGINT;
  460. VAR p: Process;
  461. BEGIN
  462. p := CurrentProcess();
  463. RETURN p.id;
  464. END GetProcessID;
  465. PROCEDURE GetCpuCycles*( process : Process; VAR cpuCycles: CpuCyclesArray; all: BOOLEAN );
  466. VAR i: LONGINT;
  467. BEGIN
  468. ASSERT( process # NIL );
  469. FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := 0 END;
  470. END GetCpuCycles;
  471. (*-----------------------------------------------------------------------*)
  472. PROCEDURE min( a, b: LONGINT ): LONGINT;
  473. BEGIN
  474. IF a <= b THEN RETURN a ELSE RETURN b END
  475. END min;
  476. PROCEDURE max( a, b: LONGINT ): LONGINT;
  477. BEGIN
  478. IF a >= b THEN RETURN a ELSE RETURN b END
  479. END max;
  480. PROCEDURE RegisterFinalizer( obj: ANY; fin: Heaps.Finalizer );
  481. VAR n: Heaps.FinalizerNode;
  482. BEGIN
  483. NEW( n ); n.finalizer := fin; Heaps.AddFinalizer( obj, n );
  484. END RegisterFinalizer;
  485. PROCEDURE FinalizeActiveObj( obj: ANY );
  486. VAR p: Process;
  487. BEGIN
  488. Unix.MtxLock( processList );
  489. p := root;
  490. WHILE (p # NIL) & (p.obj # obj) DO p := p.nextProcess END;
  491. Unix.MtxUnlock( processList );
  492. IF (p # NIL) & (p.obj = obj) THEN
  493. p.mode := Terminated;
  494. Unix.CondDestroy( p.continue ); p.continue := 0;
  495. FinalizeProtObject( obj );
  496. p.Cancel
  497. END;
  498. END FinalizeActiveObj;
  499. PROCEDURE FinalizeProtObject( obj: ANY );
  500. VAR hdr: ObjectHeader; lock: LockT;
  501. BEGIN
  502. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  503. IF hdr.lock # NIL THEN
  504. lock := S.VAL(LockT, hdr.lock);
  505. Unix.MtxDestroy( lock.mtx ); lock.mtx := 0
  506. END
  507. END FinalizeProtObject;
  508. PROCEDURE FinalizeProcess( obj: ANY );
  509. VAR p: Process;
  510. BEGIN
  511. p := obj(Process);
  512. IF p.continue # 0 THEN
  513. Unix.CondDestroy( p.continue ); p.continue := 0
  514. END
  515. END FinalizeProcess;
  516. (* Terminate calling thread. *)
  517. PROCEDURE Exit;
  518. VAR prev, p, me: Process;
  519. BEGIN
  520. me := CurrentProcess();
  521. me.mode := Terminated;
  522. Unix.MtxLock( processList );
  523. prev := NIL; p := root;
  524. WHILE (p # NIL ) & (p # me) DO prev := p; p := p.nextProcess END;
  525. IF p = me THEN
  526. IF prev = NIL THEN root := p.nextProcess ELSE prev.nextProcess := p.nextProcess END;
  527. END;
  528. Unix.MtxUnlock( processList );
  529. Unix.ThrExit( );
  530. END Exit;
  531. PROCEDURE ExitTrap*;
  532. VAR p: Process;
  533. BEGIN
  534. p := CurrentProcess();
  535. (* restart the object body if it was given the SAFE flag *)
  536. IF Restart IN p.flags THEN
  537. Unix.siglongjmp( ADDRESSOF( p.state0[0] ), 1 )
  538. END;
  539. Exit
  540. END ExitTrap;
  541. (*---------------------------- Timer --------------------------------*)
  542. PROCEDURE Remove( t: Timer ); (* remove timer from list of active timers *)
  543. VAR p, x: Timer;
  544. BEGIN
  545. Unix.MtxLock( timerListMutex );
  546. t.trigger := 0; t.handler := NIL;
  547. IF timers # NIL THEN
  548. IF t = timers THEN
  549. timers := t.next
  550. ELSE
  551. p := timers; x := p.next;
  552. WHILE (x # NIL) & (x # t) DO p := x; x := p.next END;
  553. IF x = t THEN p.next := t.next END
  554. END;
  555. t.next := NIL
  556. END;
  557. Unix.MtxUnlock( timerListMutex )
  558. END Remove;
  559. PROCEDURE Insert( t: Timer );
  560. VAR p, x: Timer;
  561. BEGIN
  562. Unix.MtxLock( timerListMutex );
  563. p := NIL; x := timers;
  564. WHILE (x # NIL) & (x.trigger < t.trigger) DO p := x; x := p.next END;
  565. t.next := x;
  566. IF p = NIL THEN timers := t ELSE p.next := t END;
  567. Unix.MtxUnlock( timerListMutex )
  568. END Insert;
  569. PROCEDURE SetTimeout*( t: Timer; h: EventHandler; ms: LONGINT );
  570. BEGIN
  571. ASSERT( ( t # NIL) & ( h # NIL) );
  572. Remove( t );
  573. IF ms < 1 THEN ms := 1 END;
  574. t.trigger := Machine.ticks + ms; t.handler := h;
  575. Insert( t );
  576. timerActivity.Restart
  577. END SetTimeout;
  578. PROCEDURE SetTimeoutAt*( t: Timer; h: EventHandler; ms: LONGINT );
  579. BEGIN
  580. ASSERT( (t # NIL) & (h # NIL) );
  581. Remove( t );
  582. t.trigger := ms; t.handler := h;
  583. Insert( t );
  584. timerActivity.Restart
  585. END SetTimeoutAt;
  586. PROCEDURE CancelTimeout*( t: Timer );
  587. BEGIN
  588. Remove( t )
  589. END CancelTimeout;
  590. (*-------------------- Garbage Collection ------------------------------------*)
  591. PROCEDURE GetContext( ctxt: Unix.Ucontext );
  592. VAR t: Process; context: Unix.McontextDesc;
  593. BEGIN
  594. t := CurrentProcess( );
  595. Unix.CopyContext( ctxt.mc, context );
  596. t.state.PC := context.r_pc;
  597. t.state.BP := context.r_bp;
  598. t.state.SP := context.r_sp
  599. END GetContext;
  600. (* called by WMProcessInfo to obtain the current state of a running process *)
  601. PROCEDURE UpdateProcessState*( p: Process );
  602. BEGIN
  603. IF p.threadId = Unix.ThrThis( ) THEN
  604. p.state.PC := Machine.CurrentPC( );
  605. p.state.BP := Machine.CurrentBP( );
  606. p.state.SP := Machine.CurrentSP( )
  607. ELSE
  608. IF p.mode = Running THEN
  609. timerStopped := TRUE;
  610. Unix.ThrSleep( 3 );
  611. IF p.mode = Running THEN (* still running *)
  612. Unix.ThrSuspend( p.threadId, TRUE );
  613. Unix.ThrResume( p.threadId );
  614. END;
  615. timerStopped := FALSE
  616. END
  617. END
  618. END UpdateProcessState;
  619. PROCEDURE SuspendActivities;
  620. VAR t, me: Process;
  621. BEGIN
  622. me := CurrentProcess();
  623. t := root;
  624. WHILE t # NIL DO
  625. IF t # me THEN
  626. Unix.ThrSuspend( t.threadId, t.mode = Running );
  627. END;
  628. t := t.nextProcess
  629. END;
  630. END SuspendActivities;
  631. PROCEDURE ResumeActivities;
  632. VAR t, me: Process;
  633. BEGIN
  634. me := CurrentProcess();
  635. t := root;
  636. WHILE t # NIL DO
  637. IF (t # me) THEN
  638. Unix.ThrResume( t.threadId );
  639. END;
  640. t := t.nextProcess
  641. END;
  642. END ResumeActivities;
  643. PROCEDURE GCLoop*; (* Timer and GC activity *)
  644. BEGIN
  645. (*
  646. If using BootConsole keep main thread running.
  647. If the thread is blocked by a mutex (MainThreadSleep)
  648. the signals SIGHUP, SIGINT and SIGQUIT don't branch into SignalHandler
  649. but terminate A2 (at least in Solaris).
  650. *)
  651. SystemA2Up := TRUE;
  652. LOOP Sleep( 100 ) END
  653. END GCLoop;
  654. PROCEDURE CurrentProcessTime*(): HUGEINT;
  655. BEGIN
  656. RETURN Machine.GetTimer()
  657. END CurrentProcessTime;
  658. PROCEDURE TimerFrequency*(): HUGEINT;
  659. BEGIN
  660. RETURN Machine.mhz * 1000000
  661. END TimerFrequency;
  662. PROCEDURE LeaveA2;
  663. VAR cur: Process; bp, n: ADDRESS;
  664. BEGIN
  665. IF clock = NIL THEN RETURN END;
  666. cur := CurrentProcess();
  667. IF cur # NIL THEN
  668. bp := Machine.CurrentBP();
  669. S.GET( bp, n );
  670. IF ODD( n ) THEN S.GET( bp + SIZEOF( ADDRESS ), bp ) ELSE bp := n END;
  671. cur.state.BP := bp;
  672. END;
  673. END LeaveA2;
  674. PROCEDURE ReenterA2;
  675. VAR cur: Process;
  676. BEGIN
  677. IF clock = NIL THEN RETURN END;
  678. cur := CurrentProcess();
  679. IF cur # NIL THEN
  680. cur.state.BP := 0;
  681. END;
  682. END ReenterA2;
  683. (*----------------------------- initialization ----------------------------------*)
  684. PROCEDURE StartTimerActivity;
  685. BEGIN
  686. timerListMutex := Unix.NewMtx( ); timers := NIL;
  687. NEW( timerActivity );
  688. END StartTimerActivity;
  689. PROCEDURE GetStacksize;
  690. VAR str: ARRAY 32 OF CHAR; i: LONGINT;
  691. BEGIN
  692. Machine.GetConfig( "StackSize", str );
  693. IF str = "" THEN stacksize := DefaultStacksize
  694. ELSE
  695. i := 0; stacksize := Machine.StrToInt( i, str );
  696. stacksize := stacksize * 1024;
  697. END;
  698. IF Glue.debug # {} THEN
  699. Trace.String( "Stacksize of active objects = " );
  700. Trace.Int( stacksize DIV 1024, 0 ); Trace.StringLn( "K" )
  701. END;
  702. END GetStacksize;
  703. PROCEDURE Convert;
  704. VAR p: Process;
  705. BEGIN
  706. (* make current thread the first active object *)
  707. mainthread := Unix.ThrThis();
  708. NEW( p, NIL, NIL, 0, {}, 0 );
  709. END Convert;
  710. PROCEDURE Init;
  711. BEGIN
  712. Unix.suspendHandler := GetContext;
  713. createProcess := Unix.NewMtx( ); processList := Unix.NewMtx( );
  714. startProcess := Unix.NewMtx( ); childrunning := Unix.NewCond( );
  715. lockMutex := Unix.NewMtx( );
  716. processPointer := Unix.NewKey( );
  717. GetStacksize;
  718. Convert;
  719. NEW( clock ); StartTimerActivity; timerStopped := FALSE;
  720. NEW( finalizerCaller );
  721. Heaps.gcStatus := GCStatusFactory()
  722. END Init;
  723. TYPE
  724. MainThread = OBJECT
  725. VAR exit: BOOLEAN;
  726. PROCEDURE & Init;
  727. BEGIN
  728. exit := FALSE;
  729. END Init;
  730. PROCEDURE Await();
  731. BEGIN {EXCLUSIVE}
  732. AWAIT( exit );
  733. END Await;
  734. END MainThread;
  735. VAR main: MainThread;
  736. PROCEDURE MainThreadSleep;
  737. BEGIN
  738. NEW( main );
  739. main.Await( );
  740. Unix.exit( 0 );
  741. END MainThreadSleep;
  742. PROCEDURE {FINAL} Final;
  743. BEGIN
  744. MainThreadSleep;
  745. END Final;
  746. PROCEDURE GCStatusFactory(): Heaps.GCStatus;
  747. VAR gcStatusExt : GCStatusExt;
  748. BEGIN
  749. ASSERT( Heaps.gcStatus = NIL );
  750. NEW( gcStatusExt );
  751. RETURN gcStatusExt
  752. END GCStatusFactory;
  753. VAR
  754. (* for compatibility and later extension *)
  755. TraceProcessHook*: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
  756. BEGIN
  757. TraceProcessHook := NIL;
  758. SystemA2Up := FALSE;
  759. Init;
  760. END Objects.