Unix.Objects.Mod 24 KB

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