source: xplcommon/test/testlocsock.cc@ 34:ad3194cb9bef

Last change on this file since 34:ad3194cb9bef 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
RevLine 
[18]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>
[21]38#include <xplcommon/LocalConnector.h>
[18]39#include <xplcommon/ReadingBuffer.h>
40#include <xplcommon/WritingBuffer.h>
[19]41#include <xplcommon/WaitableEvent.h>
[28]42#include <xplcommon/PseudoRandom.h>
[18]43
[19]44#include <cstdlib>
[18]45#include <cstdio>
[19]46#include <cassert>
47
48#include <signal.h>
49
50#include <sys/time.h>
[18]51
52//------------------------------------------------------------------------------
53
54using xplcommon::Thread;
55using xplcommon::Waiter;
56using xplcommon::LocalServerSocket;
57using xplcommon::LocalAcceptor;
58using xplcommon::LocalSocket;
59using xplcommon::LocalClientSocket;
[21]60using xplcommon::LocalConnector;
[19]61using xplcommon::ReadingBuffer;
62using xplcommon::WritingBuffer;
63using xplcommon::WaitableEvent;
[28]64using xplcommon::PseudoRandom;
[19]65
66using std::min;
67
68//------------------------------------------------------------------------------
69
[21]70void communicate(ReadingBuffer* readingBuffer, WritingBuffer* writingBuffer,
[19]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
[21]77 static const size_t reportingInterval = 10000;
[19]78
[28]79 static const int sleepThreshold = static_cast<int>(PseudoRandom::MAX * 0.99);
80 static const int sleepRemainder = PseudoRandom::MAX - sleepThreshold;
[19]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
[28]95 PseudoRandom random(seed);
[19]96 while(!toQuit) {
[28]97 size_t toWrite = random.nextUnsigned(maxToWrite, minToWrite);
[19]98
[21]99 size_t lastWriteLength = 0;
100 if (writingBuffer!=0) {
101 lastWriteLength = min(writingBuffer->getCapacity(), toWrite);
102 writingBuffer->reset();
103 writingBuffer->addLength(lastWriteLength);
104 }
105
[19]106 while(toWrite>0) {
107 if (quitEvent!=0 && quitEvent->check()) {
108 toQuit = true;
109 break;
110 }
111
[21]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 }
[19]130
[21]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 }
[19]154 }
[21]155 if (toQuit) break;
[19]156 }
157
[21]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 }
[19]196 }
[21]197 if (toQuit) break;
[19]198 }
199
[28]200 int r = random.next();
[19]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
[21]211 if (toWrite>0 && hasPending) {
[19]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
[21]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));
[19]234}
[18]235
236//------------------------------------------------------------------------------
237
238class ServerThread : public Thread
239{
[19]240private:
241 Waiter waiter;
242
243 WaitableEvent event;
244
245public:
246 ServerThread();
247
248 void signal();
249
[18]250 virtual void run();
251};
252
253//------------------------------------------------------------------------------
254
[19]255ServerThread::ServerThread() :
256 event(&waiter)
257{
258}
259
260//------------------------------------------------------------------------------
261
262void ServerThread::signal()
263{
264 event.fire();
265}
266
267//------------------------------------------------------------------------------
268
[18]269void ServerThread::run()
270{
[19]271 unsigned seed = static_cast<unsigned>(time(0)*1.2);
272 printf("ServerThread::run: seed=%u\n", seed);
[18]273
274 LocalServerSocket serverSocket("test", &waiter);
275 LocalAcceptor& acceptor = serverSocket.getAcceptor();
276
[21]277 bool eventFired = false;
[19]278 while(!acceptor.accept()) {
[21]279 eventFired = event.check();
280 if (eventFired) break;
[19]281 if (acceptor.failed()) {
[21]282 printf("ServerThread::run: acceptor failed...: %lu\n",
283 (unsigned long)acceptor.getErrorCode());
[19]284 return;
[18]285 }
[19]286 printf("ServerThread::run: waiting...\n");
287 waiter.wait();
288 }
[18]289
[21]290 if (eventFired) {
291 printf("ServerThread::run: waiting done, quitting\n");
292 return;
293 }
294
[19]295 printf("ServerThread::run: waiting done, received connection\n");
296 LocalSocket* socket = acceptor.getSocket();
297
[21]298 communicate(&socket->getReadingBuffer(), &socket->getWritingBuffer(),
[19]299 waiter, seed, "ServerThread", &event);
300
301
302 delete socket;
[18]303}
304
305//------------------------------------------------------------------------------
306//------------------------------------------------------------------------------
307
308class ClientThread : public Thread
309{
[21]310private:
311 Waiter waiter;
312
313 WaitableEvent event;
314
[18]315public:
[21]316 ClientThread();
317
318 void signal();
319
[18]320 virtual void run();
321};
322
323//------------------------------------------------------------------------------
324
[21]325ClientThread::ClientThread() :
326 event(&waiter)
327{
328}
329
330//------------------------------------------------------------------------------
331
332void ClientThread::signal()
333{
334 event.fire();
335}
336
337//------------------------------------------------------------------------------
338
[18]339void ClientThread::run()
340{
[19]341 unsigned seed = static_cast<unsigned>(time(0)*1.8);
342 printf("ClientThread::run: seed=%u\n", seed);
343
[18]344 printf("ClientThread::run: sleeping\n");
[19]345 sleep(500);
[18]346 printf("ClientThread::run: connecting\n");
347
348 LocalClientSocket socket("test", &waiter);
349
[21]350 LocalConnector& connector = socket.getConnector();
[18]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");
[19]362
[21]363 communicate(&socket.getReadingBuffer(), &socket.getWritingBuffer(),
364 waiter, seed, "ClientThread", &event);
[18]365}
366
367//------------------------------------------------------------------------------
368//------------------------------------------------------------------------------
369
370int main()
371{
[21]372#if TARGET_API_POSIX
[19]373 signal(SIGPIPE, SIG_IGN);
[21]374#endif
[19]375
[18]376 ServerThread serverThread;
377 ClientThread clientThread;
378
379 printf("Starting threads\n");
380 serverThread.start();
381 clientThread.start();
382
[19]383 Thread::sleep(60000);
[21]384 //Thread::sleep(5000);
385 printf("Signalling the server thread\n");
386 //serverThread.signal();
387 clientThread.signal();
[19]388 printf("Signalled the server thread\n");
389
[18]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.