Serious-Engine/Sources/Engine/Base/ThreadLocalStorage.h
Ryan C. Gordon 24cb244d43 First attempt to hand-merge Ryan's Linux and Mac OS X port.
This was a _ton_ of changes, made 15 years ago, so there are probably some
problems to work out still.

Among others: Engine/Base/Stream.* was mostly abandoned and will need to be
re-ported.

Still, this is a pretty good start, and probably holds a world record for
lines of changes or something.  :)
2016-03-28 23:46:13 -04:00

148 lines
3.3 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#ifndef SE_INCL_THREADLOCALSTORAGE_H
#define SE_INCL_THREADLOCALSTORAGE_H
#ifdef PRAGMA_ONCE
#pragma once
#endif
#ifdef SINGLE_THREADED
#define THREADLOCAL(type, name, defval) type name = defval
#define EXTERNTHREADLOCAL(type, name) extern type name
#elif (defined _MSC_VER)
#define THREADLOCAL(type, name, defval) type __declspec(thread) name = defval
#define EXTERNTHREADLOCAL(type, name) extern type __declspec(thread) name
#else
#define THREADLOCAL(type, name, defval) CThreadLocalStorage<type> name(defval)
#define EXTERNTHREADLOCAL(type, name) extern CThreadLocalStorage<type> name
#include <Engine/Engine.h>
// !!! FIXME : There is a race condition if a thread is making space for
// !!! FIXME : itself at the same time another thread is touching this class.
// !!! FIXME : Generally, this won't be a problem, if you are careful about
// !!! FIXME : new threads accessing an instance of CThreadLocalStorage for
// !!! FIXME : the first time. I haven't added mutexes, since it would slow
// !!! FIXME : the template class down. If you need it, either do some
// !!! FIXME : external locking, or subclass CThreadLocalStorage to include
// !!! FIXME : a locking mechanism.
// !!! FIXME: 15 years later: why didn't I just use a pthread_key?
ULONG ThreadLocalGetCurrentTID(void);
template <class T>
class CThreadLocalStorage
{
protected:
typedef struct
{
ULONG tid;
T data;
} LocalElements;
size_t FindThreadIndex(void)
{
ULONG tid = ThreadLocalGetCurrentTID();
for (size_t i = 0; i < array_size; i++)
{
if (elements[i].tid == tid)
return(i);
} // for
LocalElements *_elements = new LocalElements[array_size + 1];
for (size_t i = 0; i < array_size; i++)
{
_elements[i].data = elements[i].data;
_elements[i].tid = elements[i].tid;
} // for
delete[] elements;
elements = _elements;
elements[array_size].data = defval;
elements[array_size].tid = tid;
return(array_size++);
} // FindThreadIndex
private:
LocalElements *elements;
size_t array_size;
T defval;
public:
CThreadLocalStorage(T _defval)
: elements(NULL),
array_size(0),
defval(_defval)
{
} // Constructor
~CThreadLocalStorage(void)
{
delete[] elements;
} // Destructor
T &operator =(T val)
{
elements[FindThreadIndex()].data = val;
return(val);
} // operator =
T &operator->(void)
{
return(elements[FindThreadIndex()].data);
} // operator ->
operator T &(void)
{
return(elements[FindThreadIndex()].data);
} // operator T &
};
#if 0
// a test program.
static CThreadLocalStorage<int> tlocal(0);
void *other_thread(void *arg)
{
tlocal = 10;
while (true)
{
printf("2nd thread: %d.\n", (int) tlocal);
sleep(1);
}
return(NULL);
}
int main(int argc, char **argv)
{
pthread_t thread;
tlocal = 5;
pthread_create(&thread, NULL, other_thread, NULL);
while (true)
{
printf("main thread: %d.\n", (int) tlocal);
sleep(1);
}
return(0);
}
#endif
#endif // !defined SINGLE_THREADED
#endif // include-once blocker.
// end of ThreadLocalStorage.h ...