Messages in this thread |  | | From | Luiz Henrique Shigunov <> | Subject | %gs segment register reset when calling signal handler | Date | Thu, 29 Aug 2002 11:23:11 -0300 |
| |
Hi!
I've been working on a program to get process stat from the /proc. The program uses pthreads (linuxthreads) and on 2.4 SMP kernels it always SIGSEGV. It works fine on 2.4 UP kernels and 2.2 UP and SMP kernels.
Investigating the problem I've found that the SIGSEGV always happens on the signal handler of the linuxthreads (pthread_handle_sigrestart). And it happens because the %gs segment register is 0.
Sometimes you'll see that only the main thread will stay alive and the other ones will die.
I've made this little program to test. It will SIGSEGV after 30 min-1 hour on a SMP box. I've tested with this Red Hat box: Linux 2.4.9-21enterprise #1 SMP Thu Jan 17 13:37:56 EST 2002 i686 unknown glibc-2.2.4-29
The work around is to use the /lib/libpthread.so.0 (this one doesn't uses the %gs register) instead of the default /lib/i686/libpthread.so.0. At least on a Red Hat box it works fine.
#include <pthread.h> #include <unistd.h> #include <fcntl.h> #include <limits.h> #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <signal.h>
int walkDir(void) { DIR *dir; struct dirent *de; int file; char path[128],st_comm[17]; pid_t pid,ppid; struct dirent dirbuf;
char st_state; int st_utime,st_stime; int sm_size,sm_resident ,sm_shared ,sm_trs ,sm_lrs ,sm_drs ,sm_dt ;
if (!(dir = ::opendir("/proc"))) { return -1; }
while ((::readdir_r(dir, &dirbuf, &de) == 0) && (de != NULL)) if ((pid = ::atoi(de->d_name))) { ::snprintf(path, sizeof(path), "/proc/%d/stat",pid); if ((file = ::open(path, 0)) >= 0) { char readBuf[512]; size_t num;
num = ::read(file, readBuf, sizeof(readBuf)-1); ::close(file); if (num < 0) { ::perror(path); continue; }
readBuf[num] = 0; char *tailStr; tailStr = ::strrchr(readBuf, ')'); *tailStr = 0; ::memset(st_comm, 0, sizeof(st_comm)); if (::sscanf(readBuf, "%*d (%15c", st_comm) != 1) { continue; } if (::sscanf(tailStr+2, "%c %d %*d %*d %*d %*d %*u %*u %*u %*u %*u %d %d", &st_state,&ppid,&st_utime,&st_stime) != 4) { continue; }
::snprintf(path, sizeof(path), "/proc/%d/statm",pid); if ((file = ::open(path,0)) >= 0) { num = ::read(file, readBuf, sizeof(readBuf)-1); ::close(file); if (num < 0) { ::perror(path); continue; } readBuf[num] = 0; if (::sscanf(readBuf,"%d %d %d %d %d %d %d ", &sm_size,&sm_resident ,&sm_shared ,&sm_trs ,&sm_lrs ,&sm_drs ,&sm_dt) != 7) { ::perror(path); continue; }
int openfiles = 0; ::snprintf(path, sizeof(path), "/proc/%d/fd",pid); DIR *pdir; if ((pdir = ::opendir(path))) { struct dirent *pde; while ((::readdir_r(pdir, &dirbuf, &pde) == 0) && (pde != NULL)) openfiles++; (void) ::closedir(pdir); } }
} } (void) ::closedir(dir); return 0; }
#ifdef MY_SIGNAL pid_t thread_pid, main_pid; int thread_gs, main_gs; void (*old_sigrestart)(int); #endif
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#ifdef MY_SIGNAL static void my_pthread_sigrestart(int sig) { pid_t my_pid; int my_gs;
my_pid = getpid(); __asm__ __volatile__ ("mov %%gs, %0": "=a" (my_gs)); if (my_pid == thread_pid) { if (my_gs != thread_gs) { printf("Thread GS dif!! %d - %d\n", my_gs, thread_gs); exit(1); } } else if (my_pid == main_pid) { if (my_gs != main_gs) { printf("main GS dif!! %d - %d\n", my_gs, main_gs); exit(1); } } else { printf("Other thread!\n"); } old_sigrestart(sig); }
extern "C" int __libc_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); #endif
void *thread_main(void *arg) { #ifdef MY_SIGNAL struct sigaction sa, oldsa;
thread_pid = getpid(); __asm__ __volatile__ ("mov %%gs, %0": "=a" (thread_gs)); sa.sa_handler = my_pthread_sigrestart; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (__libc_sigaction(__SIGRTMIN, &sa, &oldsa)) { perror("sigaction thread"); exit(1); } old_sigrestart = oldsa.sa_handler; #endif while (1) { struct timezone tzone; struct timeval now; struct timespec timeout;
::pthread_mutex_lock(&mutex); ::gettimeofday(&now,&tzone); timeout.tv_sec = now.tv_sec + 4; timeout.tv_nsec = now.tv_usec * 1000; ::pthread_cond_timedwait(&cond, &mutex, &timeout); ::pthread_mutex_unlock(&mutex); } }
int main(int argc, char *argv[]) { pthread_t threadID; #ifdef MY_SIGNAL struct sigaction sa, oldsa; #endif
if (pthread_create(&threadID, NULL, thread_main, NULL)) { perror("pthread"); exit(1); }
#ifdef MY_SIGNAL main_pid = getpid(); __asm__ __volatile__ ("mov %%gs, %0": "=a" (main_gs)); sa.sa_handler = my_pthread_sigrestart; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (__libc_sigaction(__SIGRTMIN, &sa, &oldsa)) { perror("sigaction main"); exit(1); } old_sigrestart = oldsa.sa_handler; #endif while (1) { walkDir(); ::pthread_cond_signal(&cond); ::sleep(3); } }
-- Luiz Henrique Shigunov System Analyst try Automatos - The Automatic MSP @ www.automatos.com - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
|  |