Add copyright notices to all source files and put a license in LICENSE.
[versaplex.git] / wvdotnet / wveventer.cs
blobd195aa5fa66b5fabc95b195c1e77841c1790fd3b
1 /*
2 * Versaplex:
3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
5 */
6 using System;
7 using System.Net.Sockets;
8 using System.Collections;
9 using System.Collections.Generic;
10 using System.Linq;
11 using System.Threading;
13 public interface IWvEventer
15 void runonce(int msec_timeout);
16 void runonce();
17 void onreadable(Socket s, Action a);
18 void onwritable(Socket s, Action a);
19 void addpending(Object cookie, Action a);
20 void delpending(Object cookie);
21 void addtimeout(Object cookie, DateTime t, Action a);
22 void deltimeout(Object cookie);
25 public class WvEventer : IWvEventer
27 // CAREFUL! The 'pending' structure might be accessed from other threads!
28 Dictionary<object, Action>
29 pending = new Dictionary<object, Action>();
31 Dictionary<Socket, Action>
32 r = new Dictionary<Socket, Action>(),
33 w = new Dictionary<Socket, Action>();
35 class TimeAction
37 public DateTime t;
38 public Action a;
40 public TimeAction(DateTime t, Action a)
42 this.t = t;
43 this.a = a;
46 Dictionary<Object, TimeAction>
47 ta = new Dictionary<Object, TimeAction>();
49 public WvEventer()
53 public void onreadable(Socket s, Action a)
55 if (s == null) return;
56 r.Remove(s);
57 if (a != null)
58 r.Add(s, a);
61 public void onwritable(Socket s, Action a)
63 if (s == null) return;
64 w.Remove(s);
65 if (a != null)
66 w.Add(s, a);
69 public void addtimeout(Object cookie, DateTime t, Action a)
71 ta.Remove(cookie);
72 if (a != null)
73 ta.Add(cookie, new TimeAction(t, a));
76 // NOTE:
77 // This is the only kind of event you can enqueue from a thread other
78 // than the one doing runonce()!
79 // It will run your Action in the runonce() thread on the next pass.
80 public void addpending(Object cookie, Action a)
82 lock(pending)
84 pending.Remove(cookie);
85 pending.Add(cookie, a);
89 public void delpending(Object cookie)
91 lock(pending)
93 pending.Remove(cookie);
97 public void deltimeout(Object cookie)
99 ta.Remove(cookie);
102 public void runonce()
104 runonce(-1);
107 public void runonce(int msec_timeout)
109 // Console.WriteLine("Pending: {0}", pending.Count);
111 IList<Socket> rlist = r.Keys.ToList();
112 IList<Socket> wlist = w.Keys.ToList();
113 IList<TimeAction> talist = ta.Values.ToList();
114 if (msec_timeout < 0)
115 msec_timeout = 1000000;
116 TimeAction first
117 = new TimeAction(DateTime.Now
118 + TimeSpan.FromMilliseconds(msec_timeout), null);
120 foreach (TimeAction t in talist)
121 if (t.t < first.t)
122 first = t;
124 TimeSpan timeout = first.t - DateTime.Now;
125 if (timeout < TimeSpan.Zero)
126 timeout = TimeSpan.Zero;
128 lock(pending)
130 if (pending.Count > 0)
131 timeout = TimeSpan.Zero;
134 if (rlist.Count == 0 && wlist.Count == 0)
136 // Socket.Select throws an exception if all lists are empty;
137 // idiots.
138 if (timeout > TimeSpan.Zero)
139 Thread.Sleep((int)timeout.TotalMilliseconds);
141 else
143 Socket.Select((IList)rlist, (IList)wlist, null,
144 (int)timeout.TotalMilliseconds * 1000);
147 DateTime now = DateTime.Now;
148 foreach (Socket s in rlist)
149 r[s]();
150 foreach (Socket s in wlist)
151 w[s]();
152 foreach (Object cookie in ta.Keys)
154 TimeAction t = ta[cookie];
155 if (t.t <= now)
157 t.a();
158 ta.Remove(cookie);
162 Action[] nowpending;
163 lock(pending)
165 nowpending = pending.Values.ToArray();
166 pending.Clear();
168 // Console.WriteLine("NowPending: {0}", nowpending.Length);
169 foreach (Action a in nowpending)
170 a();