2008-01-23 16:55:21 +01:00
|
|
|
/*
|
|
|
|
* PROGRAM: Common Access Method
|
|
|
|
* MODULE: init.cpp
|
|
|
|
* DESCRIPTION: InstanceControl - class to control global ctors/dtors
|
|
|
|
*
|
|
|
|
* 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 Alexander Peshkoff
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2008 Alexander Peshkoff <peshkoff@mail.ru>
|
|
|
|
* and all contributors signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h"
|
|
|
|
#include "init.h"
|
|
|
|
#include "alloc.h"
|
|
|
|
|
|
|
|
// Setting this define helps (with AV at exit time) detect globals
|
|
|
|
// with destructors, declared not using InstanceControl.
|
|
|
|
// The reason for AV is that process memory pool (from where globals should allocate memory)
|
|
|
|
// is destoyed in atexit(), before destructors are called. Therefore each delete
|
|
|
|
// operator in destructor will cause AV.
|
|
|
|
#undef DEBUG_INIT
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2008-01-31 13:01:03 +01:00
|
|
|
#ifdef DEV_BUILD
|
2008-06-03 13:43:42 +02:00
|
|
|
void cleanError(const Firebird::Exception* e)
|
|
|
|
{
|
|
|
|
// This is done to be able to look at status in debugger
|
|
|
|
ISC_STATUS_ARRAY status;
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
Firebird::CircularStringsBuffer<4096> localBuffer;
|
|
|
|
e->stuff_exception(status, &localBuffer);
|
|
|
|
}
|
2008-01-31 13:01:03 +01:00
|
|
|
// we do not have big choice in error reporting when running destructors
|
|
|
|
abort();
|
|
|
|
}
|
2008-06-03 13:43:42 +02:00
|
|
|
#else
|
|
|
|
void cleanError(const Firebird::Exception*) { }
|
|
|
|
#endif
|
2008-01-23 16:55:21 +01:00
|
|
|
|
|
|
|
// This helps initialize globals, needed before regular ctors run
|
|
|
|
bool initDone = false;
|
|
|
|
|
|
|
|
void allClean()
|
|
|
|
{
|
|
|
|
Firebird::InstanceControl::destructors();
|
2008-02-28 14:59:03 +01:00
|
|
|
|
2008-01-31 13:01:03 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Firebird::StaticMutex::release();
|
|
|
|
}
|
2008-02-01 18:33:14 +01:00
|
|
|
catch (...)
|
2008-01-31 13:01:03 +01:00
|
|
|
{
|
2008-06-06 04:25:35 +02:00
|
|
|
cleanError(NULL);
|
2008-01-31 13:01:03 +01:00
|
|
|
}
|
2008-02-28 14:59:03 +01:00
|
|
|
|
2008-01-31 13:01:03 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Firebird::MemoryPool::cleanup();
|
|
|
|
}
|
2008-02-01 18:33:14 +01:00
|
|
|
catch (...)
|
2008-01-31 13:01:03 +01:00
|
|
|
{
|
2008-06-06 04:25:35 +02:00
|
|
|
cleanError(NULL);
|
2008-01-31 13:01:03 +01:00
|
|
|
}
|
2008-01-23 16:55:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef DEBUG_INIT
|
|
|
|
// This class with it's single instance ensures global cleanup
|
|
|
|
class Cleanup
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
~Cleanup()
|
|
|
|
{
|
|
|
|
allClean();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Cleanup global;
|
|
|
|
#endif //DEBUG_INIT
|
|
|
|
|
|
|
|
void init()
|
|
|
|
{
|
2009-03-05 01:52:25 +01:00
|
|
|
// This initialization code can't use mutex to protect itself
|
2009-03-04 11:26:16 +01:00
|
|
|
// cause among other it's preparing mutexes to work. But as long
|
|
|
|
// as only one thread is used to initialize globals (which is a case
|
|
|
|
// for all known in year 2009 systems), it's safe to use it if we
|
2009-03-05 07:05:50 +01:00
|
|
|
// have at least one global (not static in function) GlobalPtr<>
|
2009-03-05 01:52:25 +01:00
|
|
|
// variable. When later "static GlobalPtr<>" variables in functions
|
2009-03-04 11:26:16 +01:00
|
|
|
// are constructed (which may happen in parallel in different threads),
|
|
|
|
// races are prevented by StaticMutex::mutex.
|
|
|
|
|
2008-01-23 16:55:21 +01:00
|
|
|
if (initDone)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2008-02-01 18:33:14 +01:00
|
|
|
|
2008-02-11 10:52:32 +01:00
|
|
|
Firebird::Mutex::initMutexes();
|
2008-01-23 16:55:21 +01:00
|
|
|
Firebird::MemoryPool::init();
|
|
|
|
Firebird::StaticMutex::create();
|
|
|
|
|
|
|
|
#ifdef DEBUG_INIT
|
|
|
|
atexit(allClean);
|
|
|
|
#endif //DEBUG_INIT
|
|
|
|
|
|
|
|
initDone = true;
|
|
|
|
}
|
2009-03-04 11:26:16 +01:00
|
|
|
|
|
|
|
Firebird::InstanceControl::InstanceList* instanceList = 0;
|
|
|
|
FPTR_VOID gdsCleanup = 0;
|
|
|
|
FPTR_VOID gdsShutdown = 0;
|
2008-01-23 16:55:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace Firebird
|
|
|
|
{
|
2009-03-04 11:26:16 +01:00
|
|
|
InstanceControl::InstanceControl()
|
2008-01-23 16:55:21 +01:00
|
|
|
{
|
2009-03-04 11:26:16 +01:00
|
|
|
// Initialize required subsystems, including static mutex
|
2008-01-23 16:55:21 +01:00
|
|
|
init();
|
2009-03-04 11:26:16 +01:00
|
|
|
}
|
2008-02-28 14:59:03 +01:00
|
|
|
|
2009-03-04 11:26:16 +01:00
|
|
|
InstanceControl::InstanceList::InstanceList(DtorPriority p)
|
|
|
|
: priority(p)
|
|
|
|
{
|
|
|
|
MutexLockGuard guard(*StaticMutex::mutex);
|
2008-01-23 16:55:21 +01:00
|
|
|
next = instanceList;
|
|
|
|
instanceList = this;
|
|
|
|
}
|
|
|
|
|
2009-03-04 11:26:16 +01:00
|
|
|
InstanceControl::InstanceList::~InstanceList()
|
|
|
|
{
|
|
|
|
delete next;
|
|
|
|
}
|
|
|
|
|
2008-01-23 16:55:21 +01:00
|
|
|
void InstanceControl::destructors()
|
|
|
|
{
|
2008-03-17 17:49:47 +01:00
|
|
|
// Call fb_shutdown() if needed
|
|
|
|
if (gdsShutdown)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
gdsShutdown();
|
|
|
|
}
|
2008-06-03 13:43:42 +02:00
|
|
|
catch (const Firebird::Exception& e)
|
2008-03-17 17:49:47 +01:00
|
|
|
{
|
2008-06-03 13:43:42 +02:00
|
|
|
cleanError(&e);
|
2008-03-17 17:49:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-23 16:55:21 +01:00
|
|
|
// Call gds__cleanup() if present
|
|
|
|
if (gdsCleanup)
|
|
|
|
{
|
2008-01-31 13:01:03 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
gdsCleanup();
|
|
|
|
}
|
2008-06-03 13:43:42 +02:00
|
|
|
catch (const Firebird::Exception& e)
|
2008-01-31 13:01:03 +01:00
|
|
|
{
|
2008-06-03 13:43:42 +02:00
|
|
|
cleanError(&e);
|
2008-01-31 13:01:03 +01:00
|
|
|
}
|
2008-01-23 16:55:21 +01:00
|
|
|
}
|
|
|
|
|
2009-03-04 11:26:16 +01:00
|
|
|
InstanceControl::InstanceList::destructors();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void InstanceControl::InstanceList::destructors()
|
|
|
|
{
|
2008-01-23 16:55:21 +01:00
|
|
|
// Destroy global objects
|
2009-01-19 17:16:19 +01:00
|
|
|
DtorPriority currentPriority = PRIORITY_REGULAR, nextPriority = currentPriority;
|
2009-01-21 16:42:45 +01:00
|
|
|
|
2009-01-19 17:16:19 +01:00
|
|
|
do
|
2008-01-23 16:55:21 +01:00
|
|
|
{
|
2009-01-19 17:16:19 +01:00
|
|
|
currentPriority = nextPriority;
|
2009-01-21 16:42:45 +01:00
|
|
|
|
2009-03-04 11:26:16 +01:00
|
|
|
for (InstanceList* i = instanceList; i; i = i->next)
|
2008-01-31 13:01:03 +01:00
|
|
|
{
|
2009-01-19 17:16:19 +01:00
|
|
|
if (i->priority == currentPriority)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
i->dtor();
|
|
|
|
}
|
|
|
|
catch (const Firebird::Exception& e)
|
|
|
|
{
|
|
|
|
cleanError(&e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (i->priority > currentPriority)
|
|
|
|
{
|
|
|
|
if (nextPriority == currentPriority || i->priority < nextPriority)
|
|
|
|
{
|
|
|
|
nextPriority = i->priority;
|
|
|
|
}
|
|
|
|
}
|
2008-01-31 13:01:03 +01:00
|
|
|
}
|
2009-01-19 17:16:19 +01:00
|
|
|
} while (nextPriority != currentPriority);
|
2009-03-04 11:26:16 +01:00
|
|
|
|
|
|
|
delete instanceList;
|
|
|
|
instanceList = 0;
|
2008-01-23 16:55:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void InstanceControl::registerGdsCleanup(FPTR_VOID cleanup)
|
|
|
|
{
|
2008-06-03 08:14:59 +02:00
|
|
|
fb_assert(!gdsCleanup || !cleanup);
|
2008-01-23 16:55:21 +01:00
|
|
|
gdsCleanup = cleanup;
|
|
|
|
}
|
|
|
|
|
2008-03-17 17:49:47 +01:00
|
|
|
void InstanceControl::registerShutdown(FPTR_VOID shutdown)
|
|
|
|
{
|
2008-06-03 08:14:59 +02:00
|
|
|
fb_assert(!gdsShutdown || !shutdown);
|
2008-03-17 17:49:47 +01:00
|
|
|
gdsShutdown = shutdown;
|
|
|
|
}
|
|
|
|
|
2009-03-04 11:26:16 +01:00
|
|
|
namespace StaticMutex
|
2008-01-23 16:55:21 +01:00
|
|
|
{
|
2009-03-04 11:26:16 +01:00
|
|
|
Firebird::Mutex* mutex = NULL;
|
2008-01-23 16:55:21 +01:00
|
|
|
|
2009-03-04 11:26:16 +01:00
|
|
|
void create()
|
|
|
|
{
|
|
|
|
static char staticMutexPlace[sizeof(Firebird::Mutex)];
|
|
|
|
mutex = new(staticMutexPlace) Firebird::Mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void release()
|
|
|
|
{
|
|
|
|
mutex->~Mutex();
|
|
|
|
}
|
2008-01-23 16:55:21 +01:00
|
|
|
}
|
|
|
|
}
|