1 mike 1.1 //BEGIN_LICENSE
2 //
3 // Copyright (c) 2000 The Open Group, BMC Software, Tivoli Systems, IBM
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
15 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 // DEALINGS IN THE SOFTWARE.
19 //
20 //END_LICENSE
21 //BEGIN_HISTORY
22 mike 1.1 //
23 // Author: Michael E. Brasher
24 //
25 // $Log: Selector.cpp,v $
26 // Revision 1.3 2001/04/11 04:20:39 mike
27 // new
28 //
29 // Revision 1.4 2001/04/08 22:06:31 mike
30 // New acceptor
31 //
32 // Revision 1.3 2001/04/08 08:28:20 mike
33 // Added more windows channel implementation code.
34 //
35 // Revision 1.2 2001/04/08 05:06:06 mike
36 // New Files for Channel Implementation
37 //
38 // Revision 1.1 2001/04/08 04:46:11 mike
39 // Added new selector class for windows
40 //
41 //
42 //END_HISTORY
43 mike 1.1
44 #include "Selector.h"
45
46 PEGASUS_NAMESPACE_BEGIN
47
48 #define FD_SETSIZE 4096
49
50 #include <winsock.h>
51
52 using namespace std;
53
54 // This wrapper routine is needed to allow the select() WINSOCK routine to be
55 // called from the Selector::select() method. Using the global namespace
56 // qualifier failed since WINSOCK select() is not in the global namespace.
57
58 static inline int select_wrapper(
59 int nfds,
60 fd_set* rd_fd_set,
61 fd_set* wr_fd_set,
62 fd_set* ex_fd_set,
63 const struct timeval* tv)
64 mike 1.1 {
65 return select(FD_SETSIZE, rd_fd_set, wr_fd_set, ex_fd_set, tv);
66 }
67
68 ////////////////////////////////////////////////////////////////////////////////
69 //
70 // Routines for starting and stoping WinSock:
71 //
72 ////////////////////////////////////////////////////////////////////////////////
73
74 static Uint32 _wsaCount = 0;
75
76 static void _WSAInc()
77 {
78 if (_wsaCount == 0)
79 {
80 WSADATA tmp;
81
82 if (WSAStartup(0x202, &tmp) == SOCKET_ERROR)
83 WSACleanup();
84 }
85 mike 1.1
86 _wsaCount++;
87 }
88
89 static void _WSADec()
90 {
91 _wsaCount--;
92
93 if (_wsaCount == 0)
94 WSACleanup();
95 }
96
97 ////////////////////////////////////////////////////////////////////////////////
98 //
99 // SelectorRep
100 //
101 ////////////////////////////////////////////////////////////////////////////////
102
103 struct SelectorRep
104 {
105 fd_set rd_fd_set;
106 mike 1.1 fd_set wr_fd_set;
107 fd_set ex_fd_set;
108 fd_set active_rd_fd_set;
109 fd_set active_wr_fd_set;
110 fd_set active_ex_fd_set;
111 };
112
113 ////////////////////////////////////////////////////////////////////////////////
114 //
115 // Selector
116 //
117 ////////////////////////////////////////////////////////////////////////////////
118
119
120 Selector::Selector()
121 {
122 _rep = new SelectorRep;
123 FD_ZERO(&_rep->rd_fd_set);
124 FD_ZERO(&_rep->wr_fd_set);
125 FD_ZERO(&_rep->ex_fd_set);
126 FD_ZERO(&_rep->active_rd_fd_set);
127 mike 1.1 FD_ZERO(&_rep->active_wr_fd_set);
128 FD_ZERO(&_rep->active_ex_fd_set);
129 }
130
131 Selector::~Selector()
132 {
133 for (Uint32 i = 0, n = _entries.getSize(); i < n; i++)
134 delete _entries[i].handler;
135
136 delete _rep;
137 }
138
139 Boolean Selector::select(Uint32 milliseconds)
140 {
141 // Windows select() has a strange little bug. It returns immediately if
142 // there are no descriptors in the set even if the timeout is non-zero.
143 // To work around this, we call Sleep() for now:
144
145 if (_entries.getSize() == 0)
146 Sleep(milliseconds);
147
148 mike 1.1 // Check for events on the selected file descriptors. Only do this if
149 // there were no undispatched events from last time.
150
151 static int count = 0;
152
153 if (count == 0)
154 {
155 memcpy(&_rep->active_rd_fd_set, &_rep->rd_fd_set, sizeof(fd_set));
156 memcpy(&_rep->active_wr_fd_set, &_rep->wr_fd_set, sizeof(fd_set));
157 memcpy(&_rep->active_ex_fd_set, &_rep->ex_fd_set, sizeof(fd_set));
158
159 const Uint32 SEC = milliseconds / 1000;
160 const Uint32 USEC = (milliseconds % 1000) * 1000;
161 struct timeval tv = { SEC, USEC };
162
163 count = select_wrapper(
164 FD_SETSIZE,
165 &_rep->active_rd_fd_set,
166 &_rep->active_wr_fd_set,
167 &_rep->active_ex_fd_set,
168 &tv);
169 mike 1.1
170 if (count == 0)
171 return false;
172 else if (count == SOCKET_ERROR)
173 {
174 count = 0;
175 return false;
176 }
177 }
178
179 // Dispatch any handler events:
180
181 for (Uint32 i = 0, n = _entries.getSize(); i < n; i++)
182 {
183 Sint32 desc = _entries[i].desc;
184 Uint32 reasons = 0;
185
186 if (FD_ISSET(desc, &_rep->active_rd_fd_set))
187 reasons |= READ;
188
189 if (FD_ISSET(desc, &_rep->active_wr_fd_set))
190 mike 1.1 reasons |= WRITE;
191
192 if (FD_ISSET(desc, &_rep->active_ex_fd_set))
193 reasons |= EXCEPTION;
194
195 if (reasons)
196 {
197 SelectorHandler* handler = _entries[i].handler;
198
199 if (!handler->handle(desc, reasons))
200 removeHandler(handler);
201
202 if (reasons & WRITE)
203 {
204 FD_CLR(desc, &_rep->active_wr_fd_set);
205 }
206
207 if (reasons & EXCEPTION)
208 {
209 FD_CLR(desc, &_rep->active_ex_fd_set);
210 }
211 mike 1.1
212 if (reasons & READ)
213 {
214 FD_CLR(desc, &_rep->active_rd_fd_set);
215 }
216
217 count--;
218 return true;
219 }
220 }
221
222 return false;
223 }
224
225 Boolean Selector::addHandler(
226 Sint32 desc,
227 Uint32 reasons,
228 SelectorHandler* handler)
229 {
230 // See whether a handler is already registered for this one:
231
232 mike 1.1 Uint32 pos = _findEntry(desc);
233
234 if (pos != Uint32(-1))
235 return false;
236
237 // Set the reasons:
238
239 if (reasons & READ)
240 FD_SET(desc, &_rep->rd_fd_set);
241
242 if (reasons & WRITE)
243 FD_SET(desc, &_rep->wr_fd_set);
244
245 if (reasons & EXCEPTION)
246 FD_SET(desc, &_rep->ex_fd_set);
247
248 // Add the entry to the list:
249
250 Entry entry = { desc, handler };
251 _entries.append(entry);
252
253 mike 1.1 // Success!
254
255 return true;
256 }
257
258 Boolean Selector::removeHandler(SelectorHandler* handler)
259 {
260 // Look for the given handler and remove it!
261
262 for (Uint32 i = 0, n = _entries.getSize(); i < n; i++)
263 {
264 if (_entries[i].handler == handler)
265 {
266 Sint32 desc = _entries[i].desc;
267 FD_CLR(desc, &_rep->rd_fd_set);
268 FD_CLR(desc, &_rep->wr_fd_set);
269 FD_CLR(desc, &_rep->ex_fd_set);
270 _entries.remove(i);
271 delete handler;
272 return true;
273 }
274 mike 1.1 }
275
276 // Not found:
277
278 return false;
279 }
280
281 Uint32 Selector::_findEntry(Sint32 desc) const
282 {
283 for (Uint32 i = 0, n = _entries.getSize(); i < n; i++)
284 {
285 if (_entries[i].desc == desc)
286 return i;
287 }
288
289 return Uint32(-1);
290 }
291
292 SelectorHandler::~SelectorHandler()
293 {
294
295 mike 1.1 }
296
297 PEGASUS_NAMESPACE_END
|