sclass CompactQ extends Meta is AutoCloseable { // Step 1 - no name... well, no reserved name field, anyway. // Most queues can be probably identified from context. // if you want æ name - use Meta S name() { ret (S) metaGet("name"); } void name(S name) { metaSet(+name); } // Np syncLinkedList - just an AppendableChain // All sync is done on the main object AppendableChain q; // retired also goes to meta bool retired() { ret metaGet("retired") != null; } void retired(bool b) { metaPut("retired", trueOrNull(b)); } // stuff from RST bool cancelBeforeTrigger; // always cancel running thread and wait for it to end before starting new operation bool waitBetweenCancelAndTrigger; // make sure the old thread is actually ended // optional thread ownership marker, e.g. for OS modules. // Having slashed absolutely everything else, we do keep that as an actual field IF0 enter; // Being triggered is just having something in the queue. // So straightforward! bool triggered() { ret !isEmpty(); } // We do want to know who is servicing us... Thread thread; // This is useful also. All stuff that could go in meta though. // The main idae is to have idle queues really small so just about // every BEA object can have one and it doesn't cost us anything. WeakReference threadBeingCancelled; *(O *runnable) {} void trigger() { go(); } synchronized void go() { if (cancelBeforeTrigger) cancelAndPossiblyWait(); trigger = true; if (!running()) { temp callF(enter); thread = startThread(name, r { temp callF(enter); _run(); }); } } public void run() { go(); } void get() { go(); } // so you can use the ! syntax synchronized bool running() { ret thread != null; } // use only if this is the last time you trigger this void triggerAndWait() { trigger(); waitUntilDone(); } void waitUntilDone { while (running()) sleep(1); } void _run() ctex { while licensed { Thread oldThread; synchronized(this) { var currentInserts = syncGetAndClear(inserts); pcallFAll(currentInserts); if (!trigger) { thread = null; break; } oldThread = getWeakRef(threadBeingCancelled); trigger = false; } if (oldThread != null && oldThread != currentThread()) oldThread.join(cancelTimeOut); pcallF(runnable); } } synchronized void cancel() { if (thread == null) ret; threadBeingCancelled = new WeakReference(thread); cancelAndInterruptThread(thread); thread = null; } void cancelAndWait() { Thread _thread; synchronized { if (thread == null) ret; _thread = thread; threadBeingCancelled = new WeakReference(thread); thread = null; } cancelAndInterruptThread(_thread); } void cancelAndTrigger() { cancelAndPossiblyWait(); trigger(); } synchronized bool triggered() { ret trigger; } void cleanMeUp { cancel(); } selfType cancelBeforeTrigger() { cancelBeforeTrigger = true; this; } void cancelAndPossiblyWait() { if (waitBetweenCancelAndTrigger) cancel(); } *() {} *(S name) { name(name); } // append to q (do later) synchronized void add(Runnable r) { if (r == null) ret; synchronized { q = chainPlus(q, r); } _trigger(); } // prepend to q (do next) void addInFront(Runnable r) { if (r == null) ret; synchronized { q = itemPlusChain(r, q); } _trigger(); } void _trigger() { rst.name = name(); rst.go(); } void _bout { while (licensed() && retired()) { Runnable r; synchronized { r = first(q); q = popFirst(q); } if (r != null) pcall { r?.run(); } else onIdle(); } } public void close() { retired(true); } // TODO: interrupt thread void done() {} // legacy function bool isEmpty() { ret q == null; } int size() { ret l(q); } O mutex() { this; } // clients can synchronize on this L snapshot() { ret cloneList(q); } // you can override this void onIdle {} }