Fix problems that occurred when multiple threads were trying to read/convert files at the same time (ie: indexing and previewing threads in the GUI calling internfile()). Either get rid of or lock-protect all shared data, eliminate misc initialization possible conflicts by using static initializers. Hopefuly closes issue #51

This commit is contained in:
Jean-Francois Dockes 2011-04-28 10:58:33 +02:00
parent 01f24fa5fd
commit 55f124725f
33 changed files with 318 additions and 231 deletions

View File

@ -320,7 +320,12 @@ list<string> RclConfig::getTopdirs()
// (only the locale).
const string& RclConfig::getDefCharset(bool filename)
{
// This can't change once computed inside a process.
// This can't change once computed inside a process. It would be
// nicer to move this to a static class initializer to avoid
// possible threading issues but this doesn't work (tried) as
// things would not be ready. In practise we make sure that this
// is called from the main thread at once, by calling
// getDefCharset from recollinit
static string localecharset;
if (localecharset.empty()) {
const char *cp;

View File

@ -92,6 +92,10 @@ RclConfig *recollinit(RclInitFlags flags,
// to utf8 for indexing.
setlocale(LC_CTYPE, "");
// Make sure the locale charset is initialized (so that multiple
// threads don't try to do it at once).
config->getDefCharset();
return config;
}

View File

@ -60,49 +60,47 @@ static int charclasses[charclasses_size];
static set<unsigned int> unicign;
static set<unsigned int> visiblewhite;
// Set up character classes array and the additional unicode sets
static void setcharclasses()
{
static int init = 0;
if (init)
return;
unsigned int i;
class CharClassInit {
public:
CharClassInit()
{
unsigned int i;
// Set default value for all: SPACE
for (i = 0 ; i < 256 ; i ++)
charclasses[i] = SPACE;
// Set default value for all: SPACE
for (i = 0 ; i < 256 ; i ++)
charclasses[i] = SPACE;
char digits[] = "0123456789";
for (i = 0; i < strlen(digits); i++)
charclasses[int(digits[i])] = DIGIT;
char digits[] = "0123456789";
for (i = 0; i < strlen(digits); i++)
charclasses[int(digits[i])] = DIGIT;
char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (i = 0; i < strlen(upper); i++)
charclasses[int(upper[i])] = A_ULETTER;
char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (i = 0; i < strlen(upper); i++)
charclasses[int(upper[i])] = A_ULETTER;
char lower[] = "abcdefghijklmnopqrstuvwxyz";
for (i = 0; i < strlen(lower); i++)
charclasses[int(lower[i])] = A_LLETTER;
char lower[] = "abcdefghijklmnopqrstuvwxyz";
for (i = 0; i < strlen(lower); i++)
charclasses[int(lower[i])] = A_LLETTER;
char wild[] = "*?[]";
for (i = 0; i < strlen(wild); i++)
charclasses[int(wild[i])] = WILD;
char wild[] = "*?[]";
for (i = 0; i < strlen(wild); i++)
charclasses[int(wild[i])] = WILD;
char special[] = ".@+-,#'_\n\r";
for (i = 0; i < strlen(special); i++)
charclasses[int(special[i])] = special[i];
char special[] = ".@+-,#'_\n\r";
for (i = 0; i < strlen(special); i++)
charclasses[int(special[i])] = special[i];
for (i = 0; i < sizeof(uniign) / sizeof(int); i++) {
unicign.insert(uniign[i]);
for (i = 0; i < sizeof(uniign) / sizeof(int); i++) {
unicign.insert(uniign[i]);
}
unicign.insert((unsigned int)-1);
for (i = 0; i < sizeof(avsbwht) / sizeof(int); i++) {
visiblewhite.insert(avsbwht[i]);
}
}
unicign.insert((unsigned int)-1);
for (i = 0; i < sizeof(avsbwht) / sizeof(int); i++) {
visiblewhite.insert(avsbwht[i]);
}
init = 1;
}
};
static const CharClassInit charClassInitInstance;
static inline int whatcc(unsigned int c)
{
@ -280,8 +278,6 @@ bool TextSplit::text_to_words(const string &in)
m_flags & TXTS_KEEPWILD ? " keepwild" : "",
in.substr(0,50).c_str()));
setcharclasses();
m_span.erase();
m_inNumber = false;
m_wordStart = m_wordLen = m_prevpos = m_prevlen = m_wordpos = m_spanpos = 0;
@ -633,7 +629,6 @@ int TextSplit::countWords(const string& s, TextSplit::Flags flgs)
bool TextSplit::hasVisibleWhite(const string &in)
{
setcharclasses();
Utf8Iter it(in);
for (; !it.eof(); it++) {
unsigned int c = (unsigned char)*it;
@ -650,7 +645,6 @@ bool TextSplit::hasVisibleWhite(const string &in)
template <class T> bool u8stringToStrings(const string &s, T &tokens)
{
setcharclasses();
Utf8Iter it(s);
string current;

View File

@ -63,7 +63,13 @@ using namespace std;
#define deleteZ(X) {delete X;X = 0;}
#endif
FsIndexer::FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc)
: m_config(cnf), m_db(db), m_updater(updfunc), m_missing(new FIMissingStore)
{
m_havelocalfields = m_config->hasNameAnywhere("localfields");
}
FsIndexer::~FsIndexer() {
delete m_missing;
}
bool FsIndexer::init()
@ -121,7 +127,7 @@ bool FsIndexer::index()
}
string missing;
FileInterner::getMissingDescription(missing);
FileInterner::getMissingDescription(m_missing, missing);
if (!missing.empty()) {
LOGINFO(("FsIndexer::index missing helper program(s):\n%s\n",
missing.c_str()));
@ -359,6 +365,7 @@ FsIndexer::processone(const std::string &fn, const struct stat *stp,
// indexallfilenames is not set
return FsTreeWalker::FtwOk;
}
interner.setMissingStore(m_missing);
// File name transcoded to utf8 for indexing.
string charset = m_config->getDefCharset(true);

View File

@ -26,6 +26,7 @@ using std::list;
#include "rcldb.h"
class DbIxStatusUpdater;
class FIMissingStore;
/** Index selected parts of the file system
@ -45,12 +46,7 @@ class FsIndexer : public FsTreeWalkerCB {
* @param cnf Configuration data
* @param updfunc Status updater callback
*/
FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc = 0)
: m_config(cnf), m_db(db), m_updater(updfunc)
{
m_havelocalfields = m_config->hasNameAnywhere("localfields");
}
FsIndexer(RclConfig *cnf, Rcl::Db *db, DbIxStatusUpdater *updfunc = 0);
virtual ~FsIndexer();
/**
@ -79,6 +75,7 @@ class FsIndexer : public FsTreeWalkerCB {
string m_reason;
DbIxStatusUpdater *m_updater;
list<string> m_tdl;
FIMissingStore *m_missing;
// The configuration can set attribute fields to be inherited by
// all files in a file system area. Ie: set "rclaptg = thunderbird"

View File

@ -45,6 +45,7 @@ using namespace std;
#include "beaglequeuecache.h"
#include "cancelcheck.h"
#include "copyfile.h"
#include "ptmutex.h"
#ifdef RCL_USE_XATTR
#include "pxattr.h"
@ -76,9 +77,6 @@ static string colon_restore(const string& in)
return out;
}
set<string> FileInterner::o_missingExternal;
map<string, set<string> > FileInterner::o_typesForMissing;
#ifdef RCL_USE_XATTR
void FileInterner::reapXAttrs(const string& path)
{
@ -192,7 +190,7 @@ void FileInterner::tmpcleanup()
FileInterner::FileInterner(const string &f, const struct stat *stp,
RclConfig *cnf,
TempDir& td, int flags, const string *imime)
: m_tdir(td), m_ok(false)
: m_tdir(td), m_ok(false), m_missingdatap(0)
{
initcommon(cnf, flags);
init(f, stp, cnf, flags, imime);
@ -304,7 +302,7 @@ void FileInterner::init(const string &f, const struct stat *stp, RclConfig *cnf,
// Setup from memory data (ie: out of the web cache). imime needs to be set.
FileInterner::FileInterner(const string &data, RclConfig *cnf,
TempDir& td, int flags, const string& imime)
: m_tdir(td), m_ok(false)
: m_tdir(td), m_ok(false), m_missingdatap(0)
{
initcommon(cnf, flags);
init(data, cnf, flags, imime);
@ -366,9 +364,13 @@ void FileInterner::initcommon(RclConfig *cnf, int flags)
m_targetMType = stxtplain;
}
// We used a single beagle cache object to access beagle data. We protect it
// against multiple thread access.
static PTMutexInit o_lock;
FileInterner::FileInterner(const Rcl::Doc& idoc, RclConfig *cnf,
TempDir& td, int flags)
: m_tdir(td), m_ok(false)
: m_tdir(td), m_ok(false), m_missingdatap(0)
{
LOGDEB(("FileInterner::FileInterner(idoc)\n"));
initcommon(cnf, flags);
@ -405,10 +407,6 @@ FileInterner::FileInterner(const Rcl::Doc& idoc, RclConfig *cnf,
}
init(fn, &st, cnf, flags, &idoc.mimetype);
} else if (!backend.compare("BGL")) {
// Retrieve from our webcache (beagle data). The beagler
// object is created at the first call of this routine and
// deleted when the program exits.
static BeagleQueueCache beagler(cnf);
string data;
Rcl::Doc dotdoc;
map<string,string>::const_iterator it =
@ -418,11 +416,19 @@ FileInterner::FileInterner(const Rcl::Doc& idoc, RclConfig *cnf,
return;
}
string udi = it->second;
if (!beagler.getFromCache(udi, dotdoc, data)) {
LOGINFO(("FileInterner:: failed fetch from Beagle cache for [%s]\n",
udi.c_str()));
return;
}
{
PTMutexLocker locker(o_lock);
// Retrieve from our webcache (beagle data). The beagler
// object is created at the first call of this routine and
// deleted when the program exits.
static BeagleQueueCache beagler(cnf);
if (!beagler.getFromCache(udi, dotdoc, data)) {
LOGINFO(("FileInterner:: failed fetch from Beagle cache for [%s]\n",
udi.c_str()));
return;
}
}
if (dotdoc.mimetype.compare(idoc.mimetype)) {
LOGINFO(("FileInterner:: udi [%s], mimetp mismatch: in: [%s], bgl "
"[%s]\n", idoc.mimetype.c_str(), dotdoc.mimetype.c_str()));
@ -485,7 +491,7 @@ bool FileInterner::dataToTempFile(const string& dt, const string& mt,
// accumulate helper name if it is
void FileInterner::checkExternalMissing(const string& msg, const string& mt)
{
if (msg.find("RECFILTERROR") == 0) {
if (m_missingdatap && msg.find("RECFILTERROR") == 0) {
list<string> lerr;
stringToStrings(msg, lerr);
if (lerr.size() > 2) {
@ -495,28 +501,33 @@ void FileInterner::checkExternalMissing(const string& msg, const string& mt)
lerr.erase(it++);
string s;
stringsToString(lerr, s);
o_missingExternal.insert(s);
o_typesForMissing[s].insert(mt);
m_missingdatap->m_missingExternal.insert(s);
m_missingdatap->m_typesForMissing[s].insert(mt);
}
}
}
}
void FileInterner::getMissingExternal(string& out)
void FileInterner::getMissingExternal(FIMissingStore *st, string& out)
{
stringsToString(o_missingExternal, out);
if (st)
stringsToString(st->m_missingExternal, out);
}
void FileInterner::getMissingDescription(string& out)
void FileInterner::getMissingDescription(FIMissingStore *st, string& out)
{
if (st == 0)
return;
out.erase();
for (set<string>::const_iterator it = o_missingExternal.begin();
it != o_missingExternal.end(); it++) {
for (set<string>::const_iterator it =
st->m_missingExternal.begin();
it != st->m_missingExternal.end(); it++) {
out += *it;
map<string, set<string> >::const_iterator it2;
it2 = o_typesForMissing.find(*it);
if (it2 != o_typesForMissing.end()) {
it2 = st->m_typesForMissing.find(*it);
if (it2 != st->m_typesForMissing.end()) {
out += " (";
set<string>::const_iterator it3;
for (it3 = it2->second.begin();

View File

@ -39,6 +39,19 @@ class Doc;
struct stat;
/** Storage for missing helper program info. We want to keep this out of the
* FileInterner class, because the data will typically be accumulated by several
* FileInterner objects. Can't use static member either (because there
* may be several separate usages of the class which shouldn't mix
* their data).
*/
class FIMissingStore {
public:
// Missing external programs
set<string> m_missingExternal;
map<string, set<string> > m_typesForMissing;
};
/**
* A class to convert data from a datastore (file-system, firefox
* history, etc.) into possibly one or severaldocuments in internal
@ -110,6 +123,11 @@ class FileInterner {
~FileInterner();
void setMissingStore(FIMissingStore *st)
{
m_missingdatap = st;
}
/**
* Turn file or file part into Recoll document.
*
@ -169,11 +187,10 @@ class FileInterner {
RclConfig *cnf, const Rcl::Doc& doc);
const string& getReason() const {return m_reason;}
static void getMissingExternal(string& missing);
static void getMissingDescription(string& desc);
static void getMissingExternal(FIMissingStore *st, string& missing);
static void getMissingDescription(FIMissingStore *st, string& desc);
bool ok() {return m_ok;}
private:
static const unsigned int MAXHANDLERS = 20;
RclConfig *m_cfg;
@ -203,9 +220,7 @@ class FileInterner {
vector<TempFile> m_tempfiles;
// Error data if any
string m_reason;
// Missing external programs
static set<string> o_missingExternal;
static map<string, set<string> > o_typesForMissing;
FIMissingStore *m_missingdatap;
// Pseudo-constructors
void init(const string &fn, const struct stat *stp,

View File

@ -37,6 +37,7 @@
#include "rclconfig.h"
#include "md5.h"
#include "conftree.h"
#include "ptmutex.h"
using namespace std;
class FpKeeper {
@ -52,6 +53,7 @@ public:
private: FILE **m_fpp;
};
static PTMutexInit o_mutex;
/**
* Handles a cache for message numbers to offset translations. Permits direct
@ -78,6 +80,7 @@ public:
~MboxCache() {}
mbhoff_type get_offset(RclConfig *config, const string& udi, int msgnum)
{
PTMutexLocker locker(o_mutex);
LOGDEB0(("MboxCache::get_offsets: udi [%s] msgnum %d\n", udi.c_str(),
msgnum));
if (!ok(config)) {
@ -125,6 +128,7 @@ public:
void put_offsets(RclConfig *config, const string& udi, mbhoff_type fsize,
vector<mbhoff_type>& offs)
{
PTMutexLocker locker(o_mutex);
LOGDEB0(("MboxCache::put_offsets: %u offsets\n", offs.size()));
if (!ok(config) || !maybemakedir())
return;
@ -159,6 +163,7 @@ public:
// Check state, possibly initialize
bool ok(RclConfig *config) {
PTMutexLocker locker(o_mutex);
if (m_minfsize == -1)
return false;
if (!m_ok) {
@ -218,7 +223,9 @@ private:
};
const size_t MboxCache::o_b1size = 1024;
static class MboxCache mcache;
static const string keyquirks("mhmboxquirks");
MimeHandlerMbox::~MimeHandlerMbox()
@ -389,6 +396,7 @@ bool MimeHandlerMbox::next_document()
// avoid rereading the whole thing in this case. But I'm not sure
// we're ever used in this way (multiple retrieves on same
// object). So:
bool storeoffsets = true;
if (mtarg > 0) {
mbhoff_type off;
line_type line;
@ -404,6 +412,7 @@ bool MimeHandlerMbox::next_document()
LOGDEB0(("MimeHandlerMbox: Cache: From_ Ok\n"));
fseeko(fp, (off_t)off, SEEK_SET);
m_msgnum = mtarg -1;
storeoffsets = false;
} else {
fseek(fp, 0, SEEK_SET);
m_msgnum = 0;
@ -444,7 +453,8 @@ bool MimeHandlerMbox::next_document()
!regexec(&minifromregex, line, 0, 0, 0)) ) {
LOGDEB1(("MimeHandlerMbox: msgnum %d, "
"From_ at line %d: [%s]\n", m_msgnum, m_lineno, line));
m_offsets.push_back(message_end);
if (storeoffsets)
m_offsets.push_back(message_end);
m_msgnum++;
if ((mtarg <= 0 && m_msgnum > 1) ||
(mtarg > 0 && m_msgnum > mtarg)) {
@ -477,7 +487,7 @@ bool MimeHandlerMbox::next_document()
if (iseof) {
LOGDEB2(("MimeHandlerMbox::next: eof hit\n"));
m_havedoc = false;
if (!m_udi.empty()) {
if (!m_udi.empty() && storeoffsets) {
mcache.put_offsets(m_config, m_udi, m_fsize, m_offsets);
}
}

View File

@ -28,7 +28,6 @@ using namespace std;
#include "debuglog.h"
#include "rclconfig.h"
#include "smallut.h"
#include "pthread.h"
#include "mh_exec.h"
#include "mh_execm.h"
@ -37,6 +36,7 @@ using namespace std;
#include "mh_mbox.h"
#include "mh_text.h"
#include "mh_unknown.h"
#include "ptmutex.h"
// Performance help: we use a pool of already known and created
// handlers. There can be several instances for a given mime type
@ -48,26 +48,7 @@ using namespace std;
// simple lock should be enough as handlers are removed from the cache
// while in use and multiple copies are allowed
static multimap<string, Dijon::Filter*> o_handlers;
pthread_mutex_t o_handlers_mutex;
class HandlersLocker {
public:
HandlersLocker()
{
pthread_mutex_lock(&o_handlers_mutex);
}
~HandlersLocker()
{
pthread_mutex_unlock(&o_handlers_mutex);
}
};
class HandlersLockerInit {
public:
HandlersLockerInit()
{
pthread_mutex_init(&o_handlers_mutex, 0);
}
};
static HandlersLockerInit o_hli;
static PTMutexInit o_handlers_mutex;
/** For mime types set as "internal" in mimeconf:
* create appropriate handler object. */
@ -163,7 +144,7 @@ void returnMimeHandler(Dijon::Filter *handler)
typedef multimap<string, Dijon::Filter*>::value_type value_type;
if (handler) {
handler->clear();
HandlersLocker locker;
PTMutexLocker locker(o_handlers_mutex);
o_handlers.insert(value_type(handler->get_mime_type(), handler));
}
}
@ -172,7 +153,7 @@ void clearMimeHandlerCache()
{
typedef multimap<string, Dijon::Filter*>::value_type value_type;
map<string, Dijon::Filter *>::iterator it;
HandlersLocker locker;
PTMutexLocker locker(o_handlers_mutex);
for (it = o_handlers.begin(); it != o_handlers.end(); it++) {
delete it->second;
}
@ -187,7 +168,7 @@ Dijon::Filter *getMimeHandler(const string &mtype, RclConfig *cfg,
LOGDEB2(("getMimeHandler: mtype [%s] filtertypes %d\n",
mtype.c_str(), filtertypes));
Dijon::Filter *h = 0;
HandlersLocker locker;
PTMutexLocker locker(o_handlers_mutex);
// Get handler definition for mime type. We do this even if an
// appropriate handler object may be in the cache (indexed by mime

View File

@ -35,8 +35,6 @@
#include "debuglog.h"
#include "transcode.h"
map<string, string> MyHtmlParser::my_named_ents;
inline static bool
p_notdigit(char c)
{
@ -151,20 +149,11 @@ static const char *epairs[] = {
"rsaquo", "\xe2\x80\xba", "euro", "\xe2\x82\xac",
NULL, NULL
};
MyHtmlParser::MyHtmlParser()
: in_script_tag(false),
in_style_tag(false),
in_body_tag(false),
in_pre_tag(false),
pending_space(false),
indexing_allowed(true)
{
// The default html document charset is iso-8859-1. We'll update
// this value from the encoding tag if found.
charset = "iso-8859-1";
if (my_named_ents.empty()) {
map<string, string> my_named_ents;
class NamedEntsInitializer {
public:
NamedEntsInitializer()
{
for (int i = 0;;) {
const char *ent;
const char *val;
@ -177,6 +166,20 @@ MyHtmlParser::MyHtmlParser()
my_named_ents[string(ent)] = val;
}
}
};
static NamedEntsInitializer namedEntsInitializerInstance;
MyHtmlParser::MyHtmlParser()
: in_script_tag(false),
in_style_tag(false),
in_body_tag(false),
in_pre_tag(false),
pending_space(false),
indexing_allowed(true)
{
// The default html document charset is iso-8859-1. We'll update
// this value from the encoding tag if found.
charset = "iso-8859-1";
}
void MyHtmlParser::decode_entities(string &s)

View File

@ -40,7 +40,6 @@ class MyHtmlParser : public HtmlParser {
bool in_pre_tag;
bool pending_space;
map<string,string> meta;
static map<string, string> my_named_ents;
string dump, dmtime;
// This is the charset our caller thinks the doc used (initially
// comes from the environment/configuration, used as source for

View File

@ -48,8 +48,6 @@ using std::unique;
#include "guiutils.h"
#include "rclhelp.h"
extern RclConfig *rclconfig;
static const int initclausetypes[] = {1, 3, 0, 2, 5};
static const unsigned int iclausescnt = sizeof(initclausetypes) / sizeof(int);
static map<QString,QString> cat_translations;
@ -268,7 +266,7 @@ void AdvSearch::fillFileTypes()
QStringList ql;
if (m_ignByCats == false) {
list<string> types = rclconfig->getAllMimeTypes();
list<string> types = theconfig->getAllMimeTypes();
for (list<string>::iterator it = types.begin();
it != types.end(); it++) {
QString qs = QString::fromUtf8(it->c_str());
@ -277,7 +275,7 @@ void AdvSearch::fillFileTypes()
}
} else {
list<string> cats;
rclconfig->getMimeCategories(cats);
theconfig->getMimeCategories(cats);
for (list<string>::const_iterator it = cats.begin();
it != cats.end(); it++) {
map<QString, QString>::const_iterator it1;
@ -334,7 +332,7 @@ void AdvSearch::runSearch()
cat = (const char *)qcat.toUtf8();
}
list<string> types;
rclconfig->getMimeCatTypes(cat, types);
theconfig->getMimeCatTypes(cat, types);
for (list<string>::const_iterator it = types.begin();
it != types.end(); it++) {
sdata->addFiletype(*it);

View File

@ -49,8 +49,8 @@ using std::list;
namespace confgui {
const static int spacing = 2;
const static int margin = 2;
static const int spacing = 2;
static const int margin = 2;
void ConfParamW::setValue(const QString& value)
{

View File

@ -44,8 +44,8 @@ using std::list;
#include "rclconfig.h"
namespace confgui {
const static int spacing = 3;
const static int margin = 3;
static const int spacing = 3;
static const int margin = 3;
ConfIndexW::ConfIndexW(QWidget *parent, RclConfig *config)
: QDialog(parent), m_rclconf(config)
@ -84,6 +84,7 @@ void ConfIndexW::acceptChanges()
delete m_conf;
m_conf = 0;
m_rclconf->updateMainConfig();
snapshotConfig();
if (startIndexingAfterConfig) {
startIndexingAfterConfig = 0;

View File

@ -29,6 +29,7 @@
#include "smallut.h"
#include "rclinit.h"
#include "pathut.h"
#include "recoll.h"
static int stopindexing;
static int startindexing;
@ -60,7 +61,6 @@ class IdxThread : public QThread , public DbIxStatusUpdater {
// Maintain a copy/snapshot of idx status
DbIxStatus m_statusSnap;
bool m_interrupted;
const RclConfig *cnf;
};
void IdxThread::run()
@ -76,7 +76,11 @@ void IdxThread::run()
indexingstatus = IDXTS_NULL;
// We make a private snapshot of the config: setKeydir changes
// it during indexing and it may be updated by the main thread.
RclConfig *myconf = new RclConfig(*cnf);
RclConfig *myconf;
{
PTMutexLocker locker(thestableconfiglock);
myconf = new RclConfig(*thestableconfig);
}
int loglevel;
myconf->setKeyDir("");
myconf->getConfParam("loglevel", &loglevel);
@ -117,9 +121,8 @@ static IdxThread idxthread;
// Functions called by the main thread
void start_idxthread(const RclConfig& cnf)
void start_idxthread()
{
idxthread.cnf = &cnf;
idxthread.start();
}

View File

@ -19,11 +19,11 @@
#include <string>
#include "indexer.h"
class RclConfig;
// These two deal with starting / stopping the thread itself, not
// indexing sessions.
extern void start_idxthread(const RclConfig& cnf);
// cnf will be cloned each time we start an indexing pass. The pointer must
// stay valid for the whole program duration.
extern void start_idxthread();
extern void stop_idxthread();
// Use these to to request action from thread

View File

@ -47,7 +47,16 @@
#include "smallut.h"
#include "recollq.h"
RclConfig *rclconfig;
RclConfig *theconfig;
RclConfig *thestableconfig;
PTMutexInit thestableconfiglock;
void snapshotConfig()
{
PTMutexLocker locker(thestableconfiglock);
thestableconfig = new RclConfig(*theconfig);
}
Rcl::Db *rcldb;
#ifdef RCL_USE_ASPELL
Aspell *aspell;
@ -80,7 +89,7 @@ bool maybeOpenDb(string &reason, bool force)
}
if (!rcldb->isopen() && !rcldb->open(Rcl::Db::DbRO)) {
reason = "Could not open database in " +
rclconfig->getDbDir() + " wait for indexing to complete?";
theconfig->getDbDir() + " wait for indexing to complete?";
return false;
}
rcldb->setAbstractParams(-1, prefs.syntAbsLen, prefs.syntAbsCtx);
@ -104,7 +113,8 @@ static void recollCleanup()
rwSettings(true);
LOGDEB2(("recollCleanup: closing database\n"));
deleteZ(rcldb);
deleteZ(rclconfig);
deleteZ(theconfig);
deleteZ(thestableconfig);
#ifdef RCL_USE_ASPELL
deleteZ(aspell);
#endif
@ -165,7 +175,7 @@ int main(int argc, char **argv)
{
for (int i = 0; i < argc; i++) {
if (!strcmp(argv[i], "-t")) {
exit(recollq(&rclconfig, argc, argv));
exit(recollq(&theconfig, argc, argv));
}
}
@ -218,17 +228,18 @@ int main(int argc, char **argv)
app.installTranslator( &qt );
string reason;
rclconfig = recollinit(recollCleanup, sigcleanup, reason, &a_config);
if (!rclconfig || !rclconfig->ok()) {
theconfig = recollinit(recollCleanup, sigcleanup, reason, &a_config);
if (!theconfig || !theconfig->ok()) {
QString msg = "Configuration problem: ";
msg += QString::fromUtf8(reason.c_str());
QMessageBox::critical(0, "Recoll", msg);
exit(1);
}
snapshotConfig();
// fprintf(stderr, "recollinit done\n");
// Translations for Recoll
string translatdir = path_cat(rclconfig->getDatadir(), "translations");
string translatdir = path_cat(theconfig->getDatadir(), "translations");
QTranslator translator(0);
translator.load( QString("recoll_") + slang, translatdir.c_str() );
app.installTranslator( &translator );
@ -236,7 +247,7 @@ int main(int argc, char **argv)
// fprintf(stderr, "Translations installed\n");
#ifdef RCL_USE_ASPELL
aspell = new Aspell(rclconfig);
aspell = new Aspell(theconfig);
aspell->init(reason);
if (!aspell || !aspell->ok()) {
LOGDEB(("Aspell speller creation failed %s\n", reason.c_str()));
@ -244,7 +255,7 @@ int main(int argc, char **argv)
}
#endif
string historyfile = path_cat(rclconfig->getConfDir(), "history");
string historyfile = path_cat(theconfig->getConfDir(), "history");
g_dynconf = new RclDynConf(historyfile);
if (!g_dynconf || !g_dynconf->ok()) {
QString msg = app.translate("Main", "Configuration problem (dynconf");
@ -266,7 +277,7 @@ int main(int argc, char **argv)
mainWindow->resize(s);
}
string dbdir = rclconfig->getDbDir();
string dbdir = theconfig->getDbDir();
if (dbdir.empty()) {
QMessageBox::critical(0, "Recoll",
app.translate("Main",
@ -274,7 +285,7 @@ int main(int argc, char **argv)
exit(1);
}
rcldb = new Rcl::Db(rclconfig);
rcldb = new Rcl::Db(theconfig);
mainWindow->show();
QTimer::singleShot(0, mainWindow, SLOT(initDbOpen()));
@ -286,7 +297,7 @@ int main(int argc, char **argv)
// Start the indexing thread. It will immediately go to sleep waiting for
// something to do.
start_idxthread(*rclconfig);
start_idxthread();
mainWindow->sSearch->searchTypCMB->setCurrentIndex(prefs.ssearchTyp);
mainWindow->sSearch->searchTypeChanged(prefs.ssearchTyp);

View File

@ -518,7 +518,7 @@ void Preview::setCurTabProps(const Rcl::Doc &doc, int docnum)
}
LOGDEB(("Doc.url: [%s]\n", doc.url.c_str()));
string url;
printableUrl(rclconfig->getDefCharset(), doc.url, url);
printableUrl(theconfig->getDefCharset(), doc.url, url);
string tiptxt = url + string("\n");
tiptxt += doc.mimetype + " " + string(datebuf) + "\n";
if (meta_it != doc.meta.end() && !meta_it->second.empty())
@ -538,6 +538,11 @@ bool Preview::makeDocCurrent(const Rcl::Doc& doc, int docnum, bool sametab)
{
LOGDEB(("Preview::makeDocCurrent: %s\n", doc.url.c_str()));
if (m_loading) {
LOGERR(("Already loading\n"));
return false;
}
/* Check if we already have this page */
for (int i = 0; i < pvTab->count(); i++) {
QWidget *tw = pvTab->widget(i);
@ -621,9 +626,10 @@ class LoadThread : public QThread {
// QMessageBox::critical(0, "Recoll", Preview::tr("File does not exist"));
FileInterner interner(idoc, rclconfig, tmpdir,
FileInterner interner(idoc, theconfig, tmpdir,
FileInterner::FIF_forPreview);
FIMissingStore mst;
interner.setMissingStore(&mst);
// We don't set the interner's target mtype to html because we
// do want the html filter to do its work: we won't use the
// text, but we need the conversion to utf-8
@ -647,7 +653,7 @@ class LoadThread : public QThread {
}
} else {
out.mimetype = interner.getMimetype();
interner.getMissingExternal(missing);
interner.getMissingExternal(&mst, missing);
*statusp = -1;
}
} catch (CancelExcept) {
@ -706,10 +712,6 @@ public:
bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
{
LOGDEB1(("PreviewTextEdit::loadDocInCurrentTab()\n"));
if (m_loading) {
LOGERR(("ALready loading\n"));
return false;
}
LoadGuard guard(&m_loading);
CancelCheck::instance().setCancel(false);
@ -757,14 +759,20 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum)
if (CancelCheck::instance().cancelState())
return false;
if (status != 0) {
QMessageBox::warning(0, "Recoll",
tr("Can't turn doc into internal "
"representation for ") +
fdoc.mimetype.c_str());
QString explain;
if (!lthr.missing.empty()) {
explain = QString::fromAscii("<br>") +
tr("Missing helper program: ") +
QString::fromLocal8Bit(lthr.missing.c_str());
}
QMessageBox::warning(0, "Recoll",
tr("Can't turn doc into internal "
"representation for ") +
fdoc.mimetype.c_str() + explain);
return false;
}
// Reset config just in case.
rclconfig->setKeyDir("");
theconfig->setKeyDir("");
// Create preview text: highlight search terms
// We don't do the highlighting for very big texts: too long. We

View File

@ -97,6 +97,7 @@ void RclMain::init()
spellform = 0;
m_idxStatusAck = false;
periodictimer = new QTimer(this);
m_periodicToggle = 0;
// At least some versions of qt4 don't display the status bar if
// it's not created here.
@ -124,7 +125,7 @@ void RclMain::init()
// instead
string slangs;
list<string> langs;
if (rclconfig->getConfParam("indexstemminglanguages", slangs)) {
if (theconfig->getConfParam("indexstemminglanguages", slangs)) {
stringToStrings(slangs, langs);
} else {
QMessageBox::warning(0, "Recoll",
@ -166,7 +167,7 @@ void RclMain::init()
connect(bgrp, SIGNAL(buttonClicked(int)), this, SLOT(catgFilter(int)));
allRDB->setChecked(true);
list<string> cats;
rclconfig->getMimeCategories(cats);
theconfig->getMimeCategories(cats);
// Text for button 0 is not used. Next statement just avoids unused
// variable compiler warning for catg_strings
m_catgbutvec.push_back(catg_strings[0]);
@ -350,7 +351,7 @@ void RclMain::initDbOpen()
question
(this, "Recoll",
qApp->translate("Main", "Could not open database in ") +
QString::fromLocal8Bit(rclconfig->getDbDir().c_str()) +
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."),
@ -492,7 +493,6 @@ void RclMain::fileExit()
// indexing thread and a possible need to exit
void RclMain::periodic100()
{
static int toggle = 0;
// Check if indexing thread done
if (idxthread_getStatus() != IDXTS_NULL) {
// Indexing is stopped
@ -527,7 +527,7 @@ void RclMain::periodic100()
fileToggleIndexingAction->setEnabled(TRUE);
periodictimer->setInterval(100);
// The toggle thing is for the status to flash
if (toggle < 9) {
if (m_periodicToggle < 9) {
QString msg = tr("Indexing in progress: ");
DbIxStatus status = idxthread_idxStatus();
QString phs;
@ -548,17 +548,17 @@ void RclMain::periodic100()
msg += QString::fromAscii(cnts) + " ";
}
string mf;int ecnt = 0;
string fcharset = rclconfig->getDefCharset(true);
string fcharset = theconfig->getDefCharset(true);
if (!transcode(status.fn, mf, fcharset, "UTF-8", &ecnt) || ecnt) {
mf = url_encode(status.fn, 0);
}
msg += QString::fromUtf8(mf.c_str());
statusBar()->showMessage(msg, 4000);
} else if (toggle == 9) {
} else if (m_periodicToggle == 9) {
statusBar()->showMessage("");
}
if (++toggle >= 10)
toggle = 0;
if (++m_periodicToggle >= 10)
m_periodicToggle = 0;
}
if (recollNeedsExit)
fileExit();
@ -602,7 +602,7 @@ void RclMain::startSearch(RefCntr<Rcl::SearchData> sdata)
string stemLang = (const char *)prefs.queryStemLang.toAscii();
if (stemLang == "ALL") {
rclconfig->getConfParam("indexstemminglanguages", stemLang);
theconfig->getConfParam("indexstemminglanguages", stemLang);
}
sdata->setStemlang(stemLang);
@ -692,7 +692,7 @@ void RclMain::showIndexConfig()
{
LOGDEB(("showIndexConfig()\n"));
if (indexConfig == 0) {
indexConfig = new ConfIndexW(0, rclconfig);
indexConfig = new ConfIndexW(0, theconfig);
connect(new QShortcut(quitKeySeq, indexConfig), SIGNAL (activated()),
this, SLOT (fileExit()));
} else {
@ -744,7 +744,7 @@ void RclMain::showAboutDialog()
void RclMain::showMissingHelpers()
{
string miss = rclconfig->getMissingHelperDesc();
string miss = theconfig->getMissingHelperDesc();
QString msg = tr("External applications/commands needed and not found "
"for indexing your file types:\n\n");
if (!miss.empty()) {
@ -984,7 +984,7 @@ void RclMain::saveDocToFile(Rcl::Doc doc)
);
string tofile((const char *)s.toLocal8Bit());
TempFile temp; // not used
if (!FileInterner::idocToFile(temp, tofile, rclconfig, doc)) {
if (!FileInterner::idocToFile(temp, tofile, theconfig, doc)) {
QMessageBox::warning(0, "Recoll",
tr("Cannot extract document or create "
"temporary file"));
@ -1034,13 +1034,13 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
// Look for appropriate viewer
string cmdplusattr;
if (prefs.useDesktopOpen) {
cmdplusattr = rclconfig->getMimeViewerDef("application/x-all", "");
cmdplusattr = theconfig->getMimeViewerDef("application/x-all", "");
} else {
string apptag;
map<string,string>::const_iterator it;
if ((it = doc.meta.find(Rcl::Doc::keyapptg)) != doc.meta.end())
apptag = it->second;
cmdplusattr = rclconfig->getMimeViewerDef(doc.mimetype, apptag);
cmdplusattr = theconfig->getMimeViewerDef(doc.mimetype, apptag);
}
if (cmdplusattr.empty()) {
@ -1053,7 +1053,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
// Extract possible viewer attributes
ConfSimple attrs;
string cmd;
rclconfig->valueSplitAttributes(cmdplusattr, cmd, attrs);
theconfig->valueSplitAttributes(cmdplusattr, cmd, attrs);
bool ignoreipath = false;
if (attrs.get("ignoreipath", cmdplusattr))
ignoreipath = stringToBool(cmdplusattr);
@ -1073,7 +1073,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
// directory
string cmdpath;
if (!ExecCmd::which(lcmd.front(), cmdpath)) {
cmdpath = rclconfig->findFilter(lcmd.front());
cmdpath = theconfig->findFilter(lcmd.front());
// findFilter returns its input param if the filter is not in
// the normal places. As we already looked in the path, we
// have no use for a simple command name here (as opposed to
@ -1128,10 +1128,10 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
// If the command wants a file but this is not a file url, or
// there is an ipath that it won't understand, we need a temp file:
rclconfig->setKeyDir(path_getfather(fn));
theconfig->setKeyDir(path_getfather(fn));
if ((wantsfile && fn.empty()) || (!wantsipath && !doc.ipath.empty())) {
TempFile temp;
if (!FileInterner::idocToFile(temp, string(), rclconfig, doc)) {
if (!FileInterner::idocToFile(temp, string(), theconfig, doc)) {
QMessageBox::warning(0, "Recoll",
tr("Cannot extract document or create "
"temporary file"));
@ -1145,7 +1145,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
// If using an actual file, check that it exists, and if it is
// compressed, we may need an uncompressed version
if (!fn.empty() && rclconfig->mimeViewerNeedsUncomp(doc.mimetype)) {
if (!fn.empty() && theconfig->mimeViewerNeedsUncomp(doc.mimetype)) {
if (access(fn.c_str(), R_OK) != 0) {
QMessageBox::warning(0, "Recoll",
tr("Can't access file: ") +
@ -1153,8 +1153,8 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
return;
}
TempFile temp;
if (FileInterner::isCompressed(fn, rclconfig)) {
if (!FileInterner::maybeUncompressToTemp(temp, fn, rclconfig,
if (FileInterner::isCompressed(fn, theconfig)) {
if (!FileInterner::maybeUncompressToTemp(temp, fn, theconfig,
doc)) {
QMessageBox::warning(0, "Recoll",
tr("Can't uncompress file: ") +
@ -1208,7 +1208,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc)
ncmd += " &";
QStatusBar *stb = statusBar();
if (stb) {
string fcharset = rclconfig->getDefCharset(true);
string fcharset = theconfig->getDefCharset(true);
string prcmd;
transcode(ncmd, prcmd, fcharset, "UTF-8");
QString msg = tr("Executing: [") +
@ -1234,7 +1234,7 @@ void RclMain::startManual(const string& index)
{
Rcl::Doc doc;
doc.url = "file://";
doc.url = path_cat(doc.url, rclconfig->getDatadir());
doc.url = path_cat(doc.url, theconfig->getDatadir());
doc.url = path_cat(doc.url, "doc");
doc.url = path_cat(doc.url, "usermanual.html");
LOGDEB(("RclMain::startManual: help index is %s\n",
@ -1382,7 +1382,7 @@ void RclMain::catgFilter(int id)
if (id != 0) {
string catg = m_catgbutvec[id];
list<string> tps;
rclconfig->getMimeCatTypes(catg, tps);
theconfig->getMimeCatTypes(catg, tps);
for (list<string>::const_iterator it = tps.begin();
it != tps.end(); it++)
m_filtspec.orCrit(DocSeqFiltSpec::DSFS_MIMETYPE, *it);

View File

@ -133,7 +133,8 @@ private:
bool m_sortspecnochange;
DocSeqSortSpec m_sortspec;
RefCntr<DocSequence> m_source;
int m_periodicToggle;
virtual void init();
virtual void previewPrevOrNextInTab(Preview *, int sid, int docnum,
bool next);

View File

@ -21,6 +21,7 @@
#include "rclconfig.h"
#include "rcldb.h"
#include "idxthread.h"
#include "ptmutex.h"
// Misc declarations in need of sharing between the UI files
@ -30,7 +31,11 @@ extern bool maybeOpenDb(std::string &reason, bool force = true);
/** Retrieve configured stemming languages */
bool getStemLangs(list<string>& langs);
extern RclConfig *rclconfig;
extern RclConfig *theconfig;
extern RclConfig *thestableconfig;
extern PTMutexInit thestableconfiglock;
extern void snapshotConfig();
extern Rcl::Db *rcldb;
extern int recollNeedsExit;
extern int startIndexingAfterConfig; // 1st startup

View File

@ -158,7 +158,7 @@ string QtGuiResListPager::pageTop()
string QtGuiResListPager::iconPath(const string& mtype)
{
string iconpath;
rclconfig->getMimeIconName(mtype, &iconpath);
theconfig->getMimeIconName(mtype, &iconpath);
return iconpath;
}
@ -167,7 +167,7 @@ void QtGuiResListPager::suggest(const vector<string>uterms, vector<string>&sugg)
sugg.clear();
#ifdef RCL_USE_ASPELL
bool noaspell = false;
rclconfig->getConfParam("noaspell", &noaspell);
theconfig->getConfParam("noaspell", &noaspell);
if (noaspell)
return;
if (!aspell) {
@ -524,7 +524,7 @@ void ResList::displayPage()
{
m_pageParaToReldocnums.clear();
clear();
m_pager->displayPage(rclconfig);
m_pager->displayPage(theconfig);
LOGDEB0(("ResList::resultPageNext: hasNext %d hasPrev %d\n",
m_pager->hasPrev(), m_pager->hasNext()));
emit prevPageAvailable(m_pager->hasPrev());

View File

@ -102,7 +102,7 @@ const string& ResTablePager::parFormat()
string ResTablePager::iconPath(const string& mtype)
{
string iconpath;
rclconfig->getMimeIconName(mtype, &iconpath);
theconfig->getMimeIconName(mtype, &iconpath);
return iconpath;
}
@ -229,8 +229,8 @@ RecollModel::RecollModel(const QStringList fields, QObject *parent)
// Add dynamic "stored" fields to the full column list. This
// could be protected to be done only once, but it's no real
// problem
if (rclconfig) {
const set<string>& stored = rclconfig->getStoredFields();
if (theconfig) {
const set<string>& stored = theconfig->getStoredFields();
for (set<string>::const_iterator it = stored.begin();
it != stored.end(); it++) {
if (o_displayableFields.find(*it) == o_displayableFields.end()) {
@ -535,7 +535,7 @@ void ResTable::onTableView_currentChanged(const QModelIndex& index)
m_detail->clear();
m_detaildocnum = index.row();
m_detaildoc = doc;
m_pager->displayDoc(rclconfig, index.row(), doc, m_model->m_hdata);
m_pager->displayDoc(theconfig, index.row(), doc, m_model->m_hdata);
} else {
m_detaildocnum = -1;
}

View File

@ -82,8 +82,8 @@ void SearchClauseW::languageChange()
// sTpCMB->insertItem(tr("Complex clause"));//6
fldCMB->addItem(tr("In field"));
if (rclconfig) {
set<string> fields = rclconfig->getIndexedFields();
if (theconfig) {
set<string> fields = theconfig->getIndexedFields();
for (set<string>::const_iterator it = fields.begin();
it != fields.end(); it++) {
// Some fields don't make sense here

View File

@ -50,7 +50,7 @@ void SpellW::init()
/*2*/expTypeCMB->addItem(tr("Stem expansion"));
#ifdef RCL_USE_ASPELL
bool noaspell = false;
rclconfig->getConfParam("noaspell", &noaspell);
theconfig->getConfParam("noaspell", &noaspell);
if (!noaspell)
/*3*/expTypeCMB->addItem(tr("Spelling/Phonetic"));
#endif

View File

@ -132,9 +132,9 @@ void SSearch::startSimpleSearch()
if (tp == SST_LANG) {
string reason;
if (prefs.autoSuffsEnable)
sdata = wasaStringToRcl(rclconfig, u8, reason, (const char *)prefs.autoSuffs.toUtf8());
sdata = wasaStringToRcl(theconfig, u8, reason, (const char *)prefs.autoSuffs.toUtf8());
else
sdata = wasaStringToRcl(rclconfig, u8, reason);
sdata = wasaStringToRcl(theconfig, u8, reason);
if (sdata == 0) {
QMessageBox::warning(0, "Recoll", tr("Bad query string") + ": " +
QString::fromAscii(reason.c_str()));
@ -280,7 +280,7 @@ void SSearch::completion()
Rcl::TermMatchResult tmres;
string stemLang = (const char *)prefs.queryStemLang.toAscii();
if (stemLang == "ALL") {
rclconfig->getConfParam("indexstemminglanguages", stemLang);
theconfig->getConfParam("indexstemminglanguages", stemLang);
}
if (!rcldb->termMatch(Rcl::Db::ET_WILD, stemLang, s, tmres, max) ||
tmres.entries.size() == 0) {

View File

@ -372,7 +372,7 @@ void UIPrefsDialog::addExtraDbPB_clicked()
}
struct stat st1, st2;
stat(dbdir.c_str(), &st1);
string rcldbdir = rclconfig->getDbDir();
string rcldbdir = theconfig->getDbDir();
stat(rcldbdir.c_str(), &st2);
path_catslash(rcldbdir);

View File

@ -51,7 +51,7 @@ void ViewAction::fillLists()
actionsLV->clear();
actionsLV->verticalHeader()->setDefaultSectionSize(20);
vector<pair<string, string> > defs;
rclconfig->getMimeViewerDefs(defs);
theconfig->getMimeViewerDefs(defs);
actionsLV->setRowCount(defs.size());
int row = 0;
for (vector<pair<string, string> >::const_iterator it = defs.begin();
@ -128,7 +128,7 @@ void ViewAction::editActions()
string sact = (const char *)newaction.toLocal8Bit();
for (list<string>::const_iterator it = mtypes.begin();
it != mtypes.end(); it++) {
rclconfig->setMimeViewerDef(*it, sact);
theconfig->setMimeViewerDef(*it, sact);
}
fillLists();
}

View File

@ -372,7 +372,7 @@ string ResListPager::detailsLink()
const string &ResListPager::parFormat()
{
const static string format("<img src=\"%I\" align=\"left\">"
static const string format("<img src=\"%I\" align=\"left\">"
"%R %S %L &nbsp;&nbsp;<b>%T</b><br>"
"%M&nbsp;%D&nbsp;&nbsp;&nbsp;<i>%U</i><br>"
"%A %K");

View File

@ -80,7 +80,7 @@ string version_string(){
// Synthetic abstract marker (to discriminate from abstract actually
// found in document)
const static string rclSyntAbs("?!#@");
static const string rclSyntAbs("?!#@");
// Compute the unique term used to link documents to their origin.
// "Q" + external udi

View File

@ -38,7 +38,7 @@ namespace Rcl {
namespace StemDb {
const static string stemdirstem = "stem_";
static const string stemdirstem = "stem_";
/// Compute name of stem db for given base database and language
static string stemdbname(const string& dbdir, const string& lang)

View File

@ -19,7 +19,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -44,6 +43,7 @@
#include "smallut.h"
#include "netcon.h"
#include "closefrom.h"
#include "ptmutex.h"
#ifndef NO_NAMESPACES
using namespace std;
@ -316,38 +316,20 @@ 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
class ExecLocking {
public:
pthread_mutex_t m_mutex;
ExecLocking()
{
pthread_mutex_init(&m_mutex, 0);
}
};
ExecLocking o_lock;
class ExecLocker {
public:
ExecLocker()
{
pthread_mutex_lock(&o_lock.m_mutex);
}
~ExecLocker()
{
pthread_mutex_unlock(&o_lock.m_mutex);
}
};
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;
}
// Cleanup in case we return early
ExecCmdRsrc e(this);
// Only one thread allowed in here...
ExecLocker locker;
int ret = 0;
if (input || output) {

52
src/utils/ptmutex.h Normal file
View File

@ -0,0 +1,52 @@
/* Copyright (C) 2011 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _PTMUTEX_H_INCLUDED_
#define _PTMUTEX_H_INCLUDED_
#include <pthread.h>
/// A trivial wrapper/helper for pthread mutex locks
/// Init lock. Used as a single PTMutexInit static object.
class PTMutexInit {
public:
pthread_mutex_t m_mutex;
PTMutexInit()
{
pthread_mutex_init(&m_mutex, 0);
}
};
/// Take the lock when constructed, release when deleted
class PTMutexLocker {
public:
PTMutexLocker(PTMutexInit& l) : m_lock(l)
{
m_status = pthread_mutex_lock(&m_lock.m_mutex);
}
~PTMutexLocker()
{
pthread_mutex_unlock(&m_lock.m_mutex);
}
int ok() {return m_status == 0;}
private:
PTMutexInit& m_lock;
int m_status;
};
#endif /* _PTMUTEX_H_INCLUDED_ */