Собсьно, новости по багу на мультиядерных системах...
Виснет только графический интерфейс, ошибка в реализации синхронизации с ГУЕм Synch.BeginOberonSafe.
Сейчас пока не исправлял, но пример, в котором обновление отображения шариков выполняется не из отдельной активной процедуры Update, а классически по Action, работает вроде как безошибочно:
Так же кое-что исправил в модуле Ao - там действительно была очередь FILO, исправил на FIFO.
MODULE Ao;
(**
	project	= "Active BlackBox"
	organization	= "blackbox.metasystems.ru"
	contributors	= "OCSE Metasystems, Ltd."
	version	= "1.5 beta, based on BlackBox 1.5"
	copyright	= "Docu/Active/About"
	license	= "Docu/Active/License"
	changes	= ""
	issues	= ""
**)
	IMPORT Kernel, Synch, Mem, Details, S := SYSTEM, HostSynch;
	CONST
		idle* = {0};
		low* = {1};
		high* = {0, 1};
		bound* = {2};
		copyRefs* = {3};
		safe* = {4};
		notCloseTask* = {5};
(*		awaitOrComplete* = {6}; *)	
	CONST
		regEax = 0;
		regEbx = 3;
		regEsi = 6;
		regEdi = 7;
		regFp = 5;
		regSp = 4;		
	TYPE
		StartInfo = POINTER TO RECORD
			flags: SET;
			body: PROCEDURE;
			params: POINTER TO ARRAY OF BYTE;
			refs: POINTER TO ARRAY OF POINTER TO ARRAY OF BYTE;
			locals: POINTER TO ARRAY OF BYTE;
			ebx, esi, edi: INTEGER;
			barrier: Synch.CriticalSection;
			continue: BOOLEAN
		END;		
		Stack = RECORD
			base, fp, sp: INTEGER
		END;		
		Stop* = RECORD
			stop: BOOLEAN
		END;		
		Await = POINTER TO RECORD
			next: Await;
			sem: Synch.Semaphore
		END;		
		MONITOR* = POINTER TO RECORD (Details.Detail)
			locker: INTEGER;
			cs: Synch.CriticalSection;
			update: BOOLEAN;
			await, end: Await
		END;		
		TLS = POINTER TO RECORD
			flags: SET;
			sp: INTEGER;
			exclStack: ARRAY 128 OF RECORD
				ret: INTEGER;
				object: MONITOR
			END
		END;		
		AwaitHeap = POINTER TO RECORD (Mem.SynchedHeap) END;	
	VAR
		tls: Synch.LocalStorage;
		awaitHeap: AwaitHeap;
		heapCS: Synch.CriticalSection;	
	PROCEDURE [code] JmpEbx
		0FFH, 0E3H; (*FF 11 100  011 (EBX) *)
	PROCEDURE [code] PushEbp
		55H;
	PROCEDURE [code] MovEbpEsp
		8BH, 0ECH;
	PROCEDURE [code] PopEbp
		5DH;
	PROCEDURE [code] MovEspEbp
		8BH, 0E5H;
	PROCEDURE [code] PushEdi
		57H;
	PROCEDURE [code] PushEsi
		56H;
	PROCEDURE [code] PushEbx
		53H;
	PROCEDURE [code] PushEax
		50H;
	PROCEDURE [code] PopEsi
		5EH;
	PROCEDURE [code] PopEdi
		5FH;
	PROCEDURE [code] PopEbx
		5BH;
	PROCEDURE [code] PopEax
		58H;
	PROCEDURE [code] Ret
		0C3H;
	PROCEDURE [code] Ret8
		0C2H, 08H, 00H;
	PROCEDURE [code] Push0
		6AH, 00H;
	PROCEDURE [code] AddEsp12
		83H, 0C4H, 0F4H;
	PROCEDURE [code] AddEsp24
		83H, 0C4H, 0E8H;
	PROCEDURE [code] LeaEspEbp12
		8DH, 65H, 0F4H;
	PROCEDURE CopyParams (IN this: Stack; IN info: Mem.ProcInfo; VAR new: StartInfo; flags: SET; OUT ok: BOOLEAN);
		VAR p, par, a, len, i, k: INTEGER;
				tag: Kernel.Type;
				adrs, offs: ARRAY 32 OF INTEGER;
				(* proc desc *)
				ref: INTEGER;
				mode, form: SHORTCHAR;
				desc: Kernel.Type;
				x: INTEGER;
				name: Kernel.Name;
	BEGIN
		ok := TRUE;
		IF info.nOfPars > 0 THEN
			flags := flags * copyRefs;
			NEW(new.refs, info.nOfPars);
			(* chek varpar params *)
			FOR par := 0 TO info.nOfPars-1 DO
				ref := info.refFirstPar;
				Kernel.GetRefVar(ref, mode, form, desc, x, name);
				offs[par] := x;
				IF (mode = 3X) OR (form = 12X) & (desc.size = 0) THEN
					p := this.fp + x;
					S.GET(p, a);
					IF (this.base >= a) & (a >= this.fp) THEN	(* if varpar points to current stack... *)
						IF flags = {} THEN
							ok := FALSE;
							RETURN
						ELSIF flags = copyRefs THEN
							IF form = 11X THEN
								S.GET(p+4, tag);
								len := tag.size
							ELSIF form = 12X THEN
							 	IF desc.size = 0 THEN
									len := 1;
									FOR i := 1 TO desc.id DIV 16 MOD 16 DO
										S.GET(p+4*i, k);
										len := len * k
									END;
									len := len * Mem.TypeSize(desc.base[0])
								ELSE
									len := desc.size * Mem.TypeSize(desc.base[0])
								END
							ELSE
								len := MAX(Mem.SizeOfPar(1X, form, NIL), 4)
							END;
							NEW(new.refs[par], len);
							S.MOVE(a, S.ADR(new.refs[par][0]), len);
							adrs[par] := S.ADR(new.refs[par][0])
						END
					ELSE
						adrs[par] := a
					END
				ELSE
					adrs[par] := 0
				END
			END;
			(* copy params *)
			NEW(new.params, info.parEnd - info.parBeg);
			S.MOVE(this.fp + info.parBeg, S.ADR(new.params[0]), info.parEnd - info.parBeg);
			(* fixup varpars *)
			FOR par := 0 TO info.nOfPars-1 DO
				IF adrs[par] # 0 THEN
					S.PUT(S.ADR(new.params[0]) + offs[par] - info.parBeg, adrs[par])
				END
			END
		END
	END CopyParams;
	PROCEDURE CopyLocals (IN this: Stack; VAR new: StartInfo);
		VAR len: INTEGER;
	BEGIN
		len := this.fp - this.sp;
		IF len > 0 THEN
			NEW(new.locals, len);
			S.MOVE(this.sp, S.ADR(new.locals[0]), len)
		END
	END CopyLocals;
	PROCEDURE ^ Starter2 (self: INTEGER; inf: ANYPTR);
	PROCEDURE ^ Restore (id: INTEGER; info: ANYPTR; OUT restored: BOOLEAN);
	(* 20 - wrong flags
		21 - unknown caller module
		22 - unexpected local reference
		23 - too many param
		24 - can not be bound
	*)
	PROCEDURE ACTIVE* (flags: SET);
		VAR ebx, esi, edi: INTEGER;
				new: StartInfo;
				stackSize: INTEGER;
				ret, stackUp, fpUp: INTEGER;
				this: Stack;
				info: Mem.ProcInfo;
				(* proc info *)
				procAdr: INTEGER;
				procName: Kernel.Name;
				id: INTEGER;
				ok: BOOLEAN;
				obj: ANYPTR;
	BEGIN
		S.GETREG(regEbx, ebx); S.GETREG(regEsi, esi); S.GETREG(regEdi, edi);
		NEW(new); new.ebx := ebx; new.esi := esi; new.edi := edi;
		new.barrier := Synch.dir.NewCS(); new.barrier.ENTER;
		new.flags := flags;
		Kernel.cGetTaskStack(Kernel.cThisTask(), this.base, this.fp, this.sp);
		this.sp := this.fp + 8;				(* get sp of caller proc *)
		S.GET(this.fp+4, new.body); 	(* get addr of caller proc ACTIVE section (RET addr of this proc) *)
		S.GET(this.fp, this.fp);			(* get frame of caller proc *)
		S.GET(this.fp+4, ret);		(* get RET addr of caller proc *)
		Mem.GetProcInfo(S.VAL(INTEGER, new.body), info);
		ASSERT(Mem.firstStmt IN info.ext, 20);
		Kernel.GetRefProc(info.ref, procAdr, procName);
		CopyParams(this, info, new, flags, ok);
		ASSERT(ok, 24);
		CopyLocals(this, new);
		stackSize := 4000H;
		IF new.params # NIL THEN INC(stackSize, LEN(new.params)) END;
		IF new.locals # NIL THEN INC(stackSize, LEN(new.locals)) END;
		Kernel.cCreateTask(Starter2, new, stackSize, "Active proc: " + procName, FALSE, id);
		Kernel.cSetNativeMod(id, info.mod);
		IF flags * bound = bound THEN
			IF (info.nOfPars = 0) OR ~(Mem.object IN info.ext) THEN
				new.barrier.LEAVE;
				HALT(21)
			END;
			S.GET(this.fp + 8, obj);
			ASSERT(obj # NIL, 22);
			Kernel.cSetTaskOwner(id, obj);
			obj := NIL
		END;
		IF flags * safe = safe THEN
			Kernel.cSetTaskRestore(id, Restore, NIL)
		END;
		IF flags * {0, 1} = idle THEN
			Kernel.cSetPriority(id, Kernel.priorIdle)
		ELSIF flags * {0, 1} = low THEN
			Kernel.cSetPriority(id, Kernel.priorBelowNormal)
		ELSIF flags * {0, 1} = high THEN
			Kernel.cSetPriority(id, Kernel.priorAboveNormal)
		END;
		new.continue := TRUE;
		new.barrier.LEAVE;
		stackUp := this.fp + info.parEnd; 	(* deleting params of caller proc *)
		DEC(stackUp, 4);		(* ACTIVE param size, for RET n. *)
		S.GET(this.fp, fpUp);
		S.PUT(stackUp-4, ret);
		S.PUT(stackUp-8, fpUp);
		S.PUTREG(regFp, stackUp-8);
		S.PUTREG(0, 0) (* Clear return value in AX *)
	END ACTIVE;	
(* Old starter *)	
	PROCEDURE Starter2 (self: INTEGER; inf: ANYPTR);
		VAR ret, fp, sp, len, newFp: INTEGER;
				end, ok: BOOLEAN;
				t: TLS;
		PROCEDURE FixRet;
			VAR fp: INTEGER;
		BEGIN
			S.GETREG(regFp, fp);
			S.GET(fp + 4, ret)
		END FixRet;
	BEGIN
		end := FALSE;
		WITH inf: StartInfo DO
			inf.barrier.ENTER; inf.barrier.LEAVE;
			IF ~inf.continue THEN Kernel.cCloseTask(self, ok) END;
			t := tls.Get()(TLS);
			t.flags := inf.flags;
			S.GETREG(regSp, sp);
			S.GETREG(regFp, fp);
			FixRet;
			IF ~end THEN
				end := TRUE;
				IF inf.params # NIL THEN
					len := LEN(inf.params);
					S.MOVE(S.ADR(inf.params[0]), sp - len, len);
					DEC(sp, len)
				END;
				S.PUT(sp - 4, ret);
				S.PUT(sp - 8, fp);
				DEC(sp, 

;
				newFp := sp;
				IF inf.locals # NIL THEN
					len := LEN(inf.locals);
					S.MOVE(S.ADR(inf.locals[0]), sp - len, len);
					DEC(sp, len)
				END;
				S.PUT(sp-4, inf.body);
				DEC(sp, 4);
				S.PUTREG(regEbx, inf.ebx);
				S.PUTREG(regEsi, inf.esi);
				S.PUTREG(regEdi, inf.edi);
				S.PUTREG(regSp, sp);
				S.PUTREG(regFp, newFp);
				Ret (* go to active procedure body *)
			ELSE
				IF inf.flags * notCloseTask = {} THEN
					Kernel.cCloseTask(self, ok)
				END
			END
		END
	END Starter2;
	PROCEDURE Restore (id: INTEGER; info: ANYPTR; OUT restored: BOOLEAN);
	BEGIN
		restored := TRUE
	END Restore;
	PROCEDURE (VAR s: Stop) Stop*, NEW;
	BEGIN
		s.stop := TRUE
	END Stop;
	PROCEDURE (VAR s: Stop) ShouldStop* (): BOOLEAN, NEW;
	BEGIN
		RETURN Kernel.cShouldComplete(Kernel.cThisTask()) OR s.stop
	END ShouldStop;
	PROCEDURE (VAR s: Stop) Reset*, NEW;
	BEGIN
		s.stop := FALSE
	END Reset;
	PROCEDURE Sleep* (ms: INTEGER);
	BEGIN
		Kernel.cSleep(ms)	
	END Sleep;
	PROCEDURE Turn* ;
	BEGIN
		Kernel.cTurn
	END Turn;
	PROCEDURE (m: MONITOR) Init- (obj: ANYPTR);
	BEGIN
		Details.AssertSingle(obj, m);
		m.locker := -1;
		m.cs := Synch.dir.NewCS()
	END Init;	
	PROCEDURE (h: AwaitHeap) New (): Await;
		VAR a: Await;
	BEGIN
		NEW(a);
		a.sem := HostSynch.NewSysSemaphore(0); (* Synch.dir.NewSem(0); *)
		RETURN a
	END New;	
	PROCEDURE (h: AwaitHeap) Utile (ptr: ANYPTR);
	BEGIN
		WITH ptr: Await DO
			ptr.next := NIL
		END
	END Utile;	
(* Old ret hook *)	
	PROCEDURE RetHook;
	END RetHook;	
	PROCEDURE [noframe] RetHookNF ;
		VAR t: TLS;
				mon: MONITOR;
				aw: Await;
				ret, fp: INTEGER;
	BEGIN
		PushEbp;	(* Reserve place for ret addr substitution *)
		PushEax;
		PushEdi;
		PushEsi;
		PushEbp;
		MovEbpEsp;
		Push0;
		Push0;
		AddEsp12;
		Push0;
		t := tls.Get()(TLS);
		ASSERT(t.sp > 0, 100);
		DEC(t.sp);
		mon := t.exclStack[t.sp].object;
		ret := t.exclStack[t.sp].ret;
		IF mon.update THEN
			aw := mon.await;
			WHILE aw # NIL DO
				aw.sem.POST(1);
				aw := aw.next
			END;
			mon.await := NIL;
			mon.end := NIL;
			mon.update := FALSE
		END;
		mon.locker := -1;
		mon.cs.LEAVE;
		S.GETREG(regFp, fp);
		S.PUT(fp+16, ret);
		MovEspEbp;
		PopEbp;
		PopEsi;
		PopEdi;
		PopEax;
		Ret
	END RetHookNF;	
	(* 20 - wrong caller signature;
		21 - recursive lock
	*)	
	PROCEDURE EXCLUSIVE* ;
		VAR inf: Mem.ProcInfo;
				ret: INTEGER;
				obj: ANYPTR;
				mon: MONITOR;
				fp, adr: INTEGER;
				t: TLS;
	BEGIN
		S.GETREG(regFp, fp);
		S.GET(fp+4, ret);
		Mem.GetProcInfo(ret, inf);
		ASSERT(Mem.firstStmt IN inf.ext, 20);
		ASSERT(Mem.object IN inf.ext, 21);
		S.GET(fp, adr);
		S.GET(adr + 8, obj);
		ASSERT(obj # NIL, 22);
		mon := Kernel.ThisDetail(obj, S.VAL(Kernel.Type, S.TYP(MONITOR)))(MONITOR);
		obj := NIL;
		ASSERT(mon # NIL, 23);
		mon.cs.ENTER;
		IF mon.locker = Kernel.cThisTask() THEN
			mon.cs.LEAVE;
			HALT(24)
		END;
		t := tls.Get()(TLS);
		t.exclStack[t.sp].object := mon;
		S.GET(fp, fp);
		S.GET(fp + 4, t.exclStack[t.sp].ret);
		INC(t.sp);
		S.PUT(fp + 4, S.ADR(RetHookNF));
		mon.locker := Kernel.cThisTask()
	END EXCLUSIVE;	
	PROCEDURE UPDATE* ;
		VAR inf: Mem.ProcInfo;
				ret: INTEGER;
				obj: ANYPTR;
				mon: MONITOR;
				fp, adr: INTEGER;
				t: TLS;
	BEGIN
		S.GETREG(regFp, fp);
		S.GET(fp+4, ret);
		Mem.GetProcInfo(ret, inf);
		ASSERT(Mem.firstStmt IN inf.ext, 20);
		ASSERT(Mem.object IN inf.ext, 21);
		S.GET(fp, adr);
		S.GET(adr + 8, obj);
		ASSERT(obj # NIL, 22);
		mon := Kernel.ThisDetail(obj, S.VAL(Kernel.Type, S.ADR(MONITOR)))(MONITOR);
		obj := NIL;
		ASSERT(mon # NIL, 23);
		mon.cs.ENTER;
		mon.update := TRUE;
		IF mon.locker = Kernel.cThisTask() THEN
			mon.cs.LEAVE;
			HALT(24)
		END;
		t := tls.Get()(TLS);
		t.exclStack[t.sp].object := mon;
		S.GET(fp, fp);
		S.GET(fp + 4, t.exclStack[t.sp].ret);
		INC(t.sp);
		S.PUT(fp + 4, S.ADR(RetHookNF));
		mon.locker := Kernel.cThisTask()
	END UPDATE;	
	PROCEDURE Exit;
		VAR t: TLS;
				i: INTEGER;
				mon: MONITOR;
	BEGIN
		t := tls.Get()(TLS);
		FOR i := t.sp-1 TO 0 BY -1 DO
			mon := t.exclStack[i].object;
			mon.locker := -1;
			mon.cs.LEAVE
		END;
		t.sp := 0
	END Exit;	
	(* 20 - wrong caller signature;
		21 - call form non-exclusive block
	*)	
	PROCEDURE AWAIT* ;
		VAR fp, ret: INTEGER;
				inf: Mem.ProcInfo;
				obj: ANYPTR;
				mon: MONITOR;
				await: Await;
				t: TLS;
				ok: BOOLEAN;
	BEGIN
		S.GETREG(regFp, fp);
		S.GET(fp+4, ret);
		Mem.GetProcInfo(ret, inf);
		ASSERT(Mem.object IN inf.ext, 21);
		S.GET(fp, fp);
		S.GET(fp + 8, obj);
		ASSERT(obj # NIL, 22);
		mon := Kernel.ThisDetail(obj, S.VAL(Kernel.Type, S.ADR(MONITOR)))(MONITOR);
		obj := NIL; (* To prevent anchor until wait *)
		ASSERT(mon # NIL, 23);
		ASSERT(mon.locker = Kernel.cThisTask(), 24);
		t := tls.Get()(TLS);
(*		IF (awaitOrComplete * t.flags # {}) & Kernel.cShouldComplete(Kernel.cThisTask()) THEN
			Exit; Kernel.cCloseTask(Kernel.cThisTask(), ok)
		END; *)
		await := awaitHeap.Alloc()(Await);
		IF mon.end = NIL THEN
			mon.await := await
		ELSE
			mon.end.next := await
		END;
		mon.end := await;
		(* Unlock exclusive section *)
		mon.locker := -1;
		mon.cs.LEAVE;
		await.sem.WAIT;
		(* Re-enter exclusive section *)
		mon.cs.ENTER;
		mon.locker := Kernel.cThisTask();
		awaitHeap.Free(await); (* Only after all other awaits signalled, to prevent await.next destroing *)
(*		IF (awaitOrComplete * t.flags # {}) & Kernel.cShouldComplete(Kernel.cThisTask()) THEN
			Exit; Kernel.cCloseTask(Kernel.cThisTask(), ok)
		END *)
	END AWAIT;	
	PROCEDURE TrapChecker;
	BEGIN
		Exit
	END TrapChecker;
	PROCEDURE Init;
		VAR t: TLS;
				await: Await;
	BEGIN
		NEW(t);
		tls := Synch.dir.NewStorage(t);
		NEW(await);
		NEW(awaitHeap);
		awaitHeap.Init(0)
	END Init;
BEGIN
	Init;
	Kernel.InstallTrapGlobalChecker(TrapChecker)
CLOSE
	Kernel.RemoveTrapGlobalChecker(TrapChecker)
END Ao.
 
P.S. А модификатор [code] дерется с тегом [code] форума