8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 06:43:02 +01:00
firebird-mirror/src/common/classes/fb_tls.h

223 lines
5.4 KiB
C
Raw Normal View History

/*
* PROGRAM: Client/Server Common Code
* MODULE: fb_tls.h
* DESCRIPTION: Thread-local storage handlers
*
* 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 Nickolay Samofatov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2004 Nickolay Samofatov <nickolay@broadviewsoftware.com>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
2008-12-05 01:56:15 +01:00
#ifndef CLASSES_FB_TLS_H
#define CLASSES_FB_TLS_H
// This unit defines a few handy macros
// TLS_DECLARE is used in place of variable declaration
// TLS_GET gives value of thread-specific variable
// TLS_SET sets value of thread-specific variable
//
// TLS variable type should be smaller than size of pointer to stay portable
#include "../common/classes/init.h"
2008-01-16 07:24:06 +01:00
#if defined(HAVE___THREAD)
// Recent GCC supports __thread keyword. Sun compiler and HP-UX should have it too
# define TLS_DECLARE(TYPE, NAME) __thread TYPE NAME
# define TLS_GET(NAME) NAME
2004-11-30 07:18:39 +01:00
# define TLS_SET(NAME, VALUE) NAME = (VALUE)
2004-04-06 07:53:36 +02:00
#elif defined(WIN_NT)
namespace Firebird {
template <typename T>
class Win32Tls : private InstanceControl
2008-04-19 13:11:10 +02:00
{
2004-04-06 07:53:36 +02:00
public:
Win32Tls() : InstanceControl()
2008-04-19 13:11:10 +02:00
{
if ((key = TlsAlloc()) == MAX_ULONG)
system_call_failed::raise("TlsAlloc");
// Allocated pointer is saved by InstanceList::constructor.
2009-03-05 07:05:19 +01:00
new InstanceControl::InstanceLink<Win32Tls, PRIORITY_TLS_KEY>(this);
}
2008-04-19 13:11:10 +02:00
const T get()
{
fb_assert(key != MAX_ULONG);
const LPVOID value = TlsGetValue(key);
if ((value == NULL) && (GetLastError() != NO_ERROR))
system_call_failed::raise("TlsGetValue");
return (T) value;
}
2008-04-19 13:11:10 +02:00
void set(const T value)
{
fb_assert(key != MAX_ULONG);
if (TlsSetValue(key, (LPVOID) value) == 0)
system_call_failed::raise("TlsSetValue");
}
2008-04-19 13:11:10 +02:00
~Win32Tls()
{
}
void dtor()
2008-04-19 13:11:10 +02:00
{
if (TlsFree(key) == 0)
system_call_failed::raise("TlsFree");
key = MAX_ULONG;
}
2004-04-06 07:53:36 +02:00
private:
2008-12-05 01:56:15 +01:00
DWORD key;
2004-04-06 07:53:36 +02:00
};
} // namespace Firebird
2004-05-09 07:48:33 +02:00
# define TLS_DECLARE(TYPE, NAME) ::Firebird::Win32Tls<TYPE> NAME
2004-04-06 07:53:36 +02:00
# define TLS_GET(NAME) NAME.get()
2004-11-24 10:22:07 +01:00
# define TLS_SET(NAME, VALUE) NAME.set(VALUE)
2004-04-06 07:53:36 +02:00
2004-07-14 23:49:03 +02:00
// 14-Jul-2004 Nickolay Samofatov.
//
// Unfortunately, compiler-assisted TLS doesn't work with dynamic link libraries
2008-12-05 01:56:15 +01:00
// loaded via LoadLibrary - it intermittently crashes and these crashes are
2004-07-14 23:49:03 +02:00
// documented by MS. We may still use it for server binaries, but it requires
2008-12-05 01:56:15 +01:00
// some changes in build environment. Let's defer this till later point and
2004-07-14 23:49:03 +02:00
// think of reliable mean to prevent linking of DLL with code below (if enabled).
//
//# define TLS_DECLARE(TYPE, NAME) __declspec(thread) TYPE NAME
//# define TLS_GET(NAME) NAME
2004-11-30 07:18:39 +01:00
//# define TLS_SET(NAME, VALUE) NAME = (VALUE)
#else
2006-02-20 09:00:52 +01:00
#ifndef SOLARIS_MT
2004-06-16 14:33:13 +02:00
#include "../common/classes/init.h"
#include <pthread.h>
namespace Firebird {
template <typename T>
class TlsValue : private InstanceControl
2008-04-19 13:11:10 +02:00
{
public:
TlsValue() : InstanceControl()
#ifdef DEV_BUILD
, keySet(true)
#endif
2008-04-19 13:11:10 +02:00
{
2009-01-14 15:27:11 +01:00
int rc = pthread_key_create(&key, NULL);
if (rc)
system_call_failed::raise("pthread_key_create", rc);
// Allocated pointer is saved by InstanceList::constructor.
new InstanceControl::InstanceLink<TlsValue, PRIORITY_TLS_KEY>(this);
}
2009-03-05 01:52:25 +01:00
2008-04-19 13:11:10 +02:00
const T get()
{
fb_assert(keySet);
// We use double C-style cast to allow using scalar datatypes
// with sizes up to size of pointer without warnings
2009-01-15 04:46:48 +01:00
return (T)(IPTR) pthread_getspecific(key);
}
2008-04-19 13:11:10 +02:00
void set(const T value)
{
fb_assert(keySet);
2009-01-15 08:41:11 +01:00
int rc = pthread_setspecific(key, (void*)(IPTR) value);
if (rc)
2009-01-14 15:27:11 +01:00
system_call_failed::raise("pthread_setspecific", rc);
}
2008-04-19 13:11:10 +02:00
~TlsValue()
{
}
void dtor()
2008-04-19 13:11:10 +02:00
{
2009-01-15 08:41:11 +01:00
int rc = pthread_key_delete(key);
2009-01-14 15:27:11 +01:00
if (rc)
system_call_failed::raise("pthread_key_delete", rc);
#ifdef DEV_BUILD
2009-01-14 15:27:11 +01:00
keySet = false;
#endif
}
private:
2008-12-05 01:56:15 +01:00
pthread_key_t key;
#ifdef DEV_BUILD
2009-01-14 15:27:11 +01:00
bool keySet; // This is used to avoid conflicts when destroying global variables
#endif
};
#else //SOLARIS_MT
2004-06-16 14:33:13 +02:00
#include <thread.h>
#include <string.h>
namespace Firebird {
template <typename T>
2008-04-19 13:11:10 +02:00
class TlsValue
{
2004-06-16 14:33:13 +02:00
public:
2008-04-19 13:11:10 +02:00
static void TlsV_on_thread_exit (void * pval)
{
/* Usually should delete pval like this
2008-04-23 04:19:25 +02:00
T* ptempT = (T*) pval;
delete ptempT;
*/
}
2008-04-19 13:11:10 +02:00
TlsValue()
{
if (thr_keycreate(&key, TlsV_on_thread_exit))
system_call_failed::raise("thr_key_create");
}
2008-04-19 13:11:10 +02:00
const T get()
{
// We use double C-style cast to allow using scalar datatypes
// with sizes up to size of pointer without warnings
2008-04-19 13:11:10 +02:00
T* valuep;
if (thr_getspecific(key, (void**) &valuep) == 0)
return (T)(IPTR) valuep;
2008-04-19 13:11:10 +02:00
system_call_failed::raise("thr_getspecific");
2008-04-23 04:19:25 +02:00
return (T) NULL;
}
2008-04-19 13:11:10 +02:00
void set(const T value)
{
if (thr_setspecific(key, (void*)(IPTR) value))
system_call_failed::raise("thr_setspecific");
}
2008-04-19 13:11:10 +02:00
~TlsValue()
{
// Do nothing if no pthread_key_delete
}
2004-06-16 14:33:13 +02:00
private:
2008-12-05 01:56:15 +01:00
thread_key_t key;
2004-06-16 14:33:13 +02:00
};
#endif //SOLARIS_MT
} // namespace Firebird
2004-05-09 07:48:33 +02:00
# define TLS_DECLARE(TYPE, NAME) ::Firebird::TlsValue<TYPE> NAME
# define TLS_GET(NAME) NAME.get()
2004-11-24 10:22:07 +01:00
# define TLS_SET(NAME, VALUE) NAME.set(VALUE)
#endif
#endif // CLASSES_FB_TLS_H