diff options
Diffstat (limited to 'src/leveldb/port')
-rw-r--r-- | src/leveldb/port/port.h | 2 | ||||
-rw-r--r-- | src/leveldb/port/port_win.cc | 182 | ||||
-rw-r--r-- | src/leveldb/port/port_win.h | 161 |
3 files changed, 345 insertions, 0 deletions
diff --git a/src/leveldb/port/port.h b/src/leveldb/port/port.h index e667db40d0..4baafa8e22 100644 --- a/src/leveldb/port/port.h +++ b/src/leveldb/port/port.h @@ -14,6 +14,8 @@ # include "port/port_posix.h" #elif defined(LEVELDB_PLATFORM_CHROMIUM) # include "port/port_chromium.h" +#elif defined(LEVELDB_PLATFORM_WINDOWS) +# include "port/port_win.h" #endif #endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc new file mode 100644 index 0000000000..4ca64acbef --- /dev/null +++ b/src/leveldb/port/port_win.cc @@ -0,0 +1,182 @@ +// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "port/port_win.h" + +#include <windows.h> +#include <cassert> + +namespace leveldb { +namespace port { + +Mutex::Mutex() : + mutex_(::CreateMutex(NULL, FALSE, NULL)) { + assert(mutex_); +} + +Mutex::~Mutex() { + assert(mutex_); + ::CloseHandle(mutex_); +} + +void Mutex::Lock() { + assert(mutex_); + ::WaitForSingleObject(mutex_, INFINITE); +} + +void Mutex::Unlock() { + assert(mutex_); + ::ReleaseMutex(mutex_); +} + +void Mutex::AssertHeld() { + assert(mutex_); + assert(1); +} + +CondVar::CondVar(Mutex* mu) : + waiting_(0), + mu_(mu), + sema_(::CreateSemaphore(NULL, 0, 0x7fffffff, NULL)), + event_(::CreateEvent(NULL, FALSE, FALSE, NULL)), + broadcasted_(false){ + assert(mu_); +} + +CondVar::~CondVar() { + ::CloseHandle(sema_); + ::CloseHandle(event_); +} + +void CondVar::Wait() { + wait_mtx_.Lock(); + ++waiting_; + assert(waiting_ > 0); + wait_mtx_.Unlock(); + + ::SignalObjectAndWait(mu_->mutex_, sema_, INFINITE, FALSE); + + wait_mtx_.Lock(); + bool last = broadcasted_ && (--waiting_ == 0); + assert(waiting_ >= 0); + wait_mtx_.Unlock(); + + // we leave this function with the mutex held + if (last) + { + ::SignalObjectAndWait(event_, mu_->mutex_, INFINITE, FALSE); + } + else + { + ::WaitForSingleObject(mu_->mutex_, INFINITE); + } +} + +void CondVar::Signal() { + wait_mtx_.Lock(); + bool waiters = waiting_ > 0; + wait_mtx_.Unlock(); + + if (waiters) + { + ::ReleaseSemaphore(sema_, 1, 0); + } +} + +void CondVar::SignalAll() { + wait_mtx_.Lock(); + + broadcasted_ = (waiting_ > 0); + + if (broadcasted_) + { + // release all + ::ReleaseSemaphore(sema_, waiting_, 0); + wait_mtx_.Unlock(); + ::WaitForSingleObject(event_, INFINITE); + broadcasted_ = false; + } + else + { + wait_mtx_.Unlock(); + } +} + +AtomicPointer::AtomicPointer(void* v) { + Release_Store(v); +} + +void* AtomicPointer::Acquire_Load() const { + void * p = nullptr; + InterlockedExchangePointer(&p, rep_); + return p; +} + +void AtomicPointer::Release_Store(void* v) { + InterlockedExchangePointer(&rep_, v); +} + +void* AtomicPointer::NoBarrier_Load() const { + return rep_; +} + +void AtomicPointer::NoBarrier_Store(void* v) { + rep_ = v; +} + +enum InitializationState +{ + Uninitialized = 0, + Running = 1, + Initialized = 2 +}; + +void InitOnce(OnceType* once, void (*initializer)()) { + + static_assert(Uninitialized == LEVELDB_ONCE_INIT, "Invalid uninitialized state value"); + + InitializationState state = static_cast<InitializationState>(InterlockedCompareExchange(once, Running, Uninitialized)); + + if (state == Uninitialized) { + initializer(); + *once = Initialized; + } + + if (state == Running) { + while(*once != Initialized) { + Sleep(0); // yield + } + } + + assert(*once == Initialized); +} + +} +} diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h new file mode 100644 index 0000000000..b53d6ef70d --- /dev/null +++ b/src/leveldb/port/port_win.h @@ -0,0 +1,161 @@ +// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ +#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ + +#ifdef _MSC_VER +#define snprintf _snprintf +#define close _close +#define fread_unlocked _fread_nolock +#endif + + +#ifdef SNAPPY +#include <snappy/snappy.h> +#endif + +#include <string> + +#include <stdint.h> + +namespace leveldb { +namespace port { + +// Windows is little endian (for now :p) +static const bool kLittleEndian = true; + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld(); + + private: + friend class CondVar; + // critical sections are more efficient than mutexes + // but they are not recursive and can only be used to synchronize threads within the same process + // additionnaly they cannot be used with SignalObjectAndWait that we use for CondVar + // we use opaque void * to avoid including windows.h in port_win.h + void * mutex_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +// the Win32 API offers a dependable condition variable mechanism, but only starting with +// Windows 2008 and Vista +// no matter what we will implement our own condition variable with a semaphore +// implementation as described in a paper written by Douglas C. Schmidt and Irfan Pyarali +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + Mutex* mu_; + + Mutex wait_mtx_; + long waiting_; + + void * sema_; + void * event_; + + bool broadcasted_; +}; + +// Storage for a lock-free pointer +class AtomicPointer { + private: + void * rep_; + public: + AtomicPointer() : rep_(nullptr) { } + explicit AtomicPointer(void* v); + void* Acquire_Load() const; + + void Release_Store(void* v); + + void* NoBarrier_Load() const; + + void NoBarrier_Store(void* v); +}; + +typedef volatile long OnceType; +#define LEVELDB_ONCE_INIT (0) + +extern void InitOnce(OnceType* once, void (*initializer)()); + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +} +} + +#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ |