реклама на сайте
подробности

 
 
> Linux glibc pthread, Seg fault при использовании.
amw
сообщение Feb 28 2007, 19:14
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 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.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
amw
сообщение Mar 2 2007, 11:31
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847



Цитата
А не пробовали запустить с потоком, который только и делает, что return NULL
А то слишком много букв... sad.gif

[offtopic]
Пробовал, но от проблемы это не спасает wink.gif.
[/offtopic]


--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть.
© Lewis Carroll. Alice's adventures in wonderland.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 15:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01392 секунд с 7
ELECTRONIX ©2004-2016