diff --git a/system_wrappers/OWNERS b/system_wrappers/OWNERS new file mode 100644 index 000000000..55ce6f820 --- /dev/null +++ b/system_wrappers/OWNERS @@ -0,0 +1,6 @@ +hellner@google.com +pwestin@google.com +perkj@google.com +henrika@google.com +grunell@google.com +mflodman@google.com \ No newline at end of file diff --git a/system_wrappers/interface/aligned_malloc.h b/system_wrappers/interface/aligned_malloc.h new file mode 100644 index 000000000..c229435e6 --- /dev/null +++ b/system_wrappers/interface/aligned_malloc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ + +#include + +namespace webrtc +{ + void* AlignedMalloc( + size_t size, + size_t alignment); + void AlignedFree( + void* memBlock); +} + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ diff --git a/system_wrappers/interface/atomic32_wrapper.h b/system_wrappers/interface/atomic32_wrapper.h new file mode 100644 index 000000000..40862fb49 --- /dev/null +++ b/system_wrappers/interface/atomic32_wrapper.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Atomic system independant 32-bit integer. +// Note: uses full memory barriers. +// Note: assumes 32-bit (or higher) system +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ + +#include "common_types.h" + +namespace webrtc { +class Atomic32Impl; +class Atomic32Wrapper +{ +public: + Atomic32Wrapper(WebRtc_Word32 initialValue = 0); + ~Atomic32Wrapper(); + + // Prefix operator! + WebRtc_Word32 operator++(); + WebRtc_Word32 operator--(); + + Atomic32Wrapper& operator=(const Atomic32Wrapper& rhs); + Atomic32Wrapper& operator=(WebRtc_Word32 rhs); + + WebRtc_Word32 operator+=(WebRtc_Word32 rhs); + WebRtc_Word32 operator-=(WebRtc_Word32 rhs); + + // Sets the value atomically to newValue if the value equals compare value. + // The function returns true if the exchange happened. + bool CompareExchange(WebRtc_Word32 newValue, WebRtc_Word32 compareValue); + WebRtc_Word32 Value() const; +private: + // Disable the + and - operator since it's unclear what these operations + // should do. + Atomic32Wrapper operator+(const Atomic32Wrapper& rhs); + Atomic32Wrapper operator-(const Atomic32Wrapper& rhs); + + WebRtc_Word32& operator++(int); + WebRtc_Word32& operator--(int); + + // Cheshire cat to hide the implementation (faster than + // using virtual functions) + Atomic32Impl& _impl; +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ diff --git a/system_wrappers/interface/condition_variable_wrapper.h b/system_wrappers/interface/condition_variable_wrapper.h new file mode 100644 index 000000000..c040fbf29 --- /dev/null +++ b/system_wrappers/interface/condition_variable_wrapper.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_ + +namespace webrtc { +class CriticalSectionWrapper; + +class ConditionVariableWrapper +{ +public: + // Factory method, constructor disabled. + static ConditionVariableWrapper* CreateConditionVariable(); + + virtual ~ConditionVariableWrapper() {} + + // Calling thread will atomically release critSect and wait until next + // some other thread calls Wake() or WakeAll(). + virtual void SleepCS(CriticalSectionWrapper& critSect) = 0; + + // Same as above but with a timeout. + virtual bool SleepCS(CriticalSectionWrapper& critSect, + unsigned long maxTimeInMS) = 0; + + // Wakes one thread calling SleepCS(). + virtual void Wake() = 0; + + // Wakes all threads calling SleepCS(). + virtual void WakeAll() = 0; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_ diff --git a/system_wrappers/interface/constructor_magic.h b/system_wrappers/interface/constructor_magic.h new file mode 100644 index 000000000..b2aabc574 --- /dev/null +++ b/system_wrappers/interface/constructor_magic.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * WebRtc + * Copy from third_party/libjingle/source/talk/base/constructormagic.h + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONSTRUCTOR_MAGIC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONSTRUCTOR_MAGIC_H_ + +#ifndef DISALLOW_ASSIGN +#define DISALLOW_ASSIGN(TypeName) \ + void operator=(const TypeName&) +#endif + +#ifndef DISALLOW_COPY_AND_ASSIGN +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + DISALLOW_ASSIGN(TypeName) +#endif + +#ifndef DISALLOW_EVIL_CONSTRUCTORS +// Alternative, less-accurate legacy name. +#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ + DISALLOW_COPY_AND_ASSIGN(TypeName) +#endif + +#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_EVIL_CONSTRUCTORS(TypeName) +#endif + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONSTRUCTOR_MAGIC_H_ diff --git a/system_wrappers/interface/cpu_features_wrapper.h b/system_wrappers/interface/cpu_features_wrapper.h new file mode 100644 index 000000000..5d8a828a7 --- /dev/null +++ b/system_wrappers/interface/cpu_features_wrapper.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +// list of features. +typedef enum { + kSSE2, + kSSE3 +} CPUFeature; + +typedef int (*WebRtc_CPUInfo)(CPUFeature feature); +// returns true if the CPU supports the feature. +extern WebRtc_CPUInfo WebRtc_GetCPUInfo; +// No CPU feature is available => straight C path. +extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM; + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ diff --git a/system_wrappers/interface/cpu_wrapper.h b/system_wrappers/interface/cpu_wrapper.h new file mode 100644 index 000000000..b72c20cd5 --- /dev/null +++ b/system_wrappers/interface/cpu_wrapper.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_ + +#include "typedefs.h" + +namespace webrtc { +class CpuWrapper +{ +public: + static WebRtc_UWord32 DetectNumberOfCores(); + + static CpuWrapper* CreateCpu(); + virtual ~CpuWrapper() {} + + // Returns the average CPU usage for all processors. The CPU usage can be + // between and including 0 to 100 (%) + virtual WebRtc_Word32 CpuUsage() = 0; + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* processName, + WebRtc_UWord32 length) = 0; + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 dwProcessID) = 0; + + // The CPU usage per core is returned in cpu_usage. The CPU can be between + // and including 0 to 100 (%) + // Note that the pointer passed as cpu_usage is redirected to a local member + // of the CPU wrapper. + // numCores is the number of cores in the cpu_usage array. + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& cpu_usage) = 0; + + virtual void Reset() = 0; + virtual void Stop() = 0; + +protected: + CpuWrapper() {} + +private: + static WebRtc_UWord32 _numberOfCores; + +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_WRAPPER_H_ diff --git a/system_wrappers/interface/critical_section_wrapper.h b/system_wrappers/interface/critical_section_wrapper.h new file mode 100644 index 000000000..ad31497e7 --- /dev/null +++ b/system_wrappers/interface/critical_section_wrapper.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ + +// If the critical section is heavily contended it may be beneficial to use +// read/write locks instead. + +#include "common_types.h" + +namespace webrtc { +class CriticalSectionWrapper +{ +public: + // Factory method, constructor disabled + static CriticalSectionWrapper* CreateCriticalSection(); + + virtual ~CriticalSectionWrapper() {} + + // Tries to grab lock, beginning of a critical section. Will wait for the + // lock to become available if the grab failed. + virtual void Enter() = 0; + + // Returns a grabbed lock, end of critical section. + virtual void Leave() = 0; +}; + +// RAII extension of the critical section. Prevents Enter/Leave missmatches and +// provides more compact critical section syntax. +class CriticalSectionScoped +{ +public: + CriticalSectionScoped(CriticalSectionWrapper& critsec) + : + _ptrCritSec(&critsec) + { + _ptrCritSec->Enter(); + } + + ~CriticalSectionScoped() + { + if (_ptrCritSec) + { + Leave(); + } + } + +private: + void Leave() + { + _ptrCritSec->Leave(); + _ptrCritSec = 0; + } + + CriticalSectionWrapper* _ptrCritSec; +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ diff --git a/system_wrappers/interface/event_wrapper.h b/system_wrappers/interface/event_wrapper.h new file mode 100644 index 000000000..0c9a90810 --- /dev/null +++ b/system_wrappers/interface/event_wrapper.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_ + +namespace webrtc { +enum EventTypeWrapper +{ + kEventSignaled = 1, + kEventError = 2, + kEventTimeout = 3 +}; + +#define WEBRTC_EVENT_10_SEC 10000 +#define WEBRTC_EVENT_INFINITE 0xffffffff + +class EventWrapper +{ +public: + // Factory method. Constructor disabled. + static EventWrapper* Create(); + virtual ~EventWrapper() {} + + // Releases threads who are calling Wait() and has started waiting. Please + // note that a thread calling Wait() will not start waiting immediately. + // assumptions to the contrary is a very common source of issues in + // multithreaded programming. + // Set is sticky in the sense that it will release at least one thread + // either immediately or some time in the future. + virtual bool Set() = 0; + + // Prevents future Wait() calls from finishing without a new Set() call. + virtual bool Reset() = 0; + + // Puts the calling thread into a wait state. The thread may be released + // by a Set() call depending on if other threads are waiting and if so on + // timing. The thread that was released will call Reset() before leaving + // preventing more threads from being released. If multiple threads + // are waiting for the same Set(), only one (random) thread is guaranteed to + // be released. It is possible that multiple (random) threads are released + // Depending on timing. + virtual EventTypeWrapper Wait(unsigned long maxTime) = 0; + + // Starts a timer that will call a non-sticky version of Set() either once + // or periodically. If the timer is periodic it ensures that there is no + // drift over time relative to the system clock. + virtual bool StartTimer(bool periodic, unsigned long time) = 0; + + virtual bool StopTimer() = 0; + + // Only implemented on Windows + // Returns 1 if a key has been pressed since last call to this function. + // -1 indicates failure + // 0 indicates no key has been pressed since last call + // TODO(hellner) this function does not seem to belong here + static int KeyPressed(); +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_ diff --git a/system_wrappers/interface/file_wrapper.h b/system_wrappers/interface/file_wrapper.h new file mode 100644 index 000000000..8f0cd8c24 --- /dev/null +++ b/system_wrappers/interface/file_wrapper.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ + +#include "common_types.h" +#include "typedefs.h" + +// Implementation of an InStream and OutStream that can read (exclusive) or +// write from/to a file. + +namespace webrtc { +class FileWrapper : public InStream, public OutStream +{ +public: + enum { kMaxFileNameSize = 1024}; + enum { kFileMaxTextMessageSize = 1024}; + + // Factory method. Constructor disabled. + static FileWrapper* Create(); + + // Returns true if a file has been opened. + virtual bool Open() const = 0; + + // Opens a file in read or write mode, decided by the readOnly parameter. + virtual WebRtc_Word32 OpenFile(const WebRtc_Word8* fileNameUTF8, + const bool readOnly, + const bool loop = false, + const bool text = false) = 0; + + virtual WebRtc_Word32 CloseFile() = 0; + + // Limits the file size. + virtual WebRtc_Word32 SetMaxFileSize(WebRtc_Word32 bytes) = 0; + + // Flush any pending writes. + virtual WebRtc_Word32 Flush() = 0; + + // Returns the opened file's name in fileNameUTF8. size is the allocated + // size of fileNameUTF8. The name will be truncated if the size of + // fileNameUTF8 is to small. + virtual WebRtc_Word32 FileName(WebRtc_Word8* fileNameUTF8, + WebRtc_UWord32 size) const = 0; + + // Write text to the opened file. The written text can contain plain text + // and text with type specifiers in the same way as sprintf works. + virtual WebRtc_Word32 WriteText(const WebRtc_Word8* text, ...) = 0; + + // Reads len number of bytes from buf to file. + virtual int Read(void* buf, int len) = 0; + + // Writes len number of bytes to buf from file. Please note that the actual + // writing to file may happen some time later. Call flush to force a write + // to take affect + virtual bool Write(const void *buf,int len) = 0; + + // Rewinds the file to the start. Only available when OpenFile() has been + // called with loop argument set to true. Or readOnly argument has been set + // to false. + virtual int Rewind() = 0; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ diff --git a/system_wrappers/interface/fix_interlocked_exchange_pointer_windows.h b/system_wrappers/interface/fix_interlocked_exchange_pointer_windows.h new file mode 100644 index 000000000..d85c72472 --- /dev/null +++ b/system_wrappers/interface/fix_interlocked_exchange_pointer_windows.h @@ -0,0 +1,35 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file under third_party_mods/chromium directory of +// source tree or at +// http://src.chromium.org/viewvc/chrome/trunk/src/LICENSE + +// Various inline functions and macros to fix compilation of 32 bit target +// on MSVC with /Wp64 flag enabled. + +// The original code can be found here: +// http://src.chromium.org/svn/trunk/src/base/fix_wp64.h + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ + +#include + +// Platform SDK fixes when building with /Wp64 for a 32 bits target. +#if !defined(_WIN64) && defined(_Wp64) + +#ifdef InterlockedExchangePointer +#undef InterlockedExchangePointer +// The problem is that the macro provided for InterlockedExchangePointer() is +// doing a (LONG) C-style cast that triggers invariably the warning C4312 when +// building on 32 bits. +inline void* InterlockedExchangePointer(void* volatile* target, void* value) { + return reinterpret_cast(static_cast(InterlockedExchange( + reinterpret_cast(target), + static_cast(reinterpret_cast(value))))); +} +#endif // #ifdef InterlockedExchangePointer + +#endif // #if !defined(_WIN64) && defined(_Wp64) + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ diff --git a/system_wrappers/interface/list_wrapper.h b/system_wrappers/interface/list_wrapper.h new file mode 100644 index 000000000..bc10ad4a7 --- /dev/null +++ b/system_wrappers/interface/list_wrapper.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LIST_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LIST_WRAPPER_H_ + +#include "constructor_magic.h" + +namespace webrtc { +class CriticalSectionWrapper; + +class ListItem +{ +friend class ListWrapper; + +public: + ListItem(const void* ptr); + ListItem(const unsigned int item); + virtual ~ListItem(); + void* GetItem() const; + unsigned int GetUnsignedItem() const; + +protected: + ListItem* next_; + ListItem* prev_; + +private: + const void* item_ptr_; + const unsigned int item_; + DISALLOW_COPY_AND_ASSIGN(ListItem); +}; + +class ListWrapper +{ +public: + ListWrapper(); + virtual ~ListWrapper(); + + // Returns the number of elements stored in the list. + unsigned int GetSize() const; + + // Puts a pointer to anything last in the list. + int PushBack(const void* ptr); + // Puts a pointer to anything first in the list. + int PushFront(const void* ptr); + + // Puts a copy of the specified integer last in the list. + int PushBack(const unsigned int item_id); + // Puts a copy of the specified integer first in the list. + int PushFront(const unsigned int item_id); + + // Pops the first ListItem from the list + int PopFront(); + + // Pops the last ListItem from the list + int PopBack(); + + // Returns true if the list is empty + bool Empty() const; + + // Returns a pointer to the first ListItem in the list. + ListItem* First() const; + + // Returns a pointer to the last ListItem in the list. + ListItem* Last() const; + + // Returns a pointer to the ListItem stored after item in the list. + ListItem* Next(ListItem* item) const; + + // Returns a pointer to the ListItem stored before item in the list. + ListItem* Previous(ListItem* item) const; + + // Removes item from the list. + int Erase(ListItem* item); + + // Insert list item after existing_previous_item. Please note that new_item + // must be created using new ListItem(). The map will take ownership of + // new_item following a successfull insert. If insert fails new_item will + // not be released by the List + int Insert(ListItem* existing_previous_item, + ListItem* new_item); + + // Insert list item before existing_next_item. Please note that new_item + // must be created using new ListItem(). The map will take ownership of + // new_item following a successfull insert. If insert fails new_item will + // not be released by the List + int InsertBefore(ListItem* existing_next_item, + ListItem* new_item); + +private: + void PushBackImpl(ListItem* item); + void PushFrontImpl(ListItem* item); + + CriticalSectionWrapper* critical_section_; + ListItem* first_; + ListItem* last_; + unsigned int size_; + DISALLOW_COPY_AND_ASSIGN(ListWrapper); +}; +} //namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LIST_WRAPPER_H_ diff --git a/system_wrappers/interface/map_wrapper.h b/system_wrappers/interface/map_wrapper.h new file mode 100644 index 000000000..9297382cd --- /dev/null +++ b/system_wrappers/interface/map_wrapper.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_MAP_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_MAP_WRAPPER_H_ + +#include + +#include "constructor_magic.h" + +namespace webrtc { +class MapItem +{ +friend class MapWrapper; + +public: + MapItem(int id, void* ptr); + virtual ~MapItem(); + void* GetItem(); + int GetId(); + unsigned int GetUnsignedId(); + void SetItem(void* ptr); + +private: + int item_id_; + void* item_pointer_; + DISALLOW_COPY_AND_ASSIGN(MapItem); +}; + +class MapWrapper +{ +public: + MapWrapper(); + ~MapWrapper(); + + // Puts a pointer to anything in the map and associates it with id. Note, id + // needs to be unique for all items in the map. + int Insert(int id, void* ptr); + + // Removes item from map. + int Erase(MapItem* item); + + // Finds item with associated with id and removes it from the map. + int Erase(int id); + + // Returns the number of elements stored in the map. + int Size() const; + + // Returns a pointer to the first MapItem in the map. + MapItem* First() const; + + // Returns a pointer to the last MapItem in the map. + MapItem* Last() const; + + // Returns a pointer to the MapItem stored after item in the map. + MapItem* Next(MapItem* item) const; + + // Returns a pointer to the MapItem stored before item in the map. + MapItem* Previous(MapItem* item) const; + + // Returns a pointer to the MapItem associated with id from the map. + MapItem* Find(int id) const; + +private: + std::map map_; + DISALLOW_COPY_AND_ASSIGN(MapWrapper); +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_MAP_WRAPPER_H_ diff --git a/system_wrappers/interface/rw_lock_wrapper.h b/system_wrappers/interface/rw_lock_wrapper.h new file mode 100644 index 000000000..f0842ac85 --- /dev/null +++ b/system_wrappers/interface/rw_lock_wrapper.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_ + +// Note, Windows pre-Vista version of RW locks are not supported nativly. For +// these OSs regular critical sections have been used to approximate RW lock +// functionality and will therefore have worse performance. + +namespace webrtc { +class RWLockWrapper +{ +public: + static RWLockWrapper* CreateRWLock(); + virtual ~RWLockWrapper(); + + virtual void AcquireLockExclusive() = 0; + virtual void ReleaseLockExclusive() = 0; + + virtual void AcquireLockShared() = 0; + virtual void ReleaseLockShared() = 0; + +protected: + virtual int Init() = 0; +}; + +// RAII extensions of the RW lock. Prevents Acquire/Release missmatches and +// provides more compact locking syntax. +class ReadLockScoped +{ +public: + ReadLockScoped(RWLockWrapper& rwLock) + : + _rwLock(rwLock) + { + _rwLock.AcquireLockShared(); + } + + ~ReadLockScoped() + { + _rwLock.ReleaseLockShared(); + } + +private: + RWLockWrapper& _rwLock; +}; + +class WriteLockScoped +{ +public: + WriteLockScoped(RWLockWrapper& rwLock) + : + _rwLock(rwLock) + { + _rwLock.AcquireLockExclusive(); + } + + ~WriteLockScoped() + { + _rwLock.ReleaseLockExclusive(); + } + +private: + RWLockWrapper& _rwLock; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_ diff --git a/system_wrappers/interface/sort.h b/system_wrappers/interface/sort.h new file mode 100644 index 000000000..fb25ecfc6 --- /dev/null +++ b/system_wrappers/interface/sort.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Generic unstable sorting routines. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_ + +#include "typedefs.h" +#include "common_types.h" + +namespace webrtc +{ + enum Type + { + TYPE_Word8, + TYPE_UWord8, + TYPE_Word16, + TYPE_UWord16, + TYPE_Word32, + TYPE_UWord32, + TYPE_Word64, + TYPE_UWord64, + TYPE_Float32, + TYPE_Float64 + }; + // Sorts intrinsic data types. + // + // data [in/out] A pointer to an array of intrinsic type. + // Upon return it will be sorted in ascending order. + // numOfElements The number of elements in the array. + // dataType Enum corresponding to the type of the array. + // + // returns 0 on success, -1 on failure. + WebRtc_Word32 Sort(void* data, WebRtc_UWord32 numOfElements, Type dataType); + + // Sorts arbitrary data types. This requires an array of intrinsically typed + // key values which will be used to sort the data array. There must be a + // one-to-one correspondence between data elements and key elements, with + // corresponding elements sharing the same position in their respective + // arrays. + // + // data [in/out] A pointer to an array of arbitrary type. + // Upon return it will be sorted in ascending order. + // key [in] A pointer to an array of keys used to sort the + // data array. + // numOfElements The number of elements in the arrays. + // sizeOfElement The size, in bytes, of the data array. + // keyType Enum corresponding to the type of the key array. + // + // returns 0 on success, -1 on failure. + // + WebRtc_Word32 KeySort(void* data, void* key, WebRtc_UWord32 numOfElements, + WebRtc_UWord32 sizeOfElement, Type keyType); +} + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_ diff --git a/system_wrappers/interface/thread_wrapper.h b/system_wrappers/interface/thread_wrapper.h new file mode 100644 index 000000000..eccf3c239 --- /dev/null +++ b/system_wrappers/interface/thread_wrapper.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// System independant wrapper for spawning threads +// Note: the spawned thread will loop over the callback function until stopped. +// Note: The callback function is expected to return every 2 seconds or more +// often. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ + +namespace webrtc { +// Object that will be passed by the spawned thread when it enters the callback +// function. +#define ThreadObj void* + +// Callback function that the spawned thread will enter once spawned +typedef bool(*ThreadRunFunction)(ThreadObj); + +enum ThreadPriority +{ + kLowPriority = 1, + kNormalPriority = 2, + kHighPriority = 3, + kHighestPriority = 4, + kRealtimePriority = 5 +}; + +class ThreadWrapper +{ +public: + enum {kThreadMaxNameLength = 64}; + + virtual ~ThreadWrapper() {}; + + // Factory method. Constructor disabled. + // + // func Pointer to a, by user, specified callback function. + // obj Object associated with the thread. Passed in the callback + // function. + // prio Thread priority. May require root/admin rights. + // threadName NULL terminated thread name, will be visable in the Windows + // debugger. + static ThreadWrapper* CreateThread(ThreadRunFunction func = 0, + ThreadObj obj= 0, + ThreadPriority prio = kNormalPriority, + const char* threadName = 0); + + // Non blocking termination of the spawned thread. Note that it is not safe + // to delete this class until the spawned thread has been reclaimed. + virtual void SetNotAlive() = 0; + + // Spawns the thread. This will start the triggering of the callback + // function. + virtual bool Start(unsigned int& id) = 0; + + // Sets the threads CPU affinity. CPUs are listed 0 - (number of CPUs - 1). + // The numbers in processorNumbers specify which CPUs are allowed to run the + // thread. processorNumbers should not contain any duplicates and elements + // should be lower than (number of CPUs - 1). amountOfProcessors should be + // equal to the number of processors listed in processorNumbers + virtual bool SetAffinity(const int* /*processorNumbers*/, + const unsigned int /*amountOfProcessors*/) + {return false;} + + // Stops the spawned thread and waits for it to be reclaimed with a timeout + // of two seconds. Will return false if the thread was not reclaimed. + // Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds). + // It's ok to call Stop() even if the spawned thread has been reclaimed. + virtual bool Stop() = 0; + + // Stops the spawned thread dead in its tracks. Will likely result in a + // corrupt state. There should be an extremely good reason for even looking + // at this function. Can cause many problems deadlock being one of them. + virtual bool Shutdown() {return false;} +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ diff --git a/system_wrappers/interface/tick_util.h b/system_wrappers/interface/tick_util.h new file mode 100644 index 000000000..4c280677b --- /dev/null +++ b/system_wrappers/interface/tick_util.h @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// System independant wrapper for polling elapsed time in ms and us. +// The implementation works in the tick domain which can be mapped over to the +// time domain. +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_ + +#if _WIN32 +#include +#include +#elif WEBRTC_LINUX +#include +#else +#include +#include +#endif + +#include "typedefs.h" + +namespace webrtc { +class TickInterval; + +class TickTime +{ +public: + // Current time in the tick domain. + static TickTime Now(); + + // Now in the time domain in ms. + static WebRtc_Word64 MillisecondTimestamp(); + + // Now in the time domain in us. + static WebRtc_Word64 MicrosecondTimestamp(); + + WebRtc_Word64 Ticks() const; + + static WebRtc_Word64 MillisecondsToTicks(const WebRtc_Word64 ms); + + static WebRtc_Word64 TicksToMilliseconds(const WebRtc_Word64 ticks); + + // Returns a TickTime that is ticks later than the passed TickTime + friend TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks); + TickTime& operator+=(const WebRtc_Word64& rhs); + + + // Returns a TickInterval that is the difference in ticks beween rhs and lhs + friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs); +private: + WebRtc_Word64 _ticks; +}; + +class TickInterval +{ +public: + TickInterval(); + + WebRtc_Word64 Milliseconds() const; + WebRtc_Word64 Microseconds() const; + + // Returns the sum of two TickIntervals as a TickInterval + friend TickInterval operator+(const TickInterval& lhs, + const TickInterval& rhs); + TickInterval& operator-=(const TickInterval& rhs); + + // Returns a TickInterval corresponding to rhs - lhs + friend TickInterval operator-(const TickInterval& lhs, + const TickInterval& rhs); + TickInterval& operator+=(const TickInterval& rhs); + +private: + TickInterval(WebRtc_Word64 interval); + + friend class TickTime; + friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs); + +private: + WebRtc_Word64 _interval; +}; + +inline TickInterval operator+(const TickInterval& lhs, const TickInterval& rhs) +{ + return TickInterval(lhs._interval + rhs._interval); +} + +inline TickInterval operator-(const TickInterval& lhs, const TickInterval& rhs) +{ + return TickInterval(lhs._interval - rhs._interval); +} + +inline TickInterval operator-(const TickTime& lhs,const TickTime& rhs) +{ + return TickInterval(lhs._ticks - rhs._ticks); +} + +inline TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks) +{ + TickTime time = lhs; + time._ticks += ticks; + return time; +} + +inline TickTime TickTime::Now() +{ + TickTime result; +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + // QueryPerformanceCounter returns the value from the TSC which is + // incremented at the CPU frequency. The algorithm used requires + // the CPU frequency to be constant. Technology like speed stepping + // which has variable CPU frequency will therefore yield unpredictable, + // incorrect time estimations. + LARGE_INTEGER qpcnt; + QueryPerformanceCounter(&qpcnt); + result._ticks = qpcnt.QuadPart; + #else + static volatile LONG lastTimeGetTime = 0; + static volatile WebRtc_Word64 numWrapTimeGetTime = 0; + volatile LONG* lastTimeGetTimePtr = &lastTimeGetTime; + DWORD now = timeGetTime(); + // Atomically update the last gotten time + DWORD old = InterlockedExchange(lastTimeGetTimePtr, now); + if(now < old) + { + // If now is earlier than old, there may have been a race between + // threads. + // 0x0fffffff ~3.1 days, the code will not take that long to execute + // so it must have been a wrap around. + if(old > 0xf0000000 && now < 0x0fffffff) + { + numWrapTimeGetTime++; + } + } + result._ticks = now + (numWrapTimeGetTime<<32); + #endif +#elif defined(WEBRTC_LINUX) + struct timespec ts; + #ifdef WEBRTC_CLOCK_TYPE_REALTIME + clock_gettime(CLOCK_REALTIME, &ts); + #else + clock_gettime(CLOCK_MONOTONIC, &ts); + #endif + result._ticks = 1000000000LL * static_cast(ts.tv_sec) + static_cast(ts.tv_nsec); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + result._ticks = 1000000LL * static_cast(tv.tv_sec) + static_cast(tv.tv_usec); +#endif + return result; +} + +inline WebRtc_Word64 TickTime::MillisecondTimestamp() +{ + TickTime now = TickTime::Now(); +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (now._ticks * 1000) / qpfreq.QuadPart; + #else + return now._ticks; + #endif +#elif WEBRTC_LINUX + return now._ticks / 1000000LL; +#else + return now._ticks / 1000LL; +#endif +} + +inline WebRtc_Word64 TickTime::MicrosecondTimestamp() +{ + TickTime now = TickTime::Now(); + +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (now._ticks * 1000) / (qpfreq.QuadPart/1000); + #else + return now._ticks *1000LL; + #endif +#elif WEBRTC_LINUX + return now._ticks / 1000LL; +#else + return now._ticks; +#endif +} + +inline WebRtc_Word64 TickTime::Ticks() const +{ + return _ticks; +} + +inline WebRtc_Word64 TickTime::MillisecondsToTicks(const WebRtc_Word64 ms) +{ +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (qpfreq.QuadPart * ms) / 1000; + #else + return ms; + #endif +#elif WEBRTC_LINUX + return ms * 1000000LL; +#else + return ms * 1000LL; +#endif +} + +inline WebRtc_Word64 TickTime::TicksToMilliseconds(const WebRtc_Word64 ticks) +{ +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (ticks * 1000) / qpfreq.QuadPart; + #else + return ticks; + #endif +#elif WEBRTC_LINUX + return ticks / 1000000LL; +#else + return ticks / 1000LL; +#endif +} + +inline TickTime& TickTime::operator+=(const WebRtc_Word64& ticks) +{ + _ticks += ticks; + return *this; +} + +inline TickInterval::TickInterval() : _interval(0) +{ +} + +inline TickInterval::TickInterval(const WebRtc_Word64 interval) + : _interval(interval) +{ +} + +inline WebRtc_Word64 TickInterval::Milliseconds() const +{ +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (_interval * 1000) / qpfreq.QuadPart; + #else + // _interval is in ms + return _interval; + #endif +#elif WEBRTC_LINUX + // _interval is in ns + return _interval / 1000000; +#else + // _interval is usecs + return _interval / 1000; +#endif +} + +inline WebRtc_Word64 TickInterval::Microseconds() const +{ +#if _WIN32 + #ifdef USE_QUERY_PERFORMANCE_COUNTER + LARGE_INTEGER qpfreq; + QueryPerformanceFrequency(&qpfreq); + return (_interval * 1000000) / qpfreq.QuadPart; + #else + // _interval is in ms + return _interval *1000LL; + #endif +#elif WEBRTC_LINUX + // _interval is in ns + return _interval / 1000; +#else + // _interval is usecs + return _interval; +#endif +} + +inline TickInterval& TickInterval::operator+=(const TickInterval& rhs) +{ + _interval += rhs._interval; + return *this; +} + +inline TickInterval& TickInterval::operator-=(const TickInterval& rhs) +{ + _interval -= rhs._interval; + return *this; +} +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_ diff --git a/system_wrappers/interface/trace.h b/system_wrappers/interface/trace.h new file mode 100644 index 000000000..0f7df4d46 --- /dev/null +++ b/system_wrappers/interface/trace.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// System independant wrapper for logging runtime information to file. +// Note: All log messages will be written to the same trace file. +// Note: If to many messages are written to file there will be a build up of +// messages. Apply filtering to avoid that. +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ + +#include "common_types.h" +#include "typedefs.h" + +#ifdef WEBRTC_NO_TRACE + #define WEBRTC_TRACE +#else + // Ideally we would use __VA_ARGS__ but it's not supported by all compilers + // such as VS2003 (it's supported in VS2005). TODO (hellner) why + // would this be better than current implementation (not convinced)? + #define WEBRTC_TRACE Trace::Add +#endif + +namespace webrtc { +class Trace +{ +public: + + // Increments the reference count to the trace. + static void CreateTrace(); + // Decrements the reference count to the trace. + static void ReturnTrace(); + // Note: any instance that writes to the trace file should increment and + // decrement the reference count on construction and destruction + // respectively + + // Specifies what type of messages should be written to the trace file. The + // filter parameter is a bitmask where each message type is enumerated by + // the TraceLevel enumerator. TODO (hellner) why is the + // TraceLevel enumerator not defined in this file? + static WebRtc_Word32 SetLevelFilter(const WebRtc_UWord32 filter); + + // Returns what type of messages are written to the trace file. + static WebRtc_Word32 LevelFilter(WebRtc_UWord32& filter); + + // Sets the file name. If addFileCounter is false the same file will be + // reused when it fills up. If it's true a new file with incremented name + // will be used. + static WebRtc_Word32 SetTraceFile(const WebRtc_Word8* fileName, + const bool addFileCounter = false); + + // Returns the name of the file that the trace is currently writing to. + static WebRtc_Word32 TraceFile(WebRtc_Word8 fileName[1024]); + + // Registers callback to receive trace messages. TODO (hellner) + // why not use OutStream instead? Why is TraceCallback not defined in this + // file + static WebRtc_Word32 SetTraceCallback(TraceCallback* callback); + + // Adds a trace message for writing to file. The message is put in a queue + // for writing to file whenever possible for performance reasons. I.e. there + // is a crash it is possible that the last, vital logs are not logged yet. + // level is the the type of message to log. If that type of messages is + // filtered it will not be written to file. module is an identifier for what + // part of the code the message is comming. + // id is an identifier that should be unique for that set of classes that + // are associated (e.g. all instances owned by an engine). + // msg and the elipsis are the same as e.g. sprintf. + // TODO (hellner) Why is TraceModule not defined in this file? + static void Add(const TraceLevel level, + const TraceModule module, + const WebRtc_Word32 id, + const char* msg, ...); + +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ diff --git a/system_wrappers/source/aligned_malloc.cc b/system_wrappers/source/aligned_malloc.cc new file mode 100644 index 000000000..62257533e --- /dev/null +++ b/system_wrappers/source/aligned_malloc.cc @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "aligned_malloc.h" + +#include +#include + +#ifdef ANDROID +#include +#endif + +#if WEBRTC_MAC + #include +#else + #include +#endif + +#if _WIN32 + #include +#else + #include +#endif + +#include "typedefs.h" + +// Ok reference on memory alignment: +// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me + +namespace webrtc +{ +// TODO (hellner) better to create just one memory block and +// interpret the first sizeof(AlignedMemory) bytes as +// an AlignedMemory struct. +struct AlignedMemory +{ + void* alignedBuffer; + void* memoryPointer; +}; + +void* AlignedMalloc(size_t size, size_t alignment) +{ + if(alignment == 0) + { + // Don't allow alignment 0 since it's undefined. + return NULL; + } + // Make sure that the alignment is an integer power of two or fail. + if(alignment & (alignment - 1)) + { + return NULL; + } + + AlignedMemory* returnValue = new AlignedMemory(); + if(returnValue == NULL) + { + return NULL; + } + + // The memory is aligned towards the lowest address that so only + // alignment - 1 bytes needs to be allocated. + // A pointer to AlignedMemory must be stored so that it can be retreived for + // deletion, ergo the sizeof(uintptr_t). + returnValue->memoryPointer = malloc(size + sizeof(uintptr_t) + + alignment - 1); + if(returnValue->memoryPointer == NULL) + { + delete returnValue; + return NULL; + } + + // Alligning after the sizeof(header) bytes will leave room for the header + // in the same memory block. + uintptr_t alignStartPos = (uintptr_t)returnValue->memoryPointer; + alignStartPos += sizeof(uintptr_t); + + // The buffer should be aligned with 'alignment' bytes. The - 1 guarantees + // that we align towards the lowest address. + uintptr_t alignedPos = (alignStartPos + alignment - 1) & ~(alignment - 1); + + // alignedPos is the address sought for. + returnValue->alignedBuffer = (void*)alignedPos; + + // Store the address to the AlignedMemory struct in the header so that a + // it's possible to reclaim all memory. + uintptr_t headerPos = alignedPos; + headerPos -= sizeof(uintptr_t); + void* headerPtr = (void*) headerPos; + uintptr_t headerValue = (uintptr_t)returnValue; + memcpy(headerPtr,&headerValue,sizeof(uintptr_t)); + + return returnValue->alignedBuffer; +} + +void AlignedFree(void* memBlock) +{ + if(memBlock == NULL) + { + return; + } + uintptr_t alignedPos = (uintptr_t)memBlock; + uintptr_t headerPos = alignedPos - sizeof(uintptr_t); + + // Read out the address of the AlignedMemory struct from the header. + uintptr_t* headerPtr = (uintptr_t*)headerPos; + AlignedMemory* deleteMemory = (AlignedMemory*) *headerPtr; + + if(deleteMemory->memoryPointer != NULL) + { + free(deleteMemory->memoryPointer); + } + delete deleteMemory; +} +} // namespace webrtc diff --git a/system_wrappers/source/atomic32.cc b/system_wrappers/source/atomic32.cc new file mode 100644 index 000000000..3d6849ef2 --- /dev/null +++ b/system_wrappers/source/atomic32.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "atomic32_wrapper.h" + +#if defined(_WIN32) + #include "atomic32_windows.h" +#elif defined(WEBRTC_LINUX) + #include "atomic32_linux.h" +#elif defined(WEBRTC_MAC) + #include "atomic32_mac.h" +#else + #error unsupported os! +#endif + +namespace webrtc { +Atomic32Wrapper::Atomic32Wrapper(WebRtc_Word32 initialValue) + : _impl(*new Atomic32Impl(initialValue)) +{ +} + +Atomic32Wrapper::~Atomic32Wrapper() +{ + delete &_impl; +} + +WebRtc_Word32 Atomic32Wrapper::operator++() +{ + return ++_impl; +} + +WebRtc_Word32 Atomic32Wrapper::operator--() +{ + return --_impl; +} + +// Read and write to properly aligned variables are atomic operations. +// Ex reference (for Windows): http://msdn.microsoft.com/en-us/library/ms684122(v=VS.85).aspx +// TODO (hellner) operator= and Atomic32Wrapper::Value() can be fully +// implemented here. +Atomic32Wrapper& Atomic32Wrapper::operator=(const Atomic32Wrapper& rhs) +{ + if(this == &rhs) + { + return *this; + } + _impl = rhs._impl; + return *this; +} + +Atomic32Wrapper& Atomic32Wrapper::operator=(WebRtc_Word32 rhs) +{ + _impl = rhs; + return *this; +} + +WebRtc_Word32 Atomic32Wrapper::operator+=(WebRtc_Word32 rhs) +{ + return _impl += rhs; +} + +WebRtc_Word32 Atomic32Wrapper::operator-=(WebRtc_Word32 rhs) +{ + return _impl -= rhs; +} + +bool Atomic32Wrapper::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return _impl.CompareExchange(newValue,compareValue); +} + +WebRtc_Word32 Atomic32Wrapper::Value() const +{ + return _impl.Value(); +} +} // namespace webrtc diff --git a/system_wrappers/source/atomic32_linux.h b/system_wrappers/source/atomic32_linux.h new file mode 100644 index 000000000..f9f5650f2 --- /dev/null +++ b/system_wrappers/source/atomic32_linux.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Atomic system independant 32-bit signed integer. +// Linux implementation. +// Note: Requires gcc 4.1.2 or later. +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ + +#include +#include + +#include "common_types.h" + +namespace webrtc { +class Atomic32Impl +{ +public: + inline Atomic32Impl(WebRtc_Word32 initialValue); + inline ~Atomic32Impl(); + + inline WebRtc_Word32 operator++(); + inline WebRtc_Word32 operator--(); + + inline Atomic32Impl& operator=(const Atomic32Impl& rhs); + inline Atomic32Impl& operator=(WebRtc_Word32 rhs); + inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); + inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); + + inline bool CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue); + + inline WebRtc_Word32 Value() const; +private: + void* _ptrMemory; + // Volatile ensures full memory barriers. + volatile WebRtc_Word32* _value; +}; + +// TODO (hellner) use aligned_malloc instead of doing it manually. +inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) + : _ptrMemory(NULL), + _value(NULL) +{ // Align the memory associated with _value on a 32-bit boundary. This is a + // requirement for the used Linux APIs to be atomic. + // Keep _ptrMemory to be able to reclaim memory. + _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); + _value = (WebRtc_Word32*) (((uintptr_t)_ptrMemory+3)&(~0x3)); + *_value = initialValue; +} + +inline Atomic32Impl::~Atomic32Impl() +{ + if(_ptrMemory != NULL) + { + free(_ptrMemory); + } +} + +inline WebRtc_Word32 Atomic32Impl::operator++() +{ + WebRtc_Word32 returnValue = __sync_fetch_and_add(_value,1); + returnValue++; + return returnValue; +} + +inline WebRtc_Word32 Atomic32Impl::operator--() +{ + WebRtc_Word32 returnValue = __sync_fetch_and_sub(_value,1); + returnValue--; + return returnValue; +} + +inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) +{ + *_value = *rhs._value; + return *this; +} + +inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) +{ + *_value = rhs; + return *this; +} + +inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) +{ + WebRtc_Word32 returnValue = __sync_fetch_and_add(_value,rhs); + returnValue += rhs; + return returnValue; +} + +inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) +{ + WebRtc_Word32 returnValue = __sync_fetch_and_sub(_value,rhs); + returnValue -= rhs; + return returnValue; +} + +inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return __sync_bool_compare_and_swap(_value,compareValue,newValue); +} + +inline WebRtc_Word32 Atomic32Impl::Value() const +{ + return *_value; +} +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ diff --git a/system_wrappers/source/atomic32_mac.h b/system_wrappers/source/atomic32_mac.h new file mode 100644 index 000000000..bf8febcdb --- /dev/null +++ b/system_wrappers/source/atomic32_mac.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Atomic system independant 32-bit signed integer. +// Mac implementation. +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ + +#include +#include + +#include "common_types.h" + +namespace webrtc { +class Atomic32Impl +{ +public: + inline Atomic32Impl(WebRtc_Word32 initialValue); + inline ~Atomic32Impl(); + + inline WebRtc_Word32 operator++(); + inline WebRtc_Word32 operator--(); + + inline Atomic32Impl& operator=(const Atomic32Impl& rhs); + inline Atomic32Impl& operator=(WebRtc_Word32 rhs); + inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); + inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); + + inline bool CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue); + + inline WebRtc_Word32 Value() const; +private: + void* _ptrMemory; + // Volatile ensures full memory barriers. + volatile WebRtc_Word32* _value; +}; + +// TODO (hellner) use aligned_malloc instead of doing it manually. +inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) + : + _ptrMemory(NULL), + _value(NULL) +{ // Align the memory associated with _value on a 32-bit boundary. This is a + // requirement for the used Mac APIs to be atomic. + // Keep _ptrMemory to be able to reclaim memory. + _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); + _value = (WebRtc_Word32*) (((uintptr_t)_ptrMemory+3)&(~0x3)); + *_value = initialValue; +} + +inline Atomic32Impl::~Atomic32Impl() +{ + if(_ptrMemory != NULL) + { + free(_ptrMemory); + } +} + +inline WebRtc_Word32 Atomic32Impl::operator++() +{ + return OSAtomicIncrement32Barrier( + reinterpret_cast(_value)); +} + +inline WebRtc_Word32 Atomic32Impl::operator--() +{ + return OSAtomicDecrement32Barrier( + reinterpret_cast(_value)); +} + +inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) +{ + *_value = *rhs._value; + return *this; +} + +inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) +{ + *_value = rhs; + return *this; +} + +inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) +{ + return OSAtomicAdd32Barrier(rhs, + reinterpret_cast(_value)); +} + +inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) +{ + return OSAtomicAdd32Barrier(-rhs, + reinterpret_cast(_value)); +} + +inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return OSAtomicCompareAndSwap32Barrier( + compareValue, + newValue, + reinterpret_cast(_value)); +} + +inline WebRtc_Word32 Atomic32Impl::Value() const +{ + return *_value; +} +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ diff --git a/system_wrappers/source/atomic32_windows.h b/system_wrappers/source/atomic32_windows.h new file mode 100644 index 000000000..c27e48ea4 --- /dev/null +++ b/system_wrappers/source/atomic32_windows.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Atomic system independant 32-bit signed integer. +// Windows implementation. +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_WINDOWS_H_ + +#include +#include + +#include "common_types.h" + +namespace webrtc { +class Atomic32Impl +{ +public: + inline Atomic32Impl(WebRtc_Word32 initialValue); + inline ~Atomic32Impl(); + + inline WebRtc_Word32 operator++(); + inline WebRtc_Word32 operator--(); + + inline Atomic32Impl& operator=(const Atomic32Impl& rhs); + inline Atomic32Impl& operator=(WebRtc_Word32 rhs); + inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); + inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); + + inline bool CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue); + + inline WebRtc_Word32 Value() const; +private: + void* _ptrMemory; + // Volatile ensures full memory barriers. + volatile LONG* _value; +}; + +// TODO (hellner) use aligned_malloc instead of doing it manually. +inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) + : _ptrMemory(NULL), + _value(NULL) +{ // Align the memory associated with _value on a 32-bit boundary. This is a + // requirement for the used Windows APIs to be atomic. + // Keep _ptrMemory to be able to reclaim memory. + _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); + _value = reinterpret_cast (((uintptr_t)_ptrMemory+3)&(~0x3)); + *_value = initialValue; +} + +inline Atomic32Impl::~Atomic32Impl() +{ + if(_ptrMemory != NULL) + { + free(_ptrMemory); + } +} + +inline WebRtc_Word32 Atomic32Impl::operator++() +{ + return (WebRtc_Word32)InterlockedIncrement(_value); +} + +inline WebRtc_Word32 Atomic32Impl::operator--() +{ + return (WebRtc_Word32)InterlockedDecrement(_value); +} + +inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) +{ + *_value = *rhs._value; + return *this; +} + +inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) +{ + *_value = rhs; + return *this; +} + +inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) +{ + return InterlockedExchangeAdd(_value,rhs); +} + +inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) +{ + return InterlockedExchangeAdd(_value,-rhs); +} + +inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + const LONG oldValue = InterlockedCompareExchange(_value,newValue, + compareValue); + // If the old value and the compare value is the same an exchange happened. + return (oldValue == compareValue); +} + +inline WebRtc_Word32 Atomic32Impl::Value() const +{ + return *_value; +} +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_WINDOWS_H_ diff --git a/system_wrappers/source/condition_variable.cc b/system_wrappers/source/condition_variable.cc new file mode 100644 index 000000000..7ca1b567e --- /dev/null +++ b/system_wrappers/source/condition_variable.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if defined(_WIN32) + #include + #include "condition_variable_wrapper.h" + #include "condition_variable_windows.h" +#elif defined(WEBRTC_LINUX) + #include + #include "condition_variable_wrapper.h" + #include "condition_variable_linux.h" +#elif defined(WEBRTC_MAC) || defined(WEBRTC_MAC_INTEL) + #include + #include "condition_variable_wrapper.h" + #include "condition_variable_linux.h" + #endif + +namespace webrtc { +ConditionVariableWrapper* +ConditionVariableWrapper::CreateConditionVariable() +{ +#if defined(_WIN32) + return new ConditionVariableWindows; +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) || defined(WEBRTC_MAC_INTEL) + return ConditionVariableLinux::Create(); +#else + return NULL; +#endif +} +} // namespace webrtc diff --git a/system_wrappers/source/condition_variable_linux.cc b/system_wrappers/source/condition_variable_linux.cc new file mode 100644 index 000000000..778c2cf71 --- /dev/null +++ b/system_wrappers/source/condition_variable_linux.cc @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "condition_variable_linux.h" + +#if defined(WEBRTC_LINUX) +#include +#else +#include +#endif + +#include + +#include "critical_section_linux.h" + +namespace webrtc { +ConditionVariableWrapper* ConditionVariableLinux::Create() +{ + ConditionVariableLinux* ptr = new ConditionVariableLinux; + if (!ptr) + { + return NULL; + } + + const int error = ptr->Construct(); + if (error) + { + delete ptr; + return NULL; + } + + return ptr; +} + +ConditionVariableLinux::ConditionVariableLinux() +{ +} + +int ConditionVariableLinux::Construct() +{ + int result = 0; +#ifdef WEBRTC_CLOCK_TYPE_REALTIME + result = pthread_cond_init(&_cond, NULL); +#else + pthread_condattr_t condAttr; + result = pthread_condattr_init(&condAttr); + if (result != 0) + { + return -1; + } + result = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC); + if (result != 0) + { + return -1; + } + result = pthread_cond_init(&_cond, &condAttr); + if (result != 0) + { + return -1; + } + result = pthread_condattr_destroy(&condAttr); + if (result != 0) + { + return -1; + } +#endif + return 0; +} + +ConditionVariableLinux::~ConditionVariableLinux() +{ + pthread_cond_destroy(&_cond); +} + +void ConditionVariableLinux::SleepCS(CriticalSectionWrapper& critSect) +{ + CriticalSectionLinux* cs = reinterpret_cast( + &critSect); + pthread_cond_wait(&_cond, &cs->_mutex); +} + + +bool +ConditionVariableLinux::SleepCS( + CriticalSectionWrapper& critSect, + unsigned long maxTimeInMS) +{ + const unsigned long INFINITE = 0xFFFFFFFF; + + const int MILLISECONDS_PER_SECOND = 1000; +#ifndef WEBRTC_LINUX + const int MICROSECONDS_PER_MILLISECOND = 1000; +#endif + const int NANOSECONDS_PER_SECOND = 1000000000; + const int NANOSECONDS_PER_MILLISECOND = 1000000; + + CriticalSectionLinux* cs = reinterpret_cast( + &critSect); + + if (maxTimeInMS != INFINITE) + { + timespec ts; +#ifndef WEBRTC_MAC +#ifdef WEBRTC_CLOCK_TYPE_REALTIME + clock_gettime(CLOCK_REALTIME, &ts); +#else + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif +#else + struct timeval tv; + gettimeofday(&tv, 0); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * MICROSECONDS_PER_MILLISECOND; +#endif + + ts.tv_sec += maxTimeInMS / MILLISECONDS_PER_SECOND; + ts.tv_nsec += (maxTimeInMS - ((maxTimeInMS / MILLISECONDS_PER_SECOND)* + MILLISECONDS_PER_SECOND)) * NANOSECONDS_PER_MILLISECOND; + + if (ts.tv_nsec >= NANOSECONDS_PER_SECOND) + { + ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND; + ts.tv_nsec %= NANOSECONDS_PER_SECOND; + } + const int res = pthread_cond_timedwait(&_cond, &cs->_mutex, &ts); + return (res == ETIMEDOUT) ? false : true; + } + else + { + pthread_cond_wait(&_cond, &cs->_mutex); + return true; + } +} + +void ConditionVariableLinux::Wake() +{ + pthread_cond_signal(&_cond); +} + +void ConditionVariableLinux::WakeAll() +{ + pthread_cond_broadcast(&_cond); +} +} // namespace webrtc diff --git a/system_wrappers/source/condition_variable_linux.h b/system_wrappers/source/condition_variable_linux.h new file mode 100644 index 000000000..0300c5b5a --- /dev/null +++ b/system_wrappers/source/condition_variable_linux.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_LINUX_H_ + +#include "condition_variable_wrapper.h" + +#include + +namespace webrtc { +class ConditionVariableLinux : public ConditionVariableWrapper +{ +public: + static ConditionVariableWrapper* Create(); + ~ConditionVariableLinux(); + + void SleepCS(CriticalSectionWrapper& critSect); + bool SleepCS(CriticalSectionWrapper& critSect, unsigned long maxTimeInMS); + void Wake(); + void WakeAll(); + +private: + ConditionVariableLinux(); + int Construct(); + +private: + pthread_cond_t _cond; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_LINUX_H_ diff --git a/system_wrappers/source/condition_variable_windows.cc b/system_wrappers/source/condition_variable_windows.cc new file mode 100644 index 000000000..1805d21ba --- /dev/null +++ b/system_wrappers/source/condition_variable_windows.cc @@ -0,0 +1,224 @@ +/* + * Use of this source code is governed by the ACE copyright license which + * can be found in the LICENSE file in the third_party_mods/ace directory of + * the source tree or at http://www1.cse.wustl.edu/~schmidt/ACE-copying.html. + */ +/* + * This source code contain modifications to the original source code + * which can be found here: + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2). + * Modifications: + * 1) Dynamic detection of native support for condition variables. + * 2) Use of WebRTC defined types and classes. Renaming of some functions. + * 3) Introduction of a second event for wake all functionality. This prevents + * a thread from spinning on the same condition variable, preventing other + * threads from waking up. + */ + +// TODO (hellner): probably nicer to split up native and generic +// implementation into two different files + +#include "condition_variable_windows.h" + +#include "critical_section_windows.h" +#include "trace.h" + +namespace webrtc { +bool ConditionVariableWindows::_winSupportConditionVariablesPrimitive = false; +static HMODULE library = NULL; + +PInitializeConditionVariable _PInitializeConditionVariable; +PSleepConditionVariableCS _PSleepConditionVariableCS; +PWakeConditionVariable _PWakeConditionVariable; +PWakeAllConditionVariable _PWakeAllConditionVariable; + +typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); + +ConditionVariableWindows::ConditionVariableWindows() + : _eventID(WAKEALL_0) +{ + if (!library) + { + // Use native implementation if supported (i.e Vista+) + library = LoadLibrary(TEXT("Kernel32.dll")); + if (library) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Kernel.dll"); + + _PInitializeConditionVariable = + (PInitializeConditionVariable) GetProcAddress( + library, + "InitializeConditionVariable"); + _PSleepConditionVariableCS = + (PSleepConditionVariableCS)GetProcAddress( + library, + "SleepConditionVariableCS"); + _PWakeConditionVariable = + (PWakeConditionVariable)GetProcAddress( + library, + "WakeConditionVariable"); + _PWakeAllConditionVariable = + (PWakeAllConditionVariable)GetProcAddress( + library, + "WakeAllConditionVariable"); + + if(_PInitializeConditionVariable && + _PSleepConditionVariableCS && + _PWakeConditionVariable && + _PWakeAllConditionVariable) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded native condition variables"); + _winSupportConditionVariablesPrimitive = true; + } + } + } + + if (_winSupportConditionVariablesPrimitive) + { + _PInitializeConditionVariable(&_conditionVariable); + + _events[WAKEALL_0] = NULL; + _events[WAKEALL_1] = NULL; + _events[WAKE] = NULL; + + } else { + memset(&_numWaiters[0],0,sizeof(_numWaiters)); + + InitializeCriticalSection(&_numWaitersCritSect); + + _events[WAKEALL_0] = CreateEvent(NULL, // no security attributes + TRUE, // manual-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + + _events[WAKEALL_1] = CreateEvent(NULL, // no security attributes + TRUE, // manual-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + + _events[WAKE] = CreateEvent(NULL, // no security attributes + FALSE, // auto-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + } +} + +ConditionVariableWindows::~ConditionVariableWindows() +{ + if(!_winSupportConditionVariablesPrimitive) + { + CloseHandle(_events[WAKE]); + CloseHandle(_events[WAKEALL_1]); + CloseHandle(_events[WAKEALL_0]); + + DeleteCriticalSection(&_numWaitersCritSect); + } +} + +void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect) +{ + SleepCS(critSect, INFINITE); +} + +bool ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect, + unsigned long maxTimeInMS) +{ + CriticalSectionWindows* cs = reinterpret_cast( + &critSect); + + if(_winSupportConditionVariablesPrimitive) + { + BOOL retVal = _PSleepConditionVariableCS(&_conditionVariable, + &(cs->crit),maxTimeInMS); + return (retVal == 0) ? false : true; + + }else + { + EnterCriticalSection(&_numWaitersCritSect); + // Get the eventID for the event that will be triggered by next + // WakeAll() call and start waiting for it. + const EventWakeUpType eventID = (WAKEALL_0 == _eventID) ? + WAKEALL_1 : WAKEALL_0; + ++(_numWaiters[eventID]); + LeaveCriticalSection(&_numWaitersCritSect); + + LeaveCriticalSection(&cs->crit); + HANDLE events[2]; + events[0] = _events[WAKE]; + events[1] = _events[eventID]; + const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events. + events, + FALSE, // Wait for either. + maxTimeInMS); + + const bool retVal = (result != WAIT_TIMEOUT); + + EnterCriticalSection(&_numWaitersCritSect); + --(_numWaiters[eventID]); + // Last waiter should only be true for WakeAll(). WakeAll() correspond + // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1) + const bool lastWaiter = (result == WAIT_OBJECT_0 + 1) && + (_numWaiters[eventID] == 0); + LeaveCriticalSection(&_numWaitersCritSect); + + if (lastWaiter) + { + // Reset/unset the WakeAll() event since all threads have been + // released. + ResetEvent(_events[eventID]); + } + + EnterCriticalSection(&cs->crit); + return retVal; + } +} + +void +ConditionVariableWindows::Wake() +{ + if(_winSupportConditionVariablesPrimitive) + { + _PWakeConditionVariable(&_conditionVariable); + }else + { + EnterCriticalSection(&_numWaitersCritSect); + const bool haveWaiters = (_numWaiters[WAKEALL_0] > 0) || + (_numWaiters[WAKEALL_1] > 0); + LeaveCriticalSection(&_numWaitersCritSect); + + if (haveWaiters) + { + SetEvent(_events[WAKE]); + } + } +} + +void +ConditionVariableWindows::WakeAll() +{ + if(_winSupportConditionVariablesPrimitive) + { + _PWakeAllConditionVariable(&_conditionVariable); + }else + { + EnterCriticalSection(&_numWaitersCritSect); + // Update current WakeAll() event + _eventID = (WAKEALL_0 == _eventID) ? WAKEALL_1 : WAKEALL_0; + // Trigger current event + const EventWakeUpType eventID = _eventID; + const bool haveWaiters = _numWaiters[eventID] > 0; + LeaveCriticalSection(&_numWaitersCritSect); + + if (haveWaiters) + { + SetEvent(_events[eventID]); + } + } +} +} // namespace webrtc diff --git a/system_wrappers/source/condition_variable_windows.h b/system_wrappers/source/condition_variable_windows.h new file mode 100644 index 000000000..aab2564dd --- /dev/null +++ b/system_wrappers/source/condition_variable_windows.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ + +#include "condition_variable_wrapper.h" + +#include + +namespace webrtc { +#if !defined CONDITION_VARIABLE_INIT + typedef struct _RTL_CONDITION_VARIABLE + { + void* Ptr; + } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; + + typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; +#endif + +typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); + + +class ConditionVariableWindows : public ConditionVariableWrapper +{ +public: + ConditionVariableWindows(); + ~ConditionVariableWindows(); + + void SleepCS(CriticalSectionWrapper& critSect); + bool SleepCS(CriticalSectionWrapper& critSect, unsigned long maxTimeInMS); + void Wake(); + void WakeAll(); + +private: + enum EventWakeUpType + { + WAKEALL_0 = 0, + WAKEALL_1 = 1, + WAKE = 2, + EVENT_COUNT = 3 + }; + +private: + // Native support for Windows Vista+ + static bool _winSupportConditionVariablesPrimitive; + CONDITION_VARIABLE _conditionVariable; + + unsigned int _numWaiters[2]; + EventWakeUpType _eventID; + CRITICAL_SECTION _numWaitersCritSect; + HANDLE _events[EVENT_COUNT]; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ diff --git a/system_wrappers/source/cpu.cc b/system_wrappers/source/cpu.cc new file mode 100644 index 000000000..228587272 --- /dev/null +++ b/system_wrappers/source/cpu.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "cpu_wrapper.h" + +#if defined(_WIN32) + #include + #include "engine_configurations.h" + #include "cpu_windows.h" +#elif defined(WEBRTC_MAC) + #include + #include + #include "cpu_mac.h" +#elif defined(WEBRTC_MAC_INTEL) + #include "cpu_mac.h" +#elif defined(ANDROID) + // Not implemented yet, might be possible to use Linux implementation +#else // defined(WEBRTC_LINUX) + #include + #include "cpu_linux.h" +#endif + +#include "trace.h" + +namespace webrtc { +WebRtc_UWord32 CpuWrapper::_numberOfCores = 0; + +WebRtc_UWord32 CpuWrapper::DetectNumberOfCores() +{ + if (!_numberOfCores) + { +#if defined(_WIN32) + SYSTEM_INFO si; + GetSystemInfo(&si); + _numberOfCores = static_cast(si.dwNumberOfProcessors); + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Available number of cores:%d", _numberOfCores); + +#elif defined(WEBRTC_LINUX) && !defined(ANDROID) + _numberOfCores = get_nprocs(); + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Available number of cores:%d", _numberOfCores); + +#elif (defined(WEBRTC_MAC) || defined(WEBRTC_MAC_INTEL)) + int name[] = {CTL_HW, HW_AVAILCPU}; + int ncpu; + size_t size = sizeof(ncpu); + if(0 == sysctl(name, 2, &ncpu, &size, NULL, 0)) + { + _numberOfCores = static_cast(ncpu); + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Available number of cores:%d", _numberOfCores); + } else + { + WEBRTC_TRACE(kTraceError, kTraceUtility, -1, + "Failed to get number of cores"); + _numberOfCores = 1; + } +#else + WEBRTC_TRACE(kTraceWarning, kTraceUtility, -1, + "No function to get number of cores"); + _numberOfCores = 1; +#endif + } + return _numberOfCores; +} + +CpuWrapper* CpuWrapper::CreateCpu() +{ +#if defined(_WIN32) + return new CpuWindows(); +#elif (defined(WEBRTC_MAC) || defined(WEBRTC_MAC_INTEL)) + return new CpuWrapperMac(); +#elif defined(ANDROID) + return 0; +#else + return new CpuLinux(); +#endif +} +} // namespace webrtc diff --git a/system_wrappers/source/cpu_features.cc b/system_wrappers/source/cpu_features.cc new file mode 100644 index 000000000..850dc9b03 --- /dev/null +++ b/system_wrappers/source/cpu_features.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "cpu_features_wrapper.h" + +// No CPU feature is available => straight C path. +int GetCPUInfoNoASM(CPUFeature feature) { + (void)feature; + return 0; +} + +// Intrinsic for "cpuid". +#if defined(__pic__) && defined(__i386__) +static inline void cpuid(int cpu_info[4], int info_type) { + __asm__ volatile ( + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type)); +} +#elif defined(__i386__) || defined(__x86_64__) +static inline void cpuid(int cpu_info[4], int info_type) { + __asm__ volatile ( + "cpuid\n" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type)); +} +#endif + +#if defined(__i386__) || defined(__x86_64__) +// Actual feature detection for x86. +static int GetCPUInfo(CPUFeature feature) { + int cpu_info[4]; + cpuid(cpu_info, 1); + if (feature == kSSE2) { + return 0 != (cpu_info[3] & 0x04000000); + } + if (feature == kSSE3) { + return 0 != (cpu_info[2] & 0x00000001); + } + return 0; +} +#else +// Default to straight C for other platforms. +static int GetCPUInfo(CPUFeature feature) { + (void)feature; + return 0; +} +#endif + +WebRtc_CPUInfo WebRtc_GetCPUInfo = GetCPUInfo; +WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM = GetCPUInfoNoASM; diff --git a/system_wrappers/source/cpu_linux.cc b/system_wrappers/source/cpu_linux.cc new file mode 100644 index 000000000..a7ec50654 --- /dev/null +++ b/system_wrappers/source/cpu_linux.cc @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "cpu_linux.h" + +#include +#include +#include +#include + +namespace webrtc { +CpuLinux::CpuLinux() +{ + m_oldBusyTime = 0; + m_oldIdleTime = 0; + m_numCores = 0; + m_numCores = GetNumCores(); + m_oldBusyTimeMulti = new long long[m_numCores]; + m_oldIdleTimeMulti = new long long[m_numCores]; + m_idleArray = new long long[m_numCores]; + m_busyArray = new long long[m_numCores]; + m_resultArray = new WebRtc_UWord32[m_numCores]; + + GetData(m_oldBusyTime, m_oldIdleTime, m_busyArray, m_idleArray); +} + +CpuLinux::~CpuLinux() +{ + delete [] m_oldBusyTimeMulti; + delete [] m_oldIdleTimeMulti; + delete [] m_idleArray; + delete [] m_busyArray; + delete [] m_resultArray; +} + +WebRtc_Word32 CpuLinux::CpuUsage() +{ + WebRtc_UWord32 dummy = 0; + WebRtc_UWord32* dummyArray = NULL; + return CpuUsageMultiCore(dummy, dummyArray); +} + +WebRtc_Word32 CpuLinux::CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& coreArray) +{ + coreArray = m_resultArray; + numCores = m_numCores; + long long busy = 0; + long long idle = 0; + GetData(busy, idle, m_busyArray, m_idleArray); + + long long deltaBusy = busy - m_oldBusyTime; + long long deltaIdle = idle - m_oldIdleTime; + m_oldBusyTime = busy; + m_oldIdleTime = idle; + + int retVal = -1; + if (deltaBusy + deltaIdle == 0) + { + retVal = 0; + } + else + { + retVal = (int)(100 * (deltaBusy) / (deltaBusy + deltaIdle)); + } + + if (coreArray == NULL) + { + return retVal; + } + + for (WebRtc_UWord32 i = 0; i < m_numCores; i++) + { + deltaBusy = m_busyArray[i] - m_oldBusyTimeMulti[i]; + deltaIdle = m_idleArray[i] - m_oldIdleTimeMulti[i]; + m_oldBusyTimeMulti[i] = m_busyArray[i]; + m_oldIdleTimeMulti[i] = m_idleArray[i]; + if(deltaBusy + deltaIdle == 0) + { + coreArray[i] = 0; + } + else + { + coreArray[i] = (int)(100 * (deltaBusy) / (deltaBusy+deltaIdle)); + } + } + return retVal; +} + + +int CpuLinux::GetData(long long& busy, long long& idle, long long*& busyArray, + long long*& idleArray) +{ + FILE* fp = fopen("/proc/stat", "r"); + if (!fp) + { + return -1; + } + + char line[100]; + char* dummy = fgets(line, 100, fp); + char firstWord[100]; + sscanf(line, "%s ", firstWord); + if(strncmp(firstWord, "cpu", 3)!=0) + { + return -1; + } + char sUser[100]; + char sNice[100]; + char sSystem[100]; + char sIdle[100]; + sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem, sIdle); + long long luser = atoll(sUser); + long long lnice = atoll(sNice); + long long lsystem = atoll(sSystem); + long long lidle = atoll (sIdle); + + busy = luser + lnice + lsystem; + idle = lidle; + for (WebRtc_UWord32 i = 0; i < m_numCores; i++) + { + dummy = fgets(line, 100, fp); + sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem, + sIdle); + luser = atoll(sUser); + lnice = atoll(sNice); + lsystem = atoll(sSystem); + lidle = atoll (sIdle); + busyArray[i] = luser + lnice + lsystem; + idleArray[i] = lidle; + } + fclose(fp); + return 0; +} + +int CpuLinux::GetNumCores() +{ + FILE* fp = fopen("/proc/stat", "r"); + if (!fp) + { + return -1; + } + // Skip first line + char line[100]; + char* dummy = fgets(line, 100, fp); + int numCores = -1; + char firstWord[100]; + do + { + numCores++; + if (fgets(line, 100, fp)) + { + sscanf(line, "%s ", firstWord); + } else { + break; + } + } while (strncmp(firstWord, "cpu", 3) == 0); + fclose(fp); + return numCores; +} +} // namespace webrtc diff --git a/system_wrappers/source/cpu_linux.h b/system_wrappers/source/cpu_linux.h new file mode 100644 index 000000000..9b22e836e --- /dev/null +++ b/system_wrappers/source/cpu_linux.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_ + +#include "cpu_wrapper.h" + +namespace webrtc { +class CpuLinux : public CpuWrapper +{ +public: + CpuLinux(); + virtual ~CpuLinux(); + + virtual WebRtc_Word32 CpuUsage(); + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/, + WebRtc_UWord32 /*length*/) {return 0;} + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return 0;} + + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& array); + + virtual void Reset() {return;} + virtual void Stop() {return;} +private: + int GetData(long long& busy, long long& idle, long long*& busyArray, + long long*& idleArray); + int GetNumCores(); + + long long m_oldBusyTime; + long long m_oldIdleTime; + + long long* m_oldBusyTimeMulti; + long long* m_oldIdleTimeMulti; + + long long* m_idleArray; + long long* m_busyArray; + WebRtc_UWord32* m_resultArray; + WebRtc_UWord32 m_numCores; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_ diff --git a/system_wrappers/source/cpu_mac.cc b/system_wrappers/source/cpu_mac.cc new file mode 100644 index 000000000..c2a11e1b6 --- /dev/null +++ b/system_wrappers/source/cpu_mac.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "cpu_mac.h" + +#include +#include +#include + +#include "tick_util.h" + +namespace webrtc { +CpuWrapperMac::CpuWrapperMac() : _cpuUsage(NULL) +{ + natural_t cpuCount; + processor_info_array_t infoArray; + mach_msg_type_number_t infoCount; + + kern_return_t error = host_processor_info(mach_host_self(), + PROCESSOR_CPU_LOAD_INFO, + &cpuCount, + &infoArray, + &infoCount); + if (error) + { + return; + } + + _cpuUsage = new WebRtc_UWord32[cpuCount]; + _lastTickCount = new WebRtc_Word64[cpuCount]; + _lastTime = TickTime::MillisecondTimestamp(); + + processor_cpu_load_info_data_t* cpuLoadInfo = + (processor_cpu_load_info_data_t*) infoArray; + for (unsigned int cpu= 0; cpu < cpuCount; cpu++) + { + WebRtc_Word64 ticks = 0; + for (int state = 0; state < 2; state++) + { + ticks += cpuLoadInfo[cpu].cpu_ticks[state]; + } + _lastTickCount[cpu] = ticks; + } + vm_deallocate(mach_task_self(), (vm_address_t)infoArray, infoCount); +} + +CpuWrapperMac::~CpuWrapperMac() +{ + delete _cpuUsage; + delete _lastTickCount; +} + +WebRtc_Word32 CpuWrapperMac::CpuUsage() +{ + WebRtc_UWord32 numCores; + WebRtc_UWord32* array = NULL; + return CpuUsageMultiCore(numCores, array); +} + +WebRtc_Word32 +CpuWrapperMac::CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& array) +{ + natural_t cpuCount; + processor_info_array_t infoArray; + mach_msg_type_number_t infoCount; + + // sanity check + if(_cpuUsage == NULL) + { + return -1; + } + WebRtc_Word64 now = TickTime::MillisecondTimestamp(); + WebRtc_Word64 timeDiffMS = now - _lastTime; + // TODO(hellner) why block here? Why not just return the old + // value? Is this behavior consistent across all + // platforms? + // Make sure that at least 500 ms pass between calls. + if(timeDiffMS < 500) + { + usleep((500-timeDiffMS)*1000); + return CpuUsageMultiCore(numCores, array); + } + _lastTime = now; + + kern_return_t error = host_processor_info(mach_host_self(), + PROCESSOR_CPU_LOAD_INFO, + &cpuCount, + &infoArray, + &infoCount); + if (error) + { + return -1; + } + + processor_cpu_load_info_data_t* cpuLoadInfo = + (processor_cpu_load_info_data_t*) infoArray; + + WebRtc_Word32 totalCpuUsage = 0; + for (unsigned int cpu = 0; cpu < cpuCount; cpu++) + { + WebRtc_Word64 ticks = 0; + for (int state = 0; state < 2; state++) + { + ticks += cpuLoadInfo[cpu].cpu_ticks[state]; + } + if(timeDiffMS <= 0) + { + _cpuUsage[cpu] = 0; + }else { + _cpuUsage[cpu] = (WebRtc_UWord32)((1000 * + (ticks - _lastTickCount[cpu])) / + timeDiffMS); + } + _lastTickCount[cpu] = ticks; + totalCpuUsage += _cpuUsage[cpu]; + } + + vm_deallocate(mach_task_self(), (vm_address_t)infoArray, infoCount); + + numCores = cpuCount; + array = _cpuUsage; + return totalCpuUsage/cpuCount; +} +} // namespace webrtc diff --git a/system_wrappers/source/cpu_mac.h b/system_wrappers/source/cpu_mac.h new file mode 100644 index 000000000..04cd097be --- /dev/null +++ b/system_wrappers/source/cpu_mac.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_ + +#include "cpu_wrapper.h" + +namespace webrtc { +class CpuWrapperMac : public CpuWrapper +{ +public: + CpuWrapperMac(); + virtual ~CpuWrapperMac(); + + virtual WebRtc_Word32 CpuUsage(); + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/, + WebRtc_UWord32 /*length*/) {return -1;} + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return -1;} + + // Note: this class will block the call and sleep if called too fast + // This function blocks the calling thread if the thread is calling it more + // often than every 500 ms. + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& array); + + virtual void Reset() {} + virtual void Stop() {} + +private: + WebRtc_UWord32* _cpuUsage; + WebRtc_Word64* _lastTickCount; + WebRtc_Word64 _lastTime; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_ diff --git a/system_wrappers/source/cpu_windows.cc b/system_wrappers/source/cpu_windows.cc new file mode 100644 index 000000000..60923acb1 --- /dev/null +++ b/system_wrappers/source/cpu_windows.cc @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "cpu_windows.h" + +#define _WIN32_DCOM + +#include +#include +#include + +#pragma comment(lib, "wbemuuid.lib") + +#include "condition_variable_wrapper.h" +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "thread_wrapper.h" + +namespace webrtc { +WebRtc_Word32 CpuWindows::CpuUsage() +{ + if (!initialized_) + { + return -1; + } + // Last element is the average + return cpu_usage_[number_of_objects_ - 1]; +} + +WebRtc_Word32 CpuWindows::CpuUsageMultiCore(WebRtc_UWord32& num_cores, + WebRtc_UWord32*& cpu_usage) +{ + if (!initialized_) + { + return -1; + } + num_cores = number_of_objects_ - 1; + cpu_usage = cpu_usage_; + return cpu_usage_[number_of_objects_-1]; +} + +CpuWindows::CpuWindows() + : cpu_polling_thread(NULL), + initialize_(true), + initialized_(false), + terminate_(false), + cpu_usage_(NULL), + wbem_enum_access_(NULL), + number_of_objects_(0), + cpu_usage_handle_(0), + previous_processor_timestamp_(NULL), + timestamp_sys_100_ns_handle_(0), + previous_100ns_timestamp_(NULL), + wbem_service_(NULL), + wbem_refresher_(NULL), + wbem_enum_(NULL) +{ + // All resources are allocated in PollingCpu(). + if (AllocateComplexDataTypes()) + { + const bool success = StartPollingCpu(); + assert(success); + } + else + { + assert(false); + } +} + +CpuWindows::~CpuWindows() +{ + // All resources are reclaimed in StopPollingCpu(). + const bool success = StopPollingCpu(); + assert(success); + DeAllocateComplexDataTypes(); +} + +bool CpuWindows::AllocateComplexDataTypes() +{ + cpu_polling_thread = ThreadWrapper::CreateThread( + CpuWindows::Process, + reinterpret_cast(this), + kNormalPriority, + "CpuWindows"); + init_crit_ = CriticalSectionWrapper::CreateCriticalSection(); + init_cond_ = ConditionVariableWrapper::CreateConditionVariable(); + terminate_crit_ = CriticalSectionWrapper::CreateCriticalSection(); + terminate_cond_ = ConditionVariableWrapper::CreateConditionVariable(); + sleep_event = EventWrapper::Create(); + return (cpu_polling_thread != NULL) && (init_crit_ != NULL) && + (init_cond_ != NULL) && (terminate_crit_ != NULL) && + (terminate_cond_ != NULL) && (sleep_event != NULL); +} + +void CpuWindows::DeAllocateComplexDataTypes() +{ + if (sleep_event != NULL) + { + delete sleep_event; + sleep_event = NULL; + } + if (terminate_cond_ != NULL) + { + delete terminate_cond_; + terminate_cond_ = NULL; + } + if (terminate_crit_ != NULL) + { + delete terminate_crit_; + terminate_crit_ = NULL; + } + if (init_cond_ != NULL) + { + delete init_cond_; + init_cond_ = NULL; + } + if (init_crit_ != NULL) + { + delete init_crit_; + init_crit_ = NULL; + } + if (cpu_polling_thread != NULL) + { + delete cpu_polling_thread; + cpu_polling_thread = NULL; + } +} + +bool CpuWindows::StartPollingCpu() +{ + unsigned int dummy_id = 0; + if (!cpu_polling_thread->Start(dummy_id)) + { + return false; + } + { + CriticalSectionScoped cs(*init_crit_); + while(initialize_) + { + init_cond_->SleepCS(*init_crit_); + } + } + if (!initialized_) + { + cpu_polling_thread->Stop(); + return false; + } + return initialized_; +} + +bool CpuWindows::StopPollingCpu() +{ + if (!initialized_) + { + return false; + } + CriticalSectionScoped cs(*terminate_crit_); + terminate_ = true; + sleep_event->Set(); + while (!terminated_) + { + terminate_cond_->SleepCS(*terminate_crit_); + } + cpu_polling_thread->Stop(); + delete cpu_polling_thread; + cpu_polling_thread = NULL; + return true; +} + +bool CpuWindows::Process(void* thread_object) +{ + return reinterpret_cast(thread_object)->ProcessImpl(); +} + +bool CpuWindows::ProcessImpl() +{ + { + CriticalSectionScoped cs(*terminate_crit_); + if (terminate_) + { + const bool success = Terminate(); + assert(success); + terminated_ = true; + terminate_cond_->WakeAll(); + return false; + } + } + // Initialize on first iteration + if (initialize_) + { + CriticalSectionScoped cs(*init_crit_); + initialize_ = false; + const bool success = Initialize(); + init_cond_->WakeAll(); + if (!success || !initialized_) + { + initialized_ = false; + terminate_ = true; + return false; + } + } + // Approximately one seconds sleep for each CPU measurement. Precision is + // not important. 1 second refresh rate is also used by Performance Monitor + // (perfmon). + if(kEventTimeout != sleep_event->Wait(1000)) + { + // Terminating. No need to update CPU usage. + assert(terminate_); + return true; + } + + // UpdateCpuUsage() returns false if a single (or more) CPU read(s) failed. + // Not a major problem if it happens but make sure it doesnt trigger in + // debug. + const bool success = UpdateCpuUsage(); + assert(success); + return true; +} + +bool CpuWindows::CreateWmiConnection() +{ + IWbemLocator* service_locator = NULL; + HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemLocator, + reinterpret_cast (&service_locator)); + if (FAILED(hr)) + { + return false; + } + // To get the WMI service specify the WMI namespace. + BSTR wmi_namespace = SysAllocString(L"\\\\.\\root\\cimv2"); + if (wmi_namespace == NULL) + { + // This type of failure signifies running out of memory. + service_locator->Release(); + return false; + } + hr = service_locator->ConnectServer(wmi_namespace, NULL, NULL, NULL, 0L, + NULL, NULL, &wbem_service_); + SysFreeString(wmi_namespace); + service_locator->Release(); + return !FAILED(hr); +} + +// Sets up WMI refresher and enum +bool CpuWindows::CreatePerfOsRefresher() +{ + // Create refresher. + HRESULT hr = CoCreateInstance(CLSID_WbemRefresher, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemRefresher, + reinterpret_cast (&wbem_refresher_)); + if (FAILED(hr)) + { + return false; + } + // Create PerfOS_Processor enum. + IWbemConfigureRefresher* wbem_refresher_config = NULL; + hr = wbem_refresher_->QueryInterface( + IID_IWbemConfigureRefresher, + reinterpret_cast (&wbem_refresher_config)); + if (FAILED(hr)) + { + return false; + } + // Don't care about the particular id for the enum. + long enum_id = 0; + hr = wbem_refresher_config->AddEnum(wbem_service_, + L"Win32_PerfRawData_PerfOS_Processor", + 0, NULL, &wbem_enum_, &enum_id); + wbem_refresher_config->Release(); + wbem_refresher_config = NULL; + return !FAILED(hr); +} + +// Have to pull the first round of data to be able set the handles. +bool CpuWindows::CreatePerfOsCpuHandles() +{ + // Update the refresher so that there is data available in wbem_enum_. + wbem_refresher_->Refresh(0L); + + // The number of enumerators is the number of processor + 1 (the total). + // This is unknown at this point. + DWORD number_returned = 0; + HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_, + wbem_enum_access_, &number_returned); + // number_returned indicates the number of enumerators that are needed. + if (hr == WBEM_E_BUFFER_TOO_SMALL && + number_returned > number_of_objects_) + { + // Allocate the number IWbemObjectAccess asked for by the + // GetObjects(..) function. + wbem_enum_access_ = new IWbemObjectAccess*[number_returned]; + cpu_usage_ = new WebRtc_UWord32[number_returned]; + previous_processor_timestamp_ = new unsigned __int64[number_returned]; + previous_100ns_timestamp_ = new unsigned __int64[number_returned]; + if ((wbem_enum_access_ == NULL) || (cpu_usage_ == NULL) || + (previous_processor_timestamp_ == NULL) || + (previous_100ns_timestamp_ == NULL)) + { + // Out of memory. + return false; + } + + SecureZeroMemory(wbem_enum_access_, number_returned * + sizeof(IWbemObjectAccess*)); + memset(cpu_usage_, 0, sizeof(int) * number_returned); + memset(previous_processor_timestamp_, 0, sizeof(unsigned __int64) * + number_returned); + memset(previous_100ns_timestamp_, 0, sizeof(unsigned __int64) * + number_returned); + + number_of_objects_ = number_returned; + // Read should be successfull now that memory has been allocated. + hr = wbem_enum_->GetObjects(0L, number_of_objects_, wbem_enum_access_, + &number_returned); + if (FAILED(hr)) + { + return false; + } + } + else + { + // 0 enumerators should not be enough. Something has gone wrong here. + return false; + } + + // Get the enumerator handles that are needed for calculating CPU usage. + CIMTYPE cpu_usage_type; + hr = wbem_enum_access_[0]->GetPropertyHandle(L"PercentProcessorTime", + &cpu_usage_type, + &cpu_usage_handle_); + if (FAILED(hr)) + { + return false; + } + CIMTYPE timestamp_sys_100_ns_type; + hr = wbem_enum_access_[0]->GetPropertyHandle(L"TimeStamp_Sys100NS", + ×tamp_sys_100_ns_type, + ×tamp_sys_100_ns_handle_); + return !FAILED(hr); +} + +bool CpuWindows::Initialize() +{ + if (terminate_) + { + return false; + } + // Initialize COM library. + HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED); + if (FAILED(hr)) + { + return false; + } + hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0); + if (FAILED(hr)) + { + return false; + } + + if (!CreateWmiConnection()) + { + return false; + } + if (!CreatePerfOsRefresher()) + { + return false; + } + if (!CreatePerfOsCpuHandles()) + { + return false; + } + initialized_ = true; + return true; +} + +bool CpuWindows::Terminate() +{ + // Reverse order of Initialize(). + // Some compilers complain about deleting NULL though it's well defined + if (previous_100ns_timestamp_ != NULL) + { + delete[] previous_100ns_timestamp_; + previous_100ns_timestamp_ = NULL; + } + if (previous_processor_timestamp_ != NULL) + { + delete[] previous_processor_timestamp_; + previous_processor_timestamp_ = NULL; + } + if (cpu_usage_ != NULL) + { + delete[] cpu_usage_; + cpu_usage_ = NULL; + } + if (wbem_enum_access_ != NULL) + { + for (DWORD i = 0; i < number_of_objects_; i++) + { + if(wbem_enum_access_[i] != NULL) + { + wbem_enum_access_[i]->Release(); + } + } + delete[] wbem_enum_access_; + wbem_enum_access_ = NULL; + } + if (wbem_enum_ != NULL) + { + wbem_enum_->Release(); + wbem_enum_ = NULL; + } + if (wbem_refresher_ != NULL) + { + wbem_refresher_->Release(); + wbem_refresher_ = NULL; + } + if (wbem_service_ != NULL) + { + wbem_service_->Release(); + wbem_service_ = NULL; + } + // CoUninitialized should be called once for every CoInitializeEx. + // Regardless if it failed or not. + CoUninitialize(); + return false; +} + +bool CpuWindows::UpdateCpuUsage() +{ + wbem_refresher_->Refresh(0L); + DWORD number_returned = 0; + HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_, + wbem_enum_access_,&number_returned); + if (FAILED(hr)) + { + // wbem_enum_access_ has already been allocated. Unless the number of + // CPUs change runtime this should not happen. + return false; + } + unsigned __int64 cpu_usage = 0; + unsigned __int64 timestamp_100ns = 0; + bool returnValue = true; + for (DWORD i = 0; i < number_returned; i++) + { + hr = wbem_enum_access_[i]->ReadQWORD(cpu_usage_handle_,&cpu_usage); + if (FAILED(hr)) + { + returnValue = false; + } + hr = wbem_enum_access_[i]->ReadQWORD(timestamp_sys_100_ns_handle_, + ×tamp_100ns); + if (FAILED(hr)) + { + returnValue = false; + } + wbem_enum_access_[i]->Release(); + wbem_enum_access_[i] = NULL; + + const bool wrapparound = + (previous_processor_timestamp_[i] > cpu_usage) || + (previous_100ns_timestamp_[i] > timestamp_100ns); + const bool first_time = (previous_processor_timestamp_[i] == 0) || + (previous_100ns_timestamp_[i] == 0); + if (wrapparound || first_time) + { + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + continue; + } + const unsigned __int64 processor_timestamp_delta = + cpu_usage - previous_processor_timestamp_[i]; + const unsigned __int64 timestamp_100ns_delta = + timestamp_100ns - previous_100ns_timestamp_[i]; + + if (processor_timestamp_delta >= timestamp_100ns_delta) + { + cpu_usage_[i] = 0; + } else { + // Quotient must be float since the division is guaranteed to yield + // a value between 0 and 1 which is 0 in integer division. + const float delta_quotient = + static_cast(processor_timestamp_delta) / + static_cast(timestamp_100ns_delta); + cpu_usage_[i] = 100 - static_cast(delta_quotient * + 100); + } + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + } + return returnValue; +} +} // namespace webrtc diff --git a/system_wrappers/source/cpu_windows.h b/system_wrappers/source/cpu_windows.h new file mode 100644 index 000000000..c06b4ad68 --- /dev/null +++ b/system_wrappers/source/cpu_windows.h @@ -0,0 +1,102 @@ +// This file contains a Windows implementation of CpuWrapper. +// Note: Windows XP, Windows Server 2003 are the minimum requirements. +// The requirements are due to the implementation being based on +// WMI. +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ + +#include "cpu_wrapper.h" + +#include + +namespace webrtc { +class ConditionVariableWrapper; +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; + +class CpuWindows : public CpuWrapper +{ +public: + virtual WebRtc_Word32 CpuUsage(); + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/, + WebRtc_UWord32 /*length*/) {return -1;} + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return -1;} + + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores, + WebRtc_UWord32*& cpu_usage); + + virtual void Reset() {} + virtual void Stop() {} + + CpuWindows(); + virtual ~CpuWindows(); +private: + bool AllocateComplexDataTypes(); + void DeAllocateComplexDataTypes(); + + bool StartPollingCpu(); + bool StopPollingCpu(); + + static bool Process(void* thread_object); + bool ProcessImpl(); + + bool CreateWmiConnection(); + bool CreatePerfOsRefresher(); + bool CreatePerfOsCpuHandles(); + bool Initialize(); + bool Terminate(); + + bool UpdateCpuUsage(); + + ThreadWrapper* cpu_polling_thread; + + bool initialize_; + bool initialized_; + CriticalSectionWrapper* init_crit_; + ConditionVariableWrapper* init_cond_; + + bool terminate_; + bool terminated_; + CriticalSectionWrapper* terminate_crit_; + ConditionVariableWrapper* terminate_cond_; + + // For sleep with wake-up functionality. + EventWrapper* sleep_event; + + // Will be an array. Just care about CPU 0 for now. + WebRtc_UWord32* cpu_usage_; + + // One IWbemObjectAccess for each processor and one for the total. + // 0-n-1 is the individual processors. + // n is the total. + IWbemObjectAccess** wbem_enum_access_; + DWORD number_of_objects_; + + // Cpu timestamp + long cpu_usage_handle_; + unsigned __int64* previous_processor_timestamp_; + + // Timestamp + long timestamp_sys_100_ns_handle_; + unsigned __int64* previous_100ns_timestamp_; + + IWbemServices* wbem_service_; + + IWbemRefresher* wbem_refresher_; + + IWbemHiPerfEnum* wbem_enum_; + +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ diff --git a/system_wrappers/source/critical_section.cc b/system_wrappers/source/critical_section.cc new file mode 100644 index 000000000..213c35289 --- /dev/null +++ b/system_wrappers/source/critical_section.cc @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#if defined(_WIN32) + #include + #include "critical_section_windows.h" +#else + #include "critical_section_linux.h" +#endif + +namespace webrtc { +CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection() +{ +#ifdef _WIN32 + return new CriticalSectionWindows(); +#else + return new CriticalSectionLinux(); +#endif +} +} // namespace webrtc diff --git a/system_wrappers/source/critical_section_linux.cc b/system_wrappers/source/critical_section_linux.cc new file mode 100644 index 000000000..35e81aeac --- /dev/null +++ b/system_wrappers/source/critical_section_linux.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "critical_section_linux.h" + +namespace webrtc { +CriticalSectionLinux::CriticalSectionLinux() +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_mutex, &attr); +} + +CriticalSectionLinux::~CriticalSectionLinux() +{ + pthread_mutex_destroy(&_mutex); +} + +void +CriticalSectionLinux::Enter() +{ + pthread_mutex_lock(&_mutex); +} + +void +CriticalSectionLinux::Leave() +{ + pthread_mutex_unlock(&_mutex); +} +} // namespace webrtc diff --git a/system_wrappers/source/critical_section_linux.h b/system_wrappers/source/critical_section_linux.h new file mode 100644 index 000000000..5ada1cb47 --- /dev/null +++ b/system_wrappers/source/critical_section_linux.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_LINUX_H_ + +#include "critical_section_wrapper.h" + +#include + +namespace webrtc { +class CriticalSectionLinux : public CriticalSectionWrapper +{ +public: + CriticalSectionLinux(); + + virtual ~CriticalSectionLinux(); + + virtual void Enter(); + virtual void Leave(); + +private: + pthread_mutex_t _mutex; + friend class ConditionVariableLinux; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_LINUX_H_ diff --git a/system_wrappers/source/critical_section_windows.cc b/system_wrappers/source/critical_section_windows.cc new file mode 100644 index 000000000..1ca575175 --- /dev/null +++ b/system_wrappers/source/critical_section_windows.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "critical_section_windows.h" + +namespace webrtc { +CriticalSectionWindows::CriticalSectionWindows() +{ + InitializeCriticalSection(&crit); +} + +CriticalSectionWindows::~CriticalSectionWindows() +{ + DeleteCriticalSection(&crit); +} + +void +CriticalSectionWindows::Enter() +{ + EnterCriticalSection(&crit); +} + +void +CriticalSectionWindows::Leave() +{ + LeaveCriticalSection(&crit); +} +} // namespace webrtc diff --git a/system_wrappers/source/critical_section_windows.h b/system_wrappers/source/critical_section_windows.h new file mode 100644 index 000000000..9556fa955 --- /dev/null +++ b/system_wrappers/source/critical_section_windows.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ + +#include "typedefs.h" +#include "critical_section_wrapper.h" +#include + +namespace webrtc { +class CriticalSectionWindows : public CriticalSectionWrapper +{ +public: + CriticalSectionWindows(); + + virtual ~CriticalSectionWindows(); + + virtual void Enter(); + virtual void Leave(); + +private: + CRITICAL_SECTION crit; + + friend class ConditionVariableWindows; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ diff --git a/system_wrappers/source/event.cc b/system_wrappers/source/event.cc new file mode 100644 index 000000000..384b96142 --- /dev/null +++ b/system_wrappers/source/event.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "event_wrapper.h" + +#if defined(_WIN32) + #include + #include "event_windows.h" +#else + #include + #include "event_linux.h" +#endif + +namespace webrtc { +EventWrapper* EventWrapper::Create() +{ +#if defined(_WIN32) + return new EventWindows(); +#else + return EventLinux::Create(); +#endif +} + +int EventWrapper::KeyPressed() +{ +#if defined(_WIN32) + int keyDown = 0; + for(int key = 0x20; key < 0x90; key++) + { + short res = GetAsyncKeyState(key); + keyDown |= res%2; // Get the LSB + } + if(keyDown) + { + return 1; + } + else + { + return 0; + } +#else + return -1; +#endif +} +} // namespace webrtc diff --git a/system_wrappers/source/event_linux.cc b/system_wrappers/source/event_linux.cc new file mode 100644 index 000000000..dddd31c15 --- /dev/null +++ b/system_wrappers/source/event_linux.cc @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "event_linux.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace webrtc { +const long int E6 = 1000000; +const long int E9 = 1000 * E6; + +EventWrapper* EventLinux::Create() +{ + EventLinux* ptr = new EventLinux; + if (!ptr) + { + return NULL; + } + + const int error = ptr->Construct(); + if (error) + { + delete ptr; + return NULL; + } + return ptr; +} + + +EventLinux::EventLinux() + : _timerThread(0), + _timerEvent(0), + _periodic(false), + _time(0), + _count(0), + _state(kDown) +{ +} + +int EventLinux::Construct() +{ + // Set start time to zero + memset(&_tCreate, 0, sizeof(_tCreate)); + + int result = pthread_mutex_init(&mutex, 0); + if (result != 0) + { + return -1; + } +#ifdef WEBRTC_CLOCK_TYPE_REALTIME + result = pthread_cond_init(&cond, 0); + if (result != 0) + { + return -1; + } +#else + pthread_condattr_t condAttr; + result = pthread_condattr_init(&condAttr); + if (result != 0) + { + return -1; + } + result = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC); + if (result != 0) + { + return -1; + } + result = pthread_cond_init(&cond, &condAttr); + if (result != 0) + { + return -1; + } + result = pthread_condattr_destroy(&condAttr); + if (result != 0) + { + return -1; + } +#endif + return 0; +} + +EventLinux::~EventLinux() +{ + StopTimer(); + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mutex); +} + +bool EventLinux::Reset() +{ + if (0 != pthread_mutex_lock(&mutex)) + { + return false; + } + _state = kDown; + pthread_mutex_unlock(&mutex); + return true; +} + +bool EventLinux::Set() +{ + if (0 != pthread_mutex_lock(&mutex)) + { + return false; + } + _state = kUp; + // Release all waiting threads + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mutex); + return true; +} + +EventTypeWrapper EventLinux::Wait(unsigned long timeout) +{ + int retVal = 0; + if (0 != pthread_mutex_lock(&mutex)) + { + return kEventError; + } + + if (kDown == _state) + { + if (WEBRTC_EVENT_INFINITE != timeout) + { + timespec tEnd; +#ifndef WEBRTC_MAC +#ifdef WEBRTC_CLOCK_TYPE_REALTIME + clock_gettime(CLOCK_REALTIME, &tEnd); +#else + clock_gettime(CLOCK_MONOTONIC, &tEnd); +#endif +#else + timeval tVal; + struct timezone tZone; + tZone.tz_minuteswest = 0; + tZone.tz_dsttime = 0; + gettimeofday(&tVal,&tZone); + TIMEVAL_TO_TIMESPEC(&tVal,&tEnd); +#endif + tEnd.tv_sec += timeout / 1000; + tEnd.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6; + + if (tEnd.tv_nsec >= E9) + { + tEnd.tv_sec++; + tEnd.tv_nsec -= E9; + } + retVal = pthread_cond_timedwait(&cond, &mutex, &tEnd); + } else { + retVal = pthread_cond_wait(&cond, &mutex); + } + } + + _state = kDown; + pthread_mutex_unlock(&mutex); + + switch(retVal) + { + case 0: + return kEventSignaled; + case ETIMEDOUT: + return kEventTimeout; + default: + return kEventError; + } +} + +EventTypeWrapper EventLinux::Wait(timespec& tPulse) +{ + int retVal = 0; + if (0 != pthread_mutex_lock(&mutex)) + { + return kEventError; + } + + if (kUp != _state) + { + retVal = pthread_cond_timedwait(&cond, &mutex, &tPulse); + } + _state = kDown; + + pthread_mutex_unlock(&mutex); + + switch(retVal) + { + case 0: + return kEventSignaled; + case ETIMEDOUT: + return kEventTimeout; + default: + return kEventError; + } +} + +bool EventLinux::StartTimer(bool periodic, unsigned long time) +{ + if (_timerThread) + { + if(_periodic) + { + // Timer already started. + return false; + } else { + // New one shot timer + _time = time; + _tCreate.tv_sec = 0; + _timerEvent->Set(); + return true; + } + } + + // Start the timer thread + _timerEvent = static_cast(EventWrapper::Create()); + const char* threadName = "WebRtc_event_timer_thread"; + _timerThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority, + threadName); + _periodic = periodic; + _time = time; + unsigned int id = 0; + if (_timerThread->Start(id)) + { + return true; + } + return false; +} + +bool EventLinux::Run(ThreadObj obj) +{ + return static_cast(obj)->Process(); +} + +bool EventLinux::Process() +{ + if (_tCreate.tv_sec == 0) + { +#ifndef WEBRTC_MAC +#ifdef WEBRTC_CLOCK_TYPE_REALTIME + clock_gettime(CLOCK_REALTIME, &_tCreate); +#else + clock_gettime(CLOCK_MONOTONIC, &_tCreate); +#endif +#else + timeval tVal; + struct timezone tZone; + tZone.tz_minuteswest = 0; + tZone.tz_dsttime = 0; + gettimeofday(&tVal,&tZone); + TIMEVAL_TO_TIMESPEC(&tVal,&_tCreate); +#endif + _count=0; + } + + timespec tEnd; + unsigned long long time = _time * ++_count; + tEnd.tv_sec = _tCreate.tv_sec + time/1000; + tEnd.tv_nsec = _tCreate.tv_nsec + (time - (time/1000)*1000)*E6; + + if ( tEnd.tv_nsec >= E9 ) + { + tEnd.tv_sec++; + tEnd.tv_nsec -= E9; + } + + switch(_timerEvent->Wait(tEnd)) + { + case kEventSignaled: + return true; + case kEventError: + return false; + case kEventTimeout: + break; + } + if(_periodic || _count==1) + { + Set(); + } + return true; +} + +bool EventLinux::StopTimer() +{ + if(_timerThread) + { + _timerThread->SetNotAlive(); + } + if (_timerEvent) + { + _timerEvent->Set(); + } + if (_timerThread) + { + if(!_timerThread->Stop()) + { + return false; + } + + delete _timerThread; + _timerThread = 0; + } + if (_timerEvent) + { + delete _timerEvent; + _timerEvent = 0; + } + + // Set time to zero to force new reference time for the timer. + memset(&_tCreate, 0, sizeof(_tCreate)); + _count=0; + return true; +} +} // namespace webrtc diff --git a/system_wrappers/source/event_linux.h b/system_wrappers/source/event_linux.h new file mode 100644 index 000000000..17d193f2b --- /dev/null +++ b/system_wrappers/source/event_linux.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_LINUX_H_ + +#include "event_wrapper.h" + +#include +#include + +#include "thread_wrapper.h" + +namespace webrtc { +enum State +{ + kUp = 1, + kDown = 2 +}; + +class EventLinux : public EventWrapper +{ +public: + static EventWrapper* Create(); + + virtual ~EventLinux(); + + virtual EventTypeWrapper Wait(unsigned long maxTime); + virtual bool Set(); + virtual bool Reset(); + + virtual bool StartTimer(bool periodic, unsigned long time); + virtual bool StopTimer(); + +private: + EventLinux(); + int Construct(); + + static bool Run(ThreadObj obj); + bool Process(); + EventTypeWrapper Wait(timespec& tPulse); + + +private: + pthread_cond_t cond; + pthread_mutex_t mutex; + + ThreadWrapper* _timerThread; + EventLinux* _timerEvent; + timespec _tCreate; + + bool _periodic; + unsigned long _time; // In ms + unsigned long _count; + State _state; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_LINUX_H_ diff --git a/system_wrappers/source/event_windows.cc b/system_wrappers/source/event_windows.cc new file mode 100644 index 000000000..a0d559277 --- /dev/null +++ b/system_wrappers/source/event_windows.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "event_windows.h" + +#include "Mmsystem.h" + +namespace webrtc { +EventWindows::EventWindows() + : _event(::CreateEvent(NULL /* security attributes */, + FALSE /* manual reset */, + FALSE /* initial state */, + NULL /* name of event */)), + _timerID(NULL) +{ +} + +EventWindows::~EventWindows() +{ + CloseHandle(_event); +} + +bool EventWindows::Set() +{ + // Note: setting an event that is already set has no effect. + return SetEvent(_event); +} + +bool EventWindows::Reset() +{ + return ResetEvent(_event); +} + +EventTypeWrapper EventWindows::Wait(unsigned long maxTime) +{ + unsigned long res = WaitForSingleObject(_event, maxTime); + switch(res) + { + case WAIT_OBJECT_0: + return kEventSignaled; + case WAIT_TIMEOUT: + return kEventTimeout; + default: + return kEventError; + } +} + +bool EventWindows::StartTimer(bool periodic, unsigned long time) +{ + if (_timerID != NULL) + { + timeKillEvent(_timerID); + _timerID=NULL; + } + if (periodic) + { + _timerID=timeSetEvent(time, 0,(LPTIMECALLBACK)HANDLE(_event),0, + TIME_PERIODIC|TIME_CALLBACK_EVENT_PULSE); + } else { + _timerID=timeSetEvent(time, 0,(LPTIMECALLBACK)HANDLE(_event),0, + TIME_ONESHOT|TIME_CALLBACK_EVENT_SET); + } + + if (_timerID == NULL) + { + return false; + } + return true; +} + +bool EventWindows::StopTimer() +{ + timeKillEvent(_timerID); + _timerID = NULL; + return true; +} +} // namespace webrtc diff --git a/system_wrappers/source/event_windows.h b/system_wrappers/source/event_windows.h new file mode 100644 index 000000000..8ca1360c3 --- /dev/null +++ b/system_wrappers/source/event_windows.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ + +#include + +#include "event_wrapper.h" + +#include "typedefs.h" + +namespace webrtc { +class EventWindows : public EventWrapper +{ +public: + EventWindows(); + virtual ~EventWindows(); + + virtual EventTypeWrapper Wait(unsigned long maxTime); + virtual bool Set(); + virtual bool Reset(); + + virtual bool StartTimer(bool periodic, unsigned long time); + virtual bool StopTimer(); + +private: + HANDLE _event; + WebRtc_UWord32 _timerID; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ diff --git a/system_wrappers/source/file_impl.cc b/system_wrappers/source/file_impl.cc new file mode 100644 index 000000000..6046c2c77 --- /dev/null +++ b/system_wrappers/source/file_impl.cc @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "file_impl.h" + +#include + +#ifdef _WIN32 + #include +#else + #include + #include +#endif + +namespace webrtc { +FileWrapper* FileWrapper::Create() +{ + return new FileWrapperImpl(); +} + +FileWrapperImpl::FileWrapperImpl() + : _id(NULL), + _open(false), + _looping(false), + _readOnly(false), + _text(false), + _maxSizeInBytes(-1), + _sizeInBytes(0) +{ + memset(_fileNameUTF8, 0, kMaxFileNameSize); +} + +FileWrapperImpl::~FileWrapperImpl() +{ + if (_id != NULL) + { + fclose(_id); + } +} + +WebRtc_Word32 FileWrapperImpl::CloseFile() +{ + if (_id != NULL) + { + fclose(_id); + _id = NULL; + } + memset(_fileNameUTF8, 0, kMaxFileNameSize); + _open = false; + return 0; +} + +int FileWrapperImpl::Rewind() +{ + if(_looping || !_readOnly) + { + if (_id != NULL) + { + _sizeInBytes = 0; + return fseek(_id, 0, SEEK_SET); + } + } + return -1; +} + +WebRtc_Word32 FileWrapperImpl::SetMaxFileSize(WebRtc_Word32 bytes) +{ + _maxSizeInBytes = bytes; + return 0; +} + +WebRtc_Word32 FileWrapperImpl::Flush() +{ + if (_id != NULL) + { + return fflush(_id); + } + return -1; +} + +WebRtc_Word32 FileWrapperImpl::FileName(WebRtc_Word8* fileNameUTF8, + WebRtc_UWord32 size) const +{ + WebRtc_Word32 len = static_cast(strlen(_fileNameUTF8)); + if(len > kMaxFileNameSize) + { + assert(false); + return -1; + } + if(len < 1) + { + return -1; + } + // Make sure to NULL terminate + if(size < (WebRtc_UWord32)len) + { + len = size - 1; + } + memcpy(fileNameUTF8, _fileNameUTF8, len); + fileNameUTF8[len] = 0; + return 0; +} + +bool +FileWrapperImpl::Open() const +{ + return _open; +} + +WebRtc_Word32 FileWrapperImpl::OpenFile(const WebRtc_Word8 *fileNameUTF8, + const bool readOnly, const bool loop, + const bool text) +{ + WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); + if (length > kMaxFileNameSize) + { + return -1; + } + + _readOnly = readOnly; + + FILE *tmpId = NULL; +#if defined _WIN32 + wchar_t wideFileName[kMaxFileNameSize]; + wideFileName[0] = 0; + + MultiByteToWideChar(CP_UTF8, + 0 /*UTF8 flag*/, + fileNameUTF8, + -1 /*Null terminated string*/, + wideFileName, + kMaxFileNameSize); + if(text) + { + if(readOnly) + { + tmpId = _wfopen(wideFileName, L"rt"); + } else { + tmpId = _wfopen(wideFileName, L"wt"); + } + } else { + if(readOnly) + { + tmpId = _wfopen(wideFileName, L"rb"); + } else { + tmpId = _wfopen(wideFileName, L"wb"); + } + } +#else + if(text) + { + if(readOnly) + { + tmpId = fopen(fileNameUTF8, "rt"); + } else { + tmpId = fopen(fileNameUTF8, "wt"); + } + } else { + if(readOnly) + { + tmpId = fopen(fileNameUTF8, "rb"); + } else { + tmpId = fopen(fileNameUTF8, "wb"); + } + } +#endif + + if (tmpId != NULL) + { + // + 1 comes fro copying the NULL termination charachter too + memcpy(_fileNameUTF8, fileNameUTF8, length + 1); + if (_id != NULL) + { + fclose(_id); + } + _id = tmpId; + _looping = loop; + _open = true; + return 0; + } + return -1; +} + +int FileWrapperImpl::Read(void *buf, int len) +{ + if(len < 0) + { + return 0; + } + if (_id != NULL) + { + WebRtc_Word32 res = static_cast(fread(buf, 1, len, _id)); + if (res != len) + { + if(!_looping) + { + CloseFile(); + } + } + return res; + } + return -1; +} + +WebRtc_Word32 FileWrapperImpl::WriteText(const WebRtc_Word8* text, ...) +{ + assert(!_readOnly); + assert(!_text); + + if (_id == NULL) + { + return -1; + } + + char tempBuff[kFileMaxTextMessageSize]; + if (text) + { + va_list args; + va_start(args, text); +#ifdef _WIN32 + _vsnprintf(tempBuff, kFileMaxTextMessageSize-1, text, args); +#else + vsnprintf(tempBuff, kFileMaxTextMessageSize-1, text, args); +#endif + va_end(args); + WebRtc_Word32 nBytes; + nBytes = fprintf(_id, "%s", tempBuff); + if (nBytes > 0) + { + return 0; + } + CloseFile(); + } + return -1; +} + +bool FileWrapperImpl::Write(const void* buf, int len) +{ + assert(!_readOnly); + if (_id != NULL) + { + // Check if it's time to stop writing. + if ((_maxSizeInBytes != -1) && + _sizeInBytes + len > (WebRtc_UWord32)_maxSizeInBytes) + { + Flush(); + return false; + } + + size_t nBytes = fwrite((WebRtc_UWord8*)buf, 1, len, _id); + if (nBytes > 0) + { + _sizeInBytes += static_cast(nBytes); + return true; + } + CloseFile(); + } + return false; +} +} // namespace webrtc diff --git a/system_wrappers/source/file_impl.h b/system_wrappers/source/file_impl.h new file mode 100644 index 000000000..cf6b7347f --- /dev/null +++ b/system_wrappers/source/file_impl.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ + +#include "file_wrapper.h" + +#include + +namespace webrtc { +class FileWrapperImpl : public FileWrapper +{ +public: + FileWrapperImpl(); + virtual ~FileWrapperImpl(); + + virtual WebRtc_Word32 FileName(WebRtc_Word8* fileNameUTF8, + WebRtc_UWord32 size) const; + + virtual bool Open() const; + + virtual WebRtc_Word32 OpenFile(const WebRtc_Word8* fileNameUTF8, + const bool readOnly, + const bool loop = false, + const bool text = false); + + virtual WebRtc_Word32 CloseFile(); + virtual WebRtc_Word32 SetMaxFileSize(WebRtc_Word32 bytes); + virtual WebRtc_Word32 Flush(); + + virtual int Read(void* buf, int len); + virtual bool Write(const void *buf, int len); + virtual int Rewind(); + + virtual WebRtc_Word32 WriteText(const WebRtc_Word8* text, ...); + +private: + FILE* _id; + bool _open; + bool _looping; + bool _readOnly; + bool _text; + WebRtc_Word32 _maxSizeInBytes; // -1 indicates file size limitation is off + WebRtc_UWord32 _sizeInBytes; + WebRtc_Word8 _fileNameUTF8[kMaxFileNameSize]; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ diff --git a/system_wrappers/source/list_no_stl.cc b/system_wrappers/source/list_no_stl.cc new file mode 100644 index 000000000..d45f27b31 --- /dev/null +++ b/system_wrappers/source/list_no_stl.cc @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "list_wrapper.h" + +#include "critical_section_wrapper.h" +#include "trace.h" + +namespace webrtc { +ListItem::ListItem(const void* item) + : next_(0), + prev_(0), + item_ptr_(item), + item_(0) +{ +} + +ListItem::ListItem(const unsigned int item) + : next_(0), + prev_(0), + item_ptr_(0), + item_(item) +{ +} + +ListItem::~ListItem() +{ +} + +void* ListItem::GetItem() const +{ + return const_cast(item_ptr_); +} + +unsigned int ListItem::GetUnsignedItem() const +{ + return item_; +} + +ListWrapper::ListWrapper() + : critical_section_(CriticalSectionWrapper::CreateCriticalSection()), + first_(0), + last_(0), + size_(0) +{ +} + +ListWrapper::~ListWrapper() +{ + if (!Empty()) + { + // TODO (hellner) I'm not sure this loggin is useful. + WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1, + "Potential memory leak in ListWrapper"); + // Remove all remaining list items. + while (Erase(First()) == 0) + {} + } + delete critical_section_; +} + +bool ListWrapper::Empty() const +{ + return !first_ && !last_; +} + +unsigned int ListWrapper::GetSize() const +{ + return size_; +} + +int ListWrapper::PushBack(const void* ptr) +{ + ListItem* item = new ListItem(ptr); + CriticalSectionScoped lock(*critical_section_); + PushBackImpl(item); + return 0; +} + +int ListWrapper::PushBack(const unsigned int item_id) +{ + ListItem* item = new ListItem(item_id); + CriticalSectionScoped lock(*critical_section_); + PushBackImpl(item); + return 0; +} + +int ListWrapper::PushFront(const unsigned int item_id) +{ + ListItem* item = new ListItem(item_id); + CriticalSectionScoped lock(*critical_section_); + PushFrontImpl(item); + return 0; +} + +int ListWrapper::PushFront(const void* ptr) +{ + ListItem* item = new ListItem(ptr); + CriticalSectionScoped lock(*critical_section_); + PushFrontImpl(item); + return 0; +} + +int ListWrapper::PopFront() +{ + return Erase(first_); +} + +int ListWrapper::PopBack() +{ + return Erase(last_); +} + +ListItem* ListWrapper::First() const +{ + return first_; +} + +ListItem* ListWrapper::Last() const +{ + return last_; +} + +ListItem* ListWrapper::Next(ListItem* item) const +{ + if(!item) + { + return 0; + } + return item->next_; +} + +ListItem* ListWrapper::Previous(ListItem* item) const +{ + if (!item) + { + return 0; + } + return item->prev_; +} + +int ListWrapper::Insert(ListItem* existing_previous_item, ListItem* new_item) +{ + if (!new_item) + { + return -1; + } + // Allow existing_previous_item to be NULL if the list is empty. + // TODO (hellner) why allow this? Keep it as is for now to avoid + // breaking API contract. + if (!existing_previous_item && !Empty()) + { + return -1; + } + CriticalSectionScoped lock(*critical_section_); + if (!existing_previous_item) + { + PushBackImpl(new_item); + return 0; + } + ListItem* next_item = existing_previous_item->next_; + new_item->next_ = existing_previous_item->next_; + new_item->prev_ = existing_previous_item; + existing_previous_item->next_ = new_item; + if (next_item) + { + next_item->prev_ = new_item; + } + else + { + last_ = new_item; + } + size_++; + return 0; +} + +int ListWrapper::InsertBefore(ListItem* existing_next_item, + ListItem* new_item) +{ + if (!new_item) + { + return -1; + } + // Allow existing_next_item to be NULL if the list is empty. + // Todo: why allow this? Keep it as is for now to avoid breaking API + // contract. + if (!existing_next_item && !Empty()) + { + return -1; + } + CriticalSectionScoped lock(*critical_section_); + if (!existing_next_item) + { + PushBackImpl(new_item); + return 0; + } + + ListItem* previous_item = existing_next_item->prev_; + new_item->next_ = existing_next_item; + new_item->prev_ = previous_item; + existing_next_item->prev_ = new_item; + if (previous_item) + { + previous_item->next_ = new_item; + } + else + { + first_ = new_item; + } + size_++; + return 0; +} + +int ListWrapper::Erase(ListItem* item) +{ + if (!item) + { + return -1; + } + size_--; + ListItem* previous_item = item->prev_; + ListItem* next_item = item->next_; + if (!previous_item) + { + if(next_item) + { + next_item->prev_ = 0; + } + first_ = next_item; + } + else + { + previous_item->next_ = next_item; + } + if (!next_item) + { + if(previous_item) + { + previous_item->next_ = 0; + } + last_ = previous_item; + } + else + { + next_item->prev_ = previous_item; + } + delete item; + return 0; +} + +void ListWrapper::PushBackImpl(ListItem* item) +{ + if (Empty()) + { + first_ = item; + last_ = item; + size_++; + return; + } + + item->prev_ = last_; + last_->next_ = item; + last_ = item; + size_++; +} + +void ListWrapper::PushFrontImpl(ListItem* item) +{ + if (Empty()) + { + first_ = item; + last_ = item; + size_++; + return; + } + + item->next_ = first_; + first_->prev_ = item; + first_ = item; + size_++; +} +} //namespace webrtc diff --git a/system_wrappers/source/list_no_stl.h b/system_wrappers/source/list_no_stl.h new file mode 100644 index 000000000..26d844c78 --- /dev/null +++ b/system_wrappers/source/list_no_stl.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_LIST_NO_STL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_LIST_NO_STL_H_ + +#include "constructor_magic.h" + +namespace webrtc { +class CriticalSectionWrapper; + +class ListNoStlItem +{ +public: + ListNoStlItem(const void* ptr); + ListNoStlItem(const unsigned int item); + virtual ~ListNoStlItem(); + void* GetItem() const; + unsigned int GetUnsignedItem() const; + +protected: + ListNoStlItem* next_; + ListNoStlItem* prev_; + +private: + friend class ListNoStl; + + const void* item_ptr_; + const unsigned int item_; + DISALLOW_COPY_AND_ASSIGN(ListNoStlItem); +}; + + +class ListNoStl +{ +public: + ListNoStl(); + virtual ~ListNoStl(); + + // ListWrapper functions + unsigned int GetSize() const; + int PushBack(const void* ptr); + int PushBack(const unsigned int item_id); + int PushFront(const void* ptr); + int PushFront(const unsigned int item_id); + int PopFront(); + int PopBack(); + bool Empty() const; + ListNoStlItem* First() const; + ListNoStlItem* Last() const; + ListNoStlItem* Next(ListNoStlItem* item) const; + ListNoStlItem* Previous(ListNoStlItem* item) const; + int Erase(ListNoStlItem* item); + int Insert(ListNoStlItem* existing_previous_item, + ListNoStlItem* new_item); + + int InsertBefore(ListNoStlItem* existing_next_item, + ListNoStlItem* new_item); + +private: + void PushBack(ListNoStlItem* item); + void PushFront(ListNoStlItem* item); + + CriticalSectionWrapper* critical_section_; + ListNoStlItem* first_; + ListNoStlItem* last_; + unsigned int size_; + DISALLOW_COPY_AND_ASSIGN(ListNoStl); +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_LIST_NO_STL_H_ diff --git a/system_wrappers/source/list_stl.cc b/system_wrappers/source/list_stl.cc new file mode 100644 index 000000000..dcc63c3d0 --- /dev/null +++ b/system_wrappers/source/list_stl.cc @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "list_wrapper.h" + +#include "trace.h" + +namespace webrtc { +ListItem::ListItem(const void* item) + : this_iter_(), + item_ptr_(item), + item_(0) +{ +} + +ListItem::ListItem(const unsigned int item) + : this_iter_(), + item_ptr_(0), + item_(item) +{ +} + +ListItem::~ListItem() +{ +} + +void* ListItem::GetItem() const +{ + return const_cast(item_ptr_); +} + +unsigned int ListItem::GetUnsignedItem() const +{ + return item_; +} + +ListWrapper::ListWrapper() : list_() +{ +} + +ListWrapper::~ListWrapper() +{ + if (!Empty()) + { + // TODO (hellner) I'm not sure this loggin is useful. + WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1, + "Potential memory leak in ListWrapper"); + // Remove all remaining list items. + while (Erase(First()) == 0) + {} + } +} + +bool ListWrapper::Empty() const +{ + return list_.empty(); +} + +unsigned int ListWrapper::GetSize() const +{ + return list_.size(); +} + +int ListWrapper::PushBack(const void* ptr) +{ + ListItem* item = new ListItem(ptr); + list_.push_back(item); + return 0; +} + +int ListWrapper::PushBack(const unsigned int item_id) +{ + ListItem* item = new ListItem(item_id); + list_.push_back(item); + return 0; +} + +int ListWrapper::PushFront(const unsigned int item_id) +{ + ListItem* item = new ListItem(item_id); + list_.push_front(item); + return 0; +} + +int ListWrapper::PushFront(const void* ptr) +{ + ListItem* item = new ListItem(ptr); + list_.push_front(item); + return 0; +} + +int ListWrapper::PopFront() +{ + if(list_.empty()) + { + return -1; + } + list_.pop_front(); + return 0; +} + +int ListWrapper::PopBack() +{ + if(list_.empty()) + { + return -1; + } + list_.pop_back(); + return 0; +} + +ListItem* ListWrapper::First() const +{ + if(list_.empty()) + { + return NULL; + } + std::list::iterator item_iter = list_.begin(); + ListItem* return_item = (*item_iter); + return_item->this_iter_ = item_iter; + return return_item; +} + +ListItem* ListWrapper::Last() const +{ + if(list_.empty()) + { + return NULL; + } + // std::list::end() addresses the last item + 1. Decrement so that the + // actual last is accessed. + std::list::iterator item_iter = list_.end(); + --item_iter; + ListItem* return_item = (*item_iter); + return_item->this_iter_ = item_iter; + return return_item; +} + +ListItem* ListWrapper::Next(ListItem* item) const +{ + if(item == NULL) + { + return NULL; + } + std::list::iterator item_iter = item->this_iter_; + ++item_iter; + if (item_iter == list_.end()) + { + return NULL; + } + ListItem* return_item = (*item_iter); + return_item->this_iter_ = item_iter; + return return_item; +} + +ListItem* ListWrapper::Previous(ListItem* item) const +{ + if(item == NULL) + { + return NULL; + } + std::list::iterator item_iter = item->this_iter_; + if (item_iter == list_.begin()) + { + return NULL; + } + --item_iter; + ListItem* return_item = (*item_iter); + return_item->this_iter_ = item_iter; + return return_item; +} + +int ListWrapper::Insert(ListItem* existing_previous_item, + ListItem* new_item) +{ + // Allow existingPreviousItem to be NULL if the list is empty. + // TODO (hellner) why allow this? Keep it as is for now to avoid + // breaking API contract. + if (!existing_previous_item && !Empty()) + { + return -1; + } + + if (!new_item) + { + return -1; + } + + std::list::iterator insert_location = list_.begin(); + if (!Empty()) + { + insert_location = existing_previous_item->this_iter_; + if(insert_location != list_.end()) + { + ++insert_location; + } + } + + list_.insert(insert_location,new_item); + return 0; +} + +int ListWrapper::InsertBefore(ListItem* existing_next_item, + ListItem* new_item) +{ + // Allow existing_next_item to be NULL if the list is empty. + // Todo: why allow this? Keep it as is for now to avoid breaking API + // contract. + if (!existing_next_item && !Empty()) + { + return -1; + } + if (!new_item) + { + return -1; + } + + std::list::iterator insert_location = list_.begin(); + if (!Empty()) + { + insert_location = existing_next_item->this_iter_; + } + + list_.insert(insert_location,new_item); + return 0; +} + +int ListWrapper::Erase(ListItem* item) +{ + if(item == NULL) + { + return -1; + } + list_.erase(item->this_iter_); + return 0; +} +} // namespace webrtc diff --git a/system_wrappers/source/list_stl.h b/system_wrappers/source/list_stl.h new file mode 100644 index 000000000..b83a6648c --- /dev/null +++ b/system_wrappers/source/list_stl.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_LIST_STL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_LIST_STL_H_ + +#include + +#include "constructor_magic.h" + +namespace webrtc { +class ListItem +{ +friend class ListWrapper; + +public: + ListItem(const void* ptr); + ListItem(const unsigned int item); + virtual ~ListItem(); + void* GetItem() const; + unsigned int GetUnsignedItem() const; + +private: + mutable std::list::iterator this_iter_; + const void* item_ptr_; + const unsigned int item_; + DISALLOW_COPY_AND_ASSIGN(ListItem); +}; + +class ListWrapper +{ +public: + ListWrapper(); + ~ListWrapper(); + + // ListWrapper functions + unsigned int GetSize() const; + int PushBack(const void* ptr); + int PushBack(const unsigned int item_id); + int PushFront(const void* ptr); + int PushFront(const unsigned int item_id); + int PopFront(); + int PopBack(); + bool Empty() const; + ListItem* First() const; + ListItem* Last() const; + ListItem* Next(ListItem* item) const; + ListItem* Previous(ListItem* item) const; + int Erase(ListItem* item); + int Insert(ListItem* existing_previous_item, ListItem* new_item); + int InsertBefore(ListItem* existing_next_item, ListItem* new_item); + +private: + mutable std::list list_; + DISALLOW_COPY_AND_ASSIGN(ListWrapper); +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_LIST_STL_H_ diff --git a/system_wrappers/source/map.cc b/system_wrappers/source/map.cc new file mode 100644 index 000000000..0bff155be --- /dev/null +++ b/system_wrappers/source/map.cc @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "map_wrapper.h" + +#include "trace.h" + +namespace webrtc { +MapItem::MapItem(int id, void* item) : item_pointer_(item), item_id_(id) +{ +} + +MapItem::~MapItem() +{ +} + +void* MapItem::GetItem() +{ + return item_pointer_; +} + +int MapItem::GetId() +{ + return item_id_; +} + +unsigned int MapItem::GetUnsignedId() +{ + return static_cast(item_id_); +} + +void MapItem::SetItem(void* ptr) +{ + item_pointer_ = ptr; +} + +MapWrapper::MapWrapper() : map_() +{ +} + +MapWrapper::~MapWrapper() +{ + if (!map_.empty()) + { + WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1, + "Potential memory leak in MapWrapper"); + // Remove all map items. Please note that std::map::clear() can't be + // used because each item has some dynamically allocated memory + // associated with it (i.e. using std::map::clear would introduce a + // memory leak). + while (Erase(First()) == 0) + {} + } +} + +int MapWrapper::Size() const +{ + return (int)map_.size(); +} + +int MapWrapper::Insert(int id, void* ptr) +{ + map_[id] = new MapItem(id,ptr); + return 0; +} + +MapItem* MapWrapper::First() const +{ + std::map::const_iterator it = map_.begin(); + if (it != map_.end()) + { + return it->second; + } + return 0; +} + +MapItem* MapWrapper::Last() const +{ + std::map::const_reverse_iterator it = map_.rbegin(); + if (it != map_.rend()) + { + return it->second; + } + return 0; +} + +MapItem* MapWrapper::Next(MapItem* item) const +{ + if (item == 0) + { + return 0; + } + std::map::const_iterator it = map_.find(item->item_id_); + if (it != map_.end()) + { + it++; + if (it != map_.end()) + { + return it->second; + } + } + return 0; +} + +MapItem* MapWrapper::Previous(MapItem* item) const +{ + if (item == 0) + { + return 0; + } + + std::map::const_iterator it = map_.find(item->item_id_); + if ((it != map_.end()) && + (it != map_.begin())) + { + --it; + return it->second; + } + return 0; +} + +MapItem* MapWrapper::Find(int id) const +{ + std::map::const_iterator it = map_.find(id); + if (it != map_.end()) + { + return it->second; + } + return 0; +} + +int MapWrapper::Erase(MapItem* item) +{ + if (item == 0) + { + return -1; + } + std::map::iterator it = map_.find(item->item_id_); + if (it != map_.end()) + { + delete it->second; + map_.erase(it); + return 0; + } + return -1; +} + +int MapWrapper::Erase(const int id) +{ + std::map::iterator it = map_.find(id); + if (it != map_.end()) + { + delete it->second; + map_.erase(it); + return 0; + } + return -1; +} +} // namespace webrtc diff --git a/system_wrappers/source/map_no_stl.cc b/system_wrappers/source/map_no_stl.cc new file mode 100644 index 000000000..cb0ac0029 --- /dev/null +++ b/system_wrappers/source/map_no_stl.cc @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "map_no_stl.h" + +#include "critical_section_wrapper.h" +#include "trace.h" + +namespace webrtc { +MapNoStlItem::MapNoStlItem(int id, void* item) + : next_(0), + prev_(0), + item_id_(id), + item_ptr_(item) +{ +} + +MapNoStlItem::~MapNoStlItem() +{ +} + +void* MapNoStlItem::GetItem() +{ + return item_ptr_; +} + +int MapNoStlItem::GetId() +{ + return item_id_; +} + +unsigned int MapNoStlItem::GetUnsignedId() +{ + return static_cast(item_id_); +} + +void MapNoStlItem::SetItem(void* ptr) +{ + item_ptr_ = ptr; +} + +MapNoStl::MapNoStl() + : critical_section_(CriticalSectionWrapper::CreateCriticalSection()), + first_(0), + last_(0), + size_(0) +{ +} + +MapNoStl::~MapNoStl() +{ + if (First()) + { + WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1, + "Potential memory leak in MapNoStl"); + while (Erase(First()) == 0) + {} + } + delete critical_section_; +} + +int MapNoStl::Size() const +{ + return size_; +} + +int MapNoStl::Insert(int id, void* ptr) +{ + MapNoStlItem* new_item = new MapNoStlItem(id, ptr); + + CriticalSectionScoped lock(*critical_section_); + MapNoStlItem* item = first_; + size_++; + if (!item) + { + first_ = new_item; + last_ = new_item; + return 0; + } + while(item->next_) + { + // Three scenarios + // 1. Item should be inserted first. + // 2. Item should be inserted between two items + // 3. Item should be inserted last + if (item->GetId() > id) + { + new_item->next_ = item; + item->prev_ = new_item; + if (item == first_) + { + first_ = new_item; + } + else + { + new_item->prev_ = item->prev_; + new_item->prev_->next_ = new_item; + } + return 0; + } + item = item->next_; + } + // 3 + item->next_ = new_item; + new_item->prev_ = item; + last_ = new_item; + return 0; +} + +MapNoStlItem* MapNoStl::First() const +{ + return first_; +} + +MapNoStlItem* MapNoStl::Last() const +{ + return last_; +} + +MapNoStlItem* MapNoStl::Next(MapNoStlItem* item) const +{ + if (!item) + { + return 0; + } + return item->next_; +} + +MapNoStlItem* MapNoStl::Previous(MapNoStlItem* item) const +{ + if (!item) + { + return 0; + } + return item->prev_; +} + +MapNoStlItem* MapNoStl::Find(int id) const +{ + CriticalSectionScoped lock(*critical_section_); + MapNoStlItem* item = Locate(id); + return item; +} + +int MapNoStl::Erase(MapNoStlItem* item) +{ + if(!item) + { + return -1; + } + CriticalSectionScoped lock(*critical_section_); + return Remove(item); +} + +int MapNoStl::Erase(const int id) +{ + CriticalSectionScoped lock(*critical_section_); + MapNoStlItem* item = Locate(id); + if(!item) + { + return -1; + } + return Remove(item); +} + +MapNoStlItem* MapNoStl::Locate(int id) const +{ + MapNoStlItem* item = first_; + while(item) + { + if (item->GetId() == id) + { + return item; + } + item = item->next_; + } + return 0; +} + +int MapNoStl::Remove(MapNoStlItem* item) +{ + if (!item) + { + return -1; + } + size_--; + MapNoStlItem* previous_item = item->prev_; + MapNoStlItem* next_item = item->next_; + if (!previous_item) + { + next_item->prev_ = 0; + first_ = next_item; + } + else + { + previous_item->next_ = next_item; + } + if (!next_item) + { + previous_item->next_ = 0; + last_ = previous_item; + } + else + { + next_item->prev_ = previous_item; + } + delete item; + return 0; +} +} // namespace webrtc diff --git a/system_wrappers/source/map_no_stl.h b/system_wrappers/source/map_no_stl.h new file mode 100644 index 000000000..51bc01143 --- /dev/null +++ b/system_wrappers/source/map_no_stl.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_MAP_NO_STL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_MAP_NO_STL_H_ + +#include "constructor_magic.h" + +namespace webrtc { +class CriticalSectionWrapper; + +class MapNoStlItem +{ +friend class Map; + +public: + MapNoStlItem(int id, void* ptr); + virtual ~MapNoStlItem(); + void* GetItem(); + int GetId(); + unsigned int GetUnsignedId(); + void SetItem(void* ptr); + +protected: + MapNoStlItem* next_; + MapNoStlItem* prev_; + +private: + int item_id_; + void* item_ptr_; + DISALLOW_COPY_AND_ASSIGN(MapNoStlItem); +}; + +class MapNoStl +{ +public: + MapNoStl(); + virtual ~MapNoStl(); + + // MapWrapper functions. + int Insert(int id, void* ptr); + int Erase(MapNoStlItem* item); + int Erase(int id); + int Size() const; + MapNoStlItem* First() const; + MapNoStlItem* Last() const; + MapNoStlItem* Next(MapNoStlItem* item) const; + MapNoStlItem* Previous(MapNoStlItem* item) const; + MapNoStlItem* Find(int id) const; + +private: + MapNoStlItem* Locate(int id) const; + int Remove(MapNoStlItem* item); + + CriticalSection* critical_section_; + MapNoStlItem* first_; + MapNoStlItem* last_; + int size_; + DISALLOW_COPY_AND_ASSIGN(MapNoStl); +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_MAP_NO_STL_H_ diff --git a/system_wrappers/source/rw_lock.cc b/system_wrappers/source/rw_lock.cc new file mode 100644 index 000000000..47901d346 --- /dev/null +++ b/system_wrappers/source/rw_lock.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rw_lock_wrapper.h" + +#include + +#if defined(_WIN32) + #include "rw_lock_windows.h" +#elif defined(ANDROID) + #include + #include "rw_lock_generic.h" +#else + #include "rw_lock_linux.h" +#endif + +namespace webrtc { +RWLockWrapper* RWLockWrapper::CreateRWLock() +{ +#ifdef _WIN32 + RWLockWrapper* lock = new RWLockWindows(); +#elif defined(ANDROID) + RWLockWrapper* lock = new RWLockWrapperGeneric(); +#else + RWLockWrapper* lock = new RWLockLinux(); +#endif + if(lock->Init() != 0) + { + delete lock; + assert(false); + return NULL; + } + return lock; +} + +RWLockWrapper::~RWLockWrapper() +{ +} +} // namespace webrtc diff --git a/system_wrappers/source/rw_lock_generic.cc b/system_wrappers/source/rw_lock_generic.cc new file mode 100644 index 000000000..a468ef3b1 --- /dev/null +++ b/system_wrappers/source/rw_lock_generic.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rw_lock_generic.h" + +#include "condition_variable_wrapper.h" +#include "critical_section_wrapper.h" + +namespace webrtc { +RWLockWrapperGeneric::RWLockWrapperGeneric() + : _readersActive(0), + _writerActive(false), + _readersWaiting(0), + _writersWaiting(0) +{ + _critSectPtr = CriticalSectionWrapper::CreateCriticalSection(); + _readCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + _writeCondPtr = ConditionVariableWrapper::CreateConditionVariable(); +} + +RWLockWrapperGeneric::~RWLockWrapperGeneric() +{ + delete _writeCondPtr; + delete _readCondPtr; + delete _critSectPtr; +} + +int RWLockWrapperGeneric::Init() +{ + return 0; +} + +void RWLockWrapperGeneric::AcquireLockExclusive() +{ + _critSectPtr->Enter(); + + if (_writerActive || _readersActive > 0) + { + ++_writersWaiting; + + while (_writerActive || _readersActive > 0) + { + _writeCondPtr->SleepCS(*_critSectPtr); + } + + --_writersWaiting; + } + _writerActive = true; + _critSectPtr->Leave(); +} + +void RWLockWrapperGeneric::ReleaseLockExclusive() +{ + _critSectPtr->Enter(); + + _writerActive = false; + + if (_writersWaiting > 0) + { + _writeCondPtr->Wake(); + + }else if (_readersWaiting > 0) + { + _readCondPtr->WakeAll(); + } + _critSectPtr->Leave(); +} + +void RWLockWrapperGeneric::AcquireLockShared() +{ + _critSectPtr->Enter(); + + if (_writerActive || _writersWaiting > 0) + { + ++_readersWaiting; + + while (_writerActive || _writersWaiting > 0) + { + _readCondPtr->SleepCS(*_critSectPtr); + } + --_readersWaiting; + } + ++_readersActive; + _critSectPtr->Leave(); +} + +void RWLockWrapperGeneric::ReleaseLockShared() +{ + _critSectPtr->Enter(); + + --_readersActive; + + if (_readersActive == 0 && _writersWaiting > 0) + { + _writeCondPtr->Wake(); + } + _critSectPtr->Leave(); +} +} // namespace webrtc diff --git a/system_wrappers/source/rw_lock_generic.h b/system_wrappers/source/rw_lock_generic.h new file mode 100644 index 000000000..fff5e5d2e --- /dev/null +++ b/system_wrappers/source/rw_lock_generic.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_ + +#include "rw_lock_wrapper.h" + +namespace webrtc { +class CriticalSectionWrapper; +class ConditionVariableWrapper; + +class RWLockWrapperGeneric : public RWLockWrapper +{ +public: + RWLockWrapperGeneric(); + virtual ~RWLockWrapperGeneric(); + + virtual void AcquireLockExclusive(); + virtual void ReleaseLockExclusive(); + + virtual void AcquireLockShared(); + virtual void ReleaseLockShared(); + +protected: + virtual int Init(); + +private: + CriticalSectionWrapper* _critSectPtr; + ConditionVariableWrapper* _readCondPtr; + ConditionVariableWrapper* _writeCondPtr; + + int _readersActive; + bool _writerActive; + int _readersWaiting; + int _writersWaiting; +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_ diff --git a/system_wrappers/source/rw_lock_linux.cc b/system_wrappers/source/rw_lock_linux.cc new file mode 100644 index 000000000..084dce861 --- /dev/null +++ b/system_wrappers/source/rw_lock_linux.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rw_lock_linux.h" + +namespace webrtc { +RWLockLinux::RWLockLinux() : _lock() +{ +} + +RWLockLinux::~RWLockLinux() +{ + pthread_rwlock_destroy(&_lock); +} + +int RWLockLinux::Init() +{ + return pthread_rwlock_init(&_lock, 0); +} + +void RWLockLinux::AcquireLockExclusive() +{ + pthread_rwlock_wrlock(&_lock); +} + +void RWLockLinux::ReleaseLockExclusive() +{ + pthread_rwlock_unlock(&_lock); +} + +void RWLockLinux::AcquireLockShared() +{ + pthread_rwlock_rdlock(&_lock); +} + +void RWLockLinux::ReleaseLockShared() +{ + pthread_rwlock_unlock(&_lock); +} +} // namespace webrtc diff --git a/system_wrappers/source/rw_lock_linux.h b/system_wrappers/source/rw_lock_linux.h new file mode 100644 index 000000000..391ee8fe6 --- /dev/null +++ b/system_wrappers/source/rw_lock_linux.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_LINUX_H_ + +#include "rw_lock_wrapper.h" + +#include + +namespace webrtc { +class RWLockLinux : public RWLockWrapper +{ +public: + RWLockLinux(); + virtual ~RWLockLinux(); + + virtual void AcquireLockExclusive(); + virtual void ReleaseLockExclusive(); + + virtual void AcquireLockShared(); + virtual void ReleaseLockShared(); + +protected: + virtual int Init(); + +private: + pthread_rwlock_t _lock; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_LINUX_H_ diff --git a/system_wrappers/source/rw_lock_windows.cc b/system_wrappers/source/rw_lock_windows.cc new file mode 100644 index 000000000..cf5db5755 --- /dev/null +++ b/system_wrappers/source/rw_lock_windows.cc @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rw_lock_windows.h" + +#include "critical_section_wrapper.h" +#include "condition_variable_wrapper.h" +#include "trace.h" + +// TODO (hellner) why not just use the rw_lock_generic.cc solution if +// native is not supported? Unnecessary redundancy! + +namespace webrtc { +bool RWLockWindows::_winSupportRWLockPrimitive = false; +static HMODULE library = NULL; + +PInitializeSRWLock _PInitializeSRWLock; +PAcquireSRWLockExclusive _PAcquireSRWLockExclusive; +PAcquireSRWLockShared _PAcquireSRWLockShared; +PReleaseSRWLockShared _PReleaseSRWLockShared; +PReleaseSRWLockExclusive _PReleaseSRWLockExclusive; + +RWLockWindows::RWLockWindows() + : _critSectPtr(NULL), + _readCondPtr(NULL), + _writeCondPtr(NULL), + _readersActive(0), + _writerActive(false), + _readersWaiting(0), + _writersWaiting(0) +{ +} + +RWLockWindows::~RWLockWindows() +{ + delete _writeCondPtr; + delete _readCondPtr; + delete _critSectPtr; +} + +int RWLockWindows::Init() +{ + if(!library) + { + // Use native implementation if supported (i.e Vista+) + library = LoadLibrary(TEXT("Kernel32.dll")); + if(library) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Kernel.dll"); + + _PInitializeSRWLock = + (PInitializeSRWLock)GetProcAddress( + library, + "InitializeSRWLock"); + + _PAcquireSRWLockExclusive = + (PAcquireSRWLockExclusive)GetProcAddress( + library, + "AcquireSRWLockExclusive"); + _PReleaseSRWLockExclusive = + (PReleaseSRWLockExclusive)GetProcAddress( + library, + "ReleaseSRWLockExclusive"); + _PAcquireSRWLockShared = + (PAcquireSRWLockShared)GetProcAddress( + library, + "AcquireSRWLockShared"); + _PReleaseSRWLockShared = + (PReleaseSRWLockShared)GetProcAddress( + library, + "ReleaseSRWLockShared"); + + if( _PInitializeSRWLock && + _PAcquireSRWLockExclusive && + _PReleaseSRWLockExclusive && + _PAcquireSRWLockShared && + _PReleaseSRWLockShared ) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Simple RW Lock"); + _winSupportRWLockPrimitive = true; + } + } + } + if(_winSupportRWLockPrimitive) + { + _PInitializeSRWLock(&_lock); + } else { + _critSectPtr = CriticalSectionWrapper::CreateCriticalSection(); + _readCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + _writeCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + } + return 0; +} + +void RWLockWindows::AcquireLockExclusive() +{ + if (_winSupportRWLockPrimitive) + { + _PAcquireSRWLockExclusive(&_lock); + } else { + _critSectPtr->Enter(); + + if (_writerActive || _readersActive > 0) + { + ++_writersWaiting; + while (_writerActive || _readersActive > 0) + { + _writeCondPtr->SleepCS(*_critSectPtr); + } + --_writersWaiting; + } + _writerActive = true; + _critSectPtr->Leave(); + } +} + +void RWLockWindows::ReleaseLockExclusive() +{ + if(_winSupportRWLockPrimitive) + { + _PReleaseSRWLockExclusive(&_lock); + } else { + _critSectPtr->Enter(); + _writerActive = false; + if (_writersWaiting > 0) + { + _writeCondPtr->Wake(); + + }else if (_readersWaiting > 0) { + _readCondPtr->WakeAll(); + } + _critSectPtr->Leave(); + } +} + +void RWLockWindows::AcquireLockShared() +{ + if(_winSupportRWLockPrimitive) + { + _PAcquireSRWLockShared(&_lock); + } else + { + _critSectPtr->Enter(); + if (_writerActive || _writersWaiting > 0) + { + ++_readersWaiting; + + while (_writerActive || _writersWaiting > 0) + { + _readCondPtr->SleepCS(*_critSectPtr); + } + --_readersWaiting; + } + ++_readersActive; + _critSectPtr->Leave(); + } +} + +void RWLockWindows::ReleaseLockShared() +{ + if(_winSupportRWLockPrimitive) + { + _PReleaseSRWLockShared(&_lock); + } else + { + _critSectPtr->Enter(); + + --_readersActive; + + if (_readersActive == 0 && _writersWaiting > 0) + { + _writeCondPtr->Wake(); + } + _critSectPtr->Leave(); + } +} +} // namespace webrtc diff --git a/system_wrappers/source/rw_lock_windows.h b/system_wrappers/source/rw_lock_windows.h new file mode 100644 index 000000000..dc5355e4d --- /dev/null +++ b/system_wrappers/source/rw_lock_windows.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ + +#include "rw_lock_wrapper.h" + +#include + +#if !defined(RTL_SRWLOCK_INIT) + typedef struct _RTL_SRWLOCK + { + void* Ptr; + } RTL_SRWLOCK, *PRTL_SRWLOCK; + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +namespace webrtc { +class CriticalSectionWrapper; +class ConditionVariableWrapper; + +typedef void (WINAPI *PInitializeSRWLock)(PSRWLOCK); + +typedef void (WINAPI *PAcquireSRWLockExclusive)(PSRWLOCK); +typedef void (WINAPI *PReleaseSRWLockExclusive)(PSRWLOCK); + +typedef void (WINAPI *PAcquireSRWLockShared)(PSRWLOCK); +typedef void (WINAPI *PReleaseSRWLockShared)(PSRWLOCK); + + +class RWLockWindows :public RWLockWrapper +{ +public: + RWLockWindows(); + virtual ~RWLockWindows(); + + virtual void AcquireLockExclusive(); + virtual void ReleaseLockExclusive(); + + virtual void AcquireLockShared(); + virtual void ReleaseLockShared(); + +protected: + virtual int Init(); + +private: + // For native implementation. + static bool _winSupportRWLockPrimitive; + SRWLOCK _lock; + + // Genric implementation, fallback if native is not supported. + CriticalSectionWrapper* _critSectPtr; + ConditionVariableWrapper* _readCondPtr; + ConditionVariableWrapper* _writeCondPtr; + + int _readersActive; + bool _writerActive; + int _readersWaiting; + int _writersWaiting; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ diff --git a/system_wrappers/source/sort.cc b/system_wrappers/source/sort.cc new file mode 100644 index 000000000..f44b64497 --- /dev/null +++ b/system_wrappers/source/sort.cc @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// When the platform supports STL, the functions are implemented using a +// templated spreadsort algorithm (http://sourceforge.net/projects/spreadsort/), +// part of the Boost C++ library collection. Otherwise, the C standard library's +// qsort() will be used. + +#include "sort.h" + +#include +#include // memcpy +#include // nothrow new + +#ifdef NO_STL +#include // qsort +#else +#include // std::sort +#include +#include "spreadsort.hpp" // TODO (ajm) upgrade to spreadsortv2. +#endif + +#ifdef NO_STL +#define COMPARE_DEREFERENCED(XT, YT) \ + do \ + { \ + if ((XT) > (YT)) \ + { \ + return 1; \ + } \ + else if ((XT) < (YT)) \ + { \ + return -1; \ + } \ + \ + return 0; \ + } \ + while(0) + +#define COMPARE_FOR_QSORT(X, Y, TYPE) \ + do \ + { \ + TYPE xT = static_cast(*static_cast(X)); \ + TYPE yT = static_cast(*static_cast(Y)); \ + COMPARE_DEREFERENCED(xT, yT); \ + } \ + while(0) + +#define COMPARE_KEY_FOR_QSORT(SORT_KEY_X, SORT_KEY_Y, TYPE) \ + do \ + { \ + TYPE xT = static_cast(*static_cast \ + (static_cast(SORT_KEY_X)->key)); \ + TYPE yT = static_cast(*static_cast \ + (static_cast(SORT_KEY_Y)->key)); \ + COMPARE_DEREFERENCED(xT, yT); \ + } \ + while(0) + +#define KEY_QSORT(SORT_KEY, KEY, NUM_OF_ELEMENTS, KEY_TYPE, COMPARE_FUNC) \ + do \ + { \ + KEY_TYPE* keyT = (KEY_TYPE*)(key); \ + for (WebRtc_UWord32 i = 0; i < (NUM_OF_ELEMENTS); i++) \ + { \ + ptrSortKey[i].key = &keyT[i]; \ + ptrSortKey[i].index = i; \ + } \ + \ + qsort((SORT_KEY), (NUM_OF_ELEMENTS), sizeof(SortKey), (COMPARE_FUNC));\ + } \ + while(0) +#endif + +namespace webrtc +{ +#ifdef NO_STL + struct SortKey + { + void* key; + WebRtc_UWord32 index; + }; +#else + template + struct SortKey + { + KeyType key; + WebRtc_UWord32 index; + }; +#endif + + namespace // Unnamed namespace provides internal linkage. + { +#ifdef NO_STL + int CompareWord8(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_Word8); + } + + int CompareUWord8(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_UWord8); + } + + int CompareWord16(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_Word16); + } + + int CompareUWord16(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_UWord16); + } + + int CompareWord32(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_Word32); + } + + int CompareUWord32(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_UWord32); + } + + int CompareWord64(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_Word64); + } + + int CompareUWord64(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, WebRtc_UWord64); + } + + int CompareFloat32(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, float); + } + + int CompareFloat64(const void* x, const void* y) + { + COMPARE_FOR_QSORT(x, y, double); + } + + int CompareKeyWord8(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word8); + } + + int CompareKeyUWord8(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord8); + } + + int CompareKeyWord16(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word16); + } + + int CompareKeyUWord16(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord16); + } + + int CompareKeyWord32(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word32); + } + + int CompareKeyUWord32(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord32); + } + + int CompareKeyWord64(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_Word64); + } + + int CompareKeyUWord64(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, WebRtc_UWord64); + } + + int CompareKeyFloat32(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, float); + } + + int CompareKeyFloat64(const void* sortKeyX, const void* sortKeyY) + { + COMPARE_KEY_FOR_QSORT(sortKeyX, sortKeyY, double); + } +#else + template + struct KeyLessThan + { + bool operator()(const SortKey& sortKeyX, + const SortKey& sortKeyY) const + { + return sortKeyX.key < sortKeyY.key; + } + }; + + template + struct KeyRightShift + { + KeyType operator()(const SortKey& sortKey, + const unsigned offset) const + { + return sortKey.key >> offset; + } + }; + + template + inline void IntegerSort(void* data, WebRtc_UWord32 numOfElements) + { + DataType* dataT = static_cast(data); + boost::integer_sort(dataT, dataT + numOfElements); + } + + template + inline void FloatSort(void* data, WebRtc_UWord32 numOfElements) + { + DataType* dataT = static_cast(data); + IntegerType cVal = 0; + boost::float_sort_cast(dataT, dataT + numOfElements, cVal); + } + + template + inline void StdSort(void* data, WebRtc_UWord32 numOfElements) + { + DataType* dataT = static_cast(data); + std::sort(dataT, dataT + numOfElements); + } + + template + inline WebRtc_Word32 SetupKeySort(void* key, + SortKey*& ptrSortKey, + WebRtc_UWord32 numOfElements) + { + ptrSortKey = new(std::nothrow) SortKey[numOfElements]; + if (ptrSortKey == NULL) + { + return -1; + } + + KeyType* keyT = static_cast(key); + for (WebRtc_UWord32 i = 0; i < numOfElements; i++) + { + ptrSortKey[i].key = keyT[i]; + ptrSortKey[i].index = i; + } + + return 0; + } + + template + inline WebRtc_Word32 TeardownKeySort(void* data, + SortKey* ptrSortKey, + WebRtc_UWord32 numOfElements, WebRtc_UWord32 sizeOfElement) + { + WebRtc_UWord8* ptrData = static_cast(data); + WebRtc_UWord8* ptrDataSorted = new(std::nothrow) WebRtc_UWord8 + [numOfElements * sizeOfElement]; + if (ptrDataSorted == NULL) + { + return -1; + } + + for (WebRtc_UWord32 i = 0; i < numOfElements; i++) + { + memcpy(ptrDataSorted + i * sizeOfElement, ptrData + + ptrSortKey[i].index * sizeOfElement, sizeOfElement); + } + memcpy(ptrData, ptrDataSorted, numOfElements * sizeOfElement); + delete[] ptrSortKey; + delete[] ptrDataSorted; + return 0; + } + + template + inline WebRtc_Word32 IntegerKeySort(void* data, void* key, + WebRtc_UWord32 numOfElements, + WebRtc_UWord32 sizeOfElement) + { + SortKey* ptrSortKey; + if (SetupKeySort(key, ptrSortKey, numOfElements) != 0) + { + return -1; + } + + boost::integer_sort(ptrSortKey, ptrSortKey + numOfElements, + KeyRightShift(), KeyLessThan()); + + if (TeardownKeySort(data, ptrSortKey, numOfElements, + sizeOfElement) != 0) + { + return -1; + } + + return 0; + } + + template + inline WebRtc_Word32 StdKeySort(void* data, void* key, + WebRtc_UWord32 numOfElements, + WebRtc_UWord32 sizeOfElement) + { + SortKey* ptrSortKey; + if (SetupKeySort(key, ptrSortKey, numOfElements) != 0) + { + return -1; + } + + std::sort(ptrSortKey, ptrSortKey + numOfElements, + KeyLessThan()); + + if (TeardownKeySort(data, ptrSortKey, numOfElements, + sizeOfElement) != 0) + { + return -1; + } + + return 0; + } +#endif + } + + WebRtc_Word32 Sort(void* data, WebRtc_UWord32 numOfElements, Type type) + { + if (data == NULL) + { + return -1; + } + +#ifdef NO_STL + switch (type) + { + case TYPE_Word8: + qsort(data, numOfElements, sizeof(WebRtc_Word8), CompareWord8); + break; + case TYPE_UWord8: + qsort(data, numOfElements, sizeof(WebRtc_UWord8), CompareUWord8); + break; + case TYPE_Word16: + qsort(data, numOfElements, sizeof(WebRtc_Word16), CompareWord16); + break; + case TYPE_UWord16: + qsort(data, numOfElements, sizeof(WebRtc_UWord16), CompareUWord16); + break; + case TYPE_Word32: + qsort(data, numOfElements, sizeof(WebRtc_Word32), CompareWord32); + break; + case TYPE_UWord32: + qsort(data, numOfElements, sizeof(WebRtc_UWord32), CompareUWord32); + break; + case TYPE_Word64: + qsort(data, numOfElements, sizeof(WebRtc_Word64), CompareWord64); + break; + case TYPE_UWord64: + qsort(data, numOfElements, sizeof(WebRtc_UWord64), CompareUWord64); + break; + case TYPE_Float32: + qsort(data, numOfElements, sizeof(float), CompareFloat32); + break; + case TYPE_Float64: + qsort(data, numOfElements, sizeof(double), CompareFloat64); + break; + default: + return -1; + } +#else + // Fall back to std::sort for 64-bit types and floats due to compiler + // warnings and VS 2003 build crashes respectively with spreadsort. + switch (type) + { + case TYPE_Word8: + IntegerSort(data, numOfElements); + break; + case TYPE_UWord8: + IntegerSort(data, numOfElements); + break; + case TYPE_Word16: + IntegerSort(data, numOfElements); + break; + case TYPE_UWord16: + IntegerSort(data, numOfElements); + break; + case TYPE_Word32: + IntegerSort(data, numOfElements); + break; + case TYPE_UWord32: + IntegerSort(data, numOfElements); + break; + case TYPE_Word64: + StdSort(data, numOfElements); + break; + case TYPE_UWord64: + StdSort(data, numOfElements); + break; + case TYPE_Float32: + StdSort(data, numOfElements); + break; + case TYPE_Float64: + StdSort(data, numOfElements); + break; + default: + return -1; + } +#endif + return 0; + } + + WebRtc_Word32 KeySort(void* data, void* key, WebRtc_UWord32 numOfElements, + WebRtc_UWord32 sizeOfElement, Type keyType) + { + if (data == NULL) + { + return -1; + } + + if (key == NULL) + { + return -1; + } + + if ((WebRtc_UWord64)numOfElements * sizeOfElement > 0xffffffff) + { + return -1; + } + +#ifdef NO_STL + SortKey* ptrSortKey = new(std::nothrow) SortKey[numOfElements]; + if (ptrSortKey == NULL) + { + return -1; + } + + switch (keyType) + { + case TYPE_Word8: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word8, + CompareKeyWord8); + break; + case TYPE_UWord8: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord8, + CompareKeyUWord8); + break; + case TYPE_Word16: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word16, + CompareKeyWord16); + break; + case TYPE_UWord16: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord16, + CompareKeyUWord16); + break; + case TYPE_Word32: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word32, + CompareKeyWord32); + break; + case TYPE_UWord32: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord32, + CompareKeyUWord32); + break; + case TYPE_Word64: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_Word64, + CompareKeyWord64); + break; + case TYPE_UWord64: + KEY_QSORT(ptrSortKey, key, numOfElements, WebRtc_UWord64, + CompareKeyUWord64); + break; + case TYPE_Float32: + KEY_QSORT(ptrSortKey, key, numOfElements, float, + CompareKeyFloat32); + break; + case TYPE_Float64: + KEY_QSORT(ptrSortKey, key, numOfElements, double, + CompareKeyFloat64); + break; + default: + return -1; + } + + // Shuffle into sorted position based on index map. + WebRtc_UWord8* ptrData = static_cast(data); + WebRtc_UWord8* ptrDataSorted = new(std::nothrow) WebRtc_UWord8 + [numOfElements * sizeOfElement]; + if (ptrDataSorted == NULL) + { + return -1; + } + + for (WebRtc_UWord32 i = 0; i < numOfElements; i++) + { + memcpy(ptrDataSorted + i * sizeOfElement, ptrData + + ptrSortKey[i].index * sizeOfElement, sizeOfElement); + } + memcpy(ptrData, ptrDataSorted, numOfElements * sizeOfElement); + + delete[] ptrSortKey; + delete[] ptrDataSorted; + + return 0; +#else + // Fall back to std::sort for 64-bit types and floats due to compiler + // warnings and errors respectively with spreadsort. + switch (keyType) + { + case TYPE_Word8: + return IntegerKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_UWord8: + return IntegerKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_Word16: + return IntegerKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_UWord16: + return IntegerKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_Word32: + return IntegerKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_UWord32: + return IntegerKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_Word64: + return StdKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_UWord64: + return StdKeySort(data, key, numOfElements, + sizeOfElement); + case TYPE_Float32: + return StdKeySort(data, key, numOfElements, sizeOfElement); + case TYPE_Float64: + return StdKeySort(data, key, numOfElements, sizeOfElement); + default: + return -1; + } +#endif + } +} // namespace webrtc diff --git a/system_wrappers/source/spreadsortlib/constants.hpp b/system_wrappers/source/spreadsortlib/constants.hpp new file mode 100644 index 000000000..fa81ece86 --- /dev/null +++ b/system_wrappers/source/spreadsortlib/constants.hpp @@ -0,0 +1,42 @@ +/*Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE.*/ +#ifndef BOOST_SPREADSORT_CONSTANTS +#define BOOST_SPREADSORT_CONSTANTS +namespace boost { +namespace detail { +//Tuning constants +//Sets the minimum number of items per bin. +static const unsigned LOG_MEAN_BIN_SIZE = 2; +//This should be tuned to your processor cache; if you go too large you get cache misses on bins +//The smaller this number, the less worst-case memory usage. If too small, too many recursions slow down spreadsort +static const unsigned MAX_SPLITS = 10; +//Used to force a comparison-based sorting for small bins, if it's faster. Minimum value 0 +static const unsigned LOG_MIN_SPLIT_COUNT = 5; +//There is a minimum size below which it is not worth using spreadsort +static const long MIN_SORT_SIZE = 1000; +//This is the constant on the log base n of m calculation; make this larger the faster std::sort is relative to spreadsort +static const unsigned LOG_CONST = 2; +} +} +#endif diff --git a/system_wrappers/source/spreadsortlib/spreadsort.hpp b/system_wrappers/source/spreadsortlib/spreadsort.hpp new file mode 100644 index 000000000..2d1529aac --- /dev/null +++ b/system_wrappers/source/spreadsortlib/spreadsort.hpp @@ -0,0 +1,1688 @@ +//Templated spread_sort library + +// Copyright Steven J. Ross 2001 - 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +/* +Some improvements suggested by: +Phil Endecott and Frank Gennari +Cygwin fix provided by: +Scott McMurray +*/ + +#ifndef BOOST_SPREAD_SORT_H +#define BOOST_SPREAD_SORT_H +#include +#include +#include "constants.hpp" +#include + +namespace boost { + namespace detail { + //This only works on unsigned data types + template + inline unsigned + rough_log_2_size(const T& input) + { + unsigned result = 0; + //The && is necessary on some compilers to avoid infinite loops; it doesn't significantly impair performance + while((input >> result) && (result < (8*sizeof(T)))) ++result; + return result; + } + + //Gets the maximum size which we'll call spread_sort on to control worst-case performance + //Maintains both a minimum size to recurse and a check of distribution size versus count + //This is called for a set of bins, instead of bin-by-bin, to avoid performance overhead + inline size_t + get_max_count(unsigned log_range, size_t count) + { + unsigned divisor = rough_log_2_size(count); + //Making sure the divisor is positive + if(divisor > LOG_MEAN_BIN_SIZE) + divisor -= LOG_MEAN_BIN_SIZE; + else + divisor = 1; + unsigned relative_width = (LOG_CONST * log_range)/((divisor > MAX_SPLITS) ? MAX_SPLITS : divisor); + //Don't try to bitshift more than the size of an element + if((8*sizeof(size_t)) <= relative_width) + relative_width = (8*sizeof(size_t)) - 1; + return (size_t)1 << ((relative_width < (LOG_MEAN_BIN_SIZE + LOG_MIN_SPLIT_COUNT)) ? + (LOG_MEAN_BIN_SIZE + LOG_MIN_SPLIT_COUNT) : relative_width); + } + + //Find the minimum and maximum using < + template + inline void + find_extremes(RandomAccessIter current, RandomAccessIter last, RandomAccessIter & max, RandomAccessIter & min) + { + min = max = current; + //Start from the second item, as max and min are initialized to the first + while(++current < last) { + if(*max < *current) + max = current; + else if(*current < *min) + min = current; + } + } + + //Uses a user-defined comparison operator to find minimum and maximum + template + inline void + find_extremes(RandomAccessIter current, RandomAccessIter last, RandomAccessIter & max, RandomAccessIter & min, compare comp) + { + min = max = current; + while(++current < last) { + if(comp(*max, *current)) + max = current; + else if(comp(*current, *min)) + min = current; + } + } + + //Gets a non-negative right bit shift to operate as a logarithmic divisor + inline int + get_log_divisor(size_t count, unsigned log_range) + { + int log_divisor; + //If we can finish in one iteration without exceeding either (2 to the MAX_SPLITS) or n bins, do so + if((log_divisor = log_range - rough_log_2_size(count)) <= 0 && log_range < MAX_SPLITS) + log_divisor = 0; + else { + //otherwise divide the data into an optimized number of pieces + log_divisor += LOG_MEAN_BIN_SIZE; + if(log_divisor < 0) + log_divisor = 0; + //Cannot exceed MAX_SPLITS or cache misses slow down bin lookups dramatically + if((log_range - log_divisor) > MAX_SPLITS) + log_divisor = log_range - MAX_SPLITS; + } + return log_divisor; + } + + template + inline RandomAccessIter * + size_bins(std::vector &bin_sizes, std::vector &bin_cache, unsigned cache_offset, unsigned &cache_end, unsigned bin_count) + { + //Assure space for the size of each bin, followed by initializing sizes + if(bin_count > bin_sizes.size()) + bin_sizes.resize(bin_count); + for(size_t u = 0; u < bin_count; u++) + bin_sizes[u] = 0; + //Make sure there is space for the bins + cache_end = cache_offset + bin_count; + if(cache_end > bin_cache.size()) + bin_cache.resize(cache_end); + return &(bin_cache[cache_offset]); + } + + //Implementation for recursive integer sorting + template + inline void + spread_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes) + { + //This step is roughly 10% of runtime, but it helps avoid worst-case behavior and improve behavior with real data + //If you know the maximum and minimum ahead of time, you can pass those values in and skip this step for the first iteration + RandomAccessIter max, min; + find_extremes(first, last, max, min); + //max and min will be the same (the first item) iff all values are equivalent + if(max == min) + return; + RandomAccessIter * target_bin; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(*max >> 0) - (*min >> 0))); + div_type div_min = *min >> log_divisor; + div_type div_max = *max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin; this takes roughly 10% of runtime + for (RandomAccessIter current = first; current != last;) + bin_sizes[(*(current++) >> log_divisor) - div_min]++; + //Assign the bin positions + bins[0] = first; + for(unsigned u = 0; u < bin_count - 1; u++) + bins[u + 1] = bins[u] + bin_sizes[u]; + + //Swap into place + //This dominates runtime, mostly in the swap and bin lookups + RandomAccessIter nextbinstart = first; + for(unsigned u = 0; u < bin_count - 1; ++u) { + RandomAccessIter * local_bin = bins + u; + nextbinstart += bin_sizes[u]; + //Iterating over each element in this bin + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //Swapping elements in current into place until the correct element has been swapped in + for(target_bin = (bins + ((*current >> log_divisor) - div_min)); target_bin != local_bin; + target_bin = bins + ((*current >> log_divisor) - div_min)) { + //3-way swap; this is about 1% faster than a 2-way swap with integers + //The main advantage is less copies are involved per item put in the correct place + data_type tmp; + RandomAccessIter b = (*target_bin)++; + RandomAccessIter * b_bin = bins + ((*b >> log_divisor) - div_min); + if (b_bin != local_bin) { + RandomAccessIter c = (*b_bin)++; + tmp = *c; + *c = *b; + } + else + tmp = *b; + *b = *current; + *current = tmp; + } + } + *local_bin = nextbinstart; + } + bins[bin_count - 1] = last; + + //If we've bucketsorted, the array is sorted and we should skip recursion + if(!log_divisor) + return; + + //Recursing; log_divisor is the remaining range + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + //don't sort unless there are at least two items to compare + if(count < 2) + continue; + //using std::sort if its worst-case is better + if(count < max_count) + std::sort(lastPos, bin_cache[u]); + else + spread_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes); + } + } + + //Generic bitshift-based 3-way swapping code + template + inline void inner_swap_loop(RandomAccessIter * bins, const RandomAccessIter & nextbinstart, unsigned ii, right_shift &shift + , const unsigned log_divisor, const div_type div_min) + { + RandomAccessIter * local_bin = bins + ii; + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + for(RandomAccessIter * target_bin = (bins + (shift(*current, log_divisor) - div_min)); target_bin != local_bin; + target_bin = bins + (shift(*current, log_divisor) - div_min)) { + data_type tmp; + RandomAccessIter b = (*target_bin)++; + RandomAccessIter * b_bin = bins + (shift(*b, log_divisor) - div_min); + //Three-way swap; if the item to be swapped doesn't belong in the current bin, swap it to where it belongs + if (b_bin != local_bin) { + RandomAccessIter c = (*b_bin)++; + tmp = *c; + *c = *b; + } + //Note: we could increment current once the swap is done in this case, but that seems to impair performance + else + tmp = *b; + *b = *current; + *current = tmp; + } + } + *local_bin = nextbinstart; + } + + //Standard swapping wrapper for ascending values + template + inline void swap_loop(RandomAccessIter * bins, RandomAccessIter & nextbinstart, unsigned ii, right_shift &shift + , const std::vector &bin_sizes, const unsigned log_divisor, const div_type div_min) + { + nextbinstart += bin_sizes[ii]; + inner_swap_loop(bins, nextbinstart, ii, shift, log_divisor, div_min); + } + + //Functor implementation for recursive sorting + template + inline void + spread_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes, right_shift shift, compare comp) + { + RandomAccessIter max, min; + find_extremes(first, last, max, min, comp); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(shift(*max, 0)) - (shift(*min, 0)))); + div_type div_min = shift(*min, log_divisor); + div_type div_max = shift(*max, log_divisor); + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[shift(*(current++), log_divisor) - div_min]++; + bins[0] = first; + for(unsigned u = 0; u < bin_count - 1; u++) + bins[u + 1] = bins[u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = first; + for(unsigned u = 0; u < bin_count - 1; ++u) + swap_loop(bins, nextbinstart, u, shift, bin_sizes, log_divisor, div_min); + bins[bin_count - 1] = last; + + //If we've bucketsorted, the array is sorted and we should skip recursion + if(!log_divisor) + return; + + //Recursing + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[u], comp); + else + spread_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift, comp); + } + } + + //Functor implementation for recursive sorting with only Shift overridden + template + inline void + spread_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes, right_shift shift) + { + RandomAccessIter max, min; + find_extremes(first, last, max, min); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(shift(*max, 0)) - (shift(*min, 0)))); + div_type div_min = shift(*min, log_divisor); + div_type div_max = shift(*max, log_divisor); + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[shift(*(current++), log_divisor) - div_min]++; + bins[0] = first; + for(unsigned u = 0; u < bin_count - 1; u++) + bins[u + 1] = bins[u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = first; + for(unsigned ii = 0; ii < bin_count - 1; ++ii) + swap_loop(bins, nextbinstart, ii, shift, bin_sizes, log_divisor, div_min); + bins[bin_count - 1] = last; + + //If we've bucketsorted, the array is sorted and we should skip recursion + if(!log_divisor) + return; + + //Recursing + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[u]); + else + spread_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift); + } + } + + //Holds the bin vector and makes the initial recursive call + template + inline void + spread_sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type) + { + std::vector bin_sizes; + std::vector bin_cache; + spread_sort_rec(first, last, bin_cache, 0, bin_sizes); + } + + template + inline void + spread_sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift, compare comp) + { + std::vector bin_sizes; + std::vector bin_cache; + spread_sort_rec(first, last, bin_cache, 0, bin_sizes, shift, comp); + } + + template + inline void + spread_sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift) + { + std::vector bin_sizes; + std::vector bin_cache; + spread_sort_rec(first, last, bin_cache, 0, bin_sizes, shift); + } + } + + //Top-level sorting call for integers + template + inline void integer_sort(RandomAccessIter first, RandomAccessIter last) + { + //Don't sort if it's too small to optimize + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last); + else + detail::spread_sort(first, last, *first >> 0, *first); + } + + //integer_sort with functors + template + inline void integer_sort(RandomAccessIter first, RandomAccessIter last, + right_shift shift, compare comp) { + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last, comp); + else + detail::spread_sort(first, last, shift(*first, 0), *first, shift, comp); + } + + //integer_sort with right_shift functor + template + inline void integer_sort(RandomAccessIter first, RandomAccessIter last, + right_shift shift) { + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last); + else + detail::spread_sort(first, last, shift(*first, 0), *first, shift); + } + + //------------------------------------------------------ float_sort source -------------------------------------- + //Casts a RandomAccessIter to the specified data type + template + inline cast_type + cast_float_iter(const RandomAccessIter & floatiter) + { + cast_type result; + std::memcpy(&result, &(*floatiter), sizeof(cast_type)); + return result; + } + + //Casts a data element to the specified datinner_float_a type + template + inline cast_type + mem_cast(const data_type & data) + { + cast_type result; + std::memcpy(&result, &data, sizeof(cast_type)); + return result; + } + + namespace detail { + template + inline void + find_extremes(RandomAccessIter current, RandomAccessIter last, div_type & max, div_type & min, right_shift shift) + { + min = max = shift(*current, 0); + while(++current < last) { + div_type value = shift(*current, 0); + if(max < value) + max = value; + else if(value < min) + min = value; + } + } + + //Specialized swap loops for floating-point casting + template + inline void inner_float_swap_loop(RandomAccessIter * bins, const RandomAccessIter & nextbinstart, unsigned ii + , const unsigned log_divisor, const div_type div_min) + { + RandomAccessIter * local_bin = bins + ii; + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + for(RandomAccessIter * target_bin = (bins + ((cast_float_iter(current) >> log_divisor) - div_min)); target_bin != local_bin; + target_bin = bins + ((cast_float_iter(current) >> log_divisor) - div_min)) { + data_type tmp; + RandomAccessIter b = (*target_bin)++; + RandomAccessIter * b_bin = bins + ((cast_float_iter(b) >> log_divisor) - div_min); + //Three-way swap; if the item to be swapped doesn't belong in the current bin, swap it to where it belongs + if (b_bin != local_bin) { + RandomAccessIter c = (*b_bin)++; + tmp = *c; + *c = *b; + } + else + tmp = *b; + *b = *current; + *current = tmp; + } + } + *local_bin = nextbinstart; + } + + template + inline void float_swap_loop(RandomAccessIter * bins, RandomAccessIter & nextbinstart, unsigned ii + , const std::vector &bin_sizes, const unsigned log_divisor, const div_type div_min) + { + nextbinstart += bin_sizes[ii]; + inner_float_swap_loop(bins, nextbinstart, ii, log_divisor, div_min); + } + + template + inline void + find_extremes(RandomAccessIter current, RandomAccessIter last, cast_type & max, cast_type & min) + { + min = max = cast_float_iter(current); + while(++current < last) { + cast_type value = cast_float_iter(current); + if(max < value) + max = value; + else if(value < min) + min = value; + } + } + + //Special-case sorting of positive floats with casting instead of a right_shift + template + inline void + positive_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes) + { + div_type max, min; + find_extremes(first, last, max, min); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[(cast_float_iter(current++) >> log_divisor) - div_min]++; + bins[0] = first; + for(unsigned u = 0; u < bin_count - 1; u++) + bins[u + 1] = bins[u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = first; + for(unsigned u = 0; u < bin_count - 1; ++u) + float_swap_loop(bins, nextbinstart, u, bin_sizes, log_divisor, div_min); + bins[bin_count - 1] = last; + + //Return if we've completed bucketsorting + if(!log_divisor) + return; + + //Recursing + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(unsigned u = cache_offset; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[u]); + else + positive_float_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes); + } + } + + //Sorting negative_ float_s + //Note that bins are iterated in reverse order because max_neg_float = min_neg_int + template + inline void + negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes) + { + div_type max, min; + find_extremes(first, last, max, min); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[(cast_float_iter(current++) >> log_divisor) - div_min]++; + bins[bin_count - 1] = first; + for(int ii = bin_count - 2; ii >= 0; --ii) + bins[ii] = bins[ii + 1] + bin_sizes[ii + 1]; + + //Swap into place + RandomAccessIter nextbinstart = first; + //The last bin will always have the correct elements in it + for(int ii = bin_count - 1; ii > 0; --ii) + float_swap_loop(bins, nextbinstart, ii, bin_sizes, log_divisor, div_min); + //Since we don't process the last bin, we need to update its end position + bin_cache[cache_offset] = last; + + //Return if we've completed bucketsorting + if(!log_divisor) + return; + + //Recursing + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(int ii = cache_end - 1; ii >= (int)cache_offset; lastPos = bin_cache[ii], --ii) { + size_t count = bin_cache[ii] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[ii]); + else + negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes); + } + } + + //Sorting negative_ float_s + //Note that bins are iterated in reverse order because max_neg_float = min_neg_int + template + inline void + negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes, right_shift shift) + { + div_type max, min; + find_extremes(first, last, max, min, shift); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[shift(*(current++), log_divisor) - div_min]++; + bins[bin_count - 1] = first; + for(int ii = bin_count - 2; ii >= 0; --ii) + bins[ii] = bins[ii + 1] + bin_sizes[ii + 1]; + + //Swap into place + RandomAccessIter nextbinstart = first; + //The last bin will always have the correct elements in it + for(int ii = bin_count - 1; ii > 0; --ii) + swap_loop(bins, nextbinstart, ii, shift, bin_sizes, log_divisor, div_min); + //Since we don't process the last bin, we need to update its end position + bin_cache[cache_offset] = last; + + //Return if we've completed bucketsorting + if(!log_divisor) + return; + + //Recursing + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(int ii = cache_end - 1; ii >= (int)cache_offset; lastPos = bin_cache[ii], --ii) { + size_t count = bin_cache[ii] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[ii]); + else + negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, shift); + } + } + + template + inline void + negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes, right_shift shift, compare comp) + { + div_type max, min; + find_extremes(first, last, max, min, shift); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[shift(*(current++), log_divisor) - div_min]++; + bins[bin_count - 1] = first; + for(int ii = bin_count - 2; ii >= 0; --ii) + bins[ii] = bins[ii + 1] + bin_sizes[ii + 1]; + + //Swap into place + RandomAccessIter nextbinstart = first; + //The last bin will always have the correct elements in it + for(int ii = bin_count - 1; ii > 0; --ii) + swap_loop(bins, nextbinstart, ii, shift, bin_sizes, log_divisor, div_min); + //Since we don't process the last bin, we need to update its end position + bin_cache[cache_offset] = last; + + //Return if we've completed bucketsorting + if(!log_divisor) + return; + + //Recursing + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(int ii = cache_end - 1; ii >= (int)cache_offset; lastPos = bin_cache[ii], --ii) { + size_t count = bin_cache[ii] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[ii], comp); + else + negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, shift, comp); + } + } + + //Casting special-case for floating-point sorting + template + inline void + float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes) + { + div_type max, min; + find_extremes(first, last, max, min); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[(cast_float_iter(current++) >> log_divisor) - div_min]++; + //The index of the first positive bin + div_type first_positive = (div_min < 0) ? -div_min : 0; + //Resetting if all bins are negative + if(cache_offset + first_positive > cache_end) + first_positive = cache_end - cache_offset; + //Reversing the order of the negative bins + //Note that because of the negative/positive ordering direction flip + //We can not depend upon bin order and positions matching up + //so bin_sizes must be reused to contain the end of the bin + if(first_positive > 0) { + bins[first_positive - 1] = first; + for(int ii = first_positive - 2; ii >= 0; --ii) { + bins[ii] = first + bin_sizes[ii + 1]; + bin_sizes[ii] += bin_sizes[ii + 1]; + } + //Handling positives following negatives + if((unsigned)first_positive < bin_count) { + bins[first_positive] = first + bin_sizes[0]; + bin_sizes[first_positive] += bin_sizes[0]; + } + } + else + bins[0] = first; + for(unsigned u = first_positive; u < bin_count - 1; u++) { + bins[u + 1] = first + bin_sizes[u]; + bin_sizes[u + 1] += bin_sizes[u]; + } + + //Swap into place + RandomAccessIter nextbinstart = first; + for(unsigned u = 0; u < bin_count; ++u) { + nextbinstart = first + bin_sizes[u]; + inner_float_swap_loop(bins, nextbinstart, u, log_divisor, div_min); + } + + if(!log_divisor) + return; + + //Handling negative values first + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(int ii = cache_offset + first_positive - 1; ii >= (int)cache_offset ; lastPos = bin_cache[ii--]) { + size_t count = bin_cache[ii] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[ii]); + //sort negative values using reversed-bin spread_sort + else + negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes); + } + + for(unsigned u = cache_offset + first_positive; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[u]); + //sort positive values using normal spread_sort + else + positive_float_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes); + } + } + + //Functor implementation for recursive sorting + template + inline void + float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes, right_shift shift) + { + div_type max, min; + find_extremes(first, last, max, min, shift); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[shift(*(current++), log_divisor) - div_min]++; + //The index of the first positive bin + div_type first_positive = (div_min < 0) ? -div_min : 0; + //Resetting if all bins are negative + if(cache_offset + first_positive > cache_end) + first_positive = cache_end - cache_offset; + //Reversing the order of the negative bins + //Note that because of the negative/positive ordering direction flip + //We can not depend upon bin order and positions matching up + //so bin_sizes must be reused to contain the end of the bin + if(first_positive > 0) { + bins[first_positive - 1] = first; + for(int ii = first_positive - 2; ii >= 0; --ii) { + bins[ii] = first + bin_sizes[ii + 1]; + bin_sizes[ii] += bin_sizes[ii + 1]; + } + //Handling positives following negatives + if((unsigned)first_positive < bin_count) { + bins[first_positive] = first + bin_sizes[0]; + bin_sizes[first_positive] += bin_sizes[0]; + } + } + else + bins[0] = first; + for(unsigned u = first_positive; u < bin_count - 1; u++) { + bins[u + 1] = first + bin_sizes[u]; + bin_sizes[u + 1] += bin_sizes[u]; + } + + //Swap into place + RandomAccessIter nextbinstart = first; + for(unsigned u = 0; u < bin_count; ++u) { + nextbinstart = first + bin_sizes[u]; + inner_swap_loop(bins, nextbinstart, u, shift, log_divisor, div_min); + } + + //Return if we've completed bucketsorting + if(!log_divisor) + return; + + //Handling negative values first + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(int ii = cache_offset + first_positive - 1; ii >= (int)cache_offset ; lastPos = bin_cache[ii--]) { + size_t count = bin_cache[ii] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[ii]); + //sort negative values using reversed-bin spread_sort + else + negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, shift); + } + + for(unsigned u = cache_offset + first_positive; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[u]); + //sort positive values using normal spread_sort + else + spread_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift); + } + } + + template + inline void + float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector &bin_cache, unsigned cache_offset + , std::vector &bin_sizes, right_shift shift, compare comp) + { + div_type max, min; + find_extremes(first, last, max, min, shift); + if(max == min) + return; + unsigned log_divisor = get_log_divisor(last - first, rough_log_2_size((size_t)(max) - min)); + div_type div_min = min >> log_divisor; + div_type div_max = max >> log_divisor; + unsigned bin_count = div_max - div_min + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, bin_count); + + //Calculating the size of each bin + for (RandomAccessIter current = first; current != last;) + bin_sizes[shift(*(current++), log_divisor) - div_min]++; + //The index of the first positive bin + div_type first_positive = (div_min < 0) ? -div_min : 0; + //Resetting if all bins are negative + if(cache_offset + first_positive > cache_end) + first_positive = cache_end - cache_offset; + //Reversing the order of the negative bins + //Note that because of the negative/positive ordering direction flip + //We can not depend upon bin order and positions matching up + //so bin_sizes must be reused to contain the end of the bin + if(first_positive > 0) { + bins[first_positive - 1] = first; + for(int ii = first_positive - 2; ii >= 0; --ii) { + bins[ii] = first + bin_sizes[ii + 1]; + bin_sizes[ii] += bin_sizes[ii + 1]; + } + //Handling positives following negatives + if((unsigned)first_positive < bin_count) { + bins[first_positive] = first + bin_sizes[0]; + bin_sizes[first_positive] += bin_sizes[0]; + } + } + else + bins[0] = first; + for(unsigned u = first_positive; u < bin_count - 1; u++) { + bins[u + 1] = first + bin_sizes[u]; + bin_sizes[u + 1] += bin_sizes[u]; + } + + //Swap into place + RandomAccessIter nextbinstart = first; + for(unsigned u = 0; u < bin_count; ++u) { + nextbinstart = first + bin_sizes[u]; + inner_swap_loop(bins, nextbinstart, u, shift, log_divisor, div_min); + } + + //Return if we've completed bucketsorting + if(!log_divisor) + return; + + //Handling negative values first + size_t max_count = get_max_count(log_divisor, last - first); + RandomAccessIter lastPos = first; + for(int ii = cache_offset + first_positive - 1; ii >= (int)cache_offset ; lastPos = bin_cache[ii--]) { + size_t count = bin_cache[ii] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[ii]); + //sort negative values using reversed-bin spread_sort + else + negative_float_sort_rec(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, shift, comp); + } + + for(unsigned u = cache_offset + first_positive; u < cache_end; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + if(count < 2) + continue; + if(count < max_count) + std::sort(lastPos, bin_cache[u]); + //sort positive values using normal spread_sort + else + spread_sort_rec(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift, comp); + } + } + + template + inline void + float_Sort(RandomAccessIter first, RandomAccessIter last, cast_type, data_type) + { + std::vector bin_sizes; + std::vector bin_cache; + float_sort_rec(first, last, bin_cache, 0, bin_sizes); + } + + template + inline void + float_Sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift) + { + std::vector bin_sizes; + std::vector bin_cache; + float_sort_rec(first, last, bin_cache, 0, bin_sizes, shift); + } + + template + inline void + float_Sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift, compare comp) + { + std::vector bin_sizes; + std::vector bin_cache; + float_sort_rec(first, last, bin_cache, 0, bin_sizes, shift, comp); + } + } + + //float_sort with casting + //The cast_type must be equal in size to the data type, and must be a signed integer + template + inline void float_sort_cast(RandomAccessIter first, RandomAccessIter last, cast_type cVal) + { + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last); + else + detail::float_Sort(first, last, cVal, *first); + } + + //float_sort with casting to an int + //Only use this with IEEE floating-point numbers + template + inline void float_sort_cast_to_int(RandomAccessIter first, RandomAccessIter last) + { + int cVal = 0; + float_sort_cast(first, last, cVal); + } + + //float_sort with functors + template + inline void float_sort(RandomAccessIter first, RandomAccessIter last, right_shift shift) + { + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last); + else + detail::float_Sort(first, last, shift(*first, 0), *first, shift); + } + + template + inline void float_sort(RandomAccessIter first, RandomAccessIter last, right_shift shift, compare comp) + { + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last, comp); + else + detail::float_Sort(first, last, shift(*first, 0), *first, shift, comp); + } + + //------------------------------------------------- string_sort source --------------------------------------------- + namespace detail { + //Offsetting on identical characters. This function works a character at a time for optimal worst-case performance. + template + inline void + update_offset(RandomAccessIter first, RandomAccessIter finish, unsigned &char_offset) + { + unsigned nextOffset = char_offset; + bool done = false; + while(!done) { + RandomAccessIter curr = first; + do { + //ignore empties, but if the nextOffset would exceed the length or not match, exit; we've found the last matching character + if((*curr).size() > char_offset && ((*curr).size() <= (nextOffset + 1) || (*curr)[nextOffset] != (*first)[nextOffset])) { + done = true; + break; + } + } while(++curr != finish); + if(!done) + ++nextOffset; + } + char_offset = nextOffset; + } + + //Offsetting on identical characters. This function works a character at a time for optimal worst-case performance. + template + inline void + update_offset(RandomAccessIter first, RandomAccessIter finish, unsigned &char_offset, get_char getchar, get_length length) + { + unsigned nextOffset = char_offset; + bool done = false; + while(!done) { + RandomAccessIter curr = first; + do { + //ignore empties, but if the nextOffset would exceed the length or not match, exit; we've found the last matching character + if(length(*curr) > char_offset && (length(*curr) <= (nextOffset + 1) || getchar((*curr), nextOffset) != getchar((*first), nextOffset))) { + done = true; + break; + } + } while(++curr != finish); + if(!done) + ++nextOffset; + } + char_offset = nextOffset; + } + + //A comparison functor for strings that assumes they are identical up to char_offset + template + struct offset_lessthan { + offset_lessthan(unsigned char_offset) : fchar_offset(char_offset){} + inline bool operator()(const data_type &x, const data_type &y) const + { + unsigned minSize = std::min(x.size(), y.size()); + for(unsigned u = fchar_offset; u < minSize; ++u) { + if(static_cast(x[u]) < static_cast(y[u])) + return true; + else if(static_cast(y[u]) < static_cast(x[u])) + return false; + } + return x.size() < y.size(); + } + unsigned fchar_offset; + }; + + //A comparison functor for strings that assumes they are identical up to char_offset + template + struct offset_greaterthan { + offset_greaterthan(unsigned char_offset) : fchar_offset(char_offset){} + inline bool operator()(const data_type &x, const data_type &y) const + { + unsigned minSize = std::min(x.size(), y.size()); + for(unsigned u = fchar_offset; u < minSize; ++u) { + if(static_cast(x[u]) > static_cast(y[u])) + return true; + else if(static_cast(y[u]) > static_cast(x[u])) + return false; + } + return x.size() > y.size(); + } + unsigned fchar_offset; + }; + + //A comparison functor for strings that assumes they are identical up to char_offset + template + struct offset_char_lessthan { + offset_char_lessthan(unsigned char_offset) : fchar_offset(char_offset){} + inline bool operator()(const data_type &x, const data_type &y) const + { + unsigned minSize = std::min(length(x), length(y)); + for(unsigned u = fchar_offset; u < minSize; ++u) { + if(getchar(x, u) < getchar(y, u)) + return true; + else if(getchar(y, u) < getchar(x, u)) + return false; + } + return length(x) < length(y); + } + unsigned fchar_offset; + get_char getchar; + get_length length; + }; + + //String sorting recursive implementation + template + inline void + string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector &bin_cache + , unsigned cache_offset, std::vector &bin_sizes) + { + //This section is not strictly necessary, but makes handling of long identical substrings much faster, with a mild average performance impact. + //Iterate to the end of the empties. If all empty, return + while((*first).size() <= char_offset) { + if(++first == last) + return; + } + RandomAccessIter finish = last - 1; + //Getting the last non-empty + for(;(*finish).size() <= char_offset; --finish) { } + ++finish; + //Offsetting on identical characters. This section works a character at a time for optimal worst-case performance. + update_offset(first, finish, char_offset); + + const unsigned bin_count = (1 << (sizeof(unsignedchar_type)*8)); + //Equal worst-case between radix and comparison-based is when bin_count = n*log(n). + const unsigned max_size = bin_count; + const unsigned membin_count = bin_count + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, membin_count) + 1; + + //Calculating the size of each bin; this takes roughly 10% of runtime + for (RandomAccessIter current = first; current != last; ++current) { + if((*current).size() <= char_offset) { + bin_sizes[0]++; + } + else + bin_sizes[static_cast((*current)[char_offset]) + 1]++; + } + //Assign the bin positions + bin_cache[cache_offset] = first; + for(unsigned u = 0; u < membin_count - 1; u++) + bin_cache[cache_offset + u + 1] = bin_cache[cache_offset + u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = first; + //handling empty bins + RandomAccessIter * local_bin = &(bin_cache[cache_offset]); + nextbinstart += bin_sizes[0]; + RandomAccessIter * target_bin; + //Iterating over each element in the bin of empties + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //empties belong in this bin + while((*current).size() > char_offset) { + target_bin = bins + static_cast((*current)[char_offset]); + iter_swap(current, (*target_bin)++); + } + } + *local_bin = nextbinstart; + //iterate backwards to find the last bin with elements in it; this saves iterations in multiple loops + unsigned last_bin = bin_count - 1; + for(; last_bin && !bin_sizes[last_bin + 1]; --last_bin) { } + //This dominates runtime, mostly in the swap and bin lookups + for(unsigned u = 0; u < last_bin; ++u) { + local_bin = bins + u; + nextbinstart += bin_sizes[u + 1]; + //Iterating over each element in this bin + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //Swapping elements in current into place until the correct element has been swapped in + for(target_bin = bins + static_cast((*current)[char_offset]); target_bin != local_bin; + target_bin = bins + static_cast((*current)[char_offset])) + iter_swap(current, (*target_bin)++); + } + *local_bin = nextbinstart; + } + bins[last_bin] = last; + //Recursing + RandomAccessIter lastPos = bin_cache[cache_offset]; + //Skip this loop for empties + for(unsigned u = cache_offset + 1; u < cache_offset + last_bin + 2; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + //don't sort unless there are at least two items to compare + if(count < 2) + continue; + //using std::sort if its worst-case is better + if(count < max_size) + std::sort(lastPos, bin_cache[u], offset_lessthan(char_offset + 1)); + else + string_sort_rec(lastPos, bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes); + } + } + + //Sorts strings in reverse order, with empties at the end + template + inline void + reverse_string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector &bin_cache + , unsigned cache_offset, std::vector &bin_sizes) + { + //This section is not strictly necessary, but makes handling of long identical substrings much faster, with a mild average performance impact. + RandomAccessIter curr = first; + //Iterate to the end of the empties. If all empty, return + while((*curr).size() <= char_offset) { + if(++curr == last) + return; + } + //Getting the last non-empty + while((*(--last)).size() <= char_offset) { } + ++last; + //Offsetting on identical characters. This section works a character at a time for optimal worst-case performance. + update_offset(curr, last, char_offset); + RandomAccessIter * target_bin; + + const unsigned bin_count = (1 << (sizeof(unsignedchar_type)*8)); + //Equal worst-case between radix and comparison-based is when bin_count = n*log(n). + const unsigned max_size = bin_count; + const unsigned membin_count = bin_count + 1; + const unsigned max_bin = bin_count - 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, membin_count); + RandomAccessIter * end_bin = &(bin_cache[cache_offset + max_bin]); + + //Calculating the size of each bin; this takes roughly 10% of runtime + for (RandomAccessIter current = first; current != last; ++current) { + if((*current).size() <= char_offset) { + bin_sizes[bin_count]++; + } + else + bin_sizes[max_bin - static_cast((*current)[char_offset])]++; + } + //Assign the bin positions + bin_cache[cache_offset] = first; + for(unsigned u = 0; u < membin_count - 1; u++) + bin_cache[cache_offset + u + 1] = bin_cache[cache_offset + u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = last; + //handling empty bins + RandomAccessIter * local_bin = &(bin_cache[cache_offset + bin_count]); + RandomAccessIter lastFull = *local_bin; + //Iterating over each element in the bin of empties + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //empties belong in this bin + while((*current).size() > char_offset) { + target_bin = end_bin - static_cast((*current)[char_offset]); + iter_swap(current, (*target_bin)++); + } + } + *local_bin = nextbinstart; + nextbinstart = first; + //iterate backwards to find the last bin with elements in it; this saves iterations in multiple loops + unsigned last_bin = max_bin; + for(; last_bin && !bin_sizes[last_bin]; --last_bin) { } + //This dominates runtime, mostly in the swap and bin lookups + for(unsigned u = 0; u < last_bin; ++u) { + local_bin = bins + u; + nextbinstart += bin_sizes[u]; + //Iterating over each element in this bin + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //Swapping elements in current into place until the correct element has been swapped in + for(target_bin = end_bin - static_cast((*current)[char_offset]); target_bin != local_bin; + target_bin = end_bin - static_cast((*current)[char_offset])) + iter_swap(current, (*target_bin)++); + } + *local_bin = nextbinstart; + } + bins[last_bin] = lastFull; + //Recursing + RandomAccessIter lastPos = first; + //Skip this loop for empties + for(unsigned u = cache_offset; u <= cache_offset + last_bin; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + //don't sort unless there are at least two items to compare + if(count < 2) + continue; + //using std::sort if its worst-case is better + if(count < max_size) + std::sort(lastPos, bin_cache[u], offset_greaterthan(char_offset + 1)); + else + reverse_string_sort_rec(lastPos, bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes); + } + } + + //String sorting recursive implementation + template + inline void + string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector &bin_cache + , unsigned cache_offset, std::vector &bin_sizes, get_char getchar, get_length length) + { + //This section is not strictly necessary, but makes handling of long identical substrings much faster, with a mild average performance impact. + //Iterate to the end of the empties. If all empty, return + while(length(*first) <= char_offset) { + if(++first == last) + return; + } + RandomAccessIter finish = last - 1; + //Getting the last non-empty + for(;length(*finish) <= char_offset; --finish) { } + ++finish; + update_offset(first, finish, char_offset, getchar, length); + + const unsigned bin_count = (1 << (sizeof(unsignedchar_type)*8)); + //Equal worst-case between radix and comparison-based is when bin_count = n*log(n). + const unsigned max_size = bin_count; + const unsigned membin_count = bin_count + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, membin_count) + 1; + + //Calculating the size of each bin; this takes roughly 10% of runtime + for (RandomAccessIter current = first; current != last; ++current) { + if(length(*current) <= char_offset) { + bin_sizes[0]++; + } + else + bin_sizes[getchar((*current), char_offset) + 1]++; + } + //Assign the bin positions + bin_cache[cache_offset] = first; + for(unsigned u = 0; u < membin_count - 1; u++) + bin_cache[cache_offset + u + 1] = bin_cache[cache_offset + u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = first; + //handling empty bins + RandomAccessIter * local_bin = &(bin_cache[cache_offset]); + nextbinstart += bin_sizes[0]; + RandomAccessIter * target_bin; + //Iterating over each element in the bin of empties + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //empties belong in this bin + while(length(*current) > char_offset) { + target_bin = bins + getchar((*current), char_offset); + iter_swap(current, (*target_bin)++); + } + } + *local_bin = nextbinstart; + //iterate backwards to find the last bin with elements in it; this saves iterations in multiple loops + unsigned last_bin = bin_count - 1; + for(; last_bin && !bin_sizes[last_bin + 1]; --last_bin) { } + //This dominates runtime, mostly in the swap and bin lookups + for(unsigned ii = 0; ii < last_bin; ++ii) { + local_bin = bins + ii; + nextbinstart += bin_sizes[ii + 1]; + //Iterating over each element in this bin + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //Swapping elements in current into place until the correct element has been swapped in + for(target_bin = bins + getchar((*current), char_offset); target_bin != local_bin; + target_bin = bins + getchar((*current), char_offset)) + iter_swap(current, (*target_bin)++); + } + *local_bin = nextbinstart; + } + bins[last_bin] = last; + + //Recursing + RandomAccessIter lastPos = bin_cache[cache_offset]; + //Skip this loop for empties + for(unsigned u = cache_offset + 1; u < cache_offset + last_bin + 2; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + //don't sort unless there are at least two items to compare + if(count < 2) + continue; + //using std::sort if its worst-case is better + if(count < max_size) + std::sort(lastPos, bin_cache[u], offset_char_lessthan(char_offset + 1)); + else + string_sort_rec(lastPos, bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes, getchar, length); + } + } + + //String sorting recursive implementation + template + inline void + string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector &bin_cache + , unsigned cache_offset, std::vector &bin_sizes, get_char getchar, get_length length, compare comp) + { + //This section is not strictly necessary, but makes handling of long identical substrings much faster, with a mild average performance impact. + //Iterate to the end of the empties. If all empty, return + while(length(*first) <= char_offset) { + if(++first == last) + return; + } + RandomAccessIter finish = last - 1; + //Getting the last non-empty + for(;length(*finish) <= char_offset; --finish) { } + ++finish; + update_offset(first, finish, char_offset, getchar, length); + + const unsigned bin_count = (1 << (sizeof(unsignedchar_type)*8)); + //Equal worst-case between radix and comparison-based is when bin_count = n*log(n). + const unsigned max_size = bin_count; + const unsigned membin_count = bin_count + 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, membin_count) + 1; + + //Calculating the size of each bin; this takes roughly 10% of runtime + for (RandomAccessIter current = first; current != last; ++current) { + if(length(*current) <= char_offset) { + bin_sizes[0]++; + } + else + bin_sizes[getchar((*current), char_offset) + 1]++; + } + //Assign the bin positions + bin_cache[cache_offset] = first; + for(unsigned u = 0; u < membin_count - 1; u++) + bin_cache[cache_offset + u + 1] = bin_cache[cache_offset + u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = first; + //handling empty bins + RandomAccessIter * local_bin = &(bin_cache[cache_offset]); + nextbinstart += bin_sizes[0]; + RandomAccessIter * target_bin; + //Iterating over each element in the bin of empties + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //empties belong in this bin + while(length(*current) > char_offset) { + target_bin = bins + getchar((*current), char_offset); + iter_swap(current, (*target_bin)++); + } + } + *local_bin = nextbinstart; + //iterate backwards to find the last bin with elements in it; this saves iterations in multiple loops + unsigned last_bin = bin_count - 1; + for(; last_bin && !bin_sizes[last_bin + 1]; --last_bin) { } + //This dominates runtime, mostly in the swap and bin lookups + for(unsigned u = 0; u < last_bin; ++u) { + local_bin = bins + u; + nextbinstart += bin_sizes[u + 1]; + //Iterating over each element in this bin + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //Swapping elements in current into place until the correct element has been swapped in + for(target_bin = bins + getchar((*current), char_offset); target_bin != local_bin; + target_bin = bins + getchar((*current), char_offset)) + iter_swap(current, (*target_bin)++); + } + *local_bin = nextbinstart; + } + bins[last_bin] = last; + + //Recursing + RandomAccessIter lastPos = bin_cache[cache_offset]; + //Skip this loop for empties + for(unsigned u = cache_offset + 1; u < cache_offset + last_bin + 2; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + //don't sort unless there are at least two items to compare + if(count < 2) + continue; + //using std::sort if its worst-case is better + if(count < max_size) + std::sort(lastPos, bin_cache[u], comp); + else + string_sort_rec(lastPos + , bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes, getchar, length, comp); + } + } + + //Sorts strings in reverse order, with empties at the end + template + inline void + reverse_string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector &bin_cache + , unsigned cache_offset, std::vector &bin_sizes, get_char getchar, get_length length, compare comp) + { + //This section is not strictly necessary, but makes handling of long identical substrings much faster, with a mild average performance impact. + RandomAccessIter curr = first; + //Iterate to the end of the empties. If all empty, return + while(length(*curr) <= char_offset) { + if(++curr == last) + return; + } + //Getting the last non-empty + while(length(*(--last)) <= char_offset) { } + ++last; + //Offsetting on identical characters. This section works a character at a time for optimal worst-case performance. + update_offset(first, last, char_offset, getchar, length); + + const unsigned bin_count = (1 << (sizeof(unsignedchar_type)*8)); + //Equal worst-case between radix and comparison-based is when bin_count = n*log(n). + const unsigned max_size = bin_count; + const unsigned membin_count = bin_count + 1; + const unsigned max_bin = bin_count - 1; + unsigned cache_end; + RandomAccessIter * bins = size_bins(bin_sizes, bin_cache, cache_offset, cache_end, membin_count); + RandomAccessIter *end_bin = &(bin_cache[cache_offset + max_bin]); + + //Calculating the size of each bin; this takes roughly 10% of runtime + for (RandomAccessIter current = first; current != last; ++current) { + if(length(*current) <= char_offset) { + bin_sizes[bin_count]++; + } + else + bin_sizes[max_bin - getchar((*current), char_offset)]++; + } + //Assign the bin positions + bin_cache[cache_offset] = first; + for(unsigned u = 0; u < membin_count - 1; u++) + bin_cache[cache_offset + u + 1] = bin_cache[cache_offset + u] + bin_sizes[u]; + + //Swap into place + RandomAccessIter nextbinstart = last; + //handling empty bins + RandomAccessIter * local_bin = &(bin_cache[cache_offset + bin_count]); + RandomAccessIter lastFull = *local_bin; + RandomAccessIter * target_bin; + //Iterating over each element in the bin of empties + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //empties belong in this bin + while(length(*current) > char_offset) { + target_bin = end_bin - getchar((*current), char_offset); + iter_swap(current, (*target_bin)++); + } + } + *local_bin = nextbinstart; + nextbinstart = first; + //iterate backwards to find the last bin with elements in it; this saves iterations in multiple loops + unsigned last_bin = max_bin; + for(; last_bin && !bin_sizes[last_bin]; --last_bin) { } + //This dominates runtime, mostly in the swap and bin lookups + for(unsigned u = 0; u < last_bin; ++u) { + local_bin = bins + u; + nextbinstart += bin_sizes[u]; + //Iterating over each element in this bin + for(RandomAccessIter current = *local_bin; current < nextbinstart; ++current) { + //Swapping elements in current into place until the correct element has been swapped in + for(target_bin = end_bin - getchar((*current), char_offset); target_bin != local_bin; + target_bin = end_bin - getchar((*current), char_offset)) + iter_swap(current, (*target_bin)++); + } + *local_bin = nextbinstart; + } + bins[last_bin] = lastFull; + //Recursing + RandomAccessIter lastPos = first; + //Skip this loop for empties + for(unsigned u = cache_offset; u <= cache_offset + last_bin; lastPos = bin_cache[u], ++u) { + size_t count = bin_cache[u] - lastPos; + //don't sort unless there are at least two items to compare + if(count < 2) + continue; + //using std::sort if its worst-case is better + if(count < max_size) + std::sort(lastPos, bin_cache[u], comp); + else + reverse_string_sort_rec(lastPos + , bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes, getchar, length, comp); + } + } + + //Holds the bin vector and makes the initial recursive call + template + inline void + string_sort(RandomAccessIter first, RandomAccessIter last, data_type, unsignedchar_type) + { + std::vector bin_sizes; + std::vector bin_cache; + string_sort_rec(first, last, 0, bin_cache, 0, bin_sizes); + } + + //Holds the bin vector and makes the initial recursive call + template + inline void + reverse_string_sort(RandomAccessIter first, RandomAccessIter last, data_type, unsignedchar_type) + { + std::vector bin_sizes; + std::vector bin_cache; + reverse_string_sort_rec(first, last, 0, bin_cache, 0, bin_sizes); + } + + //Holds the bin vector and makes the initial recursive call + template + inline void + string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, data_type, unsignedchar_type) + { + std::vector bin_sizes; + std::vector bin_cache; + string_sort_rec(first, last, 0, bin_cache, 0, bin_sizes, getchar, length); + } + + //Holds the bin vector and makes the initial recursive call + template + inline void + string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, compare comp, data_type, unsignedchar_type) + { + std::vector bin_sizes; + std::vector bin_cache; + string_sort_rec(first, last, 0, bin_cache, 0, bin_sizes, getchar, length, comp); + } + + //Holds the bin vector and makes the initial recursive call + template + inline void + reverse_string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, compare comp, data_type, unsignedchar_type) + { + std::vector bin_sizes; + std::vector bin_cache; + reverse_string_sort_rec(first, last, 0, bin_cache, 0, bin_sizes, getchar, length, comp); + } + } + + //Allows character-type overloads + template + inline void string_sort(RandomAccessIter first, RandomAccessIter last, unsignedchar_type unused) + { + //Don't sort if it's too small to optimize + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last); + else + detail::string_sort(first, last, *first, unused); + } + + //Top-level sorting call; wraps using default of unsigned char + template + inline void string_sort(RandomAccessIter first, RandomAccessIter last) + { + unsigned char unused = '\0'; + string_sort(first, last, unused); + } + + //Allows character-type overloads + template + inline void reverse_string_sort(RandomAccessIter first, RandomAccessIter last, compare comp, unsignedchar_type unused) + { + //Don't sort if it's too small to optimize + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last, comp); + else + detail::reverse_string_sort(first, last, *first, unused); + } + + //Top-level sorting call; wraps using default of unsigned char + template + inline void reverse_string_sort(RandomAccessIter first, RandomAccessIter last, compare comp) + { + unsigned char unused = '\0'; + reverse_string_sort(first, last, comp, unused); + } + + template + inline void string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length) + { + //Don't sort if it's too small to optimize + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last); + else { + //skipping past empties at the beginning, which allows us to get the character type + //.empty() is not used so as not to require a user declaration of it + while(!length(*first)) { + if(++first == last) + return; + } + detail::string_sort(first, last, getchar, length, *first, getchar((*first), 0)); + } + } + + template + inline void string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, compare comp) + { + //Don't sort if it's too small to optimize + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last, comp); + else { + //skipping past empties at the beginning, which allows us to get the character type + //.empty() is not used so as not to require a user declaration of it + while(!length(*first)) { + if(++first == last) + return; + } + detail::string_sort(first, last, getchar, length, comp, *first, getchar((*first), 0)); + } + } + + template + inline void reverse_string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, compare comp) + { + //Don't sort if it's too small to optimize + if(last - first < detail::MIN_SORT_SIZE) + std::sort(first, last, comp); + else { + //skipping past empties at the beginning, which allows us to get the character type + //.empty() is not used so as not to require a user declaration of it + while(!length(*(--last))) { + //Note: if there is just one non-empty, and it's at the beginning, then it's already in sorted order + if(first == last) + return; + } + //making last just after the end of the non-empty part of the array + ++last; + detail::reverse_string_sort(first, last, getchar, length, comp, *first, getchar((*first), 0)); + } + } +} + +#endif diff --git a/system_wrappers/source/system_wrappers.gyp b/system_wrappers/source/system_wrappers.gyp new file mode 100644 index 000000000..044894179 --- /dev/null +++ b/system_wrappers/source/system_wrappers.gyp @@ -0,0 +1,146 @@ +# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# TODO: Rename files to use *_linux.cpp etc. names, to automatically include relevant files. Remove conditions section. + +{ + 'includes': [ + '../../common_settings.gypi', # Common settings + ], + 'targets': [ + { + 'target_name': 'system_wrappers', + 'type': '<(library)', + 'include_dirs': [ + 'spreadsortlib', + '../interface', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../interface', + ], + }, + 'sources': [ + '../interface/aligned_malloc.h', + '../interface/atomic32_wrapper.h', + '../interface/condition_variable_wrapper.h', + '../interface/cpu_wrapper.h', + '../interface/cpu_features_wrapper.h', + '../interface/critical_section_wrapper.h', + '../interface/event_wrapper.h', + '../interface/file_wrapper.h', + '../interface/list_wrapper.h', + '../interface/map_wrapper.h', + '../interface/rw_lock_wrapper.h', + '../interface/sort.h', + '../interface/thread_wrapper.h', + '../interface/tick_util.h', + '../interface/trace.h', + 'aligned_malloc.cc', + 'atomic32.cc', + 'atomic32_linux.h', + 'atomic32_mac.h', + 'atomic32_windows.h', + 'condition_variable.cc', + 'condition_variable_linux.h', + 'condition_variable_windows.h', + 'cpu.cc', + 'cpu_linux.h', + 'cpu_mac.h', + 'cpu_windows.h', + 'cpu_features.cc', + 'critical_section.cc', + 'critical_section_linux.h', + 'critical_section_windows.h', + 'event.cc', + 'event_linux.h', + 'event_windows.h', + 'file_impl.cc', + 'file_impl.h', + 'list_no_stl.cc', + 'map.cc', + 'rw_lock.cc', + 'rw_lock_linux.h', + 'rw_lock_windows.h', + 'sort.cc', + 'thread.cc', + 'thread_linux.h', + 'thread_windows.h', + 'trace_impl.cc', + 'trace_impl.h', + 'trace_linux.h', + 'trace_windows.h', + ], + 'conditions': [ + ['OS=="linux"', { + 'sources': [ + 'condition_variable_linux.cc', + 'cpu_linux.cc', + 'critical_section_linux.cc', + 'event_linux.cc', + 'thread_linux.cc', + 'trace_linux.cc', + 'rw_lock_linux.cc', + ], + 'link_settings': { + 'libraries': [ + '-lrt', + ], + }, + }], + ['OS=="mac"', { + 'sources': [ + 'condition_variable_linux.cc', + 'cpu_mac.cc', + 'critical_section_linux.cc', + 'event_linux.cc', + 'rw_lock_linux.cc', + 'thread_linux.cc', + 'trace_linux.cc', + ], + }], + ['OS=="win"', { + 'sources': [ + 'atomic32_windows.h', + 'condition_variable_windows.cc', + 'condition_variable_windows.h', + 'cpu_windows.cc', + 'cpu_windows.h', + 'critical_section_windows.cc', + 'critical_section_windows.h', + 'event_windows.cc', + 'event_windows.h', + 'rw_lock_windows.cc', + 'rw_lock_windows.h', + 'thread_windows.cc', + 'thread_windows.h', + 'trace_windows.cc', + 'trace_windows.h', + ], + 'link_settings': { + 'libraries': [ + '-lwinmm.lib', + ], + }, + }], + ] # conditions + }, + { + 'target_name': 'system_wrappersTest', + 'type': 'executable', + 'dependencies': [ + 'system_wrappers' + ], + 'sources': [ + '../test/Test.cpp', + ], + }, + ], # targets +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/system_wrappers/source/thread.cc b/system_wrappers/source/thread.cc new file mode 100644 index 000000000..a136cbaf1 --- /dev/null +++ b/system_wrappers/source/thread.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "thread_wrapper.h" + +#if defined(_WIN32) + #include "thread_windows.h" +#else + #include "thread_linux.h" +#endif + +namespace webrtc { +ThreadWrapper* ThreadWrapper::CreateThread(ThreadRunFunction func, + ThreadObj obj, ThreadPriority prio, + const char* threadName) +{ +#if defined(_WIN32) + return new ThreadWindows(func, obj, prio, threadName); +#else + return ThreadLinux::Create(func, obj, prio, threadName); +#endif +} +} // namespace webrtc diff --git a/system_wrappers/source/thread_linux.cc b/system_wrappers/source/thread_linux.cc new file mode 100644 index 000000000..1281c1b0d --- /dev/null +++ b/system_wrappers/source/thread_linux.cc @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "thread_linux.h" + +#include +#include // strncpy +#include // nanosleep +#include +#ifdef WEBRTC_LINUX +#include +#include +#include +#include +#include +#endif + +#include "event_wrapper.h" +#include "trace.h" + +namespace webrtc { +extern "C" +{ + static void* StartThread(void* lpParameter) + { + static_cast(lpParameter)->Run(); + return 0; + } +} + +#if (defined(WEBRTC_LINUX) && !defined(ANDROID)) +static pid_t gettid() +{ +#if defined(__NR_gettid) + return syscall(__NR_gettid); +#else + return -1; +#endif +} +#endif + +ThreadWrapper* ThreadLinux::Create(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* threadName) +{ + ThreadLinux* ptr = new ThreadLinux(func, obj, prio, threadName); + if (!ptr) + { + return NULL; + } + const int error = ptr->Construct(); + if (error) + { + delete ptr; + return NULL; + } + return ptr; +} + +ThreadLinux::ThreadLinux(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* threadName) + : _runFunction(func), + _obj(obj), + _alive(false), + _dead(true), + _prio(prio), + _event(EventWrapper::Create()), + _setThreadName(false) +{ +#ifdef WEBRTC_LINUX + _linuxPid = -1; +#endif + if (threadName != NULL) + { + _setThreadName = true; + strncpy(_name, threadName, kThreadMaxNameLength); + } +} + +int ThreadLinux::Construct() +{ + int result = 0; +#if !defined(ANDROID) + // Enable immediate cancellation if requested, see Shutdown() + result = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + if (result != 0) + { + return -1; + } + result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + if (result != 0) + { + return -1; + } +#endif + result = pthread_attr_init(&_attr); + if (result != 0) + { + return -1; + } + + return 0; +} + +ThreadLinux::~ThreadLinux() +{ + pthread_attr_destroy(&_attr); + delete _event; +} + +#define HAS_THREAD_ID !defined(MAC_IPHONE) && !defined(MAC_IPHONE_SIM) && \ + !defined(WEBRTC_MAC) && !defined(WEBRTC_MAC_INTEL) && \ + !defined(MAC_DYLIB) && !defined(MAC_INTEL_DYLIB) +#if HAS_THREAD_ID +bool ThreadLinux::Start(unsigned int& threadID) +#else +bool ThreadLinux::Start(unsigned int& /*threadID*/) +#endif +{ + if (!_runFunction) + { + return false; + } + int result = pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_DETACHED); + // Set the stack stack size to 1M. + result |= pthread_attr_setstacksize(&_attr, 1024*1024); +#ifdef WEBRTC_THREAD_RR + const int policy = SCHED_RR; +#else + const int policy = SCHED_FIFO; +#endif + _event->Reset(); + result |= pthread_create(&_thread, &_attr, &StartThread, this); + if (result != 0) + { + return false; + } + + // Wait up to 10 seconds for the OS to call the callback function. Prevents + // race condition if Stop() is called too quickly after start. + if (kEventSignaled != _event->Wait(WEBRTC_EVENT_10_SEC)) + { + // Timed out. Something went wrong. + _runFunction = NULL; + return false; + } + +#if HAS_THREAD_ID + threadID = static_cast(_thread); +#endif + sched_param param; + + const int minPrio = sched_get_priority_min(policy); + const int maxPrio = sched_get_priority_max(policy); + if ((minPrio == EINVAL) || (maxPrio == EINVAL)) + { + return false; + } + + switch (_prio) + { + case kLowPriority: + param.sched_priority = minPrio + 1; + break; + case kNormalPriority: + param.sched_priority = (minPrio + maxPrio) / 2; + break; + case kHighPriority: + param.sched_priority = maxPrio - 3; + break; + case kHighestPriority: + param.sched_priority = maxPrio - 2; + break; + case kRealtimePriority: + param.sched_priority = maxPrio - 1; + break; + default: + return false; + } + result = pthread_setschedparam(_thread, policy, ¶m); + if (result == EINVAL) + { + return false; + } + return true; +} + +#if (defined(WEBRTC_LINUX) && !defined(ANDROID)) +bool ThreadLinux::SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors) +{ + if (!processorNumbers || (amountOfProcessors == 0)) + { + return false; + } + + cpu_set_t mask; + CPU_ZERO(&mask); + + for(unsigned int processor = 0; + processor < amountOfProcessors; + processor++) + { + CPU_SET(processorNumbers[processor], &mask); + } + const int result = sched_setaffinity(_linuxPid, (unsigned int)sizeof(mask), + &mask); + if (result != 0) + { + return false; + + } + return true; +} +#else +// NOTE: On Mac OS X, use the Thread affinity API in +// /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self() +// instead of Linux gettid() syscall. +bool ThreadLinux::SetAffinity(const int* , const unsigned int) +{ + return false; +} +#endif + +void ThreadLinux::SetNotAlive() +{ + _alive = false; +} + +bool ThreadLinux::Shutdown() +{ +#if !defined(ANDROID) + if (_thread && (0 != pthread_cancel(_thread))) + { + return false; + } + + return true; +#else + return false; +#endif +} + +bool ThreadLinux::Stop() +{ + _alive = false; + + // TODO (hellner) why not use an event here? + // Wait up to 10 seconds for the thread to terminate + for (int i = 0; i < 1000 && !_dead; i++) + { + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10*1000*1000; + nanosleep(&t, NULL); + } + if (_dead) + { + return true; + } + else + { + return false; + } +} + +void ThreadLinux::Run() +{ + _alive = true; + _dead = false; +#ifdef WEBRTC_LINUX + if(_linuxPid == -1) + { + _linuxPid = gettid(); + } +#endif + // The event the Start() is waiting for. + _event->Set(); + + if (_setThreadName) + { +#ifdef WEBRTC_LINUX + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, + "Thread with id:%d name:%s started ", _linuxPid, _name); + prctl(PR_SET_NAME, (unsigned long)_name, 0, 0, 0); +#else + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, + "Thread with name:%s started ", _name); +#endif + }else + { +#ifdef WEBRTC_LINUX + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Thread with id:%d without name started", _linuxPid); +#else + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Thread without name started"); +#endif + } + do + { + if (_runFunction) + { + if (!_runFunction(_obj)) + { + _alive = false; + } + } + else + { + _alive = false; + } + } + while (_alive); + + if (_setThreadName) + { + // Don't set the name for the trace thread because it may cause a + // deadlock. TODO (hellner) there should be a better solution than + // coupling the thread and the trace class like this. + if (strcmp(_name, "Trace")) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, + "Thread with name:%s stopped", _name); + } + } + else + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, + "Thread without name stopped"); + } + _dead = true; +} +} // namespace webrtc diff --git a/system_wrappers/source/thread_linux.h b/system_wrappers/source/thread_linux.h new file mode 100644 index 000000000..3e2b90806 --- /dev/null +++ b/system_wrappers/source/thread_linux.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_LINUX_H_ + +#include "thread_wrapper.h" +#include + +namespace webrtc { +class EventWrapper; + +class ThreadLinux : public ThreadWrapper +{ +public: + static ThreadWrapper* Create(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* threadName); + + ThreadLinux(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, + const char* threadName); + ~ThreadLinux(); + + // From ThreadWrapper + virtual void SetNotAlive(); + virtual bool Start(unsigned int& id); + // Not implemented on Mac + virtual bool SetAffinity(const int* processorNumbers, + unsigned int amountOfProcessors); + virtual bool Stop(); + virtual bool Shutdown(); + + void Run(); + +private: + int Construct(); + +private: + // processing function + ThreadRunFunction _runFunction; + ThreadObj _obj; + + // internal state + bool _alive; + bool _dead; + ThreadPriority _prio; + EventWrapper* _event; + + // zero-terminated thread name string + char _name[kThreadMaxNameLength]; + bool _setThreadName; + + // handle to thread + pthread_attr_t _attr; + pthread_t _thread; +#ifdef WEBRTC_LINUX + pid_t _linuxPid; +#endif + +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_LINUX_H_ diff --git a/system_wrappers/source/thread_windows.cc b/system_wrappers/source/thread_windows.cc new file mode 100644 index 000000000..c4a3d71aa --- /dev/null +++ b/system_wrappers/source/thread_windows.cc @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "thread_windows.h" + +#include +#include +#include +#include + +#include "thread_windows_set_name.h" +#include "trace.h" + +#if defined(_WIN32) +// VS 2005: Disable warnings for default initialized arrays. +#pragma warning(disable:4351) +#endif + +namespace webrtc { +ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* threadName) + : ThreadWrapper(), + _runFunction(func), + _obj(obj), + _alive(false), + _dead(true), + _doNotCloseHandle(false), + _prio(prio), + _event(NULL), + _thread(NULL), + _id(0), + _name(), + _setThreadName(false) +{ + _event = EventWrapper::Create(); + _critsectStop = CriticalSectionWrapper::CreateCriticalSection(); + if (threadName != NULL) + { + // Set the thread name to appear in the VS debugger. + _setThreadName = true; + strncpy(_name, threadName, kThreadMaxNameLength); + } +} + +ThreadWindows::~ThreadWindows() +{ +#ifdef _DEBUG + assert(!_alive); +#endif + if (_thread) + { + CloseHandle(_thread); + } + if(_event) + { + delete _event; + } + if(_critsectStop) + { + delete _critsectStop; + } +} + +unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter) +{ + static_cast(lpParameter)->Run(); + return 0; +} + +bool ThreadWindows::Start(unsigned int& threadID) +{ + _doNotCloseHandle = false; + + // Set stack size to 1M + _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0, + &threadID); + if(_thread == NULL) + { + return false; + } + _id = threadID; + _event->Wait(INFINITE); + + switch(_prio) + { + case kLowPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL); + break; + case kNormalPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL); + break; + case kHighPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL); + break; + case kHighestPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST); + break; + case kRealtimePriority: + SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL); + break; + }; + return true; +} + +bool ThreadWindows::SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors) +{ + DWORD_PTR processorBitMask = 0; + for(unsigned int processorIndex = 0; + processorIndex < amountOfProcessors; + processorIndex++) + { + // Convert from an array with processor numbers to a bitmask + // Processor numbers start at zero. + // TODO (hellner): this looks like a bug. Shouldn't the '=' be a '+='? + // Or even better |= + processorBitMask = 1 << processorNumbers[processorIndex]; + } + return SetThreadAffinityMask(_thread,processorBitMask) != 0; +} + +void ThreadWindows::SetNotAlive() +{ + _alive = false; +} + +bool ThreadWindows::Shutdown() +{ + DWORD exitCode = 0; + BOOL ret = TRUE; + if (_thread) + { + ret = TerminateThread(_thread, exitCode); + _alive = false; + _dead = true; + _thread = NULL; + } + return ret == TRUE; +} + +bool ThreadWindows::Stop() +{ + _critsectStop->Enter(); + // Prevents the handle from being closed in ThreadWindows::Run() + _doNotCloseHandle = true; + _alive = false; + bool signaled = false; + if (_thread && !_dead) + { + _critsectStop->Leave(); + // Wait up to 2 seconds for the thread to complete. + if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000)) + { + signaled = true; + } + _critsectStop->Enter(); + } + if (_thread) + { + CloseHandle(_thread); + _thread = NULL; + } + _critsectStop->Leave(); + + if (_dead || signaled) + { + return true; + } + else + { + return false; + } +} + +void ThreadWindows::Run() +{ + _alive = true; + _dead = false; + _event->Set(); + + // All tracing must be after _event->Set to avoid deadlock in Trace. + if (_setThreadName) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread with name:%s started ", _name); + SetThreadName(-1, _name); // -1, set thread name for the calling thread. + }else + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread without name started"); + } + + do + { + if (_runFunction) + { + if (!_runFunction(_obj)) + { + _alive = false; + } + } else { + _alive = false; + } + } while(_alive); + + if (_setThreadName) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread with name:%s stopped", _name); + } else { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id, + "Thread without name stopped"); + } + + _critsectStop->Enter(); + + if (_thread && !_doNotCloseHandle) + { + HANDLE thread = _thread; + _thread = NULL; + CloseHandle(thread); + } + _dead = true; + + _critsectStop->Leave(); +}; +} // namespace webrtc diff --git a/system_wrappers/source/thread_windows.h b/system_wrappers/source/thread_windows.h new file mode 100644 index 000000000..4fd7523ec --- /dev/null +++ b/system_wrappers/source/thread_windows.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ + +#include "thread_wrapper.h" +#include "event_wrapper.h" +#include "critical_section_wrapper.h" + +#include + +namespace webrtc { + +class ThreadWindows : public ThreadWrapper +{ +public: + ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, + const char* threadName); + virtual ~ThreadWindows(); + + virtual bool Start(unsigned int& id); + bool SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors); + virtual bool Stop(); + virtual void SetNotAlive(); + + static unsigned int WINAPI StartThread(LPVOID lpParameter); + + virtual bool Shutdown(); + +protected: + virtual void Run(); + +private: + ThreadRunFunction _runFunction; + ThreadObj _obj; + + bool _alive; + bool _dead; + + // TODO (hellner) + // _doNotCloseHandle member seem pretty redundant. Should be able to remove + // it. Basically it should be fine to reclaim the handle when calling stop + // and in the destructor. + bool _doNotCloseHandle; + ThreadPriority _prio; + EventWrapper* _event; + CriticalSectionWrapper* _critsectStop; + + HANDLE _thread; + unsigned int _id; + char _name[kThreadMaxNameLength]; + bool _setThreadName; + +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ diff --git a/system_wrappers/source/thread_windows_set_name.h b/system_wrappers/source/thread_windows_set_name.h new file mode 100644 index 000000000..a46f4d630 --- /dev/null +++ b/system_wrappers/source/thread_windows_set_name.h @@ -0,0 +1,43 @@ +/* + * Use of this source code is governed by the MICROSOFT LIMITED PUBLIC LICENSE + * copyright license which can be found in the LICENSE file in the + * third_party_mods/mslpl directory of the source tree or at + * http://msdn.microsoft.com/en-us/cc300389.aspx#P. + */ +/* + * The original code can be found here: + * http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ + +namespace webrtc { + +struct THREADNAME_INFO +{ + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1 = caller thread) + DWORD dwFlags; // reserved for future use, must be zero +}; + +void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), + (ULONG_PTR*)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } +} +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ diff --git a/system_wrappers/source/trace_impl.cc b/system_wrappers/source/trace_impl.cc new file mode 100644 index 000000000..5d269ffc1 --- /dev/null +++ b/system_wrappers/source/trace_impl.cc @@ -0,0 +1,949 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "trace_impl.h" + +#include +#include // memset + +#ifdef _WIN32 +#include "trace_windows.h" +#include "fix_interlocked_exchange_pointer_windows.h" +#else +#include +#include +#include +#include "trace_linux.h" +#endif // _WIN32 + +#define KEY_LEN_CHARS 31 + +#ifdef _WIN32 + #pragma warning(disable:4355) +// VS 2005: Disable warnings for default initialized arrays. + #pragma warning(disable:4351) +#endif // _WIN32 + +namespace webrtc { +static WebRtc_UWord32 levelFilter = kTraceDefault; + +// Construct On First Use idiom. Avoids "static initialization order fiasco". +Trace* TraceImpl::StaticInstance(TraceCount inc, const TraceLevel level) +{ + // TODO (hellner): use atomic wrapper instead. + static volatile long theTraceCount = 0; + static Trace* volatile theTrace = NULL; + + TraceCreate state = WEBRTC_TRACE_EXIST; + + // Sanitys to avoid taking lock unless absolutely necessary (for + // performance reasons). inc == WEBRTC_TRACE_INC_NO_CREATE) implies that + // a message will be written to file. + if(level != kTraceAll && inc == WEBRTC_TRACE_INC_NO_CREATE) + { + if(!(level & levelFilter)) + { + return NULL; + } + } + +#ifndef _WIN32 + // TODO (pwestin): crtiSect is never reclaimed. Fix memory leak. + static CriticalSectionWrapper* crtiSect( + CriticalSectionWrapper::CreateCriticalSection()); + CriticalSectionScoped lock(*crtiSect); + + if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0) + { + return NULL; + } + + if(inc == WEBRTC_TRACE_INC || inc == WEBRTC_TRACE_INC_NO_CREATE) + { + theTraceCount++; + if(theTraceCount == 1) + { + state = WEBRTC_TRACE_CREATE; + } + } else { + theTraceCount--; + if(theTraceCount == 0) + { + state = WEBRTC_TRACE_DESTROY; + } + } + if(state == WEBRTC_TRACE_CREATE) + { + theTrace = TraceImpl::CreateTrace(); + + } else if(state == WEBRTC_TRACE_DESTROY) { + Trace* oldValue = theTrace; + theTrace = NULL; + // The lock is held by the scoped critical section. Release the lock + // temporarily so that the trace can be safely deleted. If the lock + // was kept during the delete, e.g. creating and destroying the trace + // too quickly may lead to a deadlock. + // This is due to the fact that starting and stopping a ThreadWrapper + // thread will trigger writing of trace messages. + // TODO (hellner): remove the tight coupling with the thread + // implementation. + crtiSect->Leave(); + if(oldValue) + { + delete static_cast(oldValue); + } + // Re-aqcuire the lock. + crtiSect->Enter(); + return NULL; + } +#else // _WIN32 + if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0) + { + return NULL; + } + if(inc == WEBRTC_TRACE_INC_NO_CREATE) + { + if(1 == InterlockedIncrement(&theTraceCount)) + { + // The trace has been destroyed by some other thread. Rollback. + InterlockedDecrement(&theTraceCount); + assert(false); + return NULL; + } + // Sanity to catch corrupt state. + if(theTrace == NULL) + { + assert(false); + InterlockedDecrement(&theTraceCount); + return NULL; + } + } else if(inc == WEBRTC_TRACE_INC) { + if(theTraceCount == 0) + { + state = WEBRTC_TRACE_CREATE; + } else { + if(1 == InterlockedIncrement(&theTraceCount)) + { + // InterlockedDecrement because reference count should not be + // updated just yet (that's done when the trace is created). + InterlockedDecrement(&theTraceCount); + state = WEBRTC_TRACE_CREATE; + } + } + } else { + int newValue = InterlockedDecrement(&theTraceCount); + if(newValue == 0) + { + state = WEBRTC_TRACE_DESTROY; + } + } + + if(state == WEBRTC_TRACE_CREATE) + { + // Create trace and let whichever thread finishes first assign its local + // copy to the global instance. All other threads reclaim their local + // copy. + Trace* newTrace = TraceImpl::CreateTrace(); + if(1 == InterlockedIncrement(&theTraceCount)) + { + Trace* oldValue = (Trace*)InterlockedExchangePointer( + reinterpret_cast(&theTrace), newTrace); + assert(oldValue == NULL); + assert(theTrace); + } else { + InterlockedDecrement(&theTraceCount); + if(newTrace) + { + delete static_cast(newTrace); + } + } + return NULL; + } else if(state == WEBRTC_TRACE_DESTROY) + { + Trace* oldValue = (Trace*)InterlockedExchangePointer( + reinterpret_cast(&theTrace), NULL); + if(oldValue) + { + delete static_cast(oldValue); + } + return NULL; + } +#endif // #ifndef _WIN32 + return theTrace; +} + +void Trace::CreateTrace() +{ + TraceImpl::StaticInstance(WEBRTC_TRACE_INC); +} + +void Trace::ReturnTrace() +{ + TraceImpl::StaticInstance(WEBRTC_TRACE_DEC); +} + +TraceImpl* TraceImpl::GetTrace(const TraceLevel level) +{ + return (TraceImpl*)StaticInstance(WEBRTC_TRACE_INC_NO_CREATE, level); +} + +Trace* TraceImpl::CreateTrace() +{ +#if defined(_WIN32) + return new TraceWindows(); +#else + return new TraceLinux(); +#endif +} + +TraceImpl::TraceImpl() + : _critsectInterface(*CriticalSectionWrapper::CreateCriticalSection()), + _callback(NULL), + _rowCountText(0), + _fileCountText(0), + _traceFile(*FileWrapper::Create()), + _thread(*ThreadWrapper::CreateThread(TraceImpl::Run, this, + kHighestPriority, "Trace")), + _event(*EventWrapper::Create()), + _critsectArray(*CriticalSectionWrapper::CreateCriticalSection()), + _nextFreeIdx(), + _level(), + _length(), + _messageQueue(), + _activeQueue(0) +{ + _nextFreeIdx[0] = 0; + _nextFreeIdx[1] = 0; + + unsigned int tid = 0; + _thread.Start(tid); + + for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++) + { + for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++) + { + _messageQueue[m][n] = new + WebRtc_Word8[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; + } + } +} + +bool TraceImpl::StopThread() +{ + // Release the worker thread so that it can flush any lingering messages. + _event.Set(); + + // Allow 10 ms for pending messages to be flushed out. + // TODO (hellner): why not use condition variables to do this? Or let the + // worker thread die and let this thread flush remaining + // messages? +#ifdef _WIN32 + Sleep(10); +#else + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10*1000000; + nanosleep(&t,NULL); +#endif + + _thread.SetNotAlive(); + // Make sure the thread finishes as quickly as possible (instead of having + // to wait for the timeout). + _event.Set(); + bool stopped = _thread.Stop(); + + CriticalSectionScoped lock(_critsectInterface); + _traceFile.Flush(); + _traceFile.CloseFile(); + return stopped; +} + +TraceImpl::~TraceImpl() +{ + StopThread(); + delete &_event; + delete &_traceFile; + delete &_thread; + delete &_critsectInterface; + delete &_critsectArray; + + for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++) + { + for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++) + { + delete [] _messageQueue[m][n]; + } + } +} + +WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const +{ + switch (level) + { + case kTraceStateInfo: + sprintf (szMessage, "STATEINFO ; "); + break; + case kTraceWarning: + sprintf (szMessage, "WARNING ; "); + break; + case kTraceError: + sprintf (szMessage, "ERROR ; "); + break; + case kTraceCritical: + sprintf (szMessage, "CRITICAL ; "); + break; + case kTraceInfo: + sprintf (szMessage, "DEBUGINFO ; "); + break; + case kTraceModuleCall: + sprintf (szMessage, "MODULECALL; "); + break; + case kTraceMemory: + sprintf (szMessage, "MEMORY ; "); + break; + case kTraceTimer: + sprintf (szMessage, "TIMER ; "); + break; + case kTraceStream: + sprintf (szMessage, "STREAM ; "); + break; + case kTraceApiCall: + sprintf (szMessage, "APICALL ; "); + break; + case kTraceDebug: + sprintf (szMessage, "DEBUG ; "); + break; + default: + assert(false); + return 0; + } + // All messages are 12 characters. + return 12; +} + +WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage, + const TraceModule module, + const WebRtc_Word32 id) const +{ + // Use long int to prevent problems with different definitions of + // WebRtc_Word32. + // TODO (hellner): is this actually a problem? If so, it should be better to + // clean up WebRtc_Word32 + const long int idl = id; + if(idl != -1) + { + const unsigned long int idEngine = id>>16; + const unsigned long int idChannel = id & 0xffff; + + switch (module) + { + case kTraceVoice: + sprintf(traceMessage, " VOICE:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVideo: + sprintf(traceMessage, " VIDEO:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceUtility: + sprintf(traceMessage, " UTILITY:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceRtpRtcp: + sprintf(traceMessage, " RTP/RTCP:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceTransport: + sprintf(traceMessage, " TRANSPORT:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceAudioCoding: + sprintf(traceMessage, "AUDIO CODING:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceSrtp: + sprintf(traceMessage, " SRTP:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceAudioMixerServer: + sprintf(traceMessage, " AUDIO MIX/S:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceAudioMixerClient: + sprintf(traceMessage, " AUDIO MIX/C:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVideoCoding: + sprintf(traceMessage, "VIDEO CODING:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVideoMixer: + // Print sleep time and API call + sprintf(traceMessage, " VIDEO MIX:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceFile: + sprintf(traceMessage, " FILE:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVqe: + sprintf(traceMessage, " VQE:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceAudioDevice: + sprintf(traceMessage, "AUDIO DEVICE:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVideoRenderer: + sprintf(traceMessage, "VIDEO RENDER:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVideoCapture: + sprintf(traceMessage, "VIDEO CAPTUR:%5ld %5ld;", idEngine, + idChannel); + break; + case kTraceVideoPreocessing: + sprintf(traceMessage, " VIDEO PROC:%5ld %5ld;", idEngine, + idChannel); + break; + default: + assert(false); + return 0; + } + } else { + switch (module) + { + case kTraceVoice: + sprintf (traceMessage, " VOICE:%11ld;", idl); + break; + case kTraceVideo: + sprintf (traceMessage, " VIDEO:%11ld;", idl); + break; + case kTraceUtility: + sprintf (traceMessage, " UTILITY:%11ld;", idl); + break; + case kTraceRtpRtcp: + sprintf (traceMessage, " RTP/RTCP:%11ld;", idl); + break; + case kTraceTransport: + sprintf (traceMessage, " TRANSPORT:%11ld;", idl); + break; + case kTraceAudioCoding: + sprintf (traceMessage, "AUDIO CODING:%11ld;", idl); + break; + case kTraceSrtp: + sprintf (traceMessage, " SRTP:%11ld;", idl); + break; + case kTraceAudioMixerServer: + sprintf (traceMessage, " AUDIO MIX/S:%11ld;", idl); + break; + case kTraceAudioMixerClient: + sprintf (traceMessage, " AUDIO MIX/C:%11ld;", idl); + break; + case kTraceVideoCoding: + sprintf (traceMessage, "VIDEO CODING:%11ld;", idl); + break; + case kTraceVideoMixer: + sprintf (traceMessage, " VIDEO MIX:%11ld;", idl); + break; + case kTraceFile: + sprintf (traceMessage, " FILE:%11ld;", idl); + break; + case kTraceVqe: + sprintf (traceMessage, " VQE:%11ld;", idl); + break; + case kTraceAudioDevice: + sprintf (traceMessage, "AUDIO DEVICE:%11ld;", idl); + break; + case kTraceVideoRenderer: + sprintf (traceMessage, "VIDEO RENDER:%11ld;", idl); + break; + case kTraceVideoCapture: + sprintf (traceMessage, "VIDEO CAPTUR:%11ld;", idl); + break; + case kTraceVideoPreocessing: + sprintf (traceMessage, " VIDEO PROC:%11ld;", idl); + break; + default: + assert(false); + return 0; + } + } + // All messages are 25 characters. + return 25; +} + +WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, + const bool addFileCounter) +{ + CriticalSectionScoped lock(_critsectInterface); + + _traceFile.Flush(); + _traceFile.CloseFile(); + + if(fileNameUTF8) + { + if(addFileCounter) + { + _fileCountText = 1; + + WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize]; + CreateFileName(fileNameUTF8, fileNameWithCounterUTF8, + _fileCountText); + if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false, + true) == -1) + { + return -1; + } + }else { + _fileCountText = 0; + if(_traceFile.OpenFile(fileNameUTF8, false, false, true) == -1) + { + return -1; + } + } + } + _rowCountText = 0; + return 0; +} + +WebRtc_Word32 TraceImpl::TraceFileImpl( + WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize]) +{ + CriticalSectionScoped lock(_critsectInterface); + return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize); +} + +WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) +{ + CriticalSectionScoped lock(_critsectInterface); + _callback = callback; + return 0; +} + +WebRtc_Word32 TraceImpl::AddMessage( + char* traceMessage, + const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE], + const WebRtc_UWord16 writtenSoFar) const + +{ + int length = 0; + if(writtenSoFar >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) + { + return -1; + } + // - 2 to leave room for newline and NULL termination +#ifdef _WIN32 + length = _snprintf(traceMessage, + WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2, + "%s",msg); + if(length < 0) + { + length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2; + traceMessage[length] = 0; + } +#else + length = snprintf(traceMessage, + WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar-2, "%s",msg); + if(length < 0 || length > WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar - 2) + { + length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2; + traceMessage[length] = 0; + } +#endif + // Length with NULL termination. + return length+1; +} + +void TraceImpl::AddMessageToList( + const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE], + const WebRtc_UWord16 length, + const TraceLevel level) +{ + CriticalSectionScoped lock(_critsectArray); + + if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE) + { + if( ! _traceFile.Open() && + !_callback) + { + // Keep at least the last 1/4 of old messages when not logging. + // TODO (hellner): isn't this redundant. The user will make it known + // when to start logging. Why keep messages before + // that? + for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE/4; n++) + { + const int lastQuarterOffset = (3*WEBRTC_TRACE_MAX_QUEUE/4); + memcpy(_messageQueue[_activeQueue][n], + _messageQueue[_activeQueue][n + lastQuarterOffset], + WEBRTC_TRACE_MAX_MESSAGE_SIZE); + } + _nextFreeIdx[_activeQueue] = WEBRTC_TRACE_MAX_QUEUE/4; + } else { + // More messages are being written than there is room for in the + // buffer. Drop any new messages. + // TODO (hellner): its probably better to drop old messages instead + // of new ones. One step further: if this happens + // it's due to writing faster than what can be + // processed. Maybe modify the filter at this point. + // E.g. turn of STREAM. + return; + } + } + + WebRtc_UWord16 idx = _nextFreeIdx[_activeQueue]; + _nextFreeIdx[_activeQueue]++; + + _level[_activeQueue][idx] = level; + _length[_activeQueue][idx] = length; + memcpy(_messageQueue[_activeQueue][idx], traceMessage, length); + + if(_nextFreeIdx[_activeQueue] == WEBRTC_TRACE_MAX_QUEUE-1) + { + // Loggin more messages than can be worked off. Log a warning. + memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]], + "WARNING MISSING TRACE MESSAGES\n", 32); + _nextFreeIdx[_activeQueue]++; + } +} + +bool TraceImpl::Run(void* obj) +{ + return static_cast(obj)->Process(); +} + +bool TraceImpl::Process() +{ + if(_event.Wait(1000) == kEventSignaled) + { + if(_traceFile.Open() || _callback) + { + // File mode (not calback mode). + WriteToFile(); + } + } else { + _traceFile.Flush(); + } + return true; +} + +void TraceImpl::WriteToFile() +{ + WebRtc_UWord8 localQueueActive = 0; + WebRtc_UWord16 localNextFreeIdx = 0; + + // There are two buffer. One for reading (for writing to file) and one for + // writing (for storing new messages). Let new messages be posted to the + // unused buffer so that the current buffer can be flushed safely. + { + CriticalSectionScoped lock(_critsectArray); + localNextFreeIdx = _nextFreeIdx[_activeQueue]; + _nextFreeIdx[_activeQueue] = 0; + localQueueActive = _activeQueue; + if(_activeQueue == 0) + { + _activeQueue = 1; + } else + { + _activeQueue = 0; + } + } + if(localNextFreeIdx == 0) + { + return; + } + + CriticalSectionScoped lock(_critsectInterface); + + for(WebRtc_UWord16 idx = 0; idx Print(localLevel, _messageQueue[localQueueActive][idx], + _length[localQueueActive][idx]); + } + if(_traceFile.Open()) + { + if(_rowCountText > WEBRTC_TRACE_MAX_FILE_SIZE) + { + // wrap file + _rowCountText = 0; + _traceFile.Flush(); + + if(_fileCountText == 0) + { + _traceFile.Rewind(); + } else + { + WebRtc_Word8 oldFileName[FileWrapper::kMaxFileNameSize]; + WebRtc_Word8 newFileName[FileWrapper::kMaxFileNameSize]; + + // get current name + _traceFile.FileName(oldFileName, + FileWrapper::kMaxFileNameSize); + _traceFile.CloseFile(); + + _fileCountText++; + + UpdateFileName(oldFileName, newFileName, _fileCountText); + + if(_traceFile.OpenFile(newFileName, false, false, + true) == -1) + { + return; + } + } + } + if(_rowCountText == 0) + { + WebRtc_Word8 message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1]; + WebRtc_Word32 length = AddDateTimeInfo(message); + if(length != -1) + { + message[length] = 0; + message[length-1] = '\n'; + _traceFile.Write(message, length); + _rowCountText++; + } + length = AddBuildInfo(message); + if(length != -1) + { + message[length+1] = 0; + message[length] = '\n'; + message[length-1] = '\n'; + _traceFile.Write(message, length+1); + _rowCountText++; + _rowCountText++; + } + } + WebRtc_UWord16 length = _length[localQueueActive][idx]; + _messageQueue[localQueueActive][idx][length] = 0; + _messageQueue[localQueueActive][idx][length-1] = '\n'; + _traceFile.Write(_messageQueue[localQueueActive][idx], length); + _rowCountText++; + } + } +} + +void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module, + const WebRtc_Word32 id, + const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE]) +{ + if (TraceCheck(level)) + { + char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; + char* meassagePtr = traceMessage; + + WebRtc_Word32 len = 0; + WebRtc_Word32 ackLen = 0; + + len = AddLevel(meassagePtr, level); + if(len == -1) + { + return; + } + meassagePtr += len; + ackLen += len; + + len = AddTime(meassagePtr, level); + if(len == -1) + { + return; + } + meassagePtr += len; + ackLen += len; + + len = AddModuleAndId(meassagePtr, module, id); + if(len == -1) + { + return; + } + meassagePtr += len; + ackLen += len; + + len = AddThreadId(meassagePtr); + if(len == -1) + { + return; + } + meassagePtr += len; + ackLen += len; + + len = AddMessage(meassagePtr, msg, (WebRtc_UWord16)ackLen); + if(len == -1) + { + return; + } + ackLen += len; + AddMessageToList(traceMessage,(WebRtc_UWord16)ackLen, level); + + // Make sure that messages are written as soon as possible. + _event.Set(); + } +} + +bool TraceImpl::TraceCheck(const TraceLevel level) const +{ + return (level & levelFilter)? true:false; +} + +bool TraceImpl::UpdateFileName( + const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], + WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const WebRtc_UWord32 newCount) const +{ + WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); + if(length < 0) + { + return false; + } + + WebRtc_Word32 lengthWithoutFileEnding = length-1; + while(lengthWithoutFileEnding > 0) + { + if(fileNameUTF8[lengthWithoutFileEnding] == '.') + { + break; + } else { + lengthWithoutFileEnding--; + } + } + if(lengthWithoutFileEnding == 0) + { + lengthWithoutFileEnding = length; + } + WebRtc_Word32 lengthTo_ = lengthWithoutFileEnding - 1; + while(lengthTo_ > 0) + { + if(fileNameUTF8[lengthTo_] == '_') + { + break; + } else { + lengthTo_--; + } + } + + memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthTo_); + sprintf(fileNameWithCounterUTF8+lengthTo_, "_%lu%s", newCount, + fileNameUTF8+lengthWithoutFileEnding); + return true; +} + +bool TraceImpl::CreateFileName( + const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], + WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const WebRtc_UWord32 newCount) const +{ + WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); + if(length < 0) + { + return false; + } + + WebRtc_Word32 lengthWithoutFileEnding = length-1; + while(lengthWithoutFileEnding > 0) + { + if(fileNameUTF8[lengthWithoutFileEnding] == '.') + { + break; + }else + { + lengthWithoutFileEnding--; + } + } + if(lengthWithoutFileEnding == 0) + { + lengthWithoutFileEnding = length; + } + memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthWithoutFileEnding); + sprintf(fileNameWithCounterUTF8+lengthWithoutFileEnding, "_%lu%s", + newCount, fileNameUTF8+lengthWithoutFileEnding); + return true; +} + +WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter) +{ + levelFilter = filter; + return 0; +}; + +WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter) +{ + filter = levelFilter; + return 0; +}; + +WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]) +{ + TraceImpl* trace = TraceImpl::GetTrace(); + if(trace) + { + int retVal = trace->TraceFileImpl(fileName); + ReturnTrace(); + return retVal; + } + return -1; +} + +WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName, + const bool addFileCounter) +{ + TraceImpl* trace = TraceImpl::GetTrace(); + if(trace) + { + int retVal = trace->SetTraceFileImpl(fileName, addFileCounter); + ReturnTrace(); + return retVal; + } + return -1; +} + +WebRtc_Word32 Trace::SetTraceCallback(TraceCallback* callback) +{ + TraceImpl* trace = TraceImpl::GetTrace(); + if(trace) + { + int retVal = trace->SetTraceCallbackImpl(callback); + ReturnTrace(); + return retVal; + } + return -1; +} + +void Trace::Add(const TraceLevel level, const TraceModule module, + const WebRtc_Word32 id, const char* msg, ...) + +{ + TraceImpl* trace = TraceImpl::GetTrace(level); + if(trace) + { + if(trace->TraceCheck(level)) + { + char tempBuff[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; + char* buff = 0; + if(msg) + { + va_list args; + va_start(args, msg); +#ifdef _WIN32 + _vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args); +#else + vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args); +#endif + va_end(args); + buff = tempBuff; + } + trace->AddImpl(level, module, id, buff); + } + ReturnTrace(); + } +} +} // namespace webrtc diff --git a/system_wrappers/source/trace_impl.h b/system_wrappers/source/trace_impl.h new file mode 100644 index 000000000..42e82fec7 --- /dev/null +++ b/system_wrappers/source/trace_impl.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_ + +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/event_wrapper.h" +#include "system_wrappers/interface/file_wrapper.h" +#include "system_wrappers/interface/trace.h" +#include "system_wrappers/interface/thread_wrapper.h" + +namespace webrtc { +enum TraceCount +{ + WEBRTC_TRACE_DEC = 0, + WEBRTC_TRACE_INC = 1, + WEBRTC_TRACE_INC_NO_CREATE = 2 +}; + +enum TraceCreate +{ + WEBRTC_TRACE_EXIST = 0, + WEBRTC_TRACE_CREATE = 1, + WEBRTC_TRACE_DESTROY = 2 +}; + +// TODO (pwestin) WEBRTC_TRACE_MAX_QUEUE needs to be tweaked +// TODO (hellner) the buffer should be close to how much the system can write to +// file. Increasing the buffer will not solve anything. Sooner or +// later the buffer is going to fill up anyways. +#if defined(MAC_IPHONE) + #define WEBRTC_TRACE_MAX_QUEUE 2000 +#else + #define WEBRTC_TRACE_MAX_QUEUE 8000 +#endif +#define WEBRTC_TRACE_NUM_ARRAY 2 +#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 256 +// Total buffer size is WEBRTC_TRACE_NUM_ARRAY (number of buffer partitions) * +// WEBRTC_TRACE_MAX_QUEUE (number of lines per buffer partition) * +// WEBRTC_TRACE_MAX_MESSAGE_SIZE (number of 1 byte charachters per line) = +// 1 or 4 Mbyte + +#define WEBRTC_TRACE_MAX_FILE_SIZE 100*1000 +// Number of rows that may be written to file. On average 110 bytes per row (max +// 256 bytes per row). So on average 110*100*1000 = 11 Mbyte, max 256*100*1000 = +// 25.6 Mbyte + +class TraceImpl : public Trace +{ +public: + virtual ~TraceImpl(); + + static Trace* CreateTrace(); + static TraceImpl* GetTrace(const TraceLevel level = kTraceAll); + + static Trace* StaticInstance(TraceCount inc, + const TraceLevel level = kTraceAll); + + WebRtc_Word32 SetTraceFileImpl(const WebRtc_Word8* fileName, + const bool addFileCounter); + WebRtc_Word32 TraceFileImpl( + WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]); + + WebRtc_Word32 SetTraceCallbackImpl(TraceCallback* callback); + + void AddImpl(const TraceLevel level, const TraceModule module, + const WebRtc_Word32 id, const char* msg); + + bool StopThread(); + + bool TraceCheck(const TraceLevel level) const; + +protected: + TraceImpl(); + + // OS specific implementations + virtual WebRtc_Word32 AddThreadId(char* traceMessage) const = 0; + virtual WebRtc_Word32 AddTime(char* traceMessage, + const TraceLevel level) const = 0; + + virtual WebRtc_Word32 AddBuildInfo(char* traceMessage) const = 0; + virtual WebRtc_Word32 AddDateTimeInfo(char* traceMessage) const = 0; + + static bool Run(void* obj); + bool Process(); + +private: + WebRtc_Word32 AddLevel(char* szMessage, const TraceLevel level) const; + + WebRtc_Word32 AddModuleAndId(char* traceMessage, const TraceModule module, + const WebRtc_Word32 id) const; + + WebRtc_Word32 AddMessage(char* traceMessage, + const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE], + const WebRtc_UWord16 writtenSoFar) const; + + void AddMessageToList( + const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE], + const WebRtc_UWord16 length, + const TraceLevel level); + + bool UpdateFileName( + const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], + WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const WebRtc_UWord32 newCount) const; + + bool CreateFileName( + const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], + WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const WebRtc_UWord32 newCount) const; + + void WriteToFile(); + + CriticalSectionWrapper& _critsectInterface; + TraceCallback* _callback; + WebRtc_UWord32 _rowCountText; + WebRtc_UWord32 _fileCountText; + + FileWrapper& _traceFile; + ThreadWrapper& _thread; + EventWrapper& _event; + + // _critsectArray protects _activeQueue + CriticalSectionWrapper& _critsectArray; + WebRtc_UWord16 _nextFreeIdx[WEBRTC_TRACE_NUM_ARRAY]; + TraceLevel _level[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + WebRtc_UWord16 _length[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + WebRtc_Word8* _messageQueue[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + WebRtc_UWord8 _activeQueue; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_ diff --git a/system_wrappers/source/trace_linux.cc b/system_wrappers/source/trace_linux.cc new file mode 100644 index 000000000..f4e1d2343 --- /dev/null +++ b/system_wrappers/source/trace_linux.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "trace_linux.h" + +#include +#include +#include +#include +#include + +#ifdef ANDROID + #include +#else + #include +#endif + +#if defined(_DEBUG) + #define BUILDMODE "d" +#elif defined(DEBUG) + #define BUILDMODE "d" +#elif defined(NDEBUG) + #define BUILDMODE "r" +#else + #define BUILDMODE "?" +#endif +#define BUILDTIME __TIME__ +#define BUILDDATE __DATE__ +// example: "Oct 10 2002 12:05:30 r" +#define BUILDINFO BUILDDATE " " BUILDTIME " " BUILDMODE + +namespace webrtc { +TraceLinux::TraceLinux() +{ + _prevAPITickCount = time(NULL); + _prevTickCount = _prevAPITickCount; +} + +TraceLinux::~TraceLinux() +{ + StopThread(); +} + +WebRtc_Word32 TraceLinux::AddThreadId(char* traceMessage) const +{ + WebRtc_UWord64 threadId = (WebRtc_UWord64)pthread_self(); + sprintf(traceMessage, "%10llu; ", threadId); + // 12 bytes are written. + return 12; +} + +WebRtc_Word32 TraceLinux::AddTime(char* traceMessage, + const TraceLevel level) const +{ + time_t dwCurrentTimeInSeconds = time(NULL); + struct tm systemTime; + gmtime_r(&dwCurrentTimeInSeconds, &systemTime); + + if(level == kTraceApiCall) + { + WebRtc_UWord32 dwDeltaTime = dwCurrentTimeInSeconds - _prevTickCount; + _prevTickCount = dwCurrentTimeInSeconds; + + if(_prevTickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.tm_hour, + systemTime.tm_min, systemTime.tm_sec, 0, dwDeltaTime); + } else { + WebRtc_UWord32 dwDeltaTime = dwCurrentTimeInSeconds - _prevAPITickCount; + _prevAPITickCount = dwCurrentTimeInSeconds; + if(_prevAPITickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.tm_hour, + systemTime.tm_min, systemTime.tm_sec, 0, dwDeltaTime); + } + // Messages is 22 characters. + return 22; +} + +WebRtc_Word32 TraceLinux::AddBuildInfo(char* traceMessage) const +{ + sprintf(traceMessage, "Build info: %s", BUILDINFO); + // Include NULL termination (hence + 1). + return strlen(traceMessage) + 1; +} + +WebRtc_Word32 TraceLinux::AddDateTimeInfo(char* traceMessage) const +{ + time_t t; + time(&t); + sprintf(traceMessage, "Local Date: %s", ctime(&t)); + WebRtc_Word32 len = static_cast(strlen(traceMessage)); + + if ('\n' == traceMessage[len - 1]) + { + traceMessage[len - 1] = '\0'; + --len; + } + + // Messages is 12 characters. + return len + 1; +} +} // namespace webrtc diff --git a/system_wrappers/source/trace_linux.h b/system_wrappers/source/trace_linux.h new file mode 100644 index 000000000..6e327a0b7 --- /dev/null +++ b/system_wrappers/source/trace_linux.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_LINUX_H_ + +#include "critical_section_wrapper.h" +#include "trace_impl.h" + +namespace webrtc { +class TraceLinux : public TraceImpl +{ +public: + TraceLinux(); + virtual ~TraceLinux(); + + virtual WebRtc_Word32 AddThreadId(char *traceMessage) const; + virtual WebRtc_Word32 AddTime(char* traceMessage, + const TraceLevel level) const; + + virtual WebRtc_Word32 AddBuildInfo(char* traceMessage) const; + virtual WebRtc_Word32 AddDateTimeInfo(char* traceMessage) const; + +private: + volatile mutable WebRtc_UWord32 _prevAPITickCount; + volatile mutable WebRtc_UWord32 _prevTickCount; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_LINUX_H_ diff --git a/system_wrappers/source/trace_windows.cc b/system_wrappers/source/trace_windows.cc new file mode 100644 index 000000000..404ef851a --- /dev/null +++ b/system_wrappers/source/trace_windows.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "trace_windows.h" + +#include +#include + +#include "Mmsystem.h" + +#if defined(_DEBUG) + #define BUILDMODE "d" +#elif defined(DEBUG) + #define BUILDMODE "d" +#elif defined(NDEBUG) + #define BUILDMODE "r" +#else + #define BUILDMODE "?" +#endif +#define BUILDTIME __TIME__ +#define BUILDDATE __DATE__ +// Example: "Oct 10 2002 12:05:30 r" +#define BUILDINFO BUILDDATE " " BUILDTIME " " BUILDMODE + +namespace webrtc { +TraceWindows::TraceWindows() + : _prevAPITickCount(0), + _prevTickCount(0) +{ +} + +TraceWindows::~TraceWindows() +{ + StopThread(); +} + +WebRtc_Word32 TraceWindows::AddThreadId(char* traceMessage) const +{ + WebRtc_UWord32 threadId= GetCurrentThreadId(); + sprintf (traceMessage, "%10u; ", threadId); + // Messages is 12 characters. + return 12; +} + +WebRtc_Word32 TraceWindows::AddTime(char* traceMessage, + const TraceLevel level) const +{ + WebRtc_UWord32 dwCurrentTime = timeGetTime(); + SYSTEMTIME systemTime; + GetSystemTime(&systemTime); + + if(level == kTraceApiCall) + { + WebRtc_UWord32 dwDeltaTime = dwCurrentTime- _prevTickCount; + _prevTickCount = dwCurrentTime; + + if(_prevTickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds, dwDeltaTime); + } else { + WebRtc_UWord32 dwDeltaTime = dwCurrentTime - _prevAPITickCount; + _prevAPITickCount = dwCurrentTime; + + if(_prevAPITickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds, dwDeltaTime); + } + // Messages is 12 characters. + return 22; +} + +WebRtc_Word32 TraceWindows::AddBuildInfo(char* traceMessage) const +{ + // write data and time to text file + sprintf(traceMessage, "Build info: %s", BUILDINFO); + // Include NULL termination (hence + 1). + return static_cast(strlen(traceMessage)+1); +} + +WebRtc_Word32 TraceWindows::AddDateTimeInfo(char* traceMessage) const +{ + _prevAPITickCount = timeGetTime(); + _prevTickCount = _prevAPITickCount; + + SYSTEMTIME sysTime; + GetLocalTime (&sysTime); + + TCHAR szDateStr[20]; + TCHAR szTimeStr[20]; + TCHAR *pSzDateStr = szDateStr; + TCHAR *pSzTimeStr = szTimeStr; + + // Create date string (e.g. Apr 04 2002) + GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, TEXT("MMM dd yyyy"), + szDateStr, 20); + + // Create time string (e.g. 15:32:08) + GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, TEXT("HH':'mm':'ss"), + szTimeStr, 20); + + sprintf(traceMessage, "Local Date: %s Local Time: %s", szDateStr, + szTimeStr); + + // Include NULL termination (hence + 1). + return static_cast(strlen(traceMessage)+ 1); +} +} // namespace webrtc diff --git a/system_wrappers/source/trace_windows.h b/system_wrappers/source/trace_windows.h new file mode 100644 index 000000000..2ead70183 --- /dev/null +++ b/system_wrappers/source/trace_windows.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ + +#include "trace_impl.h" +#include +#include + +namespace webrtc { +class TraceWindows : public TraceImpl +{ +public: + TraceWindows(); + virtual ~TraceWindows(); + + virtual WebRtc_Word32 AddThreadId(char *traceMessage) const; + virtual WebRtc_Word32 AddTime(char* traceMessage, + const TraceLevel level) const; + + virtual WebRtc_Word32 AddBuildInfo(char* traceMessage) const; + virtual WebRtc_Word32 AddDateTimeInfo(char* traceMessage) const; +private: + volatile mutable WebRtc_UWord32 _prevAPITickCount; + volatile mutable WebRtc_UWord32 _prevTickCount; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ diff --git a/system_wrappers/test/Test.cpp b/system_wrappers/test/Test.cpp new file mode 100644 index 000000000..7a34166b0 --- /dev/null +++ b/system_wrappers/test/Test.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include + +#ifdef _WIN32 + #include + #include +#else + #include + #define Sleep(x) usleep(x*1000) +#endif + +#include "common_types.h" +#include "trace.h" +#include "cpu_wrapper.h" + + +#ifdef _WIN32 +int _tmain(int argc, _TCHAR* argv[]) +#else +int main(int argc, char* argv[]) +#endif +{ + Trace::CreateTrace(); + Trace::SetTraceFile("testTrace.txt"); + Trace::SetLevelFilter(webrtc::kTraceAll); + + printf("Start system wrapper test\n"); + + printf("Number of cores detected:%u\n", (unsigned int)CpuWrapper::DetectNumberOfCores()); + + CpuWrapper* cpu = CpuWrapper::CreateCpu(); + + WebRtc_UWord32 numCores; + WebRtc_UWord32* cores; + + for(int i = 0; i< 10;i++) + { + WebRtc_Word32 total = cpu->CpuUsageMultiCore(numCores, cores); + + printf("\nNumCores:%d\n", (int)numCores); + printf("Total cpu:%d\n", (int)total); + + for (WebRtc_UWord32 i = 0; i< numCores;i++) + { + printf("Core:%lu CPU:%lu \n", i, cores[i]); + } + Sleep(1000); + } + + printf("Done system wrapper test\n"); + + delete cpu; + + Trace::ReturnTrace(); +}; diff --git a/system_wrappers/test/TestSort/TestSort.cpp b/system_wrappers/test/TestSort/TestSort.cpp new file mode 100644 index 000000000..6846a7135 --- /dev/null +++ b/system_wrappers/test/TestSort/TestSort.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include + +#include "sort.h" +#include "tick_util.h" + +// Excellent work polluting the global namespace Visual Studio... +#undef max +#undef min +#include + +template +struct LotsOfData +{ + KeyType key; + char data[64]; +}; + +template +int Compare(const void* dataX, const void* dataY) +{ + DataType dataX = (DataType)*(const DataType*)dataX; + DataType dataY = (DataType)*(const DataType*)dataY; + if (dataX > dataY) + { + return 1; + } + else if (dataX < dataY) + { + return -1; + } + + return 0; +}; + +template +int CompareKey(const void* dataX, const void* dataY) +{ + KeyType keyX = ((const DataType*)dataX)->key; + KeyType keyY = ((const DataType*)dataY)->key; + if (keyX > keyY) + { + return 1; + } + else if (keyX < keyY) + { + return -1; + } + + return 0; +} + +template +struct KeyLessThan +{ + bool operator()(const DataType &dataX, const DataType &dataY) const + { + return dataX.key < dataY.key; + } +}; + +const char* TypeEnumToString(webrtc::Type type) +{ + switch (type) + { + using namespace webrtc; + case TYPE_Word8: + return "Word8"; + case TYPE_UWord8: + return "UWord8"; + case TYPE_Word16: + return "Word16"; + case TYPE_UWord16: + return "UWord16"; + case TYPE_Word32: + return "Word32"; + case TYPE_UWord32: + return "UWord32"; + case TYPE_Word64: + return "Word64"; + case TYPE_UWord64: + return "UWord64"; + case TYPE_Float32: + return "Float32"; + case TYPE_Float64: + return "Float64"; + default: + return "Unrecognized"; + } +} + +template +Type TypedRand() +{ + if (std::numeric_limits::is_integer) + { + double floatRand = static_cast(rand()) / RAND_MAX; + if (std::numeric_limits::is_signed) + { + floatRand -= 0.5; + } + + // Uniform [-max()/2, max()/2] for signed + // [0, max()] for unsigned + return static_cast(floatRand * std::numeric_limits::max()); + } + else // Floating point + { + // Uniform [-0.5, 0.5] + // The outer cast is to remove template warnings. + return static_cast((static_cast(rand()) / RAND_MAX) - 0.5); + } +} + +template +void RunSortTest(webrtc::Type sortType, bool keySort) +{ + enum { DataLength = 1000 }; + enum { NumOfTests = 10000 }; + KeyType key[DataLength]; + KeyType keyRef[DataLength]; + LotsOfData data[DataLength]; + LotsOfData dataRef[DataLength]; + WebRtc_Word32 retVal = 0; + + if (keySort) + { + printf("Running %s KeySort() tests...\n", TypeEnumToString(sortType)); + } + else + { + printf("Running %s Sort() tests...\n", TypeEnumToString(sortType)); + } + + TickInterval accTicks; + for (int i = 0; i < NumOfTests; i++) + { + for (int j = 0; j < DataLength; j++) + { + key[j] = TypedRand(); + data[j].key = key[j]; + // Write index to payload. We use this later for verification. + sprintf(data[j].data, "%d", j); + } + + memcpy(dataRef, data, sizeof(data)); + memcpy(keyRef, key, sizeof(key)); + + retVal = 0; + TickTime t0 = TickTime::Now(); + if (keySort) + { + retVal = webrtc::KeySort(data, key, DataLength, sizeof(LotsOfData), + sortType); + + //std::sort(data, data + DataLength, KeyLessThan()); + //qsort(data, DataLength, sizeof(LotsOfData), + // CompareKey, KeyType>); + } + else + { + retVal = webrtc::Sort(key, DataLength, sortType); + + //std::sort(key, key + DataLength); + //qsort(key, DataLength, sizeof(KeyType), Compare); + } + TickTime t1 = TickTime::Now(); + accTicks += (t1 - t0); + + if (retVal != 0) + { + printf("Test failed at iteration %d:\n", i); + printf("Sort returned an error. "); + printf("It likely does not support the requested type\nExiting...\n"); + exit(0); + } + + // Reference sort. + if (!keySort) + { + std::sort(keyRef, keyRef + DataLength); + } + + if (keySort) + { + for (int j = 0; j < DataLength - 1; j++) + { + if (data[j].key > data[j + 1].key) + { + printf("Test failed at iteration %d:\n", i); + printf("Keys are not monotonically increasing\nExiting...\n"); + exit(0); + } + + int index = atoi(data[j].data); + if (index < 0 || index >= DataLength || data[j].key != dataRef[index].key) + { + printf("Test failed at iteration %d:\n", i); + printf("Payload data is corrupt\nExiting...\n"); + exit(0); + } + } + } + else + { + for (int j = 0; j < DataLength - 1; j++) + { + if (key[j] > key[j + 1]) + { + printf("Test failed at iteration %d:\n", i); + printf("Data is not monotonically increasing\nExiting...\n"); + exit(0); + } + } + + if (memcmp(key, keyRef, sizeof(key)) != 0) + { + printf("Test failed at iteration %d:\n", i); + printf("Sort data differs from std::sort reference\nExiting...\n"); + exit(0); + } + } + } + + printf("Compliance test passed over %d iterations\n", NumOfTests); + + WebRtc_Word64 executeTime = accTicks.Milliseconds(); + printf("Execute time: %.2f s\n\n", (float)executeTime / 1000); +} + +int main() +{ + // Seed rand(). + srand(42); + bool keySort = false; + for (int i = 0; i < 2; i++) { + RunSortTest(webrtc::TYPE_Word8, keySort); + RunSortTest(webrtc::TYPE_UWord8, keySort); + RunSortTest(webrtc::TYPE_Word16, keySort); + RunSortTest(webrtc::TYPE_UWord16, keySort); + RunSortTest(webrtc::TYPE_Word32, keySort); + RunSortTest(webrtc::TYPE_UWord32, keySort); + RunSortTest(webrtc::TYPE_Word64, keySort); + RunSortTest(webrtc::TYPE_UWord64, keySort); + RunSortTest(webrtc::TYPE_Float32, keySort); + RunSortTest(webrtc::TYPE_Float64, keySort); + + keySort = !keySort; + } + + printf("All tests passed\n"); + + return 0; +} diff --git a/system_wrappers/test/list/list.cc b/system_wrappers/test/list/list.cc new file mode 100644 index 000000000..5c4f0b96e --- /dev/null +++ b/system_wrappers/test/list/list.cc @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include + +#include "list_wrapper.h" + +const int kNumberOfElements = 10; + +void FailTest(bool failed) +{ + if (failed) + { + printf("Test failed!\n"); + printf("Press enter to continue:"); + getchar(); + exit(0); + } +} + +int GetStoredIntegerValue(ListItem* list_item) +{ + void* list_item_pointer = list_item->GetItem(); + if (list_item_pointer != NULL) + { + return *(reinterpret_cast(list_item_pointer)); + } + return static_cast(list_item->GetUnsignedItem()); +} + +void PrintList(ListWrapper& list) +{ + ListItem* list_item = list.First(); + printf("List: "); + while (list_item != NULL) + { + int item_value = GetStoredIntegerValue(list_item); + FailTest(item_value < 0); + printf(" %d",item_value); + list_item = list.Next(list_item); + } + printf("\n"); +} + +// The list should always be in ascending order +void ListSanity(ListWrapper& list) +{ + if(list.Empty()) + { + return; + } + ListItem* item_iter = list.First(); + // Fake a previous value for the first iteration + int previous_value = GetStoredIntegerValue(item_iter) - 1; + while (item_iter != NULL) + { + const int value = GetStoredIntegerValue(item_iter); + FailTest(value != previous_value + 1); + previous_value = value; + item_iter = list.Next(item_iter); + } +} + +int main(int /*argc*/, char* /*argv*/[]) +{ + printf("List Test:\n"); + int element_array[kNumberOfElements]; + for (int i = 0; i < kNumberOfElements; i++) + { + element_array[i] = i; + } + // Test PushBack 1 + ListWrapper test_list; + for (int i = 2; i < kNumberOfElements - 2; i++) + { + FailTest(test_list.PushBack((void*)&element_array[i]) != 0); + } + // Test PushBack 2 + FailTest(test_list.PushBack(element_array[kNumberOfElements - 2]) != 0); + FailTest(test_list.PushBack(element_array[kNumberOfElements - 1]) != 0); + // Test PushFront 2 + FailTest(test_list.PushFront(element_array[1]) != 0); + // Test PushFront 1 + FailTest(test_list.PushFront((void*)&element_array[0]) != 0); + // Test GetSize + FailTest(test_list.GetSize() != kNumberOfElements); + PrintList(test_list); + //Test PopFront + FailTest(test_list.PopFront() != 0); + //Test PopBack + FailTest(test_list.PopBack() != 0); + // Test GetSize + FailTest(test_list.GetSize() != kNumberOfElements - 2); + // Test Empty + FailTest(test_list.Empty()); + // Test First + ListItem* first_item = test_list.First(); + FailTest(first_item == NULL); + // Test Last + ListItem* last_item = test_list.Last(); + FailTest(last_item == NULL); + // Test Next + ListItem* second_item = test_list.Next(first_item); + FailTest(second_item == NULL); + FailTest(test_list.Next(last_item) != NULL); + FailTest(test_list.Next(NULL) != NULL); + // Test Previous + ListItem* second_to_last_item = test_list.Previous(last_item); + FailTest(second_to_last_item == NULL); + FailTest(test_list.Previous(first_item) != NULL); + FailTest(test_list.Previous(NULL) != NULL); + // Test GetUnsignedItem + FailTest(last_item->GetUnsignedItem() != + kNumberOfElements - 2); + FailTest(last_item->GetItem() != + NULL); + // Test GetItem + FailTest(GetStoredIntegerValue(second_to_last_item) != + kNumberOfElements - 3); + FailTest(second_to_last_item->GetUnsignedItem() != 0); + // Pop last and first since they are pushed as unsigned items. + FailTest(test_list.PopFront() != 0); + FailTest(test_list.PopBack() != 0); + // Test Insert. Please note that old iterators are no longer valid at + // this point. + ListItem* insert_item_last = new ListItem(reinterpret_cast(&element_array[kNumberOfElements - 2])); + FailTest(test_list.Insert(test_list.Last(),insert_item_last) != 0); + FailTest(test_list.Insert(NULL,insert_item_last) == 0); + ListItem* insert_item_last2 = new ListItem(reinterpret_cast(&element_array[kNumberOfElements - 2])); + FailTest(test_list.Insert(insert_item_last2,NULL) == 0); + // test InsertBefore + ListItem* insert_item_first = new ListItem(reinterpret_cast(&element_array[1])); + FailTest(test_list.InsertBefore(test_list.First(),insert_item_first) != 0); + FailTest(test_list.InsertBefore(NULL,insert_item_first) == 0); + ListItem* insert_item_first2 = new ListItem(reinterpret_cast(&element_array[1])); + FailTest(test_list.InsertBefore(insert_item_first2,NULL) == 0); + PrintList(test_list); + ListSanity(test_list); + // Erase the whole list + int counter = 0; + while (test_list.PopFront() == 0) + { + FailTest(counter++ > kNumberOfElements); + } + PrintList(test_list); + // Test APIs when list is empty + FailTest(test_list.GetSize() != 0); + FailTest(test_list.PopFront() != -1); + FailTest(test_list.PopBack() != -1); + FailTest(!test_list.Empty()); + FailTest(test_list.First() != NULL); + FailTest(test_list.Last() != NULL); + FailTest(test_list.Next(NULL) != NULL); + FailTest(test_list.Previous(NULL) != NULL); + FailTest(test_list.Erase(NULL) != -1); + // Test Insert APIs when list is empty + ListItem* new_item = new ListItem(reinterpret_cast(&element_array[0])); + FailTest(test_list.Insert(NULL,new_item) != 0); + FailTest(test_list.Empty()); + FailTest(test_list.PopFront() != 0); + ListItem* new_item2 = new ListItem(reinterpret_cast(&element_array[0])); + FailTest(test_list.InsertBefore(NULL,new_item2) != 0); + FailTest(test_list.Empty()); + + printf("Tests passed successfully!\n"); +} diff --git a/system_wrappers/test/map/map.cc b/system_wrappers/test/map/map.cc new file mode 100644 index 000000000..8a0d3e31d --- /dev/null +++ b/system_wrappers/test/map/map.cc @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include + +#include "map_wrapper.h" + +const int kNumberOfElements = 10; + +void FailTest(bool failed) +{ + if (failed) + { + printf("Test failed!\n"); + printf("Press enter to continue:"); + getchar(); + exit(0); + } +} + +int GetStoredIntegerValue(MapItem* map_item) +{ + void* map_item_pointer = map_item->GetItem(); + if (map_item_pointer != NULL) + { + return *(reinterpret_cast(map_item_pointer)); + } + return static_cast(map_item->GetUnsignedId()); +} + +void PrintMap(MapWrapper& map) +{ + MapItem* map_item = map.First(); + printf("Map: "); + while (map_item != NULL) + { + int item_value = GetStoredIntegerValue(map_item); + FailTest(item_value < 0); + printf(" %d",item_value); + map_item = map.Next(map_item); + } + printf("\n"); +} + +int main(int /*argc*/, char* /*argv*/[]) +{ + int element_array[kNumberOfElements]; + for (int i = 0; i < kNumberOfElements; i++) + { + element_array[i] = i; + } + // Test insert + MapWrapper test_map; + for (int i = 0; i < kNumberOfElements; i++) + { + test_map.Insert(i,(void*)&element_array[i]); + } + // Test Erase1 + MapItem* remove_item = test_map.Find(2); + FailTest(remove_item == NULL); + FailTest(test_map.Erase(remove_item) != 0); + FailTest(test_map.Find(2) != NULL); + remove_item = NULL; + FailTest(test_map.Erase(remove_item) != -1); + // Test Erase2 + FailTest(test_map.Erase(1) != 0); + FailTest(test_map.Find(1) != NULL); + FailTest(test_map.Erase(1) != -1); + // Test Size + FailTest(test_map.Size() != kNumberOfElements - 2); + PrintMap(test_map); + // Test First + MapItem* first_item = test_map.First(); + FailTest(first_item == NULL); + FailTest(GetStoredIntegerValue(first_item) != 0); + // Test Last + MapItem* last_item = test_map.Last(); + FailTest(last_item == NULL); + FailTest(GetStoredIntegerValue(last_item) != 9); + // Test Next + MapItem* second_item = test_map.Next(first_item); + FailTest(second_item == NULL); + FailTest(GetStoredIntegerValue(second_item) != 3); + FailTest(test_map.Next(last_item) != NULL); + // Test Previous + MapItem* second_to_last_item = test_map.Previous(last_item); + FailTest(second_to_last_item == NULL); + FailTest(GetStoredIntegerValue(second_to_last_item) != 8); + FailTest(test_map.Previous(first_item) != NULL); + // Test Find (only improper usage untested) + FailTest(test_map.Find(kNumberOfElements + 2) != NULL); + // Test GetId + FailTest(*(reinterpret_cast(second_to_last_item->GetItem())) != + second_to_last_item->GetId()); + FailTest(second_to_last_item->GetUnsignedId() != + static_cast(second_to_last_item->GetId())); + // Test SetItem + int swapped_item = kNumberOfElements; + last_item->SetItem(reinterpret_cast(&swapped_item)); + FailTest(GetStoredIntegerValue(last_item) != + swapped_item); + + printf("Tests passed successfully!\n"); +}