132
|
1 /*******************************************************************************
|
|
2 copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
|
3 license: BSD style: $(LICENSE)
|
|
4 author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
|
5 *******************************************************************************/
|
|
6
|
|
7 module tango.io.selector.Selector;
|
|
8
|
|
9 /**
|
|
10 * A multiplexor of conduit I/O events.
|
|
11 *
|
|
12 * A Selector can wait for I/O events (Read, Write, etc.) for multiple
|
|
13 * conduits efficiently (i.e. without consuming CPU cycles).
|
|
14 *
|
|
15 * The Selector is an alias for your system's most efficient I/O multiplexor,
|
|
16 * which will be determined during compilation.
|
|
17 *
|
|
18 * To create a Selector you need to use the open() method and when you decide
|
|
19 * you no longer need it you should call its close() method to free any system
|
|
20 * resources it may be consuming. All selectors that need to free resources
|
|
21 * when close() is called also implement a destructor that automatically calls
|
|
22 * this method. This means that if you declare your selector instance with the
|
|
23 * 'auto' keyword you won't have to worry about doing it manually.
|
|
24 *
|
|
25 * Once you have open()'ed your selector you need to associate the conduits to
|
|
26 * it by using the register() method. This method receives the conduit and the
|
|
27 * events you want to track for it. For example, if you wanted to read from
|
|
28 * the conduit you would do:
|
|
29 *
|
|
30 * ---
|
|
31 * selector.register(conduit, Event.Read, myObject);
|
|
32 * ---
|
|
33 *
|
|
34 * This method also accepts an optional third parameter to associate a
|
|
35 * user-defined object to the conduit. These three parameters together define
|
|
36 * a SelectionKey, which is what you'll receive when the conduit is "selected"
|
|
37 * (i.e. receives an event).
|
|
38 *
|
|
39 * If you need to modify your conduit's registration you need to use the
|
|
40 * reregister() method, which works like register(), but expects to be passed
|
|
41 * a conduit that has already been associated to the selector:
|
|
42 *
|
|
43 * ---
|
|
44 * selector.reregister(conduit, Event.Write, myObject);
|
|
45 * ---
|
|
46 *
|
|
47 * If you need to remove a conduit from the selector you do it by calling
|
|
48 * unregister():
|
|
49 *
|
|
50 * ---
|
|
51 * selector.unregister(conduit);
|
|
52 * ---
|
|
53 *
|
|
54 * Once you are done setting up the conduits you will want to wait for I/O
|
|
55 * events for them. To do that you need to use the select() method. This
|
|
56 * method blocks until either one of the conduits is selected or the
|
|
57 * specified timeout is reached. Even though it has two different versions:
|
|
58 * a) select(); b) select(Interval); the first one is just the same as doing
|
|
59 * select(Interval.max). In that case we don't have a timeout and
|
|
60 * select() blocks until a conduit receives an event.
|
|
61 *
|
|
62 * When select() returns you will receive an integer; if this integer is
|
|
63 * bigger than 0, it indicates the number of conduits that have been selected.
|
|
64 * If this number is 0, the it means that the selector reached a timeout, and
|
|
65 * if it's -1, then it means that there was an error. A normal block that deals
|
|
66 * with the selection process would look like this:
|
|
67 *
|
|
68 * ---
|
|
69 * try
|
|
70 * {
|
|
71 * int eventCount = selector.select(10.0);
|
|
72 * if (eventCount > 0)
|
|
73 * {
|
|
74 * // Process the I/O events in the selected set
|
|
75 * }
|
|
76 * else if (eventCount == 0)
|
|
77 * {
|
|
78 * // Timeout
|
|
79 * }
|
|
80 * else if (eventCount == -1)
|
|
81 * {
|
|
82 * // Error
|
|
83 * }
|
|
84 * else
|
|
85 * {
|
|
86 * // Error: should never happen.
|
|
87 * }
|
|
88 * }
|
|
89 * catch (SelectorException e)
|
|
90 * {
|
|
91 * Stdout.format("Exception caught: {0}", e.toString()).newline();
|
|
92 * }
|
|
93 * ---
|
|
94 *
|
|
95 * Finally, to gather the events you need to iterate over the selector's
|
|
96 * selection set, which can be accessed via the selectedSet() method.
|
|
97 *
|
|
98 * ---
|
|
99 * foreach (SelectionKey key; selector.selectedSet())
|
|
100 * {
|
|
101 * if (key.isReadable())
|
|
102 * {
|
|
103 * // Read from conduit
|
|
104 * // [...]
|
|
105 * // Then register it for writing
|
|
106 * selector.reregister(key.conduit, Event.Write, key.attachment);
|
|
107 * }
|
|
108 *
|
|
109 * if (key.isWriteable())
|
|
110 * {
|
|
111 * // Write to conduit
|
|
112 * // [...]
|
|
113 * // Then register it for reading
|
|
114 * selector.reregister(key.conduit, Event.Read, key.attachment);
|
|
115 * }
|
|
116 *
|
|
117 * if (key.isError())
|
|
118 * {
|
|
119 * // Problem with conduit; remove it from selector
|
|
120 * selector.remove(conduit);
|
|
121 * }
|
|
122 * }
|
|
123 * ---
|
|
124 */
|
|
125 version (linux)
|
|
126 {
|
|
127 public import tango.io.selector.EpollSelector;
|
|
128
|
|
129 /**
|
|
130 * Default Selector for Linux.
|
|
131 */
|
|
132 alias EpollSelector Selector;
|
|
133 }
|
|
134 else version(Posix)
|
|
135 {
|
|
136 public import tango.io.selector.PollSelector;
|
|
137
|
|
138 /**
|
|
139 * Default Selector for POSIX-compatible platforms.
|
|
140 */
|
|
141 alias PollSelector Selector;
|
|
142 }
|
|
143 else
|
|
144 {
|
|
145 public import tango.io.selector.SelectSelector;
|
|
146
|
|
147 /**
|
|
148 * Default Selector for Windows.
|
|
149 */
|
|
150 alias SelectSelector Selector;
|
|
151 }
|