모듈을 로딩하면 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/