[СИ] Простой HTTP-сервер.
Язык СИ
ОС UNIX
Имеется простой самодельный HTTP-сервр с пулом
рабочих процессов (каждому клиенту свой процесс).
Он якобы работает, но есть сомнения.
По замыслу рабочий процесс сервера должен
позаботиться, чтоб запущенный им CGI-скрипт
кончился в пределах тайм-аута, а то послать
CGI-скрипту SIGKILL.
Ниже приведена схема рабочего процесса с
куском доподлинного нового кода.
//--- глобальные ---
int volatile fl_alarm=0;
pid_t pid1;
void timer(int n)
{
kill(pid1, 9); //--- сигнал CGI-скрипту ---
fl_alarm=1;
return;
}
//--- СХЕМА РАБОЧЕГО ПРОЦЕССА ---
start:
sd=accept();
k_alive:
k=read(sd); //--- ждем запрос (с тайм-аутом) ---
pid1=fork();
//--- дочерний процесс -> CGI-скрипт ---
if(pid1==0){
close(sd);
execl();
exit(0);
}
//--- родительский процесс ---
signal(SIGALRM, timer);
alarm(tm_out); //--- общий тайм-аут запроса ---
k=read(sd); //--- POST-запрос клиента (с тайм-аутом) ---
k=write(pipe0); //--- на ввод CGI (блокирующий) ---
k=read(pipe1); //--- с вывода CGI (блокирующий) ---
k=write(sd); //--- ответ клиенту (с тайм-аутом) ---
//--- ДОПОДЛИННЫЙ КОД ---
tm=alarm(0);
if(fl_alarm>0){
pid3=wait(&status); //--- борьба с зомби, блокирующий ---
fl_alarm = 0;
}
else{
pid3=-1;
tm1=0;
while(tm1 < tm){
pid3=waitpid(pid1, &status, WNOHANG); //--- неблокирующий ---
if(pid3>0) break;
sleep(TM); //--- TM -период опроса 1 сек. ---
tm1=tm1 + TM;
}
if(pid3<=0){
kill(pid1, 9);
pid=wait(&status); //--- блокирующий ---
}
}
//--- КОНЕЦ ДОПОДЛИННОГО КОДА ---
if(fl_aliv > 0) goto k_alive;
close(sd);
goto start;
1.
kill() в обработчике сомнителен.
Я не вижу иного способа вынести его оттуда,
кроме как сделать чтение/запись в pipe-канал
с тайм-аутом подобно сокету. Иначе можно зависнуть
на read(pipe), если CGI-скрипт, например, зациклится.
Или даже все три (сокет, ввод и вывод скрипта) завести
на центральный select процесса, время вычислять, и
совсем отказаться от сигнала SIGALRM.
Это, наверно, возможно. Но простой поначалу сервер
всё больше утяжеляется.
2.
Глобальный, фигурирующий в обработчике сигнала
pid_t pid1;
Как его и можно ли правильно определить? volatile?
В статье http://www.opennet.ru/base/dev/unix_signals.txt.html
написано
«Правило 3
Существует ровно один тип статических данных, sig_atomic_t, переменную
которого может установить обработчик асинхронного сигнала. Поведение
приложения не определено, если асинхронно вызванный обработчик
обращается к статическим данным любым другим способом.»
В этой статье, однако, есть противоречия.
3.
Цикл опроса waitpid().
А как по другому?
alarm() уже выключен. Нужно выдержать тайм-аут.
В других местах вызываем wait() в расчете
на то, что SIGKILL сделает свое дело.
Если код заменить на этот (старый):
//--- ДОПОДЛИННЫЙ КОД ---
pid3=wait(&status); //--- борьба с зомби, блокирующий ---
//--- здесь сработает обработчик и пошлет сигнал другому процессу ---
tm=alarm(0);
fl_alarm = 0;
//--- КОНЕЦ ДОПОДЛИННОГО КОДА ---
то есть опасность прибить ни в чем неповинный процесс.
Получается, что теоретически сервер работать не может.
Как сделать правильно?
Кто знает прошу ответить.