240228

Yonggeun Park·2024년 2월 28일
0

복습

isr : interrupt service routin
모든 함수, 구조체에 static을 넣어준다

디바이스 드라이버 만들고 실행시키는 법
1. dev파일, Makefile 작성(우분투)
2. make 실행(우분투)
3. mknod로 device 등록(파이) - 안할 시 no such file
4. insmod로 커널에 적재(파이) - 안할 시 no such device
5. sudo ./파일명 으로 실행(파이) - sudo로 안하면 permision denied
6. rmmod로 커널에서 내림(파이)


데이터 영역은 r/w(전역변수), r/o(상수), static가 잡히고
heap 영역은 malloc으로 잡히고
stack 영역은 지역변수가 잡힌다

전역변수는 종료할 때 까지 메모리에 잡혀있다
지역변수로 잡으면 그 지역 내에서만 사용이 가능하다
그래서 heap 영역에 올라가게 해야 효율적이다
typedef는 컴파일 할 때만 있고 사라진다


포인터 변수는 32비트 아키텍쳐에서 4바이트를 나타낸다
대입 연산자는 왼쪽이 오른쪽보다 크기가 크거나 같아야한다
그렇지 않으면 데이터 손실이 일어날 수 있으니 형변환해서 담아야한다

<포인터 사용의 장점>

  • 메모리 주소를 참조해서 다양한 자료형 변수들의 접근과 조작 용이
  • 메모리 주소를 참조하여 배열과 같은 연속된 데이터에 접근과 조작 용이(우리의 경우 heap 영역의 메모리 공간을 모든 시스템 콜 함수에서 접근 가능함->pKeyData)
  • 동적 할당된 메모리 영역(힙 영역)에 접근과 조작 용이
  • 한 함수에서 다른 함수로 배열이나 문자열을 편리하게 보낼 수 있음
  • 복잡한 자료구조를 효율적으로 처리
  • 배열로 생성할 수 없는 데이터를 생성
  • 메모리 공간을 효율적 사용
  • call by reference에 의한 전역 변수의 사용을 억제

힙 영역은 할당하면 free를 해줘야한다
지역변수는 자동으로 사라지기 때문에 auto변수라고도 한다(sp)
매개변수도 지역변수다

char * 배열은 각 글자의 맨 처음글자의 번지수를 리턴한다

어플리케이션은 해제를 안해도 프로세스가 종료되면 회수하는데,
커널은 직접 free를 안하면 아얘 꺼야 종료된다

블록킹 I/O

현재는 실행하고 아무일도 안해도 프로세스의 CPU 점유율이 100%이다
가만 있을 때는 잠들고, 인터럽트가 일어나면 깨어나서 행동하고 다시 잠드는 과정을 반복시킬 것

폴더를 복제한다

~/pi_bsp/drivers$ cp -r p369_ledkey_int_kmalloc p399_ledkey_blockio

스위치를 read 했는데 0이면 키가 안눌린 것이다(데이터가 없다)
그러면 sleep 상태로 보내려 한다

대기 상태로 보냄

리눅스는 기본적으로 blocking으로 열고 NONBLOCK을 잘 사용하지 않음

sleep 상태에서 깬다고 바로 실행하는 것이 아니라 프로세스가 다 끝나야 실행이 된다
read는 많이 대기큐 하지만 write는 잘 안쓰인다

이제 실습해볼 것이다
dev.c 파일을 수정한다

10 #include <linux/wait.h>

36 DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Read);

52     wake_up_interruptible(&WaitQueue_Read);

세개를 수정 및 추가 하고,

read 함수에서 추가해준다

214 //    char kbuf;

222     if(pKeyData->keyNumber == 0)
223     {
224         if(!(filp->f_flags & O_NONBLOCK))
225         {
226//           wait_event_interruptible(WaitQueue_Read, pKeyData->keyNumber);
227         }
228     }

230     put_user(pKeyData->keyNumber,buf);

app.c를 수정한다

NONBLOCK으로 열면 cpu 점유율 100퍼가 되고
없으면 코드가 멈춰버린다

실행하면


top에도 안보이고, sudo cat /proc/kmsg에도 안보이게 잠들어있다

226//           wait_event_interruptible(WaitQueue_Read, pKeyData->keyNumber);
227             wait_event_interruptible_timeout(WaitQueue_Read, pKeyData->keyNu    mber, 100);  // 100*1/HZ = 100*1/100 = 100*0.01 = 1sec

231 //    result = copy_to_user(buf, &(kpKeyData->keyNumber), count);

근데 이렇게 실행하면
top에는 안보이지만 sudo cat /proc/kmsg에 1초에 한번씩 깨어나는 것으로 보인다
어차피 입출력 다중화 함수에서 timeout을 사용할 것이기 때문에 여기서는 다시 주석처리 한다

그리고 이 두 상황은 모두 인터럽트 발생시 정상적으로 깨어난다

입출력 다중화

폴더를 복사한다

~/pi_bsp/drivers$ cp -r p399_ledkey_blockio p432_ledkey_poll

지금 코드는 read에서 잠들어있어서 key를 안눌렀을 때 led를 절대 킬 수 없다
그리고 다음 코드로 넘어갈 수 없다
이제 키보드로 읽어서 led를 키려고 한다

입력은 여러개인데 원하는 실행은 하나인 경우를 멀티플렉스라고 한다

~/pi_bsp/drivers/p432_ledkey_poll$ cp /mnt/lect_nfs/drivers/ledkey_app_poll.c ledkey_app.c

키보드, 디바이스 드라이브 두개를 입력으로 설정한다
app.c 파일을 본다

 19     struct pollfd Events[2];  // 키보드, 디바이스드라이브 두개를 등록할 것이라 2개 선언

 43     fflush(stdin);  // 쓰레기 값 지우기
 44     memset( Events, 0, sizeof(Events));  // 초기화 하는 것
 45     Events[0].fd = fileno(stdin); // 표준입력을 키보드로 등록
 46     Events[0].events = POLLIN;  // 읽기 이벤트 감시하는 것, write는 pollout
 47     Events[1].fd = dev;
 48     Events[1].events = POLLIN;  // 여기까지 등록을 한 것
 
 51         ret = poll(Events, 2, 2000);  // 스위치, 키보드 인터럽트가 없으면 2초마다 깨어남(2000 = 2sec)

그리고 오류가 없거나 입력이 없는 것이 아닐 경우 확인한다

 62         if(Events[0].revents & POLLIN)  //stdin
 63         {
 64             fgets(keyStr,sizeof(keyStr),stdin);
 65             if(keyStr[0] == 'q')
 66                 break;
 67             keyStr[strlen(keyStr)-1] = '\0';  //'\n' clear
 68             printf("STDIN : %s\n",keyStr);
 69             buff = (char)atoi(keyStr);
 70             write(dev,&buff,sizeof(buff));
 71         }
 72         else if(Events[1].revents & POLLIN) //ledkey
 73         {
 74             ret = read(dev,&buff,sizeof(buff));
 75             printf("key_no : %d\n",buff);
 76             if(buff == 8)
 77                 break;
 78             buff = 1 << buff-1;
 79             write(dev,&buff,sizeof(buff));
 80         }

이제 dev.c를 수정할 것이다

11 #include <linux/poll.h>

290     .poll     = ledkey_poll,

file_operations를 검색해서 찾는다

2163     __poll_t (*poll) (struct file *, struct poll_table_struct *);

그래서 다시 dev.c에 가져온다

260 static __poll_t ledkey_poll (struct file * filp, struct poll_table_struct *     wait)
261 {
262     unsigned int mask=0;
263     keyData * pKeyData = (keyData *)filp->private_data;
264 #ifdef DEBUG
265     printk("_key : %u\n",(wait->_key & POLLIN));
266 #endif
267     if(wait->_key & POLLIN)
268         poll_wait(filp, &WaitQueue_Read, wait);
269     if(pKeyData->keyNumber > 0)
270         mask = POLLIN;
271     return mask;
272 }

스위치로 0~8, 키보드로 0~255 입력을 통해 잘 되는 것 확인했다

profile
Dragon_muscle

0개의 댓글

관련 채용 정보