Generic.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. AddrSize = SIZEOF( ADDRESS )
  25. VAR
  26. (* timer *)
  27. timerActivity : TimerActivity;
  28. timers : Timer;
  29. timerListMutex : Unix.Mutex_t;
  30. (* processes *)
  31. mainProcess : Process; (* runs the GC *)
  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. childrunning : Unix.Condition_t;
  38. newProcess: Process;
  39. nextPID: LONGINT;
  40. (* garbage colletion *)
  41. gcFinished: Unix.Condition_t; igc: Unix.Mutex_t;
  42. collect: BOOLEAN;
  43. finalizerCaller : FinalizerCaller;
  44. finCaller : Process;
  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. FinalizedCollection* = OBJECT (* base type for collection, extended in Kernel.Mod *)
  93. PROCEDURE RemoveAll*(obj: ANY); (** abstract *)
  94. BEGIN HALT(301) END RemoveAll;
  95. END FinalizedCollection;
  96. FinalizerNode* = POINTER TO RECORD (Heaps.FinalizerNode)
  97. c*: FinalizedCollection (* base type for collection containing object *)
  98. END;
  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. finCaller := CurrentProcess( ); 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 IS FinalizerNode THEN
  115. n(FinalizerNode).c.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. Machine.ReleaseGC
  122. END
  123. END FinalizerCaller;
  124. Body = PROCEDURE ( self: ProtectedObject );
  125. Condition = PROCEDURE ( slink: ADDRESS ): BOOLEAN;
  126. Process* = OBJECT (Heaps.ProcessLink)
  127. VAR
  128. threadId- : Unix.Thread_t;
  129. nextProcess- : Process; (* next in list of all processes *)
  130. stackBottom - : ADDRESS;
  131. context*: Unix.McontextDesc;
  132. id- : LONGINT;
  133. body : Body;
  134. mode- : LONGINT;
  135. flags- : SET;
  136. priority- : LONGINT; (* only effective if Aos is running SUID root *)
  137. succ : Process; (* in ProcessQueue *)
  138. obj- : ProtectedObject; (* associated active object *)
  139. condition- : Condition; (* awaited process' condition *)
  140. condFP- : ADDRESS; (* awaited process' condition's context *)
  141. continue : Unix.Condition_t; (* gets signaled when condition yields true *)
  142. waitingOn- : ProtectedObject;
  143. procID- : LONGINT; (* processor ID where running, not used in UnixAos *)
  144. state- : Machine.State; (*! not used in UnixAos! *)
  145. state0 : ARRAY 2048 OF CHAR; (* thread state at body start, used for restart after trap *)
  146. PROCEDURE FindRoots*;
  147. VAR sp, ptr, bp, n, a0, a1, adr: ADDRESS; desc: Modules.ProcedureDescPointer; i: LONGINT; p {UNTRACED}: ANY;
  148. me: Process;
  149. BEGIN
  150. IF mode # Terminated THEN
  151. IF SELF = CurrentProcess() THEN
  152. context.r_sp := Machine.CurrentSP();
  153. context.r_bp := Machine.CurrentBP();
  154. context.r_pc := ADDRESS OF FindRoots;
  155. END;
  156. sp := context.r_sp; bp := context.r_bp; (*pc := context.r_pc;*)
  157. TRACE(context.r_si, context.r_di, context.r_bp, context.r_sp_x);
  158. TRACE(context.r_bx, context.r_dx, context.r_cx, context.r_ax);
  159. TRACE(context.r_pc, context.r_sp, context.fpc);
  160. TRACE(sp, bp, stackBottom);
  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. TRACE(sp, stackBottom -sp);
  167. Heaps.RegisterCandidates( sp, stackBottom - sp );
  168. END;
  169. ELSIF Heaps.GCType = Heaps.MetaDataForStackGC THEN
  170. IF bp < stackBottom THEN
  171. WHILE (bp # Heaps.NilVal) & (bp > 1024) & (bp < stackBottom) DO (* do not test for bp >= sp: could be wrong temporarily! *)
  172. TRACE(bp);
  173. S.GET(bp, n);
  174. TRACE(n);
  175. IF ODD(n) THEN (* procedure descriptor at bp *)
  176. IF n > 1024 THEN
  177. desc := S.VAL(Modules.ProcedureDescPointer, n-1);
  178. IF desc # NIL THEN
  179. a0 := ADDRESSOF(desc.offsets);
  180. a1 := S.VAL(ADDRESS, desc.offsets);
  181. ASSERT(a0+SIZEOF(ADDRESS)=a1,54321);
  182. FOR i := 0 TO LEN(desc.offsets)-1 DO
  183. adr := bp + desc.offsets[i]; (* pointer at offset *)
  184. S.GET(adr, p); (* load pointer *)
  185. IF p # NIL THEN
  186. Heaps.Mark(p);
  187. END;
  188. END;
  189. END;
  190. END;
  191. S.GET(bp + SIZEOF(ADDRESS), bp);
  192. ELSE (* classical stack frame *)
  193. bp := n;
  194. END;
  195. TRACE(bp);
  196. END;
  197. ASSERT((bp = stackBottom) OR (bp<1024) ,12345);
  198. END;
  199. END;
  200. (*
  201. sp := context.r_sp;
  202. WHILE sp < stackBottom DO
  203. S.GET( sp, ptr );
  204. IF (ptr # 0) & (ptr MOD 8 = 0) THEN Heaps.Candidate( ptr ) END;
  205. INC( sp, AddrSize )
  206. END;
  207. *)
  208. END;
  209. Heaps.Mark( nextProcess )
  210. END FindRoots;
  211. PROCEDURE Cancel;
  212. VAR pt, t: Process; kt: Unix.Thread_t;
  213. BEGIN
  214. IF SELF = CurrentProcess() THEN Exit
  215. ELSE
  216. Machine.Acquire( Machine.X11 ); (* let the thread to be killed first finish its last I/O, if any *)
  217. Unix.MtxLock( processList );
  218. pt := NIL; t := root; kt := 0;
  219. WHILE (t # NIL ) & (t # SELF) DO pt := t; t := t.nextProcess END;
  220. IF t = SELF THEN
  221. kt := threadId;
  222. IF pt = NIL THEN root := t.nextProcess ELSE pt.nextProcess := t.nextProcess END;
  223. END;
  224. Unix.MtxUnlock( processList );
  225. IF kt # 0 THEN Unix.ThrKill( kt ) END;
  226. Machine.Release( Machine.X11 );
  227. END
  228. END Cancel;
  229. PROCEDURE GetPriority( ): LONGINT;
  230. BEGIN
  231. RETURN Unix.ThrGetPriority( threadId )
  232. END GetPriority;
  233. PROCEDURE SetPriority( prio: LONGINT );
  234. VAR pr: LONGINT;
  235. BEGIN
  236. pr := max( Machine.prioLow, min( prio, Machine.prioHigh ) );
  237. Unix.ThrSetPriority( threadId, pr ); (* works only if SUID root *)
  238. priority := GetPriority( )
  239. END SetPriority;
  240. PROCEDURE & Initialize( obj: ProtectedObject; bodyProc: Body; prio: LONGINT; fl: SET; stacksize: LONGINT);
  241. VAR thr: Unix.Thread_t;
  242. BEGIN
  243. SELF.obj := obj; condition := NIL; continue := Unix.ConInit(0);
  244. flags := fl;
  245. priority := prio;
  246. nextProcess := NIL;
  247. IF root # NIL THEN
  248. newProcess := SELF;
  249. ASSERT( bodyProc # NIL );
  250. body := bodyProc;
  251. Unix.MtxLock( startProcess );
  252. thr := Unix.ThrStart( BodyStarter, stacksize );
  253. Unix.ConWait( childrunning, startProcess );
  254. Unix.MtxUnlock( startProcess );
  255. RegisterFinalizer( SELF, FinalizeProcess );
  256. ELSE
  257. (* first process *)
  258. stackBottom := Glue.stackBottom;
  259. threadId := Unix.ThrThis(0);
  260. id := 0; nextPID := 1;
  261. root := SELF;
  262. mainProcess := SELF;
  263. mode := Running;
  264. END;
  265. END Initialize;
  266. END Process;
  267. GCStatusExt = OBJECT(Heaps.GCStatus)
  268. (* called from Heaps.InvokeGC, i.e. this is a hidden upcall. However, it is necessary to take the Machine.Objects lock here since writing
  269. 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
  270. if the lock is not taken. *)
  271. PROCEDURE SetgcOngoing(value: BOOLEAN);
  272. VAR p: Heaps.ProcessLink; cur, r: Process; res: LONGINT; num: LONGINT; time: LONGINT;
  273. BEGIN (* serialize writers *)
  274. cur:= CurrentProcess();
  275. IF value THEN
  276. (*collect := TRUE;
  277. TRACE(collect);
  278. collect := FALSE;
  279. *)
  280. Machine.Acquire(Machine.Objects);
  281. Machine.Acquire( Machine.Heaps );
  282. cur.context.r_sp := Machine.CurrentSP();
  283. cur.context.r_bp := Machine.CurrentBP();
  284. cur.context.r_pc := ADDRESS OF GCLoop;
  285. TRACE(cur, cur.threadId, cur.context.r_sp, cur.context.r_bp, cur.context.r_pc);
  286. SuspendActivities;
  287. Heaps.CollectGarbage( Modules.root );
  288. Machine.Release( Machine.Heaps );
  289. Machine.Release(Machine.Objects);
  290. ResumeActivities;
  291. finalizerCaller.Activate;
  292. END;
  293. END SetgcOngoing;
  294. END GCStatusExt;
  295. PROCEDURE BodyStarter;
  296. VAR p{UNTRACED}: Process; res: LONGINT; prevBP: ADDRESS; i: LONGINT;
  297. BEGIN
  298. Unix.MtxLock( startProcess );
  299. p := newProcess; newProcess := NIL;
  300. p.threadId := Unix.ThrThis(0);
  301. p.id := nextPID; INC( nextPID );
  302. p.stackBottom := Machine.CurrentBP( );
  303. S.GET( p.stackBottom, prevBP );
  304. S.PUT( prevBP, S.VAL( ADDRESS, 0 ) ); (* for terminating Reflection.StackTraceBack *)
  305. Unix.MtxLock( processList );
  306. p.nextProcess := root; root := p;
  307. Unix.MtxUnlock( processList );
  308. Unix.ConSignal( childrunning );
  309. Unix.MtxUnlock( startProcess );
  310. p.SetPriority( p.priority );
  311. (*!
  312. IF Restart IN p.flags THEN
  313. res := Unix.sigsetjmp( ADDRESSOF( p.state0[0] ), 1 );
  314. END;
  315. *)
  316. p.mode := Running;
  317. p.body( p.obj );
  318. p.mode := Terminated;
  319. Exit
  320. END BodyStarter;
  321. (*--------------------- create, lock, await, unlock -------------------------*)
  322. PROCEDURE InitProtHeader( hdr: ObjectHeader );
  323. VAR lock: LockT;
  324. BEGIN
  325. NEW(lock);
  326. hdr.lock := lock;
  327. lock.mtx := Unix.MtxInit( 0 ); lock.enter := Unix.ConInit( 0 ); hdr.lockedBy := NIL;
  328. END InitProtHeader;
  329. PROCEDURE CreateProcess*( body: Body; priority: LONGINT; flags: SET; obj: ProtectedObject );
  330. VAR p: Process; hdr: ObjectHeader;
  331. BEGIN
  332. Unix.MtxLock( createProcess );
  333. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); InitProtHeader( hdr );
  334. IF priority = 0 THEN priority := Normal END;
  335. NEW( p, obj, body, priority, flags, stacksize ) ; (* execute BodyStarter as new (posix or solaris) thread *)
  336. Unix.MtxUnlock( createProcess );
  337. RegisterFinalizer( obj, FinalizeActiveObj )
  338. END CreateProcess;
  339. PROCEDURE Lock*( obj: ProtectedObject; exclusive: BOOLEAN );
  340. VAR hdr: ObjectHeader; p: Process; lock: LockT;
  341. BEGIN
  342. ASSERT( exclusive ); (* shared not implemented yet *)
  343. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr );
  344. p := CurrentProcess();
  345. p.mode := AwaitingLock;
  346. IF hdr.lock = NIL THEN InitProtHeader( hdr ) END;
  347. lock := S.VAL(LockT, hdr.lock);
  348. Unix.MtxLock( lock.mtx );
  349. WHILE hdr.lockedBy # NIL DO
  350. (* wait until threads with complied AWAIT conditions have left the monitor *)
  351. Unix.ConWait( lock.enter, lock.mtx );
  352. END;
  353. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  354. END Lock;
  355. PROCEDURE Await*( cond: Condition; slink: ADDRESS; obj: ProtectedObject; flags: SET );
  356. VAR hdr: ObjectHeader; p, c: Process; lock: LockT;
  357. BEGIN
  358. IF 1 IN flags THEN (* compiler did not generate IF *)
  359. IF cond( slink ) THEN (* condition already true *) RETURN END
  360. END;
  361. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  362. lock := S.VAL(LockT, hdr.lock);
  363. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  364. p := CurrentProcess(); p.succ := NIL; p.condition := cond; p.condFP := slink;
  365. p.waitingOn := obj; p.mode := AwaitingCond;
  366. Put( hdr.awaitingCond, p );
  367. hdr.lockedBy := c;
  368. IF c # NIL THEN Unix.ConSignal( c.continue ) ELSE Unix.ConSignal( lock.enter ) END;
  369. Unix.ConWait( p.continue, lock.mtx );
  370. p.mode := Running; hdr.lockedBy := p; p.waitingOn := NIL
  371. END Await;
  372. PROCEDURE Unlock*( obj: ProtectedObject; dummy: BOOLEAN );
  373. VAR hdr: ObjectHeader; c: Process; lock: LockT;
  374. BEGIN
  375. S.GET( S.VAL( ADDRESS, obj ) + Heaps.HeapBlockOffset, hdr ); c := NIL;
  376. lock := S.VAL(LockT,hdr.lock);
  377. IF hdr.awaitingCond.head # NIL THEN c := FindCondition( hdr.awaitingCond ) END;
  378. hdr.lockedBy := c;
  379. IF c # NIL THEN Unix.ConSignal( c.continue ) ELSE Unix.ConSignal( lock.enter ) END;
  380. Unix.MtxUnlock( lock.mtx );
  381. END Unlock;
  382. PROCEDURE FindCondition( VAR q: ProcessQueue ): Process;
  383. VAR first, cand: Process;
  384. BEGIN
  385. Get( q, first );
  386. IF first.condition( first.condFP ) THEN RETURN first ELSE Put( q, first ) END;
  387. WHILE q.head # first DO
  388. Get( q, cand );
  389. IF cand.condition( cand.condFP ) THEN RETURN cand ELSE Put( q, cand ) END;
  390. END;
  391. RETURN NIL
  392. END FindCondition;
  393. PROCEDURE Get( VAR queue: ProcessQueue; VAR new: Process );
  394. VAR t: Process;
  395. BEGIN
  396. t := queue.head(Process);
  397. IF t # NIL THEN
  398. IF t = queue.tail THEN queue.head := NIL; queue.tail := NIL
  399. ELSE queue.head := t.succ; t.succ := NIL
  400. END
  401. END;
  402. new := t
  403. END Get;
  404. PROCEDURE Put( VAR queue: ProcessQueue; t: Process );
  405. BEGIN
  406. IF queue.head = NIL THEN queue.head := t ELSE queue.tail(Process).succ := t END;
  407. queue.tail := t
  408. END Put;
  409. (*-------------------------------------------------------------------------*)
  410. PROCEDURE Terminate*;
  411. BEGIN
  412. Exit
  413. END Terminate;
  414. PROCEDURE TerminateThis*( p: Process; unbreakable: BOOLEAN );
  415. BEGIN
  416. p.mode := Terminated;
  417. p.Cancel
  418. END TerminateThis;
  419. PROCEDURE SetPriority*( pri: LONGINT ); (* Set the current process' priority. *)
  420. VAR me: Process;
  421. BEGIN
  422. me := CurrentProcess();
  423. me.SetPriority( pri )
  424. END SetPriority;
  425. PROCEDURE Sleep*( ms: LONGINT );
  426. BEGIN
  427. Unix.ThrSleep( ms )
  428. END Sleep;
  429. PROCEDURE Yield*; (* Relinquish control. *)
  430. BEGIN
  431. Unix.ThrYield(0);
  432. END Yield;
  433. (* Return current process. (DEPRECATED, use ActiveObject) *)
  434. PROCEDURE CurrentProcess*( ): Process;
  435. VAR me: Unix.Thread_t; p: Process;
  436. BEGIN
  437. me := Unix.ThrThis(0);
  438. Unix.MtxLock( processList );
  439. p := root;
  440. WHILE (p # NIL) & (p.threadId # me) DO p := p.nextProcess END;
  441. Unix.MtxUnlock( processList );
  442. RETURN p
  443. END CurrentProcess;
  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.ConDestroy( 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.ConDestroy( 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(0);
  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; bp: ADDRESS;
  590. BEGIN
  591. t := CurrentProcess();
  592. TRACE(t, t.threadId);
  593. TRACE(Machine.CurrentBP(), ctxt.mc.r_bp);
  594. Unix.CopyContext(ctxt.mc, t.context);
  595. bp := Machine.CurrentBP();
  596. TRACE(bp);
  597. S.GET(bp+4, bp);
  598. TRACE(bp);
  599. t.context.r_bp := bp;
  600. END GetContext;
  601. PROCEDURE SuspendActivities;
  602. VAR t,me: Process; res: LONGINT;
  603. BEGIN
  604. me := CurrentProcess();
  605. t := root;
  606. WHILE t # NIL DO
  607. IF (t # me) THEN
  608. Unix.ThrSuspend(t.threadId );
  609. END;
  610. t := t.nextProcess
  611. END;
  612. (*
  613. VAR t, me: Process;
  614. BEGIN
  615. t := root;
  616. WHILE t # NIL DO
  617. IF (t # mainProcess) & (t # finCaller) THEN Unix.ThrSuspend( t.threadId ) END;
  618. t := t.nextProcess
  619. END;
  620. *)
  621. END SuspendActivities;
  622. PROCEDURE ResumeActivities;
  623. VAR t, me: Process;
  624. BEGIN
  625. me := CurrentProcess();
  626. t := root;
  627. WHILE t # NIL DO
  628. IF (t # me) (* (t # mainProcess) & (t # finCaller)*) THEN Unix.ThrResume( t.threadId ) END;
  629. t := t.nextProcess
  630. END;
  631. END ResumeActivities;
  632. (*
  633. PROCEDURE InvokeGC;
  634. BEGIN
  635. IF Machine.AcquireGC() THEN (* gets released by FinalizerCaller *)
  636. collect := TRUE;
  637. Unix.ConWait( gcFinished, igc )
  638. END;
  639. END InvokeGC;
  640. *)
  641. (*! GCLoop gets called as last procedure in BootConsole (main thread).
  642. The stack of the main thread is not limited by the boot parameter 'StackSize' !!
  643. *)
  644. PROCEDURE GCLoop*; (* Timer and GC activity *)
  645. VAR cur: Process;
  646. BEGIN
  647. RETURN;
  648. (*
  649. cur:= CurrentProcess();
  650. SetPriority( GCPriority );
  651. LOOP
  652. IF collect THEN
  653. TRACE(collect);
  654. collect := FALSE;
  655. Machine.Acquire( Machine.Heaps );
  656. cur.context.r_sp := Machine.CurrentSP();
  657. cur.context.r_bp := Machine.CurrentBP();
  658. cur.context.r_sp := ADDRESS OF GCLoop;
  659. SuspendActivities;
  660. Heaps.CollectGarbage( Modules.root );
  661. Machine.Release( Machine.Heaps );
  662. ResumeActivities;
  663. finalizerCaller.Activate;
  664. (*Unix.ConSignal( gcFinished );*)
  665. ELSE
  666. Unix.ThrSleep( 10 );
  667. END;
  668. timerActivity.UpdateTicks
  669. END
  670. *)
  671. END GCLoop;
  672. PROCEDURE CurrentProcessTime*(): HUGEINT;
  673. BEGIN
  674. RETURN Machine.GetTimer()
  675. END CurrentProcessTime;
  676. PROCEDURE TimerFrequency*(): HUGEINT;
  677. BEGIN
  678. RETURN Machine.mhz * 1000000
  679. END TimerFrequency;
  680. (*----------------------------- initialization ----------------------------------*)
  681. PROCEDURE StartTimerActivity;
  682. BEGIN
  683. timerListMutex := Unix.MtxInit(0); timers := NIL;
  684. NEW( timerActivity );
  685. END StartTimerActivity;
  686. PROCEDURE GetStacksize;
  687. VAR str: ARRAY 32 OF CHAR; i: LONGINT;
  688. BEGIN
  689. Machine.GetConfig( "StackSize", str );
  690. IF str = "" THEN stacksize := DefaultStacksize
  691. ELSE
  692. i := 0; stacksize := Machine.StrToInt( i, str );
  693. stacksize := stacksize * 1024;
  694. END;
  695. IF Glue.debug # {} THEN
  696. Trace.String( "Stacksize of active objects = " );
  697. Trace.Int( stacksize DIV 1024, 0 ); Trace.StringLn( "K" )
  698. END;
  699. END GetStacksize;
  700. PROCEDURE Convert;
  701. VAR p: Process;
  702. BEGIN
  703. (* make current thread the first active object *)
  704. NEW( p, NIL, NIL, 0, {}, 0 );
  705. END Convert;
  706. PROCEDURE Init;
  707. BEGIN
  708. TRACE("Init");
  709. Unix.suspendHandler := GetContext;
  710. (*
  711. Unix.Dlsym( 0, "Unix.MtxInit", ADDRESSOF( Unix.MtxInit ) );
  712. Unix.Dlsym( 0, "Unix.MtxDestroy", ADDRESSOF( Unix.MtxDestroy ) );
  713. Unix.Dlsym( 0, "Unix.MtxLock", ADDRESSOF( Unix.MtxLock ) );
  714. Unix.Dlsym( 0, "Unix.MtxUnlock", ADDRESSOF( Unix.MtxUnlock ) );
  715. Unix.Dlsym( 0, "Unix.ConInit", ADDRESSOF( Unix.ConInit ) );
  716. Unix.Dlsym( 0, "Unix.ConDestroy", ADDRESSOF( Unix.ConDestroy ) );
  717. Unix.Dlsym( 0, "Unix.ConWait", ADDRESSOF( Unix.ConWait ) );
  718. Unix.Dlsym( 0, "Unix.ConSignal", ADDRESSOF( Unix.ConSignal ) );
  719. Unix.Dlsym( 0, "thrStart", ADDRESSOF( thrStart ) );
  720. Unix.Dlsym( 0, "Unix.ThrThis", ADDRESSOF( Unix.ThrThis ) );
  721. Unix.Dlsym( 0, "Unix.ThrSleep", ADDRESSOF( Unix.ThrSleep ) );
  722. Unix.Dlsym( 0, "Unix.ThrYield", ADDRESSOF( Unix.ThrYield ) );
  723. Unix.Dlsym( 0, "Unix.ThrExit", ADDRESSOF( Unix.ThrExit ) );
  724. Unix.Dlsym( 0, "Unix.ThrSuspend", ADDRESSOF( Unix.ThrSuspend ) );
  725. Unix.Dlsym( 0, "Unix.ThrResume", ADDRESSOF( Unix.ThrResume ) );
  726. Unix.Dlsym( 0, "Unix.ThrGetPriority", ADDRESSOF( Unix.ThrGetPriority ) );
  727. Unix.Dlsym( 0, "Unix.ThrSetPriority", ADDRESSOF( Unix.ThrSetPriority ) );
  728. Unix.Dlsym( 0, "thrKill", ADDRESSOF( thrKill ) );
  729. *)
  730. createProcess := Unix.MtxInit( 0 ); processList := Unix.MtxInit( 0 );
  731. startProcess := Unix.MtxInit(0); childrunning := Unix.ConInit(0);
  732. collect := FALSE;
  733. igc := Unix.MtxInit( 0 ); gcFinished := Unix.ConInit( 0 );
  734. GetStacksize;
  735. Convert;
  736. StartTimerActivity;
  737. NEW( finalizerCaller );
  738. (*
  739. Heaps.saveSP := SaveSP;
  740. *)
  741. Heaps.gcStatus := GCStatusFactory()
  742. (*
  743. Heaps.GC := InvokeGC;
  744. Heaps.InvokeGC := InvokeGC;
  745. *)
  746. END Init;
  747. PROCEDURE {FINAL} Final;
  748. BEGIN
  749. TRACE("FINAL END ");
  750. (* LOOP Unix.ThrSleep( 10 ) END; *)
  751. (*
  752. Machine.Shutdown(FALSE);
  753. *)
  754. END Final;
  755. PROCEDURE GCStatusFactory(): Heaps.GCStatus;
  756. VAR gcStatusExt : GCStatusExt;
  757. BEGIN
  758. ASSERT(Heaps.gcStatus = NIL);
  759. NEW(gcStatusExt);
  760. RETURN gcStatusExt
  761. END GCStatusFactory;
  762. BEGIN
  763. TRACE("Objects.Body1");
  764. Init;
  765. TRACE("Objects.Body2");
  766. END Objects.