통신중 SIGSEGV(세그먼트에러) ...고수님에 도움을....
if(0 == readable_timeo(cam_s, 15)) break;
if((str_len = recv(cam_s, stream, nsize, MSG_WAITALL)) < nsize){
if(str_len==-1){
perror("CAM STREAM DATA RECV ERROR");
search->cam_sid = 0;
}
sd = (STREAM_DATA *)buff_s;
nsize = ntohs(sd->size);
printf(" stream data size : %d\n", nsize);
if(0 == writeable_timeo(hp_s, 15)) break;
if((str_len = send(hp_s, buff_s, buffsize_s, 0)) < buffsize_s) {
perror("HP DATA HEAD SEND ERROR");
break;
}
첫번째 에러 출력부분(truss)
send(95, "F0E104 Y", 4, 0) = 4
Incurred fault #6, FLTBOUNDS %pc = 0xFF145850
siginfo: SIGSEGV SEGV_MAPERR addr=0x0000014C
Received signal #11, SIGSEGV [caught]
siginfo: SIGSEGV SEGV_MAPERR addr=0x0000014C
두번째 에러 출력부분
write(1, " - e n 1 3 -".., 46) = 46
Incurred fault #6, FLTBOUNDS %pc = 0xFED03388
siginfo: SIGSEGV SEGV_MAPERR addr=0x00000010
Received signal #11, SIGSEGV [caught]
siginfo: SIGSEGV SEGV_MAPERR addr=0x00000010
sigprocmask(SIG_SETMASK, 0xFE9EEFE8, 0x00000000) = 0
sigaction(SIGSEGV, 0xFB2009C0, 0x00000000) = 0
sigprocmask(SIG_SETMASK, 0xFE9FADB8, 0x00000000) = 0
setcontext(0xFB200B78)
Incurred fault #6, FLTBOUNDS %pc = 0xFED03388
siginfo: SIGSEGV SEGV_MAPERR addr=0x00000010
Received signal #11, SIGSEGV [default]
siginfo: SIGSEGV SEGV_MAPERR addr=0x00000010
*** process killed ***
여러 쓰레드를 통한 recv, send 작업을 하는 프로그램입니다.
잘 되다가 쓰레드가 한 60개에서 70개 정도 붙을때 나는 경우가 많고 20안팎인때 발생하는 경우도 있습니다.
truss로 찍어보았는데 원인을 찾을 수가 없습니다.
짐작가는바가 있으시면 말씀해주시면 감사하겠습니다.
sigprocmask는 thread safety 함수가 아닙니다.
sigprocmask 대신에 pthread_sigmask를 사용하시기 바랍니다. sigwait 로 시그널을 처리하는게 쓰레드의 일반적인 시그널 처리입니다.
========================================
* The truth will set you free.
무슨 말이신지?
sigprocmask(SIG_SETMASK, 0xFE9FADB8, 0x00000000) = 0
sigprocmask()는 제가 준게 아닌데요?
제가 준게 아닌데 삽입되어 있네요.. ㅠ.ㅠ
참고로 시그널은 음...
process : signal(SIGPIPE, fun);
thread : act.sa_handler = fun;
sigaction(SIGPIPE, &act, NULL);
이렇게만 주는데요...
무슨 말씀이신지?
쓰레드 환경에서의 시그널을 잘못알고 계신듯합니다.
쓰레드 환경에선 기존에서 쓰는 sigaction 이나 signal을 쓰지 않습니다. 굳이 쓴다면 시스템 종료 프로세스에서만 사용합니다.
따라서 쓰레드에선 시그널 전담 쓰레드를 만들고, pthread_sigmask 로 블록한 상태에서 sigwait 로 처리하셔야 합니다. 그리고 signal() 함수를 사용하는 것은 좋지 못한 습관입니다. 시스템에 따라서 한번 핸들러가 호출된 뒤에 SIG_DFL로 바뀔수 있습니다.
PS) 그리고 잠깐 다른곳을 보니 같은 질문을 3개나 올리셨더군요. 한곳에 올리시는게 맞습니다. 다른 질문도 보니까 다 쓰레드에서의 시그널 처리때문에 발생하는 문제인것 같군요. 중복질문은 답변들이 중복될 수 있습니다. 급하신 마음은 알지만 조금은 신경써주시면 좋겠네요
========================================
* The truth will set you free.
네...
먼저 답변에 감사드리고 조언에 감사드립니다.
조심하겠습니다.
님이 말씀하시대로
sigemptyset(&new);
sigaddset(&new, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &new, NULL);
이렇게 SIGSEGV를 설정하였습니다.
이렇게 설정을 해도 결과는 변함이 없네요
프로세스가 죽어버립니다.
truss로 확인해보니 SIGSEGV가 원인이네요
제 생각에 SIGSEGV 발생할만한 경우로는 DB Connect와 DB작업이 의심이 되고 그 외에는 잘 모르겠네요
참고로 db는 오라클입니다.
근본적인 해결 방안이 궁금합니다.
제 말씀을 오해하신듯...
SIGSEGV는 블록할 수 있는 에러가 아닙니다.
제가 올린 글중에 시그널에 대한 글이 있으니 그것을 읽어보시기 바랍니다. 각 시그널별로 블록해야 될것이 있고 아닌 것이 있습니다. SEGV는 Segmentation Violation으로 메모리 침범으로 죽은 것입니다. 따라서 죽여야 당연한 것이죠. 블록한다고 안죽진 않습니다. 그리고 SIGSEGV가 나타나는 이유는 다른 이유이며 위에서 말씀드렸듯이 다른 시그널, 혹은 동기화가 보장되지 않는 곳에서의 작업으로 인한 것입니다. 쓰레드를 많이 만들어서 사용할때는 서로의 쓰레드가 독립적입을 보장받기 위해서 서로다른 영역을 참조하든지 혹은 동기화를 통하지 않을경우엔 SIGSEGV가 꼭 발생합니다. DB가 의심스럽다는 것은 아마도 DB 커넥션을 공유해서 발생하는 문제인듯 싶습니다.
========================================
* The truth will set you free.
컴파일 옵션의 -D_REENTRANT 가 되었는지의 확인을 해보셨으면 합
컴파일 옵션의 -D_REENTRANT 가 되었는지의 확인을 해보셨으면 합니다.
0xFF145850 에서 허용되지 않은 범위인 0x0000014C 로의 접근이니,
변수들이나 기타 등에 문제가 있을 수도 있으니 확인 해보셔야 할 듯 하군요.
여담으로 Pro*C 로 짜여진 어플리케이션등에 하지 말아야 할 것이라던지
mt 프로그램에서 쓰이지 않아야 할 것들이 쓰인것은 없는지 확인 해보셨으면
합니다. 또 스트링에 NULL이 있는 부분에서 str함수를 썼다든지 등등이요.
sun인듯하니 dbx와 core 혹은 gdb로 체크를 해보셨으면 하고요, 이정도의
정보로는 뭐든 알아내기 힘들것 입니다..
댓글 달기