Vì vậy, tôi muốn mô-đun được thực thi trong lõi riêng biệt.
và
thực sự cô lập một lõi cụ thể trong hệ thống của chúng tôi và thực hiện chỉ là một quy trình cụ thể để mà cốt lõi
Đây là một mã nguồn lao động biên soạn và thử nghiệm trên một hộp Debian sử dụng hạt nhân 3.16. Tôi sẽ mô tả làm thế nào để tải và dỡ bỏ đầu tiên và những gì tham số thông qua.
Tất cả các nguồn có thể được tìm thấy trên github đây ...
https://github.com/harryjackson/doc/tree/master/linux/kernel/toy/toy
Xây dựng và nạp module ...
make
insmod toy param_cpu_id=2
Để dỡ bỏ việc sử dụng mô-đun
rmmod toy
Tôi không sử dụng modprobe vì nó mong đợi một số cấu hình, v.v.Tham số mà chúng tôi đang chuyển đến mô-đun hạt nhân toy
là CPU mà chúng tôi muốn tách biệt. Không có thao tác thiết bị nào được gọi sẽ chạy trừ khi chúng đang thực thi trên CPU đó.
Khi các mô-đun được nạp, bạn có thể tìm thấy nó ở đây
/dev/toy
hoạt động đơn giản như
cat /dev/toy
tạo các sự kiện hạt nhân mô-đun bắt và tạo ra một số đầu ra. Bạn có thể xem kết quả bằng cách sử dụng dmesg
.
Source code ...
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harry");
MODULE_DESCRIPTION("toy kernel module");
MODULE_VERSION("0.1");
#define DEVICE_NAME "toy"
#define CLASS_NAME "toy"
static int param_cpu_id;
module_param(param_cpu_id , int, (S_IRUSR | S_IRGRP | S_IROTH));
MODULE_PARM_DESC(param_cpu_id, "CPU ID that operations run on");
//static void bar(void *arg);
//static void foo(void *cpu);
static int toy_open( struct inode *inodep, struct file *fp);
static ssize_t toy_read( struct file *fp , char *buffer, size_t len, loff_t * offset);
static ssize_t toy_write( struct file *fp , const char *buffer, size_t len, loff_t *);
static int toy_release(struct inode *inodep, struct file *fp);
static struct file_operations toy_fops = {
.owner = THIS_MODULE,
.open = toy_open,
.read = toy_read,
.write = toy_write,
.release = toy_release,
};
static struct miscdevice toy_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "toy",
.fops = &toy_fops
};
//static int CPU_IDS[64] = {0};
static int toy_open(struct inode *inodep, struct file *filep) {
int this_cpu = get_cpu();
printk(KERN_INFO "open: called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "open: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "open: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static ssize_t toy_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
int this_cpu = get_cpu();
printk(KERN_INFO "read: called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "read: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "read: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static ssize_t toy_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
int this_cpu = get_cpu();
printk(KERN_INFO "write called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "write: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "write: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static int toy_release(struct inode *inodep, struct file *filep){
int this_cpu = get_cpu();
printk(KERN_INFO "release called on CPU:%d\n", this_cpu);
if(this_cpu == param_cpu_id) {
printk(KERN_INFO "release: is on requested CPU: %d\n", smp_processor_id());
}
else {
printk(KERN_INFO "release: not on requested CPU:%d\n", smp_processor_id());
}
put_cpu();
return 0;
}
static int __init toy_init(void) {
int cpu_id;
if(param_cpu_id < 0 || param_cpu_id > 4) {
printk(KERN_INFO "toy: unable to load module without cpu parameter\n");
return -1;
}
printk(KERN_INFO "toy: loading to device driver, param_cpu_id: %d\n", param_cpu_id);
//preempt_disable(); // See notes below
cpu_id = get_cpu();
printk(KERN_INFO "toy init called and running on CPU: %d\n", cpu_id);
misc_register(&toy_device);
//preempt_enable(); // See notes below
put_cpu();
//smp_call_function_single(1,foo,(void *)(uintptr_t) 1,1);
return 0;
}
static void __exit toy_exit(void) {
misc_deregister(&toy_device);
printk(KERN_INFO "toy exit called\n");
}
module_init(toy_init);
module_exit(toy_exit);
Đoạn mã trên có chứa hai phương pháp mà bạn yêu cầu tức là cô lập của CPU và trên init
chạy trên một lõi riêng biệt.
Bật init get_cpu
vô hiệu hóa việc mua hàng tức là bất kỳ thứ gì xuất hiện sau hạt nhân sẽ không được hạt nhân nạp trước và sẽ chạy trên một lõi. Lưu ý, đây đã được thực hiện kernel sử dụng 3.16, mileage của bạn có thể thay đổi tùy thuộc vào phiên bản kernel của bạn nhưng tôi nghĩ rằng những của API đã được khoảng một thời gian dài
Đây là Makefile ...
obj-m += toy.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Notes. get_cpu
được khai báo trong linux/smp.h
như
#define get_cpu() ({ preempt_disable(); smp_processor_id(); })
#define put_cpu() preempt_enable()
do đó bạn không thực sự cần phải gọi preempt_disable
trước khi gọi get_cpu
. Cuộc gọi get_cpu là một wrapper quanh trình tự sau đây của các cuộc gọi ...
preempt_count_inc();
barrier();
và put_cpu được thực sự làm điều này ...
barrier();
if (unlikely(preempt_count_dec_and_test())) {
__preempt_schedule();
}
Bạn có thể nhận được là ưa thích như bạn thích bằng cách sử dụng trên . Hầu như tất cả những điều này được lấy từ các nguồn sau đây ..
Google cho ... smp_call_function_single
Linux phát triển hạt nhân, cuốn sách của Robert Love.
http://derekmolloy.ie/writing-a-linux-kernel-module-part-2-a-character-device/
https://github.com/vsinitsyn/reverse/blob/master/reverse.c
Đối với ràng buộc chủ đề hạt nhân cụ thể để lõi cụ thể, bạn có thể sử dụng [kthread_bind] (http://lxr.free-electrons.com/source/kernel/kthread.c#L366) hoặc [set_cpu_allowed_ptr] (http://lxr.free-electrons.com/source/kernel/sched/core.c#L1262). Để không cho phép các quy trình khác sử dụng lõi cụ thể, bạn cần phải định cấu hình lịch biểu bằng cách nào đó. Ví dụ: như được mô tả [ở đây] (http://unix.stackexchange.com/questions/186338/setting-system-wide-cpu-affinities-for-running-processes-on-a-linux-platform). – Tsyvarev
Để thêm vào nhận xét của @ Tsyvarev: 'isolcpus' (tham số hạt nhân - xem Tài liệu/kernel-parameters.txt)" có thể được sử dụng để chỉ định một hoặc nhiều CPU tách biệt với các thuật toán cân bằng và lập lịch SMP chung. xử lý lên hoặc tắt một CPU "bị cô lập" thông qua các syscalls CPU hoặc cpuset. " –
@Tsyvarev và @Gil Hamlton. Cảm ơn câu trả lời của bạn. Tôi biết 'kthread_bind'. Về các giải pháp được đề xuất: 'isolcpus' và' maxcpus', từ sự hiểu biết của tôi, các tham số đó nên được sử dụng trong khi khởi động. Tôi muốn cô lập mà không cần khởi động lại, trên thực tế, sự cô lập chỉ xảy ra khi mô-đun được tải, vì vậy tôi cảm thấy đây không phải là cách để đi. – insumity