Move ke_ headers to new public/amtl folder.
--HG-- rename : public/sourcepawn/ke_allocator_policies.h => public/amtl/ke_allocator_policies.h rename : public/sourcepawn/ke_inline_list.h => public/amtl/ke_inline_list.h rename : public/sourcepawn/ke_thread_posix.h => public/amtl/ke_thread_posix.h rename : public/sourcepawn/ke_thread_utils.h => public/amtl/ke_thread_utils.h rename : public/sourcepawn/ke_thread_windows.h => public/amtl/ke_thread_windows.h rename : public/sourcepawn/ke_utility.h => public/amtl/ke_utility.h rename : public/sourcepawn/ke_vector.h => public/amtl/ke_vector.h
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/* vim: set ts=2 sw=2 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2012 David Anderson
|
||||
*
|
||||
* This file is part of SourcePawn.
|
||||
*
|
||||
* SourcePawn is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
#ifndef _include_sourcepawn_allocatorpolicies_h_
|
||||
#define _include_sourcepawn_allocatorpolicies_h_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
class SystemAllocatorPolicy
|
||||
{
|
||||
protected:
|
||||
void reportOutOfMemory() {
|
||||
fprintf(stderr, "OUT OF MEMORY\n");
|
||||
abort();
|
||||
}
|
||||
void reportAllocationOverflow() {
|
||||
fprintf(stderr, "OUT OF MEMORY\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
public:
|
||||
void free(void *memory) {
|
||||
::free(memory);
|
||||
}
|
||||
void *malloc(size_t bytes) {
|
||||
void *ptr = ::malloc(bytes);
|
||||
if (!ptr)
|
||||
reportOutOfMemory();
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_sourcepawn_allocatorpolicies_h_
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* vim: set sts=2 ts=8 sw=2 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourcePawn
|
||||
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*/
|
||||
#ifndef _include_sourcepawn_inline_list_h_
|
||||
#define _include_sourcepawn_inline_list_h_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
template <typename T> class InlineList;
|
||||
|
||||
template <typename T>
|
||||
class InlineListNode
|
||||
{
|
||||
friend class InlineList<T>;
|
||||
|
||||
public:
|
||||
InlineListNode()
|
||||
: next_(NULL),
|
||||
prev_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
InlineListNode(InlineListNode *next, InlineListNode *prev)
|
||||
: next_(next),
|
||||
prev_(prev)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
InlineListNode *next_;
|
||||
InlineListNode *prev_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class InlineList
|
||||
{
|
||||
typedef InlineListNode<T> Node;
|
||||
|
||||
Node head_;
|
||||
|
||||
public:
|
||||
InlineList()
|
||||
: head_(&head_, &head_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
friend class InlineList;
|
||||
Node *iter_;
|
||||
|
||||
public:
|
||||
iterator(Node *iter)
|
||||
: iter_(iter)
|
||||
{
|
||||
}
|
||||
|
||||
iterator & operator ++() {
|
||||
iter_ = iter_->next;
|
||||
return *iter_;
|
||||
}
|
||||
iterator operator ++(int) {
|
||||
iterator old(*this);
|
||||
iter_ = iter_->next_;
|
||||
return old;
|
||||
}
|
||||
T * operator *() {
|
||||
return static_cast<T *>(iter_);
|
||||
}
|
||||
T * operator ->() {
|
||||
return static_cast<T *>(iter_);
|
||||
}
|
||||
bool operator !=(const iterator &where) const {
|
||||
return iter_ != where.iter_;
|
||||
}
|
||||
bool operator ==(const iterator &where) const {
|
||||
return iter_ == where.iter_;
|
||||
}
|
||||
iterator prev() const {
|
||||
iterator p(iter_->prev_);
|
||||
return p;
|
||||
}
|
||||
iterator next() const {
|
||||
iterator p(iter_->next_);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
return iterator(head_.next_);
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(&head_);
|
||||
}
|
||||
|
||||
void erase(Node *t) {
|
||||
t->prev_->next_ = t->next_;
|
||||
t->next_->prev_ = t->prev_;
|
||||
}
|
||||
|
||||
void insert(Node *t) {
|
||||
t->prev_ = head_.prev_;
|
||||
t->next_ = &head_;
|
||||
head_.prev_->next_ = t;
|
||||
head_.prev_ = t;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _include_sourcepawn_inline_list_h_
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// This file is part of SourcePawn.
|
||||
//
|
||||
// SourcePawn is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// SourcePawn is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with SourcePawn. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef _include_sourcepawn_thread_posix_h_
|
||||
#define _include_sourcepawn_thread_posix_h_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#if defined(__linux__)
|
||||
# include <sys/prctl.h>
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace ke {
|
||||
|
||||
class Mutex : public Lockable
|
||||
{
|
||||
public:
|
||||
Mutex() {
|
||||
#if !defined(NDEBUG)
|
||||
int rv =
|
||||
#endif
|
||||
pthread_mutex_init(&mutex_, NULL);
|
||||
assert(rv == 0);
|
||||
}
|
||||
~Mutex() {
|
||||
pthread_mutex_destroy(&mutex_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
return pthread_mutex_trylock(&mutex_) == 0;
|
||||
}
|
||||
|
||||
void DoLock() {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
}
|
||||
|
||||
void DoUnlock() {
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
}
|
||||
|
||||
pthread_mutex_t *raw() {
|
||||
return &mutex_;
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t mutex_;
|
||||
};
|
||||
|
||||
// Currently, this class only supports single-listener CVs.
|
||||
class ConditionVariable : public Lockable
|
||||
{
|
||||
public:
|
||||
ConditionVariable() {
|
||||
#if !defined(NDEBUG)
|
||||
int rv =
|
||||
#endif
|
||||
pthread_cond_init(&cv_, NULL);
|
||||
assert(rv == 0);
|
||||
}
|
||||
~ConditionVariable() {
|
||||
pthread_cond_destroy(&cv_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
return mutex_.DoTryLock();
|
||||
}
|
||||
void DoLock() {
|
||||
mutex_.DoLock();
|
||||
}
|
||||
void DoUnlock() {
|
||||
mutex_.DoUnlock();
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
AssertCurrentThreadOwns();
|
||||
pthread_cond_signal(&cv_);
|
||||
}
|
||||
|
||||
WaitResult Wait(size_t timeout_ms) {
|
||||
AssertCurrentThreadOwns();
|
||||
|
||||
#if defined(__linux__)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
|
||||
return Wait_Error;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
struct timespec ts;
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
#endif
|
||||
|
||||
ts.tv_sec += timeout_ms / 1000;
|
||||
ts.tv_nsec += (timeout_ms % 1000) * 1000000;
|
||||
if (ts.tv_nsec >= 1000000000) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000;
|
||||
}
|
||||
|
||||
DebugSetUnlocked();
|
||||
int rv = pthread_cond_timedwait(&cv_, mutex_.raw(), &ts);
|
||||
DebugSetLocked();
|
||||
|
||||
if (rv == ETIMEDOUT)
|
||||
return Wait_Timeout;
|
||||
if (rv == 0)
|
||||
return Wait_Signaled;
|
||||
return Wait_Error;
|
||||
}
|
||||
|
||||
WaitResult Wait() {
|
||||
AssertCurrentThreadOwns();
|
||||
|
||||
DebugSetUnlocked();
|
||||
int rv = pthread_cond_wait(&cv_, mutex_.raw());
|
||||
DebugSetLocked();
|
||||
|
||||
if (rv == 0)
|
||||
return Wait_Signaled;
|
||||
return Wait_Error;
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
pthread_cond_t cv_;
|
||||
};
|
||||
|
||||
class Thread
|
||||
{
|
||||
struct ThreadData {
|
||||
IRunnable *run;
|
||||
char name[17];
|
||||
};
|
||||
public:
|
||||
Thread(IRunnable *run, const char *name = NULL) {
|
||||
ThreadData *data = new ThreadData;
|
||||
data->run = run;
|
||||
snprintf(data->name, sizeof(data->name), "%s", name ? name : "");
|
||||
|
||||
initialized_ = (pthread_create(&thread_, NULL, Main, data) == 0);
|
||||
if (!initialized_)
|
||||
delete data;
|
||||
}
|
||||
|
||||
bool Succeeded() const {
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
void Join() {
|
||||
if (!Succeeded())
|
||||
return;
|
||||
pthread_join(thread_, NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
static void *Main(void *arg) {
|
||||
AutoPtr<ThreadData> data((ThreadData *)arg);
|
||||
|
||||
if (data->name[0]) {
|
||||
#if defined(__linux__)
|
||||
prctl(PR_SET_NAME, (unsigned long)data->name);
|
||||
#elif defined(__APPLE__)
|
||||
int (*fn)(const char *) = (int (*)(const char *))dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
||||
if (fn)
|
||||
fn(data->name);
|
||||
#endif
|
||||
}
|
||||
data->run->Run();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
bool initialized_;
|
||||
pthread_t thread_;
|
||||
};
|
||||
|
||||
} // namespace ke
|
||||
|
||||
#endif // _include_sourcepawn_thread_posix_h_
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// This file is part of SourcePawn.
|
||||
//
|
||||
// SourcePawn is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// SourcePawn is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with SourcePawn. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef _include_sourcepawn_threads_
|
||||
#define _include_sourcepawn_threads_
|
||||
|
||||
#include <assert.h>
|
||||
#if defined(_MSC_VER)
|
||||
# include <windows.h>
|
||||
# include <WinBase.h>
|
||||
#else
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
#include <ke_utility.h>
|
||||
|
||||
// Thread primitives for SourcePawn.
|
||||
//
|
||||
// -- Mutexes --
|
||||
//
|
||||
// A Lockable is a mutual exclusion primitive. It can be owned by at most one
|
||||
// thread at a time, and ownership blocks any other thread from taking taking
|
||||
// ownership. Ownership must be acquired and released on the same thread.
|
||||
// Lockables are not re-entrant.
|
||||
//
|
||||
// While a few classes support the Lockable interface, the simplest Lockable
|
||||
// object that can be instantiated is a Mutex.
|
||||
//
|
||||
// -- Condition Variables --
|
||||
//
|
||||
// A ConditionVariable provides mutually exclusive access based on a
|
||||
// condition ocurring. CVs provide two capabilities: Wait(), which will block
|
||||
// until the condition is triggered, and Notify(), which signals any blocking
|
||||
// thread that the condition has occurred.
|
||||
//
|
||||
// Condition variables have an underlying mutex lock. This lock must be
|
||||
// acquired before calling Wait() or Notify(). It is automatically released
|
||||
// once Wait begins blocking. This operation is atomic with respect to other
|
||||
// threads and the mutex. For example, it is not possible for the lock to be
|
||||
// acquired by another thread in between unlocking and blocking. Since Notify
|
||||
// also requires the lock to be acquired, there is no risk of an event
|
||||
// accidentally dissipating into thin air because it was sent before the other
|
||||
// thread began blocking.
|
||||
//
|
||||
// When Wait() returns, the lock is automatically re-acquired. This operation
|
||||
// is NOT atomic. In between waking up and re-acquiring the lock, another
|
||||
// thread may steal the lock and issue another event. Applications must
|
||||
// account for this. For example, a message pump should check that there are
|
||||
// no messages left to process before blocking again.
|
||||
//
|
||||
// Likewise, it is also not defined whether a Signal() will have any effect
|
||||
// while a thread is not waiting on the monitor. This is yet another reason
|
||||
// the above paragraph is so important - applications should, under a lock of
|
||||
// the condition variable - check for state changes before waiting.
|
||||
//
|
||||
// -- Threads --
|
||||
//
|
||||
// A Thread object, when created, spawns a new thread with the given callback
|
||||
// (the callbacks must implement IRunnable). Threads have one method of
|
||||
// interest, Join(), which will block until the thread's execution finishes.
|
||||
// Deleting a thread object will free any operating system resources associated
|
||||
// with that thread, if the thread has finished executing.
|
||||
//
|
||||
// Threads can fail to spawn; make sure to check Succeeded().
|
||||
//
|
||||
|
||||
namespace ke {
|
||||
|
||||
// Abstraction for getting a unique thread identifier. Debug-only.
|
||||
#if defined(_MSC_VER)
|
||||
typedef DWORD ThreadId;
|
||||
|
||||
static inline ThreadId GetCurrentThreadId()
|
||||
{
|
||||
return ::GetCurrentThreadId();
|
||||
}
|
||||
#else
|
||||
typedef pthread_t ThreadId;
|
||||
|
||||
static inline ThreadId GetCurrentThreadId()
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Classes which use non-reentrant, same-thread lock/unlock semantics should
|
||||
// inherit from this and implement DoLock/DoUnlock.
|
||||
class Lockable
|
||||
{
|
||||
public:
|
||||
Lockable()
|
||||
{
|
||||
#if !defined(NDEBUG)
|
||||
owner_ = 0;
|
||||
#endif
|
||||
}
|
||||
virtual ~Lockable() {
|
||||
}
|
||||
|
||||
bool TryLock() {
|
||||
if (DoTryLock()) {
|
||||
DebugSetLocked();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Lock() {
|
||||
assert(Owner() != GetCurrentThreadId());
|
||||
DoLock();
|
||||
DebugSetLocked();
|
||||
}
|
||||
|
||||
void Unlock() {
|
||||
assert(Owner() == GetCurrentThreadId());
|
||||
DebugSetUnlocked();
|
||||
DoUnlock();
|
||||
}
|
||||
|
||||
void AssertCurrentThreadOwns() const {
|
||||
assert(Owner() == GetCurrentThreadId());
|
||||
}
|
||||
#if !defined(NDEBUG)
|
||||
bool Locked() const {
|
||||
return owner_ != 0;
|
||||
}
|
||||
ThreadId Owner() const {
|
||||
return owner_;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool DoTryLock() = 0;
|
||||
virtual void DoLock() = 0;
|
||||
virtual void DoUnlock() = 0;
|
||||
|
||||
protected:
|
||||
void DebugSetUnlocked() {
|
||||
#if !defined(NDEBUG)
|
||||
owner_ = 0;
|
||||
#endif
|
||||
}
|
||||
void DebugSetLocked() {
|
||||
#if !defined(NDEBUG)
|
||||
owner_ = GetCurrentThreadId();
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
#if !defined(NDEBUG)
|
||||
ThreadId owner_;
|
||||
#endif
|
||||
};
|
||||
|
||||
// RAII for automatically locking and unlocking an object.
|
||||
class AutoLock
|
||||
{
|
||||
public:
|
||||
AutoLock(Lockable *lock)
|
||||
: lock_(lock)
|
||||
{
|
||||
lock_->Lock();
|
||||
}
|
||||
~AutoLock() {
|
||||
lock_->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
Lockable *lock_;
|
||||
};
|
||||
|
||||
class AutoTryLock
|
||||
{
|
||||
public:
|
||||
AutoTryLock(Lockable *lock)
|
||||
{
|
||||
lock_ = lock->TryLock() ? lock : NULL;
|
||||
}
|
||||
~AutoTryLock() {
|
||||
if (lock_)
|
||||
lock_->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
Lockable *lock_;
|
||||
};
|
||||
|
||||
// RAII for automatically unlocking and relocking an object.
|
||||
class AutoUnlock
|
||||
{
|
||||
public:
|
||||
AutoUnlock(Lockable *lock)
|
||||
: lock_(lock)
|
||||
{
|
||||
lock_->Unlock();
|
||||
}
|
||||
~AutoUnlock() {
|
||||
lock_->Lock();
|
||||
}
|
||||
|
||||
private:
|
||||
Lockable *lock_;
|
||||
};
|
||||
|
||||
enum WaitResult {
|
||||
// Woke up because something happened.
|
||||
Wait_Signaled,
|
||||
|
||||
// Woke up because nothing happened and a timeout was specified.
|
||||
Wait_Timeout,
|
||||
|
||||
// Woke up, but because of an error.
|
||||
Wait_Error
|
||||
};
|
||||
|
||||
// This must be implemented in order to spawn a new thread.
|
||||
class IRunnable
|
||||
{
|
||||
public:
|
||||
virtual ~IRunnable() {
|
||||
}
|
||||
|
||||
virtual void Run() = 0;
|
||||
};
|
||||
|
||||
} // namespace ke
|
||||
|
||||
// Include the actual thread implementations.
|
||||
#if defined(_MSC_VER)
|
||||
# include "ke_thread_windows.h"
|
||||
#else
|
||||
# include "ke_thread_posix.h"
|
||||
#endif
|
||||
|
||||
#endif // _include_sourcepawn_threads_
|
||||
@@ -0,0 +1,148 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
//
|
||||
// This file is part of SourcePawn.
|
||||
//
|
||||
// SourcePawn is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// SourcePawn is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with SourcePawn. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef _include_sourcepawn_thread_windows_h_
|
||||
#define _include_sourcepawn_thread_windows_h_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
class CriticalSection : public Lockable
|
||||
{
|
||||
public:
|
||||
CriticalSection() {
|
||||
InitializeCriticalSection(&cs_);
|
||||
}
|
||||
~CriticalSection() {
|
||||
DeleteCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
return !!TryEnterCriticalSection(&cs_);
|
||||
}
|
||||
void DoLock() {
|
||||
EnterCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
void DoUnlock() {
|
||||
LeaveCriticalSection(&cs_);
|
||||
}
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION cs_;
|
||||
};
|
||||
|
||||
typedef CriticalSection Mutex;
|
||||
|
||||
// Currently, this class only supports single-listener CVs.
|
||||
class ConditionVariable : public Lockable
|
||||
{
|
||||
public:
|
||||
ConditionVariable() {
|
||||
event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
}
|
||||
~ConditionVariable() {
|
||||
CloseHandle(event_);
|
||||
}
|
||||
|
||||
bool DoTryLock() {
|
||||
return cs_.DoTryLock();
|
||||
}
|
||||
void DoLock() {
|
||||
cs_.DoLock();
|
||||
}
|
||||
void DoUnlock() {
|
||||
cs_.DoUnlock();
|
||||
}
|
||||
|
||||
void Notify() {
|
||||
AssertCurrentThreadOwns();
|
||||
SetEvent(event_);
|
||||
}
|
||||
|
||||
WaitResult Wait(size_t timeout_ms) {
|
||||
// This will assert if the lock has not been acquired. We don't need to be
|
||||
// atomic here, like pthread_cond_wait, because the event bit will stick
|
||||
// until reset by a wait function.
|
||||
Unlock();
|
||||
DWORD rv = WaitForSingleObject(event_, timeout_ms);
|
||||
Lock();
|
||||
|
||||
if (rv == WAIT_TIMEOUT)
|
||||
return Wait_Timeout;
|
||||
if (rv == WAIT_FAILED)
|
||||
return Wait_Error;
|
||||
return Wait_Signaled;
|
||||
}
|
||||
|
||||
WaitResult Wait() {
|
||||
return Wait(INFINITE);
|
||||
}
|
||||
|
||||
private:
|
||||
CriticalSection cs_;
|
||||
HANDLE event_;
|
||||
};
|
||||
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
Thread(IRunnable *run, const char *name = NULL) {
|
||||
thread_ = CreateThread(NULL, 0, Main, run, 0, NULL);
|
||||
}
|
||||
~Thread() {
|
||||
if (!thread_)
|
||||
return;
|
||||
CloseHandle(thread_);
|
||||
}
|
||||
|
||||
bool Succeeded() const {
|
||||
return !!thread_;
|
||||
}
|
||||
|
||||
void Join() {
|
||||
if (!Succeeded())
|
||||
return;
|
||||
WaitForSingleObject(thread_, INFINITE);
|
||||
}
|
||||
|
||||
HANDLE handle() const {
|
||||
return thread_;
|
||||
}
|
||||
|
||||
private:
|
||||
static DWORD WINAPI Main(LPVOID arg) {
|
||||
((IRunnable *)arg)->Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma pack(push, 8)
|
||||
struct ThreadNameInfo {
|
||||
DWORD dwType;
|
||||
LPCSTR szName;
|
||||
DWORD dwThreadID;
|
||||
DWORD dwFlags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
private:
|
||||
HANDLE thread_;
|
||||
};
|
||||
|
||||
} // namespace ke
|
||||
|
||||
#endif // _include_sourcepawn_thread_windows_h_
|
||||
@@ -0,0 +1,327 @@
|
||||
/* vim: set ts=4 sw=4 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2012-2013 David Anderson
|
||||
*
|
||||
* This file is part of SourcePawn.
|
||||
*
|
||||
* SourcePawn is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
#ifndef _include_jitcraft_utility_h_
|
||||
#define _include_jitcraft_utility_h_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#define KE_32BIT
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
namespace ke {
|
||||
|
||||
static const size_t kMallocAlignment = sizeof(void *) * 2;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef int32_t int32;
|
||||
typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef uint8 * Address;
|
||||
|
||||
static const size_t kKB = 1024;
|
||||
static const size_t kMB = 1024 * kKB;
|
||||
static const size_t kGB = 1024 * kMB;
|
||||
|
||||
template <typename T> T
|
||||
ReturnAndVoid(T &t)
|
||||
{
|
||||
T saved = t;
|
||||
t = T();
|
||||
return saved;
|
||||
}
|
||||
|
||||
// Wrapper that automatically deletes its contents. The pointer can be taken
|
||||
// to avoid destruction.
|
||||
template <typename T>
|
||||
class AutoPtr
|
||||
{
|
||||
T *t_;
|
||||
|
||||
public:
|
||||
AutoPtr()
|
||||
: t_(NULL)
|
||||
{
|
||||
}
|
||||
explicit AutoPtr(T *t)
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
~AutoPtr() {
|
||||
delete t_;
|
||||
}
|
||||
T *take() {
|
||||
return ReturnAndVoid(t_);
|
||||
}
|
||||
T *operator *() const {
|
||||
return t_;
|
||||
}
|
||||
T *operator ->() const {
|
||||
return t_;
|
||||
}
|
||||
operator T *() const {
|
||||
return t_;
|
||||
}
|
||||
void operator =(T *t) {
|
||||
delete t_;
|
||||
t_ = t;
|
||||
}
|
||||
bool operator !() const {
|
||||
return !t_;
|
||||
}
|
||||
};
|
||||
|
||||
// Bob Jenkin's one-at-a-time hash function[1].
|
||||
//
|
||||
// [1] http://burtleburtle.net/bob/hash/doobs.html
|
||||
class CharacterStreamHasher
|
||||
{
|
||||
uint32 hash;
|
||||
|
||||
public:
|
||||
CharacterStreamHasher()
|
||||
: hash(0)
|
||||
{ }
|
||||
|
||||
void add(char c) {
|
||||
hash += c;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
void add(const char *s, size_t length) {
|
||||
for (size_t i = 0; i < length; i++)
|
||||
add(s[i]);
|
||||
}
|
||||
|
||||
uint32 result() {
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
static inline uint32
|
||||
HashCharSequence(const char *s, size_t length)
|
||||
{
|
||||
CharacterStreamHasher hasher;
|
||||
hasher.add(s, length);
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
// From http://burtleburtle.net/bob/hash/integer.html
|
||||
static inline uint32
|
||||
HashInt32(int32 a)
|
||||
{
|
||||
a = (a ^ 61) ^ (a >> 16);
|
||||
a = a + (a << 3);
|
||||
a = a ^ (a >> 4);
|
||||
a = a * 0x27d4eb2d;
|
||||
a = a ^ (a >> 15);
|
||||
return a;
|
||||
}
|
||||
|
||||
// From http://www.cris.com/~Ttwang/tech/inthash.htm
|
||||
static inline uint32
|
||||
HashInt64(int64 key)
|
||||
{
|
||||
key = (~key) + (key << 18); // key = (key << 18) - key - 1;
|
||||
key = key ^ (uint64(key) >> 31);
|
||||
key = key * 21; // key = (key + (key << 2)) + (key << 4);
|
||||
key = key ^ (uint64(key) >> 11);
|
||||
key = key + (key << 6);
|
||||
key = key ^ (uint64(key) >> 22);
|
||||
return uint32(key);
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
HashPointer(void *p)
|
||||
{
|
||||
#if defined(KE_32BIT)
|
||||
return HashInt32(reinterpret_cast<int32>(p));
|
||||
#elif defined(KE_64BIT)
|
||||
return HashInt64(reinterpret_cast<int64>(p));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
Log2(size_t number)
|
||||
{
|
||||
assert(number != 0);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
unsigned long rval;
|
||||
# ifdef _M_IX86
|
||||
_BitScanReverse(&rval, number);
|
||||
# elif _M_X64
|
||||
_BitScanReverse64(&rval, number);
|
||||
# endif
|
||||
return rval;
|
||||
#else
|
||||
size_t bit;
|
||||
asm("bsr %1, %0\n"
|
||||
: "=r" (bit)
|
||||
: "rm" (number));
|
||||
return bit;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
FindRightmostBit(size_t number)
|
||||
{
|
||||
assert(number != 0);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
unsigned long rval;
|
||||
# ifdef _M_IX86
|
||||
_BitScanForward(&rval, number);
|
||||
# elif _M_X64
|
||||
_BitScanForward64(&rval, number);
|
||||
# endif
|
||||
return rval;
|
||||
#else
|
||||
size_t bit;
|
||||
asm("bsf %1, %0\n"
|
||||
: "=r" (bit)
|
||||
: "rm" (number));
|
||||
return bit;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsPowerOfTwo(size_t value)
|
||||
{
|
||||
if (value == 0)
|
||||
return false;
|
||||
return !(value & (value - 1));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
Align(size_t count, size_t alignment)
|
||||
{
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
return count + (alignment - (count % alignment)) % alignment;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUint32AddSafe(unsigned a, unsigned b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return true;
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return (log2_a < sizeof(unsigned) * 8) &&
|
||||
(log2_b < sizeof(unsigned) * 8);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUintPtrAddSafe(size_t a, size_t b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return true;
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return (log2_a < sizeof(size_t) * 8) &&
|
||||
(log2_b < sizeof(size_t) * 8);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUint32MultiplySafe(unsigned a, unsigned b)
|
||||
{
|
||||
if (a <= 1 || b <= 1)
|
||||
return true;
|
||||
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return log2_a + log2_b <= sizeof(unsigned) * 8;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUintPtrMultiplySafe(size_t a, size_t b)
|
||||
{
|
||||
if (a <= 1 || b <= 1)
|
||||
return true;
|
||||
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return log2_a + log2_b <= sizeof(size_t) * 8;
|
||||
}
|
||||
|
||||
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
|
||||
#define STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
|
||||
|
||||
#define IS_ALIGNED(addr, alignment) (!(uintptr_t(addr) & ((alignment) - 1)))
|
||||
|
||||
template <typename T>
|
||||
static inline bool
|
||||
IsAligned(T addr, size_t alignment)
|
||||
{
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
return !(uintptr_t(addr) & (alignment - 1));
|
||||
}
|
||||
|
||||
static inline Address
|
||||
AlignedBase(Address addr, size_t alignment)
|
||||
{
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
return Address(uintptr_t(addr) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
template <typename T> static inline T
|
||||
Min(const T &t1, const T &t2)
|
||||
{
|
||||
return t1 < t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <typename T> static inline T
|
||||
Max(const T &t1, const T &t2)
|
||||
{
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
#define OFFSETOF(Class, Member) reinterpret_cast<size_t>(&((Class *)NULL)->Member)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define KE_SIZET_FMT "%Iu"
|
||||
#elif defined(__GNUC__)
|
||||
# define KE_SIZET_FMT "%zu"
|
||||
#else
|
||||
# error "Implement format specifier string"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define KE_CRITICAL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#else
|
||||
# define KE_CRITICAL_LIKELY(x) x
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_jitcraft_utility_h_
|
||||
@@ -0,0 +1,166 @@
|
||||
/* vim: set ts=2 sw=2 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2012 David Anderson
|
||||
*
|
||||
* This file is part of SourcePawn.
|
||||
*
|
||||
* SourcePawn is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
#ifndef _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
|
||||
#define _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <ke_allocator_policies.h>
|
||||
#include <ke_utility.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
template <typename T, typename AllocPolicy = SystemAllocatorPolicy>
|
||||
class Vector : public AllocPolicy
|
||||
{
|
||||
public:
|
||||
Vector(AllocPolicy = AllocPolicy())
|
||||
: data(NULL),
|
||||
nitems(0),
|
||||
maxsize(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Vector()
|
||||
{
|
||||
zap();
|
||||
}
|
||||
|
||||
void steal(Vector &other) {
|
||||
zap();
|
||||
data = other.data;
|
||||
nitems = other.nitems;
|
||||
maxsize = other.maxsize;
|
||||
other.reset();
|
||||
}
|
||||
|
||||
bool append(const T& item) {
|
||||
if (!growIfNeeded(1))
|
||||
return false;
|
||||
new (&data[nitems]) T(item);
|
||||
nitems++;
|
||||
return true;
|
||||
}
|
||||
void infallibleAppend(const T &item) {
|
||||
assert(growIfNeeded(1));
|
||||
new (&data[nitems]) T(item);
|
||||
nitems++;
|
||||
}
|
||||
T popCopy() {
|
||||
T t = at(length() - 1);
|
||||
pop();
|
||||
return t;
|
||||
}
|
||||
void pop() {
|
||||
assert(nitems);
|
||||
data[nitems - 1].~T();
|
||||
nitems--;
|
||||
}
|
||||
bool empty() const {
|
||||
return length() == 0;
|
||||
}
|
||||
size_t length() const {
|
||||
return nitems;
|
||||
}
|
||||
T& at(size_t i) {
|
||||
assert(i < length());
|
||||
return data[i];
|
||||
}
|
||||
const T& at(size_t i) const {
|
||||
assert(i < length());
|
||||
return data[i];
|
||||
}
|
||||
T& operator [](size_t i) {
|
||||
return at(i);
|
||||
}
|
||||
const T& operator [](size_t i) const {
|
||||
return at(i);
|
||||
}
|
||||
void clear() {
|
||||
nitems = 0;
|
||||
}
|
||||
const T &back() const {
|
||||
return at(length() - 1);
|
||||
}
|
||||
T &back() {
|
||||
return at(length() - 1);
|
||||
}
|
||||
|
||||
T *buffer() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
bool ensure(size_t desired) {
|
||||
if (desired <= length())
|
||||
return true;
|
||||
|
||||
return growIfNeeded(desired - length());
|
||||
}
|
||||
|
||||
private:
|
||||
void zap() {
|
||||
for (size_t i = 0; i < nitems; i++)
|
||||
data[i].~T();
|
||||
this->free(data);
|
||||
}
|
||||
void reset() {
|
||||
data = NULL;
|
||||
nitems = 0;
|
||||
maxsize = 0;
|
||||
}
|
||||
|
||||
bool growIfNeeded(size_t needed)
|
||||
{
|
||||
if (!IsUintPtrAddSafe(nitems, needed)) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
if (nitems + needed < maxsize)
|
||||
return true;
|
||||
if (maxsize == 0)
|
||||
maxsize = 8;
|
||||
while (nitems + needed > maxsize) {
|
||||
if (!IsUintPtrMultiplySafe(maxsize, 2)) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
maxsize *= 2;
|
||||
}
|
||||
T* newdata = (T*)this->malloc(sizeof(T) * maxsize);
|
||||
if (newdata == NULL)
|
||||
return false;
|
||||
for (size_t i = 0; i < nitems; i++) {
|
||||
new (&newdata[i]) T(data[i]);
|
||||
data[i].~T();
|
||||
}
|
||||
this->free(data);
|
||||
data = newdata;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
T* data;
|
||||
size_t nitems;
|
||||
size_t maxsize;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_ */
|
||||
|
||||
Reference in New Issue
Block a user