콘텐츠로 바로가기

now0930 일지

이런저런 생각

  • 홈
  • 비공개
  • 강좌
  • 잔여 작업 조회
  • 위치

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
Kernel Thread – Linux Device Driver Tutorial Part 19

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/

이 글 공유하기:

  • Tweet
발행일 2021-07-24글쓴이 이대원
카테고리 생활코딩 태그 linux, mutex, raspberry, spinlock, 임베디드 리눅스

댓글 남기기응답 취소

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

글 내비게이션

이전 글

timer 실습

다음 글

철까마귀의 날들

2025 5월
일 월 화 수 목 금 토
 123
45678910
11121314151617
18192021222324
25262728293031
4월    

최신 글

  • common mode, differential mode 2025-05-11
  • signal conditioner, 신호 처리기 2025-05-10
  • strain gage 2025-05-09
  • 칼만 필터 2025-05-01
  • positioner(I/P) 2025-04-26

카테고리

  • 산업계측제어기술사
  • 삶 자국
    • 책과 영화
    • 투자
  • 생활코딩
    • LEGO
    • ROS
    • tensorflow
  • 전기기사
  • 피아노 악보

메타

  • 로그인
  • 엔트리 피드
  • 댓글 피드
  • WordPress.org

페이지

  • 소개
  • 잔여 작업 조회
    • 작업 추가
    • 작업의 사진 조회
    • 작업 수정 페이지
  • 사진
    • GPS 입력된 사진
    • 사진 조회
  • 위치
    • 하기 휴가 방문지
    • 해외 출장

태그

android bash c docker driver FSM gps java kernel LEGO linux mysql network program opcua open62541 plc programmers python raspberry reinforcementLearning ros state space system program tensorflow transfer function 경제 미국 민수 삼국지 세계사 실기 에너지 역사 유전자 일본 임베디드 리눅스 전기기사 조선 중국 채윤 코딩 테스트 통계 한국사 한국어

팔로우하세요

  • Facebook
now0930 일지
WordPress로 제작.