Skip to content

Commit eeee46c

Browse files
committed
Replace fstream with cstdio
1 parent 2d42afd commit eeee46c

File tree

1 file changed

+167
-101
lines changed

1 file changed

+167
-101
lines changed

ev3dev.cpp

+167-101
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
#include <iostream>
2929
#include <sstream>
30-
#include <fstream>
3130
#include <list>
3231
#include <map>
3332
#include <array>
@@ -38,7 +37,8 @@
3837
#include <thread>
3938
#include <stdexcept>
4039
#include <string.h>
41-
#include <math.h>
40+
#include <cmath>
41+
#include <cstdio>
4242

4343
#include <dirent.h>
4444
#include <sys/mman.h>
@@ -66,6 +66,154 @@ static const int bits_per_long = sizeof(long) * 8;
6666
namespace ev3dev {
6767
namespace {
6868

69+
//-----------------------------------------------------------------------------
70+
class file_reader {
71+
public:
72+
file_reader() : f(0) {}
73+
74+
file_reader(file_reader &&other)
75+
: fname(std::move(other.fname)), f(other.f)
76+
{
77+
other.f = 0;
78+
}
79+
80+
~file_reader() {
81+
if (f) fclose(f);
82+
}
83+
84+
bool is_open() const {
85+
return f != 0;
86+
}
87+
88+
void open(const std::string &_fname) {
89+
fname = _fname;
90+
f = fopen(fname.c_str(), "r");
91+
92+
if (!f) {
93+
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)),
94+
std::string("Failed to open \"") + fname + "\"");
95+
}
96+
}
97+
98+
std::string get_string() {
99+
char buf[256];
100+
try_read([this, &buf](){ return 1 == fscanf(f, "%255s", buf); });
101+
return buf;
102+
}
103+
104+
std::string get_line() {
105+
char buf[256];
106+
try_read([this, &buf](){
107+
if (!fgets(buf, 255, f)) return false;
108+
char *pos;
109+
if ((pos=strchr(buf, '\n')) != NULL) *pos = '\0';
110+
return true;
111+
});
112+
return buf;
113+
}
114+
115+
int get_int() {
116+
int v;
117+
try_read([this, &v](){return 1 == fscanf(f, "%d", &v); });
118+
return v;
119+
}
120+
121+
void get_data(char *data, size_t count) {
122+
try_read([this, &data, count](){ return count == fread(data, count, count, f); });
123+
}
124+
private:
125+
std::string fname;
126+
FILE *f;
127+
128+
void reopen() {
129+
if (f) fclose(f);
130+
f = fopen(fname.c_str(), "r");
131+
}
132+
133+
template <class Callable>
134+
void try_read(Callable w) {
135+
for(int attempt = 0; attempt < 2; ++attempt) {
136+
fseek(f, 0, SEEK_SET);
137+
138+
if (w()) return;
139+
140+
// Failed to read the value.
141+
// This could mean the sysfs attribute was recreated and the
142+
// corresponding file handle got stale. Lets close the file and try
143+
// again (once):
144+
if (attempt != 0) {
145+
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)), fname);
146+
}
147+
148+
reopen();
149+
}
150+
}
151+
};
152+
153+
//-----------------------------------------------------------------------------
154+
class file_writer {
155+
public:
156+
file_writer() : f(0) {}
157+
158+
file_writer(file_writer &&other)
159+
: fname(std::move(other.fname)), f(other.f)
160+
{
161+
other.f = 0;
162+
}
163+
164+
~file_writer() {
165+
if (f) fclose(f);
166+
}
167+
168+
bool is_open() const {
169+
return f != 0;
170+
}
171+
172+
void open(const std::string &_fname) {
173+
fname = _fname;
174+
f = fopen(fname.c_str(), "w");
175+
176+
if (!f) {
177+
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)),
178+
std::string("Failed to open \"") + fname + "\"");
179+
}
180+
}
181+
182+
void put_string(const std::string &v) {
183+
try_write([this, &v](){ return EOF != fputs(v.c_str(), f); });
184+
}
185+
186+
void put_int(int v) {
187+
try_write([this, v](){ return fprintf(f, "%d", v) >= 0; });
188+
}
189+
190+
private:
191+
std::string fname;
192+
FILE *f;
193+
194+
void reopen() {
195+
if (f) fclose(f);
196+
f = fopen(fname.c_str(), "w");
197+
}
198+
199+
template <class Callable>
200+
void try_write(Callable w) {
201+
for(int attempt = 0; attempt < 2; ++attempt) {
202+
if (w()) return;
203+
204+
// Failed to write the value.
205+
// This could mean the sysfs attribute was recreated and the
206+
// corresponding file handle got stale. Lets close the file and try
207+
// again (once):
208+
if (attempt != 0) {
209+
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)), fname);
210+
}
211+
212+
reopen();
213+
}
214+
}
215+
};
216+
69217
// This class implements a small LRU cache. It assumes the number of elements
70218
// is small, and so uses a simple linear search.
71219
template <typename K, typename V>
@@ -118,46 +266,24 @@ class lru_cache {
118266
};
119267

120268
// A global cache of files.
121-
std::ifstream& ifstream_cache(const std::string &path) {
122-
static lru_cache<std::string, std::ifstream> cache(FSTREAM_CACHE_SIZE);
269+
file_reader& reader_cache(const std::string &path) {
270+
static lru_cache<std::string, file_reader> cache(FSTREAM_CACHE_SIZE);
123271
static std::mutex mx;
124272

125273
std::lock_guard<std::mutex> lock(mx);
126-
return cache[path];
274+
file_reader &f = cache[path];
275+
if (!f.is_open()) f.open(path);
276+
return f;
127277
}
128278

129-
std::ofstream& ofstream_cache(const std::string &path) {
130-
static lru_cache<std::string, std::ofstream> cache(FSTREAM_CACHE_SIZE);
279+
file_writer& writer_cache(const std::string &path) {
280+
static lru_cache<std::string, file_writer> cache(FSTREAM_CACHE_SIZE);
131281
static std::mutex mx;
132282

133283
std::lock_guard<std::mutex> lock(mx);
134-
return cache[path];
135-
}
136-
137-
//-----------------------------------------------------------------------------
138-
std::ofstream &ofstream_open(const std::string &path) {
139-
std::ofstream &file = ofstream_cache(path);
140-
if (!file.is_open()) {
141-
// Don't buffer writes to avoid latency. Also saves a bit of memory.
142-
file.rdbuf()->pubsetbuf(NULL, 0);
143-
file.open(path);
144-
} else {
145-
// Clear the error bits in case something happened.
146-
file.clear();
147-
}
148-
return file;
149-
}
150-
151-
std::ifstream &ifstream_open(const std::string &path) {
152-
std::ifstream &file = ifstream_cache(path);
153-
if (!file.is_open()) {
154-
file.open(path);
155-
} else {
156-
// Clear the flags bits in case something happened (like reaching EOF).
157-
file.clear();
158-
file.seekg(0, std::ios::beg);
159-
}
160-
return file;
284+
file_writer &f = cache[path];
285+
if (!f.is_open()) f.open(path);
286+
return f;
161287
}
162288

163289
} // namespace
@@ -243,25 +369,7 @@ int device::get_attr_int(const std::string &name) const {
243369
if (_path.empty())
244370
throw system_error(make_error_code(errc::function_not_supported), "no device connected");
245371

246-
for(int attempt = 0; attempt < 2; ++attempt) {
247-
ifstream &is = ifstream_open(_path + name);
248-
if (is.is_open()) {
249-
int result = 0;
250-
try {
251-
is >> result;
252-
return result;
253-
} catch(...) {
254-
// This could mean the sysfs attribute was recreated and the
255-
// corresponding file handle got stale. Lets close the file and try
256-
// again (once):
257-
if (attempt != 0) throw;
258-
259-
is.close();
260-
is.clear();
261-
}
262-
} else break;
263-
}
264-
throw system_error(make_error_code(errc::no_such_device), _path+name);
372+
return reader_cache(_path + name).get_int();
265373
}
266374

267375
//-----------------------------------------------------------------------------
@@ -271,23 +379,7 @@ void device::set_attr_int(const std::string &name, int value) {
271379
if (_path.empty())
272380
throw system_error(make_error_code(errc::function_not_supported), "no device connected");
273381

274-
for(int attempt = 0; attempt < 2; ++attempt) {
275-
ofstream &os = ofstream_open(_path + name);
276-
if (os.is_open()) {
277-
if (os << value) return;
278-
279-
// An error could mean that sysfs attribute was recreated and the cached
280-
// file handle is stale. Lets close the file and try again (once):
281-
if (attempt == 0 && errno == ENODEV) {
282-
os.close();
283-
os.clear();
284-
} else {
285-
throw system_error(std::error_code(errno, std::system_category()));
286-
}
287-
} else {
288-
throw system_error(make_error_code(errc::no_such_device), _path + name);
289-
}
290-
}
382+
writer_cache(_path + name).put_int(value);
291383
}
292384

293385
//-----------------------------------------------------------------------------
@@ -297,14 +389,7 @@ std::string device::get_attr_string(const std::string &name) const {
297389
if (_path.empty())
298390
throw system_error(make_error_code(errc::function_not_supported), "no device connected");
299391

300-
ifstream &is = ifstream_open(_path + name);
301-
if (is.is_open()) {
302-
string result;
303-
is >> result;
304-
return result;
305-
}
306-
307-
throw system_error(make_error_code(errc::no_such_device), _path+name);
392+
return reader_cache(_path + name).get_string();
308393
}
309394

310395
//-----------------------------------------------------------------------------
@@ -314,13 +399,7 @@ void device::set_attr_string(const std::string &name, const std::string &value)
314399
if (_path.empty())
315400
throw system_error(make_error_code(errc::function_not_supported), "no device connected");
316401

317-
ofstream &os = ofstream_open(_path + name);
318-
if (os.is_open()) {
319-
if (!(os << value)) throw system_error(std::error_code(errno, std::system_category()));
320-
return;
321-
}
322-
323-
throw system_error(make_error_code(errc::no_such_device), _path+name);
402+
writer_cache(_path + name).put_string(value);
324403
}
325404

326405
//-----------------------------------------------------------------------------
@@ -330,14 +409,7 @@ std::string device::get_attr_line(const std::string &name) const {
330409
if (_path.empty())
331410
throw system_error(make_error_code(errc::function_not_supported), "no device connected");
332411

333-
ifstream &is = ifstream_open(_path + name);
334-
if (is.is_open()) {
335-
string result;
336-
getline(is, result);
337-
return result;
338-
}
339-
340-
throw system_error(make_error_code(errc::no_such_device), _path+name);
412+
return reader_cache(_path + name).get_line();
341413
}
342414

343415
//-----------------------------------------------------------------------------
@@ -513,14 +585,8 @@ const std::vector<char>& sensor::bin_data() const {
513585
_bin_data.resize(num_values() * value_size);
514586
}
515587

516-
const string fname = _path + "bin_data";
517-
ifstream &is = ifstream_open(fname);
518-
if (is.is_open()) {
519-
is.read(_bin_data.data(), _bin_data.size());
520-
return _bin_data;
521-
}
522-
523-
throw system_error(make_error_code(errc::no_such_device), fname);
588+
reader_cache(_path + "bin_data").get_data(_bin_data.data(), _bin_data.size());
589+
return _bin_data;
524590
}
525591

526592
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)