spinlock, mutex 실습

모듈을 로딩하면 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/linux-device-drivers-tutorial-kernel-thread/

https://embetronicx.com/tutorials/linux/device-drivers/spinlock-in-linux-kernel-1/

https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-mutex-in-linux-kernel/

코멘트

댓글 남기기

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.