Unix.Objects.Mod 25 KB

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