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