mirror of https://gitee.com/bigwinds/arangodb
346 lines
9.2 KiB
C++
346 lines
9.2 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief scheduler thread
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
|
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Frank Celler
|
|
/// @author Martin Schoenert
|
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
|
/// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WIN32
|
|
#include "Basics/win-utils.h"
|
|
#endif
|
|
|
|
#include "Basics/logging.h"
|
|
#include "SchedulerThread.h"
|
|
|
|
#include "Scheduler/Scheduler.h"
|
|
#include "Scheduler/Task.h"
|
|
|
|
using namespace triagens::basics;
|
|
using namespace triagens::rest;
|
|
|
|
#ifdef TRI_USE_SPIN_LOCK_SCHEDULER_THREAD
|
|
#define SCHEDULER_INIT TRI_InitSpin
|
|
#define SCHEDULER_DESTROY TRI_DestroySpin
|
|
#define SCHEDULER_LOCK TRI_LockSpin
|
|
#define SCHEDULER_UNLOCK TRI_UnlockSpin
|
|
#else
|
|
#define SCHEDULER_INIT TRI_InitMutex
|
|
#define SCHEDULER_DESTROY TRI_DestroyMutex
|
|
#define SCHEDULER_LOCK TRI_LockMutex
|
|
#define SCHEDULER_UNLOCK TRI_UnlockMutex
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- constructors and destructors
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SchedulerThread::SchedulerThread (Scheduler* scheduler, EventLoop loop, bool defaultLoop)
|
|
: Thread("scheduler"),
|
|
_scheduler(scheduler),
|
|
_defaultLoop(defaultLoop),
|
|
_loop(loop),
|
|
_stopping(0),
|
|
_stopped(0),
|
|
_open(0),
|
|
_hasWork(false) {
|
|
|
|
// init lock
|
|
SCHEDULER_INIT(&_queueLock);
|
|
|
|
// allow cancelation
|
|
allowAsynchronousCancelation();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief destructor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SchedulerThread::~SchedulerThread () {
|
|
SCHEDULER_DESTROY(&_queueLock);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks if the scheduler thread is up and running
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool SchedulerThread::isStarted () {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief opens the scheduler thread for business
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool SchedulerThread::open () {
|
|
_open = 1;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief begin shutdown sequence
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SchedulerThread::beginShutdown () {
|
|
LOG_TRACE("beginning shutdown sequence of scheduler thread (%d)", (int) threadId());
|
|
|
|
_stopping = 1;
|
|
_scheduler->wakeupLoop(_loop);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief registers a task
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool SchedulerThread::registerTask (Scheduler* scheduler, Task* task) {
|
|
// thread has already been stopped
|
|
if (_stopped) {
|
|
// do nothing
|
|
return false;
|
|
}
|
|
|
|
// same thread, in this case it does not matter if we are inside the loop
|
|
if (threadId() == currentThreadId()) {
|
|
bool ok = setupTask(task, scheduler, _loop);
|
|
|
|
if (! ok) {
|
|
LOG_WARNING("In SchedulerThread::registerTask setupTask has failed");
|
|
cleanupTask(task);
|
|
deleteTask(task);
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
// different thread, be careful - we have to stop the event loop
|
|
// put the register request onto the queue
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
|
|
Work w(SETUP, scheduler, task);
|
|
_queue.push_back(w);
|
|
_hasWork = true;
|
|
|
|
scheduler->wakeupLoop(_loop);
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief unregisters a task
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SchedulerThread::unregisterTask (Task* task) {
|
|
deactivateTask(task);
|
|
|
|
// thread has already been stopped
|
|
if (_stopped) {
|
|
// do nothing
|
|
}
|
|
|
|
// same thread, in this case it does not matter if we are inside the loop
|
|
else if (threadId() == currentThreadId()) {
|
|
cleanupTask(task);
|
|
}
|
|
|
|
// different thread, be careful - we have to stop the event loop
|
|
else {
|
|
|
|
// put the unregister request unto the queue
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
|
|
Work w(CLEANUP, 0, task);
|
|
_queue.push_back(w);
|
|
_hasWork = true;
|
|
|
|
_scheduler->wakeupLoop(_loop);
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief unregisters a task
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SchedulerThread::destroyTask (Task* task) {
|
|
deactivateTask(task);
|
|
|
|
// thread has already been stopped
|
|
if (_stopped) {
|
|
deleteTask(task);
|
|
}
|
|
|
|
// same thread, in this case it does not matter if we are inside the loop
|
|
else if (threadId() == currentThreadId()) {
|
|
cleanupTask(task);
|
|
deleteTask(task);
|
|
}
|
|
|
|
// different thread, be careful - we have to stop the event loop
|
|
else {
|
|
// put the unregister request unto the queue
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
|
|
Work w(DESTROY, 0, task);
|
|
_queue.push_back(w);
|
|
_hasWork = true;
|
|
|
|
_scheduler->wakeupLoop(_loop);
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- Thread methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// {@inheritDoc}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SchedulerThread::run () {
|
|
LOG_TRACE("scheduler thread started (%d)", (int) threadId());
|
|
|
|
if (_defaultLoop) {
|
|
#ifdef TRI_HAVE_POSIX_THREADS
|
|
sigset_t all;
|
|
sigemptyset(&all);
|
|
pthread_sigmask(SIG_SETMASK, &all, 0);
|
|
#endif
|
|
}
|
|
|
|
while (_stopping == 0 && _open == 0) {
|
|
usleep(1000);
|
|
}
|
|
|
|
while (_stopping == 0) {
|
|
try {
|
|
_scheduler->eventLoop(_loop);
|
|
}
|
|
catch (...) {
|
|
#ifdef TRI_HAVE_POSIX_THREADS
|
|
if (_stopping != 0) {
|
|
LOG_WARNING("caught cancellation exception during work");
|
|
throw;
|
|
}
|
|
#endif
|
|
|
|
LOG_WARNING("caught exception from ev_loop");
|
|
}
|
|
|
|
#if defined(DEBUG_SCHEDULER_THREAD)
|
|
LOG_TRACE("left scheduler loop %d", (int) threadId());
|
|
#endif
|
|
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
|
|
if (_hasWork) {
|
|
while (! _queue.empty()) {
|
|
Work w = _queue.front();
|
|
_queue.pop_front();
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
|
|
switch (w.work) {
|
|
|
|
case CLEANUP: {
|
|
cleanupTask(w.task);
|
|
break;
|
|
}
|
|
|
|
case SETUP: {
|
|
bool ok = setupTask(w.task, w.scheduler, _loop);
|
|
if (! ok) {
|
|
cleanupTask(w.task);
|
|
deleteTask(w.task);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case DESTROY: {
|
|
cleanupTask(w.task);
|
|
deleteTask(w.task);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
}
|
|
|
|
_hasWork = false;
|
|
}
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
}
|
|
|
|
LOG_TRACE("scheduler thread stopped (%d)", (int) threadId());
|
|
|
|
_stopped = 1;
|
|
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
|
|
while (! _queue.empty()) {
|
|
Work w = _queue.front();
|
|
_queue.pop_front();
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
|
|
switch (w.work) {
|
|
case CLEANUP:
|
|
break;
|
|
|
|
case SETUP:
|
|
break;
|
|
|
|
case DESTROY:
|
|
deleteTask(w.task);
|
|
break;
|
|
}
|
|
|
|
SCHEDULER_LOCK(&_queueLock);
|
|
}
|
|
|
|
SCHEDULER_UNLOCK(&_queueLock);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- END-OF-FILE
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
|
// End:
|