Generic.Solaris.Objects.Mod 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  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. AddrSize = SIZEOF( ADDRESS )
  25. VAR
  26. (* timer *)
  27. timerActivity : TimerActivity;
  28. clock : Clock;
  29. timers : Timer;
  30. timerListMutex : Unix.Mutex_t;
  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. TYPE
  43. LockT= POINTER TO RECORD
  44. mtx, enter: ADDRESS;
  45. END;
  46. CpuCyclesArray* = ARRAY Machine.MaxCPU OF HUGEINT;
  47. ProtectedObject = POINTER TO RECORD END;
  48. ObjectHeader = Heaps.ProtRecBlock;
  49. ProcessQueue = Heaps.ProcessQueue;
  50. EventHandler* = PROCEDURE {DELEGATE};
  51. Timer* = OBJECT
  52. VAR
  53. next: Timer;
  54. trigger: LONGINT;
  55. handler: EventHandler
  56. END Timer;
  57. TimerActivity = OBJECT
  58. VAR
  59. t, r: Timer; h: EventHandler; restart: BOOLEAN;
  60. PROCEDURE UpdateTicks;
  61. BEGIN {EXCLUSIVE}
  62. Machine.UpdateTicks
  63. END UpdateTicks;
  64. PROCEDURE Restart;
  65. BEGIN {EXCLUSIVE}
  66. restart := TRUE
  67. END Restart;
  68. BEGIN {ACTIVE, SAFE, PRIORITY(High)}
  69. restart := FALSE;
  70. LOOP
  71. t := timers;
  72. IF t # NIL THEN
  73. h := NIL; r := NIL;
  74. BEGIN {EXCLUSIVE}
  75. AWAIT( (Machine.ticks >= t.trigger) OR restart ); restart := FALSE;
  76. IF Machine.ticks >= t.trigger THEN
  77. h := t.handler; r := t
  78. END
  79. END;
  80. IF r # NIL THEN Remove( r ) END;
  81. IF h # NIL THEN (* not canceled *) h END
  82. ELSE
  83. BEGIN{EXCLUSIVE}
  84. AWAIT( restart ); restart := FALSE;
  85. END
  86. END
  87. END
  88. END TimerActivity;
  89. Clock* = OBJECT
  90. VAR i: LONGINT;
  91. BEGIN{ACTIVE}
  92. LOOP
  93. Unix.ThrSleep( 10 );
  94. timerActivity.UpdateTicks
  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. Machine.ReleaseGC( )
  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; (*! not used in UnixAos! *)
  149. context : Unix.McontextDesc;
  150. state0 : ARRAY 2048 OF CHAR; (* thread state at body start, used for restart after trap *)
  151. PROCEDURE FindRoots*;
  152. VAR sp, ptr, bp, n, a0, a1, adr: ADDRESS; desc: Modules.ProcedureDescPointer; i: LONGINT; p {UNTRACED}: ANY;
  153. me: Process;
  154. BEGIN
  155. IF mode # Terminated THEN
  156. IF SELF = CurrentProcess() THEN
  157. context.r_sp := Machine.CurrentSP( );
  158. context.r_bp := Machine.CurrentBP( );
  159. END;
  160. sp := context.r_sp; bp := context.r_bp;
  161. IF Heaps.GCType = Heaps.HeuristicStackInspectionGC THEN
  162. (* Heaps.Candidate( context.r_di ); Heaps.Candidate( context.r_si );
  163. Heaps.Candidate( context.r_bx ); Heaps.Candidate( context.r_dx );
  164. Heaps.Candidate( context.r_cx ); Heaps.Candidate( context.r_ax); *)
  165. IF (stackBottom # 0) & (sp # 0) & (sp <= stackBottom) THEN
  166. Heaps.RegisterCandidates( sp, stackBottom - sp );
  167. END;
  168. ELSIF Heaps.GCType = Heaps.MetaDataForStackGC THEN
  169. IF bp < stackBottom THEN
  170. WHILE (bp # Heaps.NilVal) & (bp > 1024) & (bp < stackBottom) DO (* do not test for bp >= sp: could be wrong temporarily! *)
  171. TRACE( bp );
  172. S.GET( bp, n );
  173. TRACE( n );
  174. IF ODD( n ) THEN (* procedure descriptor at bp *)
  175. IF n > 1024 THEN
  176. desc := S.VAL( Modules.ProcedureDescPointer, n-1 );
  177. IF desc # NIL THEN
  178. a0 := ADDRESSOF( desc.offsets );
  179. a1 := S.VAL( ADDRESS, desc.offsets );
  180. ASSERT( a0+SIZEOF( ADDRESS ) = a1, 54321 );
  181. FOR i := 0 TO LEN( desc.offsets ) - 1 DO
  182. adr := bp + desc.offsets[i]; (* pointer at offset *)
  183. S.GET( adr, p ); (* load pointer *)
  184. IF p # NIL THEN
  185. Heaps.Mark( p );
  186. END
  187. END
  188. END
  189. END;
  190. S.GET( bp + SIZEOF( ADDRESS ), bp );
  191. ELSE (* classical stack frame *)
  192. bp := n;
  193. END;
  194. TRACE( bp );
  195. END;
  196. ASSERT( (bp = stackBottom) OR (bp < 1024) , 12345 );
  197. END;
  198. END
  199. END;
  200. Heaps.Mark( nextProcess )
  201. END FindRoots;
  202. PROCEDURE Cancel;
  203. VAR pt, t: Process; kt: Unix.Thread_t;
  204. BEGIN
  205. IF SELF = CurrentProcess() THEN Exit
  206. ELSE
  207. Machine.Acquire( Machine.X11 ); (* let the thread to be killed first finish its last I/O, if any *)
  208. Unix.MtxLock( processList );
  209. pt := NIL; t := root; kt := 0;
  210. WHILE (t # NIL ) & (t # SELF) DO pt := t; t := t.nextProcess END;
  211. IF t = SELF THEN
  212. kt := threadId;
  213. IF pt = NIL THEN root := t.nextProcess ELSE pt.nextProcess := t.nextProcess END;
  214. END;
  215. Unix.MtxUnlock( processList );
  216. IF kt # 0 THEN Unix.ThrKill( kt ) END;
  217. Machine.Release( Machine.X11 );
  218. END
  219. END Cancel;
  220. PROCEDURE GetPriority( ): LONGINT;
  221. BEGIN
  222. RETURN Unix.ThrGetPriority( threadId )
  223. END GetPriority;
  224. PROCEDURE SetPriority( prio: LONGINT );
  225. VAR pr: LONGINT;
  226. BEGIN
  227. pr := max( Machine.prioLow, min( prio, Machine.prioHigh ) );
  228. Unix.ThrSetPriority( threadId, pr ); (* works only if SUID root *)
  229. priority := GetPriority( )
  230. END SetPriority;
  231. PROCEDURE & Initialize( obj: ProtectedObject; bodyProc: Body; prio: LONGINT; fl: SET; stacksize: LONGINT);
  232. VAR thr: Unix.Thread_t;
  233. BEGIN
  234. SELF.obj := obj; condition := NIL; continue := Unix.ConInit(0);
  235. flags := fl;
  236. priority := prio;
  237. nextProcess := NIL;
  238. IF root # NIL THEN
  239. newProcess := SELF;
  240. ASSERT( bodyProc # NIL );
  241. body := bodyProc;
  242. Unix.MtxLock( startProcess );
  243. thr := Unix.ThrStart( BodyStarter, stacksize );
  244. Unix.ConWait( childrunning, startProcess );
  245. Unix.MtxUnlock( startProcess );
  246. RegisterFinalizer( SELF, FinalizeProcess );
  247. ELSE
  248. (* first process *)
  249. stackBottom := Glue.stackBottom;
  250. threadId := Unix.ThrThis(0);
  251. id := 0; nextPID := 1;
  252. root := SELF;
  253. mode := Running;
  254. END;
  255. END Initialize;
  256. END Process;
  257. GCStatusExt = OBJECT (Heaps.GCStatus)
  258. PROCEDURE SetgcOngoing( value: BOOLEAN );
  259. BEGIN
  260. IF value THEN
  261. IF Machine.AcquireGC( ) THEN
  262. (* Trace.StringLn( "[GC" ); *)
  263. Machine.Acquire( Machine.X11 );
  264. Machine.Acquire( Machine.Heaps );
  265. SuspendActivities;
  266. Heaps.CollectGarbage( Modules.root );
  267. Machine.Release( Machine.Heaps );
  268. Machine.Release( Machine.X11 );
  269. ResumeActivities;
  270. finalizerCaller.Activate;
  271. (* Trace.StringLn( "GC]" ) *)
  272. (* ELSE
  273. Trace.StringLn( "-GC-" ) *)
  274. END
  275. END;
  276. END SetgcOngoing;
  277. END GCStatusExt;
  278. PROCEDURE BodyStarter;
  279. VAR p{UNTRACED}: Process; res: LONGINT; prevBP: ADDRESS; i: LONGINT;
  280. BEGIN
  281. Unix.MtxLock( startProcess );
  282. p := newProcess; newProcess := NIL;
  283. p.threadId := Unix.ThrThis(0);
  284. p.id := nextPID; INC( nextPID );
  285. p.stackBottom := Machine.CurrentBP( );
  286. S.GET( p.stackBottom, prevBP );
  287. S.PUT( prevBP, S.VAL( ADDRESS, 0 ) ); (* for terminating Reflection.StackTraceBack *)
  288. Unix.MtxLock( processList );
  289. p.nextProcess := root; root := p;
  290. Unix.MtxUnlock( processList );
  291. Unix.ConSignal( childrunning );
  292. Unix.MtxUnlock( startProcess );
  293. p.SetPriority( p.priority );
  294. IF Restart IN p.flags THEN
  295. res := Unix.sigsetjmp( ADDRESSOF( p.state0[0] ), 1 );
  296. END;
  297. p.mode := Running;
  298. p.body( p.obj );
  299. p.mode := Terminated;
  300. Exit
  301. END BodyStarter;
  302. (*--------------------- create, lock, await, unlock -------------------------*)
  303. (* initialize the ObjectHeader, requires lockMutex temporarily *)
  304. PROCEDURE InitProtHeader( hdr: ObjectHeader);
  305. VAR lock: LockT;
  306. BEGIN
  307. (* we cannot hold the lockMute here because allocation can trigger the GC that requires the lock when activating the finalizers *)
  308. NEW(lock);
  309. Unix.MtxLock(lockMutex);
  310. IF hdr.lock = NIL THEN
  311. hdr.lock := lock;
  312. lock.mtx := Unix.MtxInit( 0 ); lock.enter := Unix.ConInit( 0 ); hdr.lockedBy := NIL;
  313. END;
  314. Unix.MtxUnlock(lockMutex);
  315. END InitProtHeader;
  316. PROCEDURE CreateProcess*( body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject );
  317. VAR p: Process; hdr: ObjectHeader;
  318. BEGIN
  319. Unix.MtxLock( createProcess );
  320. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  321. InitProtHeader( hdr );
  322. IF priority = 0 THEN priority := Normal END;
  323. NEW( p, obj, body, priority, flags, stacksize ) ; (* execute BodyStarter as new (posix or solaris) thread *)
  324. Unix.MtxUnlock( createProcess );
  325. RegisterFinalizer( obj, FinalizeActiveObj )
  326. END CreateProcess;
  327. PROCEDURE Lock*( obj: ProtectedObject; exclusive: BOOLEAN );
  328. VAR hdr: ObjectHeader; p: Process; lock: LockT;
  329. BEGIN
  330. ASSERT( exclusive ); (* shared not implemented yet *)
  331. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  332. p := CurrentProcess();
  333. p.context.r_sp := Machine.CurrentSP( );
  334. p.context.r_bp := Machine.CurrentBP( );
  335. p.mode := AwaitingLock;
  336. (*! we might want to replace the lock mutex by a lock free construct *)
  337. IF hdr.lock = NIL THEN InitProtHeader( hdr ) END;
  338. lock := S.VAL(LockT, hdr.lock);
  339. p.mode := Locked;
  340. Unix.MtxLock( lock.mtx );
  341. WHILE hdr.lockedBy # NIL DO
  342. (* wait until threads with complied AWAIT conditions have left the monitor *)
  343. p.mode := AwaitingLock;
  344. Unix.ConWait( lock.enter, lock.mtx );
  345. END;
  346. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  347. END Lock;
  348. PROCEDURE Await*( cond: Condition; slink: ADDRESS; obj: ProtectedObject; flags: SET );
  349. VAR hdr: ObjectHeader; p, c: Process; lock: LockT; sp: ADDRESS;
  350. BEGIN
  351. IF 1 IN flags THEN (* compiler did not generate IF *)
  352. IF cond( slink ) THEN (* condition already true *) RETURN END
  353. END;
  354. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  355. lock := S.VAL(LockT, hdr.lock);
  356. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  357. p := CurrentProcess(); p.succ := NIL; p.condition := cond; p.condFP := slink;
  358. p.waitingOn := obj; p.mode := AwaitingCond;
  359. Put( hdr.awaitingCond, p );
  360. hdr.lockedBy := c;
  361. IF c # NIL THEN Unix.ConSignal( c.continue ) ELSE Unix.ConSignal( lock.enter ) END;
  362. p.context.r_sp := Machine.CurrentSP( );
  363. p.context.r_bp := Machine.CurrentBP( );
  364. Unix.ConWait( p.continue, lock.mtx );
  365. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  366. END Await;
  367. PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
  368. VAR hdr: ObjectHeader; c: Process; lock: LockT;
  369. BEGIN
  370. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  371. lock := S.VAL(LockT,hdr.lock);
  372. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  373. hdr.lockedBy := c;
  374. IF c # NIL THEN Unix.ConSignal( c.continue ) ELSE Unix.ConSignal( lock.enter ) END;
  375. Unix.MtxUnlock( lock.mtx );
  376. END Unlock;
  377. PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
  378. VAR first, cand: Process;
  379. BEGIN
  380. Get( q, first );
  381. IF first.condition( first.condFP ) THEN RETURN first ELSE Put( q, first ) END;
  382. WHILE q.head # first DO
  383. Get( q, cand );
  384. IF cand.condition( cand.condFP ) THEN RETURN cand ELSE Put( q, cand ) END;
  385. END;
  386. RETURN NIL
  387. END FindCondition;
  388. PROCEDURE Get( VAR queue: ProcessQueue; VAR new: Process );
  389. VAR t: Process;
  390. BEGIN
  391. t := queue.head(Process);
  392. IF t # NIL THEN
  393. IF t = queue.tail THEN queue.head := NIL; queue.tail := NIL
  394. ELSE queue.head := t.succ; t.succ := NIL
  395. END
  396. END;
  397. new := t
  398. END Get;
  399. PROCEDURE Put( VAR queue: ProcessQueue; t: Process );
  400. BEGIN
  401. IF queue.head = NIL THEN queue.head := t ELSE queue.tail(Process).succ := t END;
  402. queue.tail := t
  403. END Put;
  404. (*-------------------------------------------------------------------------*)
  405. PROCEDURE Terminate*;
  406. BEGIN
  407. Exit
  408. END Terminate;
  409. PROCEDURE TerminateThis*( p: Process; unbreakable: BOOLEAN );
  410. BEGIN
  411. p.mode := Terminated;
  412. p.Cancel
  413. END TerminateThis;
  414. PROCEDURE SetPriority*( pri: LONGINT ); (* Set the current process' priority. *)
  415. VAR me: Process;
  416. BEGIN
  417. me := CurrentProcess();
  418. me.SetPriority( pri )
  419. END SetPriority;
  420. PROCEDURE Sleep*( ms: LONGINT );
  421. BEGIN
  422. Unix.ThrSleep( ms )
  423. END Sleep;
  424. PROCEDURE Yield*; (* Relinquish control. *)
  425. BEGIN
  426. Unix.ThrYield(0);
  427. END Yield;
  428. (* Return current process. (DEPRECATED, use ActiveObject) *)
  429. PROCEDURE CurrentProcess*( ): Process;
  430. VAR me: Unix.Thread_t; p: Process;
  431. BEGIN
  432. me := Unix.ThrThis(0);
  433. Unix.MtxLock( processList );
  434. p := root;
  435. WHILE (p # NIL) & (p.threadId # me) DO p := p.nextProcess END;
  436. Unix.MtxUnlock( processList );
  437. RETURN p
  438. END CurrentProcess;
  439. (* Return the active object currently executing. *)
  440. PROCEDURE ActiveObject*( ): ANY;
  441. VAR p: Process;
  442. BEGIN
  443. p := CurrentProcess();
  444. RETURN p.obj
  445. END ActiveObject;
  446. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  447. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  448. BEGIN
  449. RETURN p.stackBottom
  450. END GetStackBottom;
  451. PROCEDURE GetProcessID*( ): LONGINT;
  452. VAR p: Process;
  453. BEGIN
  454. p := CurrentProcess();
  455. RETURN p.id;
  456. END GetProcessID;
  457. PROCEDURE GetCpuCycles*( process : Process; VAR cpuCycles: CpuCyclesArray; all: BOOLEAN );
  458. VAR i: LONGINT;
  459. BEGIN
  460. ASSERT( process # NIL );
  461. FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := 0 END;
  462. END GetCpuCycles;
  463. (*-----------------------------------------------------------------------*)
  464. PROCEDURE min( a, b: LONGINT ): LONGINT;
  465. BEGIN
  466. IF a <= b THEN RETURN a ELSE RETURN b END
  467. END min;
  468. PROCEDURE max( a, b: LONGINT ): LONGINT;
  469. BEGIN
  470. IF a >= b THEN RETURN a ELSE RETURN b END
  471. END max;
  472. PROCEDURE RegisterFinalizer( obj: ANY; fin: Heaps.Finalizer );
  473. VAR n: Heaps.FinalizerNode;
  474. BEGIN
  475. NEW( n ); n.finalizer := fin; Heaps.AddFinalizer( obj, n );
  476. END RegisterFinalizer;
  477. PROCEDURE FinalizeActiveObj( obj: ANY );
  478. VAR p: Process;
  479. BEGIN
  480. Unix.MtxLock( processList );
  481. p := root;
  482. WHILE (p # NIL) & (p.obj # obj) DO p := p.nextProcess END;
  483. Unix.MtxUnlock( processList );
  484. IF (p # NIL) & (p.obj = obj) THEN
  485. p.mode := Terminated;
  486. Unix.ConDestroy( p.continue ); p.continue := 0;
  487. FinalizeProtObject( obj );
  488. p.Cancel
  489. END;
  490. END FinalizeActiveObj;
  491. PROCEDURE FinalizeProtObject( obj: ANY );
  492. VAR hdr: ObjectHeader; lock: LockT;
  493. BEGIN
  494. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  495. IF hdr.lock # NIL THEN
  496. lock := S.VAL(LockT, hdr.lock);
  497. Unix.MtxDestroy( lock.mtx ); lock.mtx := 0
  498. END
  499. END FinalizeProtObject;
  500. PROCEDURE FinalizeProcess( obj: ANY );
  501. VAR p: Process;
  502. BEGIN
  503. p := obj(Process);
  504. IF p.continue # 0 THEN
  505. Unix.ConDestroy( p.continue ); p.continue := 0
  506. END
  507. END FinalizeProcess;
  508. (* Terminate calling thread. *)
  509. PROCEDURE Exit;
  510. VAR prev, p, me: Process;
  511. BEGIN
  512. me := CurrentProcess();
  513. me.mode := Terminated;
  514. Unix.MtxLock( processList );
  515. prev := NIL; p := root;
  516. WHILE (p # NIL ) & (p # me) DO prev := p; p := p.nextProcess END;
  517. IF p = me THEN
  518. IF prev = NIL THEN root := p.nextProcess ELSE prev.nextProcess := p.nextProcess END;
  519. END;
  520. Unix.MtxUnlock( processList );
  521. Unix.ThrExit(0);
  522. END Exit;
  523. PROCEDURE ExitTrap*;
  524. VAR p: Process;
  525. BEGIN
  526. p := CurrentProcess();
  527. (* restart the object body if it was given the SAFE flag *)
  528. IF Restart IN p.flags THEN
  529. Unix.siglongjmp( ADDRESSOF( p.state0[0] ), 1 )
  530. END;
  531. Exit
  532. END ExitTrap;
  533. (*---------------------------- Timer --------------------------------*)
  534. PROCEDURE Remove( t: Timer ); (* remove timer from list of active timers *)
  535. VAR p, x: Timer;
  536. BEGIN
  537. Unix.MtxLock( timerListMutex );
  538. t.trigger := 0; t.handler := NIL;
  539. IF timers # NIL THEN
  540. IF t = timers THEN
  541. timers := t.next
  542. ELSE
  543. p := timers; x := p.next;
  544. WHILE (x # NIL) & (x # t) DO p := x; x := p.next END;
  545. IF x = t THEN p.next := t.next END
  546. END;
  547. t.next := NIL
  548. END;
  549. Unix.MtxUnlock( timerListMutex )
  550. END Remove;
  551. PROCEDURE Insert( t: Timer );
  552. VAR p, x: Timer;
  553. BEGIN
  554. Unix.MtxLock( timerListMutex );
  555. p := NIL; x := timers;
  556. WHILE (x # NIL) & (x.trigger < t.trigger) DO p := x; x := p.next END;
  557. t.next := x;
  558. IF p = NIL THEN timers := t ELSE p.next := t END;
  559. Unix.MtxUnlock( timerListMutex )
  560. END Insert;
  561. PROCEDURE SetTimeout*( t: Timer; h: EventHandler; ms: LONGINT );
  562. BEGIN
  563. ASSERT( ( t # NIL) & ( h # NIL) );
  564. Remove( t );
  565. IF ms < 1 THEN ms := 1 END;
  566. t.trigger := Machine.ticks + ms; t.handler := h;
  567. Insert( t );
  568. timerActivity.Restart
  569. END SetTimeout;
  570. PROCEDURE SetTimeoutAt*( t: Timer; h: EventHandler; ms: LONGINT );
  571. BEGIN
  572. ASSERT( (t # NIL) & (h # NIL) );
  573. Remove( t );
  574. t.trigger := ms; t.handler := h;
  575. Insert( t );
  576. timerActivity.Restart
  577. END SetTimeoutAt;
  578. PROCEDURE CancelTimeout*( t: Timer );
  579. BEGIN
  580. Remove( t )
  581. END CancelTimeout;
  582. (*-------------------- Garbage Collection ------------------------------------*)
  583. PROCEDURE GetContext( ctxt: Unix.Ucontext );
  584. VAR t: Process; bp: ADDRESS;
  585. BEGIN
  586. t := CurrentProcess();
  587. Unix.CopyContext( ctxt.mc, t.context );
  588. END GetContext;
  589. PROCEDURE SuspendActivities;
  590. VAR t,me: Process; res: LONGINT;
  591. BEGIN
  592. me := CurrentProcess();
  593. t := root;
  594. WHILE t # NIL DO
  595. IF t # me THEN
  596. (* Trace.String( "suspend " ); Trace.Hex( t.id, 2 ); Trace.Ln; *)
  597. Unix.ThrSuspend( t.threadId, t.mode = Running );
  598. END;
  599. t := t.nextProcess
  600. END;
  601. END SuspendActivities;
  602. PROCEDURE ResumeActivities;
  603. VAR t, me: Process;
  604. BEGIN
  605. me := CurrentProcess();
  606. t := root;
  607. WHILE t # NIL DO
  608. IF (t # me) THEN
  609. (* Trace.String( "resume " ); Trace.Hex( t.id, 2 ); Trace.Ln; *)
  610. Unix.ThrResume( t.threadId );
  611. END;
  612. t := t.nextProcess
  613. END;
  614. END ResumeActivities;
  615. (*! GCLoop gets called as last procedure in BootConsole (main thread).
  616. The stack of the main thread is not limited by the boot parameter 'StackSize' !!
  617. *)
  618. PROCEDURE GCLoop*; (* Timer and GC activity *)
  619. BEGIN
  620. LOOP Unix.ThrSleep( 10 ) END; (* in Solaris the main thread must not terminate !! *)
  621. (* RETURN; *)
  622. END GCLoop;
  623. PROCEDURE CurrentProcessTime*(): HUGEINT;
  624. BEGIN
  625. RETURN Machine.GetTimer()
  626. END CurrentProcessTime;
  627. PROCEDURE TimerFrequency*(): HUGEINT;
  628. BEGIN
  629. RETURN Machine.mhz * 1000000
  630. END TimerFrequency;
  631. (*----------------------------- initialization ----------------------------------*)
  632. PROCEDURE StartTimerActivity;
  633. BEGIN
  634. timerListMutex := Unix.MtxInit(0); timers := NIL;
  635. NEW( timerActivity );
  636. END StartTimerActivity;
  637. PROCEDURE GetStacksize;
  638. VAR str: ARRAY 32 OF CHAR; i: LONGINT;
  639. BEGIN
  640. Machine.GetConfig( "StackSize", str );
  641. IF str = "" THEN stacksize := DefaultStacksize
  642. ELSE
  643. i := 0; stacksize := Machine.StrToInt( i, str );
  644. stacksize := stacksize * 1024;
  645. END;
  646. IF Glue.debug # {} THEN
  647. Trace.String( "Stacksize of active objects = " );
  648. Trace.Int( stacksize DIV 1024, 0 ); Trace.StringLn( "K" )
  649. END;
  650. END GetStacksize;
  651. PROCEDURE Convert;
  652. VAR p: Process;
  653. BEGIN
  654. (* make current thread the first active object *)
  655. NEW( p, NIL, NIL, 0, {}, 0 );
  656. END Convert;
  657. PROCEDURE Init;
  658. BEGIN
  659. Unix.suspendHandler := GetContext;
  660. createProcess := Unix.MtxInit( 0 ); processList := Unix.MtxInit( 0 );
  661. startProcess := Unix.MtxInit(0); childrunning := Unix.ConInit(0);
  662. lockMutex := Unix.MtxInit(0);
  663. GetStacksize;
  664. Convert;
  665. NEW( clock ); StartTimerActivity;
  666. NEW( finalizerCaller );
  667. Heaps.gcStatus := GCStatusFactory()
  668. END Init;
  669. PROCEDURE GCStatusFactory(): Heaps.GCStatus;
  670. VAR gcStatusExt : GCStatusExt;
  671. BEGIN
  672. ASSERT( Heaps.gcStatus = NIL );
  673. NEW( gcStatusExt );
  674. RETURN gcStatusExt
  675. END GCStatusFactory;
  676. BEGIN
  677. Init;
  678. END Objects.