Instrument Neutral Distributed Interface INDI  2.0.2
select.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2022 by Pawel Soja <kernel32.pl@gmail.com>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 // internal use only
19 #pragma once
20 
21 #include <stdio.h>
22 #include <algorithm>
23 
24 #ifdef _WIN32
25 #ifndef NOMINMAX
26 #define NOMINMAX
27 #endif
28 #include <ws2tcpip.h>
29 #include <winsock2.h>
30 #include <windows.h>
31 typedef SOCKET SocketFileDescriptor;
32 static const SocketFileDescriptor SocketInvalid = INVALID_SOCKET;
33 #else
34 #define HAS_EVENT_FD
35 #include <unistd.h>
36 #include <netdb.h>
37 #include <sys/socket.h> // select
39 static const SocketFileDescriptor SocketInvalid = -1;
40 #endif
41 
42 #include "indimacros.h"
43 
44 #ifdef HAS_EVENT_FD
45 class EventFd
46 {
47  public:
49  {
50  if (socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd) < 0)
51  {
52  perror("socketpair");
53  }
54  }
55 
57  {
58  close(pipefd[0]);
59  close(pipefd[1]);
60  }
61 
62  public:
63  void wakeUp()
64  {
65  size_t c = 1;
66  // wakeup 'select' function
67  ssize_t ret = write(pipefd[1], &c, sizeof(c));
68 
69  if (ret != sizeof(c))
70  {
71  perror("the socket cannot be woken up");
72  }
73  total += ret;
74  }
75 
76  int fd() const
77  {
78  return pipefd[0];
79  }
80 
81  void clear()
82  {
83  size_t c = 0;
84  while (total > 0)
85  {
86  total -= read(pipefd[0], &c, sizeof(c));
87  }
88  }
89 
90  private:
91  int pipefd[2] = {-1, -1};
92  int total = 0;
93 };
94 #endif
95 
96 // wrapper for unix select function
97 class Select
98 {
99  public:
101  {
102  clear();
103  }
104 
105  public:
106  void wakeUp()
107  {
108 #ifdef HAS_EVENT_FD
109  eventFd.wakeUp();
110 #endif
111  }
112 
113  void clear()
114  {
115  FD_ZERO(&readEvent);
116  FD_ZERO(&writeEvent);
117  FD_ZERO(&exceptionEvent);
118  fdMax = 0;
119 #ifdef HAS_EVENT_FD
120  eventFd.clear();
121 #endif
122  }
123 
124  public:
125  void setTimeout(int timeout)
126  {
127  ts.tv_sec = timeout / 1000;
128  ts.tv_usec = (timeout % 1000) * 1000;
129  }
130 
131  void select()
132  {
133 #ifdef HAS_EVENT_FD
135 #endif
137 #ifdef HAS_EVENT_FD
138  if (isReadEvent(eventFd.fd()))
139  {
140  eventFd.clear();
141  }
142 #endif
143  }
144 
145  void select(int timeout)
146  {
147  setTimeout(timeout);
148  select();
149  }
150 
151  public:
153  {
154  FD_SET(fd, &readEvent);
155  fdMax = std::max(fdMax, fd);
156  }
157 
159  {
160  FD_SET(fd, &writeEvent);
161  fdMax = std::max(fdMax, fd);
162  }
163 
165  {
166  FD_SET(fd, &exceptionEvent);
167  fdMax = std::max(fdMax, fd);
168  }
169 
171  {
172  FD_SET(fd, &readEvent);
173  FD_SET(fd, &writeEvent);
174  fdMax = std::max(fdMax, fd);
175  }
176 
178  {
179  FD_SET(fd, &readEvent);
180  FD_SET(fd, &writeEvent);
181  FD_SET(fd, &exceptionEvent);
182  fdMax = std::max(fdMax, fd);
183  }
184 
185  public:
186 #ifdef HAS_EVENT_FD
187  bool isWakedUp() const
188  {
189  return FD_ISSET(eventFd.fd(), &readEvent);
190  }
191 #else
192  bool isWakedUp() const
193  {
194  return false;
195  }
196 #endif
197  bool isTimeout() const
198  {
199  return readyDesc == 0;
200  }
201  bool isError() const
202  {
203  return readyDesc < 0;
204  }
206  {
207  return FD_ISSET(fd, &readEvent);
208  }
210  {
211  return FD_ISSET(fd, &writeEvent);
212  }
214  {
215  return FD_ISSET(fd, &exceptionEvent);
216  }
217 
218  protected:
219  fd_set readEvent;
220  fd_set writeEvent;
223  int readyDesc {0};
224 
225  struct timeval ts
226  {
227  1, 0
228  };
229 
230 #ifdef HAS_EVENT_FD
232 #endif
233 };
Definition: select.h:46
~EventFd()
Definition: select.h:56
void wakeUp()
Definition: select.h:63
void clear()
Definition: select.h:81
int fd() const
Definition: select.h:76
EventFd()
Definition: select.h:48
Definition: select.h:98
bool isWakedUp() const
Definition: select.h:187
bool isError() const
Definition: select.h:201
void select(int timeout)
Definition: select.h:145
void setReadEvent(SocketFileDescriptor fd)
Definition: select.h:152
fd_set exceptionEvent
Definition: select.h:221
int readyDesc
Definition: select.h:223
void setReadWriteExceptionEvent(SocketFileDescriptor fd)
Definition: select.h:177
void setWriteEvent(SocketFileDescriptor fd)
Definition: select.h:158
EventFd eventFd
Definition: select.h:231
void select()
Definition: select.h:131
bool isWriteEvent(SocketFileDescriptor fd) const
Definition: select.h:209
void setTimeout(int timeout)
Definition: select.h:125
bool isTimeout() const
Definition: select.h:197
void wakeUp()
Definition: select.h:106
void setReadWriteEvent(SocketFileDescriptor fd)
Definition: select.h:170
bool isExceptionEvent(SocketFileDescriptor fd) const
Definition: select.h:213
void clear()
Definition: select.h:113
void setExceptionEvent(SocketFileDescriptor fd)
Definition: select.h:164
fd_set readEvent
Definition: select.h:219
Select()
Definition: select.h:100
fd_set writeEvent
Definition: select.h:220
SocketFileDescriptor fdMax
Definition: select.h:222
bool isReadEvent(SocketFileDescriptor fd) const
Definition: select.h:205
double max(void)
int fd
Definition: intelliscope.c:43
int SocketFileDescriptor
Definition: select.h:38