summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Steele <ken@ld-1.internal.tilera.com>2012-05-14 15:39:46 -0400
committerdormando <dormando@rydia.net>2013-12-08 17:12:01 -0800
commit8ae10eba01e3cf65a106b568698f439c4f54efbd (patch)
tree6121a383dbb76a80d48ad9dfbfac1ee090ea9af9
parentb2734f8321230bd52e36df7f82a6b1d71532e496 (diff)
downloadmemcached-8ae10eba01e3cf65a106b568698f439c4f54efbd.tar.gz
Create memcached pid file atomically using rename.
This change avoids a race condition where another application (e.g., testapp) can read the memcached pid file after memcached opens it, but before memcached writes the pid. It now writes the pid into a temporary file and then renames that file to the correct pid file name. This way the pid file can not exist without containing the correct value.
-rw-r--r--memcached.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/memcached.c b/memcached.c
index 86dfe88..b6ed7c9 100644
--- a/memcached.c
+++ b/memcached.c
@@ -4603,14 +4603,27 @@ static void save_pid(const char *pid_file) {
}
}
- if ((fp = fopen(pid_file, "w")) == NULL) {
- vperror("Could not open the pid file %s for writing", pid_file);
+ /* Create the pid file first with a temporary name, then
+ * atomically move the file to the real name to avoid a race with
+ * another process opening the file to read the pid, but finding
+ * it empty.
+ */
+ char tmp_pid_file[1024];
+ snprintf(tmp_pid_file, sizeof(tmp_pid_file), "%s.tmp", pid_file);
+
+ if ((fp = fopen(tmp_pid_file, "w")) == NULL) {
+ vperror("Could not open the pid file %s for writing", tmp_pid_file);
return;
}
fprintf(fp,"%ld\n", (long)getpid());
if (fclose(fp) == -1) {
- vperror("Could not close the pid file %s", pid_file);
+ vperror("Could not close the pid file %s", tmp_pid_file);
+ }
+
+ if (rename(tmp_pid_file, pid_file) != 0) {
+ vperror("Could not rename the pid file from %s to %s",
+ tmp_pid_file, pid_file);
}
}