The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"clone() и malloc()"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (Процессы, Треды, RPC)
Изначальное сообщение [ Отслеживать ]

"clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 11-Янв-12, 13:30 
Прошу помощи у знающих людей.

Создаю процессы с помощью clone() с флагами: CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD | CLONE_SYSVSEM.
Если добавить флаг CLONE_THREAD, то все работает нормально, но этот флаш не нужен.

При этом когда они начиют конкурировать между собой, возникает deadlock в функциях malloc()/free()

используется clone(), а не fork() потому что в приложении нужно шарить очень много данных.
используется clone(), а не pthread_create() потому что при смерти треда (seg fault) завершается сразу все приложение.
То есть хочется что бы и процессы между собой все делили, и при этом были независимы друг от друга в случае смерти.
В функциях glibc есть внутренние блокировки, непонятно только почему они заходят в deadlock.


Код для демонстрации:

int func(void *p)
{
    while (1) {
        p = (char *)malloc(6);
        memcpy(p, "12345\0", 5);
        free(p);
    }
}

#define     STACK_SIZE 1024*1024

int main()
{
    int i;
                                            
    for (i=0; i<10; i++) {
        void *stack = malloc(STACK_SIZE);
        int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD | CLONE_SYSVSEM;
        int id = clone(func, (char *)stack + STACK_SIZE, flags, NULL);
    }

    sleep(10000);

    return 0;
}

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "clone() и malloc()"  +/
Сообщение от Вова on 11-Янв-12, 14:59 
так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

4. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 11-Янв-12, 16:09 
> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.

Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
Все версии выдали:
*** glibc detected *** *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x00002af4240008c0 ***
В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb показал что ожидание внутри free.

Ответить | Правка | ^ к родителю #1 | Наверх | Cообщить модератору

7. "clone() и malloc()"  +/
Сообщение от me (??) on 11-Янв-12, 17:10 
>> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
> Все версии выдали:
> *** glibc detected *** *** glibc detected *** ./a.out: double free or
> corruption (fasttop): 0x00002af4240008c0 ***

ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.

> В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb
> показал что ожидание внутри free.

это больша на багу glibc похоже, хотя с таким кодом я не удивлён.

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

8. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 11-Янв-12, 17:52 
>>> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
>> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
>> Все версии выдали:
>> *** glibc detected *** *** glibc detected *** ./a.out: double free or
>> corruption (fasttop): 0x00002af4240008c0 ***
> ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.

С одной стороны это логично, и это тоже первое о чем я подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.
Да и malloc использует внутреннюю блокировку, что бы быть thread-safe, непонятно почему эта блокировка не спасает.
Если обернуть внешний вызов malloc/free в mutex то проблема исчезает.


>> В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb
>> показал что ожидание внутри free.
> это больша на багу glibc похоже, хотя с таким кодом я не
> удивлён.

Про код опишите, пожалуйста, что именно в нем плохо? Специально синтетический тест на конкуренцию malloc/free.

Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

9. "clone() и malloc()"  +/
Сообщение от me (??) on 11-Янв-12, 19:30 
>>>> так в чём проблема-то? Какие дедлоки? Все потоки крутятся, ничего не залочено.
>>> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
>>> Все версии выдали:
>>> *** glibc detected *** *** glibc detected *** ./a.out: double free or
>>> corruption (fasttop): 0x00002af4240008c0 ***
>> ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.
> С одной стороны это логично, и это тоже первое о чем я
> подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.

так вы-ж его не иначе с -pthread собираете? :)

> Да и malloc использует внутреннюю блокировку, что бы быть thread-safe,

без флага pthread? или с флагом но без pthread_create? серьезно? :)

> непонятно почему
> эта блокировка не спасает.
> Если обернуть внешний вызов malloc/free в mutex то проблема исчезает.
>>> В некоторых случаях появлялся deadlock и процессы просто висели в ожидании. gdb
>>> показал что ожидание внутри free.
>> это больша на багу glibc похоже, хотя с таким кодом я не
>> удивлён.
> Про код опишите, пожалуйста, что именно в нем плохо? Специально синтетический тест
> на конкуренцию malloc/free.

вы думаете он знает зачем его создали? :) ему вообщем плевать, он и malloc/malloc и free/free - поконкурирует на раз. И если там есть бага - легко поймает. Вы хотели багу рэйса - вы поймали багу рэйса (возможно, требует проверки все-же). Вы удивлены? Вас не Вова зовут?(шучу) :)

Ответить | Правка | ^ к родителю #8 | Наверх | Cообщить модератору

10. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 11-Янв-12, 21:12 
>[оверквотинг удален]
>>>> Только что скомпилировал код на CentOS 4.4 / 5 / 5.6
>>>> Все версии выдали:
>>>> *** glibc detected *** *** glibc detected *** ./a.out: double free or
>>>> corruption (fasttop): 0x00002af4240008c0 ***
>>> ну это логично вполне, он-же CLONE_VM делает и никак это не лечит.
>> С одной стороны это логично, и это тоже первое о чем я
>> подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.
> так вы-ж его не иначе с -pthread собираете? :)
>> Да и malloc использует внутреннюю блокировку, что бы быть thread-safe,
> без флага pthread? или с флагом но без pthread_create? серьезно? :)

Я собирал и без -pthread и с ней. добавлял -D_REENTRANT - все без результатно.

но... по вашему "намеку" попробовал добавить в код pthread_create(), который создает тред и сразу его закрывает. все заработало.
Очевидно что pthread_create что то проинициализировал. Я смотрел его код, но инициализацией связанных с памятью или локами не нашел (кроме стека).

Спасибо Вам за помощь.
Если возможно, подскажите, что именно инициализирует pthread_create()? что бы не использовать его как "хак".

Ответить | Правка | ^ к родителю #9 | Наверх | Cообщить модератору

11. "clone() и malloc()"  +/
Сообщение от me (??) on 11-Янв-12, 23:11 
>[оверквотинг удален]
>>> подумал. Но тот же pthread_create тоже использует CLONE_VM и проблем никаких.
>> так вы-ж его не иначе с -pthread собираете? :)
>>> Да и malloc использует внутреннюю блокировку, что бы быть thread-safe,
>> без флага pthread? или с флагом но без pthread_create? серьезно? :)
> Я собирал и без -pthread и с ней. добавлял -D_REENTRANT - все
> без результатно.
> но... по вашему "намеку" попробовал добавить в код pthread_create(), который создает тред
> и сразу его закрывает. все заработало.
> Очевидно что pthread_create что то проинициализировал. Я смотрел его код, но инициализацией
> связанных с памятью или локами не нашел (кроме стека).

не, я имел ввиду pthread_create для создания потока вместо clone. Вы показали ваш собственный фокус. (весьма занятный, кстати. но я-бы не рассчитывал, что этот код будет работать всегда)

> Спасибо Вам за помощь.

незачто и судя по-тому, что вы хотели clone() "потому что при смерти треда (seg fault) завершается сразу все приложение." - вы еще не пробовали посылать sigsegv ни одному из ваших "работающих" клонов. SIGSEGV, кстати, маскируется и обрабатывается.

> Если возможно, подскажите, что именно инициализирует pthread_create()? что бы не использовать
> его как "хак".

это "хак" и я-бы его не использовал.

Ответить | Правка | ^ к родителю #10 | Наверх | Cообщить модератору

12. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 12-Янв-12, 00:29 
> незачто и судя по-тому, что вы хотели clone() "потому что при смерти
> треда (seg fault) завершается сразу все приложение." - вы еще не
> пробовали посылать sigsegv ни одному из ваших "работающих" клонов. SIGSEGV, кстати,
> маскируется и обрабатывается.

Этот момент я хорошо тестировал. SIGSEGV вызывал разными способами.
В случае с клонами (с указанными флагами) SIGSEGV ловится слоном, вызывается exit() и клон умирает. Родитель обрабатывает waitpid и продолжает работать.
В случае с тредами (pthread_create или флаг CLONE_THREAD) SIGSEGV тоже ловится, но ловит его родитель и продолжать работать не может. Умирает родитель и умирают все поражденные треды.

Ответить | Правка | ^ к родителю #11 | Наверх | Cообщить модератору

13. "clone() и malloc()"  +/
Сообщение от pavlinux (ok) on 14-Янв-12, 18:49 
Блин, вы С учить будете? А то glibc, треды... придумали тоже... :)

У Вас указатель *stack ВСЕ ВРЕМЯ указывает на один и тот же сегмент,
над которым затем трахаются по 10 копий malloc и free!!!
Да, на уровне ядра есть блокировки, собственно благодаря которым вы и получаете SIGSEGV,
а не смерть всего компа.

Ниже я показал, что надо юзать указатель на указатель (можно массив указателей)

Ответить | Правка | ^ к родителю #12 | Наверх | Cообщить модератору

15. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 14-Янв-12, 20:04 
> Блин, вы С учить будете? А то glibc, треды... придумали тоже... :)

Буду рад, если Вы подскажите что почитать для получения новых знаний.

> У Вас указатель *stack ВСЕ ВРЕМЯ указывает на один и тот же
> сегмент,
> над которым затем трахаются по 10 копий malloc и free!!!

Мой код:
for (i=0; i<10; i++) {
        void *stack = malloc(STACK_SIZE);
}

переменной stack присывается новое значение, так что *stack никак не может указывать на одинаковый сегмент памяти.


> Ниже я показал, что надо юзать указатель на указатель (можно массив указателей)

Кусок Вашего кода:

stack = malloc(STACK_SIZE);
for (i = 0; i < 10; i++) {
   *stack = (void *)(STACK_SIZE + (char *)stack);
   clone(func, stack, FLAGS, NULL);

Вы выделили память размером STACK_SIZE,
затем в первый байт записали ссылку на конец выделенной памяти
передали в clone ссылку на выделенную память.

У доке четко написано:
The child_stack argument specifies the location of the stack used by the child process. ... The calling process must therefore set up memory space for the child stack and pass a pointer to this space to clone().
В переводе это означает что передавать нужно ссылку на память, а не ссылку на ссылку на память.
Даже, если предположить что нужно передавать последнее, то Ваш код все равно не работает так как во все 10 клонов он передаст один и тот же указатель.


P.S. Ваш код я скомпилировал и запустил, как результат:
kernel: a.out[28746]: segfault at 0000000000000000 rip 0000000000000000 rsp 00002b18a9b79008 error 14

Ответить | Правка | ^ к родителю #13 | Наверх | Cообщить модератору

16. "clone() и malloc()"  +/
Сообщение от pavlinux (ok) on 15-Янв-12, 00:59 
>[оверквотинг удален]
> В переводе это означает что передавать нужно ссылку на память,
> а не ссылку на ссылку на память.

Чуток не правильно понимаешь свойства работы с указателем на указатель.
Ну на, в твоем виде


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sched.h>
#include <signal.h>


#define STACK_SIZE (1024*1024)
#define FLAGS (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_SYSVSEM|SIGCHLD)

int func(void *p) {
    
    while (1) {
           p = (char *)malloc(6);
           memcpy(p, "12345\0", 6);
           free(p);
    }
}

int main() {

    int i;
    void **stack;
    
    for (i = 0; i < 10; i++) {
         stack = (void **)malloc(STACK_SIZE);
         clone(func, stack, FLAGS, NULL);
    }

    sleep(10);
    return 0;
}


Ответить | Правка | ^ к родителю #15 | Наверх | Cообщить модератору

18. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 15-Янв-12, 04:02 
>>[оверквотинг удален]
>> В переводе это означает что передавать нужно ссылку на память,
>> а не ссылку на ссылку на память.
> Чуток не правильно понимаешь свойства работы с указателем на указатель.
> Ну на, в твоем виде

С Вашего позволения, тоже перейду на "ты".

Объясни, мне пожалуйста, что я неправильно понимаю. Можно ссылкой в ман, гугл или куда угодно.

Что касается кода, правильно ли я понял фразу "Ну на, в твоем виде" - означает, что 2 кода которые ты привел они идентичны, только "вид" разный?
Для наглядности:

первый:

 
    void **stack;
    for (i = 0; i < 10; i++) {
         stack = (void **)malloc(STACK_SIZE);
         clone(func, stack, FLAGS, NULL);
    }


второй:

 
    void **stack;
    stack = malloc(STACK_SIZE);
    for (i = 0; i < 10; i++) {
        *stack = (void *)(STACK_SIZE + (char *)stack);
        clone(func, stack, FLAGS, NULL);
    }

Ответить | Правка | ^ к родителю #16 | Наверх | Cообщить модератору

20. "clone() и malloc()"  +/
Сообщение от pavlinux (ok) on 15-Янв-12, 14:50 
>>>[оверквотинг удален]

Короче не ..би моск

 
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

int func(void *ptr) {

    char *msg = (char *) ptr;

    while (1) {
        pthread_mutex_lock(&lock);
          msg = malloc( 6);
          strncpy(msg, "12345\0", 6);
          free(msg);
        pthread_mutex_unlock(&lock);
    }
    return 0;
}

Кстати, размер стека лучше узнавать у getrlimit(RLIMIT_STACK, rlim) ...

Ответить | Правка | ^ к родителю #18 | Наверх | Cообщить модератору

5. "clone() и malloc()"  +/
Сообщение от pavlinux (ok) on 11-Янв-12, 16:26 

int func(void *p)
{
        while (1) {
                p = (char *)malloc(6);
                memcpy(p, "12345\0", 6);
                free(p);
        }
}

#define STACK_SIZE (1024*1024)
#define FLAGS (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_SYSVSEM|SIGCHLD)

int main()
{
        int i;
        void **stack;

        stack = malloc(STACK_SIZE);
        for (i = 0; i < 10; i++) {
            *stack = (void *)(STACK_SIZE + (char *)stack);
             clone(func, stack, FLAGS, NULL);
        }
        sleep(10000);
        return 0;
}

Криво, ибо пример такой.
Давай реальную задачу.

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

17. "clone() и malloc()"  +/
Сообщение от svn (??) on 15-Янв-12, 03:19 
> При этом когда они начиют конкурировать между собой, возникает deadlock в функциях
> malloc()/free()

Конечно возникает. Потому что память одного процесса неожиданно редактирует другой процесс.

Если какой-то поток вызывает SIGSEGV - значит вся память испорчена. Общая, всего процесса!!
Ничего хорошего в работе программы с испорченной памятью не может быть.

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

19. "clone() и malloc()"  +/
Сообщение от nikolayshm email(ok) on 15-Янв-12, 04:08 
>> При этом когда они начиют конкурировать между собой, возникает deadlock в функциях
>> malloc()/free()
> Конечно возникает. Потому что память одного процесса неожиданно редактирует другой процесс.

Так вопрос-то был соответствующий - почему так. malloc/free они ведь thread-safe :)

> Если какой-то поток вызывает SIGSEGV - значит вся память испорчена. Общая, всего
> процесса!!

Кстати, это неправильное утверждение.
SIGSEGV is the signal sent to a process when it makes an invalid memory reference, or segmentation fault.

Ответить | Правка | ^ к родителю #17 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2021 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру