source: xplcommon/test/testlocsock.cc@ 28:bac3a3382c4a

Last change on this file since 28:bac3a3382c4a was 28:bac3a3382c4a, checked in by István Váradi <ivaradi@…>, 12 years ago

The local socket test program now uses the pseudo-random number generator

File size: 13.2 KB
Line 
1// Copyright (c) 2012 by István Váradi
2
3// This file is part of libxplcommon, a common utility library for
4// development related to X-Plane
5
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are met:
8
9// 1. Redistributions of source code must retain the above copyright notice, this
10// list of conditions and the following disclaimer.
11// 2. Redistributions in binary form must reproduce the above copyright notice,
12// this list of conditions and the following disclaimer in the documentation
13// and/or other materials provided with the distribution.
14
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26// The views and conclusions contained in the software and documentation are those
27// of the authors and should not be interpreted as representing official policies,
28// either expressed or implied, of the FreeBSD Project.
29
30//------------------------------------------------------------------------------
31
32#include <xplcommon/Thread.h>
33#include <xplcommon/Waiter.h>
34#include <xplcommon/LocalServerSocket.h>
35#include <xplcommon/LocalAcceptor.h>
36#include <xplcommon/LocalSocket.h>
37#include <xplcommon/LocalClientSocket.h>
38#include <xplcommon/LocalConnector.h>
39#include <xplcommon/ReadingBuffer.h>
40#include <xplcommon/WritingBuffer.h>
41#include <xplcommon/WaitableEvent.h>
42#include <xplcommon/PseudoRandom.h>
43
44#include <cstdlib>
45#include <cstdio>
46#include <cassert>
47
48#include <signal.h>
49
50#include <sys/time.h>
51
52//------------------------------------------------------------------------------
53
54using xplcommon::Thread;
55using xplcommon::Waiter;
56using xplcommon::LocalServerSocket;
57using xplcommon::LocalAcceptor;
58using xplcommon::LocalSocket;
59using xplcommon::LocalClientSocket;
60using xplcommon::LocalConnector;
61using xplcommon::ReadingBuffer;
62using xplcommon::WritingBuffer;
63using xplcommon::WaitableEvent;
64using xplcommon::PseudoRandom;
65
66using std::min;
67
68//------------------------------------------------------------------------------
69
70void communicate(ReadingBuffer* readingBuffer, WritingBuffer* writingBuffer,
71 Waiter& waiter, unsigned seed, const char* prefix,
72 WaitableEvent* quitEvent = 0)
73{
74 static const size_t minToWrite = 2076;
75 static const size_t maxToWrite = 1345670;
76
77 static const size_t reportingInterval = 10000;
78
79 static const int sleepThreshold = static_cast<int>(PseudoRandom::MAX * 0.99);
80 static const int sleepRemainder = PseudoRandom::MAX - sleepThreshold;
81 static const unsigned minSleep = 10;
82 static const unsigned maxSleep = 250;
83 static const unsigned sleepRange = maxSleep - minSleep;
84
85 size_t numBytesRead = 0;
86 size_t nextReportRead = reportingInterval;
87 size_t numWriteBlocked = 0;
88 size_t numBytesWritten = 0;
89 size_t nextReportWritten = reportingInterval;
90 size_t numReadBlocked = 0;
91 size_t numMillisSlept = 0;
92
93 bool toQuit = false;
94
95 PseudoRandom random(seed);
96 while(!toQuit) {
97 size_t toWrite = random.nextUnsigned(maxToWrite, minToWrite);
98
99 size_t lastWriteLength = 0;
100 if (writingBuffer!=0) {
101 lastWriteLength = min(writingBuffer->getCapacity(), toWrite);
102 writingBuffer->reset();
103 writingBuffer->addLength(lastWriteLength);
104 }
105
106 while(toWrite>0) {
107 if (quitEvent!=0 && quitEvent->check()) {
108 toQuit = true;
109 break;
110 }
111
112 bool hasPending = false;
113
114 if (writingBuffer!=0) {
115 size_t loopCount = 0;
116 while(toWrite>0) {
117 ++loopCount;
118 if (writingBuffer->write()) {
119 numBytesWritten += lastWriteLength;
120 toWrite -= lastWriteLength;
121
122 if (numBytesWritten>=nextReportWritten) {
123 printf("%s: written %lu bytes with %lu blocking and %lu ms sleeping\n",
124 prefix,
125 static_cast<unsigned long>(numBytesWritten),
126 static_cast<unsigned long>(numWriteBlocked),
127 static_cast<unsigned long>(numMillisSlept));
128 nextReportWritten += reportingInterval;
129 }
130
131 if (toWrite>0) {
132 if (quitEvent!=0 && quitEvent->check()) {
133 toQuit = true;
134 break;
135 } else {
136 lastWriteLength = min(writingBuffer->getCapacity(), toWrite);
137 writingBuffer->addLength(lastWriteLength);
138 if (loopCount>10) {
139 break;
140 }
141 }
142 }
143 } else if (writingBuffer->failed()) {
144 printf("%s: writing failed with error: %lu\n",
145 prefix,
146 static_cast<unsigned long>(writingBuffer->getErrorCode()));
147 toQuit = true;
148 break;
149 } else {
150 ++numWriteBlocked;
151 hasPending = true;
152 break;
153 }
154 }
155 if (toQuit) break;
156 }
157
158 if (readingBuffer!=0) {
159 size_t loopCount = 0;
160 while(true) {
161 ++loopCount;
162 if (readingBuffer->read()) {
163 size_t l = readingBuffer->getLength();
164 if (l==0) {
165 printf("%s: reading encountered end of file\n", prefix);
166 toQuit = true;
167 break;
168 }
169 numBytesRead += l;
170 if (numBytesRead>=nextReportRead) {
171 printf("%s: read %lu bytes with %lu blocking and %lu ms sleeping\n",
172 prefix,
173 static_cast<unsigned long>(numBytesRead),
174 static_cast<unsigned long>(numReadBlocked),
175 static_cast<unsigned long>(numMillisSlept));
176 nextReportRead += reportingInterval;
177 }
178 readingBuffer->reset();
179 if (quitEvent!=0 && quitEvent->check()) {
180 toQuit = true;
181 break;
182 } else if (loopCount>10) {
183 break;
184 }
185 } else if (readingBuffer->failed()) {
186 printf("%s: reading failed with error: %lu\n",
187 prefix,
188 static_cast<unsigned long>(readingBuffer->getErrorCode()));
189 toQuit = true;
190 break;
191 } else {
192 ++numReadBlocked;
193 hasPending = true;
194 break;
195 }
196 }
197 if (toQuit) break;
198 }
199
200 int r = random.next();
201 if (r>=sleepThreshold) {
202 unsigned toSleep = minSleep +
203 static_cast<unsigned>(static_cast<double>(r - sleepThreshold) *
204 sleepRange / sleepRemainder);
205 assert(toSleep>=minSleep);
206 assert(toSleep<maxSleep);
207 Thread::sleep(toSleep);
208 numMillisSlept += toSleep;
209 }
210
211 if (toWrite>0 && hasPending) {
212 waiter.wait();
213 if (waiter.failed()) {
214 printf("%s: waiting failed with error: %lu\n",
215 prefix,
216 static_cast<unsigned long>(waiter.getErrorCode()));
217 toQuit = true;
218 break;
219 }
220 }
221 }
222 }
223
224 printf("%s: written %lu bytes with %lu blocking\n",
225 prefix,
226 static_cast<unsigned long>(numBytesWritten),
227 static_cast<unsigned long>(numWriteBlocked));
228 printf("%s: read %lu bytes with %lu blocking\n",
229 prefix,
230 static_cast<unsigned long>(numBytesRead),
231 static_cast<unsigned long>(numReadBlocked));
232 printf("%s: slept %lu ms\n", prefix,
233 static_cast<unsigned long>(numMillisSlept));
234}
235
236//------------------------------------------------------------------------------
237
238class ServerThread : public Thread
239{
240private:
241 Waiter waiter;
242
243 WaitableEvent event;
244
245public:
246 ServerThread();
247
248 void signal();
249
250 virtual void run();
251};
252
253//------------------------------------------------------------------------------
254
255ServerThread::ServerThread() :
256 event(&waiter)
257{
258}
259
260//------------------------------------------------------------------------------
261
262void ServerThread::signal()
263{
264 event.fire();
265}
266
267//------------------------------------------------------------------------------
268
269void ServerThread::run()
270{
271 unsigned seed = static_cast<unsigned>(time(0)*1.2);
272 printf("ServerThread::run: seed=%u\n", seed);
273
274 LocalServerSocket serverSocket("test", &waiter);
275 LocalAcceptor& acceptor = serverSocket.getAcceptor();
276
277 bool eventFired = false;
278 while(!acceptor.accept()) {
279 eventFired = event.check();
280 if (eventFired) break;
281 if (acceptor.failed()) {
282 printf("ServerThread::run: acceptor failed...: %lu\n",
283 (unsigned long)acceptor.getErrorCode());
284 return;
285 }
286 printf("ServerThread::run: waiting...\n");
287 waiter.wait();
288 }
289
290 if (eventFired) {
291 printf("ServerThread::run: waiting done, quitting\n");
292 return;
293 }
294
295 printf("ServerThread::run: waiting done, received connection\n");
296 LocalSocket* socket = acceptor.getSocket();
297
298 communicate(&socket->getReadingBuffer(), &socket->getWritingBuffer(),
299 waiter, seed, "ServerThread", &event);
300
301
302 delete socket;
303}
304
305//------------------------------------------------------------------------------
306//------------------------------------------------------------------------------
307
308class ClientThread : public Thread
309{
310private:
311 Waiter waiter;
312
313 WaitableEvent event;
314
315public:
316 ClientThread();
317
318 void signal();
319
320 virtual void run();
321};
322
323//------------------------------------------------------------------------------
324
325ClientThread::ClientThread() :
326 event(&waiter)
327{
328}
329
330//------------------------------------------------------------------------------
331
332void ClientThread::signal()
333{
334 event.fire();
335}
336
337//------------------------------------------------------------------------------
338
339void ClientThread::run()
340{
341 unsigned seed = static_cast<unsigned>(time(0)*1.8);
342 printf("ClientThread::run: seed=%u\n", seed);
343
344 printf("ClientThread::run: sleeping\n");
345 sleep(500);
346 printf("ClientThread::run: connecting\n");
347
348 LocalClientSocket socket("test", &waiter);
349
350 LocalConnector& connector = socket.getConnector();
351
352 while(!connector.connect()) {
353 if (connector.failed()) {
354 printf("ClientThread::run: connector failed...\n");
355 return;
356 }
357 printf("ClientThread::run: waiting...\n");
358 waiter.wait();
359 }
360
361 printf("ClientThread::run: connected\n");
362
363 communicate(&socket.getReadingBuffer(), &socket.getWritingBuffer(),
364 waiter, seed, "ClientThread", &event);
365}
366
367//------------------------------------------------------------------------------
368//------------------------------------------------------------------------------
369
370int main()
371{
372#if TARGET_API_POSIX
373 signal(SIGPIPE, SIG_IGN);
374#endif
375
376 ServerThread serverThread;
377 ClientThread clientThread;
378
379 printf("Starting threads\n");
380 serverThread.start();
381 clientThread.start();
382
383 Thread::sleep(60000);
384 //Thread::sleep(5000);
385 printf("Signalling the server thread\n");
386 //serverThread.signal();
387 clientThread.signal();
388 printf("Signalled the server thread\n");
389
390 printf("Waiting for the client thread\n");
391 clientThread.join();
392 printf("Waiting for the server thread\n");
393 serverThread.join();
394 printf("Both threads returned\n");
395
396 return 0;
397}
398
399//------------------------------------------------------------------------------
400
401// Local Variables:
402// mode: C++
403// c-basic-offset: 4
404// indent-tabs-mode: nil
405// End:
Note: See TracBrowser for help on using the repository browser.