Familiarity with C++ means that students should be well-acquainted with std::unique_ptr, which is one of the smart pointers used in C++ to manage the lifecycle of dynamically allocated memory. Its core design principles are twofold: first, when a smart pointer goes out of scope, the memory it points to is automatically released, thus avoiding memory leaks caused by programmers forgetting to free memory; second, it has exclusive ownership, meaning that ownership of the memory pointed to by a smart pointer can be transferred (moved) from one std::unique_ptr to another. After the transfer, the original pointer becomes nullptr, and the new pointer becomes the sole owner of that memory, ensuring that at any given time, only one smart pointer owns that memory. In fact, a similar mechanism exists in the Linux kernel, which is written in C. This article will introduce the concept of “smart pointers” in the Linux kernel.In the Linux kernel source code header file include/linux/cleanup.h, there is a macro called __free. When we allocate a block of memory in kernel or kernel module code, we can use this macro to decorate the pointer variable pointing to that memory, and we can specify a memory release function through this macro. When this pointer goes out of its variable scope, the specified memory release function will beautomatically called to free that memory, without the programmer having to explicitly call the memory release function. Let’s look at a simple example.
In the above function, we first use kmalloc to allocate a block of memory of one page size (4K) and let the buffer pointer variable point to this memory. Unlike our usual writing style, this buffer pointer variable is followed by __free(kfree), making this buffer pointer a “smart pointer”. When the test_smart_pointer_1 function exits, the kernel will automatically call the kfree function to release the memory pointed to by buffer, so we do not need to manually call kfree, thus avoiding memory leaks due to negligence in calling kfree. It is important to note that the memory release function specified by __free must be paired with the memory allocation function.This example corresponds to the first characteristic of C++’s std::unique_ptr, where the memory pointed to by the smart pointer is automatically released when the smart pointer variable goes out of scope. Next, let’s see how this smart pointer in the Linux kernel ensures exclusive ownership and transfers ownership between smart pointers.
In the example code above, we first allocate a block of memory using the function alloc_and_init_randomly and point a smart pointer to this memory. We then perform random initialization on this memory and check the data within it. If any of the previously generated data is greater than or equal to 255, we consider the initialization to have failed (this is merely an example of initializing memory or objects, and the practicality of this initialization code is not the focus here), and we directly return NULL. At this point, this memory will be automatically released because thissmart pointer is about to go out of scope. If all previously generated random numbers are less than 255, we consider the initialization successful and need to return this memory to the outer function (test_smart_pointer_2) for use. Therefore, we need to use the macro return_ptr to return this pointer (buffer), and in the function test_smart_pointer_2, we also need to use another smart pointer to take over the ownership of this memory, thus completing the transfer of ownership of this memory. Subsequently, when the outer function test_smart_pointer_2 exits after using this memory, this memory will be automatically released. Of course, you could also use a regular pointer in the outer function to receive the return value of the function alloc_and_init_randomly, which would eliminate the smart pointer’s features, requiring you to manually call kfree to release this memory. While this approach is functionally correct, it undermines the smart pointer concept provided by the kernel.Now, let’s briefly look at the principles behind this smart pointer in the Linux kernel. It can be seen that this macro is actually implemented by __cleanup, which is a GCC compilerextension. When the compiler encounters a variable decorated with __cleanup, it automatically inserts a call to the specified cleanup function at the end of the variable’s scope (i.e., at the right curly brace }).__cleanup allows C programmers to simulate the RAII (Resource Acquisition Is Initialization) effect of C++ to some extent.
The “smart pointers” in the Linux kernel provide automated guarantees for the cleanup of local resources, simplifying error handling processes and helping kernel developers write more robust and concise code. Although it is not as powerful and versatile as C++ smart pointers, within its design goals (managing the lifecycle of stack pointers), it is a very effective and clever tool.