Mutex Lock

uOwnerLock

uOwnerLock is uC++‘s blocking, multiple-acquisition mutex lock. The task that acquired the lock can acquire it again without deadlocking, which makes it safe for recursion and for code paths where one locked function calls another that also locks the same resource. Each acquire must be matched by a release.

Why multiple acquisition instead of single?

A single-acquisition mutex deadlocks on recursion. If f() holds the lock and calls g() which also tries to acquire the same lock, the task waits for itself forever. Owner locks track who holds the lock and an acquisition count, so the owner can re-enter freely. The cost is a few extra bytes of state and a branch on each acquire.

Interface

class uOwnerLock {
public:
    uOwnerLock();
    uBaseTask * owner();       // task holding lock, or nullptr
    unsigned int times();      // # acquisitions by current owner
    void acquire();            // blocks if another task owns
    bool tryacquire();         // non-blocking attempt
    void release();            // must be called once per acquire
};

Usage

uOwnerLock lock;
 
void g() {
    lock.acquire();            // re-entrant, no deadlock
    // ...
    lock.release();
}
 
void f() {
    lock.acquire();
    g();                       // safe: same owner, times() goes 1 → 2 → 1
    lock.release();
}

Owner vs spinlock

Same external API as uLock, but with blocking instead of spinning on a failed acquire. A contending task is put on the lock’s blocked queue and descheduled, rather than looping. This is the default choice for any critical section long enough that spinning would waste more CPU than blocking costs.

Always release

Exceptions, early returns, or breaks can skip a plain lock.release(). Use one of the release patterns (_Finally or RAII) to guarantee release on every exit path.