Skip to content

Commit f5fc5e6

Browse files
committed
Serialise with lockfile during binding. Switch to clang-format
1 parent 00c4974 commit f5fc5e6

19 files changed

+803
-789
lines changed

Diff for: .gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
tsp-hpc
22
.vscode
3-
build
3+
build*

Diff for: CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ project(
66

77
find_package(SQLite3 REQUIRED)
88

9-
set(CMAKE_CXX_STANDARD 20)
9+
set(CMAKE_CXX_STANDARD 23)
1010
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
1111

1212
set(sources
13+
locker.cpp
1314
functions.cpp
14-
semaphore.cpp
1515
jitter.cpp
1616
run_cmd.cpp
1717
status_manager.cpp

Diff for: functions.cpp

+87-96
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,99 @@
1+
#include "functions.hpp"
12

2-
#include <string>
3-
#include <vector>
43
#include <cstdint>
4+
#include <cstdlib>
55
#include <cstring>
6-
#include <sys/types.h>
7-
#include <unistd.h>
8-
#include <sstream>
9-
#include <numeric>
10-
#include <fstream>
116
#include <filesystem>
7+
#include <fstream>
8+
#include <numeric>
9+
#include <sstream>
10+
#include <string>
11+
#include <vector>
1212

13-
#include "functions.hpp"
14-
15-
#define CGROUP_CPUSET_PATH_PREFIX "/sys/fs/cgroup/cpuset"
16-
#define CPUSET_FILE "/cpuset.cpus"
13+
const std::filesystem::path get_tmp() {
14+
auto tmp = std::getenv("TMPDIR");
15+
if (tmp != nullptr) {
16+
return std::filesystem::path{tmp};
17+
}
18+
tmp = std::getenv("PBS_JOBFS");
19+
if (tmp != nullptr) {
20+
return std::filesystem::path{tmp};
21+
} else {
22+
return std::filesystem::path{"/tmp"};
23+
}
24+
};
1725

18-
const char *get_tmp()
19-
{
20-
const char *out = getenv("TMPDIR");
21-
if (out == nullptr)
22-
{
23-
out = "/tmp";
24-
}
25-
return out;
26+
void die_with_err(std::string msg, int status) {
27+
throw std::runtime_error(msg + "stat=" + std::to_string(status));
2628
};
27-
void die_with_err(std::string msg, int status)
28-
{
29-
std::string out(msg);
30-
out.append("\nstat=" + std::to_string(status) + ", errno=" + std::to_string(errno));
31-
out.append(std::string("\n") + strerror(errno));
32-
throw std::runtime_error(out);
29+
30+
void die_with_err_errno(std::string msg, int status) {
31+
std::string out(msg);
32+
out.append("\nstat=" + std::to_string(status) +
33+
", errno=" + std::to_string(errno));
34+
out.append(std::string("\n") + strerror(errno));
35+
throw std::runtime_error(out);
3336
};
34-
std::vector<uint32_t> parse_cpuset_range(std::string in)
35-
{
36-
std::stringstream ss1(in);
37-
std::string token;
38-
std::vector<std::uint32_t> out;
39-
while (std::getline(ss1, token, ','))
40-
{
41-
if (token.find('-') == std::string::npos)
42-
{
43-
out.push_back(std::stoul(token));
44-
}
45-
else
46-
{
47-
std::stringstream ss2(token);
48-
std::string starts, ends;
49-
std::getline(ss2, starts, '-');
50-
std::getline(ss2, ends, '-');
51-
std::vector<std::uint32_t> tmp(std::stoul(ends) - std::stoul(starts) + 1);
52-
std::iota(tmp.begin(), tmp.end(), std::stoul(starts));
53-
out.insert(out.end(), tmp.begin(), tmp.end());
54-
}
37+
38+
std::vector<uint32_t> parse_cpuset_range(std::string in) {
39+
std::stringstream ss1(in);
40+
std::string token;
41+
std::vector<std::uint32_t> out;
42+
while (std::getline(ss1, token, ',')) {
43+
if (token.find('-') == std::string::npos) {
44+
out.push_back(std::stoul(token));
45+
} else {
46+
std::stringstream ss2(token);
47+
std::string starts, ends;
48+
std::getline(ss2, starts, '-');
49+
std::getline(ss2, ends, '-');
50+
std::vector<std::uint32_t> tmp(std::stoul(ends) - std::stoul(starts) + 1);
51+
std::iota(tmp.begin(), tmp.end(), std::stoul(starts));
52+
out.insert(out.end(), tmp.begin(), tmp.end());
5553
}
56-
return out;
54+
}
55+
return out;
5756
};
58-
std::vector<std::uint32_t> get_cgroup()
59-
{
60-
std::filesystem::path cgroup_fn(std::string("/proc/" + std::to_string(getpid()) + "/cgroup"));
61-
if (!std::filesystem::exists(cgroup_fn))
62-
{
63-
throw std::runtime_error("Cgroup file for process " + std::to_string(getpid()) + " not found");
64-
}
65-
std::string line;
66-
std::filesystem::path cpuset_path;
67-
// get cpuset path
68-
std::ifstream cgroup_file(cgroup_fn);
69-
if (cgroup_file.is_open())
70-
{
71-
while (std::getline(cgroup_file, line))
72-
{
73-
std::vector<std::string> seglist;
74-
std::string segment;
75-
std::stringstream ss(line);
76-
while (std::getline(ss, segment, ':'))
77-
{
78-
seglist.push_back(segment);
79-
};
80-
if (seglist[1] == "cpuset")
81-
{
82-
cpuset_path = CGROUP_CPUSET_PATH_PREFIX;
83-
cpuset_path += seglist[2];
84-
cpuset_path += CPUSET_FILE;
85-
}
86-
if (!cpuset_path.empty())
87-
{
88-
break;
89-
}
90-
}
91-
cgroup_file.close();
92-
}
93-
else
94-
{
95-
throw std::runtime_error("Unable to open cgroup file " + cgroup_fn.string());
96-
}
97-
// read cpuset file
98-
std::ifstream cpuset_file(cpuset_path);
99-
if (cpuset_file.is_open())
100-
{
101-
std::getline(cpuset_file, line);
102-
return parse_cpuset_range(line);
103-
}
104-
else
105-
{
106-
throw std::runtime_error("Unable to open cpuset file " + cpuset_path.string());
57+
58+
std::vector<uint32_t> get_cgroup() {
59+
static std::string cgroup_fn("/proc/self/cgroup");
60+
static std::string cgroup_cpuset_path_prefix("/sys/fs/cgroup/cpuset");
61+
static std::string cpuset_filename("/cpuset.cpus");
62+
if (!std::filesystem::exists(cgroup_fn)) {
63+
throw std::runtime_error("Cgroup file for current process not found");
64+
}
65+
std::string line;
66+
std::filesystem::path cpuset_path;
67+
// get cpuset path
68+
std::ifstream cgroup_file(cgroup_fn);
69+
if (cgroup_file.is_open()) {
70+
while (std::getline(cgroup_file, line)) {
71+
std::vector<std::string> seglist;
72+
std::string segment;
73+
std::stringstream ss(line);
74+
while (std::getline(ss, segment, ':')) {
75+
seglist.push_back(segment);
76+
};
77+
if (seglist[1] == "cpuset") {
78+
cpuset_path = cgroup_cpuset_path_prefix;
79+
cpuset_path += seglist[2];
80+
cpuset_path += cpuset_filename;
81+
}
82+
if (!cpuset_path.empty()) {
83+
break;
84+
}
10785
}
86+
cgroup_file.close();
87+
} else {
88+
throw std::runtime_error("Unable to open cgroup file " + cgroup_fn);
89+
}
90+
// read cpuset file
91+
std::ifstream cpuset_file(cpuset_path);
92+
if (cpuset_file.is_open()) {
93+
std::getline(cpuset_file, line);
94+
return parse_cpuset_range(line);
95+
} else {
96+
throw std::runtime_error("Unable to open cpuset file " +
97+
cpuset_path.string());
98+
}
10899
};

Diff for: functions.hpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#pragma once
22

3-
#include <string>
4-
#include <vector>
53
#include <cstdint>
4+
#include <filesystem>
65
#include <numeric>
6+
#include <string>
7+
#include <vector>
78

8-
const char *get_tmp();
9+
const std::filesystem::path get_tmp();
910
void die_with_err(std::string msg, int status);
11+
void die_with_err_errno(std::string msg, int status);
1012
std::vector<uint32_t> parse_cpuset_range(std::string in);
11-
std::vector<std::uint32_t> get_cgroup();
13+
std::vector<uint32_t> get_cgroup();

Diff for: jitter.cpp

+12-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
#include "jitter.hpp"
22

3-
namespace tsp
4-
{
5-
Jitter::Jitter(int limit) : rng(), dist()
6-
{
7-
std::random_device dev;
8-
rng = std::mt19937(dev());
9-
dist = std::uniform_int_distribution<int>(-abs(limit), abs(limit));
10-
}
11-
int Jitter::get()
12-
{
13-
return dist(rng);
14-
}
15-
}
3+
#include <chrono>
4+
#include <random>
5+
6+
namespace tsp {
7+
Jitter::Jitter(std::chrono::milliseconds limit)
8+
: rng(std::mt19937(std::random_device{}())),
9+
dist(std::uniform_int_distribution<int64_t>(-abs(limit).count(),
10+
abs(limit).count())) {}
11+
std::chrono::milliseconds Jitter::get() {
12+
return std::chrono::milliseconds(dist(rng));
13+
}
14+
} // namespace tsp

Diff for: jitter.hpp

+13-15
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
#pragma once
2+
#include <chrono>
3+
#include <cstdint>
24
#include <random>
35

4-
#define JITTER_MS 250
6+
namespace tsp {
7+
constexpr std::chrono::milliseconds jitter_ms{250};
8+
class Jitter {
9+
public:
10+
Jitter(std::chrono::milliseconds limit);
11+
std::chrono::milliseconds get();
512

6-
namespace tsp
7-
{
8-
class Jitter
9-
{
10-
public:
11-
Jitter(int limit);
12-
int get();
13-
~Jitter() {};
14-
15-
private:
16-
std::mt19937 rng;
17-
std::uniform_int_distribution<int> dist;
18-
};
19-
}
13+
private:
14+
std::mt19937 rng;
15+
std::uniform_int_distribution<int64_t> dist;
16+
};
17+
} // namespace tsp

Diff for: locker.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include "locker.hpp"
2+
3+
#include <array>
4+
#include <ranges>
5+
#include <signal.h>
6+
#include <string>
7+
#include <sys/file.h>
8+
#include <sys/stat.h>
9+
#include <sys/types.h>
10+
#include <unistd.h>
11+
12+
#include "functions.hpp"
13+
14+
namespace tsp {
15+
int lockfile_fd = -1;
16+
void handle_signal(int sig) {
17+
if (lockfile_fd != -1) {
18+
flock(lockfile_fd, LOCK_UN);
19+
close(lockfile_fd);
20+
}
21+
}
22+
23+
Locker::Locker() {
24+
lockfile_fd = open(lock_file_path.c_str(), O_WRONLY | O_CREAT, 0600);
25+
if (lockfile_fd == -1) {
26+
die_with_err_errno("Unable to open lockfile", lockfile_fd);
27+
}
28+
}
29+
30+
void Locker::lock() {
31+
auto flock_out = flock(lockfile_fd, LOCK_EX);
32+
if (flock_out == -1) {
33+
die_with_err_errno("Unable to lock lockfile", flock_out);
34+
}
35+
// Set up signal handler
36+
for (auto [i, sig] : std::views::enumerate(prev_sigs)) {
37+
sig = signal(i, handle_signal);
38+
}
39+
}
40+
41+
void Locker::unlock() {
42+
auto flock_out = flock(lockfile_fd, LOCK_UN);
43+
if (flock_out == -1) {
44+
die_with_err_errno("Unable to unlock lockfile", flock_out);
45+
}
46+
for (auto [i, sig] : std::views::enumerate(prev_sigs)) {
47+
if (sig == SIG_ERR) {
48+
continue;
49+
}
50+
signal(i, sig);
51+
}
52+
}
53+
54+
Locker::~Locker() {
55+
unlock();
56+
if (lockfile_fd != -1) {
57+
close(lockfile_fd);
58+
}
59+
}
60+
61+
} // namespace tsp

Diff for: locker.hpp

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <array>
5+
#include <unistd.h>
6+
#include <signal.h>
7+
8+
#include "functions.hpp"
9+
10+
namespace tsp
11+
{
12+
class Locker
13+
{
14+
public:
15+
Locker();
16+
~Locker();
17+
void lock();
18+
void unlock();
19+
20+
private:
21+
const std::string lock_file_path{get_tmp() / ".affinity_lock_file.lock"};
22+
std::array<sighandler_t, NSIG> prev_sigs;
23+
};
24+
}

0 commit comments

Comments
 (0)