Linux Device Driver Tutorial Part 22 – Mutex in Linux Kernel

This is the Series on Linux Device Driver. The aim of this series is to provide the easy and practical examples that anyone can understand. This is the Linux Device Driver Tutorial Part 22 – Mutex in Linux Kernel.

Prerequisites

In the example section, I had used Kthread to explain Mutex. If you don’t know what is Kthread and How to use it, then I would recommend you to explore that by using below link.

  1. Kthread Tutorial in Linux Kernel

Introduction

Before getting to know about Mutex, let’s take an analogy first.

Let us assume we have a car designed to accommodate only one person at any instance of time, while all the four doors of the car are open. But, if any more than one person tries to enter the car, a bomb will set off an explosion!(Quite a fancy car manufactured by EmbeTronicX!!) Now that four doors of the car are open, the car is vulnerable to explosion as anyone can enter through one of the four doors.

Now how we can solve this issue? Yes correct. We can provide a key for the car. So, the person who wants to enter the car must have access to the key. If they don’t have key, they have to wait until that key is available or they can do some other work instead of waiting for key.

Example Problems

Let’s correlate the analogy above to what happens in our software. Let’s explore situations like these through examples.

  1. You have one SPI connection. What if one thread wants to write something into that SPI device and another thread wants to read from that SPI device at the same time?
  2. You have one LED display. What if one thread is writing data at a different position of Display and another thread is writing different data at a different position of Display at the same time?
  3. You have one Linked List. What if one thread wants to insert something into the list and another one wants to delete something in the same Linked List at the same time?

In all the scenarios above, the problem encountered is the same. At any given point two threads are accessing a single resource. Now we will relate the above scenarios to our car example.

  1. In SPI example, CAR = SPI, Person = Threads, Blast = Software Crash/Software may get wrong data.
  2. In LED display example,  CAR = LED Display, Person = Threads, Blast = Display will show some unwanted junks.
  3. In Linked List example, CAR = Linked List, Person = Threads, Blast = Software Crash/Software may get wrong data.

The cases above are termed as Race Condition.

Race Condition

A race condition occurs when two or more threads can access shared data and they try to change it at the same time. Because the thread scheduling algorithm can swap between threads at any time, we don’t know the order in which the threads will attempt to access the shared data. Therefore, the result of the change in data is dependent on the thread scheduling algorithm, i.e. both threads are “racing” to access/change the data.

To avoid the race conditions, we have many ways like Semaphore, Spinlock and Mutex. In this tutorial we will concentrate on Mutex.

Mutex

mutex is a mutual exclusion lock. Only one thread can hold the lock.

Mutex can be used to prevent the simultaneous execution of a block of code by multiple threads that are running in a single or multiple processes.

Mutex is used as a synchronization primitive in situations where a resource has to be shared by multiple threads simultaneously.

Mutex has ownership. The thread which locks a Mutex must also unlock it.

So whenever you are accessing a shared resource that time first we lock mutex and then access the shared resource. When we are finished with that shared resource then we unlock the Mutex.

I hope you got some idea about Mutex. Now, let us look at Mutex in Linux Kernel.

Mutex in Linux Kernel

Today most major operating systems employ multitasking. Multitasking is where multiple threads can execute in parallel and thereby utilizing the CPU in optimum way. Even though, multitasking is useful, if not implemented cautiously can lead to concurrency issues (Race condition), which can be very difficult to handle.

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

We will be using this structure for Mutex. Refer to Linux/include/linux/mutex.h

Initializing Mutex

We can initialize Mutex in two ways

  1. Static Method
  2. Dynamic Method

Static Method

This method will be useful while using global Mutex. This macro is defined below.

DEFINE_MUTEX(name);

This call defines and initializes a mutex. Refer to Linux/include/linux/mutex.h

Dynamic Method

This method will be useful  for per-object mutexes, when mutex is just a field in a heap-allocated object. This macro is defined below.

mutex_init(struct mutex *lock);

Argument:

struct mutex *lock – the mutex to be initialized.

This call initializes already allocated mutex. Initialize the mutex to unlocked state.

It is not allowed to initialize an already locked mutex.

Example

Mutex Lock

Once a mutex has been initialized, it can be locked by any one of them explained below.

mutex_lock

This is used to lock/acquire the mutex exclusively for the current task. If the mutex is not available, the current task will sleep until it acquires the Mutex.

The mutex must later on be released by the same task that acquired it. Recursive locking is not allowed. The task may not exit without first unlocking the mutex. Also, kernel memory where the mutex resides must not be freed with the mutex still locked. The mutex must first be initialized (or statically defined) before it can be locked. memset-ing the mutex to 0 is not allowed.

void mutex_lock(struct mutex *lock);

Argument:

struct mutex *lock – the mutex to be acquired

mutex_lock_interruptible

Locks the mutex like mutex_lock, and returns 0 if the mutex has been acquired or sleep until the mutex becomes available. If a signal arrives while waiting for the lock then this function returns -EINTR.

int mutex_lock_interruptible(struct mutex *lock);

Argument:

struct mutex *lock – the mutex to be acquired

mutex_trylock

This will try to acquire the mutex, without waiting (will attempt to obtain the lock, but will not sleep). Returns 1 if the mutex has been acquired successfully, and 0 on contention.

int mutex_trylock(struct mutex *lock);

Argument:

struct mutex *lock – the mutex to be acquired

This function must not be used in interrupt context. The mutex must be released by the same task that acquired it.

Mutex Unlock

This is used to unlock/release a mutex that has been locked by a task previously.

This function must not be used in interrupt context. Unlocking of a not locked mutex is not allowed.

void mutex_unlock(struct mutex *lock);

Argument:

struct mutex *lock – the mutex to be released

Mutex Status

This function is used to check whether mutex has been locked or not.

int mutex_is_locked(struct mutex *lock);

Argument:

struct mutex *lock – the mutex to check the status.

Returns 1 if the mutex is locked, 0 if unlocked.

Example Programming

This code snippet explains how to create two threads that accesses a global variable (etx_gloabl_variable). So before accessing the variable, it should lock the mutex. After that it will release the mutex.

Driver Source Code

 

MakeFile

 

Download our new Android app. You can learn all Embedded Tutorials from your Android Phone easily.

Click Here to Download App!