LWN.net Logo

The mutex API

The mutex code may well have set a record for the shortest time spent in -mm for such a fundamental patch. It would not have been surprising for mutexes to sit in -mm through at least one kernel cycle, which would have had them being merged in or after 2.6.17. But the mutex code appeared in exactly one -mm release (2.6.15-mm2, released on January 7) before being merged into the mainline on January 9.

The actual mutex type (minus debugging fields) is quite simple:

    struct mutex {
	atomic_t		count;
	spinlock_t		wait_lock;
	struct list_head	wait_list;
    };

Unlike semaphores, mutexes have one definition which is used on all architectures. Some of the actual locking and unlocking code can be overridden if it can be made to perform better on a specific architecture, but the core data structure remains the same. The count field contains the state of the mutex. A value of one indicates that it is available, zero means locked, and a negative value means that it is locked and processes might be waiting. Separating the two "locked" cases is worthwhile: in the (usual) case where nobody is waiting for the mutex, there is no need to go through the process of seeing if anybody needs to be waked up. wait_lock controls access to wait_list, which is a simple list of processes waiting on the mutex.

The mutex API (obtained through <linux/mutex.h>) is simple. Every mutex must first be initialized either at declaration time with:

    DEFINE_MUTEX(name);

Or at run time with:

    mutex_init(struct mutex *lock);

Once a mutex has been initialized, it can be locked with any of:

    void mutex_lock(struct mutex *lock);
    int mutex_lock_interruptible(struct mutex *lock);
    int mutex_trylock(struct mutex *lock);

A call to mutex_lock() will lock the mutex, putting the calling process into an uninterruptible wait if need be. mutex_lock_interruptible() uses an interruptible sleep; if the lock is obtained, it will return zero. A return value of -EINTR means that the locking attempt was interrupted by a signal and the caller should act accordingly. Finally, mutex_trylock() will attempt to obtain the lock, but will not sleep; unlike mutex_lock_interruptible(), it returns zero on failure (the lock was unavailable) and one if the lock is acquired.

In all cases, the mutex must eventually be freed (by the same process which acquired it) through a call to:

    void mutex_unlock(struct mutex *lock);

Note that mutex_unlock() cannot be called from interrupt context. This restriction appears to have more to do with keeping mutexes from ever being used as completions than a fundamental restriction caused by the mutex design itself. Note also that a mutex can only be locked once - locking calls do not nest.

Finally, there is a function for querying the state of a mutex:

    int mutex_is_locked(struct mutex *lock);

This function will return a boolean value indicating whether the mutex is locked or not, but will not change the state of the lock.

Now that this code has been merged, the semaphore type can officially be considered to be on its way out. New code should not use semaphores, and old code which uses semaphores as mutexes should be converted over when an opportunity presents itself. The reader/writer semaphore type (rwsem) is a different beast, and is not affected by this patch. There is a debugging option which can be configured into development kernels which may help with the transition; with this option enabled, quite a few types of errors will be detected.

At this point, code which uses the counting feature of semaphores lacks a migration path. There is evidently a plan to introduce a new, architecture-independent type for these users, but that code has not yet put in an appearance. Once that step has been taken, the path will be clear for the eventual removal of semaphores from the kernel entirely.


(Log in to post comments)

The mutex API

Posted Jan 12, 2006 9:41 UTC (Thu) by simlo (subscriber, #10866) [Link]

Note that mutex_unlock() cannot be called from interrupt context. This restriction appears to have more to do with keeping mutexes from ever being used as completions than a fundamental restriction caused by the mutex design itself.

If you could it would not be a mutex but a semaphore! A mutex can only be unlocked by the owner - which must be a task. But when you turn off the debug code, Ingo's mutex is indeed just a binary semaphore.

At computer science we were indeed told to use binary semaphores as mutual exclusion locks. But it is a bad advice. The semantics is very different. To help debugging and make the code more understandable it is really a good idea to use seperate types for completion type semaphores and mutex and to enforce the mutex semantics. On real-time systems you must use a mutex with some kind of priority inversion prevention (priority inheritance or priority ceiling). Therefore it is essential not to mix up mutex with completions on that kind of systems.

Furthermore: When a mutex can't be touched from interrupts, you don't have to disable interrupts while performing mutex operations.

Copyright © 2006, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds