Merge lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb
- D_tech_demos
- Merge into alpha
Proposed by
Rick Stovall
Status: | Merged |
---|---|
Merged at revision: | 13 |
Proposed branch: | lp:~fpstovall/nrtb/D_tech_demos |
Merge into: | lp:nrtb |
Diff against target: |
2348 lines (+2303/-0) 8 files modified
D_lang/testing/candidate_libs/splat.d (+1754/-0) D_lang/testing/candidate_libs/splat.html (+269/-0) D_lang/testing/str_socket/Makefile (+30/-0) D_lang/testing/str_socket/SocketStringTransciever.mm (+49/-0) D_lang/testing/str_socket/socket_test.d (+43/-0) D_lang/testing/thread_pool/Makefile (+30/-0) D_lang/testing/thread_pool/thread_pool.d (+81/-0) D_lang/testing/thread_pool/thread_pool.mm (+47/-0) |
To merge this branch: | bzr merge lp:~fpstovall/nrtb/D_tech_demos |
Related bugs: | |
Related blueprints: |
D language technology demos
(Medium)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Rick Stovall | Approve | ||
Review via email: mp+149745@code.launchpad.net |
Commit message
Description of the change
This branch includes the tech demos we agreed were needed before proceeding with the main alpha thrust in D. All are complete and functional now.
To post a comment you must log in.
Revision history for this message
Rick Stovall (fpstovall) wrote : | # |
Revision history for this message
Rick Stovall (fpstovall) wrote : | # |
As noted above, and with no bug and no exceptions noted at this time, I am approving this release because of its lack of mainline code and because the merge is needed to facilitate progress on the Alpha phase.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'D_lang/testing/candidate_libs' |
2 | === added file 'D_lang/testing/candidate_libs/splat.d' |
3 | --- D_lang/testing/candidate_libs/splat.d 1970-01-01 00:00:00 +0000 |
4 | +++ D_lang/testing/candidate_libs/splat.d 2013-02-21 03:06:20 +0000 |
5 | @@ -0,0 +1,1754 @@ |
6 | +/* |
7 | + Copyright (C) 2006-2007 Christopher E. Miller |
8 | + |
9 | + This software is provided 'as-is', without any express or implied |
10 | + warranty. In no event will the authors be held liable for any damages |
11 | + arising from the use of this software. |
12 | + |
13 | + Permission is granted to anyone to use this software for any purpose, |
14 | + including commercial applications, and to alter it and redistribute it |
15 | + freely, subject to the following restrictions: |
16 | + |
17 | + 1. The origin of this software must not be misrepresented; you must not |
18 | + claim that you wrote the original software. If you use this software |
19 | + in a product, an acknowledgment in the product documentation would be |
20 | + appreciated but is not required. |
21 | + 2. Altered source versions must be plainly marked as such, and must not be |
22 | + misrepresented as being the original software. |
23 | + 3. This notice may not be removed or altered from any source distribution. |
24 | +*/ |
25 | + |
26 | +/** $(B ) Splat: the socket platform with the lame name. It's full of puns, but it runs! |
27 | + <a href="http://www.dprogramming.com/splat.php">Download Splat</a>. |
28 | + Version 0.7. |
29 | + For both Phobos and Tango; tested with Phobos and Tango 0.99.2. |
30 | +**/ |
31 | +module splat; |
32 | + |
33 | + |
34 | +private |
35 | +{ |
36 | + version(Windows) |
37 | + { |
38 | + version(Tango) |
39 | + { |
40 | + import tango.sys.win32.UserGdi; |
41 | + } |
42 | + else |
43 | + { |
44 | + import std.c.windows.windows; |
45 | + } |
46 | + } |
47 | + |
48 | + |
49 | + version(Tango) |
50 | + { |
51 | + import tango.core.Type; |
52 | + |
53 | + alias tango.core.Type.Time spdTime; |
54 | + alias tango.core.Type.Time.TicksPerSecond spdTICKS_PER_SECOND; |
55 | + |
56 | + |
57 | + import tango.util.time.Clock; |
58 | + |
59 | + alias Clock.now spdGetCurrentUtcTime; |
60 | + |
61 | + |
62 | + import tango.net.Socket; |
63 | + |
64 | + alias tango.net.Socket.NetHost spdInternetHost; |
65 | + |
66 | + alias tango.net.Socket.IPv4Address spdInternetAddress; |
67 | + |
68 | + alias tango.net.Socket.timeval spdTimeval; |
69 | + |
70 | + struct spdMyTimeval |
71 | + { |
72 | + int seconds; |
73 | + int microseconds; |
74 | + } |
75 | + |
76 | + |
77 | + import tango.core.Thread; |
78 | + } |
79 | + else |
80 | + { |
81 | + import std.date; |
82 | + |
83 | + alias std.date.d_time spdTime; |
84 | + alias std.date.TicksPerSecond spdTICKS_PER_SECOND; |
85 | + alias std.date.getUTCtime spdGetCurrentUtcTime; |
86 | + |
87 | + |
88 | + import std.socket; |
89 | + |
90 | + alias std.socket.InternetHost spdInternetHost; |
91 | + |
92 | + alias std.socket.InternetAddress spdInternetAddress; |
93 | + |
94 | + alias std.socket.timeval spdMyTimeval; |
95 | + |
96 | + alias std.socket.timeval spdTimeval; |
97 | + |
98 | + |
99 | + import std.thread; |
100 | + } |
101 | + |
102 | + |
103 | + debug(splat) |
104 | + { |
105 | + version(Tango) |
106 | + import tango.stdc.stdio; |
107 | + else |
108 | + import std.c.stdio; |
109 | + } |
110 | +} |
111 | + |
112 | +static assert(spdMyTimeval.sizeof == spdTimeval.sizeof); |
113 | + |
114 | + |
115 | +/** |
116 | + Run the event loop; wait for timer and socket events. |
117 | + Exceptions that occur in event callbacks break out of run. |
118 | +**/ |
119 | +// It is NOT safe to call run() before a previous call to run() returns. |
120 | +void run() |
121 | +{ |
122 | + /+ |
123 | + static bool _running = false; |
124 | + if(_running) |
125 | + return; // ? |
126 | + _running = true; |
127 | + scope(exit) |
128 | + _running = false; |
129 | + +/ |
130 | + |
131 | + _texit = false; |
132 | + |
133 | + Timer tn; |
134 | + spdMyTimeval* ptv; |
135 | + spdMyTimeval tv; |
136 | + spdTime dnow; |
137 | + SocketSet reads = new SocketSet(); |
138 | + SocketSet writes = new SocketSet(); |
139 | + int i; |
140 | + bool dotimer = false; |
141 | + |
142 | + for(;;) |
143 | + { |
144 | + tn = _tnext(); |
145 | + |
146 | + version(Windows) |
147 | + { |
148 | + if(!_tallEvents.length) |
149 | + { |
150 | + no_socket_events: |
151 | + DWORD ms = INFINITE; |
152 | + if(tn) |
153 | + { |
154 | + dnow = spdGetCurrentUtcTime(); |
155 | + if(tn._talarm <= dnow) |
156 | + goto timedout; |
157 | + ms = _tticksToMs(cast(spdTime)(tn._talarm - dnow)); |
158 | + } |
159 | + |
160 | + if(INFINITE == ms) |
161 | + { |
162 | + if(_areHosts()) |
163 | + ms = 200; |
164 | + } |
165 | + |
166 | + debug(splat) |
167 | + { |
168 | + if(INFINITE != ms) |
169 | + printf(" {SLEEP} %lu ms\n", cast(uint)ms); |
170 | + //else |
171 | + // printf(" {SLEEP} infinite\n"); |
172 | + } |
173 | + |
174 | + Sleep(ms); |
175 | + goto timedout; |
176 | + } |
177 | + } |
178 | + |
179 | + ptv = null; |
180 | + if(tn) |
181 | + { |
182 | + debug(splattimer) |
183 | + printf("splattimer: diff = %d; dotimer = %s\n", |
184 | + cast(int)(dnow - tn._talarm), |
185 | + dotimer ? "true".ptr : "false".ptr); |
186 | + |
187 | + if(tn._talarm <= dnow) |
188 | + { |
189 | + version(Windows) |
190 | + { |
191 | + assert(_tallEvents.length); |
192 | + } |
193 | + else |
194 | + { |
195 | + if(!_tallEvents.length) |
196 | + goto timedout; |
197 | + } |
198 | + if(dotimer) |
199 | + goto timedout; |
200 | + dotimer = true; // Do timer next time around. |
201 | + tv.seconds = 0; |
202 | + tv.microseconds = 0; |
203 | + } |
204 | + else |
205 | + { |
206 | + dnow = spdGetCurrentUtcTime(); |
207 | + _tticksToTimeval(tn._talarm - dnow, &tv); |
208 | + if(tv.microseconds < 0) |
209 | + tv.microseconds = 0; |
210 | + //if(tv.microseconds > 32767) |
211 | + // tv.microseconds = 32767; |
212 | + if(tv.seconds < 0) |
213 | + tv.seconds = 0; |
214 | + if(tv.seconds > 60) |
215 | + tv.seconds = 60; |
216 | + |
217 | + if(_areHosts()) |
218 | + { |
219 | + if(tv.seconds || tv.microseconds > 200_000) |
220 | + { |
221 | + tv.seconds = 0; |
222 | + tv.microseconds = 200_000; |
223 | + } |
224 | + } |
225 | + } |
226 | + ptv = &tv; |
227 | + } |
228 | + else |
229 | + { |
230 | + debug(splattimer) |
231 | + printf("splattimer: no timers\n"); |
232 | + |
233 | + if(_areHosts()) |
234 | + { |
235 | + tv.seconds = 0; |
236 | + tv.microseconds = 200_000; |
237 | + ptv = &tv; |
238 | + } |
239 | + } |
240 | + |
241 | + reads.reset(); |
242 | + writes.reset(); |
243 | + |
244 | + uint numadds = 0; |
245 | + foreach(AsyncSocket sock; _tallEvents) |
246 | + { |
247 | + //debug |
248 | + debug(splat) |
249 | + { |
250 | + if(!sock.isAlive()) |
251 | + { |
252 | + debug(splat) |
253 | + { |
254 | + printf("Splat warning: dead socket still waiting for events\n"); |
255 | + fflush(stdout); |
256 | + } |
257 | + //continue; |
258 | + } |
259 | + } |
260 | + |
261 | + if(((sock._events & EventType.READ) && !(sock._events & EventType._CANNOT_READ)) |
262 | + || ((sock._events & EventType.ACCEPT) && !(sock._events & EventType._CANNOT_ACCEPT)) |
263 | + || ((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))) |
264 | + { |
265 | + reads.add(sock); |
266 | + numadds++; |
267 | + } |
268 | + |
269 | + if(((sock._events & EventType.WRITE) && !(sock._events & EventType._CANNOT_WRITE)) |
270 | + || ((sock._events & EventType.CONNECT) && !(sock._events & EventType._CANNOT_CONNECT))) |
271 | + { |
272 | + writes.add(sock); |
273 | + numadds++; |
274 | + } |
275 | + } |
276 | + |
277 | + if(_texit) |
278 | + return; |
279 | + |
280 | + version(Windows) |
281 | + { |
282 | + if(!numadds) |
283 | + goto no_socket_events; |
284 | + |
285 | + //assert(reads.count || writes.count); |
286 | + } |
287 | + |
288 | + debug(splat) |
289 | + { |
290 | + if(ptv) |
291 | + { |
292 | + if(0 != ptv.seconds || 0 != ptv.microseconds) |
293 | + printf(" {SELECT} %lu secs, %lu microsecs\n", cast(uint)ptv.seconds, cast(uint)ptv.microseconds); |
294 | + //else |
295 | + // printf(" {SELECT} 0\n"); |
296 | + } |
297 | + //else |
298 | + //{ |
299 | + // printf(" {SELECT} infinite\n"); |
300 | + //} |
301 | + } |
302 | + |
303 | + debug(splatselect) |
304 | + printf("Socket.select(%u sockets%s)\n", numadds, |
305 | + ptv ? (((0 != ptv.seconds || 0 != ptv.microseconds)) ? ", timeout".ptr : ", 0 timeout") : ", infinite-wait".ptr); |
306 | + i = Socket.select(reads, writes, null, cast(spdTimeval*)ptv); |
307 | + switch(i) |
308 | + { |
309 | + case -1: // Interruption. |
310 | + continue; // ? |
311 | + |
312 | + case 0: // Timeout. |
313 | + goto timedout; |
314 | + |
315 | + default: // Socket event(s). |
316 | + foreach(AsyncSocket sock; _tallEvents) |
317 | + { |
318 | + if(_texit) |
319 | + return; |
320 | + |
321 | + //if(!sock.isAlive()) |
322 | + // continue; |
323 | + |
324 | + if(reads.isSet(sock)) |
325 | + { |
326 | + if((sock._events & EventType.READ) && !(sock._events & EventType._CANNOT_READ)) |
327 | + { |
328 | + switch(sock._peekreceiveclose()) |
329 | + { |
330 | + case 0: // Close. |
331 | + if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE)) |
332 | + { |
333 | + goto got_close; |
334 | + } |
335 | + else |
336 | + { |
337 | + //sock._events |= EventType._CANNOT_READ; |
338 | + sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ? |
339 | + //sock._tgotEvent(EventType.READ, 0); // Should this be an error? |
340 | + } |
341 | + break; |
342 | + case -1: // Error. |
343 | + if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE)) |
344 | + { |
345 | + //sock._events |= EventType._CANNOT_READ; |
346 | + sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ? |
347 | + sock._tgotEvent(EventType.CLOSE, -1); // ? |
348 | + } |
349 | + else |
350 | + { |
351 | + //sock._events |= EventType._CANNOT_READ; |
352 | + sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ? |
353 | + sock._tgotEvent(EventType.READ, -1); |
354 | + } |
355 | + break; |
356 | + default: // Good. |
357 | + sock._events |= EventType._CANNOT_READ; |
358 | + sock._tgotEvent(EventType.READ, 0); |
359 | + } |
360 | + } |
361 | + else if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE)) |
362 | + { |
363 | + switch(sock._peekreceiveclose()) |
364 | + { |
365 | + case 0: // Close. |
366 | + got_close: |
367 | + //sock._events |= EventType._CANNOT_CLOSE; |
368 | + sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ? |
369 | + //writes.remove(sock); // ? |
370 | + sock._tgotEvent(EventType.CLOSE, 0); |
371 | + break; |
372 | + case -1: // Error. |
373 | + //sock._events |= EventType._CANNOT_CLOSE; |
374 | + sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ? |
375 | + //writes.remove(sock); // ? |
376 | + sock._tgotEvent(EventType.CLOSE, -1); |
377 | + break; |
378 | + default: ; |
379 | + } |
380 | + } |
381 | + |
382 | + if((sock._events & EventType.ACCEPT) && !(sock._events & EventType._CANNOT_ACCEPT)) |
383 | + { |
384 | + sock._events |= EventType._CANNOT_ACCEPT; |
385 | + sock._tgotEvent(EventType.ACCEPT, 0); |
386 | + } |
387 | + |
388 | + continue; // Checking for writability (otherwise next) on a closed socket (from any above event) is problematic. |
389 | + } |
390 | + |
391 | + //if(_texit) |
392 | + // return; |
393 | + |
394 | + if(writes.isSet(sock)) |
395 | + { |
396 | + if((sock._events & EventType.CONNECT) && !(sock._events & EventType._CANNOT_CONNECT)) |
397 | + { |
398 | + sock._events |= EventType._CANNOT_CONNECT; |
399 | + sock._tgotEvent(EventType.CONNECT, 0); |
400 | + } |
401 | + |
402 | + if((sock._events & EventType.WRITE) && !(sock._events & EventType._CANNOT_WRITE)) |
403 | + { |
404 | + sock._events |= EventType._CANNOT_WRITE; |
405 | + sock._tgotEvent(EventType.WRITE, 0); |
406 | + } |
407 | + } |
408 | + } |
409 | + //continue; |
410 | + goto do_hosts; |
411 | + } |
412 | + |
413 | + // Check timers.. |
414 | + timedout: ; |
415 | + dotimer = false; |
416 | + _tdotimers(); |
417 | + |
418 | + // Check resolved hosts.. |
419 | + do_hosts: |
420 | + GetHost gh; |
421 | + while(null !is (gh = _tnextDoneHost())) |
422 | + { |
423 | + gh._tgotEvent(); |
424 | + |
425 | + if(_texit) |
426 | + return; |
427 | + } |
428 | + |
429 | + if(_texit) |
430 | + return; |
431 | + } |
432 | +} |
433 | + |
434 | + |
435 | +/// Causes run() to return as soon as it can. |
436 | +void exitLoop() |
437 | +{ |
438 | + _texit = true; |
439 | +} |
440 | + |
441 | + |
442 | +private void _tdotimers() |
443 | +{ |
444 | + size_t nalarms; |
445 | + Timer[4] talarms; |
446 | + spdTime dnow; |
447 | + Timer tn; |
448 | + dnow = spdGetCurrentUtcTime(); |
449 | + for(tn = _tfirst; tn; tn = tn._tnext) |
450 | + { |
451 | + if(dnow >= tn._talarm) |
452 | + { |
453 | + if(nalarms < talarms.length) |
454 | + talarms[nalarms] = tn; |
455 | + nalarms++; |
456 | + } |
457 | + } |
458 | + Timer[] nowalarm; |
459 | + if(nalarms <= talarms.length) |
460 | + { |
461 | + nowalarm = talarms[0 .. nalarms]; |
462 | + } |
463 | + else |
464 | + { |
465 | + nowalarm = new Timer[nalarms]; |
466 | + nalarms = 0; |
467 | + for(tn = _tfirst; tn; tn = tn._tnext) |
468 | + { |
469 | + if(dnow >= tn._talarm) |
470 | + { |
471 | + nowalarm[nalarms] = tn; |
472 | + nalarms++; |
473 | + } |
474 | + } |
475 | + assert(nowalarm.length == nalarms); |
476 | + } |
477 | + |
478 | + foreach(Timer t; nowalarm) |
479 | + { |
480 | + if(_texit) |
481 | + return; |
482 | + |
483 | + if(t._talarm != t._TALARM_INIT) // Make sure not removed by some other timer event. |
484 | + { |
485 | + t._talarm = cast(spdTime)(dnow + t._ttimeout); // Also update alarm time BEFORE in case of exception (could cause rapid fire otherwise). |
486 | + t._tgotAlarm(); |
487 | + if(t._talarm != t._TALARM_INIT) // Maybe removed itself. |
488 | + { |
489 | + // Set new alarm after this alarm due to possible delay AND possible updated timeout/interval. |
490 | + dnow = spdGetCurrentUtcTime(); // In case time lapses in some other timer event. |
491 | + t._talarm = cast(spdTime)(dnow + t._ttimeout); |
492 | + } |
493 | + } |
494 | + } |
495 | +} |
496 | + |
497 | + |
498 | +/// Timers; alarms (timeout events) depend on run(). |
499 | +class Timer |
500 | +{ |
501 | + /// Property: get and set the timer _interval in milliseconds. |
502 | + final void interval(uint iv) // setter |
503 | + { |
504 | + iv = cast(uint)_tmsToTicks(iv); |
505 | + if(!iv) |
506 | + iv = 1; |
507 | + if(iv != _ttimeout) |
508 | + { |
509 | + _ttimeout = iv; |
510 | + |
511 | + if(_talarm != _TALARM_INIT) |
512 | + { |
513 | + stop(); |
514 | + start(); |
515 | + } |
516 | + } |
517 | + } |
518 | + |
519 | + /// ditto |
520 | + final uint interval() // getter |
521 | + { |
522 | + return _tticksToMs(cast(spdTime)_ttimeout); |
523 | + } |
524 | + |
525 | + |
526 | + /// Start this timer. |
527 | + final void start() |
528 | + { |
529 | + if(_talarm) |
530 | + return; |
531 | + |
532 | + assert(_ttimeout > 0); |
533 | + |
534 | + _tadd(this); |
535 | + |
536 | + debug(splat) |
537 | + { |
538 | + printf(" {ADDTIMER:%p} %lu ms\n", cast(void*)this, interval); |
539 | + } |
540 | + } |
541 | + |
542 | + |
543 | + /// Stop this timer. |
544 | + final void stop() |
545 | + { |
546 | + if(_talarm) |
547 | + { |
548 | + _tremove(this); |
549 | + |
550 | + debug(splat) |
551 | + { |
552 | + printf(" {DELTIMER:%p} %lu ms\n", cast(void*)this, interval); |
553 | + } |
554 | + } |
555 | + } |
556 | + |
557 | + |
558 | + /// Override to be notified when the time expires. Alarms continue until stop(). |
559 | + void onAlarm() |
560 | + { |
561 | + if(_tick) |
562 | + _tick(this); |
563 | + } |
564 | + |
565 | + |
566 | + /// Construct a timer; can take a delegate that is called back automatically on an alarm. |
567 | + this() |
568 | + { |
569 | + _ttimeout = cast(uint)_tmsToTicks(100); |
570 | + } |
571 | + |
572 | + /// ditto |
573 | + this(void delegate(Timer) dg) |
574 | + { |
575 | + this(); |
576 | + this._tick = dg; |
577 | + } |
578 | + |
579 | + |
580 | + private: |
581 | + const spdTime _TALARM_INIT = cast(spdTime)0; |
582 | + spdTime _talarm = _TALARM_INIT; // Time when next event is alarmed. |
583 | + //spdTime _ttimeout; // Ticks per timeout. |
584 | + uint _ttimeout; // Ticks per timeout. |
585 | + Timer _tprev, _tnext; |
586 | + void delegate(Timer) _tick; |
587 | + |
588 | + |
589 | + void _tgotAlarm() |
590 | + { |
591 | + debug(splat) |
592 | + { |
593 | + printf(" {TIMER:%p}\n", cast(void*)this); |
594 | + } |
595 | + |
596 | + onAlarm(); |
597 | + } |
598 | +} |
599 | + |
600 | + |
601 | +// Can be OR'ed. |
602 | +/// Socket event flags. |
603 | +enum EventType |
604 | +{ |
605 | + NONE = 0, /// |
606 | + |
607 | + READ = 0x1, /// |
608 | + WRITE = 0x2, /// ditto |
609 | + //OOB = 0x4, /// ditto |
610 | + ACCEPT = 0x8, /// ditto |
611 | + CONNECT = 0x10, /// ditto |
612 | + CLOSE = 0x20, /// ditto |
613 | + |
614 | + _CANNOT_READ = READ << 16, // package |
615 | + _CANNOT_WRITE = WRITE << 16, // package |
616 | + //_CANNOT_OOB = OOB << 16, // package |
617 | + _CANNOT_ACCEPT = ACCEPT << 16, // package |
618 | + _CANNOT_CONNECT = CONNECT << 16, // package |
619 | + _CANNOT_CLOSE = CLOSE << 16, // package |
620 | +} |
621 | + |
622 | +private EventType _tEventType_ALL = EventType.READ | EventType.WRITE /+ | EventType.OOB +/ |
623 | + | EventType.ACCEPT | EventType.CONNECT | EventType.CLOSE; |
624 | +private EventType _tEventType_ALLREADS = EventType.READ | EventType.ACCEPT | EventType.CLOSE; |
625 | +private EventType _tEventType_ALLWRITES = EventType.WRITE | EventType.CONNECT; |
626 | + |
627 | + |
628 | +/** |
629 | + Callback type for socket events. |
630 | + Params: |
631 | + sock = the socket |
632 | + type = which event; will be only one of the event flags. |
633 | + err = an error code, or 0 if successful. |
634 | +**/ |
635 | +alias void delegate(Socket sock, EventType type, int err) RegisterEventCallback; |
636 | + |
637 | + |
638 | +/// Asynchronous sockets; socket events depend on run(). Mostly the same as std.socket.Socket. |
639 | +class AsyncSocket: Socket |
640 | +{ |
641 | + version(Tango) |
642 | + { |
643 | + this(AddressFamily family, SocketType type, ProtocolType protocol, bool create = true) |
644 | + { |
645 | + super(family, type, protocol, create); |
646 | + super.blocking = false; |
647 | + } |
648 | + } |
649 | + else |
650 | + { |
651 | + this(AddressFamily af, SocketType type, ProtocolType protocol) |
652 | + { |
653 | + super(af, type, protocol); |
654 | + super.blocking = false; |
655 | + } |
656 | + |
657 | + |
658 | + this(AddressFamily af, SocketType type) |
659 | + { |
660 | + super(af, type); |
661 | + super.blocking = false; |
662 | + } |
663 | + |
664 | + |
665 | + this(AddressFamily af, SocketType type, char[] protocolName) |
666 | + { |
667 | + super(af, type, protocolName); |
668 | + super.blocking = false; |
669 | + } |
670 | + } |
671 | + |
672 | + |
673 | + /** |
674 | + Registers a callback for specified socket events. |
675 | + One or more type flags may be used, or NONE to cancel all. |
676 | + Calling this twice on the same socket cancels out previously registered events for the socket. |
677 | + **/ |
678 | + // Requires run() loop. |
679 | + void event(EventType events, RegisterEventCallback callback) |
680 | + { |
681 | + this.blocking = false; |
682 | + |
683 | + this._events = EventType.NONE; |
684 | + |
685 | + if(!(events & (_tEventType_ALLREADS | _tEventType_ALLWRITES))) |
686 | + return; |
687 | + |
688 | + if(isAlive()) // Alive socket already connected or never will. |
689 | + this._events |= EventType._CANNOT_CONNECT; |
690 | + |
691 | + if(events & EventType.ACCEPT) |
692 | + events &= ~(EventType.READ | EventType.CLOSE); // Issues in select() if accept and these set. |
693 | + |
694 | + this._events = events | _tEventType_ALL; |
695 | + this._callback = callback; |
696 | + |
697 | + _tallEvents[this.handle] = this; |
698 | + } |
699 | + |
700 | + |
701 | + version(Tango) |
702 | + { |
703 | + alias fileHandle handle; |
704 | + } |
705 | + |
706 | + |
707 | + // For use with accepting(). |
708 | + protected this() |
709 | + { |
710 | + } |
711 | + |
712 | + |
713 | + version(Tango) |
714 | + { |
715 | + override Socket accept() |
716 | + { |
717 | + return accept(new AsyncSocket()); |
718 | + } |
719 | + |
720 | + // Overload. |
721 | + //alias Socket.accept accept; // Don't overload since I override this one below.. |
722 | + } |
723 | + else |
724 | + { |
725 | + protected override AsyncSocket accepting() |
726 | + { |
727 | + return new AsyncSocket(); |
728 | + } |
729 | + } |
730 | + |
731 | + |
732 | + version(Tango) |
733 | + private const bool _IS_TANGO = true; |
734 | + else |
735 | + private const bool _IS_TANGO = false; |
736 | + |
737 | + static if(_IS_TANGO && is(typeof(&this.detach))) |
738 | + { |
739 | + override void detach() |
740 | + { |
741 | + _events = EventType.NONE; |
742 | + _tallEvents.remove(this.handle); |
743 | + return super.detach(); |
744 | + } |
745 | + } |
746 | + else |
747 | + { |
748 | + override void close() |
749 | + { |
750 | + _events = EventType.NONE; |
751 | + _tallEvents.remove(this.handle); |
752 | + return super.close(); |
753 | + } |
754 | + } |
755 | + |
756 | + |
757 | + override bool blocking() // getter |
758 | + { |
759 | + return false; |
760 | + } |
761 | + |
762 | + |
763 | + override void blocking(bool byes) // setter |
764 | + { |
765 | + if(byes) |
766 | + assert(0); |
767 | + } |
768 | + |
769 | + |
770 | + version(Tango) |
771 | + { |
772 | + override int receive(void[] buf, SocketFlags flags = SocketFlags.NONE) |
773 | + { |
774 | + _events &= ~EventType._CANNOT_READ; |
775 | + return super.receive(buf, flags); |
776 | + } |
777 | + |
778 | + override int receiveFrom(void[] buf, SocketFlags flags, Address from) |
779 | + { |
780 | + _events &= ~EventType._CANNOT_READ; |
781 | + return super.receiveFrom(buf, flags, from); |
782 | + } |
783 | + |
784 | + override int receiveFrom(void[] buf, Address from) |
785 | + { |
786 | + _events &= ~EventType._CANNOT_READ; |
787 | + return super.receiveFrom(buf, from); |
788 | + } |
789 | + |
790 | + override int receiveFrom(void[] buf, SocketFlags flags = SocketFlags.NONE) |
791 | + { |
792 | + _events &= ~EventType._CANNOT_READ; |
793 | + return super.receiveFrom(buf, flags); |
794 | + } |
795 | + |
796 | + |
797 | + override int send(void[] buf, SocketFlags flags = SocketFlags.NONE) |
798 | + { |
799 | + _events &= ~EventType._CANNOT_WRITE; |
800 | + return super.send(buf, flags); |
801 | + } |
802 | + |
803 | + override int sendTo(void[] buf, SocketFlags flags, Address to) |
804 | + { |
805 | + _events &= ~EventType._CANNOT_WRITE; |
806 | + return super.sendTo(buf, flags, to); |
807 | + } |
808 | + |
809 | + override int sendTo(void[] buf, Address to) |
810 | + { |
811 | + _events &= ~EventType._CANNOT_WRITE; |
812 | + return super.sendTo(buf, to); |
813 | + } |
814 | + |
815 | + override int sendTo(void[] buf, SocketFlags flags = SocketFlags.NONE) |
816 | + { |
817 | + _events &= ~EventType._CANNOT_WRITE; |
818 | + return super.sendTo(buf, flags); |
819 | + } |
820 | + } |
821 | + else |
822 | + { |
823 | + override int receive(void[] buf, SocketFlags flags) |
824 | + { |
825 | + _events &= ~EventType._CANNOT_READ; |
826 | + return super.receive(buf, flags); |
827 | + } |
828 | + |
829 | + override int receive(void[] buf) |
830 | + { |
831 | + _events &= ~EventType._CANNOT_READ; |
832 | + return super.receive(buf); |
833 | + } |
834 | + |
835 | + override int receiveFrom(void[] buf, SocketFlags flags, out Address from) |
836 | + { |
837 | + _events &= ~EventType._CANNOT_READ; |
838 | + return super.receiveFrom(buf, flags, from); |
839 | + } |
840 | + |
841 | + override int receiveFrom(void[] buf, out Address from) |
842 | + { |
843 | + _events &= ~EventType._CANNOT_READ; |
844 | + return super.receiveFrom(buf, from); |
845 | + } |
846 | + |
847 | + override int receiveFrom(void[] buf, SocketFlags flags) |
848 | + { |
849 | + _events &= ~EventType._CANNOT_READ; |
850 | + return super.receiveFrom(buf, flags); |
851 | + } |
852 | + |
853 | + override int receiveFrom(void[] buf) |
854 | + { |
855 | + _events &= ~EventType._CANNOT_READ; |
856 | + return super.receiveFrom(buf); |
857 | + } |
858 | + |
859 | + |
860 | + override int send(void[] buf, SocketFlags flags) |
861 | + { |
862 | + _events &= ~EventType._CANNOT_WRITE; |
863 | + return super.send(buf, flags); |
864 | + } |
865 | + |
866 | + override int send(void[] buf) |
867 | + { |
868 | + _events &= ~EventType._CANNOT_WRITE; |
869 | + return super.send(buf); |
870 | + } |
871 | + |
872 | + override int sendTo(void[] buf, SocketFlags flags, Address to) |
873 | + { |
874 | + _events &= ~EventType._CANNOT_WRITE; |
875 | + return super.sendTo(buf, flags, to); |
876 | + } |
877 | + |
878 | + override int sendTo(void[] buf, Address to) |
879 | + { |
880 | + _events &= ~EventType._CANNOT_WRITE; |
881 | + return super.sendTo(buf, to); |
882 | + } |
883 | + |
884 | + override int sendTo(void[] buf, SocketFlags flags) |
885 | + { |
886 | + _events &= ~EventType._CANNOT_WRITE; |
887 | + return super.sendTo(buf, flags); |
888 | + } |
889 | + |
890 | + override int sendTo(void[] buf) |
891 | + { |
892 | + _events &= ~EventType._CANNOT_WRITE; |
893 | + return super.sendTo(buf); |
894 | + } |
895 | + } |
896 | + |
897 | + |
898 | + version(Tango) |
899 | + { |
900 | + override Socket accept(Socket s) |
901 | + { |
902 | + _events &= ~EventType._CANNOT_ACCEPT; |
903 | + return super.accept(s); |
904 | + } |
905 | + } |
906 | + else |
907 | + { |
908 | + override Socket accept() |
909 | + { |
910 | + _events &= ~EventType._CANNOT_ACCEPT; |
911 | + return super.accept(); |
912 | + } |
913 | + } |
914 | + |
915 | + |
916 | + private: |
917 | + |
918 | + EventType _events; |
919 | + RegisterEventCallback _callback; |
920 | + |
921 | + |
922 | + void _cando(EventType can) |
923 | + { |
924 | + _events &= ~(can << 16); |
925 | + } |
926 | + |
927 | + void _cannotdo(EventType cannot) |
928 | + { |
929 | + _events |= (cannot << 16); |
930 | + } |
931 | + |
932 | + bool _ifcando(EventType ifcan) |
933 | + { |
934 | + return !(_events & (ifcan << 16)); |
935 | + } |
936 | + |
937 | + |
938 | + int _peekreceiveclose() |
939 | + { |
940 | + byte[1] onebyte; |
941 | + return Socket.receive(onebyte, SocketFlags.PEEK); |
942 | + } |
943 | + |
944 | + |
945 | + void _tgotEvent(EventType type, int err) |
946 | + { |
947 | + debug(splat) |
948 | + { |
949 | + if(type == EventType.READ) |
950 | + printf(" {READ:%p}\n", cast(void*)this); |
951 | + else if(type == EventType.WRITE) |
952 | + printf(" {WRITE:%p}\n", cast(void*)this); |
953 | + else if(type == EventType.CONNECT) |
954 | + printf(" {CONNECT:%p}\n", cast(void*)this); |
955 | + else if(type == EventType.CLOSE) |
956 | + printf(" {CLOSE:%p}\n", cast(void*)this); |
957 | + else if(type == EventType.ACCEPT) |
958 | + printf(" {ACCEPT:%p}\n", cast(void*)this); |
959 | + } |
960 | + |
961 | + if(_callback) |
962 | + _callback(this, type, err); |
963 | + } |
964 | +} |
965 | + |
966 | + |
967 | +/// Asynchronous TCP socket shortcut. |
968 | +class AsyncTcpSocket: AsyncSocket |
969 | +{ |
970 | + /// |
971 | + this(AddressFamily family) |
972 | + { |
973 | + super(family, SocketType.STREAM, ProtocolType.TCP); |
974 | + } |
975 | + |
976 | + /// ditto |
977 | + this() |
978 | + { |
979 | + this(cast(AddressFamily)AddressFamily.INET); |
980 | + } |
981 | + |
982 | + /// ditto |
983 | + // Shortcut. |
984 | + this(EventType events, RegisterEventCallback eventCallback) |
985 | + { |
986 | + this(cast(AddressFamily)AddressFamily.INET); |
987 | + event(events, eventCallback); |
988 | + } |
989 | + |
990 | + /// ditto |
991 | + // Shortcut. |
992 | + this(Address connectTo, EventType events, RegisterEventCallback eventCallback) |
993 | + { |
994 | + this(connectTo.addressFamily()); |
995 | + event(events, eventCallback); |
996 | + connect(connectTo); |
997 | + } |
998 | +} |
999 | + |
1000 | + |
1001 | +/// Asynchronous UDP socket shortcut. |
1002 | +class AsyncUdpSocket: AsyncSocket |
1003 | +{ |
1004 | + /// |
1005 | + this(AddressFamily family) |
1006 | + { |
1007 | + super(family, SocketType.DGRAM, ProtocolType.UDP); |
1008 | + } |
1009 | + |
1010 | + /// ditto |
1011 | + this() |
1012 | + { |
1013 | + this(cast(AddressFamily)AddressFamily.INET); |
1014 | + } |
1015 | + |
1016 | + /// ditto |
1017 | + // Shortcut. |
1018 | + this(EventType events, RegisterEventCallback eventCallback) |
1019 | + { |
1020 | + this(cast(AddressFamily)AddressFamily.INET); |
1021 | + event(events, eventCallback); |
1022 | + } |
1023 | +} |
1024 | + |
1025 | + |
1026 | +private void _tgetHostErr() |
1027 | +{ |
1028 | + throw new Exception("Get host failure"); |
1029 | +} |
1030 | + |
1031 | + |
1032 | +/** |
1033 | + Callback type for host resolve event. |
1034 | + Params: |
1035 | + inetHost = the InternetHost/NetHost of the resolved host, or null. |
1036 | + err = an error code, or 0 if successful; if 0, inetHost will be null. |
1037 | +**/ |
1038 | +alias void delegate(spdInternetHost inetHost, int err) GetHostCallback; |
1039 | + |
1040 | + |
1041 | +/// Returned from asyncGetHost functions. |
1042 | +class GetHost |
1043 | +{ |
1044 | + /// Cancel the get-host operation. |
1045 | + void cancel() |
1046 | + { |
1047 | + _tcallback = null; |
1048 | + } |
1049 | + |
1050 | + |
1051 | + private: |
1052 | + GetHostCallback _tcallback; |
1053 | + GetHost _tnext; |
1054 | + spdInternetHost _tinetHost; |
1055 | + |
1056 | + bool _tbyname; // false == by addr |
1057 | + union |
1058 | + { |
1059 | + uint _taddr; |
1060 | + char[] _tname; |
1061 | + } |
1062 | + |
1063 | + |
1064 | + void _tgotEvent() |
1065 | + { |
1066 | + if(!_tcallback) // If cancel(). |
1067 | + return; |
1068 | + |
1069 | + if(!_tinetHost) |
1070 | + { |
1071 | + _tcallback(null, -1); // ? |
1072 | + return; |
1073 | + } |
1074 | + |
1075 | + _tcallback(_tinetHost, 0); |
1076 | + } |
1077 | + |
1078 | + |
1079 | + this() |
1080 | + { |
1081 | + } |
1082 | +} |
1083 | + |
1084 | + |
1085 | +/// Asynchronously resolve host information from a hostname; the callback depends on run(). |
1086 | +GetHost asyncGetHostByName(char[] name, GetHostCallback callback) |
1087 | +{ |
1088 | + GetHost gh; |
1089 | + gh = new GetHost; |
1090 | + version(NO_THREADS) |
1091 | + { |
1092 | + spdInternetHost ih; |
1093 | + ih = new spdInternetHost; |
1094 | + if(ih.getHostByName(name)) |
1095 | + { |
1096 | + gh.inetHost = ih; |
1097 | + } |
1098 | + } |
1099 | + else |
1100 | + { |
1101 | + gh._tcallback = callback; |
1102 | + gh._tbyname = true; |
1103 | + gh._tname = name; |
1104 | + _tgethost(gh); |
1105 | + } |
1106 | + return gh; |
1107 | +} |
1108 | + |
1109 | + |
1110 | +/// Asynchronously resolve host information from an IPv4 address; the callback depends on run(). |
1111 | +GetHost asyncGetHostByAddr(uint addr, GetHostCallback callback) |
1112 | +{ |
1113 | + GetHost gh; |
1114 | + gh = new GetHost; |
1115 | + version(NO_THREADS) |
1116 | + { |
1117 | + spdInternetHost ih; |
1118 | + ih = new spdInternetHost; |
1119 | + if(ih.getHostByAddr(addr)) |
1120 | + { |
1121 | + gh.inetHost = ih; |
1122 | + } |
1123 | + } |
1124 | + else |
1125 | + { |
1126 | + gh._tcallback = callback; |
1127 | + gh._tbyname = false; |
1128 | + gh._taddr = addr; |
1129 | + _tgethost(gh); |
1130 | + } |
1131 | + return gh; |
1132 | +} |
1133 | + |
1134 | +/// ditto |
1135 | +GetHost asyncGetHostByAddr(char[] addr, GetHostCallback callback) |
1136 | +{ |
1137 | + uint uiaddr; |
1138 | + uiaddr = spdInternetAddress.parse(addr); |
1139 | + if(spdInternetAddress.ADDR_NONE == uiaddr) |
1140 | + _tgetHostErr(); |
1141 | + return asyncGetHostByAddr(uiaddr, callback); |
1142 | +} |
1143 | + |
1144 | + |
1145 | +version = THSLEEP; |
1146 | + |
1147 | + |
1148 | +version(THSLEEP) |
1149 | +{ |
1150 | + version(Windows) |
1151 | + { |
1152 | + private void _tthsleep() |
1153 | + { |
1154 | + Sleep(200); // 0.2 secs. |
1155 | + } |
1156 | + } |
1157 | + else |
1158 | + { |
1159 | + private extern(C) int usleep(uint microseconds); |
1160 | + |
1161 | + private void _tthsleep() |
1162 | + { |
1163 | + usleep(200_000); // 0.2 secs. |
1164 | + } |
1165 | + } |
1166 | +} |
1167 | + |
1168 | + |
1169 | +private void _tgethost(GetHost gh) |
1170 | +{ |
1171 | + debug(splat) |
1172 | + { |
1173 | + printf(" {GETHOST:%p}\n", cast(void*)gh); |
1174 | + } |
1175 | + |
1176 | + //synchronized |
1177 | + { |
1178 | + gh._tnext = null; |
1179 | + |
1180 | + if(!_ththread) |
1181 | + { |
1182 | + //printf("GETHOST:newthread\n"); |
1183 | + version(Tango) |
1184 | + _ththread = new Thread(&_ththreadproc); |
1185 | + else |
1186 | + _ththread = new Thread(&_ththreadproc, null); |
1187 | + _thnext = _thaddto = gh; |
1188 | + _ththread.start(); |
1189 | + return; |
1190 | + } |
1191 | + |
1192 | + synchronized(_ththread) |
1193 | + { |
1194 | + if(!_thaddto) |
1195 | + { |
1196 | + //printf("GETHOST:!_thaddto\n"); |
1197 | + version(SPLAT_HACK_PRINTF) |
1198 | + printf(""); // Without this, the thread never sees this host. |
1199 | + _thnext = _thaddto = gh; |
1200 | + |
1201 | + version(THSLEEP) |
1202 | + { |
1203 | + } |
1204 | + else |
1205 | + { |
1206 | + debug(splat) |
1207 | + { |
1208 | + printf(" {RESUMING:_ththreadproc}\n"); |
1209 | + } |
1210 | + |
1211 | + _ththread.resume(); |
1212 | + } |
1213 | + } |
1214 | + else |
1215 | + { |
1216 | + //printf("GETHOST:_thaddto\n"); |
1217 | + _thaddto._tnext = gh; |
1218 | + _thaddto = gh; |
1219 | + } |
1220 | + } |
1221 | + } |
1222 | +} |
1223 | + |
1224 | + |
1225 | +private void _dothreadproc() |
1226 | +{ |
1227 | + GetHost gh; |
1228 | + spdInternetHost ih; |
1229 | + for(;;) |
1230 | + { |
1231 | + //synchronized(_ththread) |
1232 | + volatile |
1233 | + { |
1234 | + gh = _thnext; |
1235 | + } |
1236 | + |
1237 | + if(!gh) |
1238 | + { |
1239 | + version(THSLEEP) |
1240 | + { |
1241 | + _tthsleep(); |
1242 | + } |
1243 | + else |
1244 | + { |
1245 | + debug(splat) |
1246 | + { |
1247 | + printf(" {PAUSE:_ththreadproc}\n"); |
1248 | + } |
1249 | + |
1250 | + _ththread.pause(); |
1251 | + |
1252 | + debug(splat) |
1253 | + { |
1254 | + printf(" {RESUMED:_ththreadproc}\n"); |
1255 | + } |
1256 | + } |
1257 | + continue; |
1258 | + } |
1259 | + |
1260 | + if(gh._tcallback) // If not cancel().. |
1261 | + { |
1262 | + try |
1263 | + { |
1264 | + ih = new spdInternetHost; |
1265 | + if(gh._tbyname) |
1266 | + { |
1267 | + if(ih.getHostByName(gh._tname)) |
1268 | + gh._tinetHost = ih; |
1269 | + } |
1270 | + else // byaddr |
1271 | + { |
1272 | + if(ih.getHostByAddr(gh._taddr)) |
1273 | + gh._tinetHost = ih; |
1274 | + } |
1275 | + |
1276 | + debug(splat) |
1277 | + { |
1278 | + printf(" {GOTHOST:%p} %s\n", cast(void*)gh, gh._tinetHost ? "true".ptr : "false".ptr); |
1279 | + } |
1280 | + } |
1281 | + catch |
1282 | + { |
1283 | + } |
1284 | + } |
1285 | + |
1286 | + _thpn(gh); |
1287 | + } |
1288 | +} |
1289 | + |
1290 | + |
1291 | +version(Tango) |
1292 | +{ |
1293 | + /+ |
1294 | + private _ththreadproc() |
1295 | + { |
1296 | + _dothreadproc(); |
1297 | + } |
1298 | + +/ |
1299 | + alias _dothreadproc _ththreadproc; |
1300 | +} |
1301 | +else |
1302 | +{ |
1303 | + private int _ththreadproc(void* foo) |
1304 | + { |
1305 | + _dothreadproc(); |
1306 | + return 0; |
1307 | + } |
1308 | +} |
1309 | + |
1310 | + |
1311 | +// GDC 0.19 segfaults if this isn't in a function; might have to do with synchronized() in a loop. |
1312 | +private void _thpn(GetHost gh) |
1313 | +{ |
1314 | + synchronized(_ththread) |
1315 | + { |
1316 | + assert(gh is _thnext); |
1317 | + |
1318 | + debug(splat) |
1319 | + { |
1320 | + printf(" {DONEHOST:%p}\n", cast(void*)gh); |
1321 | + } |
1322 | + |
1323 | + _thnext = _thnext._tnext; |
1324 | + if(!_thnext) |
1325 | + _thaddto = null; |
1326 | + |
1327 | + gh._tnext = null; |
1328 | + if(_thfinlast) |
1329 | + _thfinlast._tnext = gh; |
1330 | + else |
1331 | + _thfinnext = gh; |
1332 | + _thfinlast = gh; |
1333 | + } |
1334 | +} |
1335 | + |
1336 | + |
1337 | +private GetHost _tnextDoneHost() |
1338 | +{ |
1339 | + GetHost gh; |
1340 | + |
1341 | + volatile gh = _thfinnext; |
1342 | + if(!gh) |
1343 | + return null; |
1344 | + |
1345 | + synchronized(_ththread) |
1346 | + { |
1347 | + gh = _thfinnext; |
1348 | + if(gh) |
1349 | + { |
1350 | + _thfinnext = _thfinnext._tnext; |
1351 | + if(!_thfinnext) |
1352 | + _thfinlast = null; |
1353 | + gh._tnext = null; |
1354 | + } |
1355 | + } |
1356 | + |
1357 | + return gh; |
1358 | +} |
1359 | + |
1360 | + |
1361 | +private bool _areHosts() |
1362 | +{ |
1363 | + return _thnext || _thfinnext; |
1364 | +} |
1365 | + |
1366 | + |
1367 | +/// Buffering socket I/O. |
1368 | +class SocketQueue |
1369 | +{ |
1370 | + /// |
1371 | + this(Socket sock) |
1372 | + in |
1373 | + { |
1374 | + assert(sock !is null); |
1375 | + } |
1376 | + body |
1377 | + { |
1378 | + this.sock = sock; |
1379 | + } |
1380 | + |
1381 | + |
1382 | + /// Property: get the socket of this queue. |
1383 | + final Socket socket() // getter |
1384 | + { |
1385 | + return sock; |
1386 | + } |
1387 | + |
1388 | + |
1389 | + /// Resets the buffers. |
1390 | + void reset() |
1391 | + { |
1392 | + writebuf = null; |
1393 | + readbuf = null; |
1394 | + } |
1395 | + |
1396 | + |
1397 | + /+ |
1398 | + // DMD 0.92 says error: function toString overrides but is not covariant with toString |
1399 | + override char[] toString() |
1400 | + { |
1401 | + return cast(char[])peek(); |
1402 | + } |
1403 | + +/ |
1404 | + |
1405 | + |
1406 | + /// Peek at some or all of the received data but leave it in the queue. May return less than requested. |
1407 | + void[] peek() |
1408 | + { |
1409 | + return readbuf[0 .. rpos]; |
1410 | + } |
1411 | + |
1412 | + /// ditto |
1413 | + void[] peek(uint len) |
1414 | + { |
1415 | + if(len >= rpos) |
1416 | + return peek(); |
1417 | + |
1418 | + return readbuf[0 .. len]; |
1419 | + } |
1420 | + |
1421 | + |
1422 | + /// Returns: some or all of the received data and removes this amount from the queue. May return less than requested. |
1423 | + void[] receive() |
1424 | + { |
1425 | + ubyte[] result; |
1426 | + |
1427 | + result = readbuf[0 .. rpos]; |
1428 | + readbuf = null; |
1429 | + rpos = 0; |
1430 | + |
1431 | + return result; |
1432 | + } |
1433 | + |
1434 | + /// ditto |
1435 | + void[] receive(uint len) |
1436 | + { |
1437 | + if(len >= rpos) |
1438 | + return receive(); |
1439 | + |
1440 | + ubyte[] result; |
1441 | + |
1442 | + result = readbuf[0 .. len]; |
1443 | + readbuf = readbuf[len .. readbuf.length]; |
1444 | + rpos -= len; |
1445 | + |
1446 | + return result; |
1447 | + } |
1448 | + |
1449 | + |
1450 | + /// Add data to the queue and send it over this socket. |
1451 | + void send(void[] buf) |
1452 | + { |
1453 | + if(canwrite) |
1454 | + { |
1455 | + assert(!writebuf.length); |
1456 | + |
1457 | + int st; |
1458 | + if(buf.length > 4096) |
1459 | + st = 4096; |
1460 | + else |
1461 | + st = buf.length; |
1462 | + |
1463 | + st = sock.send(buf[0 .. st]); |
1464 | + if(st > 0) |
1465 | + { |
1466 | + if(buf.length - st) |
1467 | + { |
1468 | + // dup so it can be appended to. |
1469 | + writebuf = (cast(ubyte[])buf)[st .. buf.length].dup; |
1470 | + } |
1471 | + } |
1472 | + else |
1473 | + { |
1474 | + // dup so it can be appended to. |
1475 | + writebuf = (cast(ubyte[])buf).dup; |
1476 | + } |
1477 | + |
1478 | + //canwrite = false; |
1479 | + } |
1480 | + else |
1481 | + { |
1482 | + writebuf ~= cast(ubyte[])buf; |
1483 | + } |
1484 | + } |
1485 | + |
1486 | + |
1487 | + /// Property: get the number of bytes in send buffer. |
1488 | + uint sendBytes() |
1489 | + { |
1490 | + return writebuf.length; |
1491 | + } |
1492 | + |
1493 | + |
1494 | + /// Property: get the number of bytes in recv buffer. |
1495 | + uint receiveBytes() |
1496 | + { |
1497 | + return rpos; |
1498 | + } |
1499 | + |
1500 | + |
1501 | + /// Call on a read event so that incoming data may be buffered. |
1502 | + void readEvent() |
1503 | + { |
1504 | + if(readbuf.length - rpos < 1024) |
1505 | + readbuf.length = readbuf.length + 2048; |
1506 | + |
1507 | + int rd = sock.receive(readbuf[rpos .. readbuf.length]); |
1508 | + if(rd > 0) |
1509 | + rpos += cast(uint)rd; |
1510 | + } |
1511 | + |
1512 | + |
1513 | + /// Call on a write event so that buffered outgoing data may be sent. |
1514 | + void writeEvent() |
1515 | + { |
1516 | + if(writebuf.length) |
1517 | + { |
1518 | + ubyte[] buf; |
1519 | + |
1520 | + if(writebuf.length > 4096) |
1521 | + buf = writebuf[0 .. 4096]; |
1522 | + else |
1523 | + buf = writebuf; |
1524 | + |
1525 | + int st = sock.send(buf); |
1526 | + if(st > 0) |
1527 | + writebuf = writebuf[st .. writebuf.length]; |
1528 | + } |
1529 | + else |
1530 | + { |
1531 | + //canwrite = true; |
1532 | + } |
1533 | + } |
1534 | + |
1535 | + |
1536 | + /** |
1537 | + Shortcut function for AsyncSocket. |
1538 | + Automatically calls readEvent and writeEvent as needed. |
1539 | + Same signature as RegisterEventCallback for simplicity. |
1540 | + **/ |
1541 | + void event(Socket _sock, EventType type, int err) |
1542 | + in |
1543 | + { |
1544 | + assert(_sock is sock); |
1545 | + } |
1546 | + body |
1547 | + { |
1548 | + switch(type) |
1549 | + { |
1550 | + case EventType.READ: |
1551 | + readEvent(); |
1552 | + break; |
1553 | + |
1554 | + case EventType.WRITE: |
1555 | + writeEvent(); |
1556 | + break; |
1557 | + |
1558 | + default: ; |
1559 | + } |
1560 | + } |
1561 | + |
1562 | + |
1563 | + deprecated |
1564 | + { |
1565 | + alias receiveBytes recvBytes; |
1566 | + alias receive recv; |
1567 | + } |
1568 | + |
1569 | + |
1570 | + private: |
1571 | + ubyte[] writebuf; |
1572 | + ubyte[] readbuf; |
1573 | + uint rpos; |
1574 | + Socket sock; |
1575 | + //bool canwrite = false; |
1576 | + |
1577 | + |
1578 | + bool canwrite() // getter |
1579 | + { |
1580 | + return writebuf.length == 0; |
1581 | + } |
1582 | +} |
1583 | + |
1584 | + |
1585 | +/// Returns the number of asynchronous sockets waiting for events. |
1586 | +size_t getNumberOfAsyncSockets() |
1587 | +{ |
1588 | + return _tallEvents.length; |
1589 | +} |
1590 | + |
1591 | + |
1592 | +/// Returns the number of active timers. |
1593 | +size_t getNumberOfTimers() |
1594 | +{ |
1595 | + return _tcount; |
1596 | +} |
1597 | + |
1598 | + |
1599 | +private: |
1600 | + |
1601 | +Timer _tfirst, _tlast; |
1602 | +size_t _tcount = 0; |
1603 | + |
1604 | + |
1605 | +Timer _tnext() |
1606 | +{ |
1607 | + //spdTime lowest = spdTime.max; // Wrong in Tango 0.99.2. |
1608 | + spdTime lowest = cast(spdTime)((spdTime.init + 0).max); // + 1 converts to the underlying arithmetic type to get the real max. |
1609 | + Timer t, tlowest; |
1610 | + for(t = _tfirst; t; t = t._tnext) |
1611 | + { |
1612 | + if(t._talarm < lowest) |
1613 | + { |
1614 | + tlowest = t; |
1615 | + lowest = t._talarm; |
1616 | + } |
1617 | + } |
1618 | + return tlowest; |
1619 | +} |
1620 | + |
1621 | + |
1622 | +void _tadd(Timer t) |
1623 | +in |
1624 | +{ |
1625 | + assert(t !is null); |
1626 | + assert(t._ttimeout); |
1627 | + assert(t._tprev is null); |
1628 | + assert(t._tnext is null); |
1629 | + assert(t._talarm == t._TALARM_INIT); |
1630 | +} |
1631 | +body |
1632 | +{ |
1633 | + t._talarm = cast(spdTime)(spdGetCurrentUtcTime() + t._ttimeout); |
1634 | + |
1635 | + t._tprev = _tlast; |
1636 | + _tlast = t; |
1637 | + if(!_tfirst) |
1638 | + _tfirst = t; |
1639 | + else |
1640 | + t._tprev._tnext = t; |
1641 | + |
1642 | + _tcount++; |
1643 | +} |
1644 | + |
1645 | + |
1646 | +void _tremove(Timer t) |
1647 | +in |
1648 | +{ |
1649 | + assert(t !is null); |
1650 | + assert(t._talarm != t._TALARM_INIT); |
1651 | +} |
1652 | +body |
1653 | +{ |
1654 | + t._talarm = t._TALARM_INIT; |
1655 | + |
1656 | + if(t._tprev) |
1657 | + t._tprev._tnext = t._tnext; |
1658 | + else |
1659 | + _tfirst = t._tnext; |
1660 | + |
1661 | + if(t._tnext) |
1662 | + t._tnext._tprev = t._tprev; |
1663 | + else |
1664 | + _tlast = t._tprev; |
1665 | + |
1666 | + t._tprev = null; |
1667 | + t._tnext = null; |
1668 | + |
1669 | + if(_tcount) |
1670 | + _tcount--; |
1671 | +} |
1672 | + |
1673 | + |
1674 | +template _tTicks() |
1675 | +{ |
1676 | + static if(spdTICKS_PER_SECOND == 1_000) |
1677 | + { |
1678 | + uint _tticksToSecs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND); } |
1679 | + uint _tticksToMs(spdTime ticks) { return cast(uint)ticks; } |
1680 | + //uint _tticksToNs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND * 1_000_000_000); } |
1681 | + //uint _tticksToNs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000_000); } |
1682 | + //uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND * 1_000_000); } |
1683 | + uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000); } |
1684 | + spdTime _tsecsToTicks(uint secs) { return cast(spdTime)(secs * spdTICKS_PER_SECOND); } |
1685 | + spdTime _tmsToTicks(uint ms) { return cast(spdTime)ms; } |
1686 | + } |
1687 | + else |
1688 | + { |
1689 | + uint _tticksToSecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND); } |
1690 | + uint _tticksToMs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000); } |
1691 | + //uint _tticksToNs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000_000); } |
1692 | + uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000); } |
1693 | + spdTime _tsecsToTicks(uint secs) { return cast(spdTime)(cast(double)secs * cast(double)spdTICKS_PER_SECOND); } |
1694 | + spdTime _tmsToTicks(uint ms) { return cast(spdTime)(cast(double)spdTICKS_PER_SECOND / cast(double)1_000 * cast(double)ms); } |
1695 | + } |
1696 | +} |
1697 | + |
1698 | +alias _tTicks!()._tticksToSecs _tticksToSecs; |
1699 | +alias _tTicks!()._tticksToMs _tticksToMs; |
1700 | +//alias _tTicks!()._tticksToNs _tticksToNs; |
1701 | +alias _tTicks!()._tticksToMicrosecs _tticksToMicrosecs; |
1702 | +alias _tTicks!()._tsecsToTicks _tsecsToTicks; |
1703 | +alias _tTicks!()._tmsToTicks _tmsToTicks; |
1704 | + |
1705 | + |
1706 | +unittest |
1707 | +{ |
1708 | + assert(_tsecsToTicks(_tticksToSecs(543253)) == _tsecsToTicks(_tticksToSecs(543253))); |
1709 | + assert(_tmsToTicks(_tticksToMs(3445723)) == _tmsToTicks(_tticksToMs(3445723))); |
1710 | +} |
1711 | + |
1712 | + |
1713 | +void _tticksToTimeval(spdTime ticks, spdMyTimeval* tv) |
1714 | +{ |
1715 | + tv.seconds = _tticksToSecs(ticks); |
1716 | + ticks -= _tsecsToTicks(tv.seconds); |
1717 | + tv.microseconds = _tticksToMicrosecs(ticks); |
1718 | +} |
1719 | + |
1720 | + |
1721 | +//_tEventInfo[socket_t] _tallEvents; |
1722 | +AsyncSocket[socket_t] _tallEvents; |
1723 | + |
1724 | +Thread _ththread; |
1725 | +GetHost _thnext, _thaddto; |
1726 | +GetHost _thfinnext, _thfinlast; |
1727 | + |
1728 | +bool _texit = false; |
1729 | + |
1730 | + |
1731 | +/+ |
1732 | +// Test. |
1733 | +void main() |
1734 | +{ |
1735 | + new class Timer { this() { interval = 1000; start(); } override void onAlarm() { printf(" * ALARM * \n"); } }; |
1736 | + new class Timer { this() { interval = 5000; start(); } override void onAlarm() { printf(" &die 5 spawn 2 & \n"); stop(); |
1737 | + new class Timer { this() { interval = 2000; start(); } override void onAlarm() { printf(" x spawn x \n"); } }; |
1738 | + } }; |
1739 | + new class Timer { this() { interval = 3000; start(); } override void onAlarm() { printf(" &die 3& \n"); stop(); } }; |
1740 | + new class Timer { this() { interval = 2500; start(); } override void onAlarm() |
1741 | + { |
1742 | + stop(); |
1743 | + asyncGetHostByName("www.google.com", (spdInternetHost ih, int err) { if(!err) { printf(" gGot host %.*s\n", ih.name); } }); |
1744 | + } |
1745 | + }; |
1746 | + new class Timer { this() { interval = 500; start(); } override void onAlarm() |
1747 | + { |
1748 | + printf(" (slower and slower %lu \n", interval); |
1749 | + interval = interval + 500; |
1750 | + } |
1751 | + }; |
1752 | + |
1753 | + asyncGetHostByName("www.yahoo.com", (spdInternetHost ih, int err) { if(!err) { printf(" yGot host %.*s\n", ih.name); } }); |
1754 | + asyncGetHostByName("www.ask.com", (spdInternetHost ih, int err) { if(!err) { printf(" aGot host %.*s\n", ih.name); } }); |
1755 | + |
1756 | + run(); |
1757 | +} |
1758 | ++/ |
1759 | + |
1760 | |
1761 | === added file 'D_lang/testing/candidate_libs/splat.html' |
1762 | --- D_lang/testing/candidate_libs/splat.html 1970-01-01 00:00:00 +0000 |
1763 | +++ D_lang/testing/candidate_libs/splat.html 2013-02-21 03:06:20 +0000 |
1764 | @@ -0,0 +1,269 @@ |
1765 | +<html><head> |
1766 | + <META http-equiv="content-type" content="text/html; charset=utf-8"> |
1767 | + <title>splat</title> |
1768 | + </head><body> |
1769 | + <h1>splat</h1> |
1770 | + <!-- Generated by Ddoc from splat.d --> |
1771 | +<b></b> Splat: the socket platform with the lame name. It's full of puns, but it runs! |
1772 | + <a href="http://www.dprogramming.com/splat.php">Download Splat</a>. |
1773 | + Version 0.7. |
1774 | + For both Phobos and Tango; tested with Phobos and Tango 0.99.2. |
1775 | +<br><br> |
1776 | + |
1777 | +<dl><dt><big>void <u>run</u>(); |
1778 | +</big></dt> |
1779 | +<dd>Run the event loop; wait for timer and socket events. |
1780 | + Exceptions that occur in event callbacks break out of <u>run</u>. |
1781 | +<br><br> |
1782 | + |
1783 | +</dd> |
1784 | +<dt><big>void <u>exitLoop</u>(); |
1785 | +</big></dt> |
1786 | +<dd>Causes run() to return as soon as it can. |
1787 | +<br><br> |
1788 | + |
1789 | +</dd> |
1790 | +<dt><big>class <u>Timer</u>; |
1791 | +</big></dt> |
1792 | +<dd>Timers; alarms (timeout events) depend on run(). |
1793 | +<br><br> |
1794 | + |
1795 | +<dl><dt><big>final void <u>interval</u>(uint <i>iv</i>); |
1796 | +<br>final uint <u>interval</u>(); |
1797 | +</big></dt> |
1798 | +<dd><b>Property:</b><br> |
1799 | +get and set the timer interval in milliseconds. |
1800 | +<br><br> |
1801 | + |
1802 | +</dd> |
1803 | +<dt><big>final void <u>start</u>(); |
1804 | +</big></dt> |
1805 | +<dd>Start this timer. |
1806 | +<br><br> |
1807 | + |
1808 | +</dd> |
1809 | +<dt><big>final void <u>stop</u>(); |
1810 | +</big></dt> |
1811 | +<dd>Stop this timer. |
1812 | +<br><br> |
1813 | + |
1814 | +</dd> |
1815 | +<dt><big>void <u>onAlarm</u>(); |
1816 | +</big></dt> |
1817 | +<dd>Override to be notified when the time expires. Alarms continue until stop(). |
1818 | +<br><br> |
1819 | + |
1820 | +</dd> |
1821 | +<dt><big>this(); |
1822 | +<br>this(void delegate(Timer) <i>dg</i>); |
1823 | +</big></dt> |
1824 | +<dd>Construct a timer; can take a delegate that is called back automatically on an alarm. |
1825 | +<br><br> |
1826 | + |
1827 | +</dd> |
1828 | +</dl> |
1829 | +</dd> |
1830 | +<dt><big>enum <u>EventType</u>; |
1831 | +</big></dt> |
1832 | +<dd>Socket event flags. |
1833 | +<br><br> |
1834 | + |
1835 | +<dl><dt><big><u>NONE</u></big></dt> |
1836 | +<dd><br><br> |
1837 | +</dd> |
1838 | +<dt><big><u>READ</u><br><u>WRITE</u><br><u>ACCEPT</u><br><u>CONNECT</u><br><u>CLOSE</u></big></dt> |
1839 | +<dd><br><br> |
1840 | +</dd> |
1841 | +</dl> |
1842 | +</dd> |
1843 | +<dt><big>alias <u>RegisterEventCallback</u>; |
1844 | +</big></dt> |
1845 | +<dd>Callback type for socket events. |
1846 | +<br><br> |
1847 | +<b>Params:</b><br> |
1848 | +<table><tr><td>sock</td> |
1849 | +<td>the socket</td></tr> |
1850 | +<tr><td>type</td> |
1851 | +<td>which event; will be only one of the event flags.</td></tr> |
1852 | +<tr><td>err</td> |
1853 | +<td>an error code, or 0 if successful.</td></tr> |
1854 | +</table><br> |
1855 | + |
1856 | +</dd> |
1857 | +<dt><big>class <u>AsyncSocket</u>: std.socket.Socket; |
1858 | +</big></dt> |
1859 | +<dd>Asynchronous sockets; socket events depend on run(). Mostly the same as std.socket.Socket. |
1860 | +<br><br> |
1861 | + |
1862 | +<dl><dt><big>void <u>event</u>(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>callback</i>); |
1863 | +</big></dt> |
1864 | +<dd>Registers a <i>callback</i> for specified socket <i>events</i>. |
1865 | + One or more type flags may be used, or NONE to cancel all. |
1866 | + Calling this twice on the same socket cancels out previously registered <i>events</i> for the socket. |
1867 | + |
1868 | +<br><br> |
1869 | + |
1870 | +</dd> |
1871 | +</dl> |
1872 | +</dd> |
1873 | +<dt><big>class <u>AsyncTcpSocket</u>: splat.AsyncSocket; |
1874 | +</big></dt> |
1875 | +<dd>Asynchronous TCP socket shortcut. |
1876 | +<br><br> |
1877 | + |
1878 | +<dl><dt><big>this(AddressFamily <i>family</i>); |
1879 | +<br>this(); |
1880 | +<br>this(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>); |
1881 | +<br>this(Address <i>connectTo</i>, EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>); |
1882 | +</big></dt> |
1883 | +<dd><br><br> |
1884 | +</dd> |
1885 | +</dl> |
1886 | +</dd> |
1887 | +<dt><big>class <u>AsyncUdpSocket</u>: splat.AsyncSocket; |
1888 | +</big></dt> |
1889 | +<dd>Asynchronous UDP socket shortcut. |
1890 | +<br><br> |
1891 | + |
1892 | +<dl><dt><big>this(AddressFamily <i>family</i>); |
1893 | +<br>this(); |
1894 | +<br>this(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>); |
1895 | +</big></dt> |
1896 | +<dd><br><br> |
1897 | +</dd> |
1898 | +</dl> |
1899 | +</dd> |
1900 | +<dt><big>alias <u>GetHostCallback</u>; |
1901 | +</big></dt> |
1902 | +<dd>Callback type for host resolve event. |
1903 | +<br><br> |
1904 | +<b>Params:</b><br> |
1905 | +<table><tr><td>inetHost</td> |
1906 | +<td>the InternetHost/NetHost of the resolved host, or <b>null</b>.</td></tr> |
1907 | +<tr><td>err</td> |
1908 | +<td>an error code, or 0 if successful; if 0, inetHost will be <b>null</b>.</td></tr> |
1909 | +</table><br> |
1910 | + |
1911 | +</dd> |
1912 | +<dt><big>class <u>GetHost</u>; |
1913 | +</big></dt> |
1914 | +<dd>Returned from asyncGetHost functions. |
1915 | +<br><br> |
1916 | + |
1917 | +<dl><dt><big>void <u>cancel</u>(); |
1918 | +</big></dt> |
1919 | +<dd>Cancel the get-host operation. |
1920 | +<br><br> |
1921 | + |
1922 | +</dd> |
1923 | +</dl> |
1924 | +</dd> |
1925 | +<dt><big>GetHost <u>asyncGetHostByName</u>(char[] <i>name</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>); |
1926 | +</big></dt> |
1927 | +<dd>Asynchronously resolve host information from a hostname; the <i>callback</i> depends on run(). |
1928 | +<br><br> |
1929 | + |
1930 | +</dd> |
1931 | +<dt><big>GetHost <u>asyncGetHostByAddr</u>(uint <i>addr</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>); |
1932 | +<br>GetHost <u>asyncGetHostByAddr</u>(char[] <i>addr</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>); |
1933 | +</big></dt> |
1934 | +<dd>Asynchronously resolve host information from an IPv4 address; the <i>callback</i> depends on run(). |
1935 | +<br><br> |
1936 | + |
1937 | +</dd> |
1938 | +<dt><big>class <u>SocketQueue</u>; |
1939 | +</big></dt> |
1940 | +<dd>Buffering socket I/O. |
1941 | +<br><br> |
1942 | + |
1943 | +<dl><dt><big>this(Socket <i>sock</i>); |
1944 | +</big></dt> |
1945 | +<dd><br><br> |
1946 | +</dd> |
1947 | +<dt><big>final Socket <u>socket</u>(); |
1948 | +</big></dt> |
1949 | +<dd><b>Property:</b><br> |
1950 | +get the <u>socket</u> of this queue. |
1951 | +<br><br> |
1952 | + |
1953 | +</dd> |
1954 | +<dt><big>void <u>reset</u>(); |
1955 | +</big></dt> |
1956 | +<dd>Resets the buffers. |
1957 | +<br><br> |
1958 | + |
1959 | +</dd> |
1960 | +<dt><big>void[] <u>peek</u>(); |
1961 | +<br>void[] <u>peek</u>(uint <i>len</i>); |
1962 | +</big></dt> |
1963 | +<dd>Peek at some or all of the received data but leave it in the queue. May return less than requested. |
1964 | +<br><br> |
1965 | + |
1966 | +</dd> |
1967 | +<dt><big>void[] <u>receive</u>(); |
1968 | +<br>void[] <u>receive</u>(uint <i>len</i>); |
1969 | +</big></dt> |
1970 | +<dd><b>Returns:</b><br> |
1971 | +some or all of the received data and removes this amount from the queue. May return less than requested. |
1972 | +<br><br> |
1973 | + |
1974 | +</dd> |
1975 | +<dt><big>void <u>send</u>(void[] <i>buf</i>); |
1976 | +</big></dt> |
1977 | +<dd>Add data to the queue and <u>send</u> it over this socket. |
1978 | +<br><br> |
1979 | + |
1980 | +</dd> |
1981 | +<dt><big>uint <u>sendBytes</u>(); |
1982 | +</big></dt> |
1983 | +<dd><b>Property:</b><br> |
1984 | +get the number of bytes in send buffer. |
1985 | +<br><br> |
1986 | + |
1987 | +</dd> |
1988 | +<dt><big>uint <u>receiveBytes</u>(); |
1989 | +</big></dt> |
1990 | +<dd><b>Property:</b><br> |
1991 | +get the number of bytes in recv buffer. |
1992 | +<br><br> |
1993 | + |
1994 | +</dd> |
1995 | +<dt><big>void <u>readEvent</u>(); |
1996 | +</big></dt> |
1997 | +<dd>Call on a read event so that incoming data may be buffered. |
1998 | +<br><br> |
1999 | + |
2000 | +</dd> |
2001 | +<dt><big>void <u>writeEvent</u>(); |
2002 | +</big></dt> |
2003 | +<dd>Call on a write event so that buffered outgoing data may be sent. |
2004 | +<br><br> |
2005 | + |
2006 | +</dd> |
2007 | +<dt><big>void <u>event</u>(Socket <i>_sock</i>, EventType <i>type</i>, int <i>err</i>); |
2008 | +</big></dt> |
2009 | +<dd>Shortcut function for AsyncSocket. |
2010 | + Automatically calls readEvent and writeEvent as needed. |
2011 | + Same signature as RegisterEventCallback for simplicity. |
2012 | + |
2013 | +<br><br> |
2014 | + |
2015 | +</dd> |
2016 | +</dl> |
2017 | +</dd> |
2018 | +<dt><big>uint <u>getNumberOfAsyncSockets</u>(); |
2019 | +</big></dt> |
2020 | +<dd>Returns the number of asynchronous sockets waiting for events. |
2021 | +<br><br> |
2022 | + |
2023 | +</dd> |
2024 | +<dt><big>uint <u>getNumberOfTimers</u>(); |
2025 | +</big></dt> |
2026 | +<dd>Returns the number of active timers. |
2027 | +<br><br> |
2028 | + |
2029 | +</dd> |
2030 | +</dl> |
2031 | + |
2032 | + <hr><small>Page generated by <a href="http://www.digitalmars.com/d/ddoc.html">Ddoc</a>. </small> |
2033 | + </body></html> |
2034 | |
2035 | === added file 'D_lang/testing/candidate_libs/splat07.zip' |
2036 | Binary files D_lang/testing/candidate_libs/splat07.zip 1970-01-01 00:00:00 +0000 and D_lang/testing/candidate_libs/splat07.zip 2013-02-21 03:06:20 +0000 differ |
2037 | === added directory 'D_lang/testing/str_socket' |
2038 | === added file 'D_lang/testing/str_socket/Makefile' |
2039 | --- D_lang/testing/str_socket/Makefile 1970-01-01 00:00:00 +0000 |
2040 | +++ D_lang/testing/str_socket/Makefile 2013-02-21 03:06:20 +0000 |
2041 | @@ -0,0 +1,30 @@ |
2042 | +#*********************************************** |
2043 | +# This file is part of the NRTB project (https://launchpad.net/nrtb). |
2044 | +# |
2045 | +# NRTB is free software: you can redistribute it and/or modify |
2046 | +# it under the terms of the GNU General Public License as published by |
2047 | +# the Free Software Foundation, either version 3 of the License, or |
2048 | +# (at your option) any later version. |
2049 | +# |
2050 | +# NRTB is distributed in the hope that it will be useful, |
2051 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2052 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2053 | +# GNU General Public License for more details. |
2054 | +# |
2055 | +# You should have received a copy of the GNU General Public License |
2056 | +# along with NRTB. If not, see <http://www.gnu.org/licenses/>. |
2057 | +# |
2058 | +#*********************************************** |
2059 | + |
2060 | +lib: socket_test |
2061 | + @./socket_test |
2062 | + @echo build complete |
2063 | + |
2064 | +socket_test: socket_test.d Makefile |
2065 | + @rm -f socket_test |
2066 | + @dmd socket_test.d |
2067 | + |
2068 | +clean: |
2069 | + @rm -vf *.o socket_test |
2070 | + @echo all objects and executables have been erased. |
2071 | + |
2072 | |
2073 | === added file 'D_lang/testing/str_socket/SocketStringTransciever.mm' |
2074 | --- D_lang/testing/str_socket/SocketStringTransciever.mm 1970-01-01 00:00:00 +0000 |
2075 | +++ D_lang/testing/str_socket/SocketStringTransciever.mm 2013-02-21 03:06:20 +0000 |
2076 | @@ -0,0 +1,49 @@ |
2077 | +<map version="0.9.0"> |
2078 | +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> |
2079 | +<node CREATED="1353288395487" ID="ID_1403329192" MODIFIED="1353512093507" TEXT="Socket string transciever."> |
2080 | +<node CREATED="1353288596251" ID="ID_1636926895" MODIFIED="1353512095611" POSITION="right" TEXT="Connect(address)"> |
2081 | +<node CREATED="1353289092215" ID="ID_1097805018" MODIFIED="1353289099292" TEXT="Resolves address"/> |
2082 | +<node CREATED="1353289100126" ID="ID_912894431" MODIFIED="1353289144348" TEXT="Connects to address"/> |
2083 | +<node CREATED="1353289145245" ID="ID_1737995458" MODIFIED="1353289159019" TEXT="Starts reciever thread"/> |
2084 | +<node CREATED="1353290958729" ID="ID_1494063472" MODIFIED="1353291040119" TEXT="Expects the callbacks to set at call time"/> |
2085 | +<node CREATED="1353289166189" ID="ID_244950625" MODIFIED="1353289174227" TEXT="throws on any error"/> |
2086 | +</node> |
2087 | +<node CREATED="1353288616481" ID="ID_845783483" MODIFIED="1353512095614" POSITION="right" TEXT="close()"> |
2088 | +<node CREATED="1353289189501" ID="ID_142698792" MODIFIED="1353289197939" TEXT="Shutdown reciever thread"/> |
2089 | +<node CREATED="1353289198757" ID="ID_771780490" MODIFIED="1353289263410" TEXT="close socket"/> |
2090 | +<node CREATED="1353289271773" ID="ID_357264070" MODIFIED="1353289293595" TEXT="discard any other resources allocated"/> |
2091 | +</node> |
2092 | +<node CREATED="1353288702488" ID="ID_1885052703" MODIFIED="1353512095619" POSITION="right" TEXT="regeister_receiver(funtion(newStr))"> |
2093 | +<node CREATED="1353289372692" ID="ID_1797818997" MODIFIED="1353289421498" TEXT="Replace existing reciever callback"/> |
2094 | +<node CREATED="1353289422811" ID="ID_716021446" MODIFIED="1353289467577" TEXT="The callback has the signiture function(string)"/> |
2095 | +<node CREATED="1353289476939" ID="ID_1689880619" MODIFIED="1353290199100" TEXT="The callback will be called whenever an ASCII 10 is recieved."/> |
2096 | +<node CREATED="1353290138311" ID="ID_48990930" MODIFIED="1353290251764" TEXT="The argument "newStr" will contain any bytes recieved before the ASCII 10"/> |
2097 | +<node CREATED="1353289528395" ID="ID_1457236482" MODIFIED="1353290179636" TEXT="ASCII 10s and 13s will be discarded"/> |
2098 | +</node> |
2099 | +<node CREATED="1353288756648" ID="ID_1776338151" MODIFIED="1353288803357" POSITION="right" TEXT="register_event_hander(funciton(event))"> |
2100 | +<node CREATED="1353289687346" ID="ID_146527388" MODIFIED="1353289714640" TEXT="Replace existing event handler"/> |
2101 | +<node CREATED="1353289715586" ID="ID_1957454409" MODIFIED="1353289748151" TEXT="The callback has the signiture function(string)"/> |
2102 | +<node CREATED="1353289749753" ID="ID_1524918841" MODIFIED="1353289768918" TEXT="The callback will be called whenever an event occurs"/> |
2103 | +<node CREATED="1353289775721" ID="ID_698482207" MODIFIED="1353289785327" TEXT="Available events"> |
2104 | +<node CREATED="1353495351509" ID="ID_1988403096" MODIFIED="1353495373615" TEXT="connect"/> |
2105 | +<node CREATED="1353495374592" ID="ID_1082092706" MODIFIED="1353495385858" TEXT="overflow"/> |
2106 | +<node CREATED="1353495387001" ID="ID_1818531252" MODIFIED="1353495391356" TEXT="underflow"/> |
2107 | +<node CREATED="1353495392662" ID="ID_236107112" MODIFIED="1353495399980" TEXT="dropped"/> |
2108 | +<node CREATED="1353495400962" ID="ID_909770107" MODIFIED="1353495403143" TEXT="disconnect"/> |
2109 | +</node> |
2110 | +</node> |
2111 | +<node CREATED="1353288811903" ID="ID_1354285471" MODIFIED="1353512095621" POSITION="right" TEXT="send(string)"> |
2112 | +<node CREATED="1353289903920" ID="ID_293305230" MODIFIED="1353290032885" TEXT="Sends the argument on the socket"/> |
2113 | +<node CREATED="1353290036647" ID="ID_1916879506" MODIFIED="1353290061148" TEXT="An ASCII 10 will be postixed to the string"/> |
2114 | +<node CREATED="1353290092071" ID="ID_1214127336" MODIFIED="1353290125572" TEXT="Blocks until the send is complete."/> |
2115 | +</node> |
2116 | +<node CREATED="1353290448717" ID="ID_1736651166" MODIFIED="1353512095625" POSITION="right" TEXT="worker_thread()"> |
2117 | +<node CREATED="1353290466204" ID="ID_1117113952" MODIFIED="1353290517609" TEXT="Responible for incoming bytes"/> |
2118 | +<node CREATED="1353290741723" ID="ID_910559431" MODIFIED="1353290766920" TEXT="discards ASCII 10 and 13"/> |
2119 | +<node CREATED="1353290769963" ID="ID_1282285823" MODIFIED="1353290798568" TEXT="places all other bytes in the buffer"/> |
2120 | +<node CREATED="1353290518900" ID="ID_216777552" MODIFIED="1353291656818" TEXT="calls the receiver callback with the buffer on recept of an EOM (ASCII 10)"/> |
2121 | +<node CREATED="1353290869346" ID="ID_823816252" MODIFIED="1353290886168" TEXT="Clears the buffer when the callback returns"/> |
2122 | +<node CREATED="1353291445518" ID="ID_578045982" MODIFIED="1353291464356" TEXT="Loops infinitely until closed."/> |
2123 | +</node> |
2124 | +</node> |
2125 | +</map> |
2126 | |
2127 | === added file 'D_lang/testing/str_socket/socket_test.d' |
2128 | --- D_lang/testing/str_socket/socket_test.d 1970-01-01 00:00:00 +0000 |
2129 | +++ D_lang/testing/str_socket/socket_test.d 2013-02-21 03:06:20 +0000 |
2130 | @@ -0,0 +1,43 @@ |
2131 | +/********************* |
2132 | +Multithreaded message passing example in D |
2133 | +*********************/ |
2134 | + |
2135 | +// import the concurrency and standard IO modules |
2136 | +import std.concurrency, std.stdio; |
2137 | +import std.string, std.conv, std.stream, std.stdio; |
2138 | +import std.socket, std.socketstream; |
2139 | + |
2140 | +// main is just like main in C++ |
2141 | +void main(string[] args) |
2142 | +{ |
2143 | + writeln("D Socket Send/Receive Test."); |
2144 | + |
2145 | + if (args.length < 2) |
2146 | + { |
2147 | + writeln("Usage:"); |
2148 | + writeln(" ",args[0]," httpd_IP"); |
2149 | + return; |
2150 | + } |
2151 | + |
2152 | + string IP = args[1]; |
2153 | + ushort port = 80; |
2154 | + |
2155 | + writefln(" Connecting to host %s:%d....",IP,port); |
2156 | + |
2157 | + // connect to the server |
2158 | + Socket sock = new TcpSocket(new InternetAddress(IP, port)); |
2159 | + scope(exit) sock.close(); |
2160 | + Stream ss = new SocketStream(sock); |
2161 | + |
2162 | + ss.writeString("GET / HTTP/1.0\r\nHost: " ~ IP ~ "\r\n\r\n"); |
2163 | + |
2164 | + while (!ss.eof()) |
2165 | + { |
2166 | + auto line = ss.readLine(); |
2167 | + writeln(line); |
2168 | + } |
2169 | + |
2170 | + writeln("** main() is complete **"); |
2171 | + |
2172 | +} |
2173 | + |
2174 | |
2175 | === added directory 'D_lang/testing/thread_pool' |
2176 | === added file 'D_lang/testing/thread_pool/Makefile' |
2177 | --- D_lang/testing/thread_pool/Makefile 1970-01-01 00:00:00 +0000 |
2178 | +++ D_lang/testing/thread_pool/Makefile 2013-02-21 03:06:20 +0000 |
2179 | @@ -0,0 +1,30 @@ |
2180 | +#*********************************************** |
2181 | +# This file is part of the NRTB project (https://launchpad.net/nrtb). |
2182 | +# |
2183 | +# NRTB is free software: you can redistribute it and/or modify |
2184 | +# it under the terms of the GNU General Public License as published by |
2185 | +# the Free Software Foundation, either version 3 of the License, or |
2186 | +# (at your option) any later version. |
2187 | +# |
2188 | +# NRTB is distributed in the hope that it will be useful, |
2189 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2190 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2191 | +# GNU General Public License for more details. |
2192 | +# |
2193 | +# You should have received a copy of the GNU General Public License |
2194 | +# along with NRTB. If not, see <http://www.gnu.org/licenses/>. |
2195 | +# |
2196 | +#*********************************************** |
2197 | + |
2198 | +lib: thread_pool |
2199 | + @./thread_pool |
2200 | + @echo build complete |
2201 | + |
2202 | +thread_pool: thread_pool.d Makefile |
2203 | + @rm -f thread_pool |
2204 | + @dmd thread_pool.d |
2205 | + |
2206 | +clean: |
2207 | + @rm -vf *.o thread_pool |
2208 | + @echo all objects and executables have been erased. |
2209 | + |
2210 | |
2211 | === added file 'D_lang/testing/thread_pool/thread_pool.d' |
2212 | --- D_lang/testing/thread_pool/thread_pool.d 1970-01-01 00:00:00 +0000 |
2213 | +++ D_lang/testing/thread_pool/thread_pool.d 2013-02-21 03:06:20 +0000 |
2214 | @@ -0,0 +1,81 @@ |
2215 | +/********************* |
2216 | +Multithreaded message passing example in D |
2217 | +*********************/ |
2218 | + |
2219 | +// import the concurrency and standard IO modules |
2220 | +import std.concurrency, std.stdio, core.thread; |
2221 | + |
2222 | +struct thread_pool(wp_t, alias task) |
2223 | +{ |
2224 | + // Housekeeping variables |
2225 | + private Tid listener_tid; |
2226 | + |
2227 | + // Does nothing but start the listener. |
2228 | + public this(int queue_size) { |
2229 | + listener_tid = spawn(&listener_thread!(wp_t,task),queue_size); |
2230 | + }; |
2231 | + |
2232 | + // submit a work, packet for processing. |
2233 | + public void submit(wp_t wp) { |
2234 | + listener_tid.send(thisTid, wp); |
2235 | + }; |
2236 | + |
2237 | +} |
2238 | + |
2239 | +void worker_thread(wpt, alias task)() { |
2240 | + bool running = true; |
2241 | + while (running) { |
2242 | + receive ( |
2243 | + (Tid t, wpt d) { task(t,d); }, |
2244 | + (OwnerTerminated e) { running = false; } |
2245 | + ); |
2246 | + }; |
2247 | +} |
2248 | + |
2249 | +void listener_thread(wpt, alias task)(int queue_size) { |
2250 | + |
2251 | + Tid worker_list[]; |
2252 | + ulong next = 0; |
2253 | + |
2254 | + void submit(Tid t, wpt d) { |
2255 | + worker_list[next].send(t,d); |
2256 | + next = (++next) % worker_list.length; |
2257 | + } |
2258 | + |
2259 | + // initial setup. |
2260 | + for(int i = 0; i< queue_size; i++) { |
2261 | + worker_list ~= spawn(&worker_thread!(wpt,task)); |
2262 | + } |
2263 | + |
2264 | + // service loop |
2265 | + bool running = true; |
2266 | + while (running) { |
2267 | + receive ( |
2268 | + (Tid t, wpt d) { submit(t,d); }, |
2269 | + (OwnerTerminated e) { running = false; } |
2270 | + ); |
2271 | + }; |
2272 | +}; |
2273 | + |
2274 | +//==== code starts here |
2275 | + |
2276 | +void mytask(Tid t, int i) { |
2277 | + writeln("Task ",thisTid," processed ",i); |
2278 | + Thread.sleep(dur!("msecs") (20)); |
2279 | +}; |
2280 | + |
2281 | + |
2282 | +// main is just like main in C++ |
2283 | +void main() |
2284 | +{ |
2285 | + writeln("D Message Driven Work Queue Example."); |
2286 | + auto myqueue = thread_pool!(int,mytask)(10); |
2287 | + |
2288 | + for (auto i=0; i<100; i++) { |
2289 | + myqueue.submit(i); |
2290 | + }; |
2291 | + |
2292 | + Thread.sleep(dur!("seconds") (3)); |
2293 | + writeln("Run complete"); |
2294 | + |
2295 | +}; |
2296 | \ No newline at end of file |
2297 | |
2298 | === added file 'D_lang/testing/thread_pool/thread_pool.mm' |
2299 | --- D_lang/testing/thread_pool/thread_pool.mm 1970-01-01 00:00:00 +0000 |
2300 | +++ D_lang/testing/thread_pool/thread_pool.mm 2013-02-21 03:06:20 +0000 |
2301 | @@ -0,0 +1,47 @@ |
2302 | +<map version="0.9.0"> |
2303 | +<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net --> |
2304 | +<node CREATED="1199190455281" ID="ID_1574918623" MODIFIED="1199190480522" TEXT="thread_pool"> |
2305 | +<node CREATED="1360253779843" ID="ID_432711866" MODIFIED="1360261129036" POSITION="right" TEXT="class task_pool(t)"> |
2306 | +<node CREATED="1360267525267" ID="ID_760440288" MODIFIED="1360267533846" TEXT="this()"> |
2307 | +<node CREATED="1360268024517" ID="ID_1334050998" MODIFIED="1360328468829" TEXT="starts task_pool_manager(t)(low,high,,increment,task)"/> |
2308 | +</node> |
2309 | +<node CREATED="1360081590643" ID="ID_1324728" MODIFIED="1360081668955" TEXT="struct work_packet(t)"/> |
2310 | +<node CREATED="1360081723340" ID="ID_1492950840" MODIFIED="1360081762970" TEXT="struct limits"/> |
2311 | +<node CREATED="1360081739372" ID="ID_452972575" MODIFIED="1360081747882" TEXT="struct run_ctl"/> |
2312 | +<node CREATED="1360254280681" ID="ID_778719726" MODIFIED="1360261274927" TEXT="void submit(t data)"/> |
2313 | +<node CREATED="1360254367731" ID="ID_1043224962" MODIFIED="1360261286496" TEXT="uint set_limits(low, high, increment)"/> |
2314 | +</node> |
2315 | +<node CREATED="1360082136187" ID="ID_181135344" MODIFIED="1360328486894" POSITION="right" TEXT="task pool manager(t)(low, high, increment,task)"> |
2316 | +<node CREATED="1360254670685" ID="ID_1823995507" MODIFIED="1360254677048" TEXT="Free running thread"/> |
2317 | +<node CREATED="1360254680507" ID="ID_291925315" MODIFIED="1360255051860" TEXT="On startup"> |
2318 | +<node CREATED="1360254687714" ID="ID_415174674" MODIFIED="1360254704683" TEXT="Registers with the global pool manager"/> |
2319 | +<node CREATED="1360254714285" ID="ID_1841317578" MODIFIED="1360544160805" TEXT="starts default set of task_thread(t)(thisTid,task)"/> |
2320 | +</node> |
2321 | +<node CREATED="1360254933031" ID="ID_683968420" MODIFIED="1360255382530" TEXT="Service loop"> |
2322 | +<node CREATED="1360255079468" ID="ID_1559510237" MODIFIED="1360255176424" TEXT="rcv Tid, t"> |
2323 | +<node CREATED="1360255261482" ID="ID_29306120" MODIFIED="1360255307209" TEXT="Verify there spare thread count"/> |
2324 | +<node CREATED="1360255312567" ID="ID_662023772" MODIFIED="1360255333731" TEXT="submit Tid, t to next task thread"/> |
2325 | +</node> |
2326 | +<node CREATED="1360255179495" ID="ID_548612491" MODIFIED="1360334567427" TEXT="rcv Tid, limits"> |
2327 | +<node CREATED="1360255428431" ID="ID_1067723780" MODIFIED="1360255499958" TEXT="Reset pool parameters"/> |
2328 | +<node CREATED="1360255501795" ID="ID_943031629" MODIFIED="1360255516011" TEXT="Add/remove worker threads as needed"/> |
2329 | +</node> |
2330 | +<node CREATED="1360334567882" ID="ID_1909911450" MODIFIED="1360334583842" TEXT="rvc Tid, run_ctl"> |
2331 | +<node CREATED="1360334583845" ID="ID_882927298" MODIFIED="1360336402561" TEXT="shutdown"/> |
2332 | +</node> |
2333 | +</node> |
2334 | +</node> |
2335 | +<node CREATED="1360081583633" ID="ID_1103044446" MODIFIED="1360328522599" POSITION="right" TEXT="task_thread(t)(Tid task_pool_manager,task)"> |
2336 | +<node CREATED="1360281228443" ID="ID_1814378750" MODIFIED="1360281259435" TEXT="Free running thread"/> |
2337 | +<node CREATED="1360334423885" ID="ID_1136327708" MODIFIED="1360334431123" TEXT="On startup"/> |
2338 | +<node CREATED="1360334432374" ID="ID_516047719" MODIFIED="1360334444665" TEXT="Service Loop"> |
2339 | +<node CREATED="1360334444667" ID="ID_1239866205" MODIFIED="1360334469683" TEXT="receive tid, t"> |
2340 | +<node CREATED="1360334469685" ID="ID_1854740647" MODIFIED="1360334485839" TEXT="Call task(tid,t)"/> |
2341 | +</node> |
2342 | +<node CREATED="1360334493738" ID="ID_1132173280" MODIFIED="1360334530760" TEXT="receive tid, run_ctl"> |
2343 | +<node CREATED="1360334530762" ID="ID_1133543570" MODIFIED="1360334542293" TEXT="shutdown"/> |
2344 | +</node> |
2345 | +</node> |
2346 | +</node> |
2347 | +</node> |
2348 | +</map> |
Given the non-mainline nature of this merge (proof of principle code, vs. "working" code), I intend to merge this to the alpha stream Friday night or Saturday morning unless I receive commentary indicating I should not.