LINUX.ORG.RU

[СИ] Прервать процесс.

 


0

1

[СИ] Прервать процесс.

Язык СИ ОС UNIX

Требуется прервать процесс, подвисший на блокировке файла fcntl.
Имеется кусок кода:


   int volatile fl_int = 0;
   int volatile fd_int = -1;


void sigint(int n)
{
    close(fd_int);
    fl_int=1;
    return;
}

      ....
      
    signal(SIGINT, sigint);
    sigprocmask(SIG_SETMASK, &mask2, NULL);   //--- блокирует SIGINT ---

      ....
      
    fd_int=fd;
    sigprocmask(SIG_SETMASK, &mask1, NULL);   //--- разблокирует SIGINT ---
    k=my_lock(fd, F_WRLCK);                   //--- блокировка файла fcntl ---
    sigprocmask(SIG_SETMASK, &mask2, NULL);   //--- блокирует SIGINT ---
    fd_int=-1;
    if(fl_int > 0){ fd=-1; return(-1);}
    
      ....

При опробовании это работает. Но при опробовании много чего
работает. А будет ли это работать всегда? Я имею в виду вызов
close() в обработчике сигналов. Вынести его из обработчика
(с использованием sigaction и сброшенным флагом SA_RESTART)
плохо тем, что сигнал может придти между разблокированием
сигнала и блокировкой файла. И я безнадежно зависну
на блокировке файла.

В книге Стивенса
«UNIX взимодействие процессов» в таблице 5.1 приведен список
функций, допустимых в обработчике по POSIX. В этот список
функция close() входит. Там же в примечании к этой таблице
указаны функции по ANSI C и UNIX 98. close() там нет.

Чем руководствоваться практически? Или есть ли другие способы
обойти эту двусмысленность?

Кто знает прошу ответить.


fcntl прерванный по сигналу ввероятно возвращает ложное значение. Можно проверять его и делать что нужно.

Olegymous ★★★
()

При урезании куска допустил ошибку:
if(fl_int > 0){ fd=-1; return(-1);}
следует читать
if(fl_int > 0){ fd=-1; goto ERR;}
а то fd=-1; не имеет смысла.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

Olegymous
Да.
Но вопрос в том, что сигнал может придти после разблокировки сигнала
и проверки глобального флага, но до вызова fcntl. Зависание.

В подобном случае для select-а есть pselect.

oleg_2
() автор топика
Ответ на: комментарий от Olegymous

А до разблокировки какой смысл, обработчик сигнала еще не отработает.
Сейчас проверка флага внизу, после всего. Потому что в обработчике
закрывается файл, и когда бы это ни случилось - до вызова fcntl или
по прерыванию fcntl, на закрытый файл fcntl сразу выдает ошибку.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2
обработчик() {
  // ничего не делать
}

блокировка сигнала
rv = fcntl()
разблокировка сигнала
if(rv == -1) {
  // был сигнал
}

Чем это плохо (кроме синтаксиса 1С)?

Olegymous ★★★
()
Ответ на: комментарий от Olegymous

точнее наоборот


обработчик() {
  // ничего не делать
}

разблокировка сигнала
rv = fcntl()
блокировка сигнала
if(rv == -1) {
  // был сигнал
}

Olegymous ★★★
()
Ответ на: комментарий от Olegymous

А вот идея, только что пришедшая в голову.
Что если в обработчике присваивать значение
команде.


Прототип:
int fcntl(int fd, int cmd, struct flock *lock);[br]


Сейчас:

int my_lock(int fd,int cmd)
{int k;struct flock  lock;
 lock.l_type=cmd;
 lock.l_whence=SEEK_SET;
 lock.l_start=0;
 lock.l_len=0;
 k=fcntl(fd,F_SETLKW,&lock);
 return(k);
}

      ....
    k=my_lock(fd, F_WRLCK);
      ....


А сделать примерно так:


    gl_cmd = F_WRLCK;


void sigint(int n)
{
    gl_cmd = F_UNLCK;  //--- глобальная ---
    fl_int=1;
    return;
}

      ....
    k=my_lock(fd, gl_cmd);
      ....


Меняем команду на случай до вызова fcntl.
После вызова fcntl прерываемся штатно по сигналу.
Наспех написал, наверное что-то напутал.

oleg_2
() автор топика
Ответ на: комментарий от anonymous

anonymous
Может быть.
Я с ними еще не работал.
А пока моё решение последнее как будто тоже должно бы работать?
И не сложно.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

Заменить только signal на sigaction, а то уходит на RESTART.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

> Может быть.

Я с ними еще не работал.

А посмотри, нечё сложного, на самом деле. А если прога заточена на I/O то сам бог велел.)))

anonymous
()
Ответ на: комментарий от oleg_2

не, так не сработает (если я правильно понял, что ты имеешь
в виду).

все равно остается окно для сигнала перед вызовом fcntl().
нужен close(), чтобы гарантированно испортить жизнь этому
syscall'у.

ну, или siglongjmp(), но это не есть гуд.

idle ★★★★★
()

Пользователи асинхронной LockFileEx() смотрят на линуксойдов непонимающе.

anonymous
()
Ответ на: комментарий от oleg_2

Нет, так не сработает. У вас выполнение программы идёт не по операторам языка Си, а по машинным командам. И сигнал может предти «за такт» до вызова syscall'а, когда уже сформированы его параметры.

ИМХО, можно рассмотреть вариант с установкой «будильника» setitimer на небольшое значение (допустим 0,1-0,5 с). Включать его перед fcntl(), обрабатывать sigalarm и sigint, а fcntl() запускать в цикле. Заодно можно будет считать время, проведённое на fcntl() и, даже, в отсутствии sigint не ждать блокировки бесконечно.

mky ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.