Generic.Unix.Objects.Mod 25 KB

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