|
Linux glibc pthread, Seg fault при использовании. |
|
|
|
Feb 28 2007, 19:14
|
Знающий
   
Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847

|
Доброго времени суток! Постановка задачи: Есть драйвер, имитирующий работу устройства. В драйвере функция read поверяет готовность данных, и если данные не готовы, то выпадает в sleep. Далее по таймеру имитируется поступление данных, и "будится" очередь. Есть программа, которая читает данные из устройства. При использовании отдельного потока на чтение, ПОСЛЕ УСПЕШНОГО ВЫПОЛНЕНИЯ чтений и вывода результатов программа завершается, НО часть процессов в системе начинает получать SIGSEGV. Сама программа никогда не получает этого сигнала и всегда успешно выполняется. Если не использовать отдельный поток, то все работает. linux-2.6.15 и linux-2.6.19 glibc-2.3.6 glibc-linuxthreads-2..3.6 gcc-3.4.5 Функция таймера в модуле: Код static void simple_wait_timer(unsigned long data) { int i; struct simple_device *dev = (struct simple_device *)data; dev->timer.expires += SIMPLE_TIMEOUT; dev->ipos += SIMPLE_RX_TRANSFER; if (dev->ipos >= SIMPLE_IN_SIZE) dev->ipos = 0; for (i = dev->ipos; i < dev->ipos + SIMPLE_RX_TRANSFER; i++) dev->ibuf[i] = dev->val + i; dev->val += SIMPLE_RX_TRANSFER; atomic_set(&dev->rx_ready, 1); wake_up_interruptible(&dev->rx_queue); add_timer(&dev->timer); } Функция чтения в модуле: Код static ssize_t simple_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) { int retval = 0; struct simple_device *dev = simple_devs[iminor(filp->f_dentry->d_inode)]; int pos; TRACE; if (count < (SIMPLE_RX_TRANSFER * sizeof(int))) { return -ENOMEM; } if (atomic_read(&dev->rx_ready) != 1) { interruptible_sleep_on(&dev->rx_queue); PDEBUG("awake\n"); } pos = dev->ipos; retval = copy_to_user(buf, &dev->ibuf[pos], SIMPLE_RX_TRANSFER * sizeof(int)); if (retval) { PERROR("Copied less data then requested!\n"); retval = -EFAULT; } else { retval = SIMPLE_RX_TRANSFER * sizeof(int); } atomic_set(&dev->rx_ready, 0); return retval; } Программа: Код #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> #include <sys/time.h> #include <errno.h>
#define DEVICE_NAME "/dev/simple/simple0" #define BUFSIZE (256 * sizeof(int))
#define PDEBUG(fmt, arg...) fprintf(stderr, fmt, ##arg)
int loop = 0; char buf[65536];
void *read_thread(void *arg) { int fd = *((int *)arg); int retval; int i; int len; char s[256];
i = 0; while (loop) { retval = read(fd, buf, sizeof(buf)); if (retval < 0) { fprintf(stderr, "Error reading device: %s\n", strerror(errno)); return NULL; } if (retval == (sizeof(int) * 256)) { write(1, "R", 1); } else { write(1, "r", 1); len = sprintf(s, "\n%d\n", retval); write(1, s, len); return NULL; } }
return NULL; }
void *write_thread(void *arg) { /* int i; int d = *((int *)arg) + 0x30;
fprintf(stderr, "Thread for write started "); for (i = 0; i < 10000; i++) write(1, (char *) &d, 1); */ return NULL; }
int main(int argc, char *argv[]) { int retcode; void *retval; pthread_t th_a; int fdr; int fdw; int i; struct timeval tv, tc;
printf("Hello, world!\n");
fdr = open(DEVICE_NAME, O_RDONLY); if (fdr < 0) { perror("Can not open device"); return 1; } fprintf(stderr, "%d\n", fdr);
loop = 1;
retcode = pthread_create(&th_a, NULL, read_thread, (void *) &fdr); if (retcode) { perror("Thread for read creation failed"); } for (i = 0; i < 64; i++) { write(1, ".", 1); gettimeofday(&tv, 0); tc.tv_sec = tv.tv_sec; tc.tv_usec = tv.tv_usec; while (((tc.tv_sec * 1000000 + tc.tv_usec) - (tv.tv_sec * 1000000 + tv.tv_usec)) < 100000) gettimeofday(&tc, 0); } loop = 0;
retcode = pthread_join(th_a, &retval); if (retcode) { perror("Joining of thread for read failed"); }
close(fdr);
printf("\n");
for (i = 0; i < 256; i++) { if (!(i & 7)) printf("%5d:\t", i); printf(" 0x%08X", ((int *)buf)[i]); if ((i & 7) == 7) printf("\n"); }
return 0; } Может ли кто нибудь найти в чем ошибка?
--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть. © Lewis Carroll. Alice's adventures in wonderland.
|
|
|
|
|
 |
Ответов
(1 - 3)
|
Mar 1 2007, 22:24
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 10-10-06
Пользователь №: 21 161

|
Цитата(amw @ Feb 28 2007, 18:14)  Доброго времени суток! Постановка задачи: Есть драйвер, имитирующий работу устройства. В драйвере функция read поверяет готовность данных, и если данные не готовы, то выпадает в sleep. Далее по таймеру имитируется поступление данных, и "будится" очередь. Есть программа, которая читает данные из устройства. При использовании отдельного потока на чтение, ПОСЛЕ УСПЕШНОГО ВЫПОЛНЕНИЯ чтений и вывода результатов программа завершается, НО часть процессов в системе начинает получать SIGSEGV. Сама программа никогда не получает этого сигнала и всегда успешно выполняется. Если не использовать отдельный поток, то все работает. linux-2.6.15 и linux-2.6.19 glibc-2.3.6 glibc-linuxthreads-2..3.6 gcc-3.4.5 Функция таймера в модуле: Код static void simple_wait_timer(unsigned long data) { int i; struct simple_device *dev = (struct simple_device *)data; dev->timer.expires += SIMPLE_TIMEOUT; dev->ipos += SIMPLE_RX_TRANSFER; if (dev->ipos >= SIMPLE_IN_SIZE) dev->ipos = 0; for (i = dev->ipos; i < dev->ipos + SIMPLE_RX_TRANSFER; i++) dev->ibuf[i] = dev->val + i; dev->val += SIMPLE_RX_TRANSFER; atomic_set(&dev->rx_ready, 1); wake_up_interruptible(&dev->rx_queue); add_timer(&dev->timer); } Функция чтения в модуле: Код static ssize_t simple_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) { int retval = 0; struct simple_device *dev = simple_devs[iminor(filp->f_dentry->d_inode)]; int pos; TRACE; if (count < (SIMPLE_RX_TRANSFER * sizeof(int))) { return -ENOMEM; } if (atomic_read(&dev->rx_ready) != 1) { interruptible_sleep_on(&dev->rx_queue); PDEBUG("awake\n"); } pos = dev->ipos; retval = copy_to_user(buf, &dev->ibuf[pos], SIMPLE_RX_TRANSFER * sizeof(int)); if (retval) { PERROR("Copied less data then requested!\n"); retval = -EFAULT; } else { retval = SIMPLE_RX_TRANSFER * sizeof(int); } atomic_set(&dev->rx_ready, 0); return retval; } Программа: Код #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> #include <sys/time.h> #include <errno.h>
#define DEVICE_NAME "/dev/simple/simple0" #define BUFSIZE (256 * sizeof(int))
#define PDEBUG(fmt, arg...) fprintf(stderr, fmt, ##arg)
int loop = 0; char buf[65536];
void *read_thread(void *arg) { int fd = *((int *)arg); int retval; int i; int len; char s[256];
i = 0; while (loop) { retval = read(fd, buf, sizeof(buf)); if (retval < 0) { fprintf(stderr, "Error reading device: %s\n", strerror(errno)); return NULL; } if (retval == (sizeof(int) * 256)) { write(1, "R", 1); } else { write(1, "r", 1); len = sprintf(s, "\n%d\n", retval); write(1, s, len); return NULL; } }
return NULL; }
void *write_thread(void *arg) { /* int i; int d = *((int *)arg) + 0x30;
fprintf(stderr, "Thread for write started "); for (i = 0; i < 10000; i++) write(1, (char *) &d, 1); */ return NULL; }
int main(int argc, char *argv[]) { int retcode; void *retval; pthread_t th_a; int fdr; int fdw; int i; struct timeval tv, tc;
printf("Hello, world!\n");
fdr = open(DEVICE_NAME, O_RDONLY); if (fdr < 0) { perror("Can not open device"); return 1; } fprintf(stderr, "%d\n", fdr);
loop = 1;
retcode = pthread_create(&th_a, NULL, read_thread, (void *) &fdr); if (retcode) { perror("Thread for read creation failed"); } for (i = 0; i < 64; i++) { write(1, ".", 1); gettimeofday(&tv, 0); tc.tv_sec = tv.tv_sec; tc.tv_usec = tv.tv_usec; while (((tc.tv_sec * 1000000 + tc.tv_usec) - (tv.tv_sec * 1000000 + tv.tv_usec)) < 100000) gettimeofday(&tc, 0); } loop = 0;
retcode = pthread_join(th_a, &retval); if (retcode) { perror("Joining of thread for read failed"); }
close(fdr);
printf("\n");
for (i = 0; i < 256; i++) { if (!(i & 7)) printf("%5d:\t", i); printf(" 0x%08X", ((int *)buf)[i]); if ((i & 7) == 7) printf("\n"); }
return 0; } Может ли кто нибудь найти в чем ошибка? А не пробовали запустить с потоком, который только и делает, что return NULL А то слишком много букв...
--------------------
Some days you eat the bear. Some days the bear eats you.
|
|
|
|
|
Mar 2 2007, 11:31
|
Знающий
   
Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847

|
Цитата А не пробовали запустить с потоком, который только и делает, что return NULL А то слишком много букв... sad.gif [offtopic] Пробовал, но от проблемы это не спасает  . [/offtopic]
--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть. © Lewis Carroll. Alice's adventures in wonderland.
|
|
|
|
|
Mar 2 2007, 14:45
|
Знающий
   
Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847

|
Проблема пропала после замены кода функции read драйвера на приведенную ниже. Однако непонятно в чем причина с предыдущим кодом. Код static ssize_t simple_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) { int retval = 0; struct simple_device *dev = simple_devs[iminor(filp->f_dentry->d_inode)]; int pos; TRACE; if (count < (SIMPLE_RX_TRANSFER * sizeof(int))) { return -ENOMEM; } if (wait_event_interruptible(dev->rx_queue, dev->rx_ready)) { return -ERESTARTSYS; } PDEBUG("awake\n"); pos = dev->ipos; retval = copy_to_user(buf, &dev->ibuf[pos], SIMPLE_RX_TRANSFER * sizeof(int)); if (retval) { PERROR("Copied less data then requested!\n"); retval = -EFAULT; } else { retval = SIMPLE_RX_TRANSFER * sizeof(int); } dev->rx_ready = 0; return retval; }
Сообщение отредактировал amw - Mar 2 2007, 14:46
--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть. © Lewis Carroll. Alice's adventures in wonderland.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|