모듈을 로딩하면 kernel thread부터 만들어야 한다. 같은 책 초반에 나왔는데, 다시 보니 기억할 수 없다. 스레드를 만든 후 함수와 데이터를 넘겨야 하는데, 데이터가 void 포인터다. struct로 캐스팅 하고 싶은데, 에러가 났다. kernel 코드를 보고 괄호를 몇 번 붙였다. 아! ㅅㅂ. 구글 찾아보기보다 시(간)성비가 더 좋다.
pi@raspberrypi:~/linux $ grep -wn "kthread_create" -r ./drivers ./drivers/usb/usbip/usbip_common.h:285: = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \ ./drivers/usb/atm/ueagle-atm.c:2228: sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm"); ./drivers/usb/atm/usbatm.c:977: t = kthread_create(usbatm_do_heavy_init, instance, "%s", ./drivers/usb/gadget/file_storage.c:3527: fsg->thread_task = kthread_create(fsg_main_thread, fsg, ./drivers/usb/gadget/function/u_serial.c:1059: info->console_thread = kthread_create(gs_console_thread, ./drivers/usb/gadget/function/f_mass_storage.c:2924: kthread_create(fsg_main_thread, common, "file-storage"); ./drivers/usb/host/dwc_common_port/dwc_common_fbsd.c:981: retval = kthread_create((void (*)(void *))func, data, &thread->proc, ./drivers/iio/adc/ina2xx-adc.c:840: task = kthread_create(ina2xx_capture_thread, (void *)indio_dev, pi@raspberrypi:~/linux $ vi ./drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data) { int retval; dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread)); if (!thread) { return NULL; } thread->abort = 0; retval = kthread_create((void (*)(void *))func, data, &thread->proc, RFPROC | RFNOWAIT, 0, "%s", name); if (retval) { DWC_FREE(thread); return NULL; } return thread; }
spinlock을 만든 후 초기화 하지 않으면, 사용할 수 없다. kernel에 메모리를 할당 받으면 초기화는 꼭 해줘야 하는 느낌이다.
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/gpio.h> //GPIO #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/fcntl.h> #define GPIO_10_OUT (10) #define DEVICE_DATA_MAX 256 #include <linux/kthread.h> #include <linux/delay.h> #include <linux/spinlock.h> unsigned int GPIO_irqNumber; /*사용자 데이터 부분*/ struct my_device_data{ struct cdev cdev; int index; char my_string[DEVICE_DATA_MAX]; struct timer_list simple_timer; spinlock_t lock; struct task_struct *kthread1; struct task_struct *kthread2; } ; int run_this_thread1(void* data); int run_this_thread2(void* data); int run_this_thread1(void* data) { //while(1)로 하면 kthread_stop을 할 수 없음. //루프가 없으면 kthread_stop을 불렀을 경우, segment error. //thread가 없다면, 종료를 할 수 없어 보임.. while(!kthread_should_stop()) { //data is my_device_data struct my_device_data *ptr_main_data; //ptr_main_data = data; ptr_main_data = (struct my_device_data(*))data; //공통이 구조체 접근. spin_lock(&ptr_main_data->lock); ptr_main_data->index++; //pr_info("spin lock is %0x\n",ptr_main_data->lock); pr_info("==============\n"); pr_info("[+]index is %d\n", ptr_main_data->index); pr_info("==============\n"); spin_unlock(&ptr_main_data->lock); //pr_info("spin lock is %0x\n",ptr_main_data->lock); msleep(500); } return 0; } int run_this_thread2(void* data) { while(!kthread_should_stop()) { //data is my_device_data struct my_device_data *ptr_main_data; ptr_main_data = (struct my_device_data(*))data; // //공통이 구조체 접근. spin_lock(&ptr_main_data->lock); ptr_main_data->index++; pr_info("==============\n"); pr_info("[+]index is %d\n", ptr_main_data->index); pr_info("==============\n"); spin_unlock(&ptr_main_data->lock); msleep(500); } return 0; } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) { /*Scheduling work queue*/ return IRQ_HANDLED; } //device driver 작성 부분. /*************드라이버 함수 ******************/ static int mydriver_open(struct inode *inode, struct file *file); static int mydriver_release(struct inode *inode, struct file *file); static ssize_t mydriver_read(struct file *flip, char *buf, size_t len, loff_t *off); static ssize_t mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off); /********************************************/ //file operation structure static struct file_operations fops = { .owner = THIS_MODULE, .read = mydriver_read, .write = mydriver_write, .open = mydriver_open, .release = mydriver_release, }; static int mydriver_open(struct inode *inode, struct file *file) { pr_info("Deviced file was opend.\n"); return 0; } static int mydriver_release(struct inode *inode, struct file *file) { pr_info("Deviced file was closed.\n"); return 0; } static int mydriver_read(struct file *file, char *buf, size_t len, loff_t *off) { pr_info("read\n"); return 0; } static int mydriver_write(struct file *flip, const char *buf, size_t len, loff_t *off) { return 0; } dev_t dev = 0; static struct cdev my_cdev; static struct class *dev_class; struct my_device_data *main_data; static int __init init_hw(void) { //디바이스 등록 if(( alloc_chrdev_region(&dev, 0, 1, "test_device") < 0)) { pr_err("[!]character device was not allocated\n"); goto r_unreg; } pr_info("[=]%d-%d, was allocated\n", MAJOR(dev), MINOR(dev)); //초기화 cdev_init(&my_cdev, &fops); pr_info("[=]driver was initialized\n"); //시스템에 추가 if((cdev_add(&my_cdev, dev, 1)) < 0) { pr_err("[!]cannot add device to kernel\n"); goto r_del; } //class 만듦. if((dev_class=class_create(THIS_MODULE, "my_class")) == NULL) { pr_err("[!]cannot add class\n"); goto r_class; } if((device_create(dev_class, NULL, dev, NULL, "my_device")) == NULL) { pr_err("[!]cannot create device\n"); goto r_device; } //gpio 10번을 사용. //export하여 간단히 사용. //입력은 값을 써 넣을 수 없음. 출력으로 설정. GPIO_irqNumber = gpio_to_irq(GPIO_10_OUT); pr_info("[=]irq %d was assinged\n",GPIO_irqNumber); //interrupt 등록 필요 if (request_irq(GPIO_irqNumber, (void*)gpio_irq_handler, IRQF_TRIGGER_RISING, "my_device", NULL)) { pr_err("[!]my_device: cannot register IRQ\n"); goto r_gpio; } pr_info("[=]module was installed\n"); //메모리 공간 할당. main_data = kmalloc(sizeof(struct my_device_data), GFP_KERNEL); //spin lock init spin_lock_init(&main_data->lock); main_data->index=0; if(!main_data) { pr_err("[!]cannot alloc memory\n"); goto r_memory; } pr_info("[=]got memory\n"); //thread create. main_data->kthread1 = kthread_create(run_this_thread1, main_data, "my_thread1"); main_data->kthread2 = kthread_create(run_this_thread2, main_data, "my_thread2"); if(main_data->kthread1) { wake_up_process(main_data->kthread1); pr_info("wake up thread1 at %p\n", main_data->kthread1); } if(main_data->kthread2) { wake_up_process(main_data->kthread2); pr_info("wake up thread2 at %p\n", main_data->kthread2); } return 0; r_gpio: gpio_free(GPIO_10_OUT); r_device: device_destroy(dev_class,dev); r_class: class_destroy(dev_class); r_del: cdev_del(&my_cdev); r_unreg: unregister_chrdev_region(dev,1); r_memory: ; return -1; } static void __exit exit_hw(void) { free_irq(GPIO_irqNumber, NULL); gpio_free(GPIO_10_OUT); //flush_work(struct work_struct *work); device_destroy(dev_class,dev); //class_unregister(dev_class); class_destroy(dev_class); cdev_del(&my_cdev); unregister_chrdev_region(dev,1); if(main_data->kthread1) kthread_stop(main_data->kthread1); if(main_data->kthread2) kthread_stop(main_data->kthread2); pr_info("kthread was stopped\n"); pr_info("wake up thread1 at %p\n", main_data->kthread1); pr_info("wake up thread2 at %p\n", main_data->kthread2); kfree(main_data); printk(KERN_INFO "module was removed\n"); } module_init(init_hw); module_exit(exit_hw); MODULE_LICENSE("GPL"); MODULE_AUTHOR("noname"); MODULE_DESCRIPTION("Hello, world!");
spin lock을 적용하지 않을 경우, 겹쳐쓴다. 적용하면 순서대로 실행된다 믿는다.
[ 1749.848372] ============== [ 1749.848376] [+]index is 108 [ 1749.848380] ============== [ 1750.378381] ============== [ 1750.378392] [+]index is 109 [ 1750.378399] ============== [ 1750.378414] ============== [ 1750.378421] [+]index is 110 [ 1750.378428] ============== [ 1750.898416] ============== [ 1750.898431] [+]index is 111 [ 1750.898439] ============== [ 1750.898461] ============== [ 1750.898470] [+]index is 112 [ 1750.898478] ============== [ 1751.418404] ============== [ 1751.418417] [+]index is 113 [ 1751.418426] ============== [ 1751.418446] ============== [ 1751.418455] [+]index is 114 [ 1751.418463] ============== [ 1751.938485] ============== [ 1751.938501] [+]index is 115 [ 1751.938512] ============== [ 1751.938537] ============== [ 1751.938547] [+]index is 116 [ 1751.938556] ============== [ 1752.458509] ============== [ 1752.458529] [+]index is 117 [ 1752.458538] ============== [ 1752.458560] ============== [ 1752.458570] [+]index is 118 [ 1752.458578] ============== [ 1752.978388] ============== [ 1752.978394] [+]index is 119 [ 1752.978398] ============== [ 1753.498497] kthread was stopped [ 1753.498515] wake up thread1 at 39208d2a [ 1753.498524] wake up thread2 at 5bdf5278 [ 1753.498536] module was removed [ 1773.404079] [=]236-0, was allocated [ 1773.404089] [=]driver was initialized [ 1773.406890] [=]irq 54 was assinged [ 1773.406942] [=]module was installed [ 1773.406952] [=]got memory [ 1773.410837] wake up thread1 at 6acc0d97 [ 1773.410859] wake up thread2 at 9613521a [ 1773.411132] ============== [ 1773.411143] [+]index is 1 [ 1773.411151] ============== [ 1773.411794] ============== [ 1773.411805] [+]index is 2 [ 1773.411812] ============== [ 1773.528622] ============== [ 1773.528626] ============== [ 1773.528636] [+]index is 4 [ 1773.528637] [+]index is 4 [ 1773.528640] ============== [ 1773.528641] ============== [ 1773.648584] ============== [ 1773.648585] ============== [ 1773.648589] [+]index is 6 [ 1773.648590] [+]index is 6 [ 1773.648593] ============== [ 1773.648594] ============== [ 1773.768583] ============== [ 1773.768584] ============== [ 1773.768588] [+]index is 8 [ 1773.768589] [+]index is 8 [ 1773.768591] ============== [ 1773.768594] ============== [ 1773.888583] ============== [ 1773.888587] [+]index is 9 [ 1773.888589] ============== [ 1773.888591] ============== [ 1773.888595] [+]index is 10 [ 1773.888598] ============== [ 1774.008583] ============== [ 1774.008585] ============== [ 1774.008588] [+]index is 12 [ 1774.008591] [+]index is 12 [ 1774.008594] ============== [ 1774.008596] ============== [ 1774.128592] ============== [ 1774.128593] ============== [ 1774.128597] [+]index is 14 [ 1774.128599] [+]index is 14 [ 1774.128601] ============== [ 1774.128604] ============== [ 1774.248635] ============== [ 1774.248638] ============== [ 1774.248648] [+]index is 16 [ 1774.248652] [+]index is 16 [ 1774.248657] ============== [ 1774.248663] ============== [ 1774.368631] ============== [ 1774.368642] [+]index is 17 [ 1774.368649] ============== [ 1774.378613] ============== [ 1774.378622] [+]index is 18
https://embetronicx.com/tutorials/linux/device-drivers/spinlock-in-linux-kernel-1/