Skip to content

Commit 415b4a2

Browse files
optional feature: use named semaphore to protect shared memory
1 parent 7866543 commit 415b4a2

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

src/main.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
#include "license.hpp"
88
#include "readline.hpp"
99

10+
#include "cxxsemaphore.hpp"
1011
#include "cxxshm.hpp"
1112
#include <array>
1213
#include <chrono>
14+
#include <cmath>
1315
#include <csignal>
1416
#include <cxxendian/endian.hpp>
1517
#include <cxxopts.hpp>
@@ -30,6 +32,15 @@ static constexpr double MIN_BASH_SLEEP = 0.1;
3032
//! number of digits that have to be printed for bash sleep instructions
3133
constexpr int SLEEP_DIGITS = 1;
3234

35+
//* value to increment error counter if semaphore could not be acquired
36+
static constexpr long SEMAPHORE_ERROR_INC = 10;
37+
38+
//* value to decrement error counter if semaphore could be acquired
39+
static constexpr long SEMAPHORE_ERROR_DEC = 1;
40+
41+
//* maximum value of semaphore error counter
42+
static constexpr long SEMAPHORE_ERROR_MAX = 100;
43+
3344
constexpr std::array<int, 10> TERM_SIGNALS = {SIGINT,
3445
SIGTERM,
3546
SIGHUP,
@@ -90,6 +101,12 @@ int main(int argc, char **argv) {
90101
options.add_options()("license", "show licenses");
91102
options.add_options()("data-types", "show list of supported data type identifiers");
92103
options.add_options()("constants", "list string constants that can be used as value");
104+
options.add_options()("semaphore",
105+
"protect the shared memory with an existing named semaphore against simultaneous access",
106+
cxxopts::value<std::string>());
107+
options.add_options()("semaphore-timeout",
108+
"maximum time (in seconds) to wait for semaphore (default: 0.1)",
109+
cxxopts::value<double>()->default_value("0.1"));
93110

94111
// parse arguments
95112
cxxopts::ParseResult args;
@@ -371,6 +388,29 @@ int main(int argc, char **argv) {
371388

372389
std::mutex m; // to ensure that the program is not terminated while it writes to a shared memory
373390

391+
std::unique_ptr<cxxsemaphore::Semaphore> semaphore;
392+
long semaphore_error_counter = 0;
393+
if (args.count("semaphore")) {
394+
try {
395+
semaphore = std::make_unique<cxxsemaphore::Semaphore>(args["semaphore"].as<std::string>());
396+
} catch (const std::exception &e) {
397+
std::cerr << e.what() << std::endl;
398+
return EX_SOFTWARE;
399+
}
400+
}
401+
402+
const double SEMAPHORE_TIMEOUT_S = args["semaphore-timeout"].as<double>();
403+
if (SEMAPHORE_TIMEOUT_S < 0.000'001) {
404+
std::cerr << "semaphore-timeout: invalid value" << std::endl;
405+
return EX_USAGE;
406+
}
407+
408+
double modf_dummy {};
409+
const timespec SEMAPHORE_MAX_TIME = {
410+
static_cast<time_t>(args["semaphore-timeout"].as<double>()),
411+
static_cast<suseconds_t>(std::modf(SEMAPHORE_TIMEOUT_S, &modf_dummy) * 1'000'000),
412+
};
413+
374414
std::cout << std::fixed;
375415

376416
auto last_time = std::chrono::steady_clock::now();
@@ -441,6 +481,24 @@ int main(int argc, char **argv) {
441481

442482
// write value to target
443483
std::lock_guard<std::mutex> guard(m);
484+
485+
if (semaphore) {
486+
while (!semaphore->wait(SEMAPHORE_MAX_TIME)) {
487+
std::cerr << " WARNING: Failed to acquire semaphore '" << semaphore->get_name() << "' within "
488+
<< SEMAPHORE_TIMEOUT_S << "s." << std::endl;
489+
490+
semaphore_error_counter += SEMAPHORE_ERROR_INC;
491+
492+
if (semaphore_error_counter >= SEMAPHORE_ERROR_MAX) {
493+
std::cerr << "ERROR: Repeatedly failed to acquire the semaphore" << std::endl;
494+
return EX_SOFTWARE;
495+
}
496+
}
497+
498+
semaphore_error_counter -= SEMAPHORE_ERROR_DEC;
499+
if (semaphore_error_counter < 0) semaphore_error_counter = 0;
500+
}
501+
444502
for (auto &input_data : instructions) {
445503
switch (input_data.register_type) {
446504
case InputParser::Instruction::register_type_t::DO: {
@@ -542,6 +600,8 @@ int main(int argc, char **argv) {
542600
break;
543601
}
544602
}
603+
604+
if (semaphore && semaphore->is_acquired()) semaphore->post();
545605
}
546606

547607
rl_clear_history();

0 commit comments

Comments
 (0)