00001
00002
00003
00004
00005
00006
00007
00008 #include "wvistreamlist.h"
00009 #include "wvstringlist.h"
00010 #include "wvstreamsdebugger.h"
00011 #include "wvstrutils.h"
00012
00013 #ifndef _WIN32
00014 #include "wvfork.h"
00015 #endif
00016
00017 #ifdef HAVE_VALGRIND_MEMCHECK_H
00018 #include <valgrind/memcheck.h>
00019 #else
00020 #define RUNNING_ON_VALGRIND false
00021 #endif
00022
00023
00024
00025 #define STREAMTRACE 0
00026 #if STREAMTRACE
00027 # define TRACE(x, y...) fprintf(stderr, x, ## y)
00028 #else
00029 #ifndef _MSC_VER
00030 # define TRACE(x, y...)
00031 #else
00032 # define TRACE
00033 #endif
00034 #endif
00035
00036 WvIStreamList WvIStreamList::globallist;
00037
00038
00039 WvIStreamList::WvIStreamList():
00040 in_select(false)
00041 {
00042 readcb = writecb = exceptcb = 0;
00043 auto_prune = true;
00044 if (this == &globallist)
00045 {
00046 globalstream = this;
00047 #ifndef _WIN32
00048 add_wvfork_callback(WvIStreamList::onfork);
00049 #endif
00050 set_wsname("globallist");
00051 add_debugger_commands();
00052 }
00053 }
00054
00055
00056 WvIStreamList::~WvIStreamList()
00057 {
00058
00059 }
00060
00061
00062 bool WvIStreamList::isok() const
00063 {
00064 return true;
00065 }
00066
00067
00068 class BoolGuard
00069 {
00070 public:
00071 BoolGuard(bool &_guard_bool):
00072 guard_bool(_guard_bool)
00073 {
00074 assert(!guard_bool);
00075 guard_bool = true;
00076 }
00077 ~BoolGuard()
00078 {
00079 guard_bool = false;
00080 }
00081 private:
00082 bool &guard_bool;
00083 };
00084
00085
00086 bool WvIStreamList::pre_select(SelectInfo &si)
00087 {
00088
00089 bool already_sure = false;
00090 SelectRequest oldwant;
00091
00092 sure_thing.zap();
00093
00094 time_t alarmleft = alarm_remaining();
00095 if (alarmleft == 0)
00096 already_sure = true;
00097
00098 oldwant = si.wants;
00099
00100 Iter i(*this);
00101 for (i.rewind(); i.next(); )
00102 {
00103 IWvStream &s(*i);
00104
00105 si.wants = oldwant;
00106
00107 if (!s.isok())
00108 {
00109 already_sure = true;
00110 if (auto_prune)
00111 i.xunlink();
00112 continue;
00113 }
00114 else if (s.pre_select(si))
00115 {
00116
00117 sure_thing.append(&s, false, i.link->id);
00118 }
00119 }
00120
00121 if (alarmleft >= 0 && (alarmleft < si.msec_timeout || si.msec_timeout < 0))
00122 si.msec_timeout = alarmleft;
00123
00124 si.wants = oldwant;
00125 return already_sure || !sure_thing.isempty();
00126 }
00127
00128
00129 bool WvIStreamList::post_select(SelectInfo &si)
00130 {
00131
00132 bool one_dead = false;
00133 SelectRequest oldwant = si.wants;
00134
00135 Iter i(*this);
00136 for (i.rewind(); i.cur() && i.next(); )
00137 {
00138 IWvStream &s(*i);
00139 if (s.isok())
00140 {
00141 if (s.post_select(si))
00142 {
00143 sure_thing.unlink(&s);
00144 sure_thing.append(&s, false, i.link->id);
00145 }
00146 }
00147 else
00148 one_dead = true;
00149 }
00150
00151 si.wants = oldwant;
00152 return one_dead || !sure_thing.isempty();
00153 }
00154
00155
00156
00157 void WvIStreamList::execute()
00158 {
00159 static int level = 0;
00160 const char *id;
00161 level++;
00162
00163 WvStream::execute();
00164
00165 TRACE("\n%*sList@%p: (%d sure) ", level, "", this, sure_thing.count());
00166
00167 WvIStreamListBase::Iter i(sure_thing);
00168 for (i.rewind(); i.next(); )
00169 {
00170 #if STREAMTRACE
00171 WvIStreamListBase::Iter x(*this);
00172 if (!x.find(&i()))
00173 TRACE("Yikes! %p in sure_thing, but not in main list!\n",
00174 i.cur());
00175 #endif
00176 IWvStream &s(*i);
00177
00178 id = i.link->id;
00179
00180 TRACE("[%p:%s]", &s, id);
00181
00182 i.xunlink();
00183
00184 if (s.isok())
00185 {
00186 #if DEBUG
00187 if (!RUNNING_ON_VALGRIND)
00188 {
00189 WvString strace_node("%s: %s", s.wstype(), s.wsname());
00190 ::write(-1, strace_node, strace_node.len());
00191 }
00192 #endif
00193 s.callback();
00194 }
00195
00196
00197 i.rewind();
00198 }
00199
00200 sure_thing.zap();
00201
00202 level--;
00203 TRACE("[DONE %p]\n", this);
00204 }
00205
00206 #ifndef _WIN32
00207 void WvIStreamList::onfork(pid_t p)
00208 {
00209 if (p == 0)
00210 {
00211
00212 globallist.zap(false);
00213 }
00214 }
00215 #endif
00216
00217
00218 void WvIStreamList::add_debugger_commands()
00219 {
00220 WvStreamsDebugger::add_command("globallist", 0, debugger_globallist_run_cb, 0);
00221 }
00222
00223
00224 WvString WvIStreamList::debugger_globallist_run_cb(WvStringParm cmd,
00225 WvStringList &args,
00226 WvStreamsDebugger::ResultCallback result_cb, void *)
00227 {
00228 debugger_streams_display_header(cmd, result_cb);
00229 WvIStreamList::Iter i(globallist);
00230 for (i.rewind(); i.next(); )
00231 debugger_streams_maybe_display_one_stream(static_cast<WvStream *>(i.ptr()),
00232 cmd, args, result_cb);
00233
00234 return WvString::null;
00235 }
00236