mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 22:03:03 +01:00
Added timer-related interfaces. Added helper method to wait for plugin to be released on shutdown. Misc stability changes in PluginManager.
This commit is contained in:
parent
7998963202
commit
f6914b8db0
66
src/auth/SecurityDatabase/LegacyHash.h
Normal file
66
src/auth/SecurityDatabase/LegacyHash.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* PROGRAM: JRD Access Method
|
||||
* MODULE: LegacyHash.h
|
||||
* DESCRIPTION: Firebird 2.X style hash
|
||||
*
|
||||
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.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 language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Inprise Corporation
|
||||
* and its predecessors. Portions created by Inprise Corporation are
|
||||
* Copyright (C) Inprise Corporation.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
||||
* 2003.02.02 Dmitry Yemanov: Implemented cached security database connection
|
||||
*/
|
||||
|
||||
#ifndef AUTH_LEGACY_HASH_H
|
||||
#define AUTH_LEGACY_HASH_H
|
||||
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../common/sha.h"
|
||||
|
||||
namespace Auth {
|
||||
|
||||
const size_t MAX_PASSWORD_LENGTH = 64; // used to store passwords internally
|
||||
static const char* const PASSWORD_SALT = "9z"; // for old ENC_crypt()
|
||||
const size_t SALT_LENGTH = 12; // measured after base64 coding
|
||||
|
||||
class LegacyHash
|
||||
{
|
||||
public:
|
||||
static void hash(Firebird::string& h, const Firebird::string& userName, const TEXT* passwd)
|
||||
{
|
||||
Firebird::string salt;
|
||||
Jrd::CryptSupport::random(salt, SALT_LENGTH);
|
||||
hash(h, userName, passwd, salt);
|
||||
}
|
||||
|
||||
static void hash(Firebird::string& h,
|
||||
const Firebird::string& userName,
|
||||
const Firebird::string& passwd,
|
||||
const Firebird::string& oldHash)
|
||||
{
|
||||
Firebird::string salt(oldHash);
|
||||
salt.resize(SALT_LENGTH, '=');
|
||||
Firebird::string allData(salt);
|
||||
allData += userName;
|
||||
allData += passwd;
|
||||
Jrd::CryptSupport::hash(h, allData);
|
||||
h = salt + h;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Auth
|
||||
|
||||
#endif // AUTH_LEGACY_SERVER_H
|
@ -29,7 +29,7 @@
|
||||
#include <ctype.h>
|
||||
#include "../common/common.h"
|
||||
#include "../jrd/ibase.h"
|
||||
#include "../auth/SecurityDatabase/LegacyServer.h"
|
||||
#include "../auth/SecurityDatabase/LegacyHash.h"
|
||||
#include "../common/enc_proto.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
#include "../common/isc_proto.h"
|
||||
@ -39,6 +39,7 @@
|
||||
#include "../common/classes/UserBlob.h"
|
||||
#include "../auth/SecurityDatabase/LegacyManagement.h"
|
||||
#include "../common/classes/ImplementHelper.h"
|
||||
#include "../common/classes/ClumpletWriter.h"
|
||||
#include "FirebirdPluginApi.h"
|
||||
|
||||
// Here we use version-independent symbolic link (or copy) of actual database
|
||||
@ -377,7 +378,7 @@ int FB_CARG SecurityDatabaseManagement::execute(Firebird::Status* st, User* user
|
||||
if (user->password()->entered())
|
||||
{
|
||||
ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), PASSWORD_SALT);
|
||||
SecurityDatabase::hash(encrypted2, user->userName()->get(), &encrypted1[2]);
|
||||
LegacyHash::hash(encrypted2, user->userName()->get(), &encrypted1[2]);
|
||||
STR_STORE(U.PLG$PASSWD, encrypted2.c_str());
|
||||
U.PLG$PASSWD.NULL = ISC_FALSE;
|
||||
}
|
||||
@ -452,7 +453,7 @@ int FB_CARG SecurityDatabaseManagement::execute(Firebird::Status* st, User* user
|
||||
if (user->password()->entered())
|
||||
{
|
||||
ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), PASSWORD_SALT);
|
||||
SecurityDatabase::hash(encrypted2, user->userName()->get(), &encrypted1[2]);
|
||||
LegacyHash::hash(encrypted2, user->userName()->get(), &encrypted1[2]);
|
||||
STR_STORE(U.PLG$PASSWD, encrypted2.c_str());
|
||||
U.PLG$PASSWD.NULL = ISC_FALSE;
|
||||
}
|
||||
@ -667,6 +668,7 @@ int FB_CARG SecurityDatabaseManagement::execute(Firebird::Status* st, User* user
|
||||
|
||||
// register plugin
|
||||
static Firebird::SimpleFactory<Auth::SecurityDatabaseManagement> factory;
|
||||
static Firebird::UnloadDetector unloadDetector;
|
||||
|
||||
extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master)
|
||||
{
|
||||
@ -674,6 +676,7 @@ extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master)
|
||||
|
||||
factory->addRef();
|
||||
iPlugin->registerPlugin(Firebird::PluginType::AuthUserManagement, "Legacy_Auth", &factory);
|
||||
iPlugin->setModuleCleanup(&unloadDetector);
|
||||
|
||||
iPlugin->release();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* PROGRAM: JRD Access Method
|
||||
* MODULE: pwd.cpp
|
||||
* MODULE: LegacyServer.cpp
|
||||
* DESCRIPTION: User information database access
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
@ -31,6 +31,7 @@
|
||||
#include "../jrd/ibase.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../auth/SecurityDatabase/LegacyServer.h"
|
||||
#include "../auth/SecurityDatabase/LegacyHash.h"
|
||||
#include "../common/enc_proto.h"
|
||||
#include "../jrd/err_proto.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
@ -42,89 +43,12 @@
|
||||
#include "../common/classes/objects_array.h"
|
||||
#include "../common/classes/init.h"
|
||||
#include "../common/classes/ImplementHelper.h"
|
||||
#include "Timer.h"
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
namespace {
|
||||
|
||||
// temporal implementation of timer
|
||||
|
||||
GlobalPtr<Mutex> timerMutex;
|
||||
FPTR_VOID_PTR toRun = 0;
|
||||
unsigned int cnt = 0;
|
||||
|
||||
int active = 0;
|
||||
|
||||
int stopTimer(const int, const int mask, void*)
|
||||
{
|
||||
switch(mask)
|
||||
{
|
||||
case fb_shut_preproviders:
|
||||
active = 2;
|
||||
break;
|
||||
case fb_shut_finish:
|
||||
while (active == 2)
|
||||
{
|
||||
THREAD_SLEEP(10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
THREAD_ENTRY_DECLARE threadTimer(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
while (active == 1)
|
||||
{
|
||||
{ // scope
|
||||
MutexLockGuard g(timerMutex);
|
||||
if (cnt == 0)
|
||||
{
|
||||
if (toRun)
|
||||
{
|
||||
toRun(0);
|
||||
toRun = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--cnt;
|
||||
}
|
||||
}
|
||||
|
||||
THREAD_SLEEP(100);
|
||||
}
|
||||
|
||||
active = 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fb_alloc_timer()
|
||||
{
|
||||
if (! active)
|
||||
{
|
||||
active = 1;
|
||||
Thread::start(threadTimer, 0, 0);
|
||||
fb_shutdown_callback(0, stopTimer, fb_shut_preproviders | fb_shut_finish, 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void fb_thread_timer(int, int delay, FPTR_VOID_PTR function, void*)
|
||||
{
|
||||
MutexLockGuard g(timerMutex);
|
||||
|
||||
cnt = delay / 100;
|
||||
if (! cnt)
|
||||
{
|
||||
cnt = 1;
|
||||
}
|
||||
|
||||
toRun = function;
|
||||
}
|
||||
|
||||
// BLR to search database for user name record
|
||||
|
||||
const UCHAR PWD_REQUEST[] =
|
||||
@ -194,12 +118,52 @@ const UCHAR TPB[4] =
|
||||
isc_tpb_wait
|
||||
};
|
||||
|
||||
int timer = 0;
|
||||
|
||||
} // anonymous
|
||||
} // anonymous namespace
|
||||
|
||||
namespace Auth {
|
||||
|
||||
class SecurityDatabase : public Firebird::StdIface<Firebird::ITimer, FB_I_TIMER_VERSION>
|
||||
{
|
||||
public:
|
||||
Result verify(WriterInterface* authBlock,
|
||||
Firebird::ClumpletReader& originalDpb);
|
||||
|
||||
static int shutdown(const int, const int, void*);
|
||||
|
||||
char secureDbName[MAXPATHLEN];
|
||||
|
||||
SecurityDatabase()
|
||||
: lookup_db(0), lookup_req(0)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void FB_CARG handler();
|
||||
|
||||
int FB_CARG release()
|
||||
{
|
||||
if (--refCounter == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Firebird::Mutex mutex;
|
||||
|
||||
ISC_STATUS_ARRAY status;
|
||||
|
||||
isc_db_handle lookup_db;
|
||||
isc_req_handle lookup_req;
|
||||
|
||||
void fini();
|
||||
bool lookup_user(const char*, char*);
|
||||
void prepare();
|
||||
void checkStatus(const char* callName, ISC_STATUS userError = isc_psw_db_error);
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Private interface
|
||||
@ -229,14 +193,6 @@ void SecurityDatabase::fini()
|
||||
}
|
||||
}
|
||||
|
||||
void SecurityDatabase::init()
|
||||
{
|
||||
if (! timer)
|
||||
{
|
||||
timer = fb_alloc_timer();
|
||||
}
|
||||
}
|
||||
|
||||
bool SecurityDatabase::lookup_user(const char* user_name, char* pwd)
|
||||
{
|
||||
bool found = false; // user found flag
|
||||
@ -297,7 +253,7 @@ void SecurityDatabase::prepare()
|
||||
return;
|
||||
}
|
||||
|
||||
init();
|
||||
fb_shutdown_callback(status, shutdown, fb_shut_preproviders, 0);
|
||||
|
||||
lookup_db = lookup_req = 0;
|
||||
|
||||
@ -394,7 +350,7 @@ Result SecurityDatabase::verify(WriterInterface* authBlock,
|
||||
}
|
||||
|
||||
string newHash;
|
||||
hash(newHash, login, passwordEnc, storedHash);
|
||||
LegacyHash::hash(newHash, login, passwordEnc, storedHash);
|
||||
if (newHash != storedHash)
|
||||
{
|
||||
bool legacyHash = Config::getLegacyHash();
|
||||
@ -440,14 +396,40 @@ void SecurityDatabase::checkStatus(const char* callName, ISC_STATUS userError)
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO - avoid races between timer thread and auth thread
|
||||
// TODO - account for too old instances and cleanup them
|
||||
// WHEN - when timer interface is ready
|
||||
typedef HalfStaticArray<SecurityDatabase*, 4> InstancesArray;
|
||||
GlobalPtr<InstancesArray> instances;
|
||||
GlobalPtr<Mutex> instancesMutex;
|
||||
|
||||
void SecurityDatabase::shutdown(void*)
|
||||
void FB_CARG SecurityDatabase::handler()
|
||||
{
|
||||
try
|
||||
{
|
||||
MutexLockGuard g(instancesMutex);
|
||||
|
||||
fini();
|
||||
InstancesArray& curInstances(instances);
|
||||
for (unsigned int i = 0; i < curInstances.getCount(); ++i)
|
||||
{
|
||||
if (curInstances[i] == this)
|
||||
{
|
||||
curInstances.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
release();
|
||||
}
|
||||
catch (Exception &ex)
|
||||
{
|
||||
ISC_STATUS_ARRAY status;
|
||||
ex.stuff_exception(status);
|
||||
if (status[0] == 1 && status[1] != isc_att_shutdown)
|
||||
{
|
||||
iscLogStatus("Legacy security database shutdown", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SecurityDatabase::shutdown(const int, const int, void*)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -458,7 +440,7 @@ void SecurityDatabase::shutdown(void*)
|
||||
if (curInstances[i])
|
||||
{
|
||||
curInstances[i]->fini();
|
||||
delete curInstances[i];
|
||||
curInstances[i]->release();
|
||||
curInstances[i] = NULL;
|
||||
}
|
||||
}
|
||||
@ -472,7 +454,11 @@ void SecurityDatabase::shutdown(void*)
|
||||
{
|
||||
iscLogStatus("Legacy security database shutdown", status);
|
||||
}
|
||||
|
||||
return FB_FAILURE;
|
||||
}
|
||||
|
||||
return FB_SUCCESS;
|
||||
}
|
||||
|
||||
const static unsigned int INIT_KEY = ((~0) - 1);
|
||||
@ -507,7 +493,6 @@ Result SecurityDatabaseServer::startAuthentication(Firebird::Status* status,
|
||||
|
||||
SecurityDatabase* instance = 0;
|
||||
|
||||
fb_thread_timer(timer, 10000, SecurityDatabase::shutdown, 0);
|
||||
{ // guard scope
|
||||
MutexLockGuard g(instancesMutex);
|
||||
InstancesArray& curInstances(instances);
|
||||
@ -531,7 +516,8 @@ Result SecurityDatabaseServer::startAuthentication(Firebird::Status* status,
|
||||
fb_assert(instance);
|
||||
|
||||
ClumpletReader rdr(isService ? ClumpletReader::spbList : ClumpletReader::dpbList, dpb, dpbSize);
|
||||
return instance->verify(writerInterface, rdr);
|
||||
Result rc = instance->verify(writerInterface, rdr);
|
||||
Firebird::TimerInterface()->start(instance, 10 * 1000 * 1000);
|
||||
}
|
||||
catch (const Firebird::Exception& ex)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* PROGRAM: JRD Access Method
|
||||
* MODULE: jrd_pwd.h
|
||||
* MODULE: LegacyServer.h
|
||||
* DESCRIPTION: User information database name
|
||||
*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
@ -43,61 +43,6 @@
|
||||
|
||||
namespace Auth {
|
||||
|
||||
const size_t MAX_PASSWORD_LENGTH = 64; // used to store passwords internally
|
||||
static const char* const PASSWORD_SALT = "9z"; // for old ENC_crypt()
|
||||
const size_t SALT_LENGTH = 12; // measured after base64 coding
|
||||
|
||||
class SecurityDatabase : public Firebird::GlobalStorage
|
||||
{
|
||||
public:
|
||||
Result verify(WriterInterface* authBlock,
|
||||
Firebird::ClumpletReader& originalDpb);
|
||||
|
||||
static void shutdown(void*);
|
||||
|
||||
static void hash(Firebird::string& h, const Firebird::string& userName, const TEXT* passwd)
|
||||
{
|
||||
Firebird::string salt;
|
||||
Jrd::CryptSupport::random(salt, SALT_LENGTH);
|
||||
hash(h, userName, passwd, salt);
|
||||
}
|
||||
|
||||
static void hash(Firebird::string& h,
|
||||
const Firebird::string& userName,
|
||||
const Firebird::string& passwd,
|
||||
const Firebird::string& oldHash)
|
||||
{
|
||||
Firebird::string salt(oldHash);
|
||||
salt.resize(SALT_LENGTH, '=');
|
||||
Firebird::string allData(salt);
|
||||
allData += userName;
|
||||
allData += passwd;
|
||||
Jrd::CryptSupport::hash(h, allData);
|
||||
h = salt + h;
|
||||
}
|
||||
|
||||
char secureDbName[MAXPATHLEN];
|
||||
|
||||
SecurityDatabase()
|
||||
: lookup_db(0), lookup_req(0)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Firebird::Mutex mutex;
|
||||
|
||||
ISC_STATUS_ARRAY status;
|
||||
|
||||
isc_db_handle lookup_db;
|
||||
isc_req_handle lookup_req;
|
||||
|
||||
void init();
|
||||
void fini();
|
||||
bool lookup_user(const char*, char*);
|
||||
void prepare();
|
||||
void checkStatus(const char* callName, ISC_STATUS userError = isc_psw_db_error);
|
||||
};
|
||||
|
||||
class SecurityDatabaseServerFactory : public Firebird::StdIface<Firebird::PluginsFactory, FB_PLUGINS_FACTORY_VERSION>
|
||||
{
|
||||
public:
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define FB_COMMON_CLASSES_IMPLEMENT_HELPER
|
||||
|
||||
#include "FirebirdPluginApi.h"
|
||||
#include "Timer.h"
|
||||
#include "../common/classes/alloc.h"
|
||||
#include "gen/iberror.h"
|
||||
#include "../yvalve/gds_proto.h"
|
||||
@ -170,6 +171,15 @@ class SimpleFactory : public Static<SimpleFactoryBase<P> >
|
||||
};
|
||||
|
||||
|
||||
// Master interface
|
||||
class MasterInterface : public AutoPtr<IMaster, AutoInterface>
|
||||
{
|
||||
public:
|
||||
MasterInterface() : AutoPtr<IMaster, AutoInterface>(fb_get_master_interface())
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
// Generic plugins interface
|
||||
class PluginInterface : public AutoPtr<IPlugin, AutoInterface>
|
||||
{
|
||||
@ -183,6 +193,19 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// Control timer interface
|
||||
class TimerInterface : public AutoPtr<ITimerControl, AutoInterface>
|
||||
{
|
||||
public:
|
||||
TimerInterface() : AutoPtr<ITimerControl, AutoInterface>(NULL)
|
||||
{
|
||||
IMaster* mi = fb_get_master_interface();
|
||||
reset(mi->getTimerControl());
|
||||
mi->release();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// When process exits, dynamically loaded modules (for us plugin modules)
|
||||
// are unloaded first. As the result all global variables in plugin are already destroyed
|
||||
// when yvalve is starting fb_shutdown(). This causes almost unavoidable segfault.
|
||||
@ -197,21 +220,18 @@ class UnloadDetectorHelper : public StdIface<IModuleCleanup, FB_MODULE_CLEANUP_V
|
||||
{
|
||||
public:
|
||||
UnloadDetectorHelper(MemoryPool&)
|
||||
: flagOsUnload(true)
|
||||
: flagOsUnload(true), cleanup(NULL)
|
||||
{ }
|
||||
|
||||
~UnloadDetectorHelper()
|
||||
{
|
||||
if (flagOsUnload)
|
||||
{
|
||||
fb_shutdown(5000, fb_shutrsn_exit_called);
|
||||
}
|
||||
flagOsUnload = false;
|
||||
}
|
||||
PluginInterface()->resetModuleCleanup(this);
|
||||
|
||||
void FB_CARG doClean()
|
||||
{
|
||||
flagOsUnload = false;
|
||||
fb_shutdown(5000, fb_shutrsn_exit_called);
|
||||
doClean();
|
||||
}
|
||||
}
|
||||
|
||||
int FB_CARG release()
|
||||
@ -230,8 +250,24 @@ public:
|
||||
return !flagOsUnload;
|
||||
}
|
||||
|
||||
protected:
|
||||
void setCleanup(FPTR_VOID c)
|
||||
{
|
||||
cleanup = c;
|
||||
}
|
||||
|
||||
private:
|
||||
bool flagOsUnload;
|
||||
FPTR_VOID cleanup;
|
||||
|
||||
void FB_CARG doClean()
|
||||
{
|
||||
flagOsUnload = false;
|
||||
if (cleanup)
|
||||
{
|
||||
cleanup();
|
||||
cleanup = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef GlobalPtr<UnloadDetectorHelper, InstanceControl::PRIORITY_DETECT_UNLOAD> UnloadDetector;
|
||||
|
@ -167,6 +167,7 @@ private:
|
||||
static pthread_mutexattr_t attr;
|
||||
#ifdef DEV_BUILD
|
||||
const char* reason;
|
||||
int lockCount;
|
||||
#endif
|
||||
|
||||
private:
|
||||
@ -174,6 +175,7 @@ private:
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
reason = NULL;
|
||||
lockCount = 0;
|
||||
#endif
|
||||
int rc = pthread_mutex_init(&mlock, &attr);
|
||||
if (rc)
|
||||
@ -186,6 +188,7 @@ public:
|
||||
|
||||
~Mutex()
|
||||
{
|
||||
fb_assert(lockCount == 0);
|
||||
int rc = pthread_mutex_destroy(&mlock);
|
||||
if (rc)
|
||||
system_call_failed::raise("pthread_mutex_destroy", rc);
|
||||
@ -198,6 +201,7 @@ public:
|
||||
if (rc)
|
||||
system_call_failed::raise("pthread_mutex_lock", rc);
|
||||
reason = aReason;
|
||||
++lockCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -208,6 +212,7 @@ public:
|
||||
system_call_failed::raise("pthread_mutex_lock", rc);
|
||||
#ifdef DEV_BUILD
|
||||
reason = "<..unspecified..>";
|
||||
++lockCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -218,14 +223,43 @@ public:
|
||||
return false;
|
||||
if (rc)
|
||||
system_call_failed::raise("pthread_mutex_trylock", rc);
|
||||
#ifdef DEV_BUILD
|
||||
reason = "<..unspecified..>";
|
||||
++lockCount;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void leave()
|
||||
{
|
||||
fb_assert(lockCount > 0);
|
||||
#ifdef DEV_BUILD
|
||||
--lockCount;
|
||||
#endif
|
||||
int rc = pthread_mutex_unlock(&mlock);
|
||||
if (rc)
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
++lockCount;
|
||||
#endif
|
||||
system_call_failed::raise("pthread_mutex_unlock", rc);
|
||||
}
|
||||
}
|
||||
|
||||
void assertLocked()
|
||||
{
|
||||
#ifdef DEV_BUILD
|
||||
// first of all try to enter the mutex
|
||||
// this will help to make sure it's not locked by other thread
|
||||
if (!tryEnter())
|
||||
{
|
||||
fb_assert(false);
|
||||
}
|
||||
// make sure mutex was already locked prior assertLocked
|
||||
fb_assert(lockCount > 1);
|
||||
// leave to release lock, done by us in tryEnter
|
||||
leave();
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -43,6 +43,7 @@ namespace os_utils
|
||||
|
||||
void createLockDirectory(const char* pathname);
|
||||
int openCreateSharedFile(const char* pathname, int flags);
|
||||
bool touchFile(const char* pathname);
|
||||
|
||||
} // namespace os_utils
|
||||
|
||||
|
@ -198,4 +198,23 @@ int openCreateSharedFile(const char* pathname, int flags)
|
||||
return fd;
|
||||
}
|
||||
|
||||
// set file's last access and modification time to current time
|
||||
bool touchFile(const char* pathname)
|
||||
{
|
||||
#ifdef HAVE_UTIME_H
|
||||
while (utime(pathname, NULL) < 0)
|
||||
{
|
||||
if (SYSCALL_INTERRUPTED(errno))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace os_utils
|
||||
|
@ -241,4 +241,27 @@ int openCreateSharedFile(const char* pathname, int flags)
|
||||
return ::open(pathname, flags | O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
|
||||
}
|
||||
|
||||
// set file's last access and modification time to current time
|
||||
bool touchFile(const char* pathname)
|
||||
{
|
||||
FILETIME ft;
|
||||
SYSTEMTIME st;
|
||||
|
||||
HANDLE hFile = CreateFile(pathname,
|
||||
GENERIC_READ | FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
ISC_get_security_desc(),
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
GetSystemTime(&st);
|
||||
const bool ret = SystemTimeToFileTime(&st, &ft) && SetFileTime(hFile, NULL, &ft, &ft);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace os_utils
|
||||
|
@ -704,7 +704,7 @@ public:
|
||||
}
|
||||
|
||||
virtual int FB_CARG upgradeInterface(Interface* toUpgrade, int desiredVersion,
|
||||
void* missingFunctionClass)
|
||||
void* missingFunctionClass)
|
||||
{
|
||||
fb_assert(false);
|
||||
return 0;
|
||||
@ -717,6 +717,12 @@ public:
|
||||
buf[len] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
virtual ITimerControl* getTimerControl()
|
||||
{
|
||||
fb_assert(false);
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -62,10 +62,6 @@
|
||||
#ifndef FIREBIRD_PLUGIN_API_H
|
||||
#define FIREBIRD_PLUGIN_API_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC system_header // disable warning about non-existent virtual destructor
|
||||
#endif
|
||||
|
||||
#include "Interface.h"
|
||||
|
||||
#define FB_PLUGIN_ENTRY_POINT firebird_plugin
|
||||
@ -116,7 +112,7 @@ class IFirebirdConf : public Interface
|
||||
{
|
||||
public:
|
||||
// Get integer key by it's name
|
||||
// Value <0 means name is invalid
|
||||
// Value ~0 means name is invalid
|
||||
// Keys are stable: one can use once obtained key in other instances of this interface
|
||||
virtual unsigned int FB_CARG getKey(const char* name) = 0;
|
||||
// Use to access integer and boolean values
|
||||
@ -171,7 +167,11 @@ public:
|
||||
virtual void FB_CARG registerPlugin(unsigned int interfaceType, const char* defaultName,
|
||||
PluginsFactory* factory) = 0;
|
||||
// Sets cleanup for plugin module
|
||||
// Pay attention - this should be called at plugin-regsiter time!
|
||||
// Only at this moment manager knows, which module sets his cleanup
|
||||
virtual void FB_CARG setModuleCleanup(IModuleCleanup* cleanup) = 0;
|
||||
// Remove registered before cleanup routine
|
||||
virtual void FB_CARG resetModuleCleanup(IModuleCleanup* cleanup) = 0;
|
||||
// Main function called to access plugins registered in plugins manager
|
||||
// Has front-end in GetPlugins.h - template GetPlugins
|
||||
// In namesList parameter comma or space separated list of names of configured plugins is passed
|
||||
@ -202,6 +202,8 @@ namespace PluginType {
|
||||
static const unsigned int AuthUserManagement = 13;
|
||||
static const unsigned int ExternalEngine = 14;
|
||||
static const unsigned int Trace = 15;
|
||||
|
||||
static const unsigned int MaxType = 16; // keep in sync please
|
||||
};
|
||||
|
||||
} // namespace Firebird
|
||||
|
@ -29,6 +29,8 @@
|
||||
#ifndef FB_INCLUDE_INTERFACE
|
||||
#define FB_INCLUDE_INTERFACE
|
||||
|
||||
#include "types_pub.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC system_header // disable warning about non-existent virtual destructor
|
||||
#endif
|
||||
@ -65,6 +67,7 @@ public:
|
||||
#define FB_STATUS_VERSION (FB_INTERFACE_VERSION + 5)
|
||||
|
||||
class IPlugin;
|
||||
class ITimerControl;
|
||||
|
||||
class IMaster : public Interface
|
||||
{
|
||||
@ -76,6 +79,7 @@ public:
|
||||
virtual IPlugin* FB_CARG getPluginInterface() = 0;
|
||||
virtual int FB_CARG upgradeInterface(Interface* toUpgrade, int desiredVersion, void* missingFunctionClass) = 0;
|
||||
virtual const char* FB_CARG circularAlloc(const char* s, size_t len, intptr_t thr) = 0;
|
||||
virtual ITimerControl* FB_CARG getTimerControl() = 0;
|
||||
};
|
||||
|
||||
} // namespace Firebird
|
||||
|
61
src/include/Timer.h
Normal file
61
src/include/Timer.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* PROGRAM: Firebird interface.
|
||||
* MODULE: Timer.h
|
||||
* DESCRIPTION: Timer interface defnition.
|
||||
*
|
||||
* 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/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alex Peshkov
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2011 Alex Peshkov <peshkoff at mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FIREBIRD_TIMER_H
|
||||
#define FIREBIRD_TIMER_H
|
||||
|
||||
#include "Interface.h"
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
// Identifies particular timer.
|
||||
// Callback function is invoked when timer fires.
|
||||
class ITimer : public Interface
|
||||
{
|
||||
public:
|
||||
virtual void FB_CARG handler() = 0;
|
||||
};
|
||||
#define FB_I_TIMER_VERSION (FB_INTERFACE_VERSION + 1)
|
||||
|
||||
typedef ISC_INT64 TimerDelay;
|
||||
|
||||
// Interface to set timer for particular time
|
||||
class ITimerControl : public Interface
|
||||
{
|
||||
public:
|
||||
// Set timer
|
||||
virtual void FB_CARG start(ITimer* timer, TimerDelay microSeconds) = 0;
|
||||
// Stop timer
|
||||
virtual void FB_CARG stop(ITimer* timer) = 0;
|
||||
};
|
||||
#define FB_I_TIMER_CONTROL_VERSION (FB_INTERFACE_VERSION + 2)
|
||||
|
||||
} // namespace Firebird
|
||||
|
||||
|
||||
#endif // FIREBIRD_TIMER_H
|
@ -72,11 +72,6 @@ Manager::~Manager()
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::init()
|
||||
{
|
||||
fb_shutdown_callback(0, shutdown, fb_shut_preproviders, 0);
|
||||
}
|
||||
|
||||
void Manager::addProvider(Provider* provider)
|
||||
{
|
||||
for (const Provider* prv = m_providers; prv; prv = prv->m_next)
|
||||
@ -113,7 +108,6 @@ Connection* Manager::getConnection(thread_db* tdbb, const string& dataSource,
|
||||
Database::CheckoutLockGuard guard(tdbb->getDatabase(), m_mutex);
|
||||
if (!m_initialized)
|
||||
{
|
||||
init();
|
||||
m_initialized = true;
|
||||
}
|
||||
}
|
||||
@ -157,7 +151,7 @@ void Manager::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att)
|
||||
}
|
||||
}
|
||||
|
||||
int Manager::shutdown(const int /*reason*/, const int /*mask*/, void* /*arg*/)
|
||||
int Manager::shutdown()
|
||||
{
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
for (Provider* prv = m_providers; prv; prv = prv->m_next) {
|
||||
|
@ -69,11 +69,9 @@ public:
|
||||
|
||||
// Notify providers when some jrd attachment is about to be released
|
||||
static void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att);
|
||||
static int shutdown();
|
||||
|
||||
private:
|
||||
static void init();
|
||||
static int shutdown(const int reason, const int mask, void* arg);
|
||||
|
||||
static Firebird::GlobalPtr<Manager> manager;
|
||||
static Firebird::Mutex m_mutex;
|
||||
static Provider* m_providers;
|
||||
|
@ -6514,6 +6514,9 @@ static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg)
|
||||
{
|
||||
ThreadContextHolder tdbb;
|
||||
|
||||
// Shutdown external datasets manager
|
||||
EDS::Manager::shutdown();
|
||||
|
||||
MutexLockGuard guard(databases_mutex);
|
||||
|
||||
cancel_attachments(tdbb);
|
||||
|
@ -59,6 +59,7 @@ using namespace Firebird;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
static const TimerDelay TOUCH_INTERVAL = 60 * 60; // in seconds, one hour should be enough
|
||||
|
||||
void checkFileError(const char* filename, const char* operation, ISC_STATUS iscError)
|
||||
{
|
||||
@ -120,11 +121,15 @@ ConfigStorage::ConfigStorage()
|
||||
|
||||
StorageGuard guard(this);
|
||||
checkFile();
|
||||
timer.start(sh_mem_header->cfg_file_name);
|
||||
|
||||
++sh_mem_header->cnt_uses;
|
||||
}
|
||||
|
||||
ConfigStorage::~ConfigStorage()
|
||||
{
|
||||
timer.stop();
|
||||
|
||||
::close(m_cfg_file);
|
||||
m_cfg_file = -1;
|
||||
|
||||
@ -545,4 +550,21 @@ bool ConfigStorage::getItemLength(ITEM& tag, ULONG& len)
|
||||
return true;
|
||||
}
|
||||
|
||||
void FB_CARG ConfigStorage::TouchFile::handler()
|
||||
{
|
||||
os_utils::touchFile(fileName);
|
||||
TimerInterface()->start(this, TOUCH_INTERVAL * 1000 * 1000);
|
||||
}
|
||||
|
||||
void ConfigStorage::TouchFile::start(const char* fName)
|
||||
{
|
||||
fileName = fName;
|
||||
TimerInterface()->start(this, TOUCH_INTERVAL * 1000 * 1000);
|
||||
}
|
||||
|
||||
void ConfigStorage::TouchFile::stop()
|
||||
{
|
||||
TimerInterface()->stop(this);
|
||||
}
|
||||
|
||||
} // namespace Jrd
|
||||
|
@ -67,6 +67,18 @@ private:
|
||||
bool initialize(bool);
|
||||
|
||||
void checkFile();
|
||||
void touchFile();
|
||||
|
||||
class TouchFile : public Firebird::StackIface<Firebird::ITimer, FB_I_TIMER_VERSION>
|
||||
{
|
||||
public:
|
||||
void FB_CARG handler();
|
||||
void start(const char* fName);
|
||||
void stop();
|
||||
private:
|
||||
const char* fileName;
|
||||
};
|
||||
TouchFile timer;
|
||||
|
||||
void checkDirty()
|
||||
{
|
||||
|
@ -804,12 +804,13 @@ public:
|
||||
class ExternalEngineFactoryImpl : public SimpleFactory<Engine>
|
||||
{
|
||||
} factory;
|
||||
|
||||
static Firebird::UnloadDetector unloadDetector;
|
||||
|
||||
extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master)
|
||||
{
|
||||
IPlugin* plugin = master->getPluginInterface();
|
||||
plugin->registerPlugin(PluginType::ExternalEngine, "UDR", &factory);
|
||||
plugin->setModuleCleanup(&unloadDetector);
|
||||
plugin->release();
|
||||
|
||||
libraryName->assign("fbclient");
|
||||
|
@ -28,6 +28,11 @@
|
||||
|
||||
#include "firebird.h"
|
||||
#include "Interface.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "../yvalve/MasterImplementation.h"
|
||||
#include "../common/classes/ImplementHelper.h"
|
||||
#include "../common/classes/init.h"
|
||||
#include "../common/StatusHolder.h"
|
||||
@ -35,7 +40,10 @@
|
||||
#include "../common/classes/GenericMap.h"
|
||||
#include "../common/classes/fb_pair.h"
|
||||
#include "../common/classes/rwlock.h"
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
#include "../jrd/ibase.h"
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
@ -46,6 +54,7 @@ public:
|
||||
IPlugin* FB_CARG getPluginInterface();
|
||||
int FB_CARG upgradeInterface(Interface* toUpgrade, int desiredVersion, void* missingFunctionClass);
|
||||
const char* FB_CARG circularAlloc(const char* s, size_t len, intptr_t thr);
|
||||
ITimerControl* FB_CARG getTimerControl();
|
||||
};
|
||||
|
||||
//
|
||||
@ -335,6 +344,191 @@ const char* FB_CARG MasterImplementation::circularAlloc(const char* s, size_t le
|
||||
|
||||
} // namespace Firebird
|
||||
|
||||
|
||||
//
|
||||
// timer
|
||||
//
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
namespace {
|
||||
|
||||
GlobalPtr<Mutex> timerAccess;
|
||||
GlobalPtr<Semaphore> timerWakeup;
|
||||
|
||||
bool stopThread = false;
|
||||
Thread::Handle timerThreadHandle = 0;
|
||||
|
||||
struct TimerEntry
|
||||
{
|
||||
TimerDelay fireTime;
|
||||
ITimer* timer;
|
||||
|
||||
static const TimerDelay generate(const void* /*sender*/, const TimerEntry& item) { return item.fireTime; }
|
||||
static THREAD_ENTRY_DECLARE timeThread(THREAD_ENTRY_PARAM);
|
||||
|
||||
static void init()
|
||||
{
|
||||
Thread::start(timeThread, 0, 0, &timerThreadHandle);
|
||||
}
|
||||
|
||||
static void cleanup(void);
|
||||
};
|
||||
|
||||
typedef SortedArray<TimerEntry, InlineStorage<TimerEntry, 64>, TimerDelay, TimerEntry> TimerQueue;
|
||||
GlobalPtr<TimerQueue> timerQueue;
|
||||
|
||||
InitMutex<TimerEntry> timerHolder;
|
||||
|
||||
void TimerEntry::cleanup(void)
|
||||
{
|
||||
MutexLockGuard guard(timerAccess);
|
||||
|
||||
stopThread = true;
|
||||
timerWakeup->release();
|
||||
Thread::waitForCompletion(timerThreadHandle);
|
||||
|
||||
while (timerQueue->hasData())
|
||||
{
|
||||
TimerEntry& e(timerQueue->operator[](timerQueue->getCount() - 1));
|
||||
e.timer->release();
|
||||
timerQueue->remove(&e);
|
||||
}
|
||||
}
|
||||
|
||||
TimerDelay curTime()
|
||||
{
|
||||
struct timeval cur_time;
|
||||
struct timezone tzUnused;
|
||||
|
||||
if (gettimeofday(&cur_time, &tzUnused) != 0)
|
||||
{
|
||||
system_call_failed::raise("gettimeofday");
|
||||
}
|
||||
|
||||
TimerDelay microSeconds = ((TimerDelay) cur_time.tv_sec) * 1000000 + cur_time.tv_usec;
|
||||
return microSeconds;
|
||||
}
|
||||
|
||||
TimerEntry* getTimer(ITimer* timer)
|
||||
{
|
||||
timerAccess->assertLocked();
|
||||
|
||||
for (unsigned int i = 0; i < timerQueue->getCount(); ++i)
|
||||
{
|
||||
TimerEntry& e(timerQueue->operator[](i));
|
||||
if (e.timer == timer)
|
||||
{
|
||||
return &e;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
THREAD_ENTRY_DECLARE TimerEntry::timeThread(THREAD_ENTRY_PARAM)
|
||||
{
|
||||
while (!stopThread)
|
||||
{
|
||||
TimerDelay microSeconds = 0;
|
||||
{
|
||||
MutexLockGuard guard(timerAccess);
|
||||
|
||||
const TimerDelay cur = curTime();
|
||||
while (timerQueue->getCount() > 0)
|
||||
{
|
||||
TimerEntry e(timerQueue->operator[](0));
|
||||
if (e.fireTime <= cur)
|
||||
{
|
||||
timerQueue->remove((size_t)0);
|
||||
e.timer->handler();
|
||||
e.timer->release();
|
||||
}
|
||||
else
|
||||
{
|
||||
microSeconds = e.fireTime - cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (microSeconds)
|
||||
{
|
||||
timerWakeup->tryEnter(0, microSeconds / 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
timerWakeup->enter();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class TimerImplementation : public StackIface<ITimerControl, FB_I_TIMER_CONTROL_VERSION>
|
||||
{
|
||||
public:
|
||||
void FB_CARG start(ITimer* timer, TimerDelay microSeconds)
|
||||
{
|
||||
MutexLockGuard guard(timerAccess);
|
||||
|
||||
timerHolder.init();
|
||||
|
||||
if (stopThread)
|
||||
{
|
||||
// ignore an attempt to start timer - anyway thread to make it fire is down
|
||||
return;
|
||||
}
|
||||
|
||||
TimerEntry* curTimer = getTimer(timer);
|
||||
if (!curTimer)
|
||||
{
|
||||
TimerEntry newTimer;
|
||||
|
||||
newTimer.timer = timer;
|
||||
newTimer.fireTime = curTime() + microSeconds;
|
||||
timerQueue->add(newTimer);
|
||||
timer->addRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
curTimer->fireTime = curTime() + microSeconds;
|
||||
}
|
||||
|
||||
timerWakeup->release();
|
||||
}
|
||||
|
||||
void FB_CARG stop(ITimer* timer)
|
||||
{
|
||||
MutexLockGuard guard(timerAccess);
|
||||
|
||||
TimerEntry* curTimer = getTimer(timer);
|
||||
if (curTimer)
|
||||
{
|
||||
curTimer->timer->release();
|
||||
timerQueue->remove(curTimer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ITimerControl* FB_CARG MasterImplementation::getTimerControl()
|
||||
{
|
||||
static Static<TimerImplementation> timer;
|
||||
|
||||
timer->addRef();
|
||||
return &timer;
|
||||
}
|
||||
|
||||
void shutdownTimers()
|
||||
{
|
||||
timerHolder.cleanup();
|
||||
}
|
||||
|
||||
} // namespace Firebird
|
||||
|
||||
|
||||
//
|
||||
// get master
|
||||
//
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../common/classes/fb_string.h"
|
||||
#include "../common/classes/init.h"
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/config/config.h"
|
||||
#include "../common/config/config_file.h"
|
||||
#include "../common/utils_proto.h"
|
||||
@ -295,6 +296,22 @@ namespace
|
||||
cleanup = c;
|
||||
}
|
||||
|
||||
void resetCleanup(IModuleCleanup* c)
|
||||
{
|
||||
if (cleanup == c)
|
||||
{
|
||||
cleanup = 0;
|
||||
}
|
||||
else if (next)
|
||||
{
|
||||
next->resetCleanup(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
gds__log("Failed to reset cleanup %p\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
~PluginModule()
|
||||
{
|
||||
@ -323,6 +340,33 @@ namespace
|
||||
PathName name;
|
||||
};
|
||||
|
||||
struct CountByType
|
||||
{
|
||||
int counter;
|
||||
Semaphore* waitsOn;
|
||||
|
||||
CountByType()
|
||||
: counter(0), waitsOn(NULL)
|
||||
{ }
|
||||
};
|
||||
struct CountByTypeArray
|
||||
{
|
||||
CountByTypeArray(MemoryPool&)
|
||||
{}
|
||||
|
||||
CountByType values[PluginType::MaxType];
|
||||
|
||||
CountByType& get(unsigned int t)
|
||||
{
|
||||
fb_assert(t < PluginType::MaxType);
|
||||
return values[t];
|
||||
}
|
||||
};
|
||||
|
||||
GlobalPtr<CountByTypeArray> byTypeCounters;
|
||||
|
||||
PluginModule* builtin = NULL;
|
||||
|
||||
class ConfiguredPlugin : public RefCounted, public GlobalStorage
|
||||
{
|
||||
public:
|
||||
@ -340,6 +384,10 @@ namespace
|
||||
confName = p->value.ToPathName();
|
||||
}
|
||||
}
|
||||
if (module != builtin)
|
||||
{
|
||||
byTypeCounters->get(module->getPlugin(regPlugin).type).counter++;
|
||||
}
|
||||
#ifdef DEBUG_PLUGINS
|
||||
RegisteredPlugin& r(module->getPlugin(regPlugin));
|
||||
fprintf(stderr, " ConfiguredPlugin %s module %s registered as %s type %d order %d\n",
|
||||
@ -465,7 +513,7 @@ namespace
|
||||
{
|
||||
public:
|
||||
explicit PluginsMap(MemoryPool& p)
|
||||
: GenericMap<Pair<Left<MapKey, ConfiguredPlugin*> > >(p)
|
||||
: GenericMap<Pair<Left<MapKey, ConfiguredPlugin*> > >(p), wakeIt(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -484,6 +532,7 @@ namespace
|
||||
}
|
||||
|
||||
Mutex mutex;
|
||||
Semaphore* wakeIt;
|
||||
};
|
||||
|
||||
GlobalPtr<PluginsMap> plugins;
|
||||
@ -494,6 +543,16 @@ namespace
|
||||
{
|
||||
plugins->remove(MapKey(module->getPlugin(regPlugin).type, plugName));
|
||||
}
|
||||
|
||||
fb_assert(!plugins->wakeIt);
|
||||
if (module != builtin)
|
||||
{
|
||||
unsigned int type = module->getPlugin(regPlugin).type;
|
||||
if (--(byTypeCounters->get(type).counter) == 0)
|
||||
{
|
||||
plugins->wakeIt = byTypeCounters->get(type).waitsOn;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_PLUGINS
|
||||
fprintf(stderr, "~ConfiguredPlugin %s type %d\n", plugName.c_str(), module->getPlugin(regPlugin).type);
|
||||
#endif
|
||||
@ -501,7 +560,6 @@ namespace
|
||||
|
||||
PluginModule* modules = NULL;
|
||||
|
||||
PluginModule* builtin = NULL;
|
||||
PluginModule* current = NULL;
|
||||
|
||||
PluginModule::PluginModule(ModuleLoader::Module* pmodule, const PathName& pname)
|
||||
@ -773,6 +831,12 @@ void FB_CARG PluginManager::setModuleCleanup(IModuleCleanup* cleanup)
|
||||
current->setCleanup(cleanup);
|
||||
}
|
||||
|
||||
void FB_CARG PluginManager::resetModuleCleanup(IModuleCleanup* cleanup)
|
||||
{
|
||||
MutexLockGuard g(plugins->mutex);
|
||||
|
||||
modules->resetCleanup(cleanup);
|
||||
}
|
||||
|
||||
IPluginSet* FB_CARG PluginManager::getPlugins(unsigned int interfaceType, const char* namesList,
|
||||
int desiredVersion, void* missingFunctionClass,
|
||||
@ -797,9 +861,15 @@ void FB_CARG PluginManager::releasePlugin(Plugin* plugin)
|
||||
if (parent)
|
||||
{
|
||||
parent->release();
|
||||
if (plugins->wakeIt)
|
||||
{
|
||||
plugins->wakeIt->release();
|
||||
plugins->wakeIt = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
plugin->owner(parent);
|
||||
}
|
||||
}
|
||||
@ -816,4 +886,35 @@ void PluginManager::shutdown()
|
||||
flShutdown = true;
|
||||
}
|
||||
|
||||
void PluginManager::waitForType(unsigned int typeThatMustGoAway)
|
||||
{
|
||||
fb_assert(typeThatMustGoAway < PluginType::MaxType);
|
||||
|
||||
Semaphore sem;
|
||||
Semaphore* semPtr = NULL;
|
||||
{ // guard scope
|
||||
MutexLockGuard g(plugins->mutex);
|
||||
|
||||
if (byTypeCounters->get(typeThatMustGoAway).counter > 0)
|
||||
{
|
||||
fb_assert(!byTypeCounters->get(typeThatMustGoAway).waitsOn);
|
||||
byTypeCounters->get(typeThatMustGoAway).waitsOn = semPtr = &sem;
|
||||
#ifdef DEBUG_PLUGINS
|
||||
fprintf(stderr, "PluginManager::waitForType %d\n", typeThatMustGoAway);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_PLUGINS
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "PluginManager: type %d is already gone\n", typeThatMustGoAway);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (semPtr)
|
||||
{
|
||||
semPtr->enter();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Firebird
|
||||
|
@ -49,10 +49,12 @@ public:
|
||||
IConfig* FB_CARG getConfig(const char* filename);
|
||||
void FB_CARG releasePlugin(Plugin* plugin);
|
||||
void FB_CARG setModuleCleanup(IModuleCleanup* cleanup);
|
||||
void FB_CARG resetModuleCleanup(IModuleCleanup* cleanup);
|
||||
|
||||
PluginManager();
|
||||
|
||||
static void shutdown();
|
||||
static void waitForType(unsigned int typeThatMustGoAway);
|
||||
};
|
||||
|
||||
} // namespace Firebird
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user