common/version.cc \
common/hex.cc \
common/entity_name.cc \
- common/ceph_crypto.cc
+ common/ceph_crypto.cc \
+ common/pidfile.cc
if WITH_PROFILER
libcommon_files += perfglue/cpu_profiler.cc
tools/common.h\
tools/gui.h\
tools/gui_resources.h\
- test/osd/RadosModel.h
+ test/osd/RadosModel.h\
+ common/pidfile.h
all_sources = $(cmon_SOURCES) $(ceph_SOURCES) $(cephfs_SOURCES) $(librados_config_SOURCES) $(cauthtool_SOURCES) $(monmaptool_SOURCES) \
$(crushtool_SOURCES) $(osdmaptool_SOURCES) $(cconf_SOURCES) $(mount_ceph_SOURCES) $(cmds_SOURCES) \
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "common/errno.h"
+#include "common/pidfile.h"
+#include "common/safe_io.h"
+#include "debug.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define dout_prefix *_dout
+
+static char pid_file[PATH_MAX] = "";
+
+int pidfile_write(const md_config_t *conf)
+{
+ int ret, fd;
+
+ const char *pfile = conf->pid_file;
+ if ((pfile == NULL) || (!pfile[0])) {
+ return pidfile_remove();
+ }
+ strncpy(pid_file, pfile, PATH_MAX);
+
+ fd = TEMP_FAILURE_RETRY(::open(pid_file,
+ O_CREAT|O_TRUNC|O_WRONLY, 0644));
+ if (fd < 0) {
+ int err = errno;
+ derr << "write_pid_file: failed to open pid file '"
+ << pid_file << "': " << cpp_strerror(err) << dendl;
+ return err;
+ }
+
+ char buf[20];
+ int len = snprintf(buf, sizeof(buf), "%d\n", getpid());
+ ret = safe_write(fd, buf, len);
+ if (ret < 0) {
+ derr << "write_pid_file: failed to write to pid file '"
+ << pid_file << "': " << cpp_strerror(ret) << dendl;
+ TEMP_FAILURE_RETRY(::close(fd));
+ return ret;
+ }
+ if (TEMP_FAILURE_RETRY(::close(fd))) {
+ ret = errno;
+ derr << "SimpleMessenger::write_pid_file: failed to close to pid file '"
+ << pid_file << "': " << cpp_strerror(ret) << dendl;
+ return -ret;
+ }
+
+ return 0;
+}
+
+int pidfile_remove(void)
+{
+ if (!pid_file[0])
+ return 0;
+
+ // only remove it if it has OUR pid in it!
+ int fd = TEMP_FAILURE_RETRY(::open(pid_file, O_RDONLY));
+ if (fd < 0)
+ return -errno;
+ char buf[32];
+ memset(buf, 0, sizeof(buf));
+ ssize_t res = safe_read(fd, buf, sizeof(buf));
+ if (res < 0)
+ return res;
+ TEMP_FAILURE_RETRY(::close(fd));
+ int a = atoi(buf);
+ if (a != getpid())
+ return -EDOM;
+
+ res = ::unlink(pid_file);
+ if (res)
+ return res;
+
+ pid_file[0] = '\0';
+ return 0;
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef CEPH_COMMON_PIDFILE_H
+#define CEPH_COMMON_PIDFILE_H
+
+class md_config_t;
+
+// Write a pidfile with the current pid, using the configuration in the
+// provided conf structure.
+int pidfile_write(const md_config_t *conf);
+
+// Remove the pid file that was previously written by pidfile_write.
+// This is safe to call in a signal handler context.
+int pidfile_remove(void);
+
+#endif
#include "common/BackTrace.h"
#include "common/ProfLogger.h"
+#include "common/pidfile.h"
#include "common/debug.h"
#include "common/signal.h"
#include "common/config.h"
logger_reopen_all();
}
+static void reraise_fatal(int signum)
+{
+ // Use default handler to dump core
+ int ret = raise(signum);
+
+ // Normally, we won't get here. If we do, something is very weird.
+ char buf[1024];
+ if (ret) {
+ snprintf(buf, sizeof(buf), "reraise_fatal: failed to re-raise "
+ "signal %d\n", signum);
+ dout_emergency(buf);
+ }
+ else {
+ snprintf(buf, sizeof(buf), "reraise_fatal: default handler for "
+ "signal %d didn't terminate the process?\n", signum);
+ dout_emergency(buf);
+ }
+ exit(1);
+}
+
+static void handle_shutdown_signal(int signum)
+{
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "*** Caught signal (%s) **\n "
+ "in thread %p. Shutting down.\n",
+ sys_siglist[signum], (void*)pthread_self());
+ dout_emergency(buf);
+ pidfile_remove();
+ reraise_fatal(signum);
+}
+
static void handle_fatal_signal(int signum)
{
// This code may itself trigger a SIGSEGV if the heap is corrupt. In that
snprintf(buf, sizeof(buf), "*** Caught signal (%s) **\n "
"in thread %p\n", sys_siglist[signum], (void*)pthread_self());
dout_emergency(buf);
+ pidfile_remove();
// TODO: don't use an ostringstream here. It could call malloc(), which we
// don't want inside a signal handler.
bt.print(oss);
dout_emergency(oss.str());
- // Use default handler to dump core
- int ret = raise(signum);
-
- // Normally, we won't get here. If we do, something is very weird.
- if (ret) {
- snprintf(buf, sizeof(buf), "handle_fatal_signal: failed to re-raise "
- "signal %d\n", signum);
- dout_emergency(buf);
- }
- else {
- snprintf(buf, sizeof(buf), "handle_fatal_signal: default handler for "
- "signal %d didn't terminate the process?\n", signum);
- dout_emergency(buf);
- }
- exit(1);
+ reraise_fatal(signum);
}
std::string signal_mask_to_str()
install_sighandler(SIGXCPU, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
install_sighandler(SIGXFSZ, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
install_sighandler(SIGSYS, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
+ install_sighandler(SIGTERM, handle_shutdown_signal, SA_RESETHAND | SA_NODEFER);
+ install_sighandler(SIGINT, handle_shutdown_signal, SA_RESETHAND | SA_NODEFER);
}
void block_signals(sigset_t *old_sigset, int *siglist)
#include "common/Timer.h"
#include "common/errno.h"
+#include "common/pidfile.h"
#include "common/safe_io.h"
-#include "common/signal.h"
#define DOUT_SUBSYS ms
#undef dout_prefix
return accepter.rebind(avoid_port);
}
-static void remove_pid_file(int in_signal_handler = 0)
-{
- if (!g_conf.pid_file)
- return;
-
- // only remove it if it has OUR pid in it!
- int fd = ::open(g_conf.pid_file, O_RDONLY);
- if (fd < 0)
- return; // fail silently if there is no pid to remove
-
- char buf[32];
- memset(buf, 0, sizeof(buf));
- if (TEMP_FAILURE_RETRY(::read(fd, buf, sizeof(buf)-1)) < 0) {
- int err = errno;
- if (!in_signal_handler) {
- generic_dout(0) << "remove_pid_file: error reading " << g_conf.pid_file
- << ": " << cpp_strerror(err) << dendl;
- }
- return;
- }
- TEMP_FAILURE_RETRY(::close(fd));
-
- int a = atoi(buf);
- if (a != getpid()) {
- if (!in_signal_handler) {
- generic_dout(0) << "remove_pid_file: strange, pid file " << g_conf.pid_file
- << " has " << a << ", not expected " << getpid() << dendl;
- }
- return;
- }
-
- if (::unlink(g_conf.pid_file)) {
- int err = errno;
- if (!in_signal_handler) {
- generic_dout(0) << "remove_pid_file: error unlinking " << g_conf.pid_file
- << ": " << cpp_strerror(err) << dendl;
- }
- return;
- }
-}
-
-static void handle_signal(int sig)
-{
- remove_pid_file(sig);
- signal(sig, SIG_DFL);
- kill(getpid(), sig);
-}
-
-int SimpleMessenger::write_pid_file(int pid)
-{
- int ret, fd;
-
- if (!g_conf.pid_file)
- return 0;
-
- fd = TEMP_FAILURE_RETRY(::open(g_conf.pid_file,
- O_CREAT|O_TRUNC|O_WRONLY, 0644));
- if (fd < 0) {
- int err = errno;
- derr << "SimpleMessenger::write_pid_file: failed to open pid file '"
- << g_conf.pid_file << "': " << cpp_strerror(err) << dendl;
- return err;
- }
-
- char buf[20];
- int len = snprintf(buf, sizeof(buf), "%d\n", pid);
- ret = safe_write(fd, buf, len);
- if (ret < 0) {
- derr << "SimpleMessenger::write_pid_file: failed to write to pid file '"
- << g_conf.pid_file << "': " << cpp_strerror(ret) << dendl;
- TEMP_FAILURE_RETRY(::close(fd));
- return ret;
- }
- if (TEMP_FAILURE_RETRY(::close(fd))) {
- ret = errno;
- derr << "SimpleMessenger::write_pid_file: failed to close to pid file '"
- << g_conf.pid_file << "': " << cpp_strerror(ret) << dendl;
- return ret;
- }
-
- signal(SIGTERM, handle_signal);
- signal(SIGINT, handle_signal);
-
- return 0;
-}
-
int SimpleMessenger::start(bool daemonize, uint64_t nonce)
{
// register at least one entity, first!
int r = daemon(1, 0);
assert(r >= 0);
install_standard_sighandlers();
- write_pid_file(getpid());
+ pidfile_write(&g_conf);
if (g_conf.chdir && g_conf.chdir[0]) {
if (::chdir(g_conf.chdir)) {
dout(10) << "wait: done." << dendl;
dout(1) << "shutdown complete." << dendl;
- remove_pid_file();
+ pidfile_remove();
started = false;
did_bind = false;
my_type = -1;