wvistreamlist.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvIStreamList holds a list of IWvStream objects -- and its select() and
00006  * callback() functions know how to handle multiple simultaneous streams.
00007  */
00008 #include "wvistreamlist.h"
00009 
00010 #ifndef _WIN32
00011 #include "wvfork.h"
00012 #endif
00013 
00014 // enable this to add some read/write trace messages (this can be VERY
00015 // verbose)
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     // nothing to do
00047 }
00048 
00049 
00050 bool WvIStreamList::isok() const
00051 {
00052     return true;  // "error" condition on a list is undefined
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     //BoolGuard guard(in_select);
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             // printf("pre_select sure_thing: '%s'\n", i.link->id);
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     //BoolGuard guard(in_select);
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); // don't add it twice!
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 // distribute the callback() request to all children that select 'true'
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         // list might have changed!
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         // this is a child process: don't inherit the global streamlist
00197         globallist.zap(false);
00198     }
00199 }
00200 #endif

Generated on Mon Feb 5 10:54:29 2007 for WvStreams by  doxygen 1.5.1