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

 
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  я тоже не вызывал

есть у кого-то хотябы предположения, что происходит?
Comments (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
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
ava  fish9370   gormih   xvr
advanced
Submit