namespace utils {
-void signalBlock(const int signalToBlock)
+namespace {
+
+void setSignalMask(int how, const ::sigset_t& set)
{
+ int ret = ::pthread_sigmask(how, &set, nullptr /*&oldSet*/);
+ if(ret != 0) {
+ const std::string msg = getSystemErrorMessage(ret);
+ LOGE("Error in pthread_sigmask: " << msg);
+ throw UtilsException("Error in pthread_sigmask: " + msg);
+ }
+}
+
+void changeSignal(int how, const int sigNum) {
::sigset_t set;
- if (-1 == ::sigemptyset(&set)) {
+ if(-1 == ::sigemptyset(&set)) {
const std::string msg = getSystemErrorMessage();
- LOGE("Error in sigemptyset: " << msg);
- throw UtilsException("Error in sigemptyset: " + msg);
+ LOGE("Error in sigfillset: " << msg);
+ throw UtilsException("Error in sigfillset: " + msg);
}
- if (-1 ==::sigaddset(&set, signalToBlock)) {
+ if(-1 ==::sigaddset(&set, sigNum)) {
const std::string msg = getSystemErrorMessage();
- LOGE("Error in sigaddset: " << msg);
- throw UtilsException("Error in sigaddset: " + msg);
+ LOGE("Error in sigdelset: " << msg);
+ throw UtilsException("Error in sigdelset: " + msg);
}
- int ret = ::pthread_sigmask(SIG_BLOCK, &set, nullptr /*&oldSet*/);
- if (ret != 0) {
- LOGE("Error in pthread_sigmask: " << std::to_string(ret));
- throw UtilsException("Error in pthread_sigmask: " + std::to_string(ret));
+ setSignalMask(how, set);
+}
+
+}// namespace
+
+::sigset_t getSignalMask()
+{
+ ::sigset_t set;
+ int ret = ::pthread_sigmask(0 /*ignored*/, nullptr /*get the oldset*/, &set);
+ if(ret != 0) {
+ const std::string msg = getSystemErrorMessage(ret);
+ LOGE("Error in pthread_sigmask: " << msg);
+ throw UtilsException("Error in pthread_sigmask: " + msg);
+ }
+ return set;
+}
+
+bool isSignalBlocked(const int sigNum)
+{
+ ::sigset_t set = getSignalMask();
+
+ int ret = ::sigismember(&set, sigNum);
+ if(-1 == ret) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in sigismember: " << msg);
+ throw UtilsException("Error in sigismember: " + msg);
}
+
+ return ret == 1;
+}
+
+void signalBlock(const int sigNum)
+{
+ changeSignal(SIG_BLOCK, sigNum);
+}
+
+void signalBlockAll()
+{
+ ::sigset_t set;
+ if(-1 == ::sigfillset(&set)) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in sigfillset: " << msg);
+ throw UtilsException("Error in sigfillset: " + msg);
+ }
+
+ setSignalMask(SIG_BLOCK, set);
+}
+
+void signalUnblock(const int sigNum)
+{
+ changeSignal(SIG_UNBLOCK, sigNum);
}
} // namespace utils
#ifndef COMMON_UTILS_SIGNAL_HPP
#define COMMON_UTILS_SIGNAL_HPP
+#include <csignal>
+
namespace utils {
-void signalBlock(const int signalsToBlock);
+::sigset_t getSignalMask();
+bool isSignalBlocked(const int sigNum);
+void signalBlockAll();
+void signalBlock(const int sigNum);
+void signalUnblock(const int sigNum);
} // namespace utils
--- /dev/null
+/*
+* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Contact: Jan Olszak <j.olszak@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief Eventfd wrapper
+ */
+
+#include "utils/signalfd.hpp"
+#include "utils/signal.hpp"
+#include "utils/fd-utils.hpp"
+#include "utils/exception.hpp"
+#include "logger/logger.hpp"
+
+#include <functional>
+
+namespace utils {
+
+SignalFD::SignalFD(ipc::epoll::EventPoll& eventPoll)
+ :mEventPoll(eventPoll)
+{
+ ::sigset_t set = getSignalMask();
+
+ mFD = ::signalfd(-1, &set, SFD_CLOEXEC);
+ if (mFD == -1) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in signalfd: " << msg);
+ throw UtilsException("Error in signalfd: " + msg);
+ }
+
+ mEventPoll.addFD(mFD, EPOLLIN, std::bind(&SignalFD::handleInternal, this));
+}
+
+SignalFD::~SignalFD()
+{
+ mEventPoll.removeFD(mFD);
+ utils::close(mFD);
+}
+
+int SignalFD::getFD() const
+{
+ return mFD;
+}
+
+void SignalFD::setHandler(const int sigNum, const Callback&& callback)
+{
+ Lock lock(mMutex);
+
+ bool isBlocked = isSignalBlocked(sigNum);
+
+ ::sigset_t set = getSignalMask();
+ if(!isBlocked) {
+ signalBlock(sigNum);
+ }
+
+ int error = ::signalfd(mFD, &set, SFD_CLOEXEC);
+ if (error != mFD) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in signalfd: " << msg);
+ if(!isBlocked) {
+ signalUnblock(sigNum);
+ }
+ throw UtilsException("Error in signalfd: " + msg);
+ }
+
+ mCallbacks.insert({sigNum, callback});
+}
+
+void SignalFD::handleInternal()
+{
+ signalfd_siginfo sigInfo;
+ utils::read(mFD, &sigInfo, sizeof(sigInfo));
+
+ LOGD("Got signal: " << sigInfo.ssi_signo);
+
+ {
+ Lock lock(mMutex);
+ auto it = mCallbacks.find(sigInfo.ssi_signo);
+ if (it == mCallbacks.end()) {
+ // Meantime the callback was deleted
+ LOGE("No callback for signal: " << sigInfo.ssi_signo);
+ return;
+ }
+
+ it->second(sigInfo.ssi_signo);
+ }
+}
+
+} // namespace utils
--- /dev/null
+/*
+* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Contact: Jan Olszak <j.olszak@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief Eventfd wrapper
+ */
+
+#ifndef COMMON_UTILS_SIGNALFD_HPP
+#define COMMON_UTILS_SIGNALFD_HPP
+
+#include "ipc/epoll/event-poll.hpp"
+
+#include <csignal>
+#include <sys/signalfd.h>
+
+#include <functional>
+#include <mutex>
+#include <unordered_map>
+#include <memory>
+
+namespace utils {
+
+/**
+ * SignalFD takes control over handling signals
+ * sent to the thread.
+ *
+ * It should be the only place where signal masks are modified.
+ */
+class SignalFD {
+public:
+ typedef std::function<void(const int sigNum)> Callback;
+
+ SignalFD(ipc::epoll::EventPoll& eventPoll);
+ ~SignalFD();
+
+ SignalFD(const SignalFD& signalfd) = delete;
+ SignalFD& operator=(const SignalFD&) = delete;
+
+ /**
+ * Add a callback for a specified signal
+ *
+ * @param sigNum number of the signal
+ * @param callback handler callback
+ */
+ void setHandler(const int sigNum, const Callback&& callback);
+
+ /**
+ * @return signal file descriptor
+ */
+ int getFD() const;
+
+private:
+ typedef std::unique_lock<std::mutex> Lock;
+
+ int mFD;
+ std::mutex mMutex;
+ ipc::epoll::EventPoll& mEventPoll;
+ std::unordered_map<int, Callback> mCallbacks;
+
+ void handleInternal();
+};
+
+} // namespace utils
+
+#endif // COMMON_UTILS_SIGNALFD_HPP
void removeFD(const int fd);
/**
- * Dispatch at most one signalled FD
+ * Dispatch at most one signaled FD
* @param timeoutMs how long should wait in case of no pending events
* (0 - return immediately, -1 - wait forever)
* @return false on timeout
#include "logger/backend-stderr.hpp"
#include "logger/backend-journal.hpp"
#include "utils/typeinfo.hpp"
+#include "utils/signal.hpp"
#include <boost/program_options.hpp>
#include <iostream>
}
try {
+ // Block all signals
+ // Server will unblock handled signals
+ utils::signalBlockAll();
+
Server server(CONFIG_PATH);
server.run(runAsRoot);
server.reloadIfRequired(argv);
#include <cerrno>
#include <string>
#include <cstring>
-#include <atomic>
#include <unistd.h>
#include <pwd.h>
#include <sys/stat.h>
namespace vasum {
-
Server::Server(const std::string& configPath)
- : mConfigPath(configPath)
+ : mIsUpdate(false),
+ mConfigPath(configPath),
+ mSignalFD(mDispatcher.getPoll())
{
-}
-
-
-namespace {
-
-std::atomic_bool gUpdateTriggered(false);
-utils::Latch gSignalLatch;
+ mSignalFD.setHandler(SIGINT, [this](int) {
+ mStopLatch.set();
+ });
-void signalHandler(const int sig)
-{
- LOGI("Got signal " << sig);
+ mSignalFD.setHandler(SIGTERM, [this] (int) {
+ mStopLatch.set();
+ });
- if (sig == SIGUSR1) {
+ mSignalFD.setHandler(SIGUSR1, [this] (int) {
LOGD("Received SIGUSR1 - triggering update.");
- gUpdateTriggered = true;
- }
-
- gSignalLatch.set();
+ mIsUpdate = true;
+ mStopLatch.set();
+ });
}
-} // namespace
-
void Server::run(bool asRoot)
{
if (!prepareEnvironment(mConfigPath, asRoot)) {
throw ServerException("Environment setup failed");
}
- signal(SIGINT, signalHandler);
- signal(SIGTERM, signalHandler);
- signal(SIGUSR1, signalHandler);
- utils::signalBlock(SIGPIPE);
-
LOGI("Starting daemon...");
{
utils::ScopedGlibLoop loop;
ZonesManager manager(mDispatcher.getPoll(), mConfigPath);
// Do not restore zones state at Vasum start
- // manager.restoreAll();
LOGI("Daemon started");
- gSignalLatch.wait();
+ mStopLatch.wait();
// Detach zones if we triggered an update
- if (gUpdateTriggered) {
+ if (mIsUpdate) {
manager.setZonesDetachOnExit();
}
LOGI("Stopping daemon...");
- // manager.shutdownAll() will be called in destructor
}
LOGI("Daemon stopped");
}
void Server::reloadIfRequired(char* argv[])
{
- if (gUpdateTriggered) {
+ if (mIsUpdate) {
execve(argv[0], argv, environ);
LOGE("Failed to reload " << argv[0] << ": " << getSystemErrorMessage());
}
void Server::terminate()
{
LOGI("Terminating server");
- gSignalLatch.set();
+ mStopLatch.set();
}
bool Server::checkEnvironment()
// directory or symlink
// CAP_SETUID is needed to launch specific funtions as root (see environment.cpp)
return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN,
- CAP_MAC_OVERRIDE,
- CAP_SYS_TTY_CONFIG,
- CAP_CHOWN,
- CAP_SETUID}));
+ CAP_MAC_OVERRIDE,
+ CAP_SYS_TTY_CONFIG,
+ CAP_CHOWN,
+ CAP_SETUID
+ }));
}
#define SERVER_SERVER_HPP
#include "utils/latch.hpp"
+#include "utils/signalfd.hpp"
#include "ipc/epoll/thread-dispatcher.hpp"
+#include <atomic>
#include <string>
static bool checkEnvironment();
private:
+ std::atomic_bool mIsUpdate;
std::string mConfigPath;
+ utils::Latch mStopLatch;
ipc::epoll::ThreadDispatcher mDispatcher;
-
+ utils::SignalFD mSignalFD;
/**
* Set needed caps, groups and drop root privileges.
*/
)
TARGET_LINK_LIBRARIES(${ZONE_DAEMON_CODENAME} ${ZONE_DAEMON_DEPS_LIBRARIES}
- ${Boost_LIBRARIES} Logger SimpleDbus)
+ ${Boost_LIBRARIES} Logger SimpleDbus Ipc)
## Install #####################################################################