nrtb-core team mailing list archive
-
nrtb-core team
-
Mailing list archive
-
Message #00414
[Merge] lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb
Rick Stovall has proposed merging lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb.
Requested reviews:
NRTB Core (nrtb-core): code
For more details, see:
https://code.launchpad.net/~fpstovall/nrtb/D_tech_demos/+merge/149745
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.
--
https://code.launchpad.net/~fpstovall/nrtb/D_tech_demos/+merge/149745
Your team NRTB Core is requested to review the proposed merge of lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb.
=== added directory 'D_lang/testing/candidate_libs'
=== added file 'D_lang/testing/candidate_libs/splat.d'
--- D_lang/testing/candidate_libs/splat.d 1970-01-01 00:00:00 +0000
+++ D_lang/testing/candidate_libs/splat.d 2013-02-21 03:06:20 +0000
@@ -0,0 +1,1754 @@
+/*
+ Copyright (C) 2006-2007 Christopher E. Miller
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/** $(B ) Splat: the socket platform with the lame name. It's full of puns, but it runs!
+ <a href="http://www.dprogramming.com/splat.php">Download Splat</a>.
+ Version 0.7.
+ For both Phobos and Tango; tested with Phobos and Tango 0.99.2.
+**/
+module splat;
+
+
+private
+{
+ version(Windows)
+ {
+ version(Tango)
+ {
+ import tango.sys.win32.UserGdi;
+ }
+ else
+ {
+ import std.c.windows.windows;
+ }
+ }
+
+
+ version(Tango)
+ {
+ import tango.core.Type;
+
+ alias tango.core.Type.Time spdTime;
+ alias tango.core.Type.Time.TicksPerSecond spdTICKS_PER_SECOND;
+
+
+ import tango.util.time.Clock;
+
+ alias Clock.now spdGetCurrentUtcTime;
+
+
+ import tango.net.Socket;
+
+ alias tango.net.Socket.NetHost spdInternetHost;
+
+ alias tango.net.Socket.IPv4Address spdInternetAddress;
+
+ alias tango.net.Socket.timeval spdTimeval;
+
+ struct spdMyTimeval
+ {
+ int seconds;
+ int microseconds;
+ }
+
+
+ import tango.core.Thread;
+ }
+ else
+ {
+ import std.date;
+
+ alias std.date.d_time spdTime;
+ alias std.date.TicksPerSecond spdTICKS_PER_SECOND;
+ alias std.date.getUTCtime spdGetCurrentUtcTime;
+
+
+ import std.socket;
+
+ alias std.socket.InternetHost spdInternetHost;
+
+ alias std.socket.InternetAddress spdInternetAddress;
+
+ alias std.socket.timeval spdMyTimeval;
+
+ alias std.socket.timeval spdTimeval;
+
+
+ import std.thread;
+ }
+
+
+ debug(splat)
+ {
+ version(Tango)
+ import tango.stdc.stdio;
+ else
+ import std.c.stdio;
+ }
+}
+
+static assert(spdMyTimeval.sizeof == spdTimeval.sizeof);
+
+
+/**
+ Run the event loop; wait for timer and socket events.
+ Exceptions that occur in event callbacks break out of run.
+**/
+// It is NOT safe to call run() before a previous call to run() returns.
+void run()
+{
+ /+
+ static bool _running = false;
+ if(_running)
+ return; // ?
+ _running = true;
+ scope(exit)
+ _running = false;
+ +/
+
+ _texit = false;
+
+ Timer tn;
+ spdMyTimeval* ptv;
+ spdMyTimeval tv;
+ spdTime dnow;
+ SocketSet reads = new SocketSet();
+ SocketSet writes = new SocketSet();
+ int i;
+ bool dotimer = false;
+
+ for(;;)
+ {
+ tn = _tnext();
+
+ version(Windows)
+ {
+ if(!_tallEvents.length)
+ {
+ no_socket_events:
+ DWORD ms = INFINITE;
+ if(tn)
+ {
+ dnow = spdGetCurrentUtcTime();
+ if(tn._talarm <= dnow)
+ goto timedout;
+ ms = _tticksToMs(cast(spdTime)(tn._talarm - dnow));
+ }
+
+ if(INFINITE == ms)
+ {
+ if(_areHosts())
+ ms = 200;
+ }
+
+ debug(splat)
+ {
+ if(INFINITE != ms)
+ printf(" {SLEEP} %lu ms\n", cast(uint)ms);
+ //else
+ // printf(" {SLEEP} infinite\n");
+ }
+
+ Sleep(ms);
+ goto timedout;
+ }
+ }
+
+ ptv = null;
+ if(tn)
+ {
+ debug(splattimer)
+ printf("splattimer: diff = %d; dotimer = %s\n",
+ cast(int)(dnow - tn._talarm),
+ dotimer ? "true".ptr : "false".ptr);
+
+ if(tn._talarm <= dnow)
+ {
+ version(Windows)
+ {
+ assert(_tallEvents.length);
+ }
+ else
+ {
+ if(!_tallEvents.length)
+ goto timedout;
+ }
+ if(dotimer)
+ goto timedout;
+ dotimer = true; // Do timer next time around.
+ tv.seconds = 0;
+ tv.microseconds = 0;
+ }
+ else
+ {
+ dnow = spdGetCurrentUtcTime();
+ _tticksToTimeval(tn._talarm - dnow, &tv);
+ if(tv.microseconds < 0)
+ tv.microseconds = 0;
+ //if(tv.microseconds > 32767)
+ // tv.microseconds = 32767;
+ if(tv.seconds < 0)
+ tv.seconds = 0;
+ if(tv.seconds > 60)
+ tv.seconds = 60;
+
+ if(_areHosts())
+ {
+ if(tv.seconds || tv.microseconds > 200_000)
+ {
+ tv.seconds = 0;
+ tv.microseconds = 200_000;
+ }
+ }
+ }
+ ptv = &tv;
+ }
+ else
+ {
+ debug(splattimer)
+ printf("splattimer: no timers\n");
+
+ if(_areHosts())
+ {
+ tv.seconds = 0;
+ tv.microseconds = 200_000;
+ ptv = &tv;
+ }
+ }
+
+ reads.reset();
+ writes.reset();
+
+ uint numadds = 0;
+ foreach(AsyncSocket sock; _tallEvents)
+ {
+ //debug
+ debug(splat)
+ {
+ if(!sock.isAlive())
+ {
+ debug(splat)
+ {
+ printf("Splat warning: dead socket still waiting for events\n");
+ fflush(stdout);
+ }
+ //continue;
+ }
+ }
+
+ if(((sock._events & EventType.READ) && !(sock._events & EventType._CANNOT_READ))
+ || ((sock._events & EventType.ACCEPT) && !(sock._events & EventType._CANNOT_ACCEPT))
+ || ((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE)))
+ {
+ reads.add(sock);
+ numadds++;
+ }
+
+ if(((sock._events & EventType.WRITE) && !(sock._events & EventType._CANNOT_WRITE))
+ || ((sock._events & EventType.CONNECT) && !(sock._events & EventType._CANNOT_CONNECT)))
+ {
+ writes.add(sock);
+ numadds++;
+ }
+ }
+
+ if(_texit)
+ return;
+
+ version(Windows)
+ {
+ if(!numadds)
+ goto no_socket_events;
+
+ //assert(reads.count || writes.count);
+ }
+
+ debug(splat)
+ {
+ if(ptv)
+ {
+ if(0 != ptv.seconds || 0 != ptv.microseconds)
+ printf(" {SELECT} %lu secs, %lu microsecs\n", cast(uint)ptv.seconds, cast(uint)ptv.microseconds);
+ //else
+ // printf(" {SELECT} 0\n");
+ }
+ //else
+ //{
+ // printf(" {SELECT} infinite\n");
+ //}
+ }
+
+ debug(splatselect)
+ printf("Socket.select(%u sockets%s)\n", numadds,
+ ptv ? (((0 != ptv.seconds || 0 != ptv.microseconds)) ? ", timeout".ptr : ", 0 timeout") : ", infinite-wait".ptr);
+ i = Socket.select(reads, writes, null, cast(spdTimeval*)ptv);
+ switch(i)
+ {
+ case -1: // Interruption.
+ continue; // ?
+
+ case 0: // Timeout.
+ goto timedout;
+
+ default: // Socket event(s).
+ foreach(AsyncSocket sock; _tallEvents)
+ {
+ if(_texit)
+ return;
+
+ //if(!sock.isAlive())
+ // continue;
+
+ if(reads.isSet(sock))
+ {
+ if((sock._events & EventType.READ) && !(sock._events & EventType._CANNOT_READ))
+ {
+ switch(sock._peekreceiveclose())
+ {
+ case 0: // Close.
+ if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))
+ {
+ goto got_close;
+ }
+ else
+ {
+ //sock._events |= EventType._CANNOT_READ;
+ sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+ //sock._tgotEvent(EventType.READ, 0); // Should this be an error?
+ }
+ break;
+ case -1: // Error.
+ if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))
+ {
+ //sock._events |= EventType._CANNOT_READ;
+ sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+ sock._tgotEvent(EventType.CLOSE, -1); // ?
+ }
+ else
+ {
+ //sock._events |= EventType._CANNOT_READ;
+ sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+ sock._tgotEvent(EventType.READ, -1);
+ }
+ break;
+ default: // Good.
+ sock._events |= EventType._CANNOT_READ;
+ sock._tgotEvent(EventType.READ, 0);
+ }
+ }
+ else if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))
+ {
+ switch(sock._peekreceiveclose())
+ {
+ case 0: // Close.
+ got_close:
+ //sock._events |= EventType._CANNOT_CLOSE;
+ sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+ //writes.remove(sock); // ?
+ sock._tgotEvent(EventType.CLOSE, 0);
+ break;
+ case -1: // Error.
+ //sock._events |= EventType._CANNOT_CLOSE;
+ sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+ //writes.remove(sock); // ?
+ sock._tgotEvent(EventType.CLOSE, -1);
+ break;
+ default: ;
+ }
+ }
+
+ if((sock._events & EventType.ACCEPT) && !(sock._events & EventType._CANNOT_ACCEPT))
+ {
+ sock._events |= EventType._CANNOT_ACCEPT;
+ sock._tgotEvent(EventType.ACCEPT, 0);
+ }
+
+ continue; // Checking for writability (otherwise next) on a closed socket (from any above event) is problematic.
+ }
+
+ //if(_texit)
+ // return;
+
+ if(writes.isSet(sock))
+ {
+ if((sock._events & EventType.CONNECT) && !(sock._events & EventType._CANNOT_CONNECT))
+ {
+ sock._events |= EventType._CANNOT_CONNECT;
+ sock._tgotEvent(EventType.CONNECT, 0);
+ }
+
+ if((sock._events & EventType.WRITE) && !(sock._events & EventType._CANNOT_WRITE))
+ {
+ sock._events |= EventType._CANNOT_WRITE;
+ sock._tgotEvent(EventType.WRITE, 0);
+ }
+ }
+ }
+ //continue;
+ goto do_hosts;
+ }
+
+ // Check timers..
+ timedout: ;
+ dotimer = false;
+ _tdotimers();
+
+ // Check resolved hosts..
+ do_hosts:
+ GetHost gh;
+ while(null !is (gh = _tnextDoneHost()))
+ {
+ gh._tgotEvent();
+
+ if(_texit)
+ return;
+ }
+
+ if(_texit)
+ return;
+ }
+}
+
+
+/// Causes run() to return as soon as it can.
+void exitLoop()
+{
+ _texit = true;
+}
+
+
+private void _tdotimers()
+{
+ size_t nalarms;
+ Timer[4] talarms;
+ spdTime dnow;
+ Timer tn;
+ dnow = spdGetCurrentUtcTime();
+ for(tn = _tfirst; tn; tn = tn._tnext)
+ {
+ if(dnow >= tn._talarm)
+ {
+ if(nalarms < talarms.length)
+ talarms[nalarms] = tn;
+ nalarms++;
+ }
+ }
+ Timer[] nowalarm;
+ if(nalarms <= talarms.length)
+ {
+ nowalarm = talarms[0 .. nalarms];
+ }
+ else
+ {
+ nowalarm = new Timer[nalarms];
+ nalarms = 0;
+ for(tn = _tfirst; tn; tn = tn._tnext)
+ {
+ if(dnow >= tn._talarm)
+ {
+ nowalarm[nalarms] = tn;
+ nalarms++;
+ }
+ }
+ assert(nowalarm.length == nalarms);
+ }
+
+ foreach(Timer t; nowalarm)
+ {
+ if(_texit)
+ return;
+
+ if(t._talarm != t._TALARM_INIT) // Make sure not removed by some other timer event.
+ {
+ t._talarm = cast(spdTime)(dnow + t._ttimeout); // Also update alarm time BEFORE in case of exception (could cause rapid fire otherwise).
+ t._tgotAlarm();
+ if(t._talarm != t._TALARM_INIT) // Maybe removed itself.
+ {
+ // Set new alarm after this alarm due to possible delay AND possible updated timeout/interval.
+ dnow = spdGetCurrentUtcTime(); // In case time lapses in some other timer event.
+ t._talarm = cast(spdTime)(dnow + t._ttimeout);
+ }
+ }
+ }
+}
+
+
+/// Timers; alarms (timeout events) depend on run().
+class Timer
+{
+ /// Property: get and set the timer _interval in milliseconds.
+ final void interval(uint iv) // setter
+ {
+ iv = cast(uint)_tmsToTicks(iv);
+ if(!iv)
+ iv = 1;
+ if(iv != _ttimeout)
+ {
+ _ttimeout = iv;
+
+ if(_talarm != _TALARM_INIT)
+ {
+ stop();
+ start();
+ }
+ }
+ }
+
+ /// ditto
+ final uint interval() // getter
+ {
+ return _tticksToMs(cast(spdTime)_ttimeout);
+ }
+
+
+ /// Start this timer.
+ final void start()
+ {
+ if(_talarm)
+ return;
+
+ assert(_ttimeout > 0);
+
+ _tadd(this);
+
+ debug(splat)
+ {
+ printf(" {ADDTIMER:%p} %lu ms\n", cast(void*)this, interval);
+ }
+ }
+
+
+ /// Stop this timer.
+ final void stop()
+ {
+ if(_talarm)
+ {
+ _tremove(this);
+
+ debug(splat)
+ {
+ printf(" {DELTIMER:%p} %lu ms\n", cast(void*)this, interval);
+ }
+ }
+ }
+
+
+ /// Override to be notified when the time expires. Alarms continue until stop().
+ void onAlarm()
+ {
+ if(_tick)
+ _tick(this);
+ }
+
+
+ /// Construct a timer; can take a delegate that is called back automatically on an alarm.
+ this()
+ {
+ _ttimeout = cast(uint)_tmsToTicks(100);
+ }
+
+ /// ditto
+ this(void delegate(Timer) dg)
+ {
+ this();
+ this._tick = dg;
+ }
+
+
+ private:
+ const spdTime _TALARM_INIT = cast(spdTime)0;
+ spdTime _talarm = _TALARM_INIT; // Time when next event is alarmed.
+ //spdTime _ttimeout; // Ticks per timeout.
+ uint _ttimeout; // Ticks per timeout.
+ Timer _tprev, _tnext;
+ void delegate(Timer) _tick;
+
+
+ void _tgotAlarm()
+ {
+ debug(splat)
+ {
+ printf(" {TIMER:%p}\n", cast(void*)this);
+ }
+
+ onAlarm();
+ }
+}
+
+
+// Can be OR'ed.
+/// Socket event flags.
+enum EventType
+{
+ NONE = 0, ///
+
+ READ = 0x1, ///
+ WRITE = 0x2, /// ditto
+ //OOB = 0x4, /// ditto
+ ACCEPT = 0x8, /// ditto
+ CONNECT = 0x10, /// ditto
+ CLOSE = 0x20, /// ditto
+
+ _CANNOT_READ = READ << 16, // package
+ _CANNOT_WRITE = WRITE << 16, // package
+ //_CANNOT_OOB = OOB << 16, // package
+ _CANNOT_ACCEPT = ACCEPT << 16, // package
+ _CANNOT_CONNECT = CONNECT << 16, // package
+ _CANNOT_CLOSE = CLOSE << 16, // package
+}
+
+private EventType _tEventType_ALL = EventType.READ | EventType.WRITE /+ | EventType.OOB +/
+ | EventType.ACCEPT | EventType.CONNECT | EventType.CLOSE;
+private EventType _tEventType_ALLREADS = EventType.READ | EventType.ACCEPT | EventType.CLOSE;
+private EventType _tEventType_ALLWRITES = EventType.WRITE | EventType.CONNECT;
+
+
+/**
+ Callback type for socket events.
+ Params:
+ sock = the socket
+ type = which event; will be only one of the event flags.
+ err = an error code, or 0 if successful.
+**/
+alias void delegate(Socket sock, EventType type, int err) RegisterEventCallback;
+
+
+/// Asynchronous sockets; socket events depend on run(). Mostly the same as std.socket.Socket.
+class AsyncSocket: Socket
+{
+ version(Tango)
+ {
+ this(AddressFamily family, SocketType type, ProtocolType protocol, bool create = true)
+ {
+ super(family, type, protocol, create);
+ super.blocking = false;
+ }
+ }
+ else
+ {
+ this(AddressFamily af, SocketType type, ProtocolType protocol)
+ {
+ super(af, type, protocol);
+ super.blocking = false;
+ }
+
+
+ this(AddressFamily af, SocketType type)
+ {
+ super(af, type);
+ super.blocking = false;
+ }
+
+
+ this(AddressFamily af, SocketType type, char[] protocolName)
+ {
+ super(af, type, protocolName);
+ super.blocking = false;
+ }
+ }
+
+
+ /**
+ Registers a callback for specified socket events.
+ One or more type flags may be used, or NONE to cancel all.
+ Calling this twice on the same socket cancels out previously registered events for the socket.
+ **/
+ // Requires run() loop.
+ void event(EventType events, RegisterEventCallback callback)
+ {
+ this.blocking = false;
+
+ this._events = EventType.NONE;
+
+ if(!(events & (_tEventType_ALLREADS | _tEventType_ALLWRITES)))
+ return;
+
+ if(isAlive()) // Alive socket already connected or never will.
+ this._events |= EventType._CANNOT_CONNECT;
+
+ if(events & EventType.ACCEPT)
+ events &= ~(EventType.READ | EventType.CLOSE); // Issues in select() if accept and these set.
+
+ this._events = events | _tEventType_ALL;
+ this._callback = callback;
+
+ _tallEvents[this.handle] = this;
+ }
+
+
+ version(Tango)
+ {
+ alias fileHandle handle;
+ }
+
+
+ // For use with accepting().
+ protected this()
+ {
+ }
+
+
+ version(Tango)
+ {
+ override Socket accept()
+ {
+ return accept(new AsyncSocket());
+ }
+
+ // Overload.
+ //alias Socket.accept accept; // Don't overload since I override this one below..
+ }
+ else
+ {
+ protected override AsyncSocket accepting()
+ {
+ return new AsyncSocket();
+ }
+ }
+
+
+ version(Tango)
+ private const bool _IS_TANGO = true;
+ else
+ private const bool _IS_TANGO = false;
+
+ static if(_IS_TANGO && is(typeof(&this.detach)))
+ {
+ override void detach()
+ {
+ _events = EventType.NONE;
+ _tallEvents.remove(this.handle);
+ return super.detach();
+ }
+ }
+ else
+ {
+ override void close()
+ {
+ _events = EventType.NONE;
+ _tallEvents.remove(this.handle);
+ return super.close();
+ }
+ }
+
+
+ override bool blocking() // getter
+ {
+ return false;
+ }
+
+
+ override void blocking(bool byes) // setter
+ {
+ if(byes)
+ assert(0);
+ }
+
+
+ version(Tango)
+ {
+ override int receive(void[] buf, SocketFlags flags = SocketFlags.NONE)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receive(buf, flags);
+ }
+
+ override int receiveFrom(void[] buf, SocketFlags flags, Address from)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf, flags, from);
+ }
+
+ override int receiveFrom(void[] buf, Address from)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf, from);
+ }
+
+ override int receiveFrom(void[] buf, SocketFlags flags = SocketFlags.NONE)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf, flags);
+ }
+
+
+ override int send(void[] buf, SocketFlags flags = SocketFlags.NONE)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.send(buf, flags);
+ }
+
+ override int sendTo(void[] buf, SocketFlags flags, Address to)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf, flags, to);
+ }
+
+ override int sendTo(void[] buf, Address to)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf, to);
+ }
+
+ override int sendTo(void[] buf, SocketFlags flags = SocketFlags.NONE)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf, flags);
+ }
+ }
+ else
+ {
+ override int receive(void[] buf, SocketFlags flags)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receive(buf, flags);
+ }
+
+ override int receive(void[] buf)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receive(buf);
+ }
+
+ override int receiveFrom(void[] buf, SocketFlags flags, out Address from)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf, flags, from);
+ }
+
+ override int receiveFrom(void[] buf, out Address from)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf, from);
+ }
+
+ override int receiveFrom(void[] buf, SocketFlags flags)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf, flags);
+ }
+
+ override int receiveFrom(void[] buf)
+ {
+ _events &= ~EventType._CANNOT_READ;
+ return super.receiveFrom(buf);
+ }
+
+
+ override int send(void[] buf, SocketFlags flags)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.send(buf, flags);
+ }
+
+ override int send(void[] buf)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.send(buf);
+ }
+
+ override int sendTo(void[] buf, SocketFlags flags, Address to)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf, flags, to);
+ }
+
+ override int sendTo(void[] buf, Address to)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf, to);
+ }
+
+ override int sendTo(void[] buf, SocketFlags flags)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf, flags);
+ }
+
+ override int sendTo(void[] buf)
+ {
+ _events &= ~EventType._CANNOT_WRITE;
+ return super.sendTo(buf);
+ }
+ }
+
+
+ version(Tango)
+ {
+ override Socket accept(Socket s)
+ {
+ _events &= ~EventType._CANNOT_ACCEPT;
+ return super.accept(s);
+ }
+ }
+ else
+ {
+ override Socket accept()
+ {
+ _events &= ~EventType._CANNOT_ACCEPT;
+ return super.accept();
+ }
+ }
+
+
+ private:
+
+ EventType _events;
+ RegisterEventCallback _callback;
+
+
+ void _cando(EventType can)
+ {
+ _events &= ~(can << 16);
+ }
+
+ void _cannotdo(EventType cannot)
+ {
+ _events |= (cannot << 16);
+ }
+
+ bool _ifcando(EventType ifcan)
+ {
+ return !(_events & (ifcan << 16));
+ }
+
+
+ int _peekreceiveclose()
+ {
+ byte[1] onebyte;
+ return Socket.receive(onebyte, SocketFlags.PEEK);
+ }
+
+
+ void _tgotEvent(EventType type, int err)
+ {
+ debug(splat)
+ {
+ if(type == EventType.READ)
+ printf(" {READ:%p}\n", cast(void*)this);
+ else if(type == EventType.WRITE)
+ printf(" {WRITE:%p}\n", cast(void*)this);
+ else if(type == EventType.CONNECT)
+ printf(" {CONNECT:%p}\n", cast(void*)this);
+ else if(type == EventType.CLOSE)
+ printf(" {CLOSE:%p}\n", cast(void*)this);
+ else if(type == EventType.ACCEPT)
+ printf(" {ACCEPT:%p}\n", cast(void*)this);
+ }
+
+ if(_callback)
+ _callback(this, type, err);
+ }
+}
+
+
+/// Asynchronous TCP socket shortcut.
+class AsyncTcpSocket: AsyncSocket
+{
+ ///
+ this(AddressFamily family)
+ {
+ super(family, SocketType.STREAM, ProtocolType.TCP);
+ }
+
+ /// ditto
+ this()
+ {
+ this(cast(AddressFamily)AddressFamily.INET);
+ }
+
+ /// ditto
+ // Shortcut.
+ this(EventType events, RegisterEventCallback eventCallback)
+ {
+ this(cast(AddressFamily)AddressFamily.INET);
+ event(events, eventCallback);
+ }
+
+ /// ditto
+ // Shortcut.
+ this(Address connectTo, EventType events, RegisterEventCallback eventCallback)
+ {
+ this(connectTo.addressFamily());
+ event(events, eventCallback);
+ connect(connectTo);
+ }
+}
+
+
+/// Asynchronous UDP socket shortcut.
+class AsyncUdpSocket: AsyncSocket
+{
+ ///
+ this(AddressFamily family)
+ {
+ super(family, SocketType.DGRAM, ProtocolType.UDP);
+ }
+
+ /// ditto
+ this()
+ {
+ this(cast(AddressFamily)AddressFamily.INET);
+ }
+
+ /// ditto
+ // Shortcut.
+ this(EventType events, RegisterEventCallback eventCallback)
+ {
+ this(cast(AddressFamily)AddressFamily.INET);
+ event(events, eventCallback);
+ }
+}
+
+
+private void _tgetHostErr()
+{
+ throw new Exception("Get host failure");
+}
+
+
+/**
+ Callback type for host resolve event.
+ Params:
+ inetHost = the InternetHost/NetHost of the resolved host, or null.
+ err = an error code, or 0 if successful; if 0, inetHost will be null.
+**/
+alias void delegate(spdInternetHost inetHost, int err) GetHostCallback;
+
+
+/// Returned from asyncGetHost functions.
+class GetHost
+{
+ /// Cancel the get-host operation.
+ void cancel()
+ {
+ _tcallback = null;
+ }
+
+
+ private:
+ GetHostCallback _tcallback;
+ GetHost _tnext;
+ spdInternetHost _tinetHost;
+
+ bool _tbyname; // false == by addr
+ union
+ {
+ uint _taddr;
+ char[] _tname;
+ }
+
+
+ void _tgotEvent()
+ {
+ if(!_tcallback) // If cancel().
+ return;
+
+ if(!_tinetHost)
+ {
+ _tcallback(null, -1); // ?
+ return;
+ }
+
+ _tcallback(_tinetHost, 0);
+ }
+
+
+ this()
+ {
+ }
+}
+
+
+/// Asynchronously resolve host information from a hostname; the callback depends on run().
+GetHost asyncGetHostByName(char[] name, GetHostCallback callback)
+{
+ GetHost gh;
+ gh = new GetHost;
+ version(NO_THREADS)
+ {
+ spdInternetHost ih;
+ ih = new spdInternetHost;
+ if(ih.getHostByName(name))
+ {
+ gh.inetHost = ih;
+ }
+ }
+ else
+ {
+ gh._tcallback = callback;
+ gh._tbyname = true;
+ gh._tname = name;
+ _tgethost(gh);
+ }
+ return gh;
+}
+
+
+/// Asynchronously resolve host information from an IPv4 address; the callback depends on run().
+GetHost asyncGetHostByAddr(uint addr, GetHostCallback callback)
+{
+ GetHost gh;
+ gh = new GetHost;
+ version(NO_THREADS)
+ {
+ spdInternetHost ih;
+ ih = new spdInternetHost;
+ if(ih.getHostByAddr(addr))
+ {
+ gh.inetHost = ih;
+ }
+ }
+ else
+ {
+ gh._tcallback = callback;
+ gh._tbyname = false;
+ gh._taddr = addr;
+ _tgethost(gh);
+ }
+ return gh;
+}
+
+/// ditto
+GetHost asyncGetHostByAddr(char[] addr, GetHostCallback callback)
+{
+ uint uiaddr;
+ uiaddr = spdInternetAddress.parse(addr);
+ if(spdInternetAddress.ADDR_NONE == uiaddr)
+ _tgetHostErr();
+ return asyncGetHostByAddr(uiaddr, callback);
+}
+
+
+version = THSLEEP;
+
+
+version(THSLEEP)
+{
+ version(Windows)
+ {
+ private void _tthsleep()
+ {
+ Sleep(200); // 0.2 secs.
+ }
+ }
+ else
+ {
+ private extern(C) int usleep(uint microseconds);
+
+ private void _tthsleep()
+ {
+ usleep(200_000); // 0.2 secs.
+ }
+ }
+}
+
+
+private void _tgethost(GetHost gh)
+{
+ debug(splat)
+ {
+ printf(" {GETHOST:%p}\n", cast(void*)gh);
+ }
+
+ //synchronized
+ {
+ gh._tnext = null;
+
+ if(!_ththread)
+ {
+ //printf("GETHOST:newthread\n");
+ version(Tango)
+ _ththread = new Thread(&_ththreadproc);
+ else
+ _ththread = new Thread(&_ththreadproc, null);
+ _thnext = _thaddto = gh;
+ _ththread.start();
+ return;
+ }
+
+ synchronized(_ththread)
+ {
+ if(!_thaddto)
+ {
+ //printf("GETHOST:!_thaddto\n");
+ version(SPLAT_HACK_PRINTF)
+ printf(""); // Without this, the thread never sees this host.
+ _thnext = _thaddto = gh;
+
+ version(THSLEEP)
+ {
+ }
+ else
+ {
+ debug(splat)
+ {
+ printf(" {RESUMING:_ththreadproc}\n");
+ }
+
+ _ththread.resume();
+ }
+ }
+ else
+ {
+ //printf("GETHOST:_thaddto\n");
+ _thaddto._tnext = gh;
+ _thaddto = gh;
+ }
+ }
+ }
+}
+
+
+private void _dothreadproc()
+{
+ GetHost gh;
+ spdInternetHost ih;
+ for(;;)
+ {
+ //synchronized(_ththread)
+ volatile
+ {
+ gh = _thnext;
+ }
+
+ if(!gh)
+ {
+ version(THSLEEP)
+ {
+ _tthsleep();
+ }
+ else
+ {
+ debug(splat)
+ {
+ printf(" {PAUSE:_ththreadproc}\n");
+ }
+
+ _ththread.pause();
+
+ debug(splat)
+ {
+ printf(" {RESUMED:_ththreadproc}\n");
+ }
+ }
+ continue;
+ }
+
+ if(gh._tcallback) // If not cancel()..
+ {
+ try
+ {
+ ih = new spdInternetHost;
+ if(gh._tbyname)
+ {
+ if(ih.getHostByName(gh._tname))
+ gh._tinetHost = ih;
+ }
+ else // byaddr
+ {
+ if(ih.getHostByAddr(gh._taddr))
+ gh._tinetHost = ih;
+ }
+
+ debug(splat)
+ {
+ printf(" {GOTHOST:%p} %s\n", cast(void*)gh, gh._tinetHost ? "true".ptr : "false".ptr);
+ }
+ }
+ catch
+ {
+ }
+ }
+
+ _thpn(gh);
+ }
+}
+
+
+version(Tango)
+{
+ /+
+ private _ththreadproc()
+ {
+ _dothreadproc();
+ }
+ +/
+ alias _dothreadproc _ththreadproc;
+}
+else
+{
+ private int _ththreadproc(void* foo)
+ {
+ _dothreadproc();
+ return 0;
+ }
+}
+
+
+// GDC 0.19 segfaults if this isn't in a function; might have to do with synchronized() in a loop.
+private void _thpn(GetHost gh)
+{
+ synchronized(_ththread)
+ {
+ assert(gh is _thnext);
+
+ debug(splat)
+ {
+ printf(" {DONEHOST:%p}\n", cast(void*)gh);
+ }
+
+ _thnext = _thnext._tnext;
+ if(!_thnext)
+ _thaddto = null;
+
+ gh._tnext = null;
+ if(_thfinlast)
+ _thfinlast._tnext = gh;
+ else
+ _thfinnext = gh;
+ _thfinlast = gh;
+ }
+}
+
+
+private GetHost _tnextDoneHost()
+{
+ GetHost gh;
+
+ volatile gh = _thfinnext;
+ if(!gh)
+ return null;
+
+ synchronized(_ththread)
+ {
+ gh = _thfinnext;
+ if(gh)
+ {
+ _thfinnext = _thfinnext._tnext;
+ if(!_thfinnext)
+ _thfinlast = null;
+ gh._tnext = null;
+ }
+ }
+
+ return gh;
+}
+
+
+private bool _areHosts()
+{
+ return _thnext || _thfinnext;
+}
+
+
+/// Buffering socket I/O.
+class SocketQueue
+{
+ ///
+ this(Socket sock)
+ in
+ {
+ assert(sock !is null);
+ }
+ body
+ {
+ this.sock = sock;
+ }
+
+
+ /// Property: get the socket of this queue.
+ final Socket socket() // getter
+ {
+ return sock;
+ }
+
+
+ /// Resets the buffers.
+ void reset()
+ {
+ writebuf = null;
+ readbuf = null;
+ }
+
+
+ /+
+ // DMD 0.92 says error: function toString overrides but is not covariant with toString
+ override char[] toString()
+ {
+ return cast(char[])peek();
+ }
+ +/
+
+
+ /// Peek at some or all of the received data but leave it in the queue. May return less than requested.
+ void[] peek()
+ {
+ return readbuf[0 .. rpos];
+ }
+
+ /// ditto
+ void[] peek(uint len)
+ {
+ if(len >= rpos)
+ return peek();
+
+ return readbuf[0 .. len];
+ }
+
+
+ /// Returns: some or all of the received data and removes this amount from the queue. May return less than requested.
+ void[] receive()
+ {
+ ubyte[] result;
+
+ result = readbuf[0 .. rpos];
+ readbuf = null;
+ rpos = 0;
+
+ return result;
+ }
+
+ /// ditto
+ void[] receive(uint len)
+ {
+ if(len >= rpos)
+ return receive();
+
+ ubyte[] result;
+
+ result = readbuf[0 .. len];
+ readbuf = readbuf[len .. readbuf.length];
+ rpos -= len;
+
+ return result;
+ }
+
+
+ /// Add data to the queue and send it over this socket.
+ void send(void[] buf)
+ {
+ if(canwrite)
+ {
+ assert(!writebuf.length);
+
+ int st;
+ if(buf.length > 4096)
+ st = 4096;
+ else
+ st = buf.length;
+
+ st = sock.send(buf[0 .. st]);
+ if(st > 0)
+ {
+ if(buf.length - st)
+ {
+ // dup so it can be appended to.
+ writebuf = (cast(ubyte[])buf)[st .. buf.length].dup;
+ }
+ }
+ else
+ {
+ // dup so it can be appended to.
+ writebuf = (cast(ubyte[])buf).dup;
+ }
+
+ //canwrite = false;
+ }
+ else
+ {
+ writebuf ~= cast(ubyte[])buf;
+ }
+ }
+
+
+ /// Property: get the number of bytes in send buffer.
+ uint sendBytes()
+ {
+ return writebuf.length;
+ }
+
+
+ /// Property: get the number of bytes in recv buffer.
+ uint receiveBytes()
+ {
+ return rpos;
+ }
+
+
+ /// Call on a read event so that incoming data may be buffered.
+ void readEvent()
+ {
+ if(readbuf.length - rpos < 1024)
+ readbuf.length = readbuf.length + 2048;
+
+ int rd = sock.receive(readbuf[rpos .. readbuf.length]);
+ if(rd > 0)
+ rpos += cast(uint)rd;
+ }
+
+
+ /// Call on a write event so that buffered outgoing data may be sent.
+ void writeEvent()
+ {
+ if(writebuf.length)
+ {
+ ubyte[] buf;
+
+ if(writebuf.length > 4096)
+ buf = writebuf[0 .. 4096];
+ else
+ buf = writebuf;
+
+ int st = sock.send(buf);
+ if(st > 0)
+ writebuf = writebuf[st .. writebuf.length];
+ }
+ else
+ {
+ //canwrite = true;
+ }
+ }
+
+
+ /**
+ Shortcut function for AsyncSocket.
+ Automatically calls readEvent and writeEvent as needed.
+ Same signature as RegisterEventCallback for simplicity.
+ **/
+ void event(Socket _sock, EventType type, int err)
+ in
+ {
+ assert(_sock is sock);
+ }
+ body
+ {
+ switch(type)
+ {
+ case EventType.READ:
+ readEvent();
+ break;
+
+ case EventType.WRITE:
+ writeEvent();
+ break;
+
+ default: ;
+ }
+ }
+
+
+ deprecated
+ {
+ alias receiveBytes recvBytes;
+ alias receive recv;
+ }
+
+
+ private:
+ ubyte[] writebuf;
+ ubyte[] readbuf;
+ uint rpos;
+ Socket sock;
+ //bool canwrite = false;
+
+
+ bool canwrite() // getter
+ {
+ return writebuf.length == 0;
+ }
+}
+
+
+/// Returns the number of asynchronous sockets waiting for events.
+size_t getNumberOfAsyncSockets()
+{
+ return _tallEvents.length;
+}
+
+
+/// Returns the number of active timers.
+size_t getNumberOfTimers()
+{
+ return _tcount;
+}
+
+
+private:
+
+Timer _tfirst, _tlast;
+size_t _tcount = 0;
+
+
+Timer _tnext()
+{
+ //spdTime lowest = spdTime.max; // Wrong in Tango 0.99.2.
+ spdTime lowest = cast(spdTime)((spdTime.init + 0).max); // + 1 converts to the underlying arithmetic type to get the real max.
+ Timer t, tlowest;
+ for(t = _tfirst; t; t = t._tnext)
+ {
+ if(t._talarm < lowest)
+ {
+ tlowest = t;
+ lowest = t._talarm;
+ }
+ }
+ return tlowest;
+}
+
+
+void _tadd(Timer t)
+in
+{
+ assert(t !is null);
+ assert(t._ttimeout);
+ assert(t._tprev is null);
+ assert(t._tnext is null);
+ assert(t._talarm == t._TALARM_INIT);
+}
+body
+{
+ t._talarm = cast(spdTime)(spdGetCurrentUtcTime() + t._ttimeout);
+
+ t._tprev = _tlast;
+ _tlast = t;
+ if(!_tfirst)
+ _tfirst = t;
+ else
+ t._tprev._tnext = t;
+
+ _tcount++;
+}
+
+
+void _tremove(Timer t)
+in
+{
+ assert(t !is null);
+ assert(t._talarm != t._TALARM_INIT);
+}
+body
+{
+ t._talarm = t._TALARM_INIT;
+
+ if(t._tprev)
+ t._tprev._tnext = t._tnext;
+ else
+ _tfirst = t._tnext;
+
+ if(t._tnext)
+ t._tnext._tprev = t._tprev;
+ else
+ _tlast = t._tprev;
+
+ t._tprev = null;
+ t._tnext = null;
+
+ if(_tcount)
+ _tcount--;
+}
+
+
+template _tTicks()
+{
+ static if(spdTICKS_PER_SECOND == 1_000)
+ {
+ uint _tticksToSecs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND); }
+ uint _tticksToMs(spdTime ticks) { return cast(uint)ticks; }
+ //uint _tticksToNs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND * 1_000_000_000); }
+ //uint _tticksToNs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000_000); }
+ //uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND * 1_000_000); }
+ uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000); }
+ spdTime _tsecsToTicks(uint secs) { return cast(spdTime)(secs * spdTICKS_PER_SECOND); }
+ spdTime _tmsToTicks(uint ms) { return cast(spdTime)ms; }
+ }
+ else
+ {
+ uint _tticksToSecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND); }
+ uint _tticksToMs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000); }
+ //uint _tticksToNs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000_000); }
+ uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000); }
+ spdTime _tsecsToTicks(uint secs) { return cast(spdTime)(cast(double)secs * cast(double)spdTICKS_PER_SECOND); }
+ spdTime _tmsToTicks(uint ms) { return cast(spdTime)(cast(double)spdTICKS_PER_SECOND / cast(double)1_000 * cast(double)ms); }
+ }
+}
+
+alias _tTicks!()._tticksToSecs _tticksToSecs;
+alias _tTicks!()._tticksToMs _tticksToMs;
+//alias _tTicks!()._tticksToNs _tticksToNs;
+alias _tTicks!()._tticksToMicrosecs _tticksToMicrosecs;
+alias _tTicks!()._tsecsToTicks _tsecsToTicks;
+alias _tTicks!()._tmsToTicks _tmsToTicks;
+
+
+unittest
+{
+ assert(_tsecsToTicks(_tticksToSecs(543253)) == _tsecsToTicks(_tticksToSecs(543253)));
+ assert(_tmsToTicks(_tticksToMs(3445723)) == _tmsToTicks(_tticksToMs(3445723)));
+}
+
+
+void _tticksToTimeval(spdTime ticks, spdMyTimeval* tv)
+{
+ tv.seconds = _tticksToSecs(ticks);
+ ticks -= _tsecsToTicks(tv.seconds);
+ tv.microseconds = _tticksToMicrosecs(ticks);
+}
+
+
+//_tEventInfo[socket_t] _tallEvents;
+AsyncSocket[socket_t] _tallEvents;
+
+Thread _ththread;
+GetHost _thnext, _thaddto;
+GetHost _thfinnext, _thfinlast;
+
+bool _texit = false;
+
+
+/+
+// Test.
+void main()
+{
+ new class Timer { this() { interval = 1000; start(); } override void onAlarm() { printf(" * ALARM * \n"); } };
+ new class Timer { this() { interval = 5000; start(); } override void onAlarm() { printf(" &die 5 spawn 2 & \n"); stop();
+ new class Timer { this() { interval = 2000; start(); } override void onAlarm() { printf(" x spawn x \n"); } };
+ } };
+ new class Timer { this() { interval = 3000; start(); } override void onAlarm() { printf(" &die 3& \n"); stop(); } };
+ new class Timer { this() { interval = 2500; start(); } override void onAlarm()
+ {
+ stop();
+ asyncGetHostByName("www.google.com", (spdInternetHost ih, int err) { if(!err) { printf(" gGot host %.*s\n", ih.name); } });
+ }
+ };
+ new class Timer { this() { interval = 500; start(); } override void onAlarm()
+ {
+ printf(" (slower and slower %lu \n", interval);
+ interval = interval + 500;
+ }
+ };
+
+ asyncGetHostByName("www.yahoo.com", (spdInternetHost ih, int err) { if(!err) { printf(" yGot host %.*s\n", ih.name); } });
+ asyncGetHostByName("www.ask.com", (spdInternetHost ih, int err) { if(!err) { printf(" aGot host %.*s\n", ih.name); } });
+
+ run();
+}
++/
+
=== added file 'D_lang/testing/candidate_libs/splat.html'
--- D_lang/testing/candidate_libs/splat.html 1970-01-01 00:00:00 +0000
+++ D_lang/testing/candidate_libs/splat.html 2013-02-21 03:06:20 +0000
@@ -0,0 +1,269 @@
+<html><head>
+ <META http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>splat</title>
+ </head><body>
+ <h1>splat</h1>
+ <!-- Generated by Ddoc from splat.d -->
+<b></b> Splat: the socket platform with the lame name. It's full of puns, but it runs!
+ <a href="http://www.dprogramming.com/splat.php">Download Splat</a>.
+ Version 0.7.
+ For both Phobos and Tango; tested with Phobos and Tango 0.99.2.
+<br><br>
+
+<dl><dt><big>void <u>run</u>();
+</big></dt>
+<dd>Run the event loop; wait for timer and socket events.
+ Exceptions that occur in event callbacks break out of <u>run</u>.
+<br><br>
+
+</dd>
+<dt><big>void <u>exitLoop</u>();
+</big></dt>
+<dd>Causes run() to return as soon as it can.
+<br><br>
+
+</dd>
+<dt><big>class <u>Timer</u>;
+</big></dt>
+<dd>Timers; alarms (timeout events) depend on run().
+<br><br>
+
+<dl><dt><big>final void <u>interval</u>(uint <i>iv</i>);
+<br>final uint <u>interval</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get and set the timer interval in milliseconds.
+<br><br>
+
+</dd>
+<dt><big>final void <u>start</u>();
+</big></dt>
+<dd>Start this timer.
+<br><br>
+
+</dd>
+<dt><big>final void <u>stop</u>();
+</big></dt>
+<dd>Stop this timer.
+<br><br>
+
+</dd>
+<dt><big>void <u>onAlarm</u>();
+</big></dt>
+<dd>Override to be notified when the time expires. Alarms continue until stop().
+<br><br>
+
+</dd>
+<dt><big>this();
+<br>this(void delegate(Timer) <i>dg</i>);
+</big></dt>
+<dd>Construct a timer; can take a delegate that is called back automatically on an alarm.
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>enum <u>EventType</u>;
+</big></dt>
+<dd>Socket event flags.
+<br><br>
+
+<dl><dt><big><u>NONE</u></big></dt>
+<dd><br><br>
+</dd>
+<dt><big><u>READ</u><br><u>WRITE</u><br><u>ACCEPT</u><br><u>CONNECT</u><br><u>CLOSE</u></big></dt>
+<dd><br><br>
+</dd>
+</dl>
+</dd>
+<dt><big>alias <u>RegisterEventCallback</u>;
+</big></dt>
+<dd>Callback type for socket events.
+<br><br>
+<b>Params:</b><br>
+<table><tr><td>sock</td>
+<td>the socket</td></tr>
+<tr><td>type</td>
+<td>which event; will be only one of the event flags.</td></tr>
+<tr><td>err</td>
+<td>an error code, or 0 if successful.</td></tr>
+</table><br>
+
+</dd>
+<dt><big>class <u>AsyncSocket</u>: std.socket.Socket;
+</big></dt>
+<dd>Asynchronous sockets; socket events depend on run(). Mostly the same as std.socket.Socket.
+<br><br>
+
+<dl><dt><big>void <u>event</u>(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>callback</i>);
+</big></dt>
+<dd>Registers a <i>callback</i> for specified socket <i>events</i>.
+ One or more type flags may be used, or NONE to cancel all.
+ Calling this twice on the same socket cancels out previously registered <i>events</i> for the socket.
+
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>class <u>AsyncTcpSocket</u>: splat.AsyncSocket;
+</big></dt>
+<dd>Asynchronous TCP socket shortcut.
+<br><br>
+
+<dl><dt><big>this(AddressFamily <i>family</i>);
+<br>this();
+<br>this(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>);
+<br>this(Address <i>connectTo</i>, EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>);
+</big></dt>
+<dd><br><br>
+</dd>
+</dl>
+</dd>
+<dt><big>class <u>AsyncUdpSocket</u>: splat.AsyncSocket;
+</big></dt>
+<dd>Asynchronous UDP socket shortcut.
+<br><br>
+
+<dl><dt><big>this(AddressFamily <i>family</i>);
+<br>this();
+<br>this(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>);
+</big></dt>
+<dd><br><br>
+</dd>
+</dl>
+</dd>
+<dt><big>alias <u>GetHostCallback</u>;
+</big></dt>
+<dd>Callback type for host resolve event.
+<br><br>
+<b>Params:</b><br>
+<table><tr><td>inetHost</td>
+<td>the InternetHost/NetHost of the resolved host, or <b>null</b>.</td></tr>
+<tr><td>err</td>
+<td>an error code, or 0 if successful; if 0, inetHost will be <b>null</b>.</td></tr>
+</table><br>
+
+</dd>
+<dt><big>class <u>GetHost</u>;
+</big></dt>
+<dd>Returned from asyncGetHost functions.
+<br><br>
+
+<dl><dt><big>void <u>cancel</u>();
+</big></dt>
+<dd>Cancel the get-host operation.
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>GetHost <u>asyncGetHostByName</u>(char[] <i>name</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>);
+</big></dt>
+<dd>Asynchronously resolve host information from a hostname; the <i>callback</i> depends on run().
+<br><br>
+
+</dd>
+<dt><big>GetHost <u>asyncGetHostByAddr</u>(uint <i>addr</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>);
+<br>GetHost <u>asyncGetHostByAddr</u>(char[] <i>addr</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>);
+</big></dt>
+<dd>Asynchronously resolve host information from an IPv4 address; the <i>callback</i> depends on run().
+<br><br>
+
+</dd>
+<dt><big>class <u>SocketQueue</u>;
+</big></dt>
+<dd>Buffering socket I/O.
+<br><br>
+
+<dl><dt><big>this(Socket <i>sock</i>);
+</big></dt>
+<dd><br><br>
+</dd>
+<dt><big>final Socket <u>socket</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get the <u>socket</u> of this queue.
+<br><br>
+
+</dd>
+<dt><big>void <u>reset</u>();
+</big></dt>
+<dd>Resets the buffers.
+<br><br>
+
+</dd>
+<dt><big>void[] <u>peek</u>();
+<br>void[] <u>peek</u>(uint <i>len</i>);
+</big></dt>
+<dd>Peek at some or all of the received data but leave it in the queue. May return less than requested.
+<br><br>
+
+</dd>
+<dt><big>void[] <u>receive</u>();
+<br>void[] <u>receive</u>(uint <i>len</i>);
+</big></dt>
+<dd><b>Returns:</b><br>
+some or all of the received data and removes this amount from the queue. May return less than requested.
+<br><br>
+
+</dd>
+<dt><big>void <u>send</u>(void[] <i>buf</i>);
+</big></dt>
+<dd>Add data to the queue and <u>send</u> it over this socket.
+<br><br>
+
+</dd>
+<dt><big>uint <u>sendBytes</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get the number of bytes in send buffer.
+<br><br>
+
+</dd>
+<dt><big>uint <u>receiveBytes</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get the number of bytes in recv buffer.
+<br><br>
+
+</dd>
+<dt><big>void <u>readEvent</u>();
+</big></dt>
+<dd>Call on a read event so that incoming data may be buffered.
+<br><br>
+
+</dd>
+<dt><big>void <u>writeEvent</u>();
+</big></dt>
+<dd>Call on a write event so that buffered outgoing data may be sent.
+<br><br>
+
+</dd>
+<dt><big>void <u>event</u>(Socket <i>_sock</i>, EventType <i>type</i>, int <i>err</i>);
+</big></dt>
+<dd>Shortcut function for AsyncSocket.
+ Automatically calls readEvent and writeEvent as needed.
+ Same signature as RegisterEventCallback for simplicity.
+
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>uint <u>getNumberOfAsyncSockets</u>();
+</big></dt>
+<dd>Returns the number of asynchronous sockets waiting for events.
+<br><br>
+
+</dd>
+<dt><big>uint <u>getNumberOfTimers</u>();
+</big></dt>
+<dd>Returns the number of active timers.
+<br><br>
+
+</dd>
+</dl>
+
+ <hr><small>Page generated by <a href="http://www.digitalmars.com/d/ddoc.html">Ddoc</a>. </small>
+ </body></html>
=== added file 'D_lang/testing/candidate_libs/splat07.zip'
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
=== added directory 'D_lang/testing/str_socket'
=== added file 'D_lang/testing/str_socket/Makefile'
--- D_lang/testing/str_socket/Makefile 1970-01-01 00:00:00 +0000
+++ D_lang/testing/str_socket/Makefile 2013-02-21 03:06:20 +0000
@@ -0,0 +1,30 @@
+#***********************************************
+# This file is part of the NRTB project (https://launchpad.net/nrtb).
+#
+# NRTB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# NRTB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+#
+#***********************************************
+
+lib: socket_test
+ @./socket_test
+ @echo build complete
+
+socket_test: socket_test.d Makefile
+ @rm -f socket_test
+ @dmd socket_test.d
+
+clean:
+ @rm -vf *.o socket_test
+ @echo all objects and executables have been erased.
+
=== added file 'D_lang/testing/str_socket/SocketStringTransciever.mm'
--- D_lang/testing/str_socket/SocketStringTransciever.mm 1970-01-01 00:00:00 +0000
+++ D_lang/testing/str_socket/SocketStringTransciever.mm 2013-02-21 03:06:20 +0000
@@ -0,0 +1,49 @@
+<map version="0.9.0">
+<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
+<node CREATED="1353288395487" ID="ID_1403329192" MODIFIED="1353512093507" TEXT="Socket string transciever.">
+<node CREATED="1353288596251" ID="ID_1636926895" MODIFIED="1353512095611" POSITION="right" TEXT="Connect(address)">
+<node CREATED="1353289092215" ID="ID_1097805018" MODIFIED="1353289099292" TEXT="Resolves address"/>
+<node CREATED="1353289100126" ID="ID_912894431" MODIFIED="1353289144348" TEXT="Connects to address"/>
+<node CREATED="1353289145245" ID="ID_1737995458" MODIFIED="1353289159019" TEXT="Starts reciever thread"/>
+<node CREATED="1353290958729" ID="ID_1494063472" MODIFIED="1353291040119" TEXT="Expects the callbacks to set at call time"/>
+<node CREATED="1353289166189" ID="ID_244950625" MODIFIED="1353289174227" TEXT="throws on any error"/>
+</node>
+<node CREATED="1353288616481" ID="ID_845783483" MODIFIED="1353512095614" POSITION="right" TEXT="close()">
+<node CREATED="1353289189501" ID="ID_142698792" MODIFIED="1353289197939" TEXT="Shutdown reciever thread"/>
+<node CREATED="1353289198757" ID="ID_771780490" MODIFIED="1353289263410" TEXT="close socket"/>
+<node CREATED="1353289271773" ID="ID_357264070" MODIFIED="1353289293595" TEXT="discard any other resources allocated"/>
+</node>
+<node CREATED="1353288702488" ID="ID_1885052703" MODIFIED="1353512095619" POSITION="right" TEXT="regeister_receiver(funtion(newStr))">
+<node CREATED="1353289372692" ID="ID_1797818997" MODIFIED="1353289421498" TEXT="Replace existing reciever callback"/>
+<node CREATED="1353289422811" ID="ID_716021446" MODIFIED="1353289467577" TEXT="The callback has the signiture function(string)"/>
+<node CREATED="1353289476939" ID="ID_1689880619" MODIFIED="1353290199100" TEXT="The callback will be called whenever an ASCII 10 is recieved."/>
+<node CREATED="1353290138311" ID="ID_48990930" MODIFIED="1353290251764" TEXT="The argument "newStr" will contain any bytes recieved before the ASCII 10"/>
+<node CREATED="1353289528395" ID="ID_1457236482" MODIFIED="1353290179636" TEXT="ASCII 10s and 13s will be discarded"/>
+</node>
+<node CREATED="1353288756648" ID="ID_1776338151" MODIFIED="1353288803357" POSITION="right" TEXT="register_event_hander(funciton(event))">
+<node CREATED="1353289687346" ID="ID_146527388" MODIFIED="1353289714640" TEXT="Replace existing event handler"/>
+<node CREATED="1353289715586" ID="ID_1957454409" MODIFIED="1353289748151" TEXT="The callback has the signiture function(string)"/>
+<node CREATED="1353289749753" ID="ID_1524918841" MODIFIED="1353289768918" TEXT="The callback will be called whenever an event occurs"/>
+<node CREATED="1353289775721" ID="ID_698482207" MODIFIED="1353289785327" TEXT="Available events">
+<node CREATED="1353495351509" ID="ID_1988403096" MODIFIED="1353495373615" TEXT="connect"/>
+<node CREATED="1353495374592" ID="ID_1082092706" MODIFIED="1353495385858" TEXT="overflow"/>
+<node CREATED="1353495387001" ID="ID_1818531252" MODIFIED="1353495391356" TEXT="underflow"/>
+<node CREATED="1353495392662" ID="ID_236107112" MODIFIED="1353495399980" TEXT="dropped"/>
+<node CREATED="1353495400962" ID="ID_909770107" MODIFIED="1353495403143" TEXT="disconnect"/>
+</node>
+</node>
+<node CREATED="1353288811903" ID="ID_1354285471" MODIFIED="1353512095621" POSITION="right" TEXT="send(string)">
+<node CREATED="1353289903920" ID="ID_293305230" MODIFIED="1353290032885" TEXT="Sends the argument on the socket"/>
+<node CREATED="1353290036647" ID="ID_1916879506" MODIFIED="1353290061148" TEXT="An ASCII 10 will be postixed to the string"/>
+<node CREATED="1353290092071" ID="ID_1214127336" MODIFIED="1353290125572" TEXT="Blocks until the send is complete."/>
+</node>
+<node CREATED="1353290448717" ID="ID_1736651166" MODIFIED="1353512095625" POSITION="right" TEXT="worker_thread()">
+<node CREATED="1353290466204" ID="ID_1117113952" MODIFIED="1353290517609" TEXT="Responible for incoming bytes"/>
+<node CREATED="1353290741723" ID="ID_910559431" MODIFIED="1353290766920" TEXT="discards ASCII 10 and 13"/>
+<node CREATED="1353290769963" ID="ID_1282285823" MODIFIED="1353290798568" TEXT="places all other bytes in the buffer"/>
+<node CREATED="1353290518900" ID="ID_216777552" MODIFIED="1353291656818" TEXT="calls the receiver callback with the buffer on recept of an EOM (ASCII 10)"/>
+<node CREATED="1353290869346" ID="ID_823816252" MODIFIED="1353290886168" TEXT="Clears the buffer when the callback returns"/>
+<node CREATED="1353291445518" ID="ID_578045982" MODIFIED="1353291464356" TEXT="Loops infinitely until closed."/>
+</node>
+</node>
+</map>
=== added file 'D_lang/testing/str_socket/socket_test.d'
--- D_lang/testing/str_socket/socket_test.d 1970-01-01 00:00:00 +0000
+++ D_lang/testing/str_socket/socket_test.d 2013-02-21 03:06:20 +0000
@@ -0,0 +1,43 @@
+/*********************
+Multithreaded message passing example in D
+*********************/
+
+// import the concurrency and standard IO modules
+import std.concurrency, std.stdio;
+import std.string, std.conv, std.stream, std.stdio;
+import std.socket, std.socketstream;
+
+// main is just like main in C++
+void main(string[] args)
+{
+ writeln("D Socket Send/Receive Test.");
+
+ if (args.length < 2)
+ {
+ writeln("Usage:");
+ writeln(" ",args[0]," httpd_IP");
+ return;
+ }
+
+ string IP = args[1];
+ ushort port = 80;
+
+ writefln(" Connecting to host %s:%d....",IP,port);
+
+ // connect to the server
+ Socket sock = new TcpSocket(new InternetAddress(IP, port));
+ scope(exit) sock.close();
+ Stream ss = new SocketStream(sock);
+
+ ss.writeString("GET / HTTP/1.0\r\nHost: " ~ IP ~ "\r\n\r\n");
+
+ while (!ss.eof())
+ {
+ auto line = ss.readLine();
+ writeln(line);
+ }
+
+ writeln("** main() is complete **");
+
+}
+
=== added directory 'D_lang/testing/thread_pool'
=== added file 'D_lang/testing/thread_pool/Makefile'
--- D_lang/testing/thread_pool/Makefile 1970-01-01 00:00:00 +0000
+++ D_lang/testing/thread_pool/Makefile 2013-02-21 03:06:20 +0000
@@ -0,0 +1,30 @@
+#***********************************************
+# This file is part of the NRTB project (https://launchpad.net/nrtb).
+#
+# NRTB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# NRTB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+#
+#***********************************************
+
+lib: thread_pool
+ @./thread_pool
+ @echo build complete
+
+thread_pool: thread_pool.d Makefile
+ @rm -f thread_pool
+ @dmd thread_pool.d
+
+clean:
+ @rm -vf *.o thread_pool
+ @echo all objects and executables have been erased.
+
=== added file 'D_lang/testing/thread_pool/thread_pool.d'
--- D_lang/testing/thread_pool/thread_pool.d 1970-01-01 00:00:00 +0000
+++ D_lang/testing/thread_pool/thread_pool.d 2013-02-21 03:06:20 +0000
@@ -0,0 +1,81 @@
+/*********************
+Multithreaded message passing example in D
+*********************/
+
+// import the concurrency and standard IO modules
+import std.concurrency, std.stdio, core.thread;
+
+struct thread_pool(wp_t, alias task)
+{
+ // Housekeeping variables
+ private Tid listener_tid;
+
+ // Does nothing but start the listener.
+ public this(int queue_size) {
+ listener_tid = spawn(&listener_thread!(wp_t,task),queue_size);
+ };
+
+ // submit a work, packet for processing.
+ public void submit(wp_t wp) {
+ listener_tid.send(thisTid, wp);
+ };
+
+}
+
+void worker_thread(wpt, alias task)() {
+ bool running = true;
+ while (running) {
+ receive (
+ (Tid t, wpt d) { task(t,d); },
+ (OwnerTerminated e) { running = false; }
+ );
+ };
+}
+
+void listener_thread(wpt, alias task)(int queue_size) {
+
+ Tid worker_list[];
+ ulong next = 0;
+
+ void submit(Tid t, wpt d) {
+ worker_list[next].send(t,d);
+ next = (++next) % worker_list.length;
+ }
+
+ // initial setup.
+ for(int i = 0; i< queue_size; i++) {
+ worker_list ~= spawn(&worker_thread!(wpt,task));
+ }
+
+ // service loop
+ bool running = true;
+ while (running) {
+ receive (
+ (Tid t, wpt d) { submit(t,d); },
+ (OwnerTerminated e) { running = false; }
+ );
+ };
+};
+
+//==== code starts here
+
+void mytask(Tid t, int i) {
+ writeln("Task ",thisTid," processed ",i);
+ Thread.sleep(dur!("msecs") (20));
+};
+
+
+// main is just like main in C++
+void main()
+{
+ writeln("D Message Driven Work Queue Example.");
+ auto myqueue = thread_pool!(int,mytask)(10);
+
+ for (auto i=0; i<100; i++) {
+ myqueue.submit(i);
+ };
+
+ Thread.sleep(dur!("seconds") (3));
+ writeln("Run complete");
+
+};
\ No newline at end of file
=== added file 'D_lang/testing/thread_pool/thread_pool.mm'
--- D_lang/testing/thread_pool/thread_pool.mm 1970-01-01 00:00:00 +0000
+++ D_lang/testing/thread_pool/thread_pool.mm 2013-02-21 03:06:20 +0000
@@ -0,0 +1,47 @@
+<map version="0.9.0">
+<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
+<node CREATED="1199190455281" ID="ID_1574918623" MODIFIED="1199190480522" TEXT="thread_pool">
+<node CREATED="1360253779843" ID="ID_432711866" MODIFIED="1360261129036" POSITION="right" TEXT="class task_pool(t)">
+<node CREATED="1360267525267" ID="ID_760440288" MODIFIED="1360267533846" TEXT="this()">
+<node CREATED="1360268024517" ID="ID_1334050998" MODIFIED="1360328468829" TEXT="starts task_pool_manager(t)(low,high,,increment,task)"/>
+</node>
+<node CREATED="1360081590643" ID="ID_1324728" MODIFIED="1360081668955" TEXT="struct work_packet(t)"/>
+<node CREATED="1360081723340" ID="ID_1492950840" MODIFIED="1360081762970" TEXT="struct limits"/>
+<node CREATED="1360081739372" ID="ID_452972575" MODIFIED="1360081747882" TEXT="struct run_ctl"/>
+<node CREATED="1360254280681" ID="ID_778719726" MODIFIED="1360261274927" TEXT="void submit(t data)"/>
+<node CREATED="1360254367731" ID="ID_1043224962" MODIFIED="1360261286496" TEXT="uint set_limits(low, high, increment)"/>
+</node>
+<node CREATED="1360082136187" ID="ID_181135344" MODIFIED="1360328486894" POSITION="right" TEXT="task pool manager(t)(low, high, increment,task)">
+<node CREATED="1360254670685" ID="ID_1823995507" MODIFIED="1360254677048" TEXT="Free running thread"/>
+<node CREATED="1360254680507" ID="ID_291925315" MODIFIED="1360255051860" TEXT="On startup">
+<node CREATED="1360254687714" ID="ID_415174674" MODIFIED="1360254704683" TEXT="Registers with the global pool manager"/>
+<node CREATED="1360254714285" ID="ID_1841317578" MODIFIED="1360544160805" TEXT="starts default set of task_thread(t)(thisTid,task)"/>
+</node>
+<node CREATED="1360254933031" ID="ID_683968420" MODIFIED="1360255382530" TEXT="Service loop">
+<node CREATED="1360255079468" ID="ID_1559510237" MODIFIED="1360255176424" TEXT="rcv Tid, t">
+<node CREATED="1360255261482" ID="ID_29306120" MODIFIED="1360255307209" TEXT="Verify there spare thread count"/>
+<node CREATED="1360255312567" ID="ID_662023772" MODIFIED="1360255333731" TEXT="submit Tid, t to next task thread"/>
+</node>
+<node CREATED="1360255179495" ID="ID_548612491" MODIFIED="1360334567427" TEXT="rcv Tid, limits">
+<node CREATED="1360255428431" ID="ID_1067723780" MODIFIED="1360255499958" TEXT="Reset pool parameters"/>
+<node CREATED="1360255501795" ID="ID_943031629" MODIFIED="1360255516011" TEXT="Add/remove worker threads as needed"/>
+</node>
+<node CREATED="1360334567882" ID="ID_1909911450" MODIFIED="1360334583842" TEXT="rvc Tid, run_ctl">
+<node CREATED="1360334583845" ID="ID_882927298" MODIFIED="1360336402561" TEXT="shutdown"/>
+</node>
+</node>
+</node>
+<node CREATED="1360081583633" ID="ID_1103044446" MODIFIED="1360328522599" POSITION="right" TEXT="task_thread(t)(Tid task_pool_manager,task)">
+<node CREATED="1360281228443" ID="ID_1814378750" MODIFIED="1360281259435" TEXT="Free running thread"/>
+<node CREATED="1360334423885" ID="ID_1136327708" MODIFIED="1360334431123" TEXT="On startup"/>
+<node CREATED="1360334432374" ID="ID_516047719" MODIFIED="1360334444665" TEXT="Service Loop">
+<node CREATED="1360334444667" ID="ID_1239866205" MODIFIED="1360334469683" TEXT="receive tid, t">
+<node CREATED="1360334469685" ID="ID_1854740647" MODIFIED="1360334485839" TEXT="Call task(tid,t)"/>
+</node>
+<node CREATED="1360334493738" ID="ID_1132173280" MODIFIED="1360334530760" TEXT="receive tid, run_ctl">
+<node CREATED="1360334530762" ID="ID_1133543570" MODIFIED="1360334542293" TEXT="shutdown"/>
+</node>
+</node>
+</node>
+</node>
+</map>
Follow ups