Branch data Line data Source code
1 : : // $Id: IOSource.cc 4771 2007-08-11 05:50:24Z vern $
2 : :
3 : : #include <sys/types.h>
4 : : #include <sys/time.h>
5 : : #include <unistd.h>
6 : : #include <assert.h>
7 : :
8 : : #include "util.h"
9 : : #include "IOSource.h"
10 : :
11 : 6 : IOSourceRegistry io_sources;
12 : :
13 : 3 : IOSourceRegistry::~IOSourceRegistry()
14 : : {
15 [ + + ][ # # ]: 5 : for ( SourceList::iterator i = sources.begin(); i != sources.end(); ++i )
16 : 2 : delete *i;
17 : :
18 : 3 : sources.clear();
19 : 3 : }
20 : :
21 : 0 : void IOSourceRegistry::RemoveAll()
22 : : {
23 : : // We're cheating a bit here ...
24 : 0 : dont_counts = sources.size();
25 : 0 : }
26 : :
27 : 21349 : IOSource* IOSourceRegistry::FindSoonest(double* ts)
28 : : {
29 : : // Remove sources which have gone dry. For simplicity, we only
30 : : // remove at most one each time.
31 [ + + ]: 64046 : for ( SourceList::iterator i = sources.begin();
32 : : i != sources.end(); ++i )
33 [ + + ]: 42698 : if ( ! (*i)->src->IsOpen() )
34 : : {
35 : 1 : delete *i;
36 : 1 : sources.erase(i);
37 : 1 : break;
38 : : }
39 : :
40 : : // Ideally, we would always call select on the fds to see which
41 : : // are ready, and return the soonest. Unfortunately, that'd mean
42 : : // one select-call per packet, which we can't afford in high-volume
43 : : // environments. Thus, we call select only every SELECT_FREQUENCY
44 : : // call (or if all sources report that they are dry).
45 : :
46 : 21349 : ++call_count;
47 : :
48 : 21349 : IOSource* soonest_src = 0;
49 : 21349 : double soonest_ts = 1e20;
50 : 21349 : double soonest_local_network_time = 1e20;
51 : 21349 : bool all_idle = true;
52 : :
53 : : // Find soonest source of those which tell us they have something to
54 : : // process.
55 [ + + ]: 64046 : for ( SourceList::iterator i = sources.begin(); i != sources.end(); ++i )
56 : : {
57 [ + + ]: 42697 : if ( ! (*i)->src->IsIdle() )
58 : : {
59 : 21348 : all_idle = false;
60 : 21348 : double local_network_time = 0;
61 : 21348 : double ts = (*i)->src->NextTimestamp(&local_network_time);
62 [ + + + - ]: 21348 : if ( ts > 0 && ts < soonest_ts )
63 : : {
64 : 21347 : soonest_ts = ts;
65 : 21347 : soonest_src = (*i)->src;
66 : : soonest_local_network_time =
67 : : local_network_time ?
68 [ - + ]: 21347 : local_network_time : ts;
69 : : }
70 : : }
71 : : }
72 : :
73 : : // If we found one and aren't going to select this time,
74 : : // return it.
75 : 21349 : int maxx = 0;
76 : :
77 [ + + ][ + + ]: 21349 : if ( soonest_src && (call_count % SELECT_FREQUENCY) != 0 )
78 : 20494 : goto finished;
79 : :
80 : : // Select on the join of all file descriptors.
81 : : fd_set fd_read, fd_write, fd_except;
82 : :
83 : 855 : FD_ZERO(&fd_read);
84 : 855 : FD_ZERO(&fd_write);
85 : 855 : FD_ZERO(&fd_except);
86 : :
87 [ + + ]: 2564 : for ( SourceList::iterator i = sources.begin();
88 : : i != sources.end(); ++i )
89 : : {
90 : 1709 : Source* src = (*i);
91 : :
92 [ + + ]: 1709 : if ( ! src->src->IsIdle() )
93 : : // No need to select on sources which we know to
94 : : // be ready.
95 : 853 : continue;
96 : :
97 : 856 : src->fd_read = src->fd_write = src->fd_except = 0;
98 : 856 : src->src->GetFds(&src->fd_read, &src->fd_write, &src->fd_except);
99 : :
100 : 856 : FD_SET(src->fd_read, &fd_read);
101 : 856 : FD_SET(src->fd_write, &fd_write);
102 : 856 : FD_SET(src->fd_except, &fd_except);
103 : :
104 : 856 : maxx = max(src->fd_read, maxx);
105 : 856 : maxx = max(src->fd_write, maxx);
106 : 856 : maxx = max(src->fd_except, maxx);
107 : : }
108 : :
109 : : // We can't block indefinitely even when all sources are dry:
110 : : // we're doing some IOSource-independent stuff in the main loop,
111 : : // so we need to return from time to time. (Instead of no time-out
112 : : // at all, we use a very small one. This lets FreeBSD trigger a
113 : : // BPF buffer switch on the next read when the hold buffer is empty
114 : : // while the store buffer isn't filled yet.
115 : :
116 : : struct timeval timeout;
117 : :
118 [ + + ]: 855 : if ( all_idle )
119 : : {
120 : : // Interesting: when all sources are dry, simply sleeping a
121 : : // bit *without* watching for any fd becoming ready may
122 : : // decrease CPU load. I guess that's because it allows
123 : : // the kernel's packet buffers to fill. - Robin
124 : 1 : timeout.tv_sec = 0;
125 : 1 : timeout.tv_usec = 20; // SELECT_TIMEOUT;
126 : 1 : select(0, 0, 0, 0, &timeout);
127 : : }
128 : :
129 [ - + ]: 855 : if ( ! maxx )
130 : : // No selectable fd at all.
131 : 0 : goto finished;
132 : :
133 : 855 : timeout.tv_sec = 0;
134 : 855 : timeout.tv_usec = 0;
135 : :
136 [ + + ]: 855 : if ( select(maxx + 1, &fd_read, &fd_write, &fd_except, &timeout) > 0 )
137 : : { // Find soonest.
138 [ + + ]: 2534 : for ( SourceList::iterator i = sources.begin();
139 : : i != sources.end(); ++i )
140 : : {
141 : 1689 : Source* src = (*i);
142 : :
143 [ + + ]: 1689 : if ( ! src->src->IsIdle() )
144 : 843 : continue;
145 : :
146 [ + + ][ - + ]: 846 : if ( FD_ISSET(src->fd_read, &fd_read) ||
[ # # ][ + - ]
147 : : FD_ISSET(src->fd_write, &fd_write) ||
148 : : FD_ISSET(src->fd_except, &fd_except) )
149 : : {
150 : 846 : double local_network_time = 0;
151 : 846 : double ts = src->src->NextTimestamp(&local_network_time);
152 [ - + # # ]: 846 : if ( ts > 0.0 && ts < soonest_ts )
153 : : {
154 : 0 : soonest_ts = ts;
155 : 0 : soonest_src = src->src;
156 : : soonest_local_network_time =
157 : : local_network_time ?
158 [ # # ]: 0 : local_network_time : ts;
159 : : }
160 : : }
161 : : }
162 : : }
163 : :
164 : 21349 : finished:
165 : 21349 : *ts = soonest_local_network_time;
166 : 21349 : return soonest_src;
167 : : }
168 : :
169 : 3 : void IOSourceRegistry::Register(IOSource* src, bool dont_count)
170 : : {
171 : 3 : Source* s = new Source;
172 : 3 : s->src = src;
173 [ + + ]: 3 : if ( dont_count )
174 : 2 : ++dont_counts;
175 : 3 : return sources.push_back(s);
176 [ + - ][ + - ]: 6 : }
|