2015-03-13 4 views
2

я пытаюсь сделать один экземпляр демона с помощью файла блокировки, но не кажется fcntl() работать, как ожидалось ...Fcntl F_GETLK всегда возвращает истину

int creat_lock_file (char * pid_fn) 
{ 
    struct flock pid_lck = {F_WRLCK, SEEK_SET, 0,  0,  0 }; 

    /* Open/Create pid file */ 
    int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640); 
    if (pid_fd == -1) 
    { 
    syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno)); 
    return -1; 
    } 

    /* Place write lock on pid file */ 
    if (fcntl(pid_fd, F_SETLK, &pid_lck) == -1) { 
    /* Unhandled error ocured */ 
    syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno)); 
    close (pid_fd); 
    return -1; 
    } 

    /* Write PID to lock file */ 
    char pid_lock_buf[11]; 
    sprintf (pid_lock_buf, "%ld\n", (long) getpid()); 
    write (pid_fd, pid_lock_buf, strlen (pid_lock_buf)+1); 

    return 0; 
} 

int get_lock_file_status (char * pid_fn) 
{ 
    struct flock pid_lck = {F_WRLCK, SEEK_SET, 0,  0,  0 }; 

    /* Open/Create pid file */ 
    int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640); 
    if (pid_fd == -1) 
    { 
    syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno)); 
    return -1; 
    } 

    /* try locking pid file*/ 
    if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1) 
    { 
    if(errno == EAGAIN || errno == EACCES) /* file already locked, close fd and return -1 */ 
    { 
     close (pid_fd); 
     return -1; 
    } 
    else /* Unhandled error ocured */ 
    { 
     syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno)); 
     close (pid_fd); 
     return -1; 
    } 
    } 

    close (pid_fd); 
    return 0; 
} 

так я называю get_lock_file_status и выхода из него, если возвращает -1, чтобы убедиться, что ни один другой экземпляр не работает, чем я делаю некоторые вещи (fork chdir и т. д.) и вызываю creat_lock_file для создания и блокировки файла pid после успешного создания демона ...

при выполнении и запуске программы поскольку ожидаемые прогоны создают файл блокировки и записывают pid на него, но когда второй экземпляр запускается, второй экземпляр просто открывает тот же файл блокировки и записывает его собственный pid!

что я делаю неправильно? не должен ли второй экземпляр возвращать -1 в get_lock_file_status?

+0

это, кажется, неправильный подход. для программирования блокировки файла функция flock() представляется правильным подходом. Эта функция в linux подробно описана в «man 2 flock» или по адресу: user3629249

+0

@ user3629249: 'fcntl (2)' с 'F_SET/GET/LK' в порядке, а также POSIX, который' flock (2) 'не является (хотя он широко доступен). Эти два метода имеют различное поведение w.r.t. блокировка наследования и некоторые другие вещи. 'fcntl()' может устанавливать блокировки в области файлов, которые 'flock()' не могут. – Ulfalizer

ответ

1

Вы проверяете результат F_GETLK не в том направлении. fcntl(2) с F_GETLK возвращает только -1 при ошибках. Правильный способ проверить, если можно было бы получить блокировку, чтобы проверить, если l_type поле struct flock устанавливается в F_UNLCK, как в следующем:

/* try locking pid file*/ 
if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1) { 
    syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno)); 
    close(pid_fd); 
    return -1; 
} 
close(pid_fd); 
return (pid_lck.l_type == F_UNLCK) ? 0 : -1; 

Должна быть обеспечена возможность катиться creat_lock_file() и get_lock_file_status() в одну функцию, которая открывает файл (и создает его, если он не существует), пытается установить блокировку на нем и возвращает, была ли блокировка успешной (например, файловый дескриптор или -1).

Вы должны truncate(2) PID-файл до нулевого байта, прежде чем записывать PID в него. Скажем, что PID вашего процесса равен 5, а старый PID в PID-файле - 123. Написание «5» затем сделает содержимое PID-файла «523». Усечение файла до нулевого байта решает эту проблему. (O_TRUNC не будет работать, так как вы очищаете файл при его открытии, чтобы проверить, установлен ли блокировка.)

Удаление файла PID с помощью unlink(2), когда программа выходит, также довольно распространена. Таким образом, отсутствие файла указывает, что демон не работает (хотя он не является надежным, поскольку процесс или система могут быть повреждены).

+0

Привет, спасибо за ответ, так как я прочитал ваш ответ. Я подумал о том, что вы сказали, что тестирование, если файл существует, не является хорошей идеей, потому что программа может сломаться и не успевать 'unlink()' этот файл, но что, если я читаю файл и пытаюсь найти pid, чтобы проверить, работает ли какой-либо процесс с одним и тем же pid? Это хорошая идея? –

+0

@AristosMiliaressis: Использование блокировки файлов, чтобы проверить, запущен ли демон, будет работать, даже если демон сработает и не удалит файл PID. Если демона аварийно завершает работу, блокировка файла автоматически удаляется (потому что привязана к процессу), и новый экземпляр демона сможет заблокировать файл (который говорит ему, что другой экземпляр не запущен). – Ulfalizer

+0

Для проверки того, действительно ли демон работает от, например, оболочка, проверяя, есть ли процесс с тем же PID, что и в файле, должен работать, да. Он * может * потерпеть неудачу, если демон сработает, а какой-то другой процесс произойдет с тем же PID, но это будет довольно необычно. (И вы могли бы проверить, что команда, которая начала процесс, была с 'ps (1)' тоже, чтобы убедиться.) – Ulfalizer

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

  • Нет связанных вопросов^_^