2

ロックファイルを使用して単一インスタンスのデーモンを作成しようとしていますがfcntl()、期待どおりに動作しないようです...

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;
}

したがって、-1 が返された場合は呼び出しget_lock_file_statusて終了し、他のインスタンスが実行されていないことを確認しcreat_lock_file、デーモンを正常に作成した後に pid ファイルをクレートしてロックするために呼び出します...

コンパイルして実行すると、プログラムは期待どおりに動作し、ロック ファイルが作成されて pid が書き込まれますが、2 番目のインスタンスが開始されると、2 番目のインスタンスは単に同じロック ファイルを開いて独自の pid を書き込みます。

私は何を間違っていますか?2 番目のインスタンスは で -1 を返すべきではありませんget_lock_file_statusか?

4

1 に答える 1

1

F_GETLKの結果を間違った方法でチェックしています。fcntl(2)withF_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」になります。ファイルを 0 バイトに切り詰めると、この問題は解決します。(O_TRUNCロックが設定されているかどうかをテストするためにファイルを開くときにファイルをクリアするため、機能しません。)

プログラムの終了時に PID ファイルを削除することunlink(2)もかなり一般的です。そうすれば、ファイルが存在しないということは、デーモンが実行されていないことを示します (ただし、プロセスまたはシステムがクラッシュする可能性があるため、確実ではありません)。

于 2015-03-14T08:35:06.730 に答える