-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfd.h
103 lines (81 loc) · 2.58 KB
/
fd.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#ifndef SSERVER_FD_H_INCLUDED
#define SSERVER_FD_H_INCLUDED
#include "exception.h"
#include <unistd.h>
#include <fcntl.h>
// C++11 move semantics is better, but not available by default
template<typename Base>
struct Ref {
Ref(int fd) : fd(fd) {}
int fd;
};
class FD;
typedef Ref<FD> FDRef;
class FD {
public:
FD() : fd_(-1) {}
FD(FDRef fd) : fd_(fd.fd) {}
FD(FD& fd) : fd_(fd.release()) {} // should be FD&&
explicit FD(int fd, bool blocking = true) : fd_(fd) {
// typical call is FD(open(...)), so errno is correct usually
CHECK_CALL(fd_, "open fd");
if(blocking) set_flag(O_NONBLOCK);
}
~FD() { if(fd_ != -1) close(fd_); }
FD& operator=(FD& fd) {
FD(fd).swap(*this);
return *this;
}
operator FDRef() { return FDRef(release()); }
int get() const { return fd_; }
void reset() { FD().swap(*this); }
void reset(int fd, bool blocking = true) { FD(fd, blocking).swap(*this); }
void swap(FD& fd) { std::swap(fd_, fd.fd_); }
int release() {
int fd = fd_;
fd_ = -1;
return fd;
}
int write(const char* data, size_t size) { return io(&::write, data, size); }
int read(char* buf, size_t size) { return io(&::read, buf, size); }
template<typename Op, typename Data>
int io(Op operation, Data data, size_t size) {
int result = 0;
for(size_t done = 0; done < size; done += result) {
result = operation(fd_, data + done, size - done);
if(result == 0 || (result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)))
return done;
CHECK_CALL(result, "io(" << fd_ << ")");
}
return size;
}
private:
void set_flag(long flag) {
int flags = 0;
CHECK_CALL((flags = fcntl(fd_, F_GETFL, 0)), "fcntl/GETFL(" << fd_ << ")");
CHECK_CALL(fcntl(fd_, F_SETFL, (flags | flag)), "fcntl/SETFL(" << fd_ << ")");
}
int fd_;
};
inline std::ostream& operator<<(std::ostream& o, const FD& fd) {
return o << fd.get();
}
class Pipe {
public:
Pipe() {
int fds[2];
CHECK_CALL(pipe(fds), "pipe");
reader_.reset(fds[0]);
writer_.reset(fds[1]);
}
int write(const char* data, size_t size) { return writer_.write(data, size); }
int read(char* buf, size_t size) { return reader_.read(buf, size); }
const FD& writer() const { return writer_; }
const FD& reader() const { return reader_; }
FD& writer() { return writer_; }
FD& reader() { return reader_; }
private:
FD reader_;
FD writer_;
};
#endif //SSERVER_FD_H_INCLUDED