Trong mã nguồn nhân Linux, tôi tìm thấy chức năng này:
static int __init clk_disable_unused(void)
{
// some code
}
Ở đây tôi không thể hiểu __init
nghĩa là gì.
Trong mã nguồn nhân Linux, tôi tìm thấy chức năng này:
static int __init clk_disable_unused(void)
{
// some code
}
Ở đây tôi không thể hiểu __init
nghĩa là gì.
Câu trả lời:
include/linux/init.h
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
* as `initialization' functions. The kernel can take this
* as hint that the function is used only during the initialization
* phase and free up used memory resources after
*
* Usage:
* For functions:
*
* You should add __init immediately before the function name, like:
*
* static void __init initme(int x, int y)
* {
* extern int z; z = x * y;
* }
*
* If the function has a prototype somewhere, you can also add
* __init between closing brace of the prototype and semicolon:
*
* extern int initialize_foobar_device(int, int, int) __init;
*
* For initialized data:
* You should insert __initdata between the variable name and equal
* sign followed by value, e.g.:
*
* static int init_variable __initdata = 0;
* static const char linux_logo[] __initconst = { 0x32, 0x36, ... };
*
* Don't forget to initialize data not at file scope, i.e. within a function,
* as gcc otherwise puts the data into the bss section and not into the init
* section.
*
* Also note, that this data cannot be "const".
*/
/* These are for everybody (although not all archs will actually
discard it in modules) */
#define __init __section(.init.text) __cold notrace
#define __initdata __section(.init.data)
#define __initconst __section(.init.rodata)
#define __exitdata __section(.exit.data)
#define __exit_call __used __section(.exitcall.exit)
Đây chỉ là các macro để định vị một số phần của mã linux vào các khu vực đặc biệt trong tệp nhị phân thực thi cuối cùng.
__init
, ví dụ (hoặc tốt hơn là __attribute__ ((__section__
(".init.text")))
macro này mở rộng thành) hướng dẫn trình biên dịch đánh dấu chức năng này theo một cách đặc biệt. Ở phần cuối, trình liên kết thu thập tất cả các hàm có dấu này ở cuối (hoặc đầu) của tệp nhị phân.
Khi hạt nhân khởi động, mã này chỉ chạy một lần (khởi tạo). Sau khi nó chạy, hạt nhân có thể giải phóng bộ nhớ này để sử dụng lại nó và bạn sẽ thấy thông báo hạt nhân:
Giải phóng bộ nhớ nhân không sử dụng: 108k giải phóng
Để sử dụng tính năng này, bạn cần một tệp tập lệnh trình liên kết đặc biệt, tệp này cho trình liên kết biết vị trí của tất cả các chức năng được đánh dấu.
Điều này thể hiện một tính năng của nhân 2.2 trở lên. Lưu ý sự thay đổi trong các định nghĩa của hàm init
và cleanup
. Các __init
vĩ mô gây ra các init
chức năng để được loại bỏ và bộ nhớ của nó được giải phóng khi init
kết thúc chức năng được xây dựng trong trình điều khiển, nhưng không phải module khả nạp. Nếu bạn nghĩ về thời điểm init
hàm được gọi, điều này hoàn toàn hợp lý.
__init là một macro được định nghĩa trong ./include/linux/init.h mở rộng thành __attribute__ ((__section__(".init.text")))
.
Nó hướng dẫn trình biên dịch đánh dấu chức năng này theo một cách đặc biệt. Ở phần cuối, trình liên kết thu thập tất cả các hàm có dấu này ở cuối (hoặc đầu) của tệp nhị phân. Khi hạt nhân khởi động, mã này chỉ chạy một lần (khởi tạo). Sau khi nó chạy, kernel có thể giải phóng bộ nhớ này để sử dụng lại và bạn sẽ thấy kernel
Đọc bình luận (và tài liệu cùng một lúc) trong linux / init.h .
Bạn cũng nên biết rằng gcc có một số phần mở rộng được tạo đặc biệt cho mã nhân linux và có vẻ như macro này sử dụng một trong số chúng.
Khi bạn biên dịch và chèn một mô-đun nhân Linux vào nhân, chức năng đầu tiên được thực thi là __init, về cơ bản, chức năng này được sử dụng để thực hiện khởi tạo trước khi bạn thực hiện các thao tác chính như đăng ký trình điều khiển thiết bị, v.v., Có một chức năng khác có tác dụng ngược lại __exit được gọi khi bạn loại bỏ mô-đun hạt nhân được sử dụng lại để xóa một số thiết bị đã đăng ký hoặc bất kỳ chức năng tương tự nào