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 #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 // enable this to add some read/write trace messages (this can be VERY
00024 // verbose)
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     // nothing to do
00059 }
00060 
00061 
00062 bool WvIStreamList::isok() const
00063 {
00064     return true;  // "error" condition on a list is undefined
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     //BoolGuard guard(in_select);
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             // printf("pre_select sure_thing: '%s'\n", i.link->id);
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     //BoolGuard guard(in_select);
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); // don't add it twice!
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 // distribute the callback() request to all children that select 'true'
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         // list might have changed!
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         // this is a child process: don't inherit the global streamlist
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 

Generated on Fri Oct 5 18:20:28 2007 for WvStreams by  doxygen 1.5.3