1
0
Fork 0
arangodb/Scheduler/SchedulerThread.cpp

235 lines
6.0 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief scheduler thread
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Martin Schoenert
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "SchedulerThread.h"
#include <Logger/Logger.h>
#include "Scheduler/Task.h"
using namespace triagens::basics;
namespace triagens {
namespace rest {
// -----------------------------------------------------------------------------
// constructors and destructors
// -----------------------------------------------------------------------------
SchedulerThread::SchedulerThread (Scheduler* scheduler, EventLoop loop, bool defaultLoop)
: Thread("SchedulerThread"),
scheduler(scheduler),
defaultLoop(defaultLoop),
loop(loop),
stopping(0),
hasWork(0) {
// allow cancelation
allowAsynchronousCancelation();
}
// -----------------------------------------------------------------------------
// public methods
// -----------------------------------------------------------------------------
void SchedulerThread::beginShutdown () {
// same thread, in this case it does not matter if we are inside the loop
if (threadId() == currentThreadId()) {
if (stopping == 0) {
LOGGER_DEBUG << "beginning shutdown sequence (self, " << threadId() << ")";
stopping = 1;
scheduler->wakeupLoop(loop);
}
}
// different thread, be careful and send a signal
else {
if (stopping == 0) {
LOGGER_DEBUG << "beginning shutdown sequence (" << threadId() << ")";
stopping = 1;
scheduler->wakeupLoop(loop);
}
}
}
void SchedulerThread::registerTask (Scheduler* scheduler, Task* task) {
// same thread, in this case it does not matter if we are inside the loop
if (threadId() == currentThreadId()) {
setupTask(task, scheduler, loop);
scheduler->wakeupLoop(loop);
}
// different thread, be careful - we have to stop the event loop
else {
// put the register request unto the queue
queueLock.lock();
Work w(SETUP, scheduler, task);
queue.push_back(w);
hasWork = 1;
scheduler->wakeupLoop(loop);
queueLock.unlock();
}
}
void SchedulerThread::unregisterTask (Task* task) {
deactivateTask(task);
// same thread, in this case it does not matter if we are inside the loop
if (threadId() == currentThreadId()) {
cleanupTask(task);
scheduler->wakeupLoop(loop);
}
// different thread, be careful - we have to stop the event loop
else {
// put the unregister request unto the queue
queueLock.lock();
Work w(CLEANUP, 0, task);
queue.push_back(w);
hasWork = 1;
scheduler->wakeupLoop(loop);
queueLock.unlock();
}
}
void SchedulerThread::destroyTask (Task* task) {
deactivateTask(task);
// same thread, in this case it does not matter if we are inside the loop
if (threadId() == currentThreadId()) {
cleanupTask(task);
deleteTask(task);
scheduler->wakeupLoop(loop);
}
// different thread, be careful - we have to stop the event loop
else {
// put the unregister request unto the queue
queueLock.lock();
Work w(DESTROY, 0, task);
queue.push_back(w);
hasWork = 1;
scheduler->wakeupLoop(loop);
queueLock.unlock();
}
}
// -----------------------------------------------------------------------------
// Thread methods
// -----------------------------------------------------------------------------
void SchedulerThread::run () {
LOGGER_TRACE << "scheduler thread started (" << threadId() << ")";
if (defaultLoop) {
sigset_t all;
sigemptyset(&all);
pthread_sigmask(SIG_SETMASK, &all, 0);
}
while (stopping == 0) {
try {
scheduler->eventLoop(loop);
}
catch (...) {
#ifdef TRI_HAVE_POSIX_THREADS
if (stopping != 0) {
LOGGER_WARNING << "caught cancellation exception during work";
throw;
}
#endif
LOGGER_WARNING << "caught exception from ev_loop";
}
#if defined(DEBUG_SCHEDULER_THREAD)
LOGGER_TRACE << "left scheduler loop " << threadId();
#endif
if (hasWork != 0) {
queueLock.lock();
while (! queue.empty()) {
Work w = queue.front();
queue.pop_front();
queueLock.unlock();
switch (w.work) {
case CLEANUP:
cleanupTask(w.task);
break;
case SETUP:
setupTask(w.task, w.scheduler, loop);
break;
case DESTROY:
cleanupTask(w.task);
deleteTask(w.task);
break;
}
queueLock.lock();
}
hasWork = 0;
queueLock.unlock();
}
}
LOGGER_TRACE << "scheduler thread stopped (" << threadId() << ")";
}
}
}