2014-01-30 5 views
2

У меня есть программа на основе Xlib с циклом событий, которая использует XNextEvent для получения и обработки соответствующих событий.Закрыть приложение XLib от другого процесса

Я хотел бы иметь возможность изящно закрыть эту программу из другого процесса (фактически из сценария оболочки). Мне нужно выполнить некоторую очистку при закрытии, поэтому я решил настроить обработчик сигнала (например, для SIGUSR1), и когда этот сигнал будет получен, выполните соответствующую очистку.

Мой вопрос в том, как я могу прерывать вызов (блокирование) XNextEvent от обработчика сигнала?

Любые другие предложения?

+0

Я не уверен, я понимаю ваш вопрос. Сигналы уже прерывают нормальный поток программы. Системный вызов внутри 'XNextEvent()' будет прерван для запуска вашего обработчика. Вам нечего делать, чтобы достичь этого. –

+0

Я предполагаю, что 'XNextEvent()' будет прерван для запуска моего обработчика, но как только обработчик будет запущен, выполнение возобновится, и 'XNextEvent()' все равно будет заблокирован. Вопрос заключается в том, как (безопасно) разблокировать 'XNextEvent()' из обработчика сигнала. – Grodriguez

+1

Я вижу. Я предполагаю, что вы не хотите 'exit()' из обработчика сигнала. Я не думаю, что 'XCloseDisplay()' безопасно вызывать из обработчика сигналов. Возможно, задание глобального логического значения и впрыскивание события, поэтому 'XNextEvent()' возвращает сразу же вариант. Я осмотрюсь. –

ответ

5

Я нашел способ сделать это основано на this SO question и this one.

В основном вы можете использовать макрос ConnectionNumber(), чтобы получить fd, которое читает XNextEvent(). Это позволяет мне позвонить select() себе, чтобы дождаться данных на Xlib fd и некоторых других fd. Теперь это select(), который блокируется, а не XNextEvent(). Я могу легко разблокировать select() из моего обработчика сигналов, написав второй fd.

Псевдо-код для цикла событий:

/* Get X11 fd */ 
x11_fd = ConnectionNumber(display); 

while(1) { 
    /* Create a File Description Set containing x11_fd and other_fd */ 
    FD_ZERO(&in_fds); 
    FD_SET(x11_fd, &in_fds); 
    FD_SET(other_fd, &in_fds); 

    /* Wait for X Event or exit signal */ 
    ret = select(nfds, &in_fds, ...); 
    if (FD_ISSET(other_fd, &in_fds) { 
     /* Do any cleanup and exit */ 
    } else { 
     while (XEventsQueued(display, QueuedAlready) > 0) { 
      /* Process X events */ 
     } 
    } 
} 
+0

Прошу прояснить это, код, который вы предоставили, неполный ... Не следует заменить nfds на x11_fd + 1? И почему бы не использовать exceptfds? – Centril

+0

Как явно указано в ответе, это ** псевдокод **, показывающий, как решить конкретную проблему, указанную в вопросе; он не должен быть отдельным примером. Число рейнольдсаваши вопросы: 1) nfds должен быть «наивысшим номером дескриптора файла в любом из наборов fd, переданных для выбора, плюс 1». Если x11_fd является наивысшим номером дескриптора файла, вы можете заменить nfds на x11_fd + 1, в противном случае - нет. Это зависит от вашего варианта использования. 2) «Почему бы не использовать exceptfds». Никто не говорит, что не использовать его, это снова зависит от вашего прецедента. – Grodriguez

+0

Я вижу, как мне создать 'other_fd', и как разблокировать выделение, написав на' other_fd'? – Centril

0

Предполагая, что у вас есть идентификатор процесса, вы можете использовать kill функцию:

int kill(pid_t pid, int sig);

Вы можете послать любой сигнал, но SIGKILL (SIGKILL не может быть обработан)

+0

Как я могу (безопасно) разблокировать 'XNextEvent()' из обработчика сигнала? – Grodriguez

+1

Используя ['XSendEvent()'] (http://h50146.www5.hp.com/products/software/oe/tru64unix/manual/v51a_ref/HTML/MAN/MAN3/3363_X11.HTM) с фальшивым событием? –

+1

Я думаю, что 'XSendEvent' небезопасно для вызова из обработчика сигналов ... – Grodriguez

Смежные вопросы