- Kernel Thread – Linux Device Driver Tutorial Part 19
- Process
- Threads
- Thread Management
- Types of Thread
- User Level Thread
- Kernel Level Thread
- Kernel Thread Management Functions
- Create Kernel Thread
- kthread_create
- Start Kernel Thread
- wake_up_process
- Stop Kernel Thread
- kthread_stop
- Other functions in Kernel Thread
- kthread_should_stop
- kthread_bind
- Implementation
- Thread Function
- Creating and Starting Kernel Thread
- kthread_run
- Stop Kernel Thread
- Kernel thread in Linux – Driver Source Code
- MakeFile
- Building and Testing Driver
- Threaded IRQ in Linux Device Driver – Linux Device Driver Tutorial Part 46
- Prerequisites
- Bottom Half
- Threaded IRQ in Linux Kernel
- Threaded IRQ API
- What if a threaded IRQ handler takes more time?
- Threaded IRQ in Linux – Example Programming
- Concept
- Driver Source Code
- Makefile
- Testing the Device Driver
- Output Video
Kernel Thread – Linux Device Driver Tutorial Part 19
This article is a continuation of the Series on Linux Device Driver and carries the discussion on Linux device drivers and their implementation. The aim of this series is to provide easy and practical examples that anyone can understand. This is the Kernel Thread in Linux kernel driver – Linux Device Driver Tutorial Part 19.
Process
An executing instance of a program is called a process. Some operating systems use the term ‘task‘ to refer to a program that is being executed. The process is a heavyweight process. The context switch between the process is time-consuming.
Threads
A thread is an independent flow of control that operates within the same address space as other independent flows of control within a process.
One process can have multiple threads, with each thread executing different code concurrently, while sharing data and synchronizing much more easily than cooperating processes. Threads require fewer system resources than processes and can start more quickly. Threads, also known as lightweight processes.
One of the advantages of the thread is that since all the threads within the processes share the same address space, the communication between the threads is far easier and less time-consuming as compared to processes. This approach has one disadvantage also. It leads to several concurrency issues and requires synchronization mechanisms to handle the same.
Thread Management
Whenever we are creating a thread, it has to manage by someone. So that management follows like below.
- A thread is a sequence of instructions.
- CPU can handle one instruction at a time.
- To switch between instructions on parallel threads, the execution state needs to be saved.
- Execution state in its simplest form is a program counter and CPU registers.
- The program counter tells us what instruction to execute next.
- CPU registers hold execution arguments, for example, addition operands.
- This alternation between threads requires management.
- Management includes saving state, restoring state, deciding what thread to pick next.
Types of Thread
There are two types of threads.
- User Level Thread
- Kernel Level Thread
User Level Thread
In this type, the kernel is not aware of these threads. Everything is maintained by the user thread library. That thread library contains code for creating and destroying threads, for passing messages and data between threads, for scheduling thread execution, and for saving and restoring thread contexts. So all will be in User Space.
Kernel Level Thread
Kernel level threads are managed by the OS, therefore, thread operations are implemented in the kernel code. There is no thread management code in the application area.
Anyhow each type of thread has advantages and disadvantages too.
Now we will move into Kernel Thread Programming. First, we will see the functions used in a kernel thread.
Kernel Thread Management Functions
There are many functions used in Kernel Thread. We will see each one by one. We can classify those functions based on functionalities.
- Create Kernel Thread
- Start Kernel Thread
- Stop Kernel Thread
- Other functions in Kernel Thread
For use the below functions you should include linux/kthread.h header file.
Create Kernel Thread
kthread_create
This API creates a kthread.
struct task_struct * kthread_create (int (* threadfn(void *data), void *data, const char namefmt[], . );
threadfn – the function to run until signal_pending(current).
data – data ptr for threadfn .
namefmt[] – printf-style name for the thread.
. – variable arguments
This helper function creates and names a kernel thread. But we need to wake up that thread manually. When woken, the thread will run threadfn() with data as its argument.
threadfn can either call do_exit directly if it is a standalone thread for which no one will call kthread_stop , or return when ‘ kthread_should_stop ‘ is true (which means kthread_stop has been called). The return value should be zero or a negative error number; it will be passed to kthread_stop .
It Returns task_struct or ERR_PTR(-ENOMEM) .
Start Kernel Thread
wake_up_process
This is used to Wake up a specific process. |
int wake_up_process (struct task_struct * p);
p – The process to be woken up.
Attempt to wake up the nominated process and move it to the set of runnable processes.
It returns 1 if the process was woken up, 0 if it was already running.
It may be assumed that this function implies a write memory barrier before changing the task state if and only if any tasks are woken up.
Stop Kernel Thread
kthread_stop
It stops a thread created by kthread_create . |
int kthread_stop ( struct task_struct *k);
k – thread created by kthread_create .
Sets kthread_should_stop for k to return true , wakes it and waits for it to exit. Your threadfn must not call do_exit itself, if you use this function! This can also be called after kthread_create instead of calling wake_up_process : the thread will exit without calling threadfn .
It Returns the result of threadfn , or –EINTR if wake_up_process was never called.
Other functions in Kernel Thread
kthread_should_stop
should this kthread return now?
int kthread_should_stop (void);
When someone calls kthread_stop on your kthread, it will be woken and this will return true. You should then return, and your return value will be passed through to kthread_stop .
kthread_bind
This is used to bind a just-created kthread to a CPU. |
void kthread_bind (struct task_struct *k, unsigned int cpu);
k – thread created by kthread_create.
cpu – CPU (might not be online, must be possible) for k to run on.
Implementation
Thread Function
First, we have to create our thread that has the argument of void * and should return int value. We should follow some conditions in our thread function. It is advisable.
- If that thread is a long run thread, we need to check kthread_should_stop() every time, because any function may call kthread_stop . If any function called kthread_stop , that time kthread_should_stop will return true . We have to exit our thread function if true value been returned by kthread_should_stop .
- But if your thread function is not running long, then let that thread finish its task and kill itself using do_exit .
In my thread function, let’s print something every minute and it is a continuous process. So let’s check the kthread_should_stop every time. See the below snippet to understand.
Creating and Starting Kernel Thread
So as of now, we have our thread function to run. Now, we will create a kernel thread using kthread_create and start the kernel thread using wake_up_process .
There is another function that does both processes (create and start). That is kthread_run() . You can replace both kthread_create and wake_up_process using this function.
kthread_run
This is used to create and wake a thread.
kthread_run (threadfn, data, namefmt, . );
threadfn – the function to run until signal_pending(current).
data – data ptr for threadfn.
namefmt – printf-style name for the thread.
. – variable arguments
Convenient wrapper for kthread_create followed by wake_up_process .
It returns the kthread or ERR_PTR(-ENOMEM).
You can see the below snippet which is using kthread_run .
Stop Kernel Thread
You can stop the kernel thread using kthread_stop . Use the below snippet to stop.
Kernel thread in Linux – Driver Source Code
The kernel thread will start when we insert the kernel module. It will print something every second. When we remove the module that time it stops the kernel thread. Let’s see the source code.
[Get the source code from the GitHub]
MakeFile
Building and Testing Driver
- Build the driver by using Makefile ( sudo make )
- Load the driver using sudo insmod driver.ko
- Then Check the dmesg
- So our thread is running now.
- Remove the driver using sudo rmmod driver to stop the thread.
In our next tutorial, we will discuss the tasklet in the Linux device driver.
Please find the other Linux device driver tutorials here.
Источник
Threaded IRQ in Linux Device Driver – Linux Device Driver Tutorial Part 46
This article is a continuation of the Series on Linux Device Driver and carries the discussion on Linux device drivers and their implementation. The aim of this series is to provide easy and practical examples that anyone can understand. This is the Threaded IRQ in Linux Device Driver using Raspberry PI – Linux Device Driver Tutorial Part 46.
We are using the Raspberry PI 4 Model B for this demonstration.
Prerequisites
As we are using interrupts, we came across the word called bottom half.
Bottom Half
When Interrupt triggers, the Interrupt handler should be executed very quickly and it should not run for more time (it should not perform time-consuming tasks). If we have the interrupt handler which is doing more tasks then we need to divide it into two halves.
- Top Half
- Bottom Half
The top Half is nothing but our interrupt handler. If we want to do less work, then the top half is more than enough. No need for the bottom half in that situation. But if we have more work when interrupt hits, then we need the bottom half. The bottom half runs in the future, at a more convenient time, with all interrupts enabled. So, The job of bottom halves is to perform any interrupt-related work not performed by the interrupt handler.
There are 4 bottom half mechanisms are available in Linux:
- Workqueue – Executed in a process context.
- Threaded IRQs
- Softirqs – Executed in an atomic context.
- Tasklets – Executed in an atomic context.
In this tutorial, we will discuss threaded IRQ in Linux Kernel.
Threaded IRQ in Linux Kernel
If you see in our previous tutorials where we discussed bottom halves (Workqueue, softirq, Tasklets), we have to register those bottom half and ask the kernel to call those bottom half handler functions. To simplify the process more, Linux has introduced the threaded IRQ. Using this feature, Linux is like, you just give me the handler functions (both top half and bottom half), I will call those functions at a right time. So, with this threaded IRQ, registering the interrupt handler is a bit simplified and we need not even have to schedule the bottom half ourselves. The core does this for us.
The main aim of the threaded IRQ is to reduce the time spent with interrupts being disabled and that will increase the chances of handling other interrupts. How we are achieving this? If we want to know this, we have to know what we are doing in the interrupt handler normally. Once the interrupt hits, we will disable the all interrupts and process our data or do something. Once we process that, then re-enable the interrupts. In this case, if we take more time to process in the ISR, then we might miss the other interrupts as we have disabled the interrupts in the ISR.
To eliminate this, we just do a very important process in the ISR (which takes less than 100us) and deferred other stuff to the thread function. In this case, interrupts have not been disabled for more time. So, we will respond to other interrupts too.
Threaded IRQ API
We have to use the request_threaded_irq instead of request_irq and pass two handlers to that API.
What if a threaded IRQ handler takes more time?
Okay, I can hear you guys. Some will ask, what if threaded IRQ handler ( thread_fn ) takes more time when ISR handler takes less time? In that case, we don’t miss the interrupts. But we miss the threaded IRQ function ( thread_fn ). Confusion? Let’s see this by using an example.
I have two interrupts (UART, and GPIO) being enabled. I have used threaded IRQ for UART interrupt. So, we will be having one UART ISR handler and a UART thread handler( thread_fn ). Once we receive some data from the UART, UART ISR will be triggered. Then kernel calls the UART thread handler( thread_fn ). If we take more time to process the data in the UART thread handler( thread_fn ) (basically when ( thread_fn ) takes more time), Core can able to receive the other interrupts like GPIO as the interrupts are not disabled. It will process that. But if it receives the same UART interrupt, the UART ISR will be called but the UART thread handler ( thread_fn ) may not be called as the UART thread handler is still processing the old received data.
I hope there is no confusion. If you have any questions, please comment below.
Let’s jump into programming.
Threaded IRQ in Linux – Example Programming
Concept
As we are using the GPIO interrupt, the ISR handler gpio_irq_handler will be called when we press the button or vibration is detected in the vibration sensor. There we are returning IRQ_WAKE_THREAD . So, the kernel will call the thread handler gpio_interrupt_thread_fn . In that threaded IRQ handler, we are toggling the GPIO where the LED has been connected. Please look at the softirq Linux source code below.
Driver Source Code
[Get the full updated source code from GitHub]
Makefile
Testing the Device Driver
- Build the driver by using Makefile ( sudo make )
- Load the driver using sudo insmod driver.ko
- Just press the button or vibrate the vibration sensor.
- That output LED should be toggled (This has been done from the thread function handler).
- Also, check the dmesg.
Output Video
Please find the other Linux device driver tutorials here.
Источник