Generic.Unix.Objects.Mod 24 KB

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