Move to asynchronous handling of child exec status.
[oweals/dinit.git] / cpbuffer.h
1 #ifndef CPBUFFER_H
2 #define CPBUFFER_H
3
4 #include <cstring>
5
6 // control protocol buffer, a circular buffer with 1024-byte capacity.
7 class CPBuffer
8 {
9     char buf[1024];
10     int cur_idx = 0;
11     int length = 0;  // number of elements in the buffer
12     
13     public:
14     int get_length() noexcept
15     {
16         return length;
17     }
18     
19     // fill by reading from the given fd, return positive if some was read or -1 on error.
20     int fill(int fd) noexcept
21     {
22         int pos = cur_idx + length;
23         if (pos >= 1024) pos -= 1024;
24         int max_count = std::min(1024 - pos, 1024 - length);
25         ssize_t r = read(fd, buf + cur_idx, max_count);
26         if (r >= 0) {
27             length += r;
28         }
29         return r;
30     }
31     
32     // fill by readin from the given fd, until at least the specified number of bytes are in
33     // the buffer. Return 0 if end-of-file reached before fill complete, or -1 on error.
34     int fillTo(int fd, int rlength) noexcept
35     {
36         while (length < rlength) {
37             int r = fill(fd);
38             if (r <= 0) return r;
39         }
40         return 1;
41     }
42     
43     int operator[](int idx) noexcept
44     {
45         int dest_idx = cur_idx + idx;
46         if (dest_idx > 1024) dest_idx -= 1024;
47         return buf[dest_idx];
48     }
49     
50     void consume(int amount) noexcept
51     {
52         cur_idx += amount;
53         if (cur_idx >= 1024) cur_idx -= 1024;
54         length -= amount;
55     }
56     
57     void extract(char *dest, int index, int length) noexcept
58     {
59         index += cur_idx;
60         if (index >= 1024) index -= 1024;
61         if (index + length > 1024) {
62             // wrap-around copy
63             int half = 1024 - index;
64             std::memcpy(dest, buf + index, half);
65             std::memcpy(dest + half, buf, length - half);
66         }
67         else {
68             std::memcpy(dest, buf + index, length);
69         }
70     }
71     
72     // Extract string of give length from given index
73     // Throws:  std::bad_alloc on allocation failure
74     std::string extract_string(int index, int length)
75     {
76         index += cur_idx;
77         if (index >= 1024) index -= 1024;
78         if (index + length > 1024) {
79             std::string r(buf + index, 1024 - index);
80             r.insert(r.end(), buf, buf + length - (1024 - index));
81             return r;
82         }
83         else {
84             return std::string(buf + index, length);
85         }
86     }
87 };
88
89 #endif