среда, 7 декабря 2011 г.

Останавливаем сервер или kill -0 $PID

Иногда бывает полезно, а в некоторых случаях нужно, чтобы скрипт старта - остановки сервера не завершался до полной остановки. Например - типичная ситуация, когда сервер работает с локальной базой данных и нам нужен рестарт - а в простейшем случае это совокупность стоп и старт. При медленной остановке сервера, мы получим в данном случае ошибку при старте - база, например, будет заблокирована оостанавливающимся сервером.
В скрипте, всегда, в таком случае, использовал недокументированную в некоторых unix команду:
kill -0 $PID, для проверки существования процесса.
Но недавно нам попался solaris на котором данная команда приводила к core на остановке.
pstack выводил следующее:
ffffffff7b8ca03c sigacthandler (0, ffffffff7ffff150, ffffffff7fffee70, ffffffff7d100200, 0, ffffffff7ba3c000) + 54
 --- called from signal handler with signal 0 (SIGEXIT) ---
 ffffffff7b8da240 __lwp_wait (15, ffffffff7ffff3bc, 0, 0, 0, 0) + 8
что вызывало недоумение, ведь согласно мануалу - такого сигнала в solaris нету.
Переносимое решение пришло такое - вместо kill -0 $PID использовать ps -p $PID, причем, данная команда работает заметно быстрее.
Финальный стоп скрипт такой:
while ps -p $PID 2>&1 >/dev/null
do
 sleep 1
 echo -n .
done 

пятница, 2 декабря 2011 г.

Как нам обмануть libtool.

В проектах, собираемых для множества платформ, иногда бывает необходимо использовать статическую версию библиотек времени выполнения. С нашими проектами все хорошо. Мы их делаем, заботимся о корректных файлах сборки и. т. д. Но как быть со сторонними проектами, у которых система сборки autoconf/libtool? Это хорошо, когда авторы проекта предусматривают такую возможность, допустим при помощи опции для configure. Ну еще, как вариант, можно иногда поправить все эти config.in, m4 - но коварный libtool все равно съедает опцию -static-libgcc.
И все это требует времени, т.к. autoconf не быстр, а казалось бы надо - всего то ничего - добавить опцию на командную строку gcc.
Итак, какие же для этого существуют возможности?
  1. Переопределить CC="gcc -static-libgcc". Самое простое. Иногда этого достаточно. Мне попадались экземпляры, которые анализировали данное переопределение убирая второй аргумент. Иногда, пробел между аргументами в каких то  тестах давал сбой.
  2. Переопределить CC=gcc-wrap.sh. В gcc-wrap.sh поместить следующее:
    /usr/bin/bash
    exec gcc -shared-libgcc $*
    
    Этого в большинстве случаев достаточно. Медленно правда - лишний вызов интерпретатора. Если на командную строку попадают кавычки, то такая конструкция их съест. Кавычки используются например для передачи литералов в командную строку.
  3. Самый лучший и быстрый по скорости вариант: переопределить CC=gcc-wrap на простейшую программу - оболочку gcc-wrap.c:
    #include <stdio.h> 
    #include <unistd.h> 
    #define GCCEXE "/usr/bin/gcc"
    int main(int argc, char *argv[]) {
    char **my_arg = malloc(sizeof(char *) * (argc + 2));
    int i;
    my_arg[0] = "gcc"; my_arg[1] = "-static-libgcc"; for(i=1; i< (argc + 2); i++)      my_arg[i+1] = argv[i];      execvp(GCCEXE, my_arg );      perror(GCCEXE);    return 1; }
Все. Теперь библиотеки собираются как нам надо.
Кстати, таким образом можно также убирать из командной строки ненужные нам аргументы.


четверг, 1 декабря 2011 г.

C++ библиотека-плагин для Unix. Часть 6-я. Локальные статические объекты и чем они страшны.

См. Бьeрн Страустрап. Справочное руководство по C++
Все так и работает, как Страустрап прописал. Но однажды столкнулись со следующей проблемой:
Используя boost::spirit, богатую выражениями вида:
//spirit\home\classic\core\primitives\impl\numerics.ipp
  static RT parse(ScannerT const& scan)
            {
                static self_t this_;
                return impl::implicit_lexeme_parse<RT>(this_, scan, scan);
            }
          
столкнулись со странными падениями при обращении нашей библиотеки к локальным статическим объектам. Дело это было на нашем любимом HP-UX и главное приложение, вызывающее (через dl_open) нашу библиотеку собрано на aCC. При таком раскладе конструкторы локальных статических объектов не вызываются. Пришлось spirit патчить на предмет всех локальных статиков, типа:
static boost::shared_ptr<object_with_id_base_supply<IdT> > static_supply;
                if (!static_supply.get())
                    static_supply.reset(new object_with_id_base_supply<IdT>());
                id_supply = static_supply;

заменяем на синглтон из ACE:
#define BOOST_SPIRIT_SINGLE_PTR(T)\
 (* ACE_Singleton<T, ACE_Thread_Mutex>::instance())
... 
boost::shared_ptr<object_with_id_base_supply<IdT> >& static_supply =
 BOOST_SPIRIT_SINGLE_PTR(
  boost::shared_ptr<object_with_id_base_supply<IdT> >
);
if (!static_supply.get())
  static_supply.reset(new object_with_id_base_supply<IdT>());
  id_supply = static_supply;
Ну и так далее.Кстати, у Clang есть опция -Wexit-time-destructors, предупреждающая, о том, что глобальные объекты вызывают деструкторы. Надо будет как нибудь попробовать.