/***** * * TOra - An Oracle Toolkit for DBA's and developers * Copyright (C) 2003-2005 Quest Software, Inc * Portions Copyright (C) 2005 Other Contributors * * 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; only version 2 of * the License is valid for this program. * * 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. * * As a special exception, you have permission to link this program * with the Oracle Client libraries and distribute executables, as long * as you follow the requirements of the GNU GPL in regard to all of the * software in the executable aside from Oracle client libraries. * * Specifically you are not permitted to link this program with the * Qt/UNIX, Qt/Windows or Qt Non Commercial products of TrollTech. * And you are not permitted to distribute binaries compiled against * these libraries without written consent from Quest Software, Inc. * Observe that this does not disallow linking to the Qt Free Edition. * * You may link this product with any GPL'd Qt library such as Qt/Free * * All trademarks belong to their respective owners. * *****/ #include "utils.h" #include "tomain.h" #include "tothread.h" #include #include #include #include #ifdef QT_THREAD_SUPPORT void toSemaphore::up(void) { Mutex.lock(); Value++; if (Value > 0) Condition.wakeOne(); Mutex.unlock(); } void toSemaphore::down(void) { Mutex.lock(); while (Value <= 0) { Condition.wait(&Mutex); } Value--; Mutex.unlock(); } int toSemaphore::getValue(void) { Mutex.lock(); int val = Value; Mutex.unlock(); return val; } #else #define SEM_ASSERT(x) if((x)!=0) toStatusMessage(\ qApp->translate("toSemaphore","The semaphore function \"%1\" failed").arg(QString::fromLatin1( #x ))); void toSemaphore::init(int ival) { SEM_ASSERT(sem_init(&Semaphore, 0, ival)); } toSemaphore::toSemaphore() { init(0); } toSemaphore::toSemaphore(int i) { init(i); } toSemaphore::~toSemaphore() { SEM_ASSERT(sem_destroy(&Semaphore)); } void toSemaphore::up() { SEM_ASSERT(sem_post(&Semaphore)); } void toSemaphore::down() { SEM_ASSERT(sem_wait(&Semaphore)); } int toSemaphore::getValue() { int r; SEM_ASSERT(sem_getvalue(&Semaphore, &r)); return r; } #endif #ifndef WIN32 #include pthread_t toThread::MainThread = pthread_self(); toThread *toThread::DeleteThread; toLock *toThread::Lock; #define MUTEX_ASSERT(x) if((x)!=0) toStatusMessage(\ qApp->translate("toLock","The mutex function \"%1\" failed").arg(QString::fromLatin1( #x ))); toLock::toLock(void) { MUTEX_ASSERT(pthread_mutex_init(&Mutex, NULL)); } toLock::~toLock() { MUTEX_ASSERT(pthread_mutex_destroy(&Mutex)); } void toLock::lock () { MUTEX_ASSERT(pthread_mutex_lock(&Mutex)); } void toLock::unlock() { MUTEX_ASSERT(pthread_mutex_unlock(&Mutex)); } #define THREAD_ASSERT(x) if((x)!=0) { \ throw (qApp->translate("toThread","Thread function \"%1\" failed.").arg(QString::fromLatin1( #x ))); } void toThread::initAttr() { //create the thread detached, so everything is cleaned up //after it's finished. try { THREAD_ASSERT(pthread_attr_init(&ThreadAttr)); THREAD_ASSERT(pthread_attr_setdetachstate(&ThreadAttr, PTHREAD_CREATE_DETACHED)); } TOCATCH } toThread::toThread(toTask *t) : Task(t) { if (!Lock) Lock = new toLock; initAttr(); } toThread::~toThread() { THREAD_ASSERT(pthread_attr_destroy(&ThreadAttr)); } void toThread::start() { if (pthread_create(&(Thread), &(ThreadAttr), toThreadStartWrapper, (void *)this) == 0) StartSemaphore.down(); else throw qApp->translate("toThread", "Thread function \"%1\" failed.").arg("toThread::start()"); } void toThread::startAsync() { THREAD_ASSERT(pthread_create(&(Thread), &(ThreadAttr), toThreadStartWrapper, (void *)this)); } void *toThreadStartWrapper(void *t) { toThread *thread = (toThread*)t; //tell whoever called this->start that we're running sigset_t Sigs; sigfillset(&Sigs); #ifndef TO_NO_PTHREADSIGMASK sigdelset(&Sigs, SIGHUP); // I hope this signal will cancel subqueries sigdelset(&Sigs, SIGQUIT); sigdelset(&Sigs, SIGALRM); sigdelset(&Sigs, SIGTERM); sigdelset(&Sigs, SIGCHLD); sigdelset(&Sigs, SIGWINCH); sigdelset(&Sigs, SIGSEGV); sigdelset(&Sigs, SIGPIPE); sigdelset(&Sigs, SIGUSR1); pthread_sigmask(SIG_BLOCK, &Sigs, NULL); sigemptyset(&Sigs); sigaddset(&Sigs, SIGINT); pthread_sigmask(SIG_UNBLOCK, &Sigs, NULL); #endif try { thread->StartSemaphore.up(); thread->Task->run(); } catch (const QString &exc) { fprintf(stderr, "Unhandled exception in thread:\n%s\n", (const char *)exc); } catch (...) { fprintf(stderr, "Unhandled exception in thread:\nUnknown type\n"); } delete thread->Task; toThread::Lock->lock () ; if (toThread::DeleteThread) delete toThread::DeleteThread; toThread::DeleteThread = thread; toThread::Lock->unlock(); return NULL; } bool toThread::mainThread(void) { return pthread_equal(MainThread, pthread_self()); } #ifdef QT_THREAD_SUPPORT class toThreadWrapper : public QThread { public: static void msleep(int num) { QThread::msleep(num); } }; #endif void toThread::msleep(int msec) { #ifdef QT_THREAD_SUPPORT toThreadWrapper::msleep(msec); #else struct timespec req; req.tv_sec = msec / 1000; req.tv_nsec = (msec % 1000) * 1000000; nanosleep(&req, &req); #endif } #else std::list *toThread::Threads; toLock *toThread::Lock; int toThread::LastID = 0; __declspec( thread ) int toThread::ThreadID = 0; int toThread::MainThread = -1; bool toThread::mainThread(void) { return MainThread == ThreadID; } toThread::toThread(toTask *task) : Thread(task) { if (!Threads) Threads = new std::list; if (!Lock) Lock = new toLock; } toThread::~toThread() {} void toThread::start(void) { Thread.start(); Thread.StartSemaphore.down(); Lock->lock () ; Threads->insert(Threads->end(), this); Lock->unlock(); } void toThread::startAsync(void) { Thread.start(); Lock->lock () ; Threads->insert(Threads->end(), this); Lock->unlock(); } void toThread::msleep(int msec) { taskRunner::msleep(msec); } toThread::taskRunner::taskRunner(toTask *task) : Task(task) {} void toThread::taskRunner::run(void) { try { Lock->lock () ; StartSemaphore.up(); toThread::LastID++; toThread::ThreadID = LastID; if (toThread::MainThread==-1) toThread::MainThread=LastID; Lock->unlock(); Task->run(); Lock->lock () ; delete Task; Task = NULL; Lock->unlock(); } catch (const QString &exc) { fprintf(stderr, "Unhandled exception in thread:\n%s\n", (const char *)exc); } catch (...) { fprintf(stderr, "Unhandled exception in thread:\nUnknown type\n"); } // This is a cludge to clean up finnished threads, there won't be many hanging at least Lock->lock () ; for (std::list::iterator i = toThread::Threads->begin(); i != toThread::Threads->end();) { if ((*i)->Thread.finished()) { delete (*i); Threads->erase(i); i = Threads->begin(); } else i++; } Lock->unlock(); } #endif