проблема с подключаемым модулем

 
0
 
C++
ava
fish9370 | 26.03.2013, 12:07
предыстория: было у меня ядро, были у меня модули..
работал я с ними так: - запускал ядро, заходил в консоль и запускал модуль.. и все прекрасно работало..
но в один прекрасный день я сказал себе - а почему модули нужно запускать вручную? - и сделал автозагрузку..

и здесь у меня появилась проблема: почему-то при автозапуске, если в модуле открывается сокет, этот сокет оказывается кривым, переодически функция recvfrom возвращает сообщение об ошибке (Bad file descriptor).
Все это происходит именно при форке, при запуске проги в режиме no-fork все работает как положено..

функция демонизации:

void server_way()
{
        int i, f, ppid;
        char str[10];
        if (getppid() == 1)
                return;

        if (!flags.console) {
                ppid = fork();
                if (ppid < 0) {
                        bs_verbose(LOG_ERROR, "fork error");
                        exit(1);
                }
                if (ppid > 0)
                        exit(0);

                setsid();

                /* we don't need close any descriptors */
                /* for (i = getdtablesize(); i >= 0; --i) {
                        close(i);
                }*/

                i = open("/dev/null", O_RDWR);
                dup(i);
                dup(i);
        }

        umask(027);
        chdir(config_global.bsrundir);

        f = open("basys.pid", O_RDWR | O_CREAT, 0640);
        if (f < 0) {
                bs_verbosef(lf, LOG_VERBOSE, "Can not open 'basys.pid' file\n");
                fflush(lf);
                exit(1);
        }

        if (lockf(f, F_TLOCK, 0) < 0)
                exit(0);

        sprintf(str, "%d\n", getpid());
        write(f, str, strlen(str));

        signal(SIGCHLD,SIG_IGN);
        signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
        signal(SIGTTOU,SIG_IGN);
        signal(SIGTTIN,SIG_IGN);

        signal(SIGHUP, signal_handler); /* catch hangup signal */
        signal(SIGTERM, signal_handler); /* catch kill signal */

        makesocket();

        for (i = 0; i < MAX_CONSOLES; i++)
                consoles[i].fd = -1;

        tv_startuptime = bs_tvnow();
        bs_verbosef(lf, LOG_VERBOSE, ">> server started\n");
        fflush(lf);

        while (!process_done) {

                bs_verbosef(lf, LOG_VERBOSE, "wait new connection\n");
                fflush(lf);

                int s;
                if ((s = accept(sock, (struct sockaddr *) &address, &addrlen)) < 0)
                        continue;

                for (i = 0; i < MAX_CONSOLES; i++) {
                        if (consoles[i].fd < 0) {
                                consoles[i].fd = s;
                                pthread_create(&consoles[i].tid, NULL, messenger, &consoles[i]);
                                pthread_detach(consoles[i].tid);
                                break;
                        }
                }

                if (i >= MAX_CONSOLES)
                        bs_verbosef(lf, LOG_VERBOSE, "unable to connect, max connections\n");

                usleep(100);
        }

        struct bs_cli_entry *current;
        while ((current = BS_LIST_REMOVE_HEAD(&commands, list)))
                free(current);

        struct bs_module_entry *mod;
        while ((mod = BS_LIST_REMOVE_HEAD(&modules, list))) {
                module_unload(mod->handle);
                free(mod);
        }

        close(f);
        fclose(lf);
}



еще несколько замечаний:
прога ведет лог, и вот что в этом логе странного:


tdns.c:load_module:975 loading config '/etc/basys/tdns.conf'
tdns.c:init_threads:260 count: '1000', size: '8'
tdns.c:handler_start:763 Starting listening connection
[color=red]tdns.c:handler_stop:809 wait for thread ab0cc700[/color]
src/basys.c:server_way:985 >> server started
src/basys.c:server_way:990 wait new connection


где, tdns.c - это код модуля, basys.c - это код ядра
при загрузке модуля, как и положено в unix, вызывается функция с символом _init (попросту говоря конструктор), который и вызывает функцию handler_start() - мы ее наблюдаем в логе
но дальше мы видим вызов функции handler_stop(), которая вызывается из деструктора (выделил красным), но я ее не вызывал, при этом для модуля функцию dlclose  я тоже не вызывал

есть у кого-то хотябы предположения, что происходит?
Kommentare (6)
ava
xvr | 26.03.2013, 11:53 #
Цитата (fish9370 @  26.3.2013,  11:07 findReferencedText)
есть у кого-то хотябы предположения, что происходит?

Похоже отрабатывают деструкторы в родительском процессе, который завершили в процессе демонизации (строка 15)
Распечатайте в логе pid процесса
ava
fish9370 | 26.03.2013, 12:12 #
спасибо xvr, что проявил интерес к проблеме,

я не совсем понял, что за пид нужен, напечатал так:


[[email protected] bs]# basys
src/basys.c:server_way:941 ppid: 12821



tdns.c:load_module:975 loading config '/etc/basys/tdns.conf'
tdns.c:init_threads:260 count: '1000', size: '8'
tdns.c:handler_start:763 Starting listening connection
tdns.c:handler_stop:809 wait for thread a4ae4700
src/basys.c:server_way:945 ppid: 0
src/basys.c:server_way:991 >> server started
src/basys.c:server_way:996 wait new connection
ava
fish9370 | 26.03.2013, 12:45 #
сделал так:


if (ppid > 0) {
                        bs_verbose(LOG_DEBUG, "ppid: %d\n", ppid);
                        while(1);
                        exit(0);
                }



и о чудо, сокет жив и работает, пока родительский процесс живет,
xvr ты оказался прав..

но как выкручиваться из этой ситуации?
ava
fish9370 | 26.03.2013, 14:13 #
решил проблему, отложенной загрузкой модулей (после форка)

спасибо xvr, очень ценный ответ +1
ava
xvr | 27.03.2013, 07:21 #
Цитата (fish9370 @  26.3.2013,  12:12 findReferencedText)
вроде как открытые дескрипторы (то же касается и дескрипторов открытых либ?) передаются дочернему процессу и не закрываются, пока есть хоть один владелец? 

Дескрипторы либ на самом деле не дескрипторы - они организуются на уровне пользователя динамическим линкером, и как они ведут себя при fork'е я лично не в курсе.
По поводу сокетов - да, дескрипторы наследуются. Но для убиения сокета не обязательно закрывать его дескриптор, достаточно сделать shutdown на дескриптор (любой) и сокет помрет, не взирая на наличие любого количества других открытых дескрипторов  smile 
ava
gormih | 28.03.2013, 16:37 #
Цитата (xvr @  27.3.2013,  07:21 findReferencedText)
Дескрипторы либ на самом деле не дескрипторы - они организуются на уровне пользователя динамическим линкером, и как они ведут себя при fork'е я лично не в курсе.

По поводу сокетов - да, дескрипторы наследуются. Но для убиения сокета не обязательно закрывать его дескриптор, достаточно сделать shutdown на дескриптор (любой) и сокет помрет, не взирая на наличие любого количества других открытых дескрипторов   

При fork любой процесс, у которого  пропадают все  процессы - родители попадает под базовый системный процесс init, который его успешно убивает (по задумке) smile
Registrieren Sie sich oder melden Sie sich an, um schreiben zu können.
Unternehmen des Tages
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Mitwirkende
ava  fish9370   gormih   xvr
advanced
Absenden