--- a/src/index/rclmonprc.cpp
+++ b/src/index/rclmonprc.cpp
@@ -24,7 +24,6 @@
* initialization function.
*/
-#include <pthread.h>
#include <errno.h>
#include <fnmatch.h>
#include "safeunistd.h"
@@ -34,6 +33,11 @@
#include <cstdlib>
#include <list>
#include <vector>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+
using std::list;
using std::vector;
@@ -50,8 +54,6 @@
#include "subtreelist.h"
typedef unsigned long mttcast;
-
-static pthread_t rcv_thrid;
// Seconds between auxiliary db (stem, spell) updates:
static const int dfltauxinterval = 60 *60;
@@ -135,13 +137,13 @@
vector<DelayPat> m_delaypats;
RclConfig *m_config;
bool m_ok;
- pthread_mutex_t m_mutex;
- pthread_cond_t m_cond;
+
+ std::mutex m_mutex;
+ std::condition_variable m_cond;
+
RclEQData()
- : m_config(0), m_ok(false)
+ : m_config(0), m_ok(true)
{
- if (!pthread_mutex_init(&m_mutex, 0) && !pthread_cond_init(&m_cond, 0))
- m_ok = true;
}
void readDelayPats(int dfltsecs);
DelayPat searchDelayPats(const string& path)
@@ -192,8 +194,8 @@
// when necessary.
void RclEQData::delayInsert(const queue_type::iterator &qit)
{
- MONDEB(("RclEQData::delayInsert: minclock %lu\n",
- (mttcast)qit->second.m_minclock));
+ MONDEB("RclEQData::delayInsert: minclock " << qit->second.m_minclock <<
+ std::endl);
for (delays_type::iterator dit = m_delays.begin();
dit != m_delays.end(); dit++) {
queue_type::iterator qit1 = *dit;
@@ -222,62 +224,33 @@
}
/** Wait until there is something to process on the queue, or timeout.
- * Must be called with the queue locked
+ * returns a queue lock
*/
-bool RclMonEventQueue::wait(int seconds, bool *top)
-{
- MONDEB(("RclMonEventQueue::wait\n"));
+std::unique_lock<std::mutex> RclMonEventQueue::wait(int seconds, bool *top)
+{
+ std::unique_lock<std::mutex> lock(m_data->m_mutex);
+
+ MONDEB("RclMonEventQueue::wait, seconds: " << seconds << std::endl);
if (!empty()) {
- MONDEB(("RclMonEventQueue:: imm return\n"));
- return true;
+ MONDEB("RclMonEventQueue:: immediate return\n");
+ return lock;
}
int err;
if (seconds > 0) {
- struct timespec to;
- to.tv_sec = time(0L) + seconds;
- to.tv_nsec = 0;
if (top)
*top = false;
- if ((err =
- pthread_cond_timedwait(&m_data->m_cond, &m_data->m_mutex, &to))) {
- if (err == ETIMEDOUT) {
- *top = true;
- MONDEB(("RclMonEventQueue:: timeout\n"));
- return true;
- }
- LOGERR("RclMonEventQueue::wait:pthread_cond_timedwait failedwith err " << (err) << "\n" );
- return false;
- }
+ if (m_data->m_cond.wait_for(lock, std::chrono::seconds(seconds)) ==
+ std::cv_status::timeout) {
+ *top = true;
+ MONDEB("RclMonEventQueue:: timeout\n");
+ return lock;
+ }
} else {
- if ((err = pthread_cond_wait(&m_data->m_cond, &m_data->m_mutex))) {
- LOGERR("RclMonEventQueue::wait: pthread_cond_wait failedwith err " << (err) << "\n" );
- return false;
- }
- }
- MONDEB(("RclMonEventQueue:: normal return\n"));
- return true;
-}
-
-bool RclMonEventQueue::lock()
-{
- MONDEB(("RclMonEventQueue:: lock\n"));
- if (pthread_mutex_lock(&m_data->m_mutex)) {
- LOGERR("RclMonEventQueue::lock: pthread_mutex_lock failed\n" );
- return false;
- }
- MONDEB(("RclMonEventQueue:: lock return\n"));
- return true;
-}
-
-bool RclMonEventQueue::unlock()
-{
- MONDEB(("RclMonEventQueue:: unlock\n"));
- if (pthread_mutex_unlock(&m_data->m_mutex)) {
- LOGERR("RclMonEventQueue::lock: pthread_mutex_unlock failed\n" );
- return false;
- }
- return true;
+ m_data->m_cond.wait(lock);
+ }
+ MONDEB("RclMonEventQueue:: non-timeout return\n");
+ return lock;
}
void RclMonEventQueue::setConfig(RclConfig *cnf)
@@ -312,37 +285,36 @@
void RclMonEventQueue::setTerminate()
{
- MONDEB(("RclMonEventQueue:: setTerminate\n"));
- lock();
+ MONDEB("RclMonEventQueue:: setTerminate\n");
+ std::unique_lock<std::mutex> lock(m_data->m_mutex);
m_data->m_ok = false;
- pthread_cond_broadcast(&m_data->m_cond);
- unlock();
+ m_data->m_cond.notify_all();
}
// Must be called with the queue locked
bool RclMonEventQueue::empty()
{
if (m_data == 0) {
- MONDEB(("RclMonEventQueue::empty(): true (m_data==0)\n"));
+ MONDEB("RclMonEventQueue::empty(): true (m_data==0)\n");
return true;
}
if (!m_data->m_iqueue.empty()) {
- MONDEB(("RclMonEventQueue::empty(): false (m_iqueue not empty)\n"));
+ MONDEB("RclMonEventQueue::empty(): false (m_iqueue not empty)\n");
return true;
}
if (m_data->m_dqueue.empty()) {
- MONDEB(("RclMonEventQueue::empty(): true (m_Xqueue both empty)\n"));
+ MONDEB("RclMonEventQueue::empty(): true (m_Xqueue both empty)\n");
return true;
}
// Only dqueue has events. Have to check the delays (only the
// first, earliest one):
queue_type::iterator qit = *(m_data->m_delays.begin());
if (qit->second.m_minclock > time(0)) {
- MONDEB(("RclMonEventQueue::empty(): true (no delay ready %lu)\n",
- (mttcast)qit->second.m_minclock));
+ MONDEB("RclMonEventQueue::empty(): true (no delay ready " <<
+ qit->second.m_minclock << ")\n");
return true;
}
- MONDEB(("RclMonEventQueue::empty(): returning false (delay expired)\n"));
+ MONDEB("RclMonEventQueue::empty(): returning false (delay expired)\n");
return false;
}
@@ -352,15 +324,15 @@
RclMonEvent RclMonEventQueue::pop()
{
time_t now = time(0);
- MONDEB(("RclMonEventQueue::pop(), now %lu\n", (mttcast)now));
+ MONDEB("RclMonEventQueue::pop(), now " << now << std::endl);
// Look at the delayed events, get rid of the expired/unactive
// ones, possibly return an expired/needidx one.
while (!m_data->m_delays.empty()) {
delays_type::iterator dit = m_data->m_delays.begin();
queue_type::iterator qit = *dit;
- MONDEB(("RclMonEventQueue::pop(): in delays: evt minclock %lu\n",
- (mttcast)qit->second.m_minclock));
+ MONDEB("RclMonEventQueue::pop(): in delays: evt minclock " <<
+ qit->second.m_minclock << std::endl);
if (qit->second.m_minclock <= now) {
if (qit->second.m_needidx) {
RclMonEvent ev = qit->second;
@@ -399,8 +371,8 @@
// special processing to limit their reindexing rate.
bool RclMonEventQueue::pushEvent(const RclMonEvent &ev)
{
- MONDEB(("RclMonEventQueue::pushEvent for %s\n", ev.m_path.c_str()));
- lock();
+ MONDEB("RclMonEventQueue::pushEvent for " << ev.m_path << std::endl);
+ std::unique_lock<std::mutex> lock(m_data->m_mutex);
DelayPat pat = m_data->searchDelayPats(ev.m_path);
if (pat.seconds != 0) {
@@ -432,8 +404,7 @@
m_data->m_iqueue[ev.m_path] = ev;
}
- pthread_cond_broadcast(&m_data->m_cond);
- unlock();
+ m_data->m_cond.notify_all();
return true;
}
@@ -482,19 +453,12 @@
if (!conf->getConfParam("monixinterval", &ixinterval))
ixinterval = dfltixinterval;
-
rclEQ.setConfig(conf);
rclEQ.setopts(opts);
- if (pthread_create(&rcv_thrid, 0, &rclMonRcvRun, &rclEQ) != 0) {
- LOGERR("startMonitor: cant create event-receiving thread\n" );
- return false;
- }
-
- if (!rclEQ.lock()) {
- LOGERR("startMonitor: cant lock queue ???\n" );
- return false;
- }
+ std::thread treceive(rclMonRcvRun, &rclEQ);
+ treceive.detach();
+
LOGDEB("start_monitoring: entering main loop\n" );
bool timedout;
@@ -504,61 +468,62 @@
list<string> modified;
list<string> deleted;
+ ;
+
// Set a relatively short timeout for better monitoring of exit requests
- while (rclEQ.wait(2, &timedout)) {
- // Queue is locked.
-
- // x11IsAlive() can't be called from ok() because both threads call it
- // and Xlib is not multithreaded.
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock = rclEQ.wait(2, &timedout);
+
+ // x11IsAlive() can't be called from ok() because both
+ // threads call it and Xlib is not multithreaded.
#ifndef _WIN32
- bool x11dead = !(opts & RCLMON_NOX11) && !x11IsAlive();
- if (x11dead)
- LOGDEB("RclMonprc: x11 is dead\n" );
+ bool x11dead = !(opts & RCLMON_NOX11) && !x11IsAlive();
+ if (x11dead)
+ LOGDEB("RclMonprc: x11 is dead\n" );
#else
- bool x11dead = false;
+ bool x11dead = false;
#endif
- if (!rclEQ.ok() || x11dead) {
- rclEQ.unlock();
- break;
- }
+ if (!rclEQ.ok() || x11dead) {
+ break;
+ }
- // Process event queue
- for (;;) {
- // Retrieve event
- RclMonEvent ev = rclEQ.pop();
- if (ev.m_path.empty())
- break;
- switch (ev.evtype()) {
- case RclMonEvent::RCLEVT_MODIFY:
- case RclMonEvent::RCLEVT_DIRCREATE:
- LOGDEB0("Monitor: Modify/Check on " << (ev.m_path) << "\n" );
- modified.push_back(ev.m_path);
- break;
- case RclMonEvent::RCLEVT_DELETE:
- LOGDEB0("Monitor: Delete on " << (ev.m_path) << "\n" );
- // If this is for a directory (which the caller should
- // tell us because he knows), we should purge the db
- // of all the subtree, because on a directory rename,
- // inotify will only generate one event for the
- // renamed top, not the subentries. This is relatively
- // complicated to do though, and we currently do not
- // do it, and just wait for a restart to do a full run and
- // purge.
- deleted.push_back(ev.m_path);
- if (ev.evflags() & RclMonEvent::RCLEVT_ISDIR) {
- vector<string> paths;
- if (subtreelist(conf, ev.m_path, paths)) {
- deleted.insert(deleted.end(),
- paths.begin(), paths.end());
- }
- }
- break;
- default:
- LOGDEB("Monitor: got Other on [" << (ev.m_path) << "]\n" );
- }
- }
- // Unlock queue before processing lists
- rclEQ.unlock();
+ // Process event queue
+ for (;;) {
+ // Retrieve event
+ RclMonEvent ev = rclEQ.pop();
+ if (ev.m_path.empty())
+ break;
+ switch (ev.evtype()) {
+ case RclMonEvent::RCLEVT_MODIFY:
+ case RclMonEvent::RCLEVT_DIRCREATE:
+ LOGDEB0("Monitor: Modify/Check on " << ev.m_path << "\n");
+ modified.push_back(ev.m_path);
+ break;
+ case RclMonEvent::RCLEVT_DELETE:
+ LOGDEB0("Monitor: Delete on " << (ev.m_path) << "\n" );
+ // If this is for a directory (which the caller should
+ // tell us because he knows), we should purge the db
+ // of all the subtree, because on a directory rename,
+ // inotify will only generate one event for the
+ // renamed top, not the subentries. This is relatively
+ // complicated to do though, and we currently do not
+ // do it, and just wait for a restart to do a full run and
+ // purge.
+ deleted.push_back(ev.m_path);
+ if (ev.evflags() & RclMonEvent::RCLEVT_ISDIR) {
+ vector<string> paths;
+ if (subtreelist(conf, ev.m_path, paths)) {
+ deleted.insert(deleted.end(),
+ paths.begin(), paths.end());
+ }
+ }
+ break;
+ default:
+ LOGDEB("Monitor: got Other on [" << (ev.m_path) << "]\n" );
+ }
+ }
+ }
// Process. We don't do this every time but let the lists accumulate
// a little, this saves processing. Start at once if list is big.
@@ -608,8 +573,6 @@
o_reexec->removeArg("-n");
o_reexec->reexec();
}
- // Lock queue before waiting again
- rclEQ.lock();
}
LOGDEB("Rclmonprc: calling queue setTerminate\n" );
rclEQ.setTerminate();
@@ -619,7 +582,6 @@
// during our limited time window for exiting. To be reviewed if
// we ever need several monitor invocations in the same process
// (can't foresee any reason why we'd want to do this).
- // pthread_join(rcv_thrid, 0);
LOGDEB("Monitor: returning\n" );
return true;
}