Generic.Unix.Objects.Mod 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  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. BEGIN
  230. SELF.obj := obj; condition := NIL; continue := Unix.NewCond( );
  231. flags := fl;
  232. priority := prio;
  233. nextProcess := NIL;
  234. IF root # NIL THEN
  235. newProcess := SELF;
  236. ASSERT( bodyProc # NIL );
  237. body := bodyProc;
  238. Unix.MtxLock( startProcess );
  239. threadId := Unix.ThrStart( BodyStarter, stacksize );
  240. Unix.CondWait( childrunning, startProcess );
  241. Unix.MtxUnlock( startProcess );
  242. RegisterFinalizer( SELF, FinalizeProcess );
  243. ELSE
  244. (* first process *)
  245. stackBottom := Glue.stackBottom;
  246. threadId := Unix.ThrThis( );
  247. id := 0; nextPID := 1;
  248. root := SELF;
  249. mode := Running;
  250. END;
  251. END Initialize;
  252. END Process;
  253. GCStatusExt = OBJECT (Heaps.GCStatus)
  254. (* called from Heaps.InvokeGC, i.e. this is a hidden upcall. However, it is necessary to take the Machine.Objects
  255. lock here since writing the set of variables here must not be interrupted, i.e. atomic writing of the set of variables
  256. is absolutely necessary. They system may hang if the lock is not taken. *)
  257. PROCEDURE SetgcOngoing( value: BOOLEAN );
  258. VAR cur: Process;
  259. BEGIN (* serialize writers *)
  260. cur := CurrentProcess();
  261. IF value THEN
  262. Machine.Acquire( Machine.Objects );
  263. Machine.Acquire( Machine.Heaps );
  264. cur.context.r_sp := Machine.CurrentSP();
  265. cur.context.r_bp := Machine.CurrentBP();
  266. cur.context.r_pc := ADDRESS OF GCLoop;
  267. SuspendActivities;
  268. Heaps.CollectGarbage( Modules.root );
  269. Machine.Release( Machine.Heaps );
  270. Machine.Release( Machine.Objects );
  271. ResumeActivities;
  272. finalizerCaller.Activate;
  273. END;
  274. END SetgcOngoing;
  275. END GCStatusExt;
  276. PROCEDURE BodyStarter;
  277. VAR p{UNTRACED}: Process; res: LONGINT; prevBP: ADDRESS;
  278. BEGIN
  279. Unix.MtxLock( startProcess );
  280. p := newProcess; newProcess := NIL;
  281. p.id := nextPID; INC( nextPID );
  282. p.stackBottom := Machine.CurrentBP( );
  283. S.GET( p.stackBottom, prevBP );
  284. S.PUT( prevBP, S.VAL( ADDRESS, 0 ) ); (* for terminating Reflection.StackTraceBack *)
  285. Unix.MtxLock( processList );
  286. p.nextProcess := root; root := p;
  287. Unix.MtxUnlock( processList );
  288. Unix.CondSignal( childrunning );
  289. Unix.MtxUnlock( startProcess );
  290. p.SetPriority( p.priority );
  291. IF Restart IN p.flags THEN
  292. res := Unix.sigsetjmp( ADDRESSOF( p.state0[0] ), 1 );
  293. END;
  294. p.mode := Running;
  295. p.body( p.obj );
  296. p.mode := Terminated;
  297. Exit
  298. END BodyStarter;
  299. (*--------------------- create, lock, await, unlock -------------------------*)
  300. (* initialize the ObjectHeader, requires lockMutex temporarily *)
  301. PROCEDURE InitProtHeader( hdr: ObjectHeader);
  302. VAR lock: LockT;
  303. BEGIN
  304. (* we cannot hold the lockMute here because allocation can trigger the GC that requires the lock when activating the finalizers *)
  305. NEW(lock);
  306. Unix.MtxLock(lockMutex);
  307. IF hdr.lock = NIL THEN
  308. hdr.lock := lock;
  309. lock.mtx := Unix.NewMtx( ); lock.enter := Unix.NewCond( ); hdr.lockedBy := NIL;
  310. END;
  311. Unix.MtxUnlock(lockMutex);
  312. END InitProtHeader;
  313. PROCEDURE CreateProcess*( body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject );
  314. VAR p: Process; hdr: ObjectHeader;
  315. BEGIN
  316. Unix.MtxLock( createProcess );
  317. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  318. InitProtHeader( hdr );
  319. IF priority = 0 THEN priority := Normal END;
  320. NEW( p, obj, body, priority, flags, stacksize ) ; (* execute BodyStarter as new (posix or solaris) thread *)
  321. Unix.MtxUnlock( createProcess );
  322. RegisterFinalizer( obj, FinalizeActiveObj )
  323. END CreateProcess;
  324. PROCEDURE Lock*( obj: ProtectedObject; exclusive: BOOLEAN );
  325. VAR hdr: ObjectHeader; p: Process; lock: LockT;
  326. BEGIN
  327. ASSERT( exclusive ); (* shared not implemented yet *)
  328. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  329. p := CurrentProcess();
  330. p.context.r_sp := Machine.CurrentSP( );
  331. p.context.r_bp := Machine.CurrentBP( );
  332. p.mode := AwaitingLock;
  333. (*! we might want to replace the lock mutex by a lock free construct *)
  334. IF hdr.lock = NIL THEN InitProtHeader( hdr ) END;
  335. lock := S.VAL(LockT, hdr.lock);
  336. p.mode := Locked;
  337. Unix.MtxLock( lock.mtx );
  338. WHILE hdr.lockedBy # NIL DO
  339. (* wait until threads with complied AWAIT conditions have left the monitor *)
  340. p.mode := AwaitingLock;
  341. Unix.CondWait( lock.enter, lock.mtx );
  342. END;
  343. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  344. END Lock;
  345. PROCEDURE Await*( cond: Condition; slink: ADDRESS; obj: ProtectedObject; flags: SET );
  346. VAR hdr: ObjectHeader; p, c: Process; lock: LockT;
  347. BEGIN
  348. IF 1 IN flags THEN (* compiler did not generate IF *)
  349. IF cond( slink ) THEN (* condition already true *) RETURN END
  350. END;
  351. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  352. lock := S.VAL(LockT, hdr.lock);
  353. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  354. p := CurrentProcess(); p.succ := NIL; p.condition := cond; p.condFP := slink;
  355. p.waitingOn := obj; p.mode := AwaitingCond;
  356. Put( hdr.awaitingCond, p );
  357. hdr.lockedBy := c;
  358. IF c # NIL THEN Unix.CondSignal( c.continue ) ELSE Unix.CondSignal( lock.enter ) END;
  359. p.context.r_sp := Machine.CurrentSP( );
  360. p.context.r_bp := Machine.CurrentBP( );
  361. Unix.CondWait( p.continue, lock.mtx );
  362. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  363. END Await;
  364. PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
  365. VAR hdr: ObjectHeader; c: Process; lock: LockT;
  366. BEGIN
  367. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  368. lock := S.VAL(LockT,hdr.lock);
  369. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  370. hdr.lockedBy := c;
  371. IF c # NIL THEN Unix.CondSignal( c.continue ) ELSE Unix.CondSignal( lock.enter ) END;
  372. Unix.MtxUnlock( lock.mtx );
  373. END Unlock;
  374. PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
  375. VAR first, cand: Process;
  376. BEGIN
  377. Get( q, first );
  378. IF first.condition( first.condFP ) THEN RETURN first ELSE Put( q, first ) END;
  379. WHILE q.head # first DO
  380. Get( q, cand );
  381. IF cand.condition( cand.condFP ) THEN RETURN cand ELSE Put( q, cand ) END;
  382. END;
  383. RETURN NIL
  384. END FindCondition;
  385. PROCEDURE Get( VAR queue: ProcessQueue; VAR new: Process );
  386. VAR t: Process;
  387. BEGIN
  388. t := queue.head(Process);
  389. IF t # NIL THEN
  390. IF t = queue.tail THEN queue.head := NIL; queue.tail := NIL
  391. ELSE queue.head := t.succ; t.succ := NIL
  392. END
  393. END;
  394. new := t
  395. END Get;
  396. PROCEDURE Put( VAR queue: ProcessQueue; t: Process );
  397. BEGIN
  398. IF queue.head = NIL THEN queue.head := t ELSE queue.tail(Process).succ := t END;
  399. queue.tail := t
  400. END Put;
  401. (*-------------------------------------------------------------------------*)
  402. PROCEDURE Terminate*;
  403. BEGIN
  404. Exit
  405. END Terminate;
  406. PROCEDURE TerminateThis*( p: Process; unbreakable: BOOLEAN );
  407. BEGIN
  408. p.mode := Terminated;
  409. p.Cancel
  410. END TerminateThis;
  411. PROCEDURE SetPriority*( pri: LONGINT ); (* Set the current process' priority. *)
  412. VAR me: Process;
  413. BEGIN
  414. me := CurrentProcess();
  415. me.SetPriority( pri )
  416. END SetPriority;
  417. PROCEDURE Sleep*( ms: LONGINT );
  418. BEGIN
  419. Unix.ThrSleep( ms )
  420. END Sleep;
  421. PROCEDURE Yield*; (* Relinquish control. *)
  422. BEGIN
  423. Unix.ThrYield( );
  424. END Yield;
  425. (* Return current process. (DEPRECATED, use ActiveObject) *)
  426. PROCEDURE CurrentProcess*( ): Process;
  427. VAR me: Unix.Thread_t; p: Process;
  428. BEGIN
  429. me := Unix.ThrThis( );
  430. Unix.MtxLock( processList );
  431. p := root;
  432. WHILE (p # NIL) & (p.threadId # me) DO p := p.nextProcess END;
  433. Unix.MtxUnlock( processList );
  434. RETURN p
  435. END CurrentProcess;
  436. PROCEDURE CurrentProcess0( ): Process;
  437. VAR me: Unix.Thread_t; p: Process;
  438. BEGIN
  439. me := Unix.ThrThis( );
  440. p := root;
  441. WHILE (p # NIL) & (p.threadId # me) DO p := p.nextProcess END;
  442. RETURN p
  443. END CurrentProcess0;
  444. (* Return the active object currently executing. *)
  445. PROCEDURE ActiveObject*( ): ANY;
  446. VAR p: Process;
  447. BEGIN
  448. p := CurrentProcess();
  449. RETURN p.obj
  450. END ActiveObject;
  451. (* Return stack bottom of process. For compatibility WinAos/UnixAos/NativeAos *)
  452. PROCEDURE GetStackBottom*(p: Process): ADDRESS;
  453. BEGIN
  454. RETURN p.stackBottom
  455. END GetStackBottom;
  456. PROCEDURE GetProcessID*( ): LONGINT;
  457. VAR p: Process;
  458. BEGIN
  459. p := CurrentProcess();
  460. RETURN p.id;
  461. END GetProcessID;
  462. PROCEDURE GetCpuCycles*( process : Process; VAR cpuCycles: CpuCyclesArray; all: BOOLEAN );
  463. VAR i: LONGINT;
  464. BEGIN
  465. ASSERT( process # NIL );
  466. FOR i := 0 TO Machine.MaxCPU-1 DO cpuCycles[i] := 0 END;
  467. END GetCpuCycles;
  468. (*-----------------------------------------------------------------------*)
  469. PROCEDURE min( a, b: LONGINT ): LONGINT;
  470. BEGIN
  471. IF a <= b THEN RETURN a ELSE RETURN b END
  472. END min;
  473. PROCEDURE max( a, b: LONGINT ): LONGINT;
  474. BEGIN
  475. IF a >= b THEN RETURN a ELSE RETURN b END
  476. END max;
  477. PROCEDURE RegisterFinalizer( obj: ANY; fin: Heaps.Finalizer );
  478. VAR n: Heaps.FinalizerNode;
  479. BEGIN
  480. NEW( n ); n.finalizer := fin; Heaps.AddFinalizer( obj, n );
  481. END RegisterFinalizer;
  482. PROCEDURE FinalizeActiveObj( obj: ANY );
  483. VAR p: Process;
  484. BEGIN
  485. Unix.MtxLock( processList );
  486. p := root;
  487. WHILE (p # NIL) & (p.obj # obj) DO p := p.nextProcess END;
  488. Unix.MtxUnlock( processList );
  489. IF (p # NIL) & (p.obj = obj) THEN
  490. p.mode := Terminated;
  491. Unix.CondDestroy( p.continue ); p.continue := 0;
  492. FinalizeProtObject( obj );
  493. p.Cancel
  494. END;
  495. END FinalizeActiveObj;
  496. PROCEDURE FinalizeProtObject( obj: ANY );
  497. VAR hdr: ObjectHeader; lock: LockT;
  498. BEGIN
  499. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  500. IF hdr.lock # NIL THEN
  501. lock := S.VAL(LockT, hdr.lock);
  502. Unix.MtxDestroy( lock.mtx ); lock.mtx := 0
  503. END
  504. END FinalizeProtObject;
  505. PROCEDURE FinalizeProcess( obj: ANY );
  506. VAR p: Process;
  507. BEGIN
  508. p := obj(Process);
  509. IF p.continue # 0 THEN
  510. Unix.CondDestroy( p.continue ); p.continue := 0
  511. END
  512. END FinalizeProcess;
  513. (* Terminate calling thread. *)
  514. PROCEDURE Exit;
  515. VAR prev, p, me: Process;
  516. BEGIN
  517. me := CurrentProcess();
  518. me.mode := Terminated;
  519. Unix.MtxLock( processList );
  520. prev := NIL; p := root;
  521. WHILE (p # NIL ) & (p # me) DO prev := p; p := p.nextProcess END;
  522. IF p = me THEN
  523. IF prev = NIL THEN root := p.nextProcess ELSE prev.nextProcess := p.nextProcess END;
  524. END;
  525. Unix.MtxUnlock( processList );
  526. Unix.ThrExit( );
  527. END Exit;
  528. PROCEDURE ExitTrap*;
  529. VAR p: Process;
  530. BEGIN
  531. p := CurrentProcess();
  532. (* restart the object body if it was given the SAFE flag *)
  533. IF Restart IN p.flags THEN
  534. Unix.siglongjmp( ADDRESSOF( p.state0[0] ), 1 )
  535. END;
  536. Exit
  537. END ExitTrap;
  538. (*---------------------------- Timer --------------------------------*)
  539. PROCEDURE Remove( t: Timer ); (* remove timer from list of active timers *)
  540. VAR p, x: Timer;
  541. BEGIN
  542. Unix.MtxLock( timerListMutex );
  543. t.trigger := 0; t.handler := NIL;
  544. IF timers # NIL THEN
  545. IF t = timers THEN
  546. timers := t.next
  547. ELSE
  548. p := timers; x := p.next;
  549. WHILE (x # NIL) & (x # t) DO p := x; x := p.next END;
  550. IF x = t THEN p.next := t.next END
  551. END;
  552. t.next := NIL
  553. END;
  554. Unix.MtxUnlock( timerListMutex )
  555. END Remove;
  556. PROCEDURE Insert( t: Timer );
  557. VAR p, x: Timer;
  558. BEGIN
  559. Unix.MtxLock( timerListMutex );
  560. p := NIL; x := timers;
  561. WHILE (x # NIL) & (x.trigger < t.trigger) DO p := x; x := p.next END;
  562. t.next := x;
  563. IF p = NIL THEN timers := t ELSE p.next := t END;
  564. Unix.MtxUnlock( timerListMutex )
  565. END Insert;
  566. PROCEDURE SetTimeout*( t: Timer; h: EventHandler; ms: LONGINT );
  567. BEGIN
  568. ASSERT( ( t # NIL) & ( h # NIL) );
  569. Remove( t );
  570. IF ms < 1 THEN ms := 1 END;
  571. t.trigger := Machine.ticks + ms; t.handler := h;
  572. Insert( t );
  573. timerActivity.Restart
  574. END SetTimeout;
  575. PROCEDURE SetTimeoutAt*( t: Timer; h: EventHandler; ms: LONGINT );
  576. BEGIN
  577. ASSERT( (t # NIL) & (h # NIL) );
  578. Remove( t );
  579. t.trigger := ms; t.handler := h;
  580. Insert( t );
  581. timerActivity.Restart
  582. END SetTimeoutAt;
  583. PROCEDURE CancelTimeout*( t: Timer );
  584. BEGIN
  585. Remove( t )
  586. END CancelTimeout;
  587. (*-------------------- Garbage Collection ------------------------------------*)
  588. PROCEDURE GetContext( ctxt: Unix.Ucontext );
  589. VAR t: Process;
  590. BEGIN
  591. (* use CurrentProcess0 here instead of CurrentProcess here in order to
  592. avoid a apossible deadlock *)
  593. t := CurrentProcess0();
  594. Unix.CopyContext( ctxt.mc, t.context );
  595. END GetContext;
  596. PROCEDURE SuspendActivities;
  597. VAR t, me: Process;
  598. BEGIN
  599. me := CurrentProcess();
  600. t := root;
  601. WHILE t # NIL DO
  602. IF t # me THEN
  603. Unix.ThrSuspend( t.threadId, t.mode = Running );
  604. END;
  605. t := t.nextProcess
  606. END;
  607. END SuspendActivities;
  608. PROCEDURE ResumeActivities;
  609. VAR t, me: Process;
  610. BEGIN
  611. me := CurrentProcess();
  612. t := root;
  613. WHILE t # NIL DO
  614. IF (t # me) THEN
  615. Unix.ThrResume( t.threadId );
  616. END;
  617. t := t.nextProcess
  618. END;
  619. END ResumeActivities;
  620. PROCEDURE GCLoop*; (* Timer and GC activity *)
  621. BEGIN
  622. (*
  623. If using BootConsole keep main thread running.
  624. If the thread is blocked by a mutex (MainThreadSleep)
  625. the signals SIGHUP, SIGINT and SIGQUIT don't branch into SignalHandler
  626. but terminate A2 (at least in Solaris).
  627. *)
  628. LOOP Sleep( 100 ) END
  629. END GCLoop;
  630. PROCEDURE CurrentProcessTime*(): HUGEINT;
  631. BEGIN
  632. RETURN Machine.GetTimer()
  633. END CurrentProcessTime;
  634. PROCEDURE TimerFrequency*(): HUGEINT;
  635. BEGIN
  636. RETURN Machine.mhz * 1000000
  637. END TimerFrequency;
  638. PROCEDURE LeaveA2;
  639. VAR cur: Process; bp, n: ADDRESS;
  640. BEGIN
  641. IF clock = NIL THEN RETURN END;
  642. cur := CurrentProcess();
  643. IF cur # NIL THEN
  644. bp := Machine.CurrentBP();
  645. S.GET( bp, n );
  646. IF ODD( n ) THEN S.GET( bp + SIZEOF( ADDRESS ), bp ) ELSE bp := n END;
  647. cur.context.r_bp := bp;
  648. END;
  649. END LeaveA2;
  650. PROCEDURE ReenterA2;
  651. VAR cur: Process;
  652. BEGIN
  653. IF clock = NIL THEN RETURN END;
  654. cur := CurrentProcess();
  655. IF cur # NIL THEN
  656. cur.context.r_bp := 0;
  657. END;
  658. END ReenterA2;
  659. (*----------------------------- initialization ----------------------------------*)
  660. PROCEDURE StartTimerActivity;
  661. BEGIN
  662. timerListMutex := Unix.NewMtx( ); timers := NIL;
  663. NEW( timerActivity );
  664. END StartTimerActivity;
  665. PROCEDURE GetStacksize;
  666. VAR str: ARRAY 32 OF CHAR; i: LONGINT;
  667. BEGIN
  668. Machine.GetConfig( "StackSize", str );
  669. IF str = "" THEN stacksize := DefaultStacksize
  670. ELSE
  671. i := 0; stacksize := Machine.StrToInt( i, str );
  672. stacksize := stacksize * 1024;
  673. END;
  674. IF Glue.debug # {} THEN
  675. Trace.String( "Stacksize of active objects = " );
  676. Trace.Int( stacksize DIV 1024, 0 ); Trace.StringLn( "K" )
  677. END;
  678. END GetStacksize;
  679. PROCEDURE Convert;
  680. VAR p: Process;
  681. BEGIN
  682. (* make current thread the first active object *)
  683. NEW( p, NIL, NIL, 0, {}, 0 );
  684. END Convert;
  685. PROCEDURE Init;
  686. BEGIN
  687. Unix.suspendHandler := GetContext;
  688. createProcess := Unix.NewMtx( ); processList := Unix.NewMtx( );
  689. startProcess := Unix.NewMtx( ); childrunning := Unix.NewCond( );
  690. lockMutex := Unix.NewMtx( );
  691. GetStacksize;
  692. Convert;
  693. NEW( clock ); StartTimerActivity;
  694. NEW( finalizerCaller );
  695. Heaps.gcStatus := GCStatusFactory()
  696. END Init;
  697. TYPE
  698. MainThread = OBJECT
  699. VAR exit: BOOLEAN;
  700. PROCEDURE & Init;
  701. BEGIN
  702. exit := FALSE;
  703. END Init;
  704. PROCEDURE Await();
  705. BEGIN {EXCLUSIVE}
  706. AWAIT( exit );
  707. END Await;
  708. END MainThread;
  709. VAR main: MainThread;
  710. PROCEDURE MainThreadSleep;
  711. BEGIN
  712. NEW( main );
  713. main.Await( );
  714. Unix.exit( 0 );
  715. END MainThreadSleep;
  716. PROCEDURE {FINAL} Final;
  717. BEGIN
  718. MainThreadSleep;
  719. END Final;
  720. PROCEDURE GCStatusFactory(): Heaps.GCStatus;
  721. VAR gcStatusExt : GCStatusExt;
  722. BEGIN
  723. ASSERT( Heaps.gcStatus = NIL );
  724. NEW( gcStatusExt );
  725. RETURN gcStatusExt
  726. END GCStatusFactory;
  727. VAR
  728. (* for compatibility and later extension *)
  729. TraceProcessHook*: PROCEDURE (prcoess: Process; pc, bp: ADDRESS; stacklow, stackhigh: ADDRESS);
  730. BEGIN
  731. TraceProcessHook := NIL;
  732. Init;
  733. END Objects.