Skip to content

Commit

Permalink
Fix some mythbackend shutdown races.
Browse files Browse the repository at this point in the history
The Scheduler and AutoExpirer each keep a pointer to MainServer, but the main server was being deleted while those threads were still running with a pointer to the deleted MainServer. The scheduler doesn't have any semaphore for the variable so this shuts down that thread in the MainServer dtor. AutoExpire does mutex protect the variable, so this just adds a AutoExpirer::SetMainServer(NULL) call to the MainServer dtor for that one.

The HouseKeeping thread wasn't being explicitly stopped, but keeps a pointer to the scheduler and uses gCoreContext.. so we now tear it down before we delete the Scheduler and MythCoreContext.

The JobQueue thread wasn't being explicitly stopped, but used the gCoreContext; we now tear it down before we delete MythCoreContext.
  • Loading branch information
daniel-kristjansson committed Jul 28, 2011
1 parent 13deede commit c01fd21
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 2 deletions.
16 changes: 14 additions & 2 deletions mythtv/programs/mythbackend/main_helpers.cpp
Expand Up @@ -220,8 +220,20 @@ void cleanup(void)
signal(SIGUSR1, SIG_DFL);
#endif

delete gCoreContext->GetScheduler();
gCoreContext->SetScheduler(NULL);
delete housekeeping;
housekeeping = NULL;

if (gCoreContext)
{
delete gCoreContext->GetScheduler();
gCoreContext->SetScheduler(NULL);
}

delete expirer;
expirer;

delete jobqueue;
jobqueue = NULL;

delete g_pUPnp;
g_pUPnp = NULL;
Expand Down
24 changes: 24 additions & 0 deletions mythtv/programs/mythbackend/mainserver.cpp
Expand Up @@ -125,6 +125,7 @@ class ProcessRequestThread : public QThread
public:
ProcessRequestThread(MainServer *ms) :
parent(ms), socket(NULL), threadlives(false) {}
~ProcessRequestThread() { killit(); wait(); }

void setup(MythSocket *sock)
{
Expand Down Expand Up @@ -247,6 +248,12 @@ MainServer::MainServer(bool master, int port,

MainServer::~MainServer()
{
// since Scheduler::SetMainServer() isn't thread-safe
// we need to shut down the scheduler thread before we
// can call SetMainServer(NULL)
if (m_sched)
m_sched->Stop();

PreviewGeneratorQueue::RemoveListener(this);
PreviewGeneratorQueue::TeardownPreviewGeneratorQueue();

Expand All @@ -256,6 +263,23 @@ MainServer::~MainServer()
mythserver->deleteLater();
mythserver = NULL;
}

if (m_sched)
{
m_sched->Wait();
m_sched->SetMainServer(NULL);
}

if (m_expirer)
m_expirer->SetMainServer(NULL);

QMutexLocker locker(&threadPoolLock);
MythDeque<ProcessRequestThread*>::iterator it;
for (it = threadPool.begin(); it != threadPool.end(); ++it)
(*it)->killit();
for (it = threadPool.begin(); it != threadPool.end(); ++it)
delete (*it);
threadPool.clear();
}

void MainServer::autoexpireUpdate(void)
Expand Down
7 changes: 7 additions & 0 deletions mythtv/programs/mythbackend/scheduler.cpp
Expand Up @@ -139,6 +139,13 @@ Scheduler::~Scheduler()
wait();
}

void Scheduler::Stop(void)
{
QMutexLocker locker(&schedLock);
doRun = false;
reschedWait.wakeAll();
}

void Scheduler::SetMainServer(MainServer *ms)
{
m_mainServer = ms;
Expand Down
3 changes: 3 additions & 0 deletions mythtv/programs/mythbackend/scheduler.h
Expand Up @@ -37,6 +37,9 @@ class Scheduler : public QThread, public MythScheduler
QString recordTbl = "record", Scheduler *master_sched = NULL);
~Scheduler();

void Stop(void);
void Wait(void) { QThread::wait(); }

void SetExpirer(AutoExpire *autoExpirer) { m_expirer = autoExpirer; }

void Reschedule(int recordid);
Expand Down

0 comments on commit c01fd21

Please sign in to comment.