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