none
This commit is contained in:
commit
75ba4a2169
@ -67,14 +67,6 @@ static AspellApi aapi;
|
||||
badnames += #NM + string(" "); \
|
||||
}
|
||||
|
||||
static const char *aspell_progs[] = {
|
||||
#ifdef ASPELL_PROG
|
||||
ASPELL_PROG ,
|
||||
#endif
|
||||
"/usr/local/bin/aspell",
|
||||
"/usr/bin/aspell"
|
||||
};
|
||||
static const unsigned int naspellprogs = sizeof(aspell_progs) / sizeof(char*);
|
||||
static const char *aspell_lib_suffixes[] = {
|
||||
".so",
|
||||
".so.15",
|
||||
@ -137,12 +129,18 @@ bool Aspell::init(string &reason)
|
||||
}
|
||||
|
||||
m_data = new AspellData;
|
||||
for (unsigned int i = 0; i < naspellprogs; i++) {
|
||||
if (access(aspell_progs[i], X_OK) == 0) {
|
||||
m_data->m_exec = aspell_progs[i];
|
||||
break;
|
||||
}
|
||||
|
||||
const char *aspell_prog_from_env = getenv("ASPELL_PROG");
|
||||
if (aspell_prog_from_env && access(aspell_prog_from_env, X_OK) == 0) {
|
||||
m_data->m_exec = aspell_prog_from_env;
|
||||
#ifdef ASPELL_PROG
|
||||
} else if (access(ASPELL_PROG, X_OK) == 0) {
|
||||
m_data->m_exec = ASPELL_PROG;
|
||||
#endif // ASPELL_PROG
|
||||
} else {
|
||||
ExecCmd::which("aspell", m_data->m_exec);
|
||||
}
|
||||
|
||||
if (m_data->m_exec.empty()) {
|
||||
reason = "aspell program not found or not executable";
|
||||
deleteZ(m_data);
|
||||
@ -153,9 +151,8 @@ bool Aspell::init(string &reason)
|
||||
// be clever with ASPELL_PROG.
|
||||
vector<string> libdirs;
|
||||
libdirs.push_back(LIBDIR);
|
||||
#ifdef ASPELL_PROG
|
||||
// The aspell library has to live under the same prefix as the
|
||||
// aspell program.
|
||||
// If not in the standard place, the aspell library has to live
|
||||
// under the same prefix as the aspell program.
|
||||
{
|
||||
string aspellPrefix = path_getfather(path_getfather(m_data->m_exec));
|
||||
// This would probably require some more tweaking on solaris/irix etc.
|
||||
@ -164,7 +161,6 @@ bool Aspell::init(string &reason)
|
||||
if (libaspell != LIBDIR)
|
||||
libdirs.push_back(libaspell);
|
||||
}
|
||||
#endif
|
||||
|
||||
reason = "Could not open shared library ";
|
||||
for (vector<string>::iterator it = libdirs.begin();
|
||||
|
||||
@ -17,6 +17,12 @@ autom4*
|
||||
config.cache
|
||||
config.log
|
||||
config.status
|
||||
doc/user/usermanual.aux
|
||||
doc/user/usermanual.log
|
||||
doc/user/usermanual.out
|
||||
doc/user/usermanual.pdf
|
||||
doc/user/usermanual.tex-pdf
|
||||
doc/user/usermanual.tex-pdf-tmp
|
||||
excludefile
|
||||
kde/recoll_applet
|
||||
lib/librcl.a
|
||||
|
||||
@ -437,6 +437,7 @@ utils/netcon.cpp
|
||||
utils/netcon.h
|
||||
utils/pathut.cpp
|
||||
utils/pathut.h
|
||||
utils/ptmutex.h
|
||||
utils/pxattr.cpp
|
||||
utils/pxattr.h
|
||||
utils/readfile.cpp
|
||||
|
||||
@ -72,7 +72,7 @@ void startManual(const string& helpindex)
|
||||
mainWindow->startManual(helpindex);
|
||||
}
|
||||
|
||||
bool maybeOpenDb(string &reason, bool force)
|
||||
bool maybeOpenDb(string &reason, bool force, bool *maindberror)
|
||||
{
|
||||
if (!rcldb) {
|
||||
reason = "Internal error: db not created";
|
||||
@ -87,9 +87,13 @@ bool maybeOpenDb(string &reason, bool force)
|
||||
LOGDEB(("main: adding [%s]\n", it->c_str()));
|
||||
rcldb->addQueryDb(*it);
|
||||
}
|
||||
if (!rcldb->isopen() && !rcldb->open(Rcl::Db::DbRO)) {
|
||||
Rcl::Db::OpenError error;
|
||||
if (!rcldb->isopen() && !rcldb->open(Rcl::Db::DbRO, &error)) {
|
||||
reason = "Could not open database in " +
|
||||
theconfig->getDbDir() + " wait for indexing to complete?";
|
||||
if (maindberror) {
|
||||
*maindberror = (error == Rcl::Db::DbOpenMainDb) ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
rcldb->setAbstractParams(-1, prefs.syntAbsLen, prefs.syntAbsCtx);
|
||||
@ -114,7 +118,7 @@ static void recollCleanup()
|
||||
LOGDEB2(("recollCleanup: closing database\n"));
|
||||
deleteZ(rcldb);
|
||||
deleteZ(theconfig);
|
||||
deleteZ(thestableconfig);
|
||||
// deleteZ(thestableconfig);
|
||||
#ifdef RCL_USE_ASPELL
|
||||
deleteZ(aspell);
|
||||
#endif
|
||||
|
||||
@ -345,25 +345,31 @@ void RclMain::initDbOpen()
|
||||
bool needindexconfig = false;
|
||||
bool nodb = false;
|
||||
string reason;
|
||||
if (!maybeOpenDb(reason)) {
|
||||
bool maindberror;
|
||||
if (!maybeOpenDb(reason, true, &maindberror)) {
|
||||
nodb = true;
|
||||
switch (QMessageBox::
|
||||
question
|
||||
(this, "Recoll",
|
||||
qApp->translate("Main", "Could not open database in ") +
|
||||
QString::fromLocal8Bit(theconfig->getDbDir().c_str()) +
|
||||
qApp->translate("Main",
|
||||
".\n"
|
||||
"Click Cancel if you want to edit the configuration file before indexing starts, or Ok to let it proceed."),
|
||||
"Ok", "Cancel", 0, 0)) {
|
||||
if (maindberror) {
|
||||
switch (QMessageBox::
|
||||
question
|
||||
(this, "Recoll",
|
||||
qApp->translate("Main", "Could not open database in ") +
|
||||
QString::fromLocal8Bit(theconfig->getDbDir().c_str()) +
|
||||
qApp->translate("Main",
|
||||
".\n"
|
||||
"Click Cancel if you want to edit the configuration file before indexing starts, or Ok to let it proceed."),
|
||||
"Ok", "Cancel", 0, 0)) {
|
||||
|
||||
case 0: // Ok: indexing is going to start.
|
||||
start_indexing(true);
|
||||
break;
|
||||
case 0: // Ok: indexing is going to start.
|
||||
start_indexing(true);
|
||||
break;
|
||||
|
||||
case 1: // Cancel
|
||||
needindexconfig = true;
|
||||
break;
|
||||
case 1: // Cancel
|
||||
needindexconfig = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Could not open external index. Db not open. Check external indexes list."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,8 @@
|
||||
// Misc declarations in need of sharing between the UI files
|
||||
|
||||
// Open the database if needed. We now force a close/open by default
|
||||
extern bool maybeOpenDb(std::string &reason, bool force = true);
|
||||
extern bool maybeOpenDb(std::string &reason, bool force = true,
|
||||
bool *maindberror = 0);
|
||||
|
||||
/** Retrieve configured stemming languages */
|
||||
bool getStemLangs(list<string>& langs);
|
||||
|
||||
@ -534,8 +534,11 @@ list<string> Db::getStemmerNames()
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Db::open(OpenMode mode)
|
||||
bool Db::open(OpenMode mode, OpenError *error)
|
||||
{
|
||||
if (error)
|
||||
*error = DbOpenMainDb;
|
||||
|
||||
if (m_ndb == 0 || m_config == 0) {
|
||||
m_reason = "Null configuration or Xapian Db";
|
||||
return false;
|
||||
@ -586,12 +589,17 @@ bool Db::open(OpenMode mode)
|
||||
m_ndb->xrdb = Xapian::Database(dir);
|
||||
for (list<string>::iterator it = m_extraDbs.begin();
|
||||
it != m_extraDbs.end(); it++) {
|
||||
if (error)
|
||||
*error = DbOpenExtraDb;
|
||||
LOGDEB(("Db::Open: adding query db [%s]\n", it->c_str()));
|
||||
// Used to be non-fatal (1.13 and older) but I can't see why
|
||||
// An error here used to be non-fatal (1.13 and older)
|
||||
// but I can't see why
|
||||
m_ndb->xrdb.add_database(Xapian::Database(*it));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
*error = DbOpenMainDb;
|
||||
|
||||
// Check index format version. Must not try to check a just created or
|
||||
// truncated db
|
||||
@ -608,6 +616,8 @@ bool Db::open(OpenMode mode)
|
||||
m_mode = mode;
|
||||
m_ndb->m_isopen = true;
|
||||
m_basedir = dir;
|
||||
if (error)
|
||||
*error = DbOpenNoError;
|
||||
return true;
|
||||
} XCATCHERROR(ermsg);
|
||||
|
||||
|
||||
@ -95,7 +95,8 @@ class Db {
|
||||
~Db();
|
||||
|
||||
enum OpenMode {DbRO, DbUpd, DbTrunc};
|
||||
bool open(OpenMode mode);
|
||||
enum OpenError {DbOpenNoError, DbOpenMainDb, DbOpenExtraDb};
|
||||
bool open(OpenMode mode, OpenError *error = 0);
|
||||
bool close();
|
||||
bool isopen();
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
depth = ..
|
||||
include $(depth)/mk/sysconf
|
||||
|
||||
PROGS = trcopyfile trcircache trmd5 trreadfile trfileudi trconftree \
|
||||
wipedir smallut \
|
||||
trfstreewalk trpathut \
|
||||
transcode trbase64 \
|
||||
trmimeparse trexecmd utf8iter idfile
|
||||
PROGS = trnetcon trcopyfile trcircache trmd5 trreadfile trfileudi trconftree \
|
||||
wipedir smallut \
|
||||
trfstreewalk trpathut \
|
||||
transcode trbase64 \
|
||||
trmimeparse trexecmd utf8iter idfile
|
||||
|
||||
all: $(PROGS) $(BIGLIB)
|
||||
|
||||
@ -54,6 +54,12 @@ trpathut : $(PATHUT_OBJS)
|
||||
trpathut.o : pathut.cpp pathut.h
|
||||
$(CXX) -o trpathut.o -c $(ALL_CXXFLAGS) -DTEST_PATHUT pathut.cpp
|
||||
|
||||
NETCON_OBJS= trnetcon.o $(BIGLIB)
|
||||
trnetcon : $(NETCON_OBJS)
|
||||
$(CXX) $(ALL_CXXFLAGS) -o trnetcon $(NETCON_OBJS) $(LIBICONV) $(LIBSYS)
|
||||
trnetcon.o : netcon.cpp netcon.h
|
||||
$(CXX) -o trnetcon.o -c $(ALL_CXXFLAGS) -DTEST_NETCON netcon.cpp
|
||||
|
||||
FILEUDI_OBJS= trfileudi.o $(BIGLIB)
|
||||
trfileudi : $(FILEUDI_OBJS)
|
||||
$(CXX) $(ALL_CXXFLAGS) -o trfileudi $(FILEUDI_OBJS)
|
||||
|
||||
@ -76,7 +76,7 @@ static bool inflateToDynBuf(void *inp, UINT inlen, void **outpp, UINT *outlenp);
|
||||
// Entry header.
|
||||
// 3 x 32 bits sizes as hex integers + 1 x 16 bits flag + at least 1 zero
|
||||
// 15 + 3x(9) + 3 + 1 = 46
|
||||
const char *headerformat = "circacheSizes = %x %x %x %hx";
|
||||
static const char *headerformat = "circacheSizes = %x %x %x %hx";
|
||||
#define CIRCACHE_HEADER_SIZE 64
|
||||
|
||||
class EntryHeaderData {
|
||||
|
||||
@ -335,7 +335,11 @@ DebugLog *getdbl()
|
||||
}
|
||||
DebugLog *dbl;
|
||||
if (!(dbl = (DebugLog *)pthread_getspecific(dbl_key))) {
|
||||
dbl = new DebugLog;
|
||||
if ((dbl = new DebugLog) == 0) {
|
||||
fprintf(stderr, "debuglog: new DebugLog returned 0! ");
|
||||
abort();
|
||||
}
|
||||
|
||||
dbl->setwriter(theWriter);
|
||||
initfiles();
|
||||
status = pthread_setspecific(dbl_key, dbl);
|
||||
|
||||
@ -313,16 +313,9 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// The netcon selectloop that doexec() uses for reading/writing would
|
||||
// be complicated to render thread-safe. Use locking to ensure only
|
||||
// one thread in there
|
||||
static PTMutexInit o_lock;
|
||||
|
||||
int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
const string *input, string *output)
|
||||
{
|
||||
// Only one thread allowed in here...
|
||||
PTMutexLocker locker(o_lock);
|
||||
|
||||
if (startExec(cmd, args, input != 0, output != 0) < 0) {
|
||||
return -1;
|
||||
@ -330,7 +323,7 @@ int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
|
||||
// Cleanup in case we return early
|
||||
ExecCmdRsrc e(this);
|
||||
|
||||
SelectLoop myloop;
|
||||
int ret = 0;
|
||||
if (input || output) {
|
||||
// Setup output
|
||||
@ -342,7 +335,7 @@ int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
}
|
||||
oclicon->setcallback(RefCntr<NetconWorker>
|
||||
(new ExecReader(output, m_advise)));
|
||||
Netcon::addselcon(m_fromcmd, Netcon::NETCONPOLL_READ);
|
||||
myloop.addselcon(m_fromcmd, Netcon::NETCONPOLL_READ);
|
||||
// Give up ownership
|
||||
m_fromcmd.release();
|
||||
}
|
||||
@ -355,14 +348,14 @@ int ExecCmd::doexec(const string &cmd, const list<string>& args,
|
||||
}
|
||||
iclicon->setcallback(RefCntr<NetconWorker>
|
||||
(new ExecWriter(input, m_provide)));
|
||||
Netcon::addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE);
|
||||
myloop.addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE);
|
||||
// Give up ownership
|
||||
m_tocmd.release();
|
||||
}
|
||||
|
||||
// Do the actual reading/writing/waiting
|
||||
Netcon::setperiodichandler(0, 0, m_timeoutMs);
|
||||
while ((ret = Netcon::selectloop()) > 0) {
|
||||
myloop.setperiodichandler(0, 0, m_timeoutMs);
|
||||
while ((ret = myloop.doLoop()) > 0) {
|
||||
LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret));
|
||||
if (m_advise)
|
||||
m_advise->newData(0);
|
||||
|
||||
@ -83,46 +83,23 @@ int Netcon::select1(int fd, int timeo, int write)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// The select loop mechanism allows several netcons to be used for io
|
||||
// in a program without blocking as long as there is data to be read
|
||||
// or written.
|
||||
|
||||
// Set by client callback to tell selectloop to return.
|
||||
bool Netcon::o_selectloopDoReturn;
|
||||
int Netcon::o_selectloopReturnValue;
|
||||
|
||||
// Other static data for the selectloop mecanism
|
||||
// Could be declared as static members, but I don't see any advantage
|
||||
// to it as all code in this file is in Netcon:: anyway.
|
||||
|
||||
// Map of NetconP indexed by fd
|
||||
static map<int, NetconP> polldata;
|
||||
|
||||
// The last time we did the periodic thing
|
||||
static struct timeval lasthdlcall;
|
||||
// The call back function and its parameter
|
||||
static int (*periodichandler)(void *);
|
||||
static void *periodicparam;
|
||||
// The periodic interval
|
||||
static int periodicmillis;
|
||||
|
||||
void Netcon::setperiodichandler(int (*handler)(void *), void *p, int ms)
|
||||
void SelectLoop::setperiodichandler(int (*handler)(void *), void *p, int ms)
|
||||
{
|
||||
periodichandler = handler;
|
||||
periodicparam = p;
|
||||
periodicmillis = ms;
|
||||
if (periodicmillis > 0)
|
||||
gettimeofday(&lasthdlcall, 0);
|
||||
m_periodichandler = handler;
|
||||
m_periodicparam = p;
|
||||
m_periodicmillis = ms;
|
||||
if (m_periodicmillis > 0)
|
||||
gettimeofday(&m_lasthdlcall, 0);
|
||||
}
|
||||
|
||||
// Compute the appropriate timeout so that the select call returns in
|
||||
// time to call the periodic routine.
|
||||
static void periodictimeout(struct timeval *tv)
|
||||
void SelectLoop::periodictimeout(struct timeval *tv)
|
||||
{
|
||||
// If periodic not set, the select call times out and we loop
|
||||
// after a very long time (we'd need to pass NULL to select for an
|
||||
// infinite wait, and I'm too lazy to handle it)
|
||||
if (periodicmillis <= 0) {
|
||||
if (m_periodicmillis <= 0) {
|
||||
tv->tv_sec = 10000;
|
||||
tv->tv_usec = 0;
|
||||
return;
|
||||
@ -130,7 +107,7 @@ static void periodictimeout(struct timeval *tv)
|
||||
|
||||
struct timeval mtv;
|
||||
gettimeofday(&mtv, 0);
|
||||
int millis = periodicmillis - MILLIS(lasthdlcall, mtv);
|
||||
int millis = m_periodicmillis - MILLIS(m_lasthdlcall, mtv);
|
||||
|
||||
// millis <= 0 means we should have already done the thing. *dont* set the
|
||||
// tv to 0, which means no timeout at all !
|
||||
@ -142,50 +119,49 @@ static void periodictimeout(struct timeval *tv)
|
||||
|
||||
// Check if it's time to call the handler. selectloop will return to
|
||||
// caller if it or we return 0
|
||||
static int maybecallperiodic()
|
||||
int SelectLoop::maybecallperiodic()
|
||||
{
|
||||
if (periodicmillis <= 0)
|
||||
if (m_periodicmillis <= 0)
|
||||
return 1;
|
||||
struct timeval mtv;
|
||||
gettimeofday(&mtv, 0);
|
||||
int millis = periodicmillis - MILLIS(lasthdlcall, mtv);
|
||||
int millis = m_periodicmillis - MILLIS(m_lasthdlcall, mtv);
|
||||
if (millis <= 0) {
|
||||
gettimeofday(&lasthdlcall, 0);
|
||||
if (periodichandler)
|
||||
return periodichandler(periodicparam);
|
||||
gettimeofday(&m_lasthdlcall, 0);
|
||||
if (m_periodichandler)
|
||||
return m_periodichandler(m_periodicparam);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Netcon::selectloop()
|
||||
int SelectLoop::doLoop()
|
||||
{
|
||||
static int placetostart;
|
||||
for (;;) {
|
||||
if (o_selectloopDoReturn) {
|
||||
o_selectloopDoReturn = false;
|
||||
if (m_selectloopDoReturn) {
|
||||
m_selectloopDoReturn = false;
|
||||
LOGDEB(("Netcon::selectloop: returning on request\n"));
|
||||
return o_selectloopReturnValue;
|
||||
return m_selectloopReturnValue;
|
||||
}
|
||||
int nfds;
|
||||
fd_set rd, wd;
|
||||
FD_ZERO(&rd);
|
||||
FD_ZERO(&wd);
|
||||
|
||||
// Look for all descriptors in the map and set up the read and
|
||||
// write fd_sets for select()
|
||||
// Walk the netcon map and set up the read and write fd_sets
|
||||
// for select()
|
||||
nfds = 0;
|
||||
for (map<int,NetconP>::iterator it = polldata.begin();
|
||||
it != polldata.end(); it++) {
|
||||
for (map<int,NetconP>::iterator it = m_polldata.begin();
|
||||
it != m_polldata.end(); it++) {
|
||||
NetconP &pll = it->second;
|
||||
int fd = it->first;
|
||||
LOGDEB2(("Selectloop: fd %d flags 0x%x\n",fd, pll->m_wantedEvents));
|
||||
if (pll->m_wantedEvents & NETCONPOLL_READ) {
|
||||
if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) {
|
||||
FD_SET(fd, &rd);
|
||||
nfds = MAX(nfds, fd + 1);
|
||||
}
|
||||
if (pll->m_wantedEvents & NETCONPOLL_WRITE) {
|
||||
if (pll->m_wantedEvents & Netcon::NETCONPOLL_WRITE) {
|
||||
FD_SET(fd, &wd);
|
||||
nfds = MAX(nfds, fd + 1);
|
||||
}
|
||||
@ -199,7 +175,7 @@ int Netcon::selectloop()
|
||||
|
||||
// Just in case there would still be open fds in there
|
||||
// (with no r/w flags set). Should not be needed, but safer
|
||||
polldata.clear();
|
||||
m_polldata.clear();
|
||||
LOGDEB1(("Netcon::selectloop: no fds\n"));
|
||||
return 0;
|
||||
}
|
||||
@ -217,7 +193,7 @@ int Netcon::selectloop()
|
||||
LOGSYSERR("Netcon::selectloop", "select", "");
|
||||
return -1;
|
||||
}
|
||||
if (periodicmillis > 0)
|
||||
if (m_periodicmillis > 0)
|
||||
if (maybecallperiodic() <= 0)
|
||||
return 1;
|
||||
|
||||
@ -231,10 +207,10 @@ int Netcon::selectloop()
|
||||
// map may change between 2 sweeps, so that we'd have to be smart
|
||||
// with the iterator. As the cost per unused fd is low (just 2 bit
|
||||
// flag tests), we keep it like this for now
|
||||
if (placetostart >= nfds)
|
||||
placetostart = 0;
|
||||
if (m_placetostart >= nfds)
|
||||
m_placetostart = 0;
|
||||
int i, fd;
|
||||
for (i = 0, fd = placetostart; i < nfds;i++, fd++) {
|
||||
for (i = 0, fd = m_placetostart; i < nfds;i++, fd++) {
|
||||
if (fd >= nfds)
|
||||
fd = 0;
|
||||
|
||||
@ -247,53 +223,56 @@ int Netcon::selectloop()
|
||||
if (none)
|
||||
continue;
|
||||
|
||||
map<int,NetconP>::iterator it = polldata.find(fd);
|
||||
if (it == polldata.end()) {
|
||||
map<int,NetconP>::iterator it = m_polldata.find(fd);
|
||||
if (it == m_polldata.end()) {
|
||||
/// This should not happen actually
|
||||
LOGDEB2(("Netcon::selectloop: fd %d not found\n", fd));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Next start will be one beyond last serviced (modulo nfds)
|
||||
placetostart = fd + 1;
|
||||
m_placetostart = fd + 1;
|
||||
NetconP &pll = it->second;
|
||||
if (canread && pll->cando(NETCONPOLL_READ) <= 0)
|
||||
pll->m_wantedEvents &= ~NETCONPOLL_READ;
|
||||
if (canwrite && pll->cando(NETCONPOLL_WRITE) <= 0)
|
||||
pll->m_wantedEvents &= ~NETCONPOLL_WRITE;
|
||||
if (!(pll->m_wantedEvents & (NETCONPOLL_WRITE|NETCONPOLL_READ))) {
|
||||
if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0)
|
||||
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_READ;
|
||||
if (canwrite && pll->cando(Netcon::NETCONPOLL_WRITE) <= 0)
|
||||
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_WRITE;
|
||||
if (!(pll->m_wantedEvents & (Netcon::NETCONPOLL_WRITE|Netcon::NETCONPOLL_READ))) {
|
||||
LOGDEB0(("Netcon::selectloop: fd %d has 0x%x mask, erasing\n",
|
||||
it->first, it->second->m_wantedEvents));
|
||||
polldata.erase(it);
|
||||
m_polldata.erase(it);
|
||||
}
|
||||
} // fd sweep
|
||||
|
||||
} // forever loop
|
||||
LOGERR(("Netcon::selectloop: got out of loop !\n"));
|
||||
LOGERR(("SelectLoop::doLoop: got out of loop !\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add a connection to the monitored set.
|
||||
int Netcon::addselcon(NetconP con, int events)
|
||||
int SelectLoop::addselcon(NetconP con, int events)
|
||||
{
|
||||
if (con.isNull()) return -1;
|
||||
LOGDEB1(("Netcon::addselcon: fd %d\n", con->m_fd));
|
||||
con->set_nonblock(1);
|
||||
con->setselevents(events);
|
||||
polldata[con->m_fd] = con;
|
||||
m_polldata[con->m_fd] = con;
|
||||
con->setloop(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove a connection from the monitored set.
|
||||
int Netcon::remselcon(NetconP con)
|
||||
int SelectLoop::remselcon(NetconP con)
|
||||
{
|
||||
if (con.isNull()) return -1;
|
||||
LOGDEB1(("Netcon::remselcon: fd %d\n", con->m_fd));
|
||||
map<int,NetconP>::iterator it = polldata.find(con->m_fd);
|
||||
if (it == polldata.end()) {
|
||||
map<int,NetconP>::iterator it = m_polldata.find(con->m_fd);
|
||||
if (it == m_polldata.end()) {
|
||||
LOGDEB1(("Netcon::remselcon: con not found for fd %d\n", con->m_fd));
|
||||
return -1;
|
||||
}
|
||||
polldata.erase(it);
|
||||
con->setloop(0);
|
||||
m_polldata.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -969,7 +948,7 @@ int main(int argc, char **argv)
|
||||
argv++;
|
||||
}
|
||||
DebugLog::setfilename("stderr");
|
||||
DebugLog::getdbl()->setloglevel(DEBINFO);
|
||||
DebugLog::getdbl()->setloglevel(DEBDEB2);
|
||||
|
||||
if (op_flags & OPT_c) {
|
||||
if (argc != 2) {
|
||||
@ -1032,7 +1011,8 @@ public:
|
||||
}
|
||||
if (m_count >= 10) {
|
||||
fprintf(stderr, "Did 10, enough\n");
|
||||
Netcon::selectloopReturn(0);
|
||||
if (con->getloop())
|
||||
con->getloop()->loopReturn(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1077,9 +1057,10 @@ int trycli(char *host, char *serv)
|
||||
RefCntr<NetconWorker> worker =
|
||||
RefCntr<NetconWorker>(new CliNetconWorker());
|
||||
clicon->setcallback(worker);
|
||||
Netcon::addselcon(con, Netcon::NETCONPOLL_WRITE);
|
||||
SelectLoop myloop;
|
||||
myloop.addselcon(con, Netcon::NETCONPOLL_WRITE);
|
||||
fprintf(stderr, "client ready\n");
|
||||
int ret = Netcon::selectloop();
|
||||
int ret = myloop.doLoop();
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "selectloop failed\n");
|
||||
exit(1);
|
||||
@ -1130,6 +1111,11 @@ private:
|
||||
};
|
||||
|
||||
class MyNetconServLis : public NetconServLis {
|
||||
public:
|
||||
MyNetconServLis(SelectLoop &loop)
|
||||
: NetconServLis(), m_loop(loop)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
int cando(Netcon::Event reason) {
|
||||
NetconServCon *con = accept();
|
||||
@ -1138,9 +1124,10 @@ protected:
|
||||
RefCntr<NetconWorker> worker =
|
||||
RefCntr<NetconWorker>(new ServNetconWorker());
|
||||
con->setcallback(worker);
|
||||
addselcon(NetconP(con), NETCONPOLL_READ);
|
||||
m_loop.addselcon(NetconP(con), NETCONPOLL_READ);
|
||||
return 1;
|
||||
}
|
||||
SelectLoop& m_loop;
|
||||
};
|
||||
|
||||
NetconP lis;
|
||||
@ -1158,7 +1145,8 @@ onexit(int sig)
|
||||
int tryserv(char *serv)
|
||||
{
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
MyNetconServLis *servlis = new MyNetconServLis();
|
||||
SelectLoop myloop;
|
||||
MyNetconServLis *servlis = new MyNetconServLis(myloop);
|
||||
lis = NetconP(servlis);
|
||||
if (lis.isNull()) {
|
||||
fprintf(stderr, "new NetconServLis failed\n");
|
||||
@ -1178,9 +1166,9 @@ int tryserv(char *serv)
|
||||
fprintf(stderr, "openservice(%s) failed\n", serv);
|
||||
return 1;
|
||||
}
|
||||
Netcon::addselcon(lis, Netcon::NETCONPOLL_READ);
|
||||
myloop.addselcon(lis, Netcon::NETCONPOLL_READ);
|
||||
fprintf(stderr, "openservice(%s) Ok\n", serv);
|
||||
if (Netcon::selectloop() < 0) {
|
||||
if (myloop.doLoop() < 0) {
|
||||
fprintf(stderr, "selectloop failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -16,8 +16,12 @@
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <map>
|
||||
#include "refcntr.h"
|
||||
|
||||
using std::map;
|
||||
|
||||
/// A set of classes to manage client-server communication over a
|
||||
/// connection-oriented network, or a pipe.
|
||||
///
|
||||
@ -34,12 +38,14 @@
|
||||
/// Base class for all network endpoints:
|
||||
class Netcon;
|
||||
typedef RefCntr<Netcon> NetconP;
|
||||
class SelectLoop;
|
||||
|
||||
class Netcon {
|
||||
public:
|
||||
enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE=0x2};
|
||||
Netcon()
|
||||
: m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0)
|
||||
: m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0),
|
||||
m_loop(0)
|
||||
{}
|
||||
virtual ~Netcon();
|
||||
/// Remember whom we're talking to. We let external code do this because
|
||||
@ -75,12 +81,41 @@ public:
|
||||
/// Clear events from current set
|
||||
int clearselevents(int evs) {return m_wantedEvents &= ~evs;}
|
||||
|
||||
friend class SelectLoop;
|
||||
SelectLoop *getloop() {return m_loop;}
|
||||
|
||||
/// Utility function for a simplified select() interface: check one fd
|
||||
/// for reading or writing, for a specified maximum number of seconds.
|
||||
static int select1(int fd, int secs, int writing = 0);
|
||||
|
||||
/// The selectloop interface is used to implement parallel servers.
|
||||
/// All the interface is static (independant of any given object).
|
||||
|
||||
protected:
|
||||
char *m_peer; // Name of the connected host
|
||||
int m_fd;
|
||||
bool m_ownfd;
|
||||
int m_didtimo;
|
||||
// Used when part of the selectloop map.
|
||||
short m_wantedEvents;
|
||||
SelectLoop *m_loop;
|
||||
// Method called by the selectloop when something can be done with a netcon
|
||||
virtual int cando(Netcon::Event reason) = 0;
|
||||
// Called when added to loop
|
||||
virtual void setloop(SelectLoop *loop) {m_loop = loop;}
|
||||
};
|
||||
|
||||
|
||||
/// The selectloop interface is used to implement parallel servers.
|
||||
// The select loop mechanism allows several netcons to be used for io
|
||||
// in a program without blocking as long as there is data to be read
|
||||
// or written. In a multithread program which is also using select, it
|
||||
// would typically make sense to have one SelectLoop active per
|
||||
// thread.
|
||||
class SelectLoop {
|
||||
public:
|
||||
SelectLoop()
|
||||
: m_selectloopDoReturn(false), m_selectloopReturnValue(0),
|
||||
m_placetostart(0),
|
||||
m_periodichandler(0), m_periodicparam(0), m_periodicmillis(0)
|
||||
{}
|
||||
|
||||
/// Loop waiting for events on the connections and call the
|
||||
/// cando() method on the object when something happens (this will in
|
||||
@ -88,20 +123,20 @@ public:
|
||||
/// call the periodic handler (if set) at regular intervals.
|
||||
/// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic
|
||||
/// timeout (should call back in after processing)
|
||||
static int selectloop();
|
||||
int doLoop();
|
||||
|
||||
/// Call from data handler: make selectloop return the param value
|
||||
static void selectloopReturn(int value)
|
||||
void loopReturn(int value)
|
||||
{
|
||||
o_selectloopDoReturn = true;
|
||||
o_selectloopReturnValue = value;
|
||||
m_selectloopDoReturn = true;
|
||||
m_selectloopReturnValue = value;
|
||||
}
|
||||
/// Add a connection to be monitored (this will usually be called
|
||||
/// from the server's listen connection's accept callback)
|
||||
static int addselcon(NetconP con, int);
|
||||
/// Remove a connection from the monitored set. Note that this is
|
||||
/// automatically called from the Netcon destructor, and when EOF is
|
||||
/// detected on a connection.
|
||||
static int remselcon(NetconP con);
|
||||
int addselcon(NetconP con, int events);
|
||||
/// Remove a connection from the monitored set. This is
|
||||
/// automatically called when EOF is detected on a connection.
|
||||
int remselcon(NetconP con);
|
||||
|
||||
/// Set a function to be called periodically, or a time before return.
|
||||
/// @param handler the function to be called.
|
||||
@ -112,35 +147,45 @@ public:
|
||||
/// @param clp client data to be passed to handler at every call.
|
||||
/// @param ms milliseconds interval between handler calls or
|
||||
/// before return. Set to 0 for no periodic handler.
|
||||
static void setperiodichandler(int (*handler)(void *), void *clp, int ms);
|
||||
void setperiodichandler(int (*handler)(void *), void *clp, int ms);
|
||||
|
||||
protected:
|
||||
static bool o_selectloopDoReturn;
|
||||
static int o_selectloopReturnValue;
|
||||
char *m_peer; // Name of the connected host
|
||||
int m_fd;
|
||||
bool m_ownfd;
|
||||
int m_didtimo;
|
||||
// Used when part of the selectloop map.
|
||||
short m_wantedEvents;
|
||||
// Method called by the selectloop when something can be done with a netcon
|
||||
virtual int cando(Netcon::Event reason) = 0;
|
||||
private:
|
||||
// Set by client callback to tell selectloop to return.
|
||||
bool m_selectloopDoReturn;
|
||||
int m_selectloopReturnValue;
|
||||
int m_placetostart;
|
||||
|
||||
// Map of NetconP indexed by fd
|
||||
map<int, NetconP> m_polldata;
|
||||
|
||||
// The last time we did the periodic thing. Initialized by setperiodic()
|
||||
struct timeval m_lasthdlcall;
|
||||
// The call back function and its parameter
|
||||
int (*m_periodichandler)(void *);
|
||||
void *m_periodicparam;
|
||||
// The periodic interval
|
||||
int m_periodicmillis;
|
||||
void periodictimeout(struct timeval *tv);
|
||||
int maybecallperiodic();
|
||||
};
|
||||
|
||||
|
||||
///////////////////////
|
||||
class NetconData;
|
||||
|
||||
/// Class for the application callback routine (when in
|
||||
/// selectloop). It would be nicer to override cando() in a subclass
|
||||
/// instead of setting a callback, but this can't be done conveniently
|
||||
/// because accept() always creates a base NetconData (another way
|
||||
/// would be to pass a factory function function to the listener, to create
|
||||
/// NetconData derivatives).
|
||||
/// Class for the application callback routine (when in selectloop).
|
||||
///
|
||||
/// This is set by the app on the NetconData by calling
|
||||
/// setcallback(). It is then called from the NetconData's cando()
|
||||
/// routine, itself called by selectloop.
|
||||
///
|
||||
/// It would be nicer to override cando() in a subclass instead of
|
||||
/// setting a callback, but this can't be done conveniently because
|
||||
/// accept() always creates a base NetconData (another approach would
|
||||
/// be to pass a factory function to the listener, to create
|
||||
/// NetconData derived classes).
|
||||
class NetconWorker {
|
||||
public:
|
||||
virtual ~NetconWorker() {}
|
||||
// NetconP holds a NetconData oeuf corse
|
||||
virtual int data(NetconData *con, Netcon::Event reason) = 0;
|
||||
};
|
||||
|
||||
@ -185,7 +230,7 @@ private:
|
||||
int m_bufbytes; // Bytes of data.
|
||||
int m_bufsize; // Total buffer size
|
||||
RefCntr<NetconWorker> m_user;
|
||||
virtual int cando(Netcon::Event reason);
|
||||
virtual int cando(Netcon::Event reason); // Selectloop slot
|
||||
};
|
||||
|
||||
/// Network endpoint, client side.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user