/
ColdCore-3.0a9.02/
ColdCore-3.0a9.02/src/
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()]);
};