2011-04-28 16:35:58 +02:00
|
|
|
/*
|
|
|
|
*
|
2011-04-30 04:28:31 +02:00
|
|
|
* The contents of this file are subject to the Initial
|
|
|
|
* Developer's Public License Version 1.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.ibphoenix.com/idpl.html.
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on
|
|
|
|
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
|
|
|
|
* express or implied. See the License for the specific
|
2011-04-28 16:35:58 +02:00
|
|
|
* language governing rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The contents of this file or any work derived from this file
|
2011-04-30 04:28:31 +02:00
|
|
|
* may not be distributed under any other license whatsoever
|
|
|
|
* without the express prior written permission of the original
|
2011-04-28 16:35:58 +02:00
|
|
|
* author.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The Original Code was created by James A. Starkey for IBPhoenix.
|
|
|
|
*
|
|
|
|
* Copyright (c) 1997 - 2000, 2001, 2003 James A. Starkey
|
|
|
|
* Copyright (c) 1997 - 2000, 2001, 2003 Netfrastructure, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
2011-04-28 18:59:29 +02:00
|
|
|
* The Code was ported into Firebird Open Source RDBMS project by
|
2011-04-28 16:35:58 +02:00
|
|
|
* Vladyslav Khorsun at 2010
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*/
|
|
|
|
|
2012-03-01 09:55:43 +01:00
|
|
|
#include "firebird.h"
|
2011-04-28 16:35:58 +02:00
|
|
|
#include "fb_tls.h"
|
|
|
|
#include "../thd.h"
|
|
|
|
#include "SyncObject.h"
|
|
|
|
#include "Synchronize.h"
|
|
|
|
|
2011-05-23 17:33:19 +02:00
|
|
|
#ifdef TIME_WITH_SYS_TIME
|
|
|
|
# include <sys/time.h>
|
|
|
|
# include <time.h>
|
|
|
|
#else
|
|
|
|
# ifdef HAVE_SYS_TIME_H
|
|
|
|
# include <sys/time.h>
|
|
|
|
# else
|
|
|
|
# include <time.h>
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2011-04-28 16:35:58 +02:00
|
|
|
#define NANO 1000000000
|
|
|
|
#define MICRO 1000000
|
|
|
|
|
|
|
|
namespace Firebird {
|
|
|
|
|
|
|
|
Synchronize::Synchronize()
|
2011-04-30 04:28:31 +02:00
|
|
|
: shutdownInProgress(false),
|
|
|
|
sleeping(false),
|
|
|
|
wakeup(false)
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
evnt = CreateEvent(NULL, false, false, NULL);
|
2011-05-23 17:33:19 +02:00
|
|
|
#else
|
2011-04-28 16:35:58 +02:00
|
|
|
int ret = pthread_mutex_init(&mutex, NULL);
|
|
|
|
pthread_cond_init(&condition, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
Synchronize::~Synchronize()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
CloseHandle(evnt);
|
2011-05-23 17:33:19 +02:00
|
|
|
#else
|
2011-04-28 16:35:58 +02:00
|
|
|
int ret = pthread_mutex_destroy(&mutex);
|
|
|
|
ret = pthread_cond_destroy(&condition);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Synchronize::sleep()
|
|
|
|
{
|
|
|
|
sleeping = true;
|
2011-05-23 17:33:19 +02:00
|
|
|
|
2011-04-28 16:35:58 +02:00
|
|
|
#ifdef _WIN32
|
2011-05-23 17:33:19 +02:00
|
|
|
|
2011-04-28 16:35:58 +02:00
|
|
|
#ifdef _DEBUG
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
const int n = WaitForSingleObject(evnt, 10000);
|
|
|
|
if (n != WAIT_TIMEOUT)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
sleep (INFINITE);
|
|
|
|
#endif
|
|
|
|
|
2011-05-23 17:33:19 +02:00
|
|
|
#else
|
2011-04-28 16:35:58 +02:00
|
|
|
int ret = pthread_mutex_lock(&mutex);
|
2011-05-23 17:33:19 +02:00
|
|
|
if (ret)
|
|
|
|
system_call_failed::raise("pthread_mutex_lock", ret);
|
2011-04-28 16:35:58 +02:00
|
|
|
|
|
|
|
while (!wakeup)
|
|
|
|
pthread_cond_wait(&condition, &mutex);
|
|
|
|
|
|
|
|
wakeup = false;
|
|
|
|
ret = pthread_mutex_unlock(&mutex);
|
2011-05-23 17:33:19 +02:00
|
|
|
if (ret)
|
|
|
|
system_call_failed::raise("pthread_mutex_unlock", ret);
|
2011-04-28 16:35:58 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
sleeping = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Synchronize::sleep(int milliseconds)
|
|
|
|
{
|
|
|
|
sleeping = true;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
const int n = WaitForSingleObject(evnt, milliseconds);
|
|
|
|
sleeping = false;
|
|
|
|
|
|
|
|
return n != WAIT_TIMEOUT;
|
2011-05-23 17:33:19 +02:00
|
|
|
#else
|
2011-04-28 16:35:58 +02:00
|
|
|
struct timeval microTime;
|
|
|
|
int ret = gettimeofday(µTime, NULL);
|
|
|
|
SINT64 nanos = (SINT64) microTime.tv_sec * NANO + microTime.tv_usec * 1000 +
|
|
|
|
(SINT64) milliseconds * 1000000;
|
|
|
|
struct timespec nanoTime;
|
|
|
|
nanoTime.tv_sec = nanos / NANO;
|
|
|
|
nanoTime.tv_nsec = nanos % NANO;
|
2011-05-23 17:33:19 +02:00
|
|
|
|
2011-04-28 16:35:58 +02:00
|
|
|
ret = pthread_mutex_lock (&mutex);
|
2011-05-23 17:33:19 +02:00
|
|
|
if (ret)
|
|
|
|
system_call_failed::raise("pthread_mutex_lock", ret);
|
|
|
|
|
2011-04-28 16:35:58 +02:00
|
|
|
int seconds = nanoTime.tv_sec - microTime.tv_sec;
|
|
|
|
|
|
|
|
while (!wakeup)
|
|
|
|
{
|
|
|
|
#ifdef MVS
|
|
|
|
ret = pthread_cond_timedwait(&condition, &mutex, &nanoTime);
|
|
|
|
if (ret == -1 && errno == EAGAIN)
|
|
|
|
ret = ETIMEDOUT;
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
ret = pthread_cond_timedwait(&condition, &mutex, &nanoTime);
|
|
|
|
if (ret == ETIMEDOUT)
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
/***
|
|
|
|
if (!wakeup)
|
2011-04-30 04:28:31 +02:00
|
|
|
Log::debug("Synchronize::sleep(milliseconds): unexpected wakeup, ret %d\n", ret);
|
2011-04-28 16:35:58 +02:00
|
|
|
***/
|
|
|
|
}
|
|
|
|
|
|
|
|
sleeping = false;
|
|
|
|
wakeup = false;
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
return ret != ETIMEDOUT;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Synchronize::wake()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2011-04-30 04:28:31 +02:00
|
|
|
SetEvent(evnt);
|
2011-05-23 17:33:19 +02:00
|
|
|
#else
|
2011-04-28 16:35:58 +02:00
|
|
|
int ret = pthread_mutex_lock(&mutex);
|
2011-05-23 17:33:19 +02:00
|
|
|
if (ret)
|
|
|
|
system_call_failed::raise("pthread_mutex_lock", ret);
|
|
|
|
|
2011-04-28 16:35:58 +02:00
|
|
|
wakeup = true;
|
|
|
|
pthread_cond_broadcast(&condition);
|
|
|
|
|
2011-05-23 17:33:19 +02:00
|
|
|
ret = pthread_mutex_unlock(&mutex);
|
|
|
|
if (ret)
|
|
|
|
system_call_failed::raise("pthread_mutex_unlock", ret);
|
2011-04-28 16:35:58 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Synchronize::shutdown()
|
|
|
|
{
|
|
|
|
shutdownInProgress = true;
|
|
|
|
wake();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ThreadSync
|
|
|
|
|
2011-04-30 04:28:31 +02:00
|
|
|
TLS_DECLARE(ThreadSync*, threadIndex);
|
2011-04-28 16:35:58 +02:00
|
|
|
|
2011-04-30 04:28:31 +02:00
|
|
|
ThreadSync::ThreadSync(const char* desc)
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
|
|
|
init(desc);
|
|
|
|
setThread(this);
|
|
|
|
}
|
|
|
|
|
2011-04-30 04:28:31 +02:00
|
|
|
void ThreadSync::init(const char* desc)
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
|
|
|
description = desc;
|
|
|
|
threadId = getCurrentThreadId();
|
|
|
|
prevWaiting = nextWaiting = NULL;
|
2011-04-30 13:38:00 +02:00
|
|
|
lockType = SYNC_NONE;
|
2011-04-28 16:35:58 +02:00
|
|
|
lockGranted = false;
|
|
|
|
lockPending = NULL;
|
|
|
|
locks = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadSync::~ThreadSync()
|
|
|
|
{
|
2011-04-30 04:28:31 +02:00
|
|
|
setThread(NULL);
|
2011-04-28 16:35:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ThreadSync* ThreadSync::findThread()
|
|
|
|
{
|
|
|
|
return TLS_GET(threadIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-30 04:28:31 +02:00
|
|
|
ThreadSync* ThreadSync::getThread(const char* desc)
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
2011-04-30 04:28:31 +02:00
|
|
|
ThreadSync* thread = findThread();
|
2011-04-28 16:35:58 +02:00
|
|
|
|
|
|
|
if (!thread)
|
|
|
|
{
|
2011-04-30 04:28:31 +02:00
|
|
|
thread = new ThreadSync(desc);
|
2011-04-28 16:35:58 +02:00
|
|
|
setThread(thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
|
2011-04-30 04:28:31 +02:00
|
|
|
void ThreadSync::setThread(ThreadSync* thread)
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
|
|
|
TLS_SET(threadIndex, thread);
|
|
|
|
}
|
|
|
|
|
2012-03-01 09:55:43 +01:00
|
|
|
ThreadId ThreadSync::getCurrentThreadId()
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
|
|
|
return getThreadId();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-24 08:34:16 +02:00
|
|
|
const char* ThreadSync::getWhere() const
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
|
|
|
if (lockPending && lockPending->where)
|
|
|
|
return lockPending->where;
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ThreadSync::validateLocks()
|
|
|
|
{
|
2011-04-30 04:28:31 +02:00
|
|
|
ThreadSync* thread = getThread("ThreadSync::validateLocks");
|
2011-04-28 16:35:58 +02:00
|
|
|
|
2011-04-30 13:38:00 +02:00
|
|
|
// hvlad: not worked, probably we should implement it at some day
|
2011-04-28 16:35:58 +02:00
|
|
|
if (thread->locks)
|
|
|
|
{
|
2011-04-30 04:28:31 +02:00
|
|
|
SYNC_LOG_DEBUG("thread %d has active locks:\n", thread->threadId);
|
|
|
|
for (Sync* sync = thread->locks; sync; sync = sync->prior)
|
|
|
|
SYNC_LOG_DEBUG(" %s\n", sync->where);
|
2011-04-28 16:35:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-30 04:28:31 +02:00
|
|
|
void ThreadSync::grantLock(SyncObject* lock)
|
2011-04-28 16:35:58 +02:00
|
|
|
{
|
2011-04-28 18:59:29 +02:00
|
|
|
fb_assert(!lockGranted);
|
|
|
|
fb_assert(!lockPending || lockPending->syncObject == lock);
|
2011-04-28 16:35:58 +02:00
|
|
|
|
|
|
|
lockGranted = true;
|
|
|
|
lockPending = NULL;
|
|
|
|
|
|
|
|
wake();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Firebird
|