IO for Windows
Stefan Schuermans

Stefan Schuermans commited on 2017-10-28 20:23:07
Showing 4 changed files, with 189 additions and 14 deletions.

... ...
@@ -0,0 +1,93 @@
1
+/* Blinker
2
+   Copyright 2011-2014 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#include <winsock2.h>
7
+#include <set>
8
+
9
+#include "Io.h"
10
+#include "Time.h"
11
+
12
+namespace Blinker {
13
+
14
+/**
15
+ * @brief wait for I/O events
16
+ * @param[in] read I/O objects to check for readability
17
+ * @param[out] read I/O objects that are readable
18
+ * @param[in] write I/O objects to check for writability
19
+ * @param[out] write I/O objects that are writable
20
+ * @param[in] timeout maximum time to wait
21
+ */
22
+void Io::wait(Set &read, Set &write, const Time &timeout)
23
+{
24
+  // get read set and write set
25
+  fd_set fd_rd;
26
+  FD_ZERO(&fd_rd);
27
+  for (Set::const_iterator it = read.begin(); it != read.end(); ++it) {
28
+    if ((*it)->m_socket != INVALID_SOCKET) {
29
+      FD_SET((*it)->m_socket, &fd_rd);
30
+    }
31
+  }
32
+  fd_set fd_wr;
33
+  FD_ZERO(&fd_wr);
34
+  for (Set::const_iterator it = write.begin(); it != write.end(); ++it) {
35
+    if ((*it)->m_socket != INVALID_SOCKET) {
36
+      FD_SET((*it)->m_socket, &fd_wr);
37
+    }
38
+  }
39
+
40
+  // get timeout
41
+  struct timeval to;
42
+  if (timeout < Time::zero) // don't use negaitve timeout
43
+    Time::zero.toTimeval(to);
44
+  else
45
+    timeout.toTimeval(to);
46
+
47
+  // wait for I/O event on sockets
48
+  fd_set fd_err;
49
+  FD_ZERO(&fd_err);
50
+  int res = select(0 /* ignore on Windows */, &fd_rd, &fd_wr, &fd_err, &to);
51
+
52
+  // error or timeout
53
+  if (res <= 0) {
54
+    // return with empty sets
55
+    read.clear();
56
+    write.clear();
57
+    return;
58
+  }
59
+
60
+  // remove file descriptors without event pending from sets
61
+  Set::iterator it;
62
+  it = read.begin();
63
+  while (it != read.end()) {
64
+    if ((*it)->m_socket != INVALID_SOCKET &&
65
+        FD_ISSET((*it)->m_socket, &fd_rd)) {
66
+      ++it;
67
+    } else {
68
+      Set::iterator del = it;
69
+      ++it;
70
+      read.erase(del);
71
+    }
72
+  } // while it
73
+  it = write.begin();
74
+  while (it != write.end()) {
75
+    if ((*it)->m_socket != INVALID_SOCKET &&
76
+        FD_ISSET((*it)->m_socket, &fd_wr)) {
77
+      ++it;
78
+    } else {
79
+      Set::iterator del = it;
80
+      ++it;
81
+      write.erase(del);
82
+    }
83
+  } // while it
84
+}
85
+
86
+/// constructor
87
+Io::Io():
88
+  m_socket(INVALID_SOCKET)
89
+{
90
+}
91
+
92
+} // namespace Blinker
93
+
... ...
@@ -0,0 +1,53 @@
1
+/* Blinker
2
+   Copyright 2011-2014 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef BLINKER_IO_H
7
+#define BLINKER_IO_H
8
+
9
+#include <winsock2.h>
10
+
11
+#include <set>
12
+
13
+#include "Time.h"
14
+
15
+namespace Blinker {
16
+
17
+/// base class for I/O objects
18
+class Io
19
+{
20
+public:
21
+  /// set of I/O objects
22
+  typedef std::set<Io *> Set;
23
+
24
+public:
25
+  /**
26
+   * @brief wait for I/O events
27
+   * @param[in] read I/O objects to check for readability
28
+   * @param[out] read I/O objects that are readable
29
+   * @param[in] write I/O objects to check for writability
30
+   * @param[out] write I/O objects that are writable
31
+   * @param[in] timeout maximum time to wait
32
+   */
33
+  static void wait(Set &read, Set &write, const Time &timeout);
34
+
35
+public:
36
+  /// constructor
37
+  Io();
38
+
39
+private:
40
+  /// copy constructor disabled
41
+  Io(const Io &that);
42
+
43
+  /// assignment operator disabled
44
+  const Io & operator=(const Io &that);
45
+
46
+protected:
47
+  SOCKET m_socket; ///< socket descriptor or INVALID_SOCKET
48
+}; // class Io
49
+
50
+} // namespace Blinker
51
+
52
+#endif // #ifndef BLINKER_IO_H
53
+
... ...
@@ -178,22 +178,26 @@ float Time::toFloatSec() const
178 178
   return m_sec + m_ns * 1.0e-9f;
179 179
 }
180 180
 
181
-/// fix internal time representation after calculation
182
-void Time::fix()
181
+/**
182
+ * @brief convert to struct timeval
183
+ * @param[out] tv struct timeval
184
+ */
185
+void Time::toTimeval(struct timeval &tv) const
183 186
 {
184
-  if (m_ns >= 1000000000) {
185
-    m_sec += m_ns / 1000000000;
186
-    m_ns = m_ns % 1000000000;
187
-  } else if (m_ns <= -1000000000) {
188
-    m_sec -= -m_ns / 1000000000;
189
-    m_ns = -(-m_ns % 1000000000);
187
+  if (m_sec >= 0) {
188
+    tv.tv_sec = m_sec;
189
+    tv.tv_usec = (m_ns + 500) / 1000;
190
+    if (tv.tv_usec >= 1000000) {
191
+      ++tv.tv_sec;
192
+      tv.tv_usec -= 1000000;
193
+    }
194
+  } else {
195
+    tv.tv_sec = m_sec;
196
+    tv.tv_usec = -((-m_ns + 500) / 1000);
197
+    if (tv.tv_usec <= -1000000) {
198
+      --tv.tv_sec;
199
+      tv.tv_usec += 1000000;
190 200
     }
191
-  if (m_sec > 0 && m_ns < 0) {
192
-    m_sec -= 1;
193
-    m_ns += 1000000000;
194
-  } else if (m_sec < 0 && m_ns > 0) {
195
-    m_sec += 1;
196
-    m_ns -= 1000000000;
197 201
   }
198 202
 }
199 203
 
... ...
@@ -212,6 +216,25 @@ void Time::fromFileTime(FILETIME const &ft)
212 216
   m_ns = (ft_u.u.QuadPart % 10000000ULL) * 100ULL;
213 217
 }
214 218
 
219
+/// fix internal time representation after calculation
220
+void Time::fix()
221
+{
222
+  if (m_ns >= 1000000000) {
223
+    m_sec += m_ns / 1000000000;
224
+    m_ns = m_ns % 1000000000;
225
+  } else if (m_ns <= -1000000000) {
226
+    m_sec -= -m_ns / 1000000000;
227
+    m_ns = -(-m_ns % 1000000000);
228
+  }
229
+  if (m_sec > 0 && m_ns < 0) {
230
+    m_sec -= 1;
231
+    m_ns += 1000000000;
232
+  } else if (m_sec < 0 && m_ns > 0) {
233
+    m_sec += 1;
234
+    m_ns -= 1000000000;
235
+  }
236
+}
237
+
215 238
 /// sleep for duration
216 239
 void Time::sleepFor() const
217 240
 {
... ...
@@ -78,6 +78,12 @@ public:
78 78
    */
79 79
   float toFloatSec() const;
80 80
 
81
+  /**
82
+   * @brief convert to struct timeval
83
+   * @param[out] tv struct timeval
84
+   */
85
+  void toTimeval(struct timeval &tv) const;
86
+
81 87
   /**
82 88
    * @brief convert from file time strcuture
83 89
    * @param[in] ft file time structure
84 90