Generic.Unix.Objects.Mod 24 KB

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