Warning: session_start(): open(/var/lib/php/sessions/sess_bh3ins5phst0euvc5fq6hs3sao, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// Previous version (#1000934) was 328 bytes when idle.
// And we can evaporate this even further by mergine the queue
// with the object it belongs to. Probably we'll end up paying nothing
// for an idle object while still enjoying the experience of being
// able to start a thread instantly whenever needed.
sclass CompactQ extends Meta is AutoCloseable {
// Step 1 - no name... well, no reserved name field, anyway.
// Most queues can probably be identified from context.
// if you want æ name - use Meta
S name() { ret or2((S) metaGet("name"), toString()); }
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)); }
// optional thread ownership marker, e.g. for OS modules.
// Having slashed absolutely everything else, we do keep that as an actual field
IF0 enter;
// We do want to know who is servicing us currently...
Thread thread;
bool startingThread;
AutoCloseable enter() { ret callF(enter); }
synchronized bool running() { ret thread != null; }
bool done() { ret retired() || !licensed() || isEmpty(); }
void waitUntilDone {
while (!done()) sleep(1);
}
// Yes, in JavaX functions can have any number of names
public synchronized void close aka cancel() {
retired(true);
clear();
if (thread == null) ret;
// threadBeingCancelled = new WeakReference(thread); // optional
cancelAndInterruptThread(thread);
thread = null;
}
public synchronized void clear {
q = null;
}
// append to q (do later)
void add(Runnable r) {
if (r == null) ret;
synchronized { q = chainPlus(q, r); }
checkForAction();
}
// prepend to q (do next)
void addInFront(Runnable r) {
if (r == null) ret;
synchronized { q = itemPlusChain(r, q); }
checkForAction();
}
protected void checkForAction() {
synchronized {
if (done() || running() || startingThread)
ret;
// There seems to be work, so we start a thread.
set startingThread;
}
try {
// At this point, we are not synchronized, but uncontested.
// No one else will try to start a thread.
temp enter();
startThread(name(), () -> {
try {
temp enter();
// Put us in the book.
synchronized {
startingThread = false;
thread = currentThread();
}
// And off we go!
_bout();
} finally {
thread = null;
startingThread = false;
}
});
} on fail {
close();
}
}
// work as long there is work
void _bout {
while (licensed() && !retired()) {
Runnable r;
synchronized {
r = first(q);
q = popFirst(q);
}
if (r != null)
pcall { r?.run(); }
else
onIdle();
}
}
synchronized bool isEmpty() { ret q == null; }
synchronized int size() { ret l(q); }
O mutex() { this; } // clients can synchronize on this
L snapshot() { ret cloneList(q); }
// you can override this
void onIdle {}
}