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 ★★★★★
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.