디바이스 드라이버에서 특정 프로세스에게 주기적인 signal을 보내려고 함니다.
근데 시그널 핸들러를 몇번 수행 하다가 시스템이 죽는 현상이 발생합니다. ㅠ
제가 초보라 무엇이 문제인지 잘 모르겠습니다 .
고수님들의 많은 조언 부탁드립니다 .
아래는 소스코드입니다.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 디바이스 드라이버
시그널을 보내기위해서 해당 프로세스의 정보를 가지고 오려는 ioctl 입니다.
int ioctltest_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {
ioctl_test_info ctrl_info;
int size;
size = _IOC_SIZE( cmd );
printk("size %dn", size);
switch(cmd) {
case IOCTLTEST_WRITE :
copy_from_user ( (void *) &ctrl_info, (const void *) arg, size );
user_pid = (pid_t *)ctrl_info.size;
printk("user pid number %dn", user_pid);
user_struct = find_task_by_pid(user_pid);
printk("OKn");
check_number =1;
break;
}
return 0;
}
struct file_operations ioctltest_fops = {
.owner = THIS_MODULE,
.ioctl = ioctltest_ioctl,
.open = ioctltest_open,
.release = ioctltest_release,
};
......................................
// 여기서 해당 프로세스에게 시그널을 보냅니다.
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
if (check_number == 1 )
{
force_sig(SIGUSR1, user_struct);
//send_sig_info(SIGUSR2,(struct siginfo *)1 ,user_struct);
}
else
{
printk(" signal send not user process n");
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////시그널을 받을 유저 프로세스
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <linux/sched.h>
#include "test.h"
#include <signal.h>
#define name "/dev/test"
struct task_struct *task;
int a =1;
void test_handler() ////////////////////////////////시그널 핸들러
{
printf(" %dn", a++);
}
int main()
{
int fd;
int ret,i;
ioctl_test_info info;
struct task_struct *p;
fd = open(name,O_RDWR|O_NDELAY);
signal(SIGUSR1, (void *)test_handler); ////////////////// 시그널 핸들러 등록
printf("fd : %dn", fd);
info.size = getpid();
printf(" pid %d n", info.size);
ioctl(fd, IOCTLTEST_WRITE , &info.size);
printf( " signal ok %dn", i);
while (1){
}
close(fd);
return 0;
}
댓글 19
-
김태훈
2011.04.06 20:04
-
송창인
2011.04.06 21:02
아 ! 안녕하세요 ㅎㅎ
저번에 많이 지도 해주신 분이시네요 감사합니다.
네 커널에서 특정 프로세스에게 시그날을 보내는것입니다.
위의 코드의 수정을 통해 시그날이 가기는하는데 도중에 죽어버리는 현상이 있습니다 무엇이 문제인지 ....;;;;;
test_handler에서 printf를 빼주니까 3000~4000번 정도의 시그날이 오다가 죽습니다 ㅠ
또한 test_handler는 커널영역인지가 궁금합니다 여기저기 돌아다니면서 찾아본 결과
커널영역이라고 하시는 분이 계서서;;;;
만약 test_handler가 커널영역이라면 ....
커널 영역이아닌 유저 영역에 시그날을 날릴수 있는 방법을 알고 싶습니다
매번 도움을 주셔서 감사드립니다 ㅠㅠ
-
김태훈
2011.04.07 01:40
커널에서 프로세스로 시그널을 발생해야 하는 이유(목적/용도)를 알려고 하는 이유는 일반적으로 커널 <-> 프로세스간 통신때 시그널을 사용하는 것을 본적이 없기 때문입니다. 시그널은 프로세스간 통신(Inter-Process Communication)에 사용됩니다. (물론, 가능은 합니다만...)
시그널 사용 목적을 알려주시면 같은 동작을 하는 다른 방법을 추천 해 드릴려고 했었습니다.
-
송창인
2011.04.07 01:48
감사합니다 ^^
커널에서 쏘는 이유는 주기적인 프로세스로 만들어 주기 위해서입니다
커널에서 주기적인 시그널을 날리게 되면 그걸 받는 프로세스가 주기적으로
동작하게 해주기 위해서입니다
어느정도 실행이 되는것을 확인했지만 어느정도 보내면 시스템이 죽어서
;;;;;;;;;; 찾아본 결과 커널의 스택에 유저의 정보을 올리게 되어 실행이 되는 것으로 알앗는데
스택이 초기화 되면서 유저의 정보를 버린다네요 ㅠㅠ
다른방법이 있으면 알려주세요 ㅠ
-
김남형
2011.04.07 13:36
저 글을 썼던 의도는 시그널 핸들러의 동작 과정을 이해하기 위함이지
이를 실제 프로그램에 반영하기 위한 예제로 생각하시면 곤란합니다.. ;;
-
송창인
2011.04.07 01:54
아 올려 주셨네요 저도 저것을 보고 이해를 했습니다
적용을 해보았지만 frame->sc.eip 에서 에러가 뜨네요 ㅋ
error : dereferencing pointer to incomplete type 가 떠서 찾아보고 있는 중이였습니다 ㅎ
알면 알 수록 어려운 세계네요 ㅎ
-
이상철
2011.04.07 10:08
제 생각엔 signal을 이용하는것보다 디바이스 드라이버 내에서 poll을 구현하시고,
프로세스에서는 poll이나 select를 이용해서 받으면 될거 같습니다.
루프에서 poll이나 select를 사용하면 주기적으로 실행이 가능합니다.
select : 고르다, 뽑다, 고른, 정선한, 선택하다추천:1 댓글
-
이상철
2011.04.11 17:09
네 단지 어떤 이벤트가 왔을때 요청을 기다리던 프로세스에 전달을 하는것이라면 필요 없습니다.
예제로 올린 소스는 단지 poll을 구현한것을 참고하기 위해 올린 것입니다.
그리고 이 소스에서 ioctl은 key입력 할 때 몇개 설정이 되어야 하는 부분이 있어서 사용한것입니다.
-
송창인
2011.04.11 16:09
소스코드 감사드립니다
보면서 많은 것을 느끼게 되었습니다 ㅠ
아직도 이해가 않가는 부분이 있습니다.
poll을 사용하면 ioctl이 필요 없지 않습니까?
-
이상철
2011.04.08 09:06
이전에 만들었던 key입력 드라이버하고 테스트 프로그램 올릴께요.
여기서 poll구현한 부분 참고 하시면 될거 같습니다.
그리고 김남형씨께서 말씀하신대로 구현 하신 소스에 ioctl부분 이상하네요...
-
송창인
2011.04.07 11:32
댓글 감사드립니다
리눅스 초보라 poll 의 방법을 알아보았지만
어떻게 해야할지 감이 안잡히네요 ㅠ
-
김남형
2011.04.07 13:42
위 코드에서 가장 기본적인 문제는 ioctl로 인자를 전달하는 부분에 있는 것 같군요.. ;;
(user process의 info와 kernel의 ctrl_info가 동일한 구조체일 경우)
=== user process ===
info.size = getpid();
ioctl(fd, IOCTLTEST_WRITE , &info.size);=== kernel ===
case IOCTLTEST_WRITE :
copy_from_user ( (void *) &ctrl_info, (const void *) arg, size );
user_pid = (pid_t *)ctrl_info.size;추천:1 댓글
-
송창인
2011.04.11 16:05
아 몇일을 밤샘했더니 ;;;;
정신이 없어서 지금에서야 댓글을 다네요 ㅠ
많은 지적과 관심 감사드립니다 ㅠ
많은 가르침 덕분에에 시스템이 죽는 부분은 어느정도 해결 한거 같습니다 ㅠ
죄송한 말이지만 인자 전달 어느 부분이 문제가 있는지 알려 주실수 있으세요?
그리고 시그널 자체가 많은 시간을 잡아 먹는지 궁금합니다 ㅠ
주기적인 동작을 하지 않아서 또 앉아서 시간과의 싸움을 하고 있네요 ㅠ
-
송창인
2011.04.11 17:57
조금 전 질문이 애매한것 같아서 다시 올리게 됩니다 ;;;
handler_pre가 실질적으로 1ms로 매번 실행되는 함수이고 (이것은 주기적으로 도는것을 확인했습니다)
그함수내에서 signal을 이용하여 유저 프로세스도 마찮가지로 1ms로 동작을 하게 하려는데
유저프로세스의 우선순위를 높여줘도 주기를 벗어 나네요 ;;;;;
그래서 signal 자체의 문제인지 스케줄링의 문제인지
대부분은 주기에 맞게 동작을 하는데 가끔씩 주기를 벗어나서 ;;;;;
-
백창우
2011.04.14 11:55
scheduling 정책에 따라 그럴수도 있습니다. sigwait 하게 되면 해당 task는 ready queue에서 빠지고 wait queue로 이동하게 됩니다.
ready queue, wait queue란 용어에 혼돈하지 마시기바랍니다.
리눅스만 OS가 아니기 때문에 일반적으로 OS 분야에서는 ready queue, wait queue란 용어를 더 많이 사용합니다.
우선 task가 sigwait 하게 되면 reday queue에서 빠져 wait queue에 wait하게 됩니다.
그 상황에서 signal이 도착하면 task는 wait queue에서 wakeup하여 ready queue로 이동하게 됩니다.
이때 scheduling 정책에 따라 해당 task가 다른 task에 의해 바로 수행되지 않을 수도 있습니다.
signal의 원리를 파악하시고, 고민해보십시요.
일반적으로 정확한 동기화를 위해서 signal은 구조적 특성에 의해 거의 사용하지 않습니다.
PS. 스터디라면 signal을 사용해서 무엇을 하는 기능을 구현 할것이 아니라,
signal 자체 매커니즘을 연구해보는게 어떨지 싶네요.
-
송창인
2011.04.14 11:41
흠 sigwait 를 사용해보니 ;;; 시그널을 받는것이 엄청 느리네요;;;;
sigwait를 써야할지 안써야 할지 고민이네요 ;;;
카운터를 사용하여 확인해본결과 오히려 안썼을때 보다 시그널을 더 못받아 오는거 같네요 ;;;
-
백창우
2011.04.14 02:39
먼저 첫 번째 질문의 답은
네. 먼저 온 signal을 잃을 수도 있습니다.
하지만 정말 하고 싶었던 이야기는 signal을 받았다고 해서 task가 바로 반응하지(정확하게 말하면 shinal handler가 동작하지)는 않는다는 것입니다.
두 번째 질문의 답은
sigwait()을 사용하면 동기화가 가능합니다. 위 코드에서는 while(1) {} 안에 sigwait()을 넣어주면 되겠군요.
-
송창인
2011.04.13 22:58
아 감사합니다~!!
과제는 아닙니다 ^^ 공부를 하려다보니 여기 까지 왓네요 ;;; 타이머를 이용해서 1ms로 동작하는것은 확인했습니다.
하지만 윈도우에서 signal을 보내면 됬던것이 리눅스에서는 주기가 깨져서 ;;;
그리고 백창우님께서 말씀하신
"signal 발생 여부의 체크는 system call이 끝나는 순간 이루어지기 때문에, 중간에 system call이 없으면,
process는 signal 발생 여부도 체크하지 않죠." 이 말씀이 시그널을 잃어 버릴수도 있다는 건가요 ?
이해를 못해서;;;;;
동기화 ipc에 관한 부분을 찾아 봐야 겟네요 ㅠㅠ
또한 시그널을 동기화 하게 만들어주는 방법도 있던데 sigwait()인가 그것을 적용해도 안되는건가요?
-
백창우
2011.04.13 22:46
우선 Asynchronous IPC인 signal을 가지고, 주기적으로 동작하게 하는건 불가능합니다.
signal 발생 여부의 체크는 system call이 끝나는 순간 이루어지기 때문에, 중간에 system call이 없으면,
process는 signal 발생 여부도 체크하지 않죠.
결국, 애초에 Asynchronous IPC인 signal로 1ms 주기로 task가 어떤 동작을 하게 하기는 힘들다.
그리고 위 코드 자체에서 어떻게 1ms로 signal을 보내는지도 나타나 있지 않아서 답변해주기도 힘들다.
입니다.
그런데 이거 숙제 안닌가요? 위에도 똑같은 질문을 하신분이 계시군요.
추천:1 댓글
.
커널에서 프로세스로 시그널을 보내려고 하시는 목적이 무엇인가요?
왜냐하면, 용도에 따라 좀 더 깔끔한 디자인이 가능하기 때문입니다.