Generic.Unix.Objects.Mod 25 KB

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