new object $mutex: $root; var $mutex locks = 0; var $mutex queues = 0; var $mutex suspended = 0; var $mutex tasks = 0; var $root created_on = 858071384; var $root flags = ['variables, 'methods, 'code, 'core]; var $root help_node = $help_mutex; var $root inited = 1; var $root managed = [$mutex]; var $root manager = $mutex; private method ._add_to_lock() { arg tid, val; if ((| ((locks[val])[1]) == tid |)) locks = locks.add(val, [tid, ((locks[val])[2]) + 1]); else locks = locks.add(val, [tid, 1]); }; private method ._del_from_lock() { arg tid, val; var i, l; if (((| (l = locks[val]) |)[1]) != tid) return; if ((l[2]) == 1) { (| (locks = locks.del(val)) |); ._del_from_queue(val); } else { locks = locks.add(val, [tid, (l[2]) - 1]); } }; private method ._del_from_queue() { arg val; var tid, s, q; q = (| queues[val] |) || []; (| (queues = queues.del(val)) |); for tid in (q) { if ((s = suspended[tid]) == 1) { suspended = suspended.del(tid); (| $scheduler.resume(tid) |); } else { suspended = suspended.add(tid, s - 1); } } }; private method ._test_lock() { arg tid, val; var i; if ((| ((locks[val])[1]) != tid |)) { queues = queues.add(val, (| (queues[val]) + [tid] |) || [tid]); return 0; } return 1; }; private method ._test_locks() { arg tid, values; var i; return filter i in (values) where (!(._test_lock(tid, i))); }; public method .cleanup_dead_tasks() { var t, i, j; t = tasks(); for i in (tasks.keys()) { if (!(i in t)) { for j in (tasks[i]) ._del_from_lock(i, j); tasks = tasks.del(i); } } }; public method .grab() { arg @values; var i, tid, l, obj; values ?= [0]; tid = task_id(); for obj in (.descendants()) obj.grab(@values); tasks = tasks.add(tid, (| (tasks[tid]) + [values] |) || values); while (1) { if (!(l = ._test_locks(tid, values))) { for i in (values) ._add_to_lock(tid, i); return; } else { suspended = suspended.add(tid, l.length()); $scheduler.suspend(this()); } } }; root method .init_mutex() { tasks = (suspended = (queues = (locks = #[]))); }; public method .release() { arg @values; var tid, t, vlist, i, obj; values ?= [0]; tid = task_id(); vlist = tasks[tid]; for obj in (.descendants()) obj.release(@values); for i in (values) { vlist = vlist.setremove(i); ._del_from_lock(tid, i); } if (vlist) tasks = tasks.add(tid, vlist); else tasks = tasks.del(tid); }; public method .release_all() { .release(@tasks[task_id()]); };