wip: Inter-process messaging

This commit is contained in:
Michael Carlberg 2016-11-13 19:05:30 +01:00
parent c480f6fd1e
commit 489f3ce480
7 changed files with 164 additions and 30 deletions

View File

@ -79,5 +79,7 @@ set(SETTING_PATH_MEMORY_INFO "/proc/meminfo"
CACHE STRING "Path to file containing memory info") CACHE STRING "Path to file containing memory info")
set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp" set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp"
CACHE STRING "Path to file containing the current temperature") CACHE STRING "Path to file containing the current temperature")
set(SETTING_PATH_MESSAGING_FIFO "/tmp/lemonbuddy_mqueue.%pid%"
CACHE STRING "Path to file containing the current temperature")
# }}} # }}}

View File

@ -4,8 +4,8 @@
#include "components/bar.hpp" #include "components/bar.hpp"
#include "components/config.hpp" #include "components/config.hpp"
#include "components/eventloop.hpp" #include "components/eventloop.hpp"
#include "components/ipc.hpp"
#include "components/logger.hpp" #include "components/logger.hpp"
#include "components/signals.hpp"
#include "config.hpp" #include "config.hpp"
#include "utils/command.hpp" #include "utils/command.hpp"
#include "utils/inotify.hpp" #include "utils/inotify.hpp"
@ -17,12 +17,13 @@ LEMONBUDDY_NS
class controller { class controller {
public: public:
explicit controller(connection& conn, const logger& logger, const config& config, unique_ptr<eventloop> eventloop, explicit controller(connection& conn, const logger& logger, const config& config, unique_ptr<eventloop> eventloop,
unique_ptr<bar> bar, inotify_util::watch_t& confwatch) unique_ptr<bar> bar, unique_ptr<ipc> ipc, inotify_util::watch_t& confwatch)
: m_connection(conn) : m_connection(conn)
, m_log(logger) , m_log(logger)
, m_conf(config) , m_conf(config)
, m_eventloop(forward<decltype(eventloop)>(eventloop)) , m_eventloop(forward<decltype(eventloop)>(eventloop))
, m_bar(forward<decltype(bar)>(bar)) , m_bar(forward<decltype(bar)>(bar))
, m_ipc(forward<decltype(ipc)>(ipc))
, m_confwatch(confwatch) {} , m_confwatch(confwatch) {}
~controller(); ~controller();
@ -53,6 +54,7 @@ class controller {
const config& m_conf; const config& m_conf;
unique_ptr<eventloop> m_eventloop; unique_ptr<eventloop> m_eventloop;
unique_ptr<bar> m_bar; unique_ptr<bar> m_bar;
unique_ptr<ipc> m_ipc;
stateflag m_running{false}; stateflag m_running{false};
stateflag m_reload{false}; stateflag m_reload{false};
@ -67,7 +69,7 @@ class controller {
inotify_util::watch_t& m_confwatch; inotify_util::watch_t& m_confwatch;
command_util::command_t m_command; command_util::command_t m_command;
bool m_writeback = false; bool m_writeback{false};
}; };
namespace { namespace {
@ -83,7 +85,8 @@ namespace {
configure_logger(), configure_logger(),
configure_config(), configure_config(),
configure_eventloop(), configure_eventloop(),
configure_bar()); configure_bar(),
configure_ipc());
// clang-format on // clang-format on
} }
} }

View File

@ -0,0 +1,54 @@
#pragma once
#include "common.hpp"
#include "components/logger.hpp"
LEMONBUDDY_NS
/**
* Component used for inter-process communication.
*
* A unique messaging channel will be setup for each
* running process which will allow messages and
* events to be sent to the process externally.
*/
class ipc {
public:
struct message_internal {
static constexpr auto prefix{"app:"};
};
struct message_command {
static constexpr auto prefix{"cmd:"};
};
struct message_custom {
static constexpr auto prefix{"custom:"};
};
explicit ipc(const logger& logger) : m_log(logger) {}
~ipc();
void receive_messages();
protected:
void parse(string payload);
private:
const logger& m_log;
stateflag m_running{false};
string m_fifo;
int m_fd;
};
namespace {
/**
* Configure injection module
*/
template <typename T = unique_ptr<ipc>>
di::injector<T> configure_ipc() {
return di::make_injector(configure_logger());
}
}
LEMONBUDDY_NS_END

View File

@ -39,6 +39,7 @@
#define PATH_CPU_INFO "@SETTING_PATH_CPU_INFO@" #define PATH_CPU_INFO "@SETTING_PATH_CPU_INFO@"
#define PATH_MEMORY_INFO "@SETTING_PATH_MEMORY_INFO@" #define PATH_MEMORY_INFO "@SETTING_PATH_MEMORY_INFO@"
#define PATH_TEMPERATURE_INFO "@SETTING_PATH_TEMPERATURE_INFO@" #define PATH_TEMPERATURE_INFO "@SETTING_PATH_TEMPERATURE_INFO@"
#define PATH_MESSAGING_FIFO "@SETTING_PATH_MESSAGING_FIFO@"
auto print_build_info = []() { auto print_build_info = []() {
// clang-format off // clang-format off

View File

@ -2,6 +2,12 @@
#include <mutex> #include <mutex>
#include "components/controller.hpp" #include "components/controller.hpp"
#include "components/bar.hpp"
#include "components/config.hpp"
#include "components/eventloop.hpp"
#include "components/ipc.hpp"
#include "components/logger.hpp"
#include "components/signals.hpp" #include "components/signals.hpp"
#include "modules/backlight.hpp" #include "modules/backlight.hpp"
#include "modules/battery.hpp" #include "modules/battery.hpp"
@ -56,6 +62,11 @@ controller::~controller() {
m_eventloop.reset(); m_eventloop.reset();
} }
if (m_ipc) {
m_log.info("Deconstructing ipc");
m_ipc.reset();
}
if (m_bar) { if (m_bar) {
m_log.info("Deconstructing bar"); m_log.info("Deconstructing bar");
m_bar.reset(); m_bar.reset();
@ -94,30 +105,23 @@ void controller::bootstrap(bool writeback, bool dump_wmname) {
// Listen for events on the root window to be able to // Listen for events on the root window to be able to
// break the blocking wait call when cleaning up // break the blocking wait call when cleaning up
m_log.trace("controller: Listen for events on the root window"); m_log.trace("controller: Listen for events on the root window");
try {
const uint32_t value_list[2]{XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY}; const uint32_t value_list[2]{XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
m_connection.change_window_attributes_checked(m_connection.root(), XCB_CW_EVENT_MASK, value_list); m_connection.change_window_attributes_checked(m_connection.root(), XCB_CW_EVENT_MASK, value_list);
} catch (const exception& err) {
throw application_error("Failed to change root window event mask: " + string{err.what()});
}
try {
m_log.trace("controller: Setup bar"); m_log.trace("controller: Setup bar");
m_bar->bootstrap(m_writeback || dump_wmname); m_bar->bootstrap(m_writeback || dump_wmname);
m_bar->bootstrap_tray(); m_bar->bootstrap_tray();
} catch (const exception& err) {
throw application_error("Failed to setup bar renderer: " + string{err.what()});
}
if (dump_wmname) { if (dump_wmname) {
std::cout << m_bar->settings().wmname << std::endl; std::cout << m_bar->settings().wmname << std::endl;
return; return;
} }
m_log.trace("controller: Attach eventloop callbacks"); m_log.trace("controller: Attach eventloop update callback");
m_eventloop->set_update_cb(bind(&controller::on_update, this)); m_eventloop->set_update_cb(bind(&controller::on_update, this));
if (!m_writeback) { if (!m_writeback) {
m_log.trace("controller: Attach eventloop input callback");
g_signals::bar::action_click = bind(&controller::on_mouse_event, this, placeholders::_1); g_signals::bar::action_click = bind(&controller::on_mouse_event, this, placeholders::_1);
m_eventloop->set_input_db(bind(&controller::on_unrecognized_action, this, placeholders::_1)); m_eventloop->set_input_db(bind(&controller::on_unrecognized_action, this, placeholders::_1));
} }
@ -138,6 +142,11 @@ bool controller::run() {
install_sigmask(); install_sigmask();
install_confwatch(); install_confwatch();
#if DEBUG
// Start listening for ipc messages
m_threads.emplace_back(thread(&ipc::receive_messages, m_ipc.get()));
#endif
// Listen for X events in separate thread // Listen for X events in separate thread
if (!m_writeback) { if (!m_writeback) {
m_threads.emplace_back(thread(&controller::wait_for_xevent, this)); m_threads.emplace_back(thread(&controller::wait_for_xevent, this));

67
src/components/ipc.cpp Normal file
View File

@ -0,0 +1,67 @@
#include <fcntl.h>
#include <sys/stat.h>
#include "components/ipc.hpp"
#include "config.hpp"
#include "utils/file.hpp"
#include "utils/io.hpp"
#include "utils/string.hpp"
LEMONBUDDY_NS
/**
* Interrupt the blocked listener and
* remove the file handler
*/
ipc::~ipc() {
m_running = false;
if (!m_fifo.empty()) {
m_log.info("Interrupting ipc message receiver");
auto f{make_unique<file_util::file_ptr>(m_fifo)};
char p[1]{'q'};
fwrite(p, sizeof(char), sizeof(p), (*f)());
unlink(m_fifo.c_str());
}
}
/**
* Start listening for event messages
*/
void ipc::receive_messages() {
m_running = true;
m_fifo = string_util::replace(PATH_MESSAGING_FIFO, "%pid%", to_string(getpid()));
if (mkfifo(m_fifo.c_str(), 0666) == -1) {
m_log.err("Failed to create messaging channel");
}
m_log.info("Listening for ipc messages on: %s", m_fifo);
while ((m_fd = open(m_fifo.c_str(), O_RDONLY)) != -1 && m_running) {
parse(io_util::readline(m_fd));
close(m_fd);
}
}
/**
* Process received message and delegate
* valid events to the target modules
*/
void ipc::parse(string payload) {
if (payload.empty()) {
return;
} else if (payload.find(message_internal::prefix) == 0) {
m_log.info("Received internal message: (payload=%s)", payload);
} else if (payload.find(message_command::prefix) == 0) {
m_log.info("Received command message: (payload=%s)", payload);
} else if (payload.find(message_custom::prefix) == 0) {
m_log.info("Received custom message: (payload=%s)", payload);
} else {
m_log.info("Received unknown message: (payload=%s)", payload);
}
}
LEMONBUDDY_NS_END

View File

@ -37,26 +37,24 @@ namespace io_util {
} }
string readline(int read_fd, int& bytes_read) { string readline(int read_fd, int& bytes_read) {
std::stringstream buffer; stringstream buffer;
char char_; char char_;
int bytes = 0;
bytes_read = 0; bytes_read = 0;
while ((bytes_read += ::read(read_fd, &char_, 1)) > 0) { while ((bytes = ::read(read_fd, &char_, 1)) > 0) {
buffer << char_; if (bytes <= 0)
break;
if (char_ == '\n' || char_ == '\x00') if (char_ == '\n' || char_ == '\x00')
break; break;
bytes_read += bytes;
buffer << char_;
} }
if (bytes_read == 0) { if (bytes_read <= 0)
// Reached EOF
} else if (bytes_read == -1) {
// Read failed
} else {
return string_util::strip_trailing_newline(buffer.str());
}
return ""; return "";
return string_util::strip_trailing_newline(buffer.str());
} }
string readline(int read_fd) { string readline(int read_fd) {