null

Авторестарт сервера с помощью vim, C и sh

Недавно пришлось активно заниматься отладкой одного самописного сервера на одном скриптовом языке (то есть без явной компиляции). Процесс происходил в два окна. В одном открыт исходник, в другом запускается сервер и наблюдается результат. Перезапускать вручную сервер после каждой правки быстро надоело, захотелось, чтобы всё происходило само, по нажатию волшебной кнопки save. Как бы это сделать? Решение посетило следующее: В качестве "штуки", перезапускающей сервер был написан monitor.c (возможно, не самое подходящее название):

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

struct sigaction act;
pid_t  pid;

void handle_usr1(int s) {
    if (kill(pid, SIGINT) == -1 && errno == ESRCH) {
        perror("wrong pid of killed process");
        exit(1);
    }
    wait(NULL);
}


int main(int argc, char * argv[]) {

    act.sa_handler = handle_usr1;
    sigaction(SIGUSR1, &act, NULL);
    printf("MONITOR PID %d\n", (int) getpid());

loop:
    pid = fork();

    if (pid == 0) {         /* is a child */
        execvp(argv[1], &argv[1]);
        perror("exec returned control");
        exit(1);
    } else if (pid > 0) {   /* is a parent */
        if (wait(NULL) != -1) {
            exit(2);
        }
        goto loop;
    } else {                /* fork failed, no child is created */
        perror("fork failed");
        exit(3);
    }
}

Запускать его следует так:

monitor cmd [arg] ...

Monitor выводит в терминал свой PID и запускает cmd с аргументами arg ... По сигналу SIGUSR1, monitor прибивает запущенную программу и перезапускает её с теми же аргументами.
Monitor ожидает, что сервер не завершится сам по себе, а только по сигналу, в противном случае, monitor также завершается с кодом 2.

Итак, сервер перезапускается по сигналу SIGUSR1, что дальше? Дальше следует как-то посылать сигнал. Для этого я использовал автокоманды редактора vim:

:au BufWritePost $PATTERN !kill -s USR1 $PID

При записи буфера в файл, имя которого соответствует $PATTERN, автоматически будет выполняться команда:

kill -s USR1 $PID
Итак, всё что нужно:
    # иметь скомпилированный монитор:
gcc -o monitor monitor.c
    # запустить монитор с сервером, увидеть PID монитора:
./monitor ./server
> MONITOR PID 1234
> ...
    # открыть vim и добавить автокоманду с нужным PID
vim server
:au BufWritePost server !kill -s USR1 1234

Теперь, при сохранении исходника (vim команда :w), сервер будет рестартовать автоматически - одним рутинным действием меньше.

Также стоит отметить, если есть уверенность, что на системе запускается только один процесс с именем ./server, вполне можно обойтись простым циклом в sh:

while true; do ./server; done
и следующей автокомандой для vim:
:au BufWritePost server !pkill ./server
Несомненным преимуществом такого подхода является его простота.