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